1 package gval
2
3 import (
4 "context"
5 "fmt"
6 "reflect"
7 "testing"
8 )
9
10 func Test_Infix(t *testing.T) {
11 type subTest struct {
12 name string
13 a interface{}
14 b interface{}
15 wantRet interface{}
16 }
17 tests := []struct {
18 name string
19 infix
20 subTests []subTest
21 }{
22 {
23 "number operator",
24 infix{
25 number: func(a, b float64) (interface{}, error) { return a * b, nil },
26 },
27 []subTest{
28 {"float64 arguments", 7., 3., 21.},
29 {"int arguments", 7, 3, 21.},
30 {"string arguments", "7", "3.", 21.},
31 },
32 },
33 {
34 "number and string operator",
35 infix{
36 number: func(a, b float64) (interface{}, error) { return a + b, nil },
37 text: func(a, b string) (interface{}, error) { return fmt.Sprintf("%v%v", a, b), nil },
38 },
39
40 []subTest{
41 {"float64 arguments", 7., 3., 10.},
42 {"int arguments", 7, 3, 10.},
43 {"number string arguments", "7", "3.", "73."},
44 {"string arguments", "hello ", "world", "hello world"},
45 },
46 },
47 {
48 "bool operator",
49 infix{
50 shortCircuit: func(a interface{}) (interface{}, bool) { return false, a == false },
51 boolean: func(a, b bool) (interface{}, error) { return a && b, nil },
52 },
53
54 []subTest{
55 {"bool arguments", false, true, false},
56 {"number arguments", 0, true, false},
57 {"lower string arguments", "false", "true", false},
58 {"upper string arguments", "TRUE", "FALSE", false},
59 {"shortCircuit", false, "not a boolean", false},
60 },
61 },
62 {
63 "bool, number, text and interface operator",
64 infix{
65 number: func(a, b float64) (interface{}, error) { return a == b, nil },
66 boolean: func(a, b bool) (interface{}, error) { return a == b, nil },
67 text: func(a, b string) (interface{}, error) { return a == b, nil },
68 arbitrary: func(a, b interface{}) (interface{}, error) { return a == b, nil },
69 },
70
71 []subTest{
72 {"number string and int arguments", "7", 7, true},
73 {"bool string and bool arguments", "true", true, true},
74 {"string arguments", "hello", "hello", true},
75 {"upper string arguments", "TRUE", "FALSE", false},
76 },
77 },
78 }
79 for _, tt := range tests {
80 t.Run(tt.name, func(t *testing.T) {
81 tt.infix.initiate("<" + tt.name + ">")
82 builder := tt.infix.builder
83 for _, tt := range tt.subTests {
84 t.Run(tt.name, func(t *testing.T) {
85 eval, err := builder(constant(tt.a), constant(tt.b))
86 if err != nil {
87 t.Fatal(err)
88 }
89
90 got, err := eval(context.Background(), nil)
91 if err != nil {
92 t.Fatal(err)
93 }
94
95 if !reflect.DeepEqual(got, tt.wantRet) {
96 t.Fatalf("binaryOperator() eval() = %v, want %v", got, tt.wantRet)
97 }
98 })
99 }
100 })
101 }
102 }
103
104 func Test_stageStack_push(t *testing.T) {
105 p := (*Parser)(nil)
106 tests := []struct {
107 name string
108 pres []operatorPrecedence
109 expect string
110 }{
111 {
112 "flat",
113 []operatorPrecedence{1, 1, 1, 1},
114 "((((AB)C)D)E)",
115 },
116 {
117 "asc",
118 []operatorPrecedence{1, 2, 3, 4},
119 "(A(B(C(DE))))",
120 },
121 {
122 "desc",
123 []operatorPrecedence{4, 3, 2, 1},
124 "((((AB)C)D)E)",
125 },
126 {
127 "mixed",
128 []operatorPrecedence{1, 2, 1, 1},
129 "(((A(BC))D)E)",
130 },
131 }
132 for _, tt := range tests {
133 t.Run(tt.name, func(t *testing.T) {
134 X := int('A')
135
136 op := func(a, b Evaluable) (Evaluable, error) {
137 return func(c context.Context, o interface{}) (interface{}, error) {
138 aa, _ := a.EvalString(c, nil)
139 bb, _ := b.EvalString(c, nil)
140 s := "(" + aa + bb + ")"
141 return s, nil
142 }, nil
143 }
144 stack := stageStack{}
145 for _, pre := range tt.pres {
146 if err := stack.push(stage{p.Const(string(rune(X))), op, pre}); err != nil {
147 t.Fatal(err)
148 }
149 X++
150 }
151
152 if err := stack.push(stage{p.Const(string(rune(X))), nil, 0}); err != nil {
153 t.Fatal(err)
154 }
155
156 if len(stack) != 1 {
157 t.Fatalf("stack must hold exactly one element")
158 }
159
160 got, _ := stack[0].EvalString(context.Background(), nil)
161 if got != tt.expect {
162 t.Fatalf("got %s but expected %s", got, tt.expect)
163 }
164 })
165 }
166 }
167
View as plain text