github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/ast/parser_test.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package ast 5 6 import ( 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/google/syzkaller/sys/targets" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 func TestParseAll(t *testing.T) { 17 files, err := filepath.Glob(filepath.Join("..", "..", "sys", targets.Linux, "*.txt")) 18 if err != nil || len(files) == 0 { 19 t.Fatalf("failed to read sys dir: %v", err) 20 } 21 files = append(files, filepath.FromSlash("testdata/all.txt")) 22 for _, file := range files { 23 data, err := os.ReadFile(file) 24 if err != nil { 25 t.Fatalf("failed to read file: %v", err) 26 } 27 t.Run(file, func(t *testing.T) { 28 eh := func(pos Pos, msg string) { 29 t.Fatalf("%v: %v", pos, msg) 30 } 31 desc := Parse(data, file, eh) 32 if desc == nil { 33 t.Fatalf("parsing failed, but no error produced") 34 } 35 data2 := Format(desc) 36 desc2 := Parse(data2, file, eh) 37 if desc2 == nil { 38 t.Fatalf("parsing failed, but no error produced") 39 } 40 if len(desc.Nodes) != len(desc2.Nodes) { 41 t.Fatalf("formatting number of top level decls: %v/%v", 42 len(desc.Nodes), len(desc2.Nodes)) 43 } 44 for i := range desc.Nodes { 45 n1, n2 := desc.Nodes[i], desc2.Nodes[i] 46 if n1 == nil { 47 t.Fatalf("got nil node") 48 } 49 assert.Equal(t, n1, n2, "formating changed code") 50 } 51 assert.Equal(t, string(data), string(Format(desc.Clone()))) 52 nodes0 := 0 53 desc.Walk(func(n Node) { 54 nodes0++ 55 if SerializeNode(n) == "" { 56 t.Fatalf("empty serialized node: %#v", n) 57 } 58 }) 59 nodes1 := 0 60 desc.Walk(Recursive(func(n Node) bool { 61 nodes1++ 62 pos, typ, _ := n.Info() 63 if typ == "" { 64 t.Fatalf("%v: node has empty typ=%q: %#v", pos, typ, n) 65 } 66 return true 67 })) 68 nodes2 := 0 69 desc.Walk(PostRecursive(func(n Node) { 70 nodes2++ 71 })) 72 if nodes0 != len(desc.Nodes) || nodes1 <= len(desc.Nodes) || nodes1 != nodes2 { 73 t.Fatalf("bad walk: desc=%v, top=%v recursive=%v, postrecursive=%v", 74 len(desc.Nodes), nodes0, nodes1, nodes2) 75 } 76 desc4 := desc.Filter(func(n Node) bool { return true }) 77 desc5 := desc.Filter(func(n Node) bool { return false }) 78 if len(desc4.Nodes) != len(desc.Nodes) || len(desc5.Nodes) != 0 { 79 t.Fatalf("filter is broken: desc=%v desc4=%v desc5=%v", 80 len(desc.Nodes), len(desc4.Nodes), len(desc5.Nodes)) 81 } 82 }) 83 } 84 } 85 86 func TestParse(t *testing.T) { 87 for _, test := range parseTests { 88 t.Run(test.name, func(t *testing.T) { 89 errorHandler := func(pos Pos, msg string) { 90 t.Logf("%v: %v", pos, msg) 91 } 92 Parse([]byte(test.input), "foo", errorHandler) 93 }) 94 } 95 } 96 97 var parseTests = []struct { 98 name string 99 input string 100 result []interface{} 101 }{ 102 { 103 "empty", 104 ``, 105 []interface{}{}, 106 }, 107 { 108 "new-line", 109 ` 110 111 `, 112 []interface{}{}, 113 }, 114 { 115 "nil", 116 "\x00", 117 []interface{}{}, 118 }, 119 } 120 121 func TestErrors(t *testing.T) { 122 files, err := os.ReadDir("testdata") 123 if err != nil { 124 t.Fatal(err) 125 } 126 if len(files) == 0 { 127 t.Fatal("no input files") 128 } 129 for _, f := range files { 130 if !strings.HasSuffix(f.Name(), ".txt") { 131 continue 132 } 133 name := f.Name() 134 t.Run(name, func(t *testing.T) { 135 em := NewErrorMatcher(t, filepath.Join("testdata", name)) 136 desc := Parse(em.Data, name, em.ErrorHandler) 137 if desc != nil && em.Count() != 0 { 138 em.DumpErrors() 139 t.Fatalf("parsing succeed, but got errors") 140 } 141 if desc == nil && em.Count() == 0 { 142 t.Fatalf("parsing failed, but got no errors") 143 } 144 em.Check() 145 }) 146 } 147 }