ronantakizawa/codereview-bench huggingface dataset:
Repository: junegunn/fzf
File: src/terminal.go (Go)

Code before:
}

func (t *Terminal) hasPreviewer() bool {
	return t.previewBox != nil
}

func (t *Terminal) isPreviewEnabled() bool {
	return t.hasPreviewer() && t.previewer.enabled
}

func (t *Terminal) hasPreviewWindow() bool {
	return t.pwindow != nil && t.isPreviewEnabled()
}

func (t *Terminal) currentItem() *Item {
	cnt := t.merger.Length()
	if cnt > 0 && cnt > t.cy {
		return t.merger.Get(t.cy).item
	}
	return nil
}

func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, []*Item) {
	current := t.currentItem()
	plus, query, file := hasPreviewFlags(template)
	if !(query && len(t.input) > 0 || file || (forcePlus || plus) && len(t.selected) > 0) {
		return current != nil, []*Item{current, current}
	}

	// We would still want to update preview window even if there is no match if
	//   1. command template contains {q} and the query string is not empty
	//   2. or it contains {+} and we have more than one item already selected.
	// To do so, we pass an empty Item instead of nil to trigger an update.
	if current == nil {
		current = &minItem
	}

	var sels []*Item
	if len(t.selected) == 0 {
		sels = []*Item{current, current}
	} else {
		sels = make([]*Item, len(t.selected)+1)
		sels[0] = current
		for i, sel := range t.sortSelected() {
			sels[i+1] = sel.item
		}
	}
	return true, sels
}

func (t *Terminal) selectItem(item *Item) {

Review comment (suggestion):
I don't think `file` should affect the control flow here. Let me know if I'm mistaken.

Code after:

func (t *Terminal) hasPreviewWindow() bool {
	return t.pwindow != nil && t.isPreviewEnabled()
}

func (t *Terminal) currentItem() *Item {
	cnt := t.merger.Length()
	if cnt > 0 && cnt > t.cy {
		return t.merger.Get(t.cy).item
	}
	return nil
}

func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, []*Item) {
	current := t.currentItem()
	plus, query := hasPreviewFlags(template)
	if !(query && len(t.input) > 0 || (forcePlus || plus) && len(t.selected) > 0) {
		return current != nil, []*Item{current, current}
	}

	// We would still want to update preview window even if there is no match if
	//   1. command template contains {q} and the query string is not empty
	//   2. or it contains {+} and we have more than one item already selected.
	// To do so, we pass an empty Item instead of nil to trigger an update.
	if current == nil {
		current = &minItem
	}

	var sels []*Item
	if len(t.selected) == 0 {
		sels = []*Item{current, current}
	} else {
		sels = make([]*Item, len(t.selected)+1)
		sels[0] = current
		for i, sel := range t.sortSelected() {
			sels[i+1] = sel.item
		}
	}
	return true, sels
}

func (t *Terminal) selectItem(item *Item) {
	t.selected[item.Index()] = selectedItem{time.Now(), item}
	t.version++
}

func (t *Terminal) deselectItem(item *Item) {
	delete(t.selected, item.Index())
	t.version++
}
Repository: junegunn/fzf
File: src/terminal.go (Go)

Code before:
	}
	return
}

func writeTemporaryFile(data []string) string {
	f, err := ioutil.TempFile("", "fzf-preview-*")
	if err != nil {
		errorExit("Unable to create temporary file")
	}
	defer f.Close()

	f.WriteString(strings.Join(data, "\n"))
	f.WriteString("\n")
	activeTempFiles = append(activeTempFiles, f.Name())
	return f.Name()
}

func cleanTemporaryFiles() error {
	var err error
	var filename string

	for len(activeTempFiles) != 0 {
		filename, activeTempFiles = activeTempFiles[0], activeTempFiles[1:]
		err = os.Remove(filename)
		if err != nil {
			return err
		}
	}
	return nil
}

func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, forcePlus bool, query string, allItems []*Item) string {
	current := allItems[:1]
	selected := allItems[1:]
	if current[0] == nil {
		current = []*Item{}
	}
	if selected[0] == nil {
		selected = []*Item{}
	}
	return placeholder.ReplaceAllStringFunc(template, func(match string) string {
		escaped, match, flags := parsePlaceholder(match)

		if escaped {
			return match
		}

		// Current query
		if match == "{q}" {
			return quoteEntry(query)
		}

Review comment (suggestion):
We're not gonna do anything with the return value. We should just ignore the error and proceed with the rest.

Code after:
	return
}

func writeTemporaryFile(data []string, printSep string) string {
	f, err := ioutil.TempFile("", "fzf-preview-*")
	if err != nil {
		errorExit("Unable to create temporary file")
	}
	defer f.Close()

	f.WriteString(strings.Join(data, printSep))
	f.WriteString(printSep)
	activeTempFiles = append(activeTempFiles, f.Name())
	return f.Name()
}

func cleanTemporaryFiles() {
	for _, filename := range activeTempFiles {
		os.Remove(filename)
	}
	activeTempFiles = []string{}
}

func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, printsep string, forcePlus bool, query string, allItems []*Item) string {
	current := allItems[:1]
	selected := allItems[1:]
	if current[0] == nil {
		current = []*Item{}
	}
	if selected[0] == nil {
		selected = []*Item{}
	}
	return placeholder.ReplaceAllStringFunc(template, func(match string) string {
		escaped, match, flags := parsePlaceholder(match)

		if escaped {
			return match
		}

		// Current query
		if match == "{q}" {
			return quoteEntry(query)
		}

		items := current
		if flags.plus || forcePlus {
			items = selected
		}

		replacements := make([]string, len(items))
Repository: junegunn/fzf
File: src/options.go (Go)

Code before:
		errorExit("empty jump labels")
	}

	if validateJumpLabels {
		for _, r := range opts.JumpLabels {
			if r < 32 || r > 126 {
				errorExit("non-ascii jump labels are not allowed")
			}
		}
	}

	if validatePointer {
		if err := validateSign(opts.Pointer, "pointer"); err != nil {
			errorExit(err.Error())
		}
	}

	if validateMarker {
		if err := validateSign(opts.Marker, "marker"); err != nil {
			errorExit(err.Error())
		}
	}
}

func validateSign(sign string, signOptName string) error {
	if strings.Contains(sign, "\n") || strings.Contains(sign, "\t") {
		return fmt.Errorf("In %v, \\n or \\t cannot be included", signOptName)
	}

	widthSum := 0
	for _, r := range sign {
		widthSum += runewidth.RuneWidth(r)
	}
	if widthSum > 2 {
		return fmt.Errorf("%v display width should be up to 2", signOptName)
	}
	return nil
}

func postProcessOptions(opts *Options) {
	if util.IsWindows() && opts.Height.size > 0 {
		errorExit("--height option is currently not supported on Windows")
	}
	// Default actions for CTRL-N / CTRL-P when --history is set
	if opts.History != nil {
		if _, prs := opts.Keymap[tui.CtrlP]; !prs {
			opts.Keymap[tui.CtrlP] = toActions(actPreviousHistory)
		}
		if _, prs := opts.Keymap[tui.CtrlN]; !prs {
			opts.Keymap[tui.CtrlN] = toActions(actNextHistory)
		}

Review comment (suggestion):
It would be more precise to use https://golang.org/pkg/unicode/#IsGraphic
Error message can be `invalid character in %v`

Code after:
	if len(opts.JumpLabels) == 0 {
		errorExit("empty jump labels")
	}

	if validateJumpLabels {
		for _, r := range opts.JumpLabels {
			if r < 32 || r > 126 {
				errorExit("non-ascii jump labels are not allowed")
			}
		}
	}

	if validatePointer {
		if err := validateSign(opts.Pointer, "pointer"); err != nil {
			errorExit(err.Error())
		}
	}

	if validateMarker {
		if err := validateSign(opts.Marker, "marker"); err != nil {
			errorExit(err.Error())
		}
	}
}

func validateSign(sign string, signOptName string) error {
	if sign == "" {
		return fmt.Errorf("%v cannot be empty", signOptName)
	}
	widthSum := 0
	for _, r := range sign {
		if !unicode.IsGraphic(r) {
			return fmt.Errorf("invalid character in %v", signOptName)
		}
		widthSum += runewidth.RuneWidth(r)
		if widthSum > 2 {
			return fmt.Errorf("%v display width should be up to 2", signOptName)
		}
	}
	return nil
}

func postProcessOptions(opts *Options) {
	if util.IsWindows() && opts.Height.size > 0 {
		errorExit("--height option is currently not supported on Windows")
	}
	// Default actions for CTRL-N / CTRL-P when --history is set
	if opts.History != nil {
		if _, prs := opts.Keymap[tui.CtrlP]; !prs {
			opts.Keymap[tui.CtrlP] = toActions(actPreviousHistory)
		}
Repository: junegunn/fzf
File: src/reader.go (Go)

Code before:
}

func (r *Reader) readFiles() bool {
	fn := func(path string, mode os.FileInfo) error {
		path = filepath.Clean(path)
		if path != "." {
			if mode.Mode().IsDir() && filepath.Base(path)[0] == '.' {
				return filepath.SkipDir
			}
			if r.pusher([]byte(path)) {
				atomic.StoreInt32(&r.event, int32(EvtReadNew))
			}
		}
		return nil
	}
	cb := walker.WithErrorCallback(func(pathname string, err error) error {
		return nil
	})
	return walker.Walk(".", fn, cb) == nil
}

func (r *Reader) readFromCommand(shell *string, command string) bool {
	r.mutex.Lock()
	r.killed = false
	r.command = &command
	if shell != nil {
		r.exec = util.ExecCommandWith(*shell, command, true)
	} else {
		r.exec = util.ExecCommand(command, true)
	}
	out, err := r.exec.StdoutPipe()
	if err != nil {
		r.mutex.Unlock()
		return false
	}
	err = r.exec.Start()
	r.mutex.Unlock()
	if err != nil {
		return false
	}
	r.feed(out)
	return r.exec.Wait() == nil
}


Review comment (suggestion):
Thanks @mattn!

Looks like we can just omit error callback here.

i.e. `return walker.Walk(".", fn) == nil`

Code after:
	return true
}

func (r *Reader) readFiles() bool {
	r.killed = false
	fn := func(path string, mode os.FileInfo) error {
		path = filepath.Clean(path)
		if path != "." {
			if mode.Mode().IsDir() && filepath.Base(path)[0] == '.' {
				return filepath.SkipDir
			}
			if r.pusher([]byte(path)) {
				atomic.StoreInt32(&r.event, int32(EvtReadNew))
			}
		}
		r.mutex.Lock()
		defer r.mutex.Unlock()
		if r.killed {
			return context.Canceled
		}
		return nil
	}
	cb := walker.WithErrorCallback(func(pathname string, err error) error {
		return nil
	})
	return walker.Walk(".", fn, cb) == nil
}

func (r *Reader) readFromCommand(shell *string, command string) bool {
	r.mutex.Lock()
	r.killed = false
	r.command = &command
	if shell != nil {
		r.exec = util.ExecCommandWith(*shell, command, true)
	} else {
		r.exec = util.ExecCommand(command, true)
	}
	out, err := r.exec.StdoutPipe()
	if err != nil {
		r.mutex.Unlock()
		return false
	}
	err = r.exec.Start()
	r.mutex.Unlock()
	if err != nil {
		return false
	}
	r.feed(out)
	return r.exec.Wait() == nil
}
Repository: junegunn/fzf
File: src/terminal.go (Go)

Code before:
					t.cx = len(t.input)
				}
			case actAbort:
				req(reqQuit)
			case actDeleteChar:
				t.delChar()
			case actDeleteCharEOF:
				if !t.delChar() && t.cx == 0 {
					req(reqQuit)
				}
			case actEndOfLine:
				t.cx = len(t.input)
			case actCancel:
				if len(t.input) == 0 {
					req(reqQuit)
				} else {
					t.yanked = t.input
					t.input = []rune{}
					t.cx = 0
				}
			case actBackwardDeleteCharEOF:
				if len(t.input) == 0 {
					req(reqQuit)
				} else if t.cx > 0 {
                    t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
                    t.cx--
				}
			case actForwardChar:
				if t.cx < len(t.input) {
					t.cx++
				}
			case actBackwardDeleteChar:
				if t.cx > 0 {
					t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
					t.cx--
				}
			case actSelectAll:
				if t.multi > 0 {
					for i := 0; i < t.merger.Length(); i++ {
						if !t.selectItem(t.merger.Get(i).item) {
							break
						}
					}
					req(reqList, reqInfo)
				}
			case actDeselectAll:
				if t.multi > 0 {
					for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
						t.deselectItem(t.merger.Get(i).item)
					}
					req(reqList, reqInfo)

Review comment (suggestion):
Go uses tab instead of spaces for indentation.  Please `gofmt` the file.

Code after:
					t.cx = len(t.input)
				}
			case actAbort:
				req(reqQuit)
			case actDeleteChar:
				t.delChar()
			case actDeleteCharEOF:
				if !t.delChar() && t.cx == 0 {
					req(reqQuit)
				}
			case actEndOfLine:
				t.cx = len(t.input)
			case actCancel:
				if len(t.input) == 0 {
					req(reqQuit)
				} else {
					t.yanked = t.input
					t.input = []rune{}
					t.cx = 0
				}
			case actBackwardDeleteCharEOF:
				if len(t.input) == 0 {
					req(reqQuit)
				} else if t.cx > 0 {
					t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
					t.cx--
				}
			case actForwardChar:
				if t.cx < len(t.input) {
					t.cx++
				}
			case actBackwardDeleteChar:
				if t.cx > 0 {
					t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
					t.cx--
				}
			case actSelectAll:
				if t.multi > 0 {
					for i := 0; i < t.merger.Length(); i++ {
						if !t.selectItem(t.merger.Get(i).item) {
							break
						}
					}
					req(reqList, reqInfo)
				}
			case actDeselectAll:
				if t.multi > 0 {
					for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
						t.deselectItem(t.merger.Get(i).item)
					}
					req(reqList, reqInfo)
Repository: junegunn/fzf
File: test/test_go.rb (Ruby)

Code before:
        go(%W[new-window -d -P -F #I #{Shell.unsets + Shell.fish}]).first
      else
        raise "Unknown shell: #{shell}"
      end
    go(%W[set-window-option -t #{@win} pane-base-index 0])
    @lines = `tput lines`.chomp.to_i

    return unless shell == :fish
    send_keys('function fish_prompt; end; clear', :Enter)
    self.until(&:empty?)
  end

  def kill
    go(%W[kill-window -t #{win}])
  end

  def send_keys(*args)
    target =
      if args.last.is_a?(Hash)
        hash = args.pop
        go(%W[select-window -t #{win}])
        "#{win}.#{hash[:pane]}"
      else
        win
      end
    go(%W[send-keys -t #{target}] + args.map { |key| key.to_s })
  end

  def paste(str)
    system('tmux', 'setb', str, ';', 'pasteb', '-t', win, ';', 'send-keys', '-t', win, 'Enter')
  end

  def capture(pane = 0)
    File.unlink TEMPNAME while File.exist? TEMPNAME
    wait do
      go(%W[capture-pane -t #{win}.#{pane} ; save-buffer #{TEMPNAME}])
      $CHILD_STATUS.exitstatus.zero?
    end
    File.read(TEMPNAME).split($INPUT_RECORD_SEPARATOR)[0, @lines].reverse.drop_while(&:empty?).reverse
  end

  def until(refresh = false, pane = 0)
    lines = nil
    begin
      wait do
        lines = capture(pane)
        class << lines
          def counts
            lazy
              .map { |l| l.scan %r{^. ([0-9]+)\/([0-9]+)( \(([0-9]+)\))?} }
              .reject(&:empty?)

Review comment (bug):
So you're reverting https://github.com/junegunn/fzf/commit/2b98fee13602a90bcfaf76a0d75388b76692a95f here. It was an attempt to mitigate intermittent Travis CI failures. It seemed at that time that sending keys one by one sequentially instead of sending them all at once, especially in the presence of escape sequences, improved the situation. Do you think we no longer need it?


Code after:
    end

    def fish
      UNSETS.map { |v| v + '= ' }.join + 'fish'
    end
  end
end

class Tmux
  attr_reader :win

  def initialize(shell = :bash)
    @win = go(%W[new-window -d -P -F #I #{Shell.send(shell)}]).first
    go(%W[set-window-option -t #{@win} pane-base-index 0])
    return unless shell == :fish

    send_keys('function fish_prompt; end; clear', :Enter)
    self.until(&:empty?)
  end

  def kill
    go(%W[kill-window -t #{win}])
  end

  def send_keys(*args)
    target =
      if args.last.is_a?(Hash)
        hash = args.pop
        go(%W[select-window -t #{win}])
        "#{win}.#{hash[:pane]}"
      else
        win
      end
    go(%W[send-keys -t #{target}] + args.map(&:to_s))
  end

  def paste(str)
    system('tmux', 'setb', str, ';', 'pasteb', '-t', win, ';', 'send-keys', '-t', win, 'Enter')
  end

  def capture(pane = 0)
    go(%W[capture-pane -p -t #{win}.#{pane}]).reverse.drop_while(&:empty?).reverse
  end

  def until(refresh = false, pane = 0)
    lines = nil
    begin
      wait do
        lines = capture(pane)
        class << lines
          def counts
Repository: junegunn/fzf
File: src/util/atomicbool.go (Go)

Code before:
package util

import (
	"sync/atomic"
)

// AtomicBool is a boxed-class that provides synchronized access to the
// underlying boolean value
type AtomicBool struct {
	state int32 // "1" is true, "0" is false
}

// NewAtomicBool returns a new AtomicBool
func NewAtomicBool(initialState bool) *AtomicBool {
	var state int32 = 0
	if initialState == true {
		state = 1
	}
	return &AtomicBool{state: state}
}

// Get returns the current boolean value synchronously
func (a *AtomicBool) Get() bool {
	return atomic.LoadInt32(&a.state) == 1
}

// Set updates the boolean value synchronously
func (a *AtomicBool) Set(newState bool) bool {
	var state int32 = 0
	if newState == true {
		state = 1
	}
	atomic.StoreInt32(&a.state, state)
	return newState
}


Review comment (suggestion):
Can be simplified:

```go
var state int32
if initialState {
    state = 1
}
```

Code after:
package util

import (
	"sync/atomic"
)

func convertBoolToInt32(b bool) int32 {
	if b {
		return 1
	}
	return 0
}

// AtomicBool is a boxed-class that provides synchronized access to the
// underlying boolean value
type AtomicBool struct {
	state int32 // "1" is true, "0" is false
}

// NewAtomicBool returns a new AtomicBool
func NewAtomicBool(initialState bool) *AtomicBool {
	return &AtomicBool{state: convertBoolToInt32(initialState)}
}

// Get returns the current boolean value synchronously
func (a *AtomicBool) Get() bool {
	return atomic.LoadInt32(&a.state) == 1
}

// Set updates the boolean value synchronously
func (a *AtomicBool) Set(newState bool) bool {
	atomic.StoreInt32(&a.state, convertBoolToInt32(newState))
	return newState
}
Repository: junegunn/fzf
File: src/util/atomicbool.go (Go)

Code before:
	"sync/atomic"
)

// AtomicBool is a boxed-class that provides synchronized access to the
// underlying boolean value
type AtomicBool struct {
	state int32 // "1" is true, "0" is false
}

// NewAtomicBool returns a new AtomicBool
func NewAtomicBool(initialState bool) *AtomicBool {
	var state int32 = 0
	if initialState == true {
		state = 1
	}
	return &AtomicBool{state: state}
}

// Get returns the current boolean value synchronously
func (a *AtomicBool) Get() bool {
	return atomic.LoadInt32(&a.state) == 1
}

// Set updates the boolean value synchronously
func (a *AtomicBool) Set(newState bool) bool {
	var state int32 = 0
	if newState == true {
		state = 1
	}
	atomic.StoreInt32(&a.state, state)
	return newState
}


Review comment (suggestion):
Can be simplified:

```go
var state int32
if newState {
    state = 1
}
```

Code after:
	"sync/atomic"
)

func convertBoolToInt32(b bool) int32 {
	if b {
		return 1
	}
	return 0
}

// AtomicBool is a boxed-class that provides synchronized access to the
// underlying boolean value
type AtomicBool struct {
	state int32 // "1" is true, "0" is false
}

// NewAtomicBool returns a new AtomicBool
func NewAtomicBool(initialState bool) *AtomicBool {
	return &AtomicBool{state: convertBoolToInt32(initialState)}
}

// Get returns the current boolean value synchronously
func (a *AtomicBool) Get() bool {
	return atomic.LoadInt32(&a.state) == 1
}

// Set updates the boolean value synchronously
func (a *AtomicBool) Set(newState bool) bool {
	atomic.StoreInt32(&a.state, convertBoolToInt32(newState))
	return newState
}
Repository: junegunn/fzf
File: src/terminal.go (Go)

Code before:
}

func (t *Terminal) killPreview(code int) {
	select {
	case t.killChan <- code:
	default:
		if code != exitCancel {
			os.Exit(code)
		}
	}
}

func (t *Terminal) cancelPreview() {
	t.killPreview(exitCancel)
}

// Loop is called to start Terminal I/O
func (t *Terminal) Loop() {
	// prof := profile.Start(profile.ProfilePath("/tmp/"))
	<-t.startChan
	{ // Late initialization
		intChan := make(chan os.Signal, 1)
		signal.Notify(intChan, os.Interrupt, syscall.SIGTERM)
		go func() {
			for {
				s := <-intChan
				// Don't quit by SIGINT while executing because it should be for the executing command and not for fzf itself
				if !(s == os.Interrupt && t.executing) {
					t.reqBox.Set(reqQuit, nil)
				}
			}
		}()

		contChan := make(chan os.Signal, 1)
		notifyOnCont(contChan)
		go func() {
			for {
				<-contChan
				t.reqBox.Set(reqReinit, nil)
			}
		}()

		resizeChan := make(chan os.Signal, 1)
		notifyOnResize(resizeChan) // Non-portable
		go func() {
			for {
				<-resizeChan
				t.reqBox.Set(reqRedraw, nil)
			}
		}()


Review comment (refactor):
We can simplify this to `for s := range intChan {`.

* https://gobyexample.com/range-over-channels


Code after:
}

func (t *Terminal) killPreview(code int) {
	select {
	case t.killChan <- code:
	default:
		if code != exitCancel {
			os.Exit(code)
		}
	}
}

func (t *Terminal) cancelPreview() {
	t.killPreview(exitCancel)
}

// Loop is called to start Terminal I/O
func (t *Terminal) Loop() {
	// prof := profile.Start(profile.ProfilePath("/tmp/"))
	<-t.startChan
	{ // Late initialization
		intChan := make(chan os.Signal, 1)
		signal.Notify(intChan, os.Interrupt, syscall.SIGTERM)
		go func() {
			for s := range intChan {
				// Don't quit by SIGINT while executing because it should be for the executing command and not for fzf itself
				if !(s == os.Interrupt && t.executing.Get()) {
					t.reqBox.Set(reqQuit, nil)
				}
			}
		}()

		contChan := make(chan os.Signal, 1)
		notifyOnCont(contChan)
		go func() {
			for {
				<-contChan
				t.reqBox.Set(reqReinit, nil)
			}
		}()

		resizeChan := make(chan os.Signal, 1)
		notifyOnResize(resizeChan) // Non-portable
		go func() {
			for {
				<-resizeChan
				t.reqBox.Set(reqRedraw, nil)
			}
		}()

		t.mutex.Lock()
Repository: junegunn/fzf
File: src/reader_test.go (Go)

Code before:
package fzf

import (
	"testing"
	"time"

	"github.com/junegunn/fzf/src/util"
)

func TestReadFromCommand(t *testing.T) {
	strs := []string{}
	eb := util.NewEventBox()
	reader := NewReader(
		func(s []byte) bool { strs = append(strs, string(s)); return true },
		eb, false, true)

	reader.startEventPoller()

	// Check EventBox
	if eb.Peek(EvtReadNew) {
		t.Error("EvtReadNew should not be set yet")
	}

	// Normal command
	reader.fin(reader.readFromCommand(nil, `echo abc && echo def`))
	if len(strs) != 2 || strs[0] != util.OS.Sieve("abc", "abc ") || strs[1] != "def" {
		t.Errorf("%s", strs)
	}

	// Check EventBox again
	eb.WaitFor(EvtReadFin)

	// Wait should return immediately
	eb.Wait(func(events *util.Events) {
		events.Clear()
	})

	// EventBox is cleared
	if eb.Peek(EvtReadNew) {
		t.Error("EvtReadNew should not be set yet")
	}

	// Make sure that event poller is finished
	time.Sleep(readerPollIntervalMax)

	// Restart event poller
	reader.startEventPoller()

	// Failing command
	reader.fin(reader.readFromCommand(nil, `no-such-command`))
	strs = []string{}

Review comment (suggestion):
I would simply change the command so that it yields the same result on both systems.

i.e. `echo abc&&echo def`


Code after:
package fzf

import (
	"testing"
	"time"

	"github.com/junegunn/fzf/src/util"
)

func TestReadFromCommand(t *testing.T) {
	strs := []string{}
	eb := util.NewEventBox()
	reader := NewReader(
		func(s []byte) bool { strs = append(strs, string(s)); return true },
		eb, false, true)

	reader.startEventPoller()

	// Check EventBox
	if eb.Peek(EvtReadNew) {
		t.Error("EvtReadNew should not be set yet")
	}

	// Normal command
	reader.fin(reader.readFromCommand(nil, `echo abc&&echo def`))
	if len(strs) != 2 || strs[0] != "abc" || strs[1] != "def" {
		t.Errorf("%s", strs)
	}

	// Check EventBox again
	eb.WaitFor(EvtReadFin)

	// Wait should return immediately
	eb.Wait(func(events *util.Events) {
		events.Clear()
	})

	// EventBox is cleared
	if eb.Peek(EvtReadNew) {
		t.Error("EvtReadNew should not be set yet")
	}

	// Make sure that event poller is finished
	time.Sleep(readerPollIntervalMax)

	// Restart event poller
	reader.startEventPoller()

	// Failing command
	reader.fin(reader.readFromCommand(nil, `no-such-command`))
	strs = []string{}