github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/parse_switch_test.go (about)

     1  package expressions_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	_ "github.com/lmorg/murex/builtins"
     7  	"github.com/lmorg/murex/config/defaults"
     8  	"github.com/lmorg/murex/lang"
     9  	"github.com/lmorg/murex/lang/expressions"
    10  	"github.com/lmorg/murex/test/count"
    11  	"github.com/lmorg/murex/utils/home"
    12  	"github.com/lmorg/murex/utils/json"
    13  )
    14  
    15  type testParseSwitchT struct {
    16  	Expression string
    17  	Expected   []testParseSwitchNodeT
    18  	Error      bool
    19  }
    20  
    21  type testParseSwitchNodeT struct {
    22  	Condition  string
    23  	Parameters []string
    24  }
    25  
    26  func (t *testParseSwitchT) Json() string { return json.LazyLoggingPretty(t.Expected) }
    27  
    28  func runTestParseSwitch(t *testing.T, tests []testParseSwitchT) {
    29  	t.Helper()
    30  
    31  	count.Tests(t, len(tests))
    32  
    33  	lang.InitEnv()
    34  	defaults.Config(lang.ShellProcess.Config, false)
    35  
    36  	for i, test := range tests {
    37  		p := lang.NewTestProcess()
    38  		p.Name.Set(t.Name())
    39  		defaults.Config(p.Config, false)
    40  
    41  		if err := p.Config.Set("proc", "strict-vars", false, nil); err != nil {
    42  			panic(err)
    43  		}
    44  		if err := p.Config.Set("proc", "strict-arrays", false, nil); err != nil {
    45  			panic(err)
    46  		}
    47  		expSwitch, err := expressions.ParseSwitch(p, []rune(test.Expression))
    48  
    49  		if (err != nil) != test.Error {
    50  			t.Errorf("Unexpected mismatch in errors in test %d", i)
    51  			t.Logf("  Expression: '%s'", test.Expression)
    52  			t.Logf("  Expected:   %s", test.Json())
    53  			t.Logf("  err exp:    %v", test.Error)
    54  			t.Logf("  err act:    %v", err)
    55  			continue
    56  		}
    57  
    58  		var actual testParseSwitchT
    59  		for j := range expSwitch {
    60  			node := testParseSwitchNodeT{
    61  				Condition:  expSwitch[j].Condition,
    62  				Parameters: expSwitch[j].ParametersAll(),
    63  			}
    64  			actual.Expected = append(actual.Expected, node)
    65  		}
    66  
    67  		if test.Json() != actual.Json() {
    68  			t.Errorf("Expected does not match actual in test %d", i)
    69  			t.Logf("  Expression: '%s'", test.Expression)
    70  			t.Logf("  Expected:   %s", test.Json())
    71  			t.Logf("  Actual:     %s", actual.Json())
    72  			t.Logf("  err exp:    %v", test.Error)
    73  			t.Logf("  err act:    %v", err)
    74  		}
    75  	}
    76  }
    77  
    78  func TestParseSwitchBasic(t *testing.T) {
    79  	tests := []testParseSwitchT{
    80  		{
    81  			Expression: `case "foo" { bar }`,
    82  			Expected: []testParseSwitchNodeT{
    83  				{
    84  					Condition:  "case",
    85  					Parameters: []string{"foo", "{ bar }"},
    86  				},
    87  			},
    88  		},
    89  		{
    90  			Expression: `if "foo" { bar }`,
    91  			Expected: []testParseSwitchNodeT{
    92  				{
    93  					Condition:  "if",
    94  					Parameters: []string{"foo", "{ bar }"},
    95  				},
    96  			},
    97  		},
    98  		{
    99  			Expression: `case "foo" then { bar }`,
   100  			Expected: []testParseSwitchNodeT{
   101  				{
   102  					Condition:  "case",
   103  					Parameters: []string{"foo", "then", "{ bar }"},
   104  				},
   105  			},
   106  		},
   107  		{
   108  			Expression: `if "foo" then { bar }`,
   109  			Expected: []testParseSwitchNodeT{
   110  				{
   111  					Condition:  "if",
   112  					Parameters: []string{"foo", "then", "{ bar }"},
   113  				},
   114  			},
   115  		},
   116  		{
   117  			Expression: `default { bar }`,
   118  			Expected: []testParseSwitchNodeT{
   119  				{
   120  					Condition:  "default",
   121  					Parameters: []string{"{ bar }"},
   122  				},
   123  			},
   124  		},
   125  		{
   126  			Expression: `if:"foo" {bar}`,
   127  			Expected: []testParseSwitchNodeT{
   128  				{
   129  					Condition:  "if",
   130  					Parameters: []string{"foo", "{bar}"},
   131  				},
   132  			},
   133  		},
   134  	}
   135  
   136  	runTestParseSwitch(t, tests)
   137  }
   138  
   139  func TestParseSwitchQuotes(t *testing.T) {
   140  	tests := []testParseSwitchT{
   141  		{
   142  			Expression: `case 'foo'`,
   143  			Expected: []testParseSwitchNodeT{
   144  				{
   145  					Condition:  "case",
   146  					Parameters: []string{"foo"},
   147  				},
   148  			},
   149  		},
   150  		{
   151  			Expression: `case "foo"`,
   152  			Expected: []testParseSwitchNodeT{
   153  				{
   154  					Condition:  "case",
   155  					Parameters: []string{"foo"},
   156  				},
   157  			},
   158  		},
   159  		{
   160  			Expression: `case (foo)`,
   161  			Expected: []testParseSwitchNodeT{
   162  				{
   163  					Condition:  "case",
   164  					Parameters: []string{"foo"},
   165  				},
   166  			},
   167  		},
   168  		{
   169  			Expression: `case (f(o)o)`,
   170  			Expected: []testParseSwitchNodeT{
   171  				{
   172  					Condition:  "case",
   173  					Parameters: []string{"f(o)o"},
   174  				},
   175  			},
   176  		},
   177  	}
   178  
   179  	runTestParseSwitch(t, tests)
   180  }
   181  
   182  func TestParseSwitchMultiStatement(t *testing.T) {
   183  	tests := []testParseSwitchT{
   184  		{
   185  			Expression: `if "a" { b }; case "c" { d }; default { e }`,
   186  			Expected: []testParseSwitchNodeT{
   187  				{
   188  					Condition:  "if",
   189  					Parameters: []string{"a", "{ b }"},
   190  				},
   191  				{
   192  					Condition:  "case",
   193  					Parameters: []string{"c", "{ d }"},
   194  				},
   195  				{
   196  					Condition:  "default",
   197  					Parameters: []string{"{ e }"},
   198  				},
   199  			},
   200  		},
   201  		{
   202  			Expression: `
   203  				if "a" { b }
   204  				case "c" { d }
   205  				default { e }
   206  			`,
   207  			Expected: []testParseSwitchNodeT{
   208  				{
   209  					Condition:  "if",
   210  					Parameters: []string{"a", "{ b }"},
   211  				},
   212  				{
   213  					Condition:  "case",
   214  					Parameters: []string{"c", "{ d }"},
   215  				},
   216  				{
   217  					Condition:  "default",
   218  					Parameters: []string{"{ e }"},
   219  				},
   220  			},
   221  		},
   222  	}
   223  
   224  	runTestParseSwitch(t, tests)
   225  }
   226  
   227  func TestParseSwitchEscape(t *testing.T) {
   228  	tests := []testParseSwitchT{
   229  		{
   230  			Expression: `case \s { bar }`,
   231  			Expected: []testParseSwitchNodeT{
   232  				{
   233  					Condition:  "case",
   234  					Parameters: []string{" ", "{ bar }"},
   235  				},
   236  			},
   237  		},
   238  		{
   239  			Expression: `case \t { bar }`,
   240  			Expected: []testParseSwitchNodeT{
   241  				{
   242  					Condition:  "case",
   243  					Parameters: []string{"\t", "{ bar }"},
   244  				},
   245  			},
   246  		},
   247  		{
   248  			Expression: `case \r { bar }`,
   249  			Expected: []testParseSwitchNodeT{
   250  				{
   251  					Condition:  "case",
   252  					Parameters: []string{"\r", "{ bar }"},
   253  				},
   254  			},
   255  		},
   256  		{
   257  			Expression: `case \n { bar }`,
   258  			Expected: []testParseSwitchNodeT{
   259  				{
   260  					Condition:  "case",
   261  					Parameters: []string{"\n", "{ bar }"},
   262  				},
   263  			},
   264  		},
   265  		{
   266  			Expression: `case \q { bar }`,
   267  			Expected: []testParseSwitchNodeT{
   268  				{
   269  					Condition:  "case",
   270  					Parameters: []string{"q", "{ bar }"},
   271  				},
   272  			},
   273  		},
   274  		{
   275  			Expression: `case \\ { bar }`,
   276  			Expected: []testParseSwitchNodeT{
   277  				{
   278  					Condition:  "case",
   279  					Parameters: []string{"\\", "{ bar }"},
   280  				},
   281  			},
   282  		},
   283  	}
   284  
   285  	runTestParseSwitch(t, tests)
   286  }
   287  
   288  func TestParseSwitchComments(t *testing.T) {
   289  	tests := []testParseSwitchT{
   290  		{
   291  			Expression: `
   292  				case 1 { a }
   293  				# case 2 { b }
   294  				case 3 { c }`,
   295  			Expected: []testParseSwitchNodeT{
   296  				{
   297  					Condition:  "case",
   298  					Parameters: []string{"1", "{ a }"},
   299  				},
   300  				{
   301  					Condition:  "case",
   302  					Parameters: []string{"3", "{ c }"},
   303  				},
   304  			},
   305  		},
   306  		{
   307  			Expression: `
   308  				case 1 { a }
   309  				/# case 2 { b } #/
   310  				case 3 { c }`,
   311  			Expected: []testParseSwitchNodeT{
   312  				{
   313  					Condition:  "case",
   314  					Parameters: []string{"1", "{ a }"},
   315  				},
   316  				{
   317  					Condition:  "case",
   318  					Parameters: []string{"3", "{ c }"},
   319  				},
   320  			},
   321  		},
   322  		{
   323  			Expression: `case 1 /#2#/ 3 { a }`,
   324  			Expected: []testParseSwitchNodeT{
   325  				{
   326  					Condition:  "case",
   327  					Parameters: []string{"1", "3", "{ a }"},
   328  				},
   329  			},
   330  		},
   331  	}
   332  
   333  	runTestParseSwitch(t, tests)
   334  }
   335  
   336  func TestParseSwitchVariables(t *testing.T) {
   337  	tests := []testParseSwitchT{
   338  		{
   339  			Expression: `case $foo { $bar }`,
   340  			Expected: []testParseSwitchNodeT{
   341  				{
   342  					Condition:  "case",
   343  					Parameters: []string{"", "{ $bar }"},
   344  				},
   345  			},
   346  		},
   347  		{
   348  			Expression: `case @foo { $bar }`,
   349  			Expected: []testParseSwitchNodeT{
   350  				{
   351  					Condition:  "case",
   352  					Parameters: []string{"{ $bar }"},
   353  				},
   354  			},
   355  		},
   356  		{
   357  			Expression: `case ~ { ~ }`,
   358  			Expected: []testParseSwitchNodeT{
   359  				{
   360  					Condition:  "case",
   361  					Parameters: []string{home.MyDir, "{ ~ }"},
   362  				},
   363  			},
   364  		},
   365  	}
   366  
   367  	runTestParseSwitch(t, tests)
   368  }
   369  
   370  func TestParseSwitchSubshells(t *testing.T) {
   371  	tests := []testParseSwitchT{
   372  		{
   373  			Expression: `case ${out foo} { $bar }`,
   374  			Expected: []testParseSwitchNodeT{
   375  				{
   376  					Condition:  "case",
   377  					Parameters: []string{"foo", "{ $bar }"},
   378  				},
   379  			},
   380  		},
   381  		{
   382  			Expression: `case @{ja: [1..3]} { ~ }`,
   383  			Expected: []testParseSwitchNodeT{
   384  				{
   385  					Condition:  "case",
   386  					Parameters: []string{"1", "2", "3", "{ ~ }"},
   387  				},
   388  			},
   389  		},
   390  	}
   391  
   392  	runTestParseSwitch(t, tests)
   393  }
   394  
   395  func TestParseSwitchCreators(t *testing.T) {
   396  	tests := []testParseSwitchT{
   397  		{
   398  			Expression: `case %(foo) { bar }`,
   399  			Expected: []testParseSwitchNodeT{
   400  				{
   401  					Condition:  "case",
   402  					Parameters: []string{"foo", "{ bar }"},
   403  				},
   404  			},
   405  		},
   406  		{
   407  			Expression: `case %[1 2 3] { bar }`,
   408  			Expected: []testParseSwitchNodeT{
   409  				{
   410  					Condition:  "case",
   411  					Parameters: []string{"[1,2,3]", "{ bar }"},
   412  				},
   413  			},
   414  		},
   415  		{
   416  			Expression: `case %{a:1, b:2, c:3} { bar }`,
   417  			Expected: []testParseSwitchNodeT{
   418  				{
   419  					Condition:  "case",
   420  					Parameters: []string{`{"a":1,"b":2,"c":3}`, "{ bar }"},
   421  				},
   422  			},
   423  		},
   424  	}
   425  
   426  	runTestParseSwitch(t, tests)
   427  }