Source file src/cmd/go/internal/generate/generate_test.go

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package generate
     6  
     7  import (
     8  	"internal/testenv"
     9  	"os"
    10  	"path/filepath"
    11  	"reflect"
    12  	"runtime"
    13  	"testing"
    14  )
    15  
    16  type splitTest struct {
    17  	in  string
    18  	out []string
    19  }
    20  
    21  // Same as above, except including source line number to set
    22  type splitTestWithLine struct {
    23  	in         string
    24  	out        []string
    25  	lineNumber int
    26  }
    27  
    28  const anyLineNo = 0
    29  
    30  var splitTests = []splitTest{
    31  	{"", nil},
    32  	{"x", []string{"x"}},
    33  	{" a b\tc ", []string{"a", "b", "c"}},
    34  	{` " a " `, []string{" a "}},
    35  	{"$GOARCH", []string{runtime.GOARCH}},
    36  	{"$GOOS", []string{runtime.GOOS}},
    37  	{"$GOFILE", []string{"proc.go"}},
    38  	{"$GOPACKAGE", []string{"sys"}},
    39  	{"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
    40  	{"/$XXNOTDEFINED/", []string{"//"}},
    41  	{"/$DOLLAR/", []string{"/$/"}},
    42  	{"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
    43  }
    44  
    45  func TestGenerateCommandParse(t *testing.T) {
    46  	dir := filepath.Join(testenv.GOROOT(t), "src", "sys")
    47  	g := &Generator{
    48  		r:        nil, // Unused here.
    49  		path:     filepath.Join(dir, "proc.go"),
    50  		dir:      dir,
    51  		file:     "proc.go",
    52  		pkg:      "sys",
    53  		commands: make(map[string][]string),
    54  	}
    55  	g.setEnv()
    56  	g.setShorthand([]string{"-command", "yacc", "go", "tool", "yacc"})
    57  	for _, test := range splitTests {
    58  		// First with newlines.
    59  		got := g.split("//go:generate " + test.in + "\n")
    60  		if !reflect.DeepEqual(got, test.out) {
    61  			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
    62  		}
    63  		// Then with CRLFs, thank you Windows.
    64  		got = g.split("//go:generate " + test.in + "\r\n")
    65  		if !reflect.DeepEqual(got, test.out) {
    66  			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
    67  		}
    68  	}
    69  }
    70  
    71  // These environment variables will be undefined before the splitTestWithLine tests
    72  var undefEnvList = []string{
    73  	"_XYZZY_",
    74  }
    75  
    76  // These environment variables will be defined before the splitTestWithLine tests
    77  var defEnvMap = map[string]string{
    78  	"_PLUGH_": "SomeVal",
    79  	"_X":      "Y",
    80  }
    81  
    82  // TestGenerateCommandShortHand - similar to TestGenerateCommandParse,
    83  // except:
    84  //  1. if the result starts with -command, record that shorthand
    85  //     before moving on to the next test.
    86  //  2. If a source line number is specified, set that in the parser
    87  //     before executing the test.  i.e., execute the split as if it
    88  //     processing that source line.
    89  func TestGenerateCommandShorthand(t *testing.T) {
    90  	dir := filepath.Join(testenv.GOROOT(t), "src", "sys")
    91  	g := &Generator{
    92  		r:        nil, // Unused here.
    93  		path:     filepath.Join(dir, "proc.go"),
    94  		dir:      dir,
    95  		file:     "proc.go",
    96  		pkg:      "sys",
    97  		commands: make(map[string][]string),
    98  	}
    99  
   100  	var inLine string
   101  	var expected, got []string
   102  
   103  	g.setEnv()
   104  
   105  	// Set up the system environment variables
   106  	for i := range undefEnvList {
   107  		os.Unsetenv(undefEnvList[i])
   108  	}
   109  	for k := range defEnvMap {
   110  		os.Setenv(k, defEnvMap[k])
   111  	}
   112  
   113  	// simple command from environment variable
   114  	inLine = "//go:generate -command CMD0 \"ab${_X}cd\""
   115  	expected = []string{"-command", "CMD0", "abYcd"}
   116  	got = g.split(inLine + "\n")
   117  
   118  	if !reflect.DeepEqual(got, expected) {
   119  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   120  	}
   121  
   122  	// try again, with an extra level of indirection (should leave variable in command)
   123  	inLine = "//go:generate -command CMD0 \"ab${DOLLAR}{_X}cd\""
   124  	expected = []string{"-command", "CMD0", "ab${_X}cd"}
   125  	got = g.split(inLine + "\n")
   126  
   127  	if !reflect.DeepEqual(got, expected) {
   128  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   129  	}
   130  
   131  	// Now the interesting part, record that output as a command
   132  	g.setShorthand(got)
   133  
   134  	// see that the command still substitutes correctly from env. variable
   135  	inLine = "//go:generate CMD0"
   136  	expected = []string{"abYcd"}
   137  	got = g.split(inLine + "\n")
   138  
   139  	if !reflect.DeepEqual(got, expected) {
   140  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   141  	}
   142  
   143  	// Now change the value of $X and see if the recorded definition is
   144  	// still intact (vs. having the $_X already substituted out)
   145  
   146  	os.Setenv("_X", "Z")
   147  	inLine = "//go:generate CMD0"
   148  	expected = []string{"abZcd"}
   149  	got = g.split(inLine + "\n")
   150  
   151  	if !reflect.DeepEqual(got, expected) {
   152  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   153  	}
   154  
   155  	// What if the variable is now undefined?  Should be empty substitution.
   156  
   157  	os.Unsetenv("_X")
   158  	inLine = "//go:generate CMD0"
   159  	expected = []string{"abcd"}
   160  	got = g.split(inLine + "\n")
   161  
   162  	if !reflect.DeepEqual(got, expected) {
   163  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   164  	}
   165  
   166  	// Try another undefined variable as an extra check
   167  	os.Unsetenv("_Z")
   168  	inLine = "//go:generate -command CMD1 \"ab${_Z}cd\""
   169  	expected = []string{"-command", "CMD1", "abcd"}
   170  	got = g.split(inLine + "\n")
   171  
   172  	if !reflect.DeepEqual(got, expected) {
   173  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   174  	}
   175  
   176  	g.setShorthand(got)
   177  
   178  	inLine = "//go:generate CMD1"
   179  	expected = []string{"abcd"}
   180  	got = g.split(inLine + "\n")
   181  
   182  	if !reflect.DeepEqual(got, expected) {
   183  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   184  	}
   185  
   186  	const val = "someNewValue"
   187  	os.Setenv("_Z", val)
   188  
   189  	// try again with the properly-escaped variable.
   190  
   191  	inLine = "//go:generate -command CMD2 \"ab${DOLLAR}{_Z}cd\""
   192  	expected = []string{"-command", "CMD2", "ab${_Z}cd"}
   193  	got = g.split(inLine + "\n")
   194  
   195  	if !reflect.DeepEqual(got, expected) {
   196  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   197  	}
   198  
   199  	g.setShorthand(got)
   200  
   201  	inLine = "//go:generate CMD2"
   202  	expected = []string{"ab" + val + "cd"}
   203  	got = g.split(inLine + "\n")
   204  
   205  	if !reflect.DeepEqual(got, expected) {
   206  		t.Errorf("split(%q): got %q expected %q", inLine, got, expected)
   207  	}
   208  }
   209  
   210  // Command-related tests for TestGenerateCommandShortHand2
   211  // -- Note line numbers included to check substitutions from "build-in" variable - $GOLINE
   212  var splitTestsLines = []splitTestWithLine{
   213  	{"-command TEST1 $GOLINE", []string{"-command", "TEST1", "22"}, 22},
   214  	{"-command TEST2 ${DOLLAR}GOLINE", []string{"-command", "TEST2", "$GOLINE"}, 26},
   215  	{"TEST1", []string{"22"}, 33},
   216  	{"TEST2", []string{"66"}, 66},
   217  	{"TEST1 ''", []string{"22", "''"}, 99},
   218  	{"TEST2 ''", []string{"44", "''"}, 44},
   219  }
   220  
   221  // TestGenerateCommandShortHand - similar to TestGenerateCommandParse,
   222  // except:
   223  //  1. if the result starts with -command, record that shorthand
   224  //     before moving on to the next test.
   225  //  2. If a source line number is specified, set that in the parser
   226  //     before executing the test.  i.e., execute the split as if it
   227  //     processing that source line.
   228  func TestGenerateCommandShortHand2(t *testing.T) {
   229  	dir := filepath.Join(testenv.GOROOT(t), "src", "sys")
   230  	g := &Generator{
   231  		r:        nil, // Unused here.
   232  		path:     filepath.Join(dir, "proc.go"),
   233  		dir:      dir,
   234  		file:     "proc.go",
   235  		pkg:      "sys",
   236  		commands: make(map[string][]string),
   237  	}
   238  	g.setEnv()
   239  	for _, test := range splitTestsLines {
   240  		// if the test specified a line number, reflect that
   241  		if test.lineNumber != anyLineNo {
   242  			g.lineNum = test.lineNumber
   243  			g.setEnv()
   244  		}
   245  		// First with newlines.
   246  		got := g.split("//go:generate " + test.in + "\n")
   247  		if !reflect.DeepEqual(got, test.out) {
   248  			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
   249  		}
   250  		// Then with CRLFs, thank you Windows.
   251  		got = g.split("//go:generate " + test.in + "\r\n")
   252  		if !reflect.DeepEqual(got, test.out) {
   253  			t.Errorf("split(%q): got %q expected %q", test.in, got, test.out)
   254  		}
   255  		if got[0] == "-command" { // record commands
   256  			g.setShorthand(got)
   257  		}
   258  	}
   259  }
   260  

View as plain text