• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	"bufio"
8	"bytes"
9	"io/ioutil"
10	"path/filepath"
11	"regexp"
12	"strings"
13	"testing"
14)
15
16type ErrorMatcher struct {
17	Data   []byte
18	expect []*errorDesc
19	got    []*errorDesc
20}
21
22type errorDesc struct {
23	file    string
24	line    int
25	col     int
26	text    string
27	matched bool
28}
29
30func NewErrorMatcher(t *testing.T, file string) *ErrorMatcher {
31	data, err := ioutil.ReadFile(file)
32	if err != nil {
33		t.Fatalf("failed to open input file: %v", err)
34	}
35	var stripped []byte
36	var errors []*errorDesc
37	s := bufio.NewScanner(bytes.NewReader(data))
38	for i := 1; s.Scan(); i++ {
39		ln := s.Bytes()
40		for {
41			pos := bytes.LastIndex(ln, []byte("###"))
42			if pos == -1 {
43				break
44			}
45			errors = append(errors, &errorDesc{
46				file: filepath.Base(file),
47				line: i,
48				text: strings.TrimSpace(string(ln[pos+3:])),
49			})
50			ln = ln[:pos]
51		}
52		stripped = append(stripped, ln...)
53		stripped = append(stripped, '\n')
54	}
55	if err := s.Err(); err != nil {
56		t.Fatalf("failed to scan input file: %v", err)
57	}
58	return &ErrorMatcher{
59		Data:   stripped,
60		expect: errors,
61	}
62}
63
64var errorLocationRe = regexp.MustCompile(`at [a-z][a-z0-9]+\.txt:[0-9]+:[0-9]+`)
65
66func (em *ErrorMatcher) ErrorHandler(pos Pos, msg string) {
67	if match := errorLocationRe.FindStringSubmatchIndex(msg); match != nil {
68		msg = msg[0:match[0]] + "at LOCATION" + msg[match[1]:]
69	}
70	em.got = append(em.got, &errorDesc{
71		file: pos.File,
72		line: pos.Line,
73		col:  pos.Col,
74		text: msg,
75	})
76}
77
78func (em *ErrorMatcher) Count() int {
79	return len(em.got)
80}
81
82func (em *ErrorMatcher) Check(t *testing.T) {
83nextErr:
84	for _, e := range em.got {
85		for _, want := range em.expect {
86			if want.matched || want.line != e.line || want.text != e.text {
87				continue
88			}
89			want.matched = true
90			continue nextErr
91		}
92		t.Errorf("unexpected error:\n%v:%v:%v: %v", e.file, e.line, e.col, e.text)
93	}
94	for _, want := range em.expect {
95		if want.matched {
96			continue
97		}
98		t.Errorf("unmatched error:\n%v:%v: %v", want.file, want.line, want.text)
99	}
100}
101
102func (em *ErrorMatcher) DumpErrors(t *testing.T) {
103	for _, e := range em.got {
104		t.Logf("%v:%v:%v: %v", e.file, e.line, e.col, e.text)
105	}
106}
107