forked from arnodel/golua
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlinechecker.go
100 lines (88 loc) · 2.23 KB
/
linechecker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package luatesting
import (
"bufio"
"bytes"
"fmt"
"regexp"
)
var expectedPtn = regexp.MustCompile(`^ *--> [=~].*$`)
type LineChecker struct {
SourceLineno int
lineChecker
}
type lineChecker interface {
CheckLine([]byte) error
}
type LiteralLineChecker []byte
func (c LiteralLineChecker) CheckLine(output []byte) error {
expected := []byte(c)
if bytes.Equal(output, expected) {
return nil
}
return fmt.Errorf("expected: %q, got: %q", expected, output)
}
type RegexLineChecker regexp.Regexp
func (c *RegexLineChecker) CheckLine(output []byte) error {
ptn := (*regexp.Regexp)(c)
if ptn.Match(output) {
return nil
}
return fmt.Errorf("expected regex: %s, got %q", ptn, output)
}
func ExtractLineCheckers(source []byte) []LineChecker {
var (
scanner = bufio.NewScanner(bytes.NewReader(source))
lineno = 0
checkers []LineChecker
)
for scanner.Scan() {
lineno++
var (
line = scanner.Bytes()
lc lineChecker
)
if !expectedPtn.Match(line) {
continue
}
line = bytes.TrimLeft(line, " ")
switch line[4] {
case '=':
lit := make([]byte, len(line)-5)
copy(lit, line[5:])
lc = LiteralLineChecker(lit)
case '~':
lc = (*RegexLineChecker)(regexp.MustCompile(string(line[5:])))
default:
panic("We shouldn't get there")
}
checkers = append(checkers, LineChecker{SourceLineno: lineno, lineChecker: lc})
}
return checkers
}
func CheckLines(output []byte, checkers []LineChecker) error {
// On windows we may get \r\n instead of \n
output = normalizeNewLines(output)
if len(output) > 0 && output[len(output)-1] == '\n' {
output = output[:len(output)-1]
}
lines := bytes.Split(output, []byte{'\n'})
for i, line := range lines {
if i >= len(checkers) {
return fmt.Errorf("Extra output line #%d: %q", i+1, line)
}
if err := checkers[i].CheckLine(line); err != nil {
return fmt.Errorf("[output line %d, source line %d] %s", i+1, checkers[i].SourceLineno, err)
}
}
if len(checkers) > len(lines) {
return fmt.Errorf("Expected %d output lines, got %d", len(checkers), len(lines))
}
return nil
}
var newLines = regexp.MustCompile(`(?s)\r\n|\n\r|\r`)
func normalizeNewLines(b []byte) []byte {
if bytes.IndexByte(b, '\r') == -1 {
return b
}
return newLines.ReplaceAllLiteral(b, []byte{'\n'})
}