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