Black Lives Matter. Support the Equal Justice Initiative.

Source file src/go/build/read_test.go

Documentation: go/build

     1  // Copyright 2012 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 build
     6  
     7  import (
     8  	"fmt"
     9  	"go/token"
    10  	"io"
    11  	"strings"
    12  	"testing"
    13  )
    14  
    15  const quote = "`"
    16  
    17  type readTest struct {
    18  	// Test input contains ℙ where readGoInfo should stop.
    19  	in  string
    20  	err string
    21  }
    22  
    23  var readGoInfoTests = []readTest{
    24  	{
    25  		`package p`,
    26  		"",
    27  	},
    28  	{
    29  		`package p; import "x"`,
    30  		"",
    31  	},
    32  	{
    33  		`package p; import . "x"`,
    34  		"",
    35  	},
    36  	{
    37  		`package p; import "x";ℙvar x = 1`,
    38  		"",
    39  	},
    40  	{
    41  		`package p
    42  
    43  		// comment
    44  
    45  		import "x"
    46  		import _ "x"
    47  		import a "x"
    48  
    49  		/* comment */
    50  
    51  		import (
    52  			"x" /* comment */
    53  			_ "x"
    54  			a "x" // comment
    55  			` + quote + `x` + quote + `
    56  			_ /*comment*/ ` + quote + `x` + quote + `
    57  			a ` + quote + `x` + quote + `
    58  		)
    59  		import (
    60  		)
    61  		import ()
    62  		import()import()import()
    63  		import();import();import()
    64  
    65  		ℙvar x = 1
    66  		`,
    67  		"",
    68  	},
    69  	{
    70  		"\ufeff𝔻" + `package p; import "x";ℙvar x = 1`,
    71  		"",
    72  	},
    73  }
    74  
    75  var readCommentsTests = []readTest{
    76  	{
    77  		`ℙpackage p`,
    78  		"",
    79  	},
    80  	{
    81  		`ℙpackage p; import "x"`,
    82  		"",
    83  	},
    84  	{
    85  		`ℙpackage p; import . "x"`,
    86  		"",
    87  	},
    88  	{
    89  		"\ufeff𝔻" + `ℙpackage p; import . "x"`,
    90  		"",
    91  	},
    92  	{
    93  		`// foo
    94  
    95  		/* bar */
    96  
    97  		/* quux */ // baz
    98  
    99  		/*/ zot */
   100  
   101  		// asdf
   102  		ℙHello, world`,
   103  		"",
   104  	},
   105  	{
   106  		"\ufeff𝔻" + `// foo
   107  
   108  		/* bar */
   109  
   110  		/* quux */ // baz
   111  
   112  		/*/ zot */
   113  
   114  		// asdf
   115  		ℙHello, world`,
   116  		"",
   117  	},
   118  }
   119  
   120  func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
   121  	for i, tt := range tests {
   122  		var in, testOut string
   123  		j := strings.Index(tt.in, "ℙ")
   124  		if j < 0 {
   125  			in = tt.in
   126  			testOut = tt.in
   127  		} else {
   128  			in = tt.in[:j] + tt.in[j+len("ℙ"):]
   129  			testOut = tt.in[:j]
   130  		}
   131  		d := strings.Index(tt.in, "𝔻")
   132  		if d >= 0 {
   133  			in = in[:d] + in[d+len("𝔻"):]
   134  			testOut = testOut[d+len("𝔻"):]
   135  		}
   136  		r := strings.NewReader(in)
   137  		buf, err := read(r)
   138  		if err != nil {
   139  			if tt.err == "" {
   140  				t.Errorf("#%d: err=%q, expected success (%q)", i, err, string(buf))
   141  			} else if !strings.Contains(err.Error(), tt.err) {
   142  				t.Errorf("#%d: err=%q, expected %q", i, err, tt.err)
   143  			}
   144  			continue
   145  		}
   146  		if tt.err != "" {
   147  			t.Errorf("#%d: success, expected %q", i, tt.err)
   148  			continue
   149  		}
   150  
   151  		out := string(buf)
   152  		if out != testOut {
   153  			t.Errorf("#%d: wrong output:\nhave %q\nwant %q\n", i, out, testOut)
   154  		}
   155  	}
   156  }
   157  
   158  func TestReadGoInfo(t *testing.T) {
   159  	testRead(t, readGoInfoTests, func(r io.Reader) ([]byte, error) {
   160  		var info fileInfo
   161  		err := readGoInfo(r, &info)
   162  		return info.header, err
   163  	})
   164  }
   165  
   166  func TestReadComments(t *testing.T) {
   167  	testRead(t, readCommentsTests, readComments)
   168  }
   169  
   170  var readFailuresTests = []readTest{
   171  	{
   172  		`package`,
   173  		"syntax error",
   174  	},
   175  	{
   176  		"package p\n\x00\nimport `math`\n",
   177  		"unexpected NUL in input",
   178  	},
   179  	{
   180  		`package p; import`,
   181  		"syntax error",
   182  	},
   183  	{
   184  		`package p; import "`,
   185  		"syntax error",
   186  	},
   187  	{
   188  		"package p; import ` \n\n",
   189  		"syntax error",
   190  	},
   191  	{
   192  		`package p; import "x`,
   193  		"syntax error",
   194  	},
   195  	{
   196  		`package p; import _`,
   197  		"syntax error",
   198  	},
   199  	{
   200  		`package p; import _ "`,
   201  		"syntax error",
   202  	},
   203  	{
   204  		`package p; import _ "x`,
   205  		"syntax error",
   206  	},
   207  	{
   208  		`package p; import .`,
   209  		"syntax error",
   210  	},
   211  	{
   212  		`package p; import . "`,
   213  		"syntax error",
   214  	},
   215  	{
   216  		`package p; import . "x`,
   217  		"syntax error",
   218  	},
   219  	{
   220  		`package p; import (`,
   221  		"syntax error",
   222  	},
   223  	{
   224  		`package p; import ("`,
   225  		"syntax error",
   226  	},
   227  	{
   228  		`package p; import ("x`,
   229  		"syntax error",
   230  	},
   231  	{
   232  		`package p; import ("x"`,
   233  		"syntax error",
   234  	},
   235  }
   236  
   237  func TestReadFailuresIgnored(t *testing.T) {
   238  	// Syntax errors should not be reported (false arg to readImports).
   239  	// Instead, entire file should be the output and no error.
   240  	// Convert tests not to return syntax errors.
   241  	tests := make([]readTest, len(readFailuresTests))
   242  	copy(tests, readFailuresTests)
   243  	for i := range tests {
   244  		tt := &tests[i]
   245  		if !strings.Contains(tt.err, "NUL") {
   246  			tt.err = ""
   247  		}
   248  	}
   249  	testRead(t, tests, func(r io.Reader) ([]byte, error) {
   250  		var info fileInfo
   251  		err := readGoInfo(r, &info)
   252  		return info.header, err
   253  	})
   254  }
   255  
   256  var readEmbedTests = []struct {
   257  	in, out string
   258  }{
   259  	{
   260  		"package p\n",
   261  		"",
   262  	},
   263  	{
   264  		"package p\nimport \"embed\"\nvar i int\n//go:embed x y z\nvar files embed.FS",
   265  		`test:4:12:x
   266  		 test:4:14:y
   267  		 test:4:16:z`,
   268  	},
   269  	{
   270  		"package p\nimport \"embed\"\nvar i int\n//go:embed x \"\\x79\" `z`\nvar files embed.FS",
   271  		`test:4:12:x
   272  		 test:4:14:y
   273  		 test:4:21:z`,
   274  	},
   275  	{
   276  		"package p\nimport \"embed\"\nvar i int\n//go:embed x y\n//go:embed z\nvar files embed.FS",
   277  		`test:4:12:x
   278  		 test:4:14:y
   279  		 test:5:12:z`,
   280  	},
   281  	{
   282  		"package p\nimport \"embed\"\nvar i int\n\t //go:embed x y\n\t //go:embed z\n\t var files embed.FS",
   283  		`test:4:14:x
   284  		 test:4:16:y
   285  		 test:5:14:z`,
   286  	},
   287  	{
   288  		"package p\nimport \"embed\"\n//go:embed x y z\nvar files embed.FS",
   289  		`test:3:12:x
   290  		 test:3:14:y
   291  		 test:3:16:z`,
   292  	},
   293  	{
   294  		"\ufeffpackage p\nimport \"embed\"\n//go:embed x y z\nvar files embed.FS",
   295  		`test:3:12:x
   296  		 test:3:14:y
   297  		 test:3:16:z`,
   298  	},
   299  	{
   300  		"package p\nimport \"embed\"\nvar s = \"/*\"\n//go:embed x\nvar files embed.FS",
   301  		`test:4:12:x`,
   302  	},
   303  	{
   304  		`package p
   305  		 import "embed"
   306  		 var s = "\"\\\\"
   307  		 //go:embed x
   308  		 var files embed.FS`,
   309  		`test:4:15:x`,
   310  	},
   311  	{
   312  		"package p\nimport \"embed\"\nvar s = `/*`\n//go:embed x\nvar files embed.FS",
   313  		`test:4:12:x`,
   314  	},
   315  	{
   316  		"package p\nimport \"embed\"\nvar s = z/ *y\n//go:embed pointer\nvar pointer embed.FS",
   317  		"test:4:12:pointer",
   318  	},
   319  	{
   320  		"package p\n//go:embed x y z\n", // no import, no scan
   321  		"",
   322  	},
   323  	{
   324  		"package p\n//go:embed x y z\nvar files embed.FS", // no import, no scan
   325  		"",
   326  	},
   327  	{
   328  		"\ufeffpackage p\n//go:embed x y z\nvar files embed.FS", // no import, no scan
   329  		"",
   330  	},
   331  }
   332  
   333  func TestReadEmbed(t *testing.T) {
   334  	fset := token.NewFileSet()
   335  	for i, tt := range readEmbedTests {
   336  		info := fileInfo{
   337  			name: "test",
   338  			fset: fset,
   339  		}
   340  		err := readGoInfo(strings.NewReader(tt.in), &info)
   341  		if err != nil {
   342  			t.Errorf("#%d: %v", i, err)
   343  			continue
   344  		}
   345  		b := &strings.Builder{}
   346  		sep := ""
   347  		for _, emb := range info.embeds {
   348  			fmt.Fprintf(b, "%s%v:%s", sep, emb.pos, emb.pattern)
   349  			sep = "\n"
   350  		}
   351  		got := b.String()
   352  		want := strings.Join(strings.Fields(tt.out), "\n")
   353  		if got != want {
   354  			t.Errorf("#%d: embeds:\n%s\nwant:\n%s", i, got, want)
   355  		}
   356  	}
   357  }
   358  

View as plain text