github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/shellwords/shellwords_test.go (about)

     1  package shellwords
     2  
     3  import (
     4  	"go/build"
     5  	"os"
     6  	"path"
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/spf13/pflag"
    11  	"github.com/stretchr/testify/assert"
    12  )
    13  
    14  func TestParseMySQLCli(t *testing.T) {
    15  	p := NewParser()
    16  	p.ParseEnv = true
    17  	s := `--MYSQL_PWD="! 8BE4" --mysql --host="127.0.0.1" -P 9633 -u 'root'`
    18  	args, err := p.Parse(s)
    19  
    20  	assert.Nil(t, err)
    21  	assert.Equal(t, []string{"--MYSQL_PWD=! 8BE4", "--mysql", "--host=127.0.0.1", "-P", "9633", "-u", "root"}, args)
    22  
    23  	pf := pflag.NewFlagSet("ds", pflag.ExitOnError)
    24  
    25  	pf.BoolP("mysql", "", false, "mysql command")
    26  	pf.StringP("MYSQL_PWD", "", "", "MYSQL_PWD env password")
    27  	pf.StringP("database", "D", "", "Database to use")
    28  	pf.StringP("host", "h", "", "Connect to host")
    29  	pf.IntP("port", "P", 3306, "Port number to use")
    30  	pf.StringP("user", "u", "", "User for login if not current user")
    31  	pf.StringP("password", "p", "", "Password to use when connecting to serve")
    32  
    33  	err = pf.Parse(args)
    34  	assert.Nil(t, err)
    35  
    36  	host, _ := pf.GetString("host")
    37  	assert.Equal(t, "127.0.0.1", host)
    38  
    39  	port, _ := pf.GetInt("port")
    40  	assert.Equal(t, 9633, port)
    41  
    42  	user, _ := pf.GetString("user")
    43  	assert.Equal(t, "root", user)
    44  
    45  	db, _ := pf.GetString("database")
    46  	assert.Equal(t, "", db)
    47  
    48  	password, _ := pf.GetString("password")
    49  	if password == "" {
    50  		password, _ = pf.GetString("MYSQL_PWD")
    51  	}
    52  
    53  	assert.Equal(t, "! 8BE4", password)
    54  }
    55  
    56  // nolint gochecknoglobals
    57  var testcases = []struct {
    58  	line     string
    59  	expected []string
    60  }{
    61  	{``, []string{}},
    62  	{`""`, []string{``}},
    63  	{`''`, []string{``}},
    64  	{`var --bar=baz`, []string{`var`, `--bar=baz`}},
    65  	{`var --bar="baz"`, []string{`var`, `--bar=baz`}},
    66  	{`var "--bar=baz"`, []string{`var`, `--bar=baz`}},
    67  	{`var "--bar='baz'"`, []string{`var`, `--bar='baz'`}},
    68  	{"var --bar=`baz`", []string{`var`, "--bar=`baz`"}},
    69  	{`var "--bar=\"baz'"`, []string{`var`, `--bar="baz'`}},
    70  	{`var "--bar=\'baz\'"`, []string{`var`, `--bar='baz'`}},
    71  	{`var --bar='\'`, []string{`var`, `--bar=\`}},
    72  	{`var "--bar baz"`, []string{`var`, `--bar baz`}},
    73  	{`var --"bar baz"`, []string{`var`, `--bar baz`}},
    74  	{`var  --"bar baz"`, []string{`var`, `--bar baz`}},
    75  	{`a "b"`, []string{`a`, `b`}},
    76  	{`a " b "`, []string{`a`, ` b `}},
    77  	{`a "   "`, []string{`a`, `   `}},
    78  	{`a 'b'`, []string{`a`, `b`}},
    79  	{`a ' b '`, []string{`a`, ` b `}},
    80  	{`a '   '`, []string{`a`, `   `}},
    81  	{"foo bar\\  ", []string{`foo`, `bar `}},
    82  	{`foo "" bar ''`, []string{`foo`, ``, `bar`, ``}},
    83  }
    84  
    85  func TestSimple(t *testing.T) {
    86  	for _, testcase := range testcases {
    87  		args, err := Parse(testcase.line)
    88  		if err != nil {
    89  			t.Fatal(err)
    90  		}
    91  
    92  		if !reflect.DeepEqual(args, testcase.expected) {
    93  			t.Fatalf("Expected %#v for %q, but %#v:", testcase.expected, testcase.line, args)
    94  		}
    95  	}
    96  }
    97  
    98  func TestError(t *testing.T) {
    99  	_, err := Parse("foo '")
   100  	if err == nil {
   101  		t.Fatal("Should be an error")
   102  	}
   103  
   104  	_, err = Parse(`foo "`)
   105  
   106  	if err == nil {
   107  		t.Fatal("Should be an error")
   108  	}
   109  
   110  	_, err = Parse("foo `")
   111  	if err == nil {
   112  		t.Fatal("Should be an error")
   113  	}
   114  }
   115  
   116  func TestShellRun(t *testing.T) {
   117  	dir, err := os.Getwd()
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	pwd, err := shellRun("pwd", "")
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  
   127  	pwd2, err := shellRun("pwd", path.Join(dir, "/testdata"))
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  
   132  	if pwd == pwd2 {
   133  		t.Fatal("`pwd` should be changed")
   134  	}
   135  }
   136  
   137  func TestShellRunNoEnv(t *testing.T) {
   138  	old := os.Getenv("SHELL")
   139  	defer os.Setenv("SHELL", old)
   140  	os.Unsetenv("SHELL")
   141  
   142  	dir, err := os.Getwd()
   143  	if err != nil {
   144  		t.Fatal(err)
   145  	}
   146  
   147  	pwd, err := shellRun("pwd", "")
   148  	if err != nil {
   149  		t.Fatal(err)
   150  	}
   151  
   152  	pwd2, err := shellRun("pwd", path.Join(dir, "/testdata"))
   153  	if err != nil {
   154  		t.Fatal(err)
   155  	}
   156  
   157  	if pwd == pwd2 {
   158  		t.Fatal("`pwd` should be changed")
   159  	}
   160  }
   161  
   162  func TestBacktick(t *testing.T) {
   163  	goversion, err := shellRun("go version", "")
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  
   168  	parser := NewParser()
   169  	parser.ParseBacktick = true
   170  	args, err := parser.Parse("echo `go version`")
   171  	if err != nil {
   172  		t.Fatal(err)
   173  	}
   174  
   175  	expected := []string{"echo", goversion}
   176  
   177  	if !reflect.DeepEqual(args, expected) {
   178  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   179  	}
   180  
   181  	args, err = parser.Parse(`echo $(echo foo)`)
   182  	if err != nil {
   183  		t.Fatal(err)
   184  	}
   185  
   186  	expected = []string{"echo", "foo"}
   187  	if !reflect.DeepEqual(args, expected) {
   188  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   189  	}
   190  
   191  	args, err = parser.Parse(`echo bar=$(echo 200)cm`)
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  
   196  	expected = []string{"echo", "bar=200cm"}
   197  
   198  	if !reflect.DeepEqual(args, expected) {
   199  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   200  	}
   201  
   202  	parser.ParseBacktick = false
   203  	args, _ = parser.Parse(`echo $(echo "foo")`)
   204  	expected = []string{"echo", `$(echo "foo")`}
   205  
   206  	if !reflect.DeepEqual(args, expected) {
   207  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   208  	}
   209  
   210  	args, err = parser.Parse("echo $(`echo1)")
   211  
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  
   216  	expected = []string{"echo", "$(`echo1)"}
   217  	if !reflect.DeepEqual(args, expected) {
   218  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   219  	}
   220  }
   221  
   222  func TestBacktickMulti(t *testing.T) {
   223  	parser := NewParser()
   224  	parser.ParseBacktick = true
   225  	args, err := parser.Parse(`echo $(go env GOPATH && go env GOROOT)`)
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  
   230  	expected := []string{"echo", build.Default.GOPATH + "\n" + build.Default.GOROOT}
   231  
   232  	if !reflect.DeepEqual(args, expected) {
   233  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   234  	}
   235  }
   236  
   237  func TestBacktickError(t *testing.T) {
   238  	parser := NewParser()
   239  	parser.ParseBacktick = true
   240  	_, err := parser.Parse("echo `go Version`")
   241  
   242  	if err == nil {
   243  		t.Fatal("Should be an error")
   244  	}
   245  
   246  	expected := "exit status 2:go Version: unknown command\nRun 'go help' for usage.\n"
   247  	if expected != err.Error() {
   248  		t.Fatalf("Expected %q, but %q", expected, err.Error())
   249  	}
   250  
   251  	_, err = parser.Parse(`echo $(echo1)`)
   252  	if err == nil {
   253  		t.Fatal("Should be an error")
   254  	}
   255  
   256  	_, err = parser.Parse(`echo FOO=$(echo1)`)
   257  
   258  	if err == nil {
   259  		t.Fatal("Should be an error")
   260  	}
   261  
   262  	_, err = parser.Parse(`echo $(echo1`)
   263  
   264  	if err == nil {
   265  		t.Fatal("Should be an error")
   266  	}
   267  
   268  	_, err = parser.Parse(`echo $ (echo1`)
   269  
   270  	if err == nil {
   271  		t.Fatal("Should be an error")
   272  	}
   273  
   274  	_, err = parser.Parse(`echo (echo1`)
   275  
   276  	if err == nil {
   277  		t.Fatal("Should be an error")
   278  	}
   279  
   280  	_, err = parser.Parse(`echo )echo1`)
   281  	if err == nil {
   282  		t.Fatal("Should be an error")
   283  	}
   284  }
   285  
   286  func TestEnv(t *testing.T) {
   287  	os.Setenv("FOO", "bar")
   288  
   289  	parser := NewParser()
   290  	parser.ParseEnv = true
   291  	args, err := parser.Parse("echo $FOO")
   292  	if err != nil {
   293  		t.Fatal(err)
   294  	}
   295  
   296  	expected := []string{"echo", "bar"}
   297  	if !reflect.DeepEqual(args, expected) {
   298  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   299  	}
   300  }
   301  
   302  func TestCustomEnv(t *testing.T) {
   303  	parser := NewParser()
   304  	parser.ParseEnv = true
   305  	parser.Getenv = func(k string) string { return map[string]string{"FOO": "baz"}[k] }
   306  	args, err := parser.Parse("echo $FOO")
   307  	if err != nil {
   308  		t.Fatal(err)
   309  	}
   310  
   311  	expected := []string{"echo", "baz"}
   312  
   313  	if !reflect.DeepEqual(args, expected) {
   314  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   315  	}
   316  }
   317  
   318  func TestNoEnv(t *testing.T) {
   319  	parser := NewParser()
   320  	parser.ParseEnv = true
   321  	args, err := parser.Parse("echo $BAR")
   322  	if err != nil {
   323  		t.Fatal(err)
   324  	}
   325  
   326  	expected := []string{"echo"}
   327  	if !reflect.DeepEqual(args, expected) {
   328  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   329  	}
   330  }
   331  
   332  func TestEnvArguments(t *testing.T) {
   333  	os.Setenv("FOO", "bar baz")
   334  
   335  	parser := NewParser()
   336  	parser.ParseEnv = true
   337  	args, err := parser.Parse("echo $FOO")
   338  	if err != nil {
   339  		t.Fatal(err)
   340  	}
   341  
   342  	expected := []string{"echo", "bar baz"}
   343  	if !reflect.DeepEqual(args, expected) {
   344  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   345  	}
   346  }
   347  
   348  func TestEnvArgumentsFail(t *testing.T) {
   349  	os.Setenv("FOO", "bar '")
   350  
   351  	parser := NewParser()
   352  	parser.ParseEnv = true
   353  	_, err := parser.Parse("echo $FOO")
   354  	if err != nil {
   355  		t.Fatal("Should not be an error")
   356  	}
   357  
   358  	_, err = parser.Parse("$FOO")
   359  
   360  	if err != nil {
   361  		t.Fatal("Should not be an error")
   362  	}
   363  
   364  	_, err = parser.Parse("echo $FOO")
   365  	if err != nil {
   366  		t.Fatal("Should be an error")
   367  	}
   368  
   369  	os.Setenv("FOO", "bar `")
   370  
   371  	_, err = parser.Parse("$FOO ")
   372  	if err != nil {
   373  		t.Fatal("Should be an error")
   374  	}
   375  }
   376  
   377  func TestDupEnv(t *testing.T) {
   378  	os.Setenv("FOO", "bar")
   379  	os.Setenv("FOO_BAR", "baz")
   380  
   381  	parser := NewParser()
   382  	parser.ParseEnv = true
   383  	args, err := parser.Parse("echo $$FOO$")
   384  	if err != nil {
   385  		t.Fatal(err)
   386  	}
   387  
   388  	expected := []string{"echo", "$bar$"}
   389  
   390  	if !reflect.DeepEqual(args, expected) {
   391  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   392  	}
   393  
   394  	args, err = parser.Parse("echo $${FOO_BAR}$")
   395  	if err != nil {
   396  		t.Fatal(err)
   397  	}
   398  
   399  	expected = []string{"echo", "$baz$"}
   400  
   401  	if !reflect.DeepEqual(args, expected) {
   402  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   403  	}
   404  }
   405  
   406  func TestHaveMore(t *testing.T) {
   407  	parser := NewParser()
   408  	parser.ParseEnv = true
   409  
   410  	line := "echo foo; seq 1 10"
   411  	args, err := parser.Parse(line)
   412  	if err != nil {
   413  		t.Fatalf(err.Error())
   414  	}
   415  
   416  	expected := []string{"echo", "foo"}
   417  	if !reflect.DeepEqual(args, expected) {
   418  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   419  	}
   420  
   421  	if parser.Position == 0 {
   422  		t.Fatalf("Commands should be remaining")
   423  	}
   424  
   425  	line = string([]rune(line)[parser.Position+1:])
   426  	args, err = parser.Parse(line)
   427  
   428  	if err != nil {
   429  		t.Fatalf(err.Error())
   430  	}
   431  
   432  	expected = []string{"seq", "1", "10"}
   433  
   434  	if !reflect.DeepEqual(args, expected) {
   435  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   436  	}
   437  
   438  	if parser.Position > 0 {
   439  		t.Fatalf("Commands should not be remaining")
   440  	}
   441  }
   442  
   443  func TestHaveRedirect(t *testing.T) {
   444  	parser := NewParser()
   445  	parser.ParseEnv = true
   446  
   447  	line := "ls -la 2>foo"
   448  	args, err := parser.Parse(line)
   449  	if err != nil {
   450  		t.Fatalf(err.Error())
   451  	}
   452  
   453  	expected := []string{"ls", "-la"}
   454  	if !reflect.DeepEqual(args, expected) {
   455  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   456  	}
   457  
   458  	if parser.Position == 0 {
   459  		t.Fatalf("Commands should be remaining")
   460  	}
   461  }
   462  
   463  func TestBackquoteInFlag(t *testing.T) {
   464  	parser := NewParser()
   465  	parser.ParseBacktick = true
   466  	args, err := parser.Parse("cmd -flag=`echo val1` -flag=val2")
   467  	if err != nil {
   468  		panic(err)
   469  	}
   470  
   471  	expected := []string{"cmd", "-flag=val1", "-flag=val2"}
   472  	if !reflect.DeepEqual(args, expected) {
   473  		t.Fatalf("Expected %#v, but %#v:", expected, args)
   474  	}
   475  }