github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/cmd/compile/internal/syntax/parser_test.go (about) 1 // Copyright 2016 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 syntax 6 7 import ( 8 "bytes" 9 "cmd/internal/src" 10 "flag" 11 "fmt" 12 "io/ioutil" 13 "path/filepath" 14 "runtime" 15 "strings" 16 "sync" 17 "testing" 18 "time" 19 ) 20 21 var fast = flag.Bool("fast", false, "parse package files in parallel") 22 var src_ = flag.String("src", "parser.go", "source file to parse") 23 var verify = flag.Bool("verify", false, "verify idempotent printing") 24 25 func TestParse(t *testing.T) { 26 ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0) 27 } 28 29 func TestStdLib(t *testing.T) { 30 if testing.Short() { 31 t.Skip("skipping test in short mode") 32 } 33 34 var m1 runtime.MemStats 35 runtime.ReadMemStats(&m1) 36 start := time.Now() 37 38 type parseResult struct { 39 filename string 40 lines uint 41 } 42 43 results := make(chan parseResult) 44 go func() { 45 defer close(results) 46 for _, dir := range []string{ 47 runtime.GOROOT(), 48 } { 49 walkDirs(t, dir, func(filename string) { 50 if debug { 51 fmt.Printf("parsing %s\n", filename) 52 } 53 ast, err := ParseFile(filename, nil, nil, 0) 54 if err != nil { 55 t.Error(err) 56 return 57 } 58 if *verify { 59 verifyPrint(filename, ast) 60 } 61 results <- parseResult{filename, ast.Lines} 62 }) 63 } 64 }() 65 66 var count, lines uint 67 for res := range results { 68 count++ 69 lines += res.lines 70 if testing.Verbose() { 71 fmt.Printf("%5d %s (%d lines)\n", count, res.filename, res.lines) 72 } 73 } 74 75 dt := time.Since(start) 76 var m2 runtime.MemStats 77 runtime.ReadMemStats(&m2) 78 dm := float64(m2.TotalAlloc-m1.TotalAlloc) / 1e6 79 80 fmt.Printf("parsed %d lines (%d files) in %v (%d lines/s)\n", lines, count, dt, int64(float64(lines)/dt.Seconds())) 81 fmt.Printf("allocated %.3fMb (%.3fMb/s)\n", dm, dm/dt.Seconds()) 82 } 83 84 func walkDirs(t *testing.T, dir string, action func(string)) { 85 fis, err := ioutil.ReadDir(dir) 86 if err != nil { 87 t.Error(err) 88 return 89 } 90 91 var files, dirs []string 92 for _, fi := range fis { 93 if fi.Mode().IsRegular() { 94 if strings.HasSuffix(fi.Name(), ".go") { 95 path := filepath.Join(dir, fi.Name()) 96 files = append(files, path) 97 } 98 } else if fi.IsDir() && fi.Name() != "testdata" { 99 path := filepath.Join(dir, fi.Name()) 100 if !strings.HasSuffix(path, "/test") { 101 dirs = append(dirs, path) 102 } 103 } 104 } 105 106 if *fast { 107 var wg sync.WaitGroup 108 wg.Add(len(files)) 109 for _, filename := range files { 110 go func(filename string) { 111 defer wg.Done() 112 action(filename) 113 }(filename) 114 } 115 wg.Wait() 116 } else { 117 for _, filename := range files { 118 action(filename) 119 } 120 } 121 122 for _, dir := range dirs { 123 walkDirs(t, dir, action) 124 } 125 } 126 127 func verifyPrint(filename string, ast1 *File) { 128 var buf1 bytes.Buffer 129 _, err := Fprint(&buf1, ast1, true) 130 if err != nil { 131 panic(err) 132 } 133 134 ast2, err := ParseBytes(src.NewFileBase(filename, filename), buf1.Bytes(), nil, nil, 0) 135 if err != nil { 136 panic(err) 137 } 138 139 var buf2 bytes.Buffer 140 _, err = Fprint(&buf2, ast2, true) 141 if err != nil { 142 panic(err) 143 } 144 145 if bytes.Compare(buf1.Bytes(), buf2.Bytes()) != 0 { 146 fmt.Printf("--- %s ---\n", filename) 147 fmt.Printf("%s\n", buf1.Bytes()) 148 fmt.Println() 149 150 fmt.Printf("--- %s ---\n", filename) 151 fmt.Printf("%s\n", buf2.Bytes()) 152 fmt.Println() 153 panic("not equal") 154 } 155 } 156 157 func TestIssue17697(t *testing.T) { 158 _, err := ParseBytes(nil, nil, nil, nil, 0) // return with parser error, don't panic 159 if err == nil { 160 t.Errorf("no error reported") 161 } 162 } 163 164 func TestParseFile(t *testing.T) { 165 _, err := ParseFile("", nil, nil, 0) 166 if err == nil { 167 t.Error("missing io error") 168 } 169 170 var first error 171 _, err = ParseFile("", func(err error) { 172 if first == nil { 173 first = err 174 } 175 }, nil, 0) 176 if err == nil || first == nil { 177 t.Error("missing io error") 178 } 179 if err != first { 180 t.Errorf("got %v; want first error %v", err, first) 181 } 182 } 183 184 func TestLineDirectives(t *testing.T) { 185 for _, test := range []struct { 186 src, msg string 187 filename string 188 line, col uint // 0-based 189 }{ 190 // test validity of //line directive 191 {`//line :`, "invalid line number: ", "", 0, 8}, 192 {`//line :x`, "invalid line number: x", "", 0, 8}, 193 {`//line foo :`, "invalid line number: ", "", 0, 12}, 194 {`//line foo:123abc`, "invalid line number: 123abc", "", 0, 11}, 195 {`/**///line foo:x`, "syntax error: package statement must be first", "", 0, 16}, //line directive not at start of line - ignored 196 {`//line foo:0`, "invalid line number: 0", "", 0, 11}, 197 {fmt.Sprintf(`//line foo:%d`, lineMax+1), fmt.Sprintf("invalid line number: %d", lineMax+1), "", 0, 11}, 198 199 // test effect of //line directive on (relative) position information 200 {"//line foo:123\n foo", "syntax error: package statement must be first", "foo", 123 - linebase, 3}, 201 {"//line foo:123\n//line bar:345\nfoo", "syntax error: package statement must be first", "bar", 345 - linebase, 0}, 202 } { 203 _, err := ParseBytes(nil, []byte(test.src), nil, nil, 0) 204 if err == nil { 205 t.Errorf("%s: no error reported", test.src) 206 continue 207 } 208 perr, ok := err.(Error) 209 if !ok { 210 t.Errorf("%s: got %v; want parser error", test.src, err) 211 continue 212 } 213 if msg := perr.Msg; msg != test.msg { 214 t.Errorf("%s: got msg = %q; want %q", test.src, msg, test.msg) 215 } 216 if filename := perr.Pos.RelFilename(); filename != test.filename { 217 t.Errorf("%s: got filename = %q; want %q", test.src, filename, test.filename) 218 } 219 if line := perr.Pos.RelLine(); line != test.line+linebase { 220 t.Errorf("%s: got line = %d; want %d", test.src, line, test.line+linebase) 221 } 222 if col := perr.Pos.Col(); col != test.col+colbase { 223 t.Errorf("%s: got col = %d; want %d", test.src, col, test.col+colbase) 224 } 225 } 226 }