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
4package ast
5
6import (
7	"bytes"
8	"io/ioutil"
9	"path/filepath"
10	"reflect"
11	"strings"
12	"testing"
13)
14
15func TestParseAll(t *testing.T) {
16	files, err := filepath.Glob(filepath.Join("..", "..", "sys", "linux", "*.txt"))
17	if err != nil || len(files) == 0 {
18		t.Fatalf("failed to read sys dir: %v", err)
19	}
20	for _, file := range files {
21		data, err := ioutil.ReadFile(file)
22		if err != nil {
23			t.Fatalf("failed to read file: %v", err)
24		}
25		t.Run(file, func(t *testing.T) {
26			eh := func(pos Pos, msg string) {
27				t.Fatalf("%v: %v", pos, msg)
28			}
29			desc := Parse(data, file, eh)
30			if desc == nil {
31				t.Fatalf("parsing failed, but no error produced")
32			}
33			data2 := Format(desc)
34			desc2 := Parse(data2, file, eh)
35			if desc2 == nil {
36				t.Fatalf("parsing failed, but no error produced")
37			}
38			if len(desc.Nodes) != len(desc2.Nodes) {
39				t.Fatalf("formatting number of top level decls: %v/%v",
40					len(desc.Nodes), len(desc2.Nodes))
41			}
42			for i := range desc.Nodes {
43				n1, n2 := desc.Nodes[i], desc2.Nodes[i]
44				if n1 == nil {
45					t.Fatalf("got nil node")
46				}
47				if !reflect.DeepEqual(n1, n2) {
48					t.Fatalf("formatting changed code:\n%#v\nvs:\n%#v", n1, n2)
49				}
50			}
51			data3 := Format(desc.Clone())
52			if !bytes.Equal(data, data3) {
53				t.Fatalf("Clone lost data")
54			}
55		})
56	}
57}
58
59func TestParse(t *testing.T) {
60	for _, test := range parseTests {
61		t.Run(test.name, func(t *testing.T) {
62			errorHandler := func(pos Pos, msg string) {
63				t.Logf("%v: %v", pos, msg)
64			}
65			Parse([]byte(test.input), "foo", errorHandler)
66		})
67	}
68}
69
70var parseTests = []struct {
71	name   string
72	input  string
73	result []interface{}
74}{
75	{
76		"empty",
77		``,
78		[]interface{}{},
79	},
80	{
81		"new-line",
82		`
83
84`,
85		[]interface{}{},
86	},
87	{
88		"nil",
89		"\x00",
90		[]interface{}{},
91	},
92}
93
94func TestErrors(t *testing.T) {
95	files, err := ioutil.ReadDir("testdata")
96	if err != nil {
97		t.Fatal(err)
98	}
99	if len(files) == 0 {
100		t.Fatal("no input files")
101	}
102	for _, f := range files {
103		if !strings.HasSuffix(f.Name(), ".txt") {
104			continue
105		}
106		name := f.Name()
107		t.Run(name, func(t *testing.T) {
108			em := NewErrorMatcher(t, filepath.Join("testdata", name))
109			desc := Parse(em.Data, name, em.ErrorHandler)
110			if desc != nil && em.Count() != 0 {
111				em.DumpErrors(t)
112				t.Fatalf("parsing succeed, but got errors")
113			}
114			if desc == nil && em.Count() == 0 {
115				t.Fatalf("parsing failed, but got no errors")
116			}
117			em.Check(t)
118		})
119	}
120}
121