...
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 package chunkedfile
26
27 import (
28 "fmt"
29 "io/ioutil"
30 "regexp"
31 "runtime"
32 "strconv"
33 "strings"
34 )
35
36 const debug = false
37
38
39
40 type Chunk struct {
41 Source string
42 filename string
43 report Reporter
44 wantErrs map[int]*regexp.Regexp
45 }
46
47
48 type Reporter interface {
49 Errorf(format string, args ...interface{})
50 }
51
52
53
54
55
56
57
58 func Read(filename string, report Reporter) (chunks []Chunk) {
59 data, err := ioutil.ReadFile(filename)
60 if err != nil {
61 report.Errorf("%s", err)
62 return
63 }
64 linenum := 1
65
66 eol := "\n"
67 if runtime.GOOS == "windows" {
68 eol = "\r\n"
69 }
70
71 for i, chunk := range strings.Split(string(data), eol+"---"+eol) {
72 if debug {
73 fmt.Printf("chunk %d at line %d: %s\n", i, linenum, chunk)
74 }
75
76 src := strings.Repeat("\n", linenum-1) + chunk
77
78 wantErrs := make(map[int]*regexp.Regexp)
79
80
81
82 lines := strings.Split(chunk, "\n")
83 for j := 0; j < len(lines); j, linenum = j+1, linenum+1 {
84 line := lines[j]
85 hashes := strings.Index(line, "###")
86 if hashes < 0 {
87 continue
88 }
89 rest := strings.TrimSpace(line[hashes+len("###"):])
90 pattern, err := strconv.Unquote(rest)
91 if err != nil {
92 report.Errorf("\n%s:%d: not a quoted regexp: %s", filename, linenum, rest)
93 continue
94 }
95 rx, err := regexp.Compile(pattern)
96 if err != nil {
97 report.Errorf("\n%s:%d: %v", filename, linenum, err)
98 continue
99 }
100 wantErrs[linenum] = rx
101 if debug {
102 fmt.Printf("\t%d\t%s\n", linenum, rx)
103 }
104 }
105 linenum++
106
107 chunks = append(chunks, Chunk{src, filename, report, wantErrs})
108 }
109 return chunks
110 }
111
112
113
114 func (chunk *Chunk) GotError(linenum int, msg string) {
115 if rx, ok := chunk.wantErrs[linenum]; ok {
116 delete(chunk.wantErrs, linenum)
117 if !rx.MatchString(msg) {
118 chunk.report.Errorf("\n%s:%d: error %q does not match pattern %q", chunk.filename, linenum, msg, rx)
119 }
120 } else {
121 chunk.report.Errorf("\n%s:%d: unexpected error: %v", chunk.filename, linenum, msg)
122 }
123 }
124
125
126
127 func (chunk *Chunk) Done() {
128 for linenum, rx := range chunk.wantErrs {
129 chunk.report.Errorf("\n%s:%d: expected error matching %q", chunk.filename, linenum, rx)
130 }
131 }
132
View as plain text