github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/go_fn_test.go (about) 1 package eval_test 2 3 import ( 4 "errors" 5 "math/big" 6 "reflect" 7 "testing" 8 9 . "github.com/markusbkk/elvish/pkg/eval" 10 "github.com/markusbkk/elvish/pkg/eval/errs" 11 . "github.com/markusbkk/elvish/pkg/eval/evaltest" 12 "github.com/markusbkk/elvish/pkg/eval/vals" 13 ) 14 15 type someOptions struct { 16 Foo string 17 Bar string 18 } 19 20 func (o *someOptions) SetDefaultOptions() { o.Bar = "default" } 21 22 //lint:ignore ST1012 test code 23 var anError = errors.New("an error") 24 25 type namedSlice []string 26 27 func TestGoFn_RawOptions(t *testing.T) { 28 Test(t, 29 That("f").DoesNothing(). 30 WithSetup(f(func() {})), 31 32 // RawOptions 33 That("f &foo=bar").DoesNothing(). 34 WithSetup(f(func(opts RawOptions) { 35 if opts["foo"] != "bar" { 36 t.Errorf("RawOptions parameter doesn't get options") 37 } 38 })), 39 // Options when the function does not accept options. 40 That("f &foo=bar").Throws(ErrNoOptAccepted). 41 WithSetup(f(func() { 42 t.Errorf("Function called when there are extra options") 43 })), 44 // Parsed options 45 That("f &foo=bar").DoesNothing(). 46 WithSetup(f(func(opts someOptions) { 47 if opts.Foo != "bar" { 48 t.Errorf("ScanOptions parameter doesn't get options") 49 } 50 if opts.Bar != "default" { 51 t.Errorf("ScanOptions parameter doesn't use default value") 52 } 53 })), 54 // Invalid option; regression test for #958. 55 That("f &bad=bar").Throws(UnknownOption{"bad"}). 56 WithSetup(f(func(opts someOptions) { 57 t.Errorf("function called when there are invalid options") 58 })), 59 // Invalid option type; regression test for #958. 60 That("f &foo=[]").Throws(ErrorWithType(vals.WrongType{})). 61 WithSetup(f(func(opts someOptions) { 62 t.Errorf("function called when there are invalid options") 63 })), 64 65 // Argument 66 That("f lorem ipsum").DoesNothing(). 67 WithSetup(f(func(x, y string) { 68 if x != "lorem" { 69 t.Errorf("Argument x not passed") 70 } 71 if y != "ipsum" { 72 t.Errorf("Argument y not passed") 73 } 74 })), 75 // Variadic arguments 76 That("f lorem ipsum").DoesNothing(). 77 WithSetup(f(func(args ...string) { 78 wantArgs := []string{"lorem", "ipsum"} 79 if !reflect.DeepEqual(args, wantArgs) { 80 t.Errorf("got args %v, want %v", args, wantArgs) 81 } 82 })), 83 // Argument conversion 84 That("f 314 1.25").DoesNothing(). 85 WithSetup(f(func(i int, f float64) { 86 if i != 314 { 87 t.Errorf("Integer argument i not passed") 88 } 89 if f != 1.25 { 90 t.Errorf("Float argument f not passed") 91 } 92 })), 93 // Inputs 94 That("f [foo bar]").DoesNothing(). 95 WithSetup(f(testInputs(t, "foo", "bar"))), 96 That("f [foo bar]").DoesNothing(). 97 WithSetup(f(testInputs(t, "foo", "bar"))), 98 // Too many arguments 99 That("f x"). 100 Throws(errs.ArityMismatch{What: "arguments", 101 ValidLow: 0, ValidHigh: 0, Actual: 1}). 102 WithSetup(f(func() { 103 t.Errorf("Function called when there are too many arguments") 104 })), 105 // Too few arguments 106 That("f"). 107 Throws(errs.ArityMismatch{What: "arguments", 108 ValidLow: 1, ValidHigh: 1, Actual: 0}). 109 WithSetup(f(func(x string) { 110 t.Errorf("Function called when there are too few arguments") 111 })), 112 That("f"). 113 Throws(errs.ArityMismatch{What: "arguments", 114 ValidLow: 1, ValidHigh: -1, Actual: 0}). 115 WithSetup(f(func(x string, y ...string) { 116 t.Errorf("Function called when there are too few arguments") 117 })), 118 // Wrong argument type 119 That("f (num 1)").Throws(ErrorWithType(WrongArgType{})). 120 WithSetup(f(func(x string) { 121 t.Errorf("Function called when arguments have wrong type") 122 })), 123 That("f str").Throws(ErrorWithType(WrongArgType{})). 124 WithSetup(f(func(x int) { 125 t.Errorf("Function called when arguments have wrong type") 126 })), 127 128 // Return value 129 That("f").Puts("foo"). 130 WithSetup(f(func() string { return "foo" })), 131 // Return value conversion 132 That("f").Puts(314). 133 WithSetup(f(func() *big.Int { return big.NewInt(314) })), 134 // Slice and array return value 135 That("f").Puts("foo", "bar"). 136 WithSetup(f(func() []string { return []string{"foo", "bar"} })), 137 That("f").Puts("foo", "bar"). 138 WithSetup(f(func() [2]string { return [2]string{"foo", "bar"} })), 139 // Named types with underlying slice type treated as a single value 140 That("f").Puts(namedSlice{"foo", "bar"}). 141 WithSetup(f(func() namedSlice { return namedSlice{"foo", "bar"} })), 142 143 // Error return value 144 That("f").Throws(anError). 145 WithSetup(f(func() (string, error) { return "x", anError })), 146 That("f").DoesNothing(). 147 WithSetup(f(func() error { return nil })), 148 ) 149 } 150 151 func f(body interface{}) func(*Evaler) { 152 return func(ev *Evaler) { 153 ev.ExtendGlobal(BuildNs().AddGoFn("f", body)) 154 } 155 } 156 157 func testInputs(t *testing.T, wantValues ...interface{}) func(Inputs) { 158 return func(i Inputs) { 159 t.Helper() 160 var values []interface{} 161 i(func(x interface{}) { 162 values = append(values, x) 163 }) 164 wantValues := []interface{}{"foo", "bar"} 165 if !reflect.DeepEqual(values, wantValues) { 166 t.Errorf("Inputs parameter didn't get supplied inputs") 167 } 168 } 169 }