// tomltestgen retrieves a given version of the language-agnostic TOML test suite in // https://github.com/BurntSushi/toml-test and generates go-toml unit tests. // // Within the go-toml package, run `go generate`. Otherwise, use: // // go run github.com/pelletier/go-toml/cmd/tomltestgen -o toml_testgen_test.go package main import ( "archive/zip" "bytes" "flag" "fmt" "go/format" "io" "io/ioutil" "log" "net/http" "os" "regexp" "strconv" "strings" "text/template" "time" ) type invalid struct { Name string Input string } type valid struct { Name string Input string JsonRef string } type testsCollection struct { Ref string Timestamp string Invalid []invalid Valid []valid Count int } const srcTemplate = "// Generated by tomltestgen for toml-test ref {{.Ref}} on {{.Timestamp}}\n" + "package toml_test\n" + " import (\n" + " \"testing\"\n" + ")\n" + "{{range .Invalid}}\n" + "func TestTOMLTest_Invalid_{{.Name}}(t *testing.T) {\n" + " input := {{.Input|gostr}}\n" + " testgenInvalid(t, input)\n" + "}\n" + "{{end}}\n" + "\n" + "{{range .Valid}}\n" + "func TestTOMLTest_Valid_{{.Name}}(t *testing.T) {\n" + " input := {{.Input|gostr}}\n" + " jsonRef := {{.JsonRef|gostr}}\n" + " testgenValid(t, input, jsonRef)\n" + "}\n" + "{{end}}\n" func downloadTmpFile(url string) string { log.Println("starting to download file from", url) resp, err := http.Get(url) if err != nil { panic(err) } defer resp.Body.Close() tmpfile, err := ioutil.TempFile("", "toml-test-*.zip") if err != nil { panic(err) } defer tmpfile.Close() copiedLen, err := io.Copy(tmpfile, resp.Body) if err != nil { panic(err) } if resp.ContentLength > 0 && copiedLen != resp.ContentLength { panic(fmt.Errorf("copied %d bytes, request body had %d", copiedLen, resp.ContentLength)) } return tmpfile.Name() } func kebabToCamel(kebab string) string { camel := "" nextUpper := true for _, c := range kebab { if nextUpper { camel += strings.ToUpper(string(c)) nextUpper = false } else if c == '-' { nextUpper = true } else if c == '/' { nextUpper = true camel += "_" } else { camel += string(c) } } return camel } func readFileFromZip(f *zip.File) string { reader, err := f.Open() if err != nil { panic(err) } defer reader.Close() bytes, err := ioutil.ReadAll(reader) if err != nil { panic(err) } return string(bytes) } func templateGoStr(input string) string { return strconv.Quote(input) } var ( ref = flag.String("r", "master", "git reference") out = flag.String("o", "", "output file") ) func usage() { _, _ = fmt.Fprintf(os.Stderr, "usage: tomltestgen [flags]\n") flag.PrintDefaults() } func main() { flag.Usage = usage flag.Parse() url := "https://codeload.github.com/BurntSushi/toml-test/zip/" + *ref resultFile := downloadTmpFile(url) defer os.Remove(resultFile) log.Println("file written to", resultFile) zipReader, err := zip.OpenReader(resultFile) if err != nil { panic(err) } defer zipReader.Close() collection := testsCollection{ Ref: *ref, Timestamp: time.Now().Format(time.RFC3339), } zipFilesMap := map[string]*zip.File{} for _, f := range zipReader.File { zipFilesMap[f.Name] = f } testFileRegexp := regexp.MustCompile(`([^/]+/tests/(valid|invalid)/(.+))\.(toml)`) for _, f := range zipReader.File { groups := testFileRegexp.FindStringSubmatch(f.Name) if len(groups) > 0 { name := kebabToCamel(groups[3]) testType := groups[2] log.Printf("> [%s] %s\n", testType, name) tomlContent := readFileFromZip(f) switch testType { case "invalid": collection.Invalid = append(collection.Invalid, invalid{ Name: name, Input: tomlContent, }) collection.Count++ case "valid": baseFilePath := groups[1] jsonFilePath := baseFilePath + ".json" jsonContent := readFileFromZip(zipFilesMap[jsonFilePath]) collection.Valid = append(collection.Valid, valid{ Name: name, Input: tomlContent, JsonRef: jsonContent, }) collection.Count++ default: panic(fmt.Sprintf("unknown test type: %s", testType)) } } } log.Printf("Collected %d tests from toml-test\n", collection.Count) funcMap := template.FuncMap{ "gostr": templateGoStr, } t := template.Must(template.New("src").Funcs(funcMap).Parse(srcTemplate)) buf := new(bytes.Buffer) err = t.Execute(buf, collection) if err != nil { panic(err) } outputBytes, err := format.Source(buf.Bytes()) if err != nil { panic(err) } if *out == "" { fmt.Println(string(outputBytes)) return } err = os.WriteFile(*out, outputBytes, 0644) if err != nil { panic(err) } }