src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/external_cmd_unix_internal_test.go (about)

     1  //go:build unix
     2  
     3  package eval
     4  
     5  import (
     6  	"os"
     7  	"reflect"
     8  	"syscall"
     9  	"testing"
    10  
    11  	"src.elv.sh/pkg/env"
    12  	"src.elv.sh/pkg/parse"
    13  	"src.elv.sh/pkg/testutil"
    14  )
    15  
    16  func TestExec_Argv0Argv(t *testing.T) {
    17  	dir := testutil.InTempDir(t)
    18  	testutil.ApplyDir(testutil.Dir{
    19  		"bin": testutil.Dir{
    20  			"elvish": testutil.File{Perm: 0755},
    21  			"cat":    testutil.File{Perm: 0755},
    22  		},
    23  	})
    24  
    25  	testutil.Setenv(t, "PATH", dir+"/bin")
    26  	testutil.Setenv(t, env.SHLVL, "1")
    27  
    28  	var tests = []struct {
    29  		name      string
    30  		code      string
    31  		wantArgv0 string
    32  		wantArgv  []string
    33  		wantError bool
    34  	}{
    35  		{
    36  			name:      "absolute path command",
    37  			code:      "exec /bin/sh foo bar",
    38  			wantArgv0: "/bin/sh",
    39  			wantArgv:  []string{"/bin/sh", "foo", "bar"},
    40  		},
    41  		{
    42  			name:      "relative path command",
    43  			code:      "exec cat foo bar",
    44  			wantArgv0: dir + "/bin/cat",
    45  			wantArgv:  []string{dir + "/bin/cat", "foo", "bar"},
    46  		},
    47  		{
    48  			name:      "no command",
    49  			code:      "exec",
    50  			wantArgv0: dir + "/bin/elvish",
    51  			wantArgv:  []string{dir + "/bin/elvish"},
    52  		},
    53  		{
    54  			name:      "bad command",
    55  			code:      "exec bad",
    56  			wantError: true,
    57  		},
    58  	}
    59  
    60  	for _, test := range tests {
    61  		t.Run(test.name, func(t *testing.T) {
    62  			t.Helper()
    63  			var (
    64  				gotArgv0 string
    65  				gotArgv  []string
    66  			)
    67  			syscallExec = func(argv0 string, argv []string, envv []string) error {
    68  				gotArgv0 = argv0
    69  				gotArgv = argv
    70  				return nil
    71  			}
    72  			defer func() { syscallExec = syscall.Exec }()
    73  
    74  			ev := NewEvaler()
    75  			err := ev.Eval(parse.Source{Name: "[test]", Code: test.code}, EvalCfg{})
    76  
    77  			if gotArgv0 != test.wantArgv0 {
    78  				t.Errorf("got argv0 %q, want %q", gotArgv0, test.wantArgv0)
    79  			}
    80  			if !reflect.DeepEqual(gotArgv, test.wantArgv) {
    81  				t.Errorf("got argv %q, want %q", gotArgv, test.wantArgv)
    82  			}
    83  			hasError := err != nil
    84  			if hasError != test.wantError {
    85  				t.Errorf("has error %v, want %v", hasError, test.wantError)
    86  			}
    87  		})
    88  	}
    89  }
    90  
    91  func TestDecSHLVL(t *testing.T) {
    92  	// Valid integers are decremented, regardless of sign
    93  	testDecSHLVL(t, "-2", "-3")
    94  	testDecSHLVL(t, "-1", "-2")
    95  	testDecSHLVL(t, "0", "-1")
    96  	testDecSHLVL(t, "1", "0")
    97  	testDecSHLVL(t, "2", "1")
    98  	testDecSHLVL(t, "3", "2")
    99  
   100  	// Non-integers are kept unchanged
   101  	testDecSHLVL(t, "", "")
   102  	testDecSHLVL(t, "x", "x")
   103  }
   104  
   105  func testDecSHLVL(t *testing.T, oldValue, newValue string) {
   106  	t.Helper()
   107  	testutil.Setenv(t, env.SHLVL, oldValue)
   108  
   109  	decSHLVL()
   110  	if gotValue := os.Getenv(env.SHLVL); gotValue != newValue {
   111  		t.Errorf("got new value %q, want %q", gotValue, newValue)
   112  	}
   113  }