1 package exec_test
2
3 import (
4
5
6 "reflect"
7 "testing"
8
9 "github.com/noirbizarre/gonja/exec"
10 "github.com/stretchr/testify/assert"
11 )
12
13 type flags struct {
14 IsString bool
15 IsCallable bool
16 IsBool bool
17 IsFloat bool
18 IsInteger bool
19 IsNumber bool
20 IsList bool
21 IsDict bool
22 IsIterable bool
23 IsNil bool
24 IsTrue bool
25 IsError bool
26 }
27
28 func (f *flags) assert(t *testing.T, value *exec.Value) {
29 assert := assert.New(t)
30
31 val := reflect.ValueOf(value)
32 fval := reflect.ValueOf(f).Elem()
33
34 for i := 0; i < fval.NumField(); i++ {
35 name := fval.Type().Field(i).Name
36 method := val.MethodByName(name)
37 bVal := fval.Field(i).Interface().(bool)
38 result := method.Call([]reflect.Value{})
39 bResult := result[0].Interface().(bool)
40 if bVal {
41 assert.Truef(bResult, `%s() should be true`, name)
42 } else {
43 assert.Falsef(bResult, `%s() should be false`, name)
44 }
45 }
46 }
47
48 var valueCases = []struct {
49 name string
50 value interface{}
51 asString string
52 flags flags
53 }{
54 {"nil", nil, "", flags{IsNil: true}},
55 {"string", "Hello World", "Hello World", flags{IsString: true, IsTrue: true, IsIterable: true}},
56 {"int", 42, "42", flags{IsInteger: true, IsNumber: true, IsTrue: true}},
57 {"int 0", 0, "0", flags{IsInteger: true, IsNumber: true}},
58 {"float", 42., "42.0", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
59 {"float with trailing zeros", 42.04200, "42.042", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
60 {"float max precision", 42.5556700089099, "42.55567000891", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
61 {"float max precision rounded up", 42.555670008999999, "42.555670009", flags{IsFloat: true, IsNumber: true, IsTrue: true}},
62 {"float 0.0", 0., "0.0", flags{IsFloat: true, IsNumber: true}},
63 {"true", true, "True", flags{IsBool: true, IsTrue: true}},
64 {"false", false, "False", flags{IsBool: true}},
65 {"slice", []int{1, 2, 3}, "[1, 2, 3]", flags{IsTrue: true, IsIterable: true, IsList: true}},
66 {"strings slice", []string{"a", "b", "c"}, "['a', 'b', 'c']", flags{IsTrue: true, IsIterable: true, IsList: true}},
67 {
68 "values slice",
69 []*exec.Value{exec.AsValue(1), exec.AsValue(2), exec.AsValue(3)},
70 "[1, 2, 3]",
71 flags{IsTrue: true, IsIterable: true, IsList: true},
72 },
73 {"string values slice",
74 []*exec.Value{exec.AsValue("a"), exec.AsValue("b"), exec.AsValue("c")},
75 "['a', 'b', 'c']",
76 flags{IsTrue: true, IsIterable: true, IsList: true},
77 },
78 {"array", [3]int{1, 2, 3}, "[1, 2, 3]", flags{IsTrue: true, IsIterable: true, IsList: true}},
79 {"strings array", [3]string{"a", "b", "c"}, "['a', 'b', 'c']", flags{IsTrue: true, IsIterable: true, IsList: true}},
80 {
81 "dict as map",
82 map[string]string{"a": "a", "b": "b"},
83 "{'a': 'a', 'b': 'b'}",
84 flags{IsTrue: true, IsIterable: true, IsDict: true},
85 },
86 {
87 "dict as Dict/Pairs",
88 &exec.Dict{[]*exec.Pair{
89 {exec.AsValue("a"), exec.AsValue("a")},
90 {exec.AsValue("b"), exec.AsValue("b")},
91 }},
92 "{'a': 'a', 'b': 'b'}",
93 flags{IsTrue: true, IsIterable: true, IsDict: true},
94 },
95 {"func", func() {}, "<func() Value>", flags{IsCallable: true}},
96 }
97
98 func TestValue(t *testing.T) {
99 for _, lc := range valueCases {
100 test := lc
101 t.Run(test.name, func(t *testing.T) {
102 defer func() {
103 if err := recover(); err != nil {
104 t.Error(err)
105 }
106 }()
107 assert := assert.New(t)
108
109 value := exec.AsValue(test.value)
110
111 assert.Equal(test.asString, value.String())
112 test.flags.assert(t, value)
113 })
114 }
115 }
116
117 func TestValueFromMap(t *testing.T) {
118 for _, lc := range valueCases {
119 test := lc
120 t.Run(test.name, func(t *testing.T) {
121 defer func() {
122 if err := recover(); err != nil {
123 t.Error(err)
124 }
125 }()
126 assert := assert.New(t)
127
128 data := map[string]interface{}{"value": test.value}
129 value := exec.AsValue(data["value"])
130
131 assert.Equal(test.asString, value.String())
132 test.flags.assert(t, value)
133 })
134 }
135 }
136
137 type testStruct struct {
138 Attr string
139 }
140
141 func (t testStruct) String() string {
142 return t.Attr
143 }
144
145 var getattrCases = []struct {
146 name string
147 value interface{}
148 attr string
149 found bool
150 asString string
151 flags flags
152 }{
153 {"nil", nil, "missing", false, "", flags{IsError: true}},
154 {"attr found", testStruct{"test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true, IsIterable: true}},
155 {"attr not found", testStruct{"test"}, "Missing", false, "", flags{IsNil: true}},
156 {"item", map[string]interface{}{"Attr": "test"}, "Attr", false, "", flags{IsNil: true}},
157 }
158
159 func TestValueGetAttr(t *testing.T) {
160 for _, lc := range getattrCases {
161 test := lc
162 t.Run(test.name, func(t *testing.T) {
163 defer func() {
164 if err := recover(); err != nil {
165 t.Error(err)
166 }
167 }()
168 assert := assert.New(t)
169
170 value := exec.AsValue(test.value)
171 out, found := value.Getattr(test.attr)
172
173 if !test.flags.IsError && out.IsError() {
174 t.Fatalf(`Unexpected error: %s`, out.Error())
175 }
176
177 if test.found {
178 assert.Truef(found, `Attribute '%s' should be found on %s`, test.attr, value)
179 assert.Equal(test.asString, out.String())
180 } else {
181 assert.Falsef(found, `Attribute '%s' should not be found on %s`, test.attr, value)
182 }
183
184 test.flags.assert(t, out)
185 })
186 }
187 }
188
189 var getitemCases = []struct {
190 name string
191 value interface{}
192 key interface{}
193 found bool
194 asString string
195 flags flags
196 }{
197 {"nil", nil, "missing", false, "", flags{IsError: true}},
198 {"item found", map[string]interface{}{"Attr": "test"}, "Attr", true, "test", flags{IsString: true, IsTrue: true, IsIterable: true}},
199 {"item not found", map[string]interface{}{"Attr": "test"}, "Missing", false, "test", flags{IsNil: true}},
200 {"attr", testStruct{"test"}, "Attr", false, "", flags{IsNil: true}},
201 {"dict found", &exec.Dict{[]*exec.Pair{
202 {exec.AsValue("key"), exec.AsValue("value")},
203 {exec.AsValue("otherKey"), exec.AsValue("otherValue")},
204 }}, "key", true, "value", flags{IsTrue: true, IsString: true, IsIterable: true}},
205 }
206
207 func TestValueGetitem(t *testing.T) {
208 for _, lc := range getitemCases {
209 test := lc
210 t.Run(test.name, func(t *testing.T) {
211 defer func() {
212 if err := recover(); err != nil {
213 t.Error(err)
214 }
215 }()
216 assert := assert.New(t)
217
218 value := exec.AsValue(test.value)
219 out, found := value.Getitem(test.key)
220
221 if !test.flags.IsError && out.IsError() {
222 t.Fatalf(`Unexpected error: %s`, out.Error())
223 }
224
225 if test.found {
226 assert.Truef(found, `Key '%s' should be found on %s`, test.key, value)
227 assert.Equal(test.asString, out.String())
228 } else {
229 assert.Falsef(found, `Key '%s' should not be found on %s`, test.key, value)
230 }
231
232 test.flags.assert(t, out)
233 })
234 }
235 }
236
237 var setCases = []struct {
238 name string
239 value interface{}
240 attr string
241 set interface{}
242 error bool
243 asString string
244 }{
245 {"nil", nil, "missing", "whatever", true, ""},
246 {"existing attr on struct by ref", &testStruct{"test"}, "Attr", "value", false, "value"},
247 {"existing attr on struct by value", testStruct{"test"}, "Attr", "value", true, `Can't write field "Attr"`},
248 {"missing attr on struct by ref", &testStruct{"test"}, "Missing", "value", true, "test"},
249 {"missing attr on struct by value", testStruct{"test"}, "Missing", "value", true, "test"},
250 {
251 "existing key on map",
252 map[string]interface{}{"Attr": "test"},
253 "Attr",
254 "value",
255 false,
256 "{'Attr': 'value'}",
257 },
258 {
259 "new key on map",
260 map[string]interface{}{"Attr": "test"},
261 "New",
262 "value",
263 false,
264 "{'Attr': 'test', 'New': 'value'}",
265 },
266 }
267
268 func TestValueSet(t *testing.T) {
269 for _, lc := range setCases {
270 test := lc
271 t.Run(test.name, func(t *testing.T) {
272 defer func() {
273 if err := recover(); err != nil {
274 t.Error(err)
275 }
276 }()
277 assert := assert.New(t)
278
279 value := exec.AsValue(test.value)
280 err := value.Set(test.attr, test.set)
281
282 if test.error {
283 assert.NotNil(err)
284 } else {
285 assert.Nil(err)
286 assert.Equal(test.asString, value.String())
287 }
288 })
289 }
290 }
291
292 var valueKeysCases = []struct {
293 name string
294 value interface{}
295 asString string
296 isError bool
297 }{
298 {"nil", nil, "", true},
299 {"string", "Hello World", "", true},
300 {"int", 42, "", true},
301 {"float", 42., "", true},
302 {"true", true, "", true},
303 {"false", false, "", true},
304 {"slice", []int{1, 2, 3}, "", true},
305
306 {"dict as map", map[string]string{"c": "c", "a": "a", "B": "B"}, "['a', 'B', 'c']", false},
307
308 {
309 "dict as Dict/Pairs",
310 &exec.Dict{[]*exec.Pair{
311 {exec.AsValue("c"), exec.AsValue("c")},
312 {exec.AsValue("A"), exec.AsValue("A")},
313 {exec.AsValue("b"), exec.AsValue("b")},
314 }},
315 "['c', 'A', 'b']",
316 false,
317 },
318 {"func", func() {}, "", true},
319 }
320
321 func TestValueKeys(t *testing.T) {
322 for _, lc := range valueKeysCases {
323 test := lc
324 t.Run(test.name, func(t *testing.T) {
325 defer func() {
326 if err := recover(); err != nil {
327 t.Error(err)
328 }
329 }()
330 assert := assert.New(t)
331
332 value := exec.AsValue(test.value)
333 keys := value.Keys()
334 if test.isError {
335 assert.Len(keys, 0)
336 } else {
337 assert.Equal(test.asString, keys.String())
338 }
339 })
340 }
341 }
342
View as plain text