github.com/CiscoM31/godata@v1.0.10/parser_test.go (about) 1 package godata 2 3 import ( 4 "context" 5 "strconv" 6 "testing" 7 ) 8 9 func TestPEMDAS(t *testing.T) { 10 ctx := context.Background() 11 parser := EmptyParser() 12 parser.DefineFunction("sin", []int{1}, false) 13 parser.DefineFunction("max", []int{2}, false) 14 parser.DefineOperator("^", 2, OpAssociationRight, 5) 15 parser.DefineOperator("*", 2, OpAssociationLeft, 5) 16 parser.DefineOperator("/", 2, OpAssociationLeft, 5) 17 parser.DefineOperator("+", 2, OpAssociationLeft, 4) 18 parser.DefineOperator("-", 2, OpAssociationLeft, 4) 19 20 // 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3 21 tokens := []*Token{ 22 {Value: "3"}, 23 {Value: "+"}, 24 {Value: "4"}, 25 {Value: "*"}, 26 {Value: "2"}, 27 {Value: "/"}, 28 {Value: "("}, 29 {Value: "1"}, 30 {Value: "-"}, 31 {Value: "5"}, 32 {Value: ")"}, 33 {Value: "^"}, 34 {Value: "2"}, 35 {Value: "^"}, 36 {Value: "3"}, 37 } 38 39 // 3 4 2 * 1 5 - 2 3 ^ ^ / + 40 expected := []string{"3", "4", "2", "*", "1", "5", "-", "2", "3", "^", "^", 41 "/", "+"} 42 43 result, err := parser.InfixToPostfix(ctx, tokens) 44 45 if err != nil { 46 t.Error(err) 47 return 48 } 49 50 for i, v := range expected { 51 if result.Empty() { 52 t.Error("Output is not the expected length.") 53 return 54 } 55 56 token := result.Dequeue() 57 if v != token.Value { 58 t.Error("Expected " + v + " at index " + strconv.Itoa(i) + " got " + 59 token.Value) 60 } 61 } 62 } 63 64 func BenchmarkPEMDAS(b *testing.B) { 65 ctx := context.Background() 66 parser := EmptyParser() 67 parser.DefineFunction("sin", []int{1}, false) 68 parser.DefineFunction("max", []int{2}, false) 69 parser.DefineOperator("^", 2, OpAssociationRight, 5) 70 parser.DefineOperator("*", 2, OpAssociationLeft, 5) 71 parser.DefineOperator("/", 2, OpAssociationLeft, 5) 72 parser.DefineOperator("+", 2, OpAssociationLeft, 4) 73 parser.DefineOperator("-", 2, OpAssociationLeft, 4) 74 75 // 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3 76 tokens := []*Token{ 77 {Value: "3"}, 78 {Value: "+"}, 79 {Value: "4"}, 80 {Value: "*"}, 81 {Value: "2"}, 82 {Value: "/"}, 83 {Value: "("}, 84 {Value: "1"}, 85 {Value: "-"}, 86 {Value: "5"}, 87 {Value: ")"}, 88 {Value: "^"}, 89 {Value: "2"}, 90 {Value: "^"}, 91 {Value: "3"}, 92 } 93 94 for i := 0; i < b.N; i++ { 95 if _, err := parser.InfixToPostfix(ctx, tokens); err != nil { 96 b.Fatalf("Failed to transform tokens from infix to postfix: %v", err) 97 } 98 } 99 } 100 101 func TestBoolean(t *testing.T) { 102 ctx := context.Background() 103 parser := EmptyParser() 104 parser.DefineOperator("NOT", 1, OpAssociationNone, 3) 105 parser.DefineOperator("AND", 2, OpAssociationLeft, 2) 106 parser.DefineOperator("OR", 2, OpAssociationLeft, 1) 107 108 // (A OR NOT B) AND C OR B 109 tokens := []*Token{ 110 {Value: "("}, 111 {Value: "A"}, 112 {Value: "OR"}, 113 {Value: "NOT"}, 114 {Value: "B"}, 115 {Value: ")"}, 116 {Value: "AND"}, 117 {Value: "C"}, 118 {Value: "OR"}, 119 {Value: "B"}, 120 } 121 122 // A B NOT OR C AND B OR 123 expected := []string{"A", "B", "NOT", "OR", "C", "AND", "B", "OR"} 124 result, err := parser.InfixToPostfix(ctx, tokens) 125 126 if err != nil { 127 t.Error(err) 128 return 129 } 130 131 for i, v := range expected { 132 if result.Empty() { 133 t.Error("Output is not the expected length.") 134 return 135 } 136 137 token := result.Dequeue() 138 if v != token.Value { 139 t.Error("Expected " + v + " at index " + strconv.Itoa(i) + " got " + 140 token.Value) 141 } 142 } 143 } 144 145 func TestFunc(t *testing.T) { 146 ctx := context.Background() 147 parser := EmptyParser() 148 parser.DefineFunction("sin", []int{1}, false) 149 parser.DefineFunction("max", []int{2}, false) 150 parser.DefineFunction("volume", []int{3}, false) 151 parser.DefineOperator("^", 2, OpAssociationRight, 5) 152 parser.DefineOperator("*", 2, OpAssociationLeft, 5) 153 parser.DefineOperator("/", 2, OpAssociationLeft, 5) 154 parser.DefineOperator("+", 2, OpAssociationLeft, 4) 155 parser.DefineOperator("-", 2, OpAssociationLeft, 4) 156 157 // max(sin(5*pi)+3, sin(5)+volume(3,2,4)/[]int{3}) 158 tokens := []*Token{ 159 {Value: "max"}, 160 {Value: "("}, 161 {Value: "sin"}, 162 {Value: "("}, 163 {Value: "5"}, 164 {Value: "*"}, 165 {Value: "pi"}, 166 {Value: ")"}, 167 {Value: "+"}, 168 {Value: "3"}, 169 {Value: ","}, 170 {Value: "sin"}, 171 {Value: "("}, 172 {Value: "5"}, 173 {Value: ")"}, 174 {Value: "+"}, 175 {Value: "volume"}, 176 {Value: "("}, 177 {Value: "3"}, 178 {Value: ","}, 179 {Value: "2"}, 180 {Value: ","}, 181 {Value: "4"}, 182 {Value: ")"}, 183 {Value: "/"}, 184 {Value: "2"}, 185 {Value: ")"}, 186 } 187 188 // 5 pi * sin 3 + 5 sin 3 2 4 volume 2 / + max 189 expected := []string{ 190 "5", "pi", "*", "1" /* arg count */, "list", /* list expression */ 191 "sin", "3", "+", "5", "1" /* arg count */, "list", /* list expression */ 192 "sin", "3", "2", "4", "3" /* arg count */, "list", /* list expression */ 193 "volume", "2", 194 "/", "+", 195 "2" /* arg count */, "list" /* list expression */, "max"} 196 result, err := parser.InfixToPostfix(ctx, tokens) 197 198 if err != nil { 199 t.Error(err) 200 return 201 } 202 203 for i, v := range expected { 204 if result.Empty() { 205 t.Error("Output is not the expected length.") 206 return 207 } 208 209 token := result.Dequeue() 210 if v != token.Value { 211 t.Errorf("Expected %v at index %d got %v", v, i, token.Value) 212 } 213 } 214 } 215 216 func TestTree(t *testing.T) { 217 ctx := context.Background() 218 parser := EmptyParser() 219 parser.DefineFunction("sin", []int{1}, false) 220 parser.DefineFunction("max", []int{2}, false) 221 parser.DefineOperator("^", 2, OpAssociationRight, 5) 222 parser.DefineOperator("*", 2, OpAssociationLeft, 5) 223 parser.DefineOperator("/", 2, OpAssociationLeft, 5) 224 parser.DefineOperator("+", 2, OpAssociationLeft, 4) 225 parser.DefineOperator("-", 2, OpAssociationLeft, 4) 226 227 // sin ( max ( 2, 3 ) / 3 * 3.1415 ) 228 tokens := []*Token{ 229 {Value: "sin"}, 230 {Value: "("}, 231 {Value: "max"}, 232 {Value: "("}, 233 {Value: "2"}, 234 {Value: ","}, 235 {Value: "3"}, 236 {Value: ")"}, 237 {Value: "/"}, 238 {Value: "3"}, 239 {Value: "*"}, 240 {Value: "pi"}, 241 {Value: ")"}, 242 } 243 244 // 2 3 max 3 / 3.1415 * sin 245 result, err := parser.InfixToPostfix(ctx, tokens) 246 if err != nil { 247 t.Fatal(err) 248 } 249 250 root, err := parser.PostfixToTree(ctx, result) 251 if err != nil { 252 t.Fatalf("Error parsing query: %v", err) 253 } 254 if root.Token.Value != "sin" { 255 t.Error("Root node is not sin") 256 } 257 if root.Children[0].Token.Value != "*" { 258 t.Error("Level 2 node is not *") 259 } 260 if root.Children[0].Children[1].Token.Value != "pi" { 261 t.Error("Level 3 right node is not pi", root.Children[0].Children[1].Token.Value) 262 } 263 if root.Children[0].Children[0].Token.Value != "/" { 264 t.Error("Level 3 left node is not /", root.Children[0].Children[0].Token.Value) 265 } 266 if root.Children[0].Children[0].Children[1].Token.Value != "3" { 267 t.Error("Level 4 right node is not 3", root.Children[0].Children[0].Children[1].Token.Value) 268 } 269 if root.Children[0].Children[0].Children[0].Token.Value != "max" { 270 t.Error("Level 4 left node is not max", root.Children[0].Children[0].Children[0].Token.Value) 271 } 272 if root.Children[0].Children[0].Children[0].Children[0].Token.Value != "2" { 273 t.Error("Level 5 ieft node is not 2", root.Children[0].Children[0].Children[0].Children[0].Token.Value) 274 } 275 if root.Children[0].Children[0].Children[0].Children[1].Token.Value != "3" { 276 t.Error("Level 5 right node is not 3", root.Children[0].Children[0].Children[0].Children[1].Token.Value) 277 } 278 } 279 280 func BenchmarkBuildTree(b *testing.B) { 281 ctx := context.Background() 282 parser := EmptyParser() 283 parser.DefineFunction("sin", []int{1}, false) 284 parser.DefineFunction("max", []int{2}, false) 285 parser.DefineOperator("^", 2, OpAssociationRight, 5) 286 parser.DefineOperator("*", 2, OpAssociationLeft, 5) 287 parser.DefineOperator("/", 2, OpAssociationLeft, 5) 288 parser.DefineOperator("+", 2, OpAssociationLeft, 4) 289 parser.DefineOperator("-", 2, OpAssociationLeft, 4) 290 291 // sin ( max ( 2, 3 ) / 3 * 3.1415 ) 292 tokens := []*Token{ 293 {Value: "sin"}, 294 {Value: "("}, 295 {Value: "max"}, 296 {Value: "("}, 297 {Value: "2"}, 298 {Value: ","}, 299 {Value: "3"}, 300 {Value: ")"}, 301 {Value: "/"}, 302 {Value: "3"}, 303 {Value: "*"}, 304 {Value: "pi"}, 305 {Value: ")"}, 306 } 307 308 // 2 3 max 3 / 3.1415 * sin 309 for i := 0; i < b.N; i++ { 310 result, _ := parser.InfixToPostfix(ctx, tokens) 311 if _, err := parser.PostfixToTree(ctx, result); err != nil { 312 b.Fatalf("Failed to transform tokens: %v", err) 313 } 314 } 315 }