Home | History | Annotate | Download | only in ast
      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 	"bytes"
      8 	"io/ioutil"
      9 	"path/filepath"
     10 	"reflect"
     11 	"strings"
     12 	"testing"
     13 )
     14 
     15 func 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 
     59 func 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 
     70 var 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 
     94 func 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