github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/parse_expression_test.go (about) 1 package expressions 2 3 import ( 4 "testing" 5 6 "github.com/lmorg/murex/config/defaults" 7 "github.com/lmorg/murex/lang" 8 "github.com/lmorg/murex/lang/expressions/primitives" 9 "github.com/lmorg/murex/lang/expressions/symbols" 10 "github.com/lmorg/murex/test" 11 "github.com/lmorg/murex/test/count" 12 "github.com/lmorg/murex/utils/json" 13 ) 14 15 type expTestT struct { 16 input string 17 expected string 18 pos int 19 error bool 20 } 21 22 type expTestsT struct { 23 tests []expTestT 24 symbol symbols.Exp 25 } 26 27 func testParserSymbol(t *testing.T, tests expTestsT) { 28 t.Helper() 29 30 count.Tests(t, len(tests.tests)) 31 32 lang.InitEnv() 33 defaults.Config(lang.ShellProcess.Config, false) 34 p := lang.NewTestProcess() 35 p.Name.Set("(test)") 36 p.Config.Set("proc", "strict-vars", false, nil) 37 p.Config.Set("proc", "strict-arrays", false, nil) 38 39 for i, test := range tests.tests { 40 tree := NewParser(p, []rune(test.input), 0) 41 err := tree.parseExpression(true, true) 42 43 switch { 44 case (err != nil) != test.error: 45 t.Errorf("Error: %v", err) 46 t.Logf(" Test: %d", i) 47 t.Logf(" Expression: '%s'", test.input) 48 t.Logf(" exp symbol: '%s'", tests.symbol.String()) 49 continue 50 51 case test.error: 52 continue 53 54 case len(tree.ast) == 0: 55 t.Error("No ASTs generated:") 56 t.Logf(" Test: %d", i) 57 t.Logf(" Expression: '%s'", test.input) 58 t.Logf(" exp symbol: '%s'", tests.symbol.String()) 59 continue 60 61 case tree.ast[0].key != tests.symbol: 62 t.Error("Unexpected symbol:") 63 64 case tree.ast[0].Value() != test.expected: 65 t.Error("Expected doesn't match actual:") 66 67 case tree.ast[0].pos != test.pos: 68 t.Errorf("Pos doesn't match expected:") 69 70 default: 71 // success 72 continue 73 } 74 75 t.Logf(" Test: %d", i) 76 t.Logf(" Expression: '%s'", test.input) 77 t.Logf(" exp symbol: '%s'", tests.symbol.String()) 78 t.Logf(" act symbol: '%s'", tree.ast[0].key.String()) 79 t.Logf(" Expected: '%s'", test.expected) 80 t.Logf(" Actual: '%s'", tree.ast[0].Value()) 81 t.Logf(" act bytes: %v", tree.ast[0].value) 82 t.Logf(" Character pos (exp: %d, act: %d)", test.pos, tree.ast[0].pos) 83 } 84 } 85 86 func testParserObject(t *testing.T, tests expTestsT) { 87 t.Helper() 88 89 count.Tests(t, len(tests.tests)) 90 91 lang.InitEnv() 92 defaults.Config(lang.ShellProcess.Config, false) 93 p := lang.NewTestProcess() 94 p.Config.Set("proc", "strict-vars", false, nil) 95 p.Config.Set("proc", "strict-arrays", false, nil) 96 97 for i, test := range tests.tests { 98 tree := NewParser(p, []rune(test.input), 0) 99 err := tree.parseExpression(true, true) 100 var actVal string 101 var failed bool 102 103 switch { 104 case (err != nil) != test.error: 105 t.Errorf("Error: %v", err) 106 t.Logf(" Test: %d", i) 107 t.Logf(" Expression: '%s'", test.input) 108 t.Logf(" exp symbol: '%s'", tests.symbol.String()) 109 continue 110 111 case test.error: 112 continue 113 114 case len(tree.ast) == 0: 115 t.Error("No ASTs generated:") 116 t.Logf(" Test: %d", i) 117 t.Logf(" Expression: '%s'", test.input) 118 t.Logf(" exp symbol: '%s'", tests.symbol.String()) 119 continue 120 121 case tree.ast[0].key != tests.symbol: 122 t.Error("Unexpected symbol:") 123 failed = true 124 125 case tree.ast[0].pos != test.pos: 126 t.Errorf("Pos doesn't match expected:") 127 failed = true 128 129 default: 130 v, err := tree.ast[0].dt.GetValue() 131 if (err != nil) != test.error { 132 t.Errorf("Error: %v", err) 133 failed = true 134 } else { 135 actVal = json.LazyLogging(v.Value) 136 if actVal != test.expected { 137 t.Error("Expected doesn't match actual:") 138 failed = true 139 } 140 } 141 } 142 143 if failed { 144 t.Logf(" Test: %d", i) 145 t.Logf(" Expression: '%s'", test.input) 146 t.Logf(" exp symbol: '%s'", tests.symbol.String()) 147 t.Logf(" act symbol: '%s'", tree.ast[0].key.String()) 148 t.Logf(" Expected: '%s'", test.expected) 149 t.Logf(" Actual: '%s'", actVal) 150 t.Logf(" Character pos (exp: %d, act: %d)", test.pos, tree.ast[0].pos) 151 } 152 } 153 } 154 155 type expressionTestT struct { 156 Expression string 157 Expected any 158 Error bool 159 } 160 161 func testExpression(t *testing.T, tests []expressionTestT, strictTypes bool) { 162 t.Helper() 163 164 count.Tests(t, len(tests)) 165 166 lang.InitEnv() 167 defaults.Config(lang.ShellProcess.Config, false) 168 p := lang.NewTestProcess() 169 if err := p.Config.Set("proc", "strict-vars", false, nil); err != nil { 170 panic(err) 171 } 172 if err := p.Config.Set("proc", "strict-arrays", false, nil); err != nil { 173 panic(err) 174 } 175 if err := p.Config.Set("proc", "strict-types", strictTypes, nil); err != nil { 176 panic(err) 177 } 178 179 for i, test := range tests { 180 tree := NewParser(p, []rune(test.Expression), 0) 181 182 err := tree.parseExpression(true, true) 183 if err != nil { 184 t.Errorf("Parser error in test %d: %s", i, err.Error()) 185 continue 186 } 187 dt, err := tree.executeExpr() 188 var val *primitives.Value 189 190 switch { 191 default: 192 // success 193 continue 194 195 case (err != nil) != test.Error: 196 t.Error("tree.executeExpr() err != nil:") 197 198 case len(tree.ast) == 0: 199 t.Error("Empty AST tree produced:") 200 201 case dt != nil: 202 val, err = dt.GetValue() 203 switch { 204 default: 205 // success 206 continue 207 case (err != nil) != test.Error: 208 t.Error("dt.GetValue() err != nil:") 209 case val.Value != test.Expected: 210 t.Error("Result doesn't match expected:") 211 } 212 } 213 214 t.Logf(" Test: %d", i) 215 t.Logf(" Expression: '%s'", test.Expression) 216 t.Logf(" Expected: %s (%T)", json.LazyLogging(test.Expected), test.Expected) 217 t.Logf(" Actual: %s (%T)", json.LazyLogging(val.Value), val.Value) 218 t.Logf(" Struct: %v", json.LazyLogging(val)) 219 t.Logf(" exp error: %v", test.Error) 220 t.Logf(" Error: %v", err) 221 t.Logf(" Dump(): %s", json.LazyLoggingPretty(tree.Dump())) 222 t.Logf(" raw memory: %v", tree) 223 } 224 } 225 226 func TestParseExprLogicalAnd(t *testing.T) { 227 tests := []test.MurexTest{ 228 { 229 Block: "true == true && true == true", 230 Stdout: "true", 231 }, 232 { 233 Block: "true == false && true == true", 234 Stdout: "", 235 ExitNum: 1, 236 }, 237 } 238 239 test.RunMurexTests(tests, t) 240 }