github.com/elves/elvish@v0.15.0/pkg/edit/testutils_test.go (about)

     1  package edit
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/elves/elvish/pkg/cli/clitest"
     8  	"github.com/elves/elvish/pkg/cli/term"
     9  	"github.com/elves/elvish/pkg/eval"
    10  	"github.com/elves/elvish/pkg/eval/vals"
    11  	"github.com/elves/elvish/pkg/eval/vars"
    12  	"github.com/elves/elvish/pkg/parse"
    13  	"github.com/elves/elvish/pkg/store"
    14  	"github.com/elves/elvish/pkg/testutil"
    15  )
    16  
    17  var Styles = clitest.Styles
    18  
    19  type fixture struct {
    20  	Editor  *Editor
    21  	TTYCtrl clitest.TTYCtrl
    22  	Evaler  *eval.Evaler
    23  	Store   store.Store
    24  	Home    string
    25  
    26  	width   int
    27  	codeCh  <-chan string
    28  	errCh   <-chan error
    29  	cleanup func()
    30  }
    31  
    32  func rc(codes ...string) func(*fixture) {
    33  	return func(f *fixture) { evals(f.Evaler, codes...) }
    34  }
    35  
    36  func assign(name string, val interface{}) func(*fixture) {
    37  	return func(f *fixture) {
    38  		f.Evaler.AddGlobal(eval.CombineNs(f.Evaler.Global(),
    39  			eval.NsBuilder{"temp": vars.NewReadOnly(val)}.Ns()))
    40  		evals(f.Evaler, name+` = $temp`)
    41  	}
    42  }
    43  
    44  func storeOp(storeFn func(store.Store)) func(*fixture) {
    45  	return func(f *fixture) {
    46  		storeFn(f.Store)
    47  		// TODO(xiaq): Don't depend on this Elvish API.
    48  		evals(f.Evaler, "edit:history:fast-forward")
    49  	}
    50  }
    51  
    52  func setup(fns ...func(*fixture)) *fixture {
    53  	st, cleanupStore := store.MustGetTempStore()
    54  	home, cleanupFs := testutil.InTempHome()
    55  	tty, ttyCtrl := clitest.NewFakeTTY()
    56  	ev := eval.NewEvaler()
    57  	ed := NewEditor(tty, ev, st)
    58  	ev.AddModule("edit", ed.Ns())
    59  	evals(ev,
    60  		`use edit`,
    61  		// This is the same as the default prompt for non-root users. This makes
    62  		// sure that the tests will work when run as root.
    63  		"edit:prompt = { tilde-abbr $pwd; put '> ' }",
    64  		// This will simplify most tests against the terminal.
    65  		"edit:rprompt = { }")
    66  	f := &fixture{Editor: ed, TTYCtrl: ttyCtrl, Evaler: ev, Store: st, Home: home}
    67  	for _, fn := range fns {
    68  		fn(f)
    69  	}
    70  	_, f.width = tty.Size()
    71  	f.codeCh, f.errCh = clitest.StartReadCode(f.Editor.ReadCode)
    72  	f.cleanup = func() {
    73  		f.Editor.app.CommitEOF()
    74  		f.Wait()
    75  		cleanupFs()
    76  		cleanupStore()
    77  	}
    78  	return f
    79  }
    80  
    81  func (f *fixture) Wait() (string, error) {
    82  	return <-f.codeCh, <-f.errCh
    83  }
    84  
    85  func (f *fixture) Cleanup() {
    86  	f.cleanup()
    87  }
    88  
    89  func (f *fixture) MakeBuffer(args ...interface{}) *term.Buffer {
    90  	return term.NewBufferBuilder(f.width).MarkLines(args...).Buffer()
    91  }
    92  
    93  func (f *fixture) TestTTY(t *testing.T, args ...interface{}) {
    94  	t.Helper()
    95  	f.TTYCtrl.TestBuffer(t, f.MakeBuffer(args...))
    96  }
    97  
    98  func (f *fixture) TestTTYNotes(t *testing.T, args ...interface{}) {
    99  	t.Helper()
   100  	f.TTYCtrl.TestNotesBuffer(t, f.MakeBuffer(args...))
   101  }
   102  
   103  func feedInput(ttyCtrl clitest.TTYCtrl, s string) {
   104  	for _, r := range s {
   105  		ttyCtrl.Inject(term.K(r))
   106  	}
   107  }
   108  
   109  func evals(ev *eval.Evaler, codes ...string) {
   110  	for _, code := range codes {
   111  		err := ev.Eval(parse.Source{Name: "[test]", Code: code}, eval.EvalCfg{})
   112  		if err != nil {
   113  			panic(fmt.Errorf("eval %q: %s", code, err))
   114  		}
   115  	}
   116  }
   117  
   118  func getGlobal(ev *eval.Evaler, name string) interface{} {
   119  	v, _ := ev.Global().Index(name)
   120  	return v
   121  }
   122  
   123  func testGlobals(t *testing.T, ev *eval.Evaler, wantVals map[string]interface{}) {
   124  	t.Helper()
   125  	for name, wantVal := range wantVals {
   126  		testGlobal(t, ev, name, wantVal)
   127  	}
   128  }
   129  
   130  func testGlobal(t *testing.T, ev *eval.Evaler, name string, wantVal interface{}) {
   131  	t.Helper()
   132  	if val := getGlobal(ev, name); !vals.Equal(val, wantVal) {
   133  		t.Errorf("$%s = %s, want %s",
   134  			name, vals.Repr(val, vals.NoPretty), vals.Repr(wantVal, vals.NoPretty))
   135  	}
   136  }