github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/external_cmd_unix_internal_test.go (about)

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