...
1
2
3
4
5
6 package main
7
8 import (
9 "archive/zip"
10 "bytes"
11 "flag"
12 "fmt"
13 "go/format"
14 "io"
15 "io/ioutil"
16 "log"
17 "net/http"
18 "os"
19 "regexp"
20 "strconv"
21 "strings"
22 "text/template"
23 "time"
24 )
25
26 type invalid struct {
27 Name string
28 Input string
29 }
30
31 type valid struct {
32 Name string
33 Input string
34 JsonRef string
35 }
36
37 type testsCollection struct {
38 Ref string
39 Timestamp string
40 Invalid []invalid
41 Valid []valid
42 Count int
43 }
44
45 const srcTemplate = "// Generated by tomltestgen for toml-test ref {{.Ref}} on {{.Timestamp}}\n" +
46 "package toml\n" +
47 " import (\n" +
48 " \"testing\"\n" +
49 ")\n" +
50
51 "{{range .Invalid}}\n" +
52 "func TestInvalid{{.Name}}(t *testing.T) {\n" +
53 " input := {{.Input|gostr}}\n" +
54 " testgenInvalid(t, input)\n" +
55 "}\n" +
56 "{{end}}\n" +
57 "\n" +
58 "{{range .Valid}}\n" +
59 "func TestValid{{.Name}}(t *testing.T) {\n" +
60 " input := {{.Input|gostr}}\n" +
61 " jsonRef := {{.JsonRef|gostr}}\n" +
62 " testgenValid(t, input, jsonRef)\n" +
63 "}\n" +
64 "{{end}}\n"
65
66 func downloadTmpFile(url string) string {
67 log.Println("starting to download file from", url)
68 resp, err := http.Get(url)
69 if err != nil {
70 panic(err)
71 }
72 defer resp.Body.Close()
73
74 tmpfile, err := ioutil.TempFile("", "toml-test-*.zip")
75 if err != nil {
76 panic(err)
77 }
78 defer tmpfile.Close()
79
80 copiedLen, err := io.Copy(tmpfile, resp.Body)
81 if err != nil {
82 panic(err)
83 }
84 if resp.ContentLength > 0 && copiedLen != resp.ContentLength {
85 panic(fmt.Errorf("copied %d bytes, request body had %d", copiedLen, resp.ContentLength))
86 }
87 return tmpfile.Name()
88 }
89
90 func kebabToCamel(kebab string) string {
91 camel := ""
92 nextUpper := true
93 for _, c := range kebab {
94 if nextUpper {
95 camel += strings.ToUpper(string(c))
96 nextUpper = false
97 } else if c == '-' {
98 nextUpper = true
99 } else {
100 camel += string(c)
101 }
102 }
103 return camel
104 }
105
106 func readFileFromZip(f *zip.File) string {
107 reader, err := f.Open()
108 if err != nil {
109 panic(err)
110 }
111 defer reader.Close()
112 bytes, err := ioutil.ReadAll(reader)
113 if err != nil {
114 panic(err)
115 }
116 return string(bytes)
117 }
118
119 func templateGoStr(input string) string {
120 if len(input) > 0 && input[len(input)-1] == '\n' {
121 input = input[0 : len(input)-1]
122 }
123 if strings.Contains(input, "`") {
124 lines := strings.Split(input, "\n")
125 for idx, line := range lines {
126 lines[idx] = strconv.Quote(line + "\n")
127 }
128 return strings.Join(lines, " + \n")
129 }
130 return "`" + input + "`"
131 }
132
133 var (
134 ref = flag.String("r", "master", "git reference")
135 )
136
137 func usage() {
138 _, _ = fmt.Fprintf(os.Stderr, "usage: tomltestgen [flags]\n")
139 flag.PrintDefaults()
140 }
141
142 func main() {
143 flag.Usage = usage
144 flag.Parse()
145
146 url := "https://codeload.github.com/BurntSushi/toml-test/zip/" + *ref
147 resultFile := downloadTmpFile(url)
148 defer os.Remove(resultFile)
149 log.Println("file written to", resultFile)
150
151 zipReader, err := zip.OpenReader(resultFile)
152 if err != nil {
153 panic(err)
154 }
155 defer zipReader.Close()
156
157 collection := testsCollection{
158 Ref: *ref,
159 Timestamp: time.Now().Format(time.RFC3339),
160 }
161
162 zipFilesMap := map[string]*zip.File{}
163
164 for _, f := range zipReader.File {
165 zipFilesMap[f.Name] = f
166 }
167
168 testFileRegexp := regexp.MustCompile(`([^/]+/tests/(valid|invalid)/(.+))\.(toml)`)
169 for _, f := range zipReader.File {
170 groups := testFileRegexp.FindStringSubmatch(f.Name)
171 if len(groups) > 0 {
172 name := kebabToCamel(groups[3])
173 testType := groups[2]
174
175 log.Printf("> [%s] %s\n", testType, name)
176
177 tomlContent := readFileFromZip(f)
178
179 switch testType {
180 case "invalid":
181 collection.Invalid = append(collection.Invalid, invalid{
182 Name: name,
183 Input: tomlContent,
184 })
185 collection.Count++
186 case "valid":
187 baseFilePath := groups[1]
188 jsonFilePath := baseFilePath + ".json"
189 jsonContent := readFileFromZip(zipFilesMap[jsonFilePath])
190
191 collection.Valid = append(collection.Valid, valid{
192 Name: name,
193 Input: tomlContent,
194 JsonRef: jsonContent,
195 })
196 collection.Count++
197 default:
198 panic(fmt.Sprintf("unknown test type: %s", testType))
199 }
200 }
201 }
202
203 log.Printf("Collected %d tests from toml-test\n", collection.Count)
204
205 funcMap := template.FuncMap{
206 "gostr": templateGoStr,
207 }
208 t := template.Must(template.New("src").Funcs(funcMap).Parse(srcTemplate))
209 buf := new(bytes.Buffer)
210 err = t.Execute(buf, collection)
211 if err != nil {
212 panic(err)
213 }
214 outputBytes, err := format.Source(buf.Bytes())
215 if err != nil {
216 panic(err)
217 }
218 fmt.Println(string(outputBytes))
219 }
220
View as plain text