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 }