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  }