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