| // Copyright 2011 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package generate |
| |
| import ( |
| "os" |
| "reflect" |
| "runtime" |
| "testing" |
| ) |
| |
| type splitTest struct { |
| in string |
| out []string |
| } |
| |
| // Same as above, except including source line number to set |
| type splitTestWithLine struct { |
| in string |
| out []string |
| lineNumber int |
| } |
| |
| const anyLineNo = 0 |
| |
| var splitTests = []splitTest{ |
| {"", nil}, |
| {"x", []string{"x"}}, |
| {" a b\tc ", []string{"a", "b", "c"}}, |
| {` " a " `, []string{" a "}}, |
| {"$GOARCH", []string{runtime.GOARCH}}, |
| {"$GOOS", []string{runtime.GOOS}}, |
| {"$GOFILE", []string{"proc.go"}}, |
| {"$GOPACKAGE", []string{"sys"}}, |
| {"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}}, |
| {"/$XXNOTDEFINED/", []string{"//"}}, |
| {"/$DOLLAR/", []string{"/$/"}}, |
| {"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}}, |
| } |
| |
| func TestGenerateCommandParse(t *testing.T) { |
| g := &Generator{ |
| r: nil, // Unused here. |
| path: "/usr/ken/sys/proc.go", |
| dir: "/usr/ken/sys", |
| file: "proc.go", |
| pkg: "sys", |
| commands: make(map[string][]string), |
| } |
| g.setEnv() |
| g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"}) |
| for _, test := range splitTests { |
| // First with newlines. |
| got := g.split("//go:generate " + test.in + "\n") |
| if !reflect.DeepEqual(got, test.out) { |
| t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) |
| } |
| // Then with CRLFs, thank you Windows. |
| got = g.split("//go:generate " + test.in + "\r\n") |
| if !reflect.DeepEqual(got, test.out) { |
| t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) |
| } |
| } |
| } |
| |
| // These environment variables will be undefined before the splitTestWithLine tests |
| var undefEnvList = []string{ |
| "_XYZZY_", |
| } |
| |
| // These environment variables will be defined before the splitTestWithLine tests |
| var defEnvMap = map[string]string{ |
| "_PLUGH_": "SomeVal", |
| "_X": "Y", |
| } |
| |
| // TestGenerateCommandShortHand - similar to TestGenerateCommandParse, |
| // except: |
| // 1. if the result starts with -command, record that shorthand |
| // before moving on to the next test. |
| // 2. If a source line number is specified, set that in the parser |
| // before executing the test. i.e., execute the split as if it |
| // processing that source line. |
| func TestGenerateCommandShorthand(t *testing.T) { |
| g := &Generator{ |
| r: nil, // Unused here. |
| path: "/usr/ken/sys/proc.go", |
| dir: "/usr/ken/sys", |
| file: "proc.go", |
| pkg: "sys", |
| commands: make(map[string][]string), |
| } |
| |
| var inLine string |
| var expected, got []string |
| |
| g.setEnv() |
| |
| // Set up the system environment variables |
| for i := range undefEnvList { |
| os.Unsetenv(undefEnvList[i]) |
| } |
| for k := range defEnvMap { |
| os.Setenv(k, defEnvMap[k]) |
| } |
| |
| // simple command from environment variable |
| inLine = "//go:generate -command CMD0 \"ab${_X}cd\"" |
| expected = []string{"-command", "CMD0", "abYcd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| // try again, with an extra level of indirection (should leave variable in command) |
| inLine = "//go:generate -command CMD0 \"ab${DOLLAR}{_X}cd\"" |
| expected = []string{"-command", "CMD0", "ab${_X}cd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| // Now the interesting part, record that output as a command |
| g.setShorthand(got) |
| |
| // see that the command still substitutes correctly from env. variable |
| inLine = "//go:generate CMD0" |
| expected = []string{"abYcd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| // Now change the value of $X and see if the recorded definition is |
| // still intact (vs. having the $_X already substituted out) |
| |
| os.Setenv("_X", "Z") |
| inLine = "//go:generate CMD0" |
| expected = []string{"abZcd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| // What if the variable is now undefined? Should be empty substitution. |
| |
| os.Unsetenv("_X") |
| inLine = "//go:generate CMD0" |
| expected = []string{"abcd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| // Try another undefined variable as an extra check |
| os.Unsetenv("_Z") |
| inLine = "//go:generate -command CMD1 \"ab${_Z}cd\"" |
| expected = []string{"-command", "CMD1", "abcd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| g.setShorthand(got) |
| |
| inLine = "//go:generate CMD1" |
| expected = []string{"abcd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| const val = "someNewValue" |
| os.Setenv("_Z", val) |
| |
| // try again with the properly-escaped variable. |
| |
| inLine = "//go:generate -command CMD2 \"ab${DOLLAR}{_Z}cd\"" |
| expected = []string{"-command", "CMD2", "ab${_Z}cd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| |
| g.setShorthand(got) |
| |
| inLine = "//go:generate CMD2" |
| expected = []string{"ab" + val + "cd"} |
| got = g.split(inLine + "\n") |
| |
| if !reflect.DeepEqual(got, expected) { |
| t.Errorf("split(%q): got %q expected %q", inLine, got, expected) |
| } |
| } |
| |
| // Command-related tests for TestGenerateCommandShortHand2 |
| // -- Note line numbers included to check substitutions from "build-in" variable - $GOLINE |
| var splitTestsLines = []splitTestWithLine{ |
| {"-command TEST1 $GOLINE", []string{"-command", "TEST1", "22"}, 22}, |
| {"-command TEST2 ${DOLLAR}GOLINE", []string{"-command", "TEST2", "$GOLINE"}, 26}, |
| {"TEST1", []string{"22"}, 33}, |
| {"TEST2", []string{"66"}, 66}, |
| {"TEST1 ''", []string{"22", "''"}, 99}, |
| {"TEST2 ''", []string{"44", "''"}, 44}, |
| } |
| |
| // TestGenerateCommandShortHand - similar to TestGenerateCommandParse, |
| // except: |
| // 1. if the result starts with -command, record that shorthand |
| // before moving on to the next test. |
| // 2. If a source line number is specified, set that in the parser |
| // before executing the test. i.e., execute the split as if it |
| // processing that source line. |
| func TestGenerateCommandShortHand2(t *testing.T) { |
| g := &Generator{ |
| r: nil, // Unused here. |
| path: "/usr/ken/sys/proc.go", |
| dir: "/usr/ken/sys", |
| file: "proc.go", |
| pkg: "sys", |
| commands: make(map[string][]string), |
| } |
| g.setEnv() |
| for _, test := range splitTestsLines { |
| // if the test specified a line number, reflect that |
| if test.lineNumber != anyLineNo { |
| g.lineNum = test.lineNumber |
| g.setEnv() |
| } |
| // First with newlines. |
| got := g.split("//go:generate " + test.in + "\n") |
| if !reflect.DeepEqual(got, test.out) { |
| t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) |
| } |
| // Then with CRLFs, thank you Windows. |
| got = g.split("//go:generate " + test.in + "\r\n") |
| if !reflect.DeepEqual(got, test.out) { |
| t.Errorf("split(%q): got %q expected %q", test.in, got, test.out) |
| } |
| if got[0] == "-command" { // record commands |
| g.setShorthand(got) |
| } |
| } |
| } |