...

Source file src/github.com/pelletier/go-toml/cmd/tomltestgen/main.go

Documentation: github.com/pelletier/go-toml/cmd/tomltestgen

     1  // Tomltestgen is a program that retrieves a given version of
     2  // https://github.com/BurntSushi/toml-test and generates go code for go-toml's unit tests
     3  // based on the test files.
     4  //
     5  // Usage: go run github.com/pelletier/go-toml/cmd/tomltestgen > toml_testgen_test.go
     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