diff --git a/cmd/tomltestgen/main.go b/cmd/tomltestgen/main.go new file mode 100644 index 00000000..6603d802 --- /dev/null +++ b/cmd/tomltestgen/main.go @@ -0,0 +1,224 @@ +// 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 = "// +build testsuite\n\n" + + "// 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) + } +} diff --git a/testsuite/add.go b/testsuite/add.go new file mode 100644 index 00000000..3f9bea99 --- /dev/null +++ b/testsuite/add.go @@ -0,0 +1,74 @@ +package testsuite + +import ( + "fmt" + "math" + "time" + + "github.com/pelletier/go-toml/v2" +) + +// addTag adds JSON tags to a data structure as expected by toml-test. +func addTag(key string, tomlData interface{}) interface{} { + // Switch on the data type. + switch orig := tomlData.(type) { + default: + //return map[string]interface{}{} + panic(fmt.Sprintf("Unknown type: %T", tomlData)) + + // A table: we don't need to add any tags, just recurse for every table + // entry. + case map[string]interface{}: + typed := make(map[string]interface{}, len(orig)) + for k, v := range orig { + typed[k] = addTag(k, v) + } + return typed + + // An array: we don't need to add any tags, just recurse for every table + // entry. + case []map[string]interface{}: + typed := make([]map[string]interface{}, len(orig)) + for i, v := range orig { + typed[i] = addTag("", v).(map[string]interface{}) + } + return typed + case []interface{}: + typed := make([]interface{}, len(orig)) + for i, v := range orig { + typed[i] = addTag("", v) + } + return typed + + // Datetime: tag as datetime. + case toml.LocalTime: + return tag("time-local", orig.String()) + case toml.LocalDate: + return tag("date-local", orig.String()) + case toml.LocalDateTime: + return tag("datetime-local", orig.String()) + case time.Time: + return tag("datetime", orig.Format("2006-01-02T15:04:05.999999999Z07:00")) + + // Tag primitive values: bool, string, int, and float64. + case bool: + return tag("bool", fmt.Sprintf("%v", orig)) + case string: + return tag("string", orig) + case int64: + return tag("integer", fmt.Sprintf("%d", orig)) + case float64: + // Special case for nan since NaN == NaN is false. + if math.IsNaN(orig) { + return tag("float", "nan") + } + return tag("float", fmt.Sprintf("%v", orig)) + } +} + +func tag(typeName string, data interface{}) map[string]interface{} { + return map[string]interface{}{ + "type": typeName, + "value": data, + } +} diff --git a/testsuite/parser.go b/testsuite/parser.go new file mode 100644 index 00000000..afb0005c --- /dev/null +++ b/testsuite/parser.go @@ -0,0 +1,69 @@ +package testsuite + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/pelletier/go-toml/v2" +) + +type parser struct{} + +func (p parser) Decode(input string) (output string, outputIsError bool, retErr error) { + defer func() { + if r := recover(); r != nil { + switch rr := r.(type) { + case error: + retErr = rr + default: + retErr = fmt.Errorf("%s", rr) + } + } + }() + + var v interface{} + + if err := toml.Unmarshal([]byte(input), &v); err != nil { + return err.Error(), true, nil + } + + j, err := json.MarshalIndent(addTag("", v), "", " ") + if err != nil { + return "", false, retErr + } + + return string(j), false, retErr +} + +func (p parser) Encode(input string) (output string, outputIsError bool, retErr error) { + defer func() { + if r := recover(); r != nil { + switch rr := r.(type) { + case error: + retErr = rr + default: + retErr = fmt.Errorf("%s", rr) + } + } + }() + + var tmp interface{} + err := json.Unmarshal([]byte(input), &tmp) + if err != nil { + return "", false, err + } + + rm, err := rmTag(tmp) + if err != nil { + return err.Error(), true, retErr + } + + buf := new(bytes.Buffer) + err = toml.NewEncoder(buf).Encode(rm) + if err != nil { + return err.Error(), true, retErr + } + + return buf.String(), false, retErr +} diff --git a/testsuite/rm.go b/testsuite/rm.go new file mode 100644 index 00000000..18a97039 --- /dev/null +++ b/testsuite/rm.go @@ -0,0 +1,110 @@ +package testsuite + +import ( + "fmt" + "strconv" + "time" +) + +// Remove JSON tags to a data structure as returned by toml-test. +func rmTag(typedJson interface{}) (interface{}, error) { + // Check if key is in the table m. + in := func(key string, m map[string]interface{}) bool { + _, ok := m[key] + return ok + } + + // Switch on the data type. + switch v := typedJson.(type) { + + // Object: this can either be a TOML table or a primitive with tags. + case map[string]interface{}: + // This value represents a primitive: remove the tags and return just + // the primitive value. + if len(v) == 2 && in("type", v) && in("value", v) { + ut, err := untag(v) + if err != nil { + return ut, fmt.Errorf("tag.Remove: %w", err) + } + return ut, nil + } + + // Table: remove tags on all children. + m := make(map[string]interface{}, len(v)) + for k, v2 := range v { + var err error + m[k], err = rmTag(v2) + if err != nil { + return nil, err + } + } + return m, nil + + // Array: remove tags from all itenm. + case []interface{}: + a := make([]interface{}, len(v)) + for i := range v { + var err error + a[i], err = rmTag(v[i]) + if err != nil { + return nil, err + } + } + return a, nil + } + + // The top level must be an object or array. + return nil, fmt.Errorf("unrecognized JSON format '%T'", typedJson) +} + +// Return a primitive: read the "type" and convert the "value" to that. +func untag(typed map[string]interface{}) (interface{}, error) { + t := typed["type"].(string) + v := typed["value"].(string) + switch t { + case "string": + return v, nil + case "integer": + n, err := strconv.ParseInt(v, 10, 64) + if err != nil { + return nil, fmt.Errorf("untag: %w", err) + } + return n, nil + case "float": + f, err := strconv.ParseFloat(v, 64) + if err != nil { + return nil, fmt.Errorf("untag: %w", err) + } + return f, nil + case "datetime": + return parseTime(v, "2006-01-02T15:04:05.999999999Z07:00", false) + case "datetime-local": + return parseTime(v, "2006-01-02T15:04:05.999999999", true) + case "date-local": + return parseTime(v, "2006-01-02", true) + case "time-local": + return parseTime(v, "15:04:05.999999999", true) + case "bool": + switch v { + case "true": + return true, nil + case "false": + return false, nil + } + return nil, fmt.Errorf("untag: could not parse %q as a boolean", v) + } + + return nil, fmt.Errorf("untag: unrecognized tag type %q", t) +} + +func parseTime(v, format string, local bool) (t time.Time, err error) { + if local { + t, err = time.ParseInLocation(format, v, time.Local) + } else { + t, err = time.Parse(format, v) + } + if err != nil { + return time.Time{}, fmt.Errorf("Could not parse %q as a datetime: %w", v, err) + } + return t, nil +} diff --git a/testsuite/testsuite.go b/testsuite/testsuite.go new file mode 100644 index 00000000..56c3a037 --- /dev/null +++ b/testsuite/testsuite.go @@ -0,0 +1,48 @@ +// Package testsuite provides helper functions for interoperating with the +// language-agnostic TOML test suite at github.com/BurntSushi/toml-test. +package testsuite + +import ( + "encoding/json" + "log" + "os" + + "github.com/pelletier/go-toml/v2" +) + +// Marshal is a helpfer function for calling toml.Marshal +// +// Only needed to avoid package import loops. +func Marshal(v interface{}) ([]byte, error) { + return toml.Marshal(v) +} + +// Unmarshal is a helper function for calling toml.Unmarshal. +// +// Only needed to avoid package import loops. +func Unmarshal(data []byte, v interface{}) error { + return toml.Unmarshal(data, v) +} + +// ValueToTaggedJSON takes a data structure and returns the tagged JSON +// representation. +func ValueToTaggedJSON(doc interface{}) ([]byte, error) { + return json.MarshalIndent(addTag("", doc), "", " ") +} + +// DecodeStdin is a helper function for the toml-test binary interface. TOML input +// is read from STDIN and a resulting tagged JSON representation is written to +// STDOUT. +func DecodeStdin() { + var decoded map[string]interface{} + + if err := toml.NewDecoder(os.Stdin).Decode(&decoded); err != nil { + log.Fatalf("Error decoding TOML: %s", err) + } + + j := json.NewEncoder(os.Stdout) + j.SetIndent("", " ") + if err := j.Encode(addTag("", decoded)); err != nil { + log.Fatalf("Error encoding JSON: %s", err) + } +} diff --git a/toml_testgen_support_test.go b/toml_testgen_support_test.go index 071ea6da..ea974181 100644 --- a/toml_testgen_support_test.go +++ b/toml_testgen_support_test.go @@ -1,14 +1,13 @@ +//go:generate go run ./cmd/tomltestgen/main.go -o toml_testgen_test.go + // This is a support file for toml_testgen_test.go package toml_test import ( "encoding/json" - "fmt" - "strconv" "testing" - "time" - "github.com/pelletier/go-toml/v2" + "github.com/pelletier/go-toml/v2/testsuite" "github.com/stretchr/testify/require" ) @@ -17,10 +16,14 @@ func testgenInvalid(t *testing.T, input string) { t.Logf("Input TOML:\n%s", input) doc := map[string]interface{}{} - err := toml.Unmarshal([]byte(input), &doc) + err := testsuite.Unmarshal([]byte(input), &doc) if err == nil { - t.Log(json.Marshal(doc)) + out, err := json.Marshal(doc) + if err != nil { + panic("could not marshal map to json") + } + t.Log("JSON output from unmarshal:", string(out)) t.Fatalf("test did not fail") } } @@ -29,124 +32,14 @@ func testgenValid(t *testing.T, input string, jsonRef string) { t.Helper() t.Logf("Input TOML:\n%s", input) - doc := map[string]interface{}{} + // TODO: change this to interface{} + var doc map[string]interface{} - err := toml.Unmarshal([]byte(input), &doc) + err := testsuite.Unmarshal([]byte(input), &doc) if err != nil { t.Fatalf("failed parsing toml: %s", err) } - - refDoc := testgenBuildRefDoc(jsonRef) - - require.Equal(t, refDoc, doc) - - out, err := toml.Marshal(doc) - require.NoError(t, err) - - doc2 := map[string]interface{}{} - err = toml.Unmarshal(out, &doc2) + j, err := testsuite.ValueToTaggedJSON(doc) require.NoError(t, err) - - require.Equal(t, refDoc, doc2) -} - -func testgenBuildRefDoc(jsonRef string) map[string]interface{} { - descTree := map[string]interface{}{} - - err := json.Unmarshal([]byte(jsonRef), &descTree) - if err != nil { - panic(fmt.Sprintf("reference doc should be valid JSON: %s", err)) - } - - doc := testGenTranslateDesc(descTree) - if doc == nil { - return map[string]interface{}{} - } - - return doc.(map[string]interface{}) -} - -//nolint:funlen,gocognit,cyclop -func testGenTranslateDesc(input interface{}) interface{} { - a, ok := input.([]interface{}) - if ok { - xs := make([]interface{}, len(a)) - for i, v := range a { - xs[i] = testGenTranslateDesc(v) - } - - return xs - } - - d, ok := input.(map[string]interface{}) - if !ok { - panic(fmt.Sprintf("input should be valid map[string]: %v", input)) - } - - var ( - dtype string - dvalue interface{} - ) - - //nolint:nestif - if len(d) == 2 { - dtypeiface, ok := d["type"] - if ok { - dvalue, ok = d["value"] - if ok { - dtype = dtypeiface.(string) - - switch dtype { - case "string": - return dvalue.(string) - case "float": - v, err := strconv.ParseFloat(dvalue.(string), 64) - if err != nil { - panic(fmt.Sprintf("invalid float '%s': %s", dvalue, err)) - } - - return v - case "integer": - v, err := strconv.ParseInt(dvalue.(string), 10, 64) - if err != nil { - panic(fmt.Sprintf("invalid int '%s': %s", dvalue, err)) - } - - return v - case "bool": - return dvalue.(string) == "true" - case "datetime": - dt, err := time.Parse("2006-01-02T15:04:05Z", dvalue.(string)) - if err != nil { - panic(fmt.Sprintf("invalid datetime '%s': %s", dvalue, err)) - } - - return dt - case "array": - if dvalue == nil { - return nil - } - - a := dvalue.([]interface{}) - - xs := make([]interface{}, len(a)) - - for i, v := range a { - xs[i] = testGenTranslateDesc(v) - } - - return xs - } - - panic(fmt.Sprintf("unknown type: %s", dtype)) - } - } - } - - dest := map[string]interface{}{} - for k, v := range d { - dest[k] = testGenTranslateDesc(v) - } - - return dest + require.Equal(t, jsonRef, string(j)+"\n") } diff --git a/toml_testgen_test.go b/toml_testgen_test.go index 1be0d14f..3eab4f73 100644 --- a/toml_testgen_test.go +++ b/toml_testgen_test.go @@ -1,1002 +1,1526 @@ -// Generated by tomltestgen for toml-test ref 39e37e6 on 2019-03-19T23:58:45-07:00 +//go:build testsuite +// +build testsuite + +// Generated by tomltestgen for toml-test ref master on 2021-09-30T20:29:36-05:00 package toml_test import ( "testing" ) -func TestInvalidDatetimeMalformedNoLeads(t *testing.T) { +func TestTOMLTest_Invalid_Array_MissingSeparator(t *testing.T) { + input := "wrong = [ 1 2 3 ]\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_NoClose2(t *testing.T) { + input := "x = [42 #\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_NoCloseTable2(t *testing.T) { + input := "x = [{ key = 42 #\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_NoCloseTable(t *testing.T) { + input := "x = [{ key = 42\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_NoClose(t *testing.T) { + input := "long_array = [ 1, 2, 3\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_Tables1(t *testing.T) { + input := "# INVALID TOML DOC\nfruit = []\n\n[[fruit]] # Not allowed\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_Tables2(t *testing.T) { + input := "# INVALID TOML DOC\n[[fruit]]\n name = \"apple\"\n\n [[fruit.variety]]\n name = \"red delicious\"\n\n # This table conflicts with the previous table\n [fruit.variety]\n name = \"granny smith\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_TextAfterArrayEntries(t *testing.T) { + input := "array = [\n \"Is there life after an array separator?\", No\n \"Entry\"\n]\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_TextBeforeArraySeparator(t *testing.T) { + input := "array = [\n \"Is there life before an array separator?\" No,\n \"Entry\"\n]\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Array_TextInArray(t *testing.T) { + input := "array = [\n \"Entry 1\",\n I don't belong,\n \"Entry 2\",\n]\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Bool_MixedCase(t *testing.T) { + input := "valid = False\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Bool_WrongCaseFalse(t *testing.T) { + input := "b = FALSE\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Bool_WrongCaseTrue(t *testing.T) { + input := "a = TRUE\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_CommentDel(t *testing.T) { + input := "comment-del = \"0x7f\" # \u007f\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_CommentLf(t *testing.T) { + input := "comment-lf = \"ctrl-P\" # \x10\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_CommentNull(t *testing.T) { + input := "comment-null = \"null\" # \x00\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_CommentUs(t *testing.T) { + input := "comment-us = \"ctrl-_\" # \x1f\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_MultiDel(t *testing.T) { + input := "multi-del = \"\"\"null\u007f\"\"\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_MultiLf(t *testing.T) { + input := "multi-lf = \"\"\"null\x10\"\"\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_MultiNull(t *testing.T) { + input := "multi-null = \"\"\"null\x00\"\"\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_MultiUs(t *testing.T) { + input := "multi-us = \"\"\"null\x1f\"\"\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawmultiDel(t *testing.T) { + input := "rawmulti-del = '''null\u007f'''\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawmultiLf(t *testing.T) { + input := "rawmulti-lf = '''null\x10'''\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawmultiNull(t *testing.T) { + input := "rawmulti-null = '''null\x00'''\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawmultiUs(t *testing.T) { + input := "rawmulti-us = '''null\x1f'''\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawstringDel(t *testing.T) { + input := "rawstring-del = 'null\u007f'\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawstringLf(t *testing.T) { + input := "rawstring-lf = 'null\x10'\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawstringNull(t *testing.T) { + input := "rawstring-null = 'null\x00'\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_RawstringUs(t *testing.T) { + input := "rawstring-us = 'null\x1f'\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_StringBs(t *testing.T) { + input := "string-bs = \"backspace\b\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_StringDel(t *testing.T) { + input := "string-del = \"null\u007f\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_StringLf(t *testing.T) { + input := "string-lf = \"null\x10\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_StringNull(t *testing.T) { + input := "string-null = \"null\x00\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Control_StringUs(t *testing.T) { + input := "string-us = \"null\x1f\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Datetime_ImpossibleDate(t *testing.T) { + input := "d = 2006-01-50T00:00:00Z\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Datetime_NoLeadsWithMilli(t *testing.T) { + input := "with-milli = 1987-07-5T17:45:00.12Z\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Datetime_NoLeads(t *testing.T) { + input := "no-leads = 1987-7-05T17:45:00Z\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Datetime_NoSecs(t *testing.T) { + input := "no-secs = 1987-07-05T17:45Z\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Datetime_NoT(t *testing.T) { + input := "no-t = 1987-07-0517:45:00Z\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Datetime_TrailingT(t *testing.T) { + input := "d = 2006-01-30T\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Encoding_BadUtf8AtEnd(t *testing.T) { + input := "# There is a 0xda at after the quotes, and no EOL at the end of the file.\n#\n# This is a bit of an edge case: This indicates there should be two bytes\n# (0b1101_1010) but there is no byte to follow because it's the end of the file.\nx = \"\"\"\"\"\"\xda" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Encoding_BadUtf8InComment(t *testing.T) { + input := "# \xc3\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Encoding_BadUtf8InString(t *testing.T) { + input := "# The following line contains an invalid UTF-8 sequence.\nbad = \"\xc3\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Encoding_BomNotAtStart1(t *testing.T) { + input := "bom-not-at-start \xff\xfd\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Encoding_BomNotAtStart2(t *testing.T) { + input := "bom-not-at-start= \xff\xfd\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Encoding_Utf16Bom(t *testing.T) { + input := "\xfe\xff\x00#\x00 \x00U\x00T\x00F\x00-\x001\x006\x00 \x00w\x00i\x00t\x00h\x00 \x00B\x00O\x00M\x00\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Encoding_Utf16(t *testing.T) { + input := "\x00#\x00 \x00U\x00T\x00F\x00-\x001\x006\x00 \x00w\x00i\x00t\x00h\x00o\x00u\x00t\x00 \x00B\x00O\x00M\x00\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_DoublePoint1(t *testing.T) { + input := "double-point-1 = 0..1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_DoublePoint2(t *testing.T) { + input := "double-point-2 = 0.1.2\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_ExpDoubleE1(t *testing.T) { + input := "exp-double-e-1 = 1ee2\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_ExpDoubleE2(t *testing.T) { + input := "exp-double-e-2 = 1e2e3\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_ExpDoubleUs(t *testing.T) { + input := "exp-double-us = 1e__23\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_ExpLeadingUs(t *testing.T) { + input := "exp-leading-us = 1e_23\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_ExpPoint1(t *testing.T) { + input := "exp-point-1 = 1e2.3\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_ExpPoint2(t *testing.T) { + input := "exp-point-2 = 1.e2\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_ExpTrailingUs(t *testing.T) { + input := "exp-trailing-us = 1e_23_\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_InfIncomplete1(t *testing.T) { + input := "inf-incomplete-1 = in\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_InfIncomplete2(t *testing.T) { + input := "inf-incomplete-2 = +in\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_InfIncomplete3(t *testing.T) { + input := "inf-incomplete-3 = -in\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_Inf_underscore(t *testing.T) { + input := "inf_underscore = in_f\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_LeadingPointNeg(t *testing.T) { + input := "leading-point-neg = -.12345\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_LeadingPointPlus(t *testing.T) { + input := "leading-point-plus = +.12345\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_LeadingPoint(t *testing.T) { + input := "leading-point = .12345\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_LeadingUs(t *testing.T) { + input := "leading-us = _1.2\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_LeadingZeroNeg(t *testing.T) { + input := "leading-zero-neg = -03.14\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_LeadingZeroPlus(t *testing.T) { + input := "leading-zero-plus = +03.14\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_LeadingZero(t *testing.T) { + input := "leading-zero = 03.14\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_NanIncomplete1(t *testing.T) { + input := "nan-incomplete-1 = na\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_NanIncomplete2(t *testing.T) { + input := "nan-incomplete-2 = +na\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_NanIncomplete3(t *testing.T) { + input := "nan-incomplete-3 = -na\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_Nan_underscore(t *testing.T) { + input := "nan_underscore = na_n\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_TrailingPointMin(t *testing.T) { + input := "trailing-point-min = -1.\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_TrailingPointPlus(t *testing.T) { + input := "trailing-point-plus = +1.\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_TrailingPoint(t *testing.T) { + input := "trailing-point = 1.\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_TrailingUs(t *testing.T) { + input := "trailing-us = 1.2_\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_UsAfterPoint(t *testing.T) { + input := "us-after-point = 1._2\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Float_UsBeforePoint(t *testing.T) { + input := "us-before-point = 1_.2\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_DoubleComma(t *testing.T) { + input := "t = {x=3,,y=4}\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_Empty(t *testing.T) { + input := "t = {,}\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_Linebreak1(t *testing.T) { + input := "# No newlines are allowed between the curly braces unless they are valid within\n# a value.\nsimple = { a = 1 \n}\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_Linebreak2(t *testing.T) { + input := "t = {a=1,\nb=2}\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_Linebreak3(t *testing.T) { + input := "t = {a=1\n,b=2}\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_Linebreak4(t *testing.T) { + input := "json_like = {\n first = \"Tom\",\n last = \"Preston-Werner\"\n}\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_NoComma(t *testing.T) { + input := "t = {x = 3 y = 4}\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_InlineTable_TrailingComma(t *testing.T) { + input := "# A terminating comma (also called trailing comma) is not permitted after the\n# last key/value pair in an inline table\nabc = { abc = 123, }\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_CapitalBin(t *testing.T) { + input := "capital-bin = 0B0\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_CapitalHex(t *testing.T) { + input := "capital-hex = 0X1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_CapitalOct(t *testing.T) { + input := "capital-oct = 0O0\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_DoubleSignNex(t *testing.T) { + input := "double-sign-nex = --99\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_DoubleSignPlus(t *testing.T) { + input := "double-sign-plus = ++99\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_DoubleUs(t *testing.T) { + input := "double-us = 1__23\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_InvalidBin(t *testing.T) { + input := "invalid-bin = 0b0012\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_InvalidHex(t *testing.T) { + input := "invalid-hex = 0xaafz\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_InvalidOct(t *testing.T) { + input := "invalid-oct = 0o778\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingUsBin(t *testing.T) { + input := "leading-us-bin = _0o1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingUsHex(t *testing.T) { + input := "leading-us-hex = _0o1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingUsOct(t *testing.T) { + input := "leading-us-oct = _0o1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingUs(t *testing.T) { + input := "leading-us = _123\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingZero1(t *testing.T) { + input := "leading-zero-1 = 01\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingZero2(t *testing.T) { + input := "leading-zero-2 = 00\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingZeroSign1(t *testing.T) { + input := "leading-zero-sign-1 = -01\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_LeadingZeroSign2(t *testing.T) { + input := "leading-zero-sign-2 = +01\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_NegativeBin(t *testing.T) { + input := "negative-bin = -0b11010110\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_NegativeHex(t *testing.T) { + input := "negative-hex = -0xff\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_NegativeOct(t *testing.T) { + input := "negative-oct = -0o99\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_PositiveBin(t *testing.T) { + input := "positive-bin = +0b11010110\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_PositiveHex(t *testing.T) { + input := "positive-hex = +0xff\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_PositiveOct(t *testing.T) { + input := "positive-oct = +0o99\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_TextAfterInteger(t *testing.T) { + input := "answer = 42 the ultimate answer?\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_TrailingUsBin(t *testing.T) { + input := "trailing-us-bin = 0b1_\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_TrailingUsHex(t *testing.T) { + input := "trailing-us-hex = 0x1_\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_TrailingUsOct(t *testing.T) { + input := "trailing-us-oct = 0o1_\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_TrailingUs(t *testing.T) { + input := "trailing-us = 123_\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_UsAfterBin(t *testing.T) { + input := "us-after-bin = 0b_1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_UsAfterHex(t *testing.T) { + input := "us-after-hex = 0x_1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Integer_UsAfterOct(t *testing.T) { + input := "us-after-oct = 0o_1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_AfterArray(t *testing.T) { + input := "[[agencies]] owner = \"S Cjelli\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_AfterTable(t *testing.T) { + input := "[error] this = \"should not be here\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_AfterValue(t *testing.T) { + input := "first = \"Tom\" last = \"Preston-Werner\" # INVALID\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_BareInvalidCharacter(t *testing.T) { + input := "bare!key = 123\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_DottedRedefineTable(t *testing.T) { + input := "# Defined a.b as int\na.b = 1\n# Tries to access it as table: error\na.b.c = 2\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_DuplicateKeys(t *testing.T) { + input := "dupe = false\ndupe = true\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_Duplicate(t *testing.T) { + input := "# DO NOT DO THIS\nname = \"Tom\"\nname = \"Pradyun\"\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_Empty(t *testing.T) { + input := " = 1\n" + testgenInvalid(t, input) +} + +func TestTOMLTest_Invalid_Key_Escape(t *testing.T) { + input := "\\u00c0 = \"latin capital letter A with grave\"\n" + testgenInvalid(t, input) +} - input := `no-leads = 1987-7-05T17:45:00Z` +func TestTOMLTest_Invalid_Key_Hash(t *testing.T) { + input := "a# = 1\n" testgenInvalid(t, input) } -func TestInvalidDatetimeMalformedNoSecs(t *testing.T) { +func TestTOMLTest_Invalid_Key_Multiline(t *testing.T) { + input := "\"\"\"long\nkey\"\"\" = 1\n" + testgenInvalid(t, input) +} - input := `no-secs = 1987-07-05T17:45Z` +func TestTOMLTest_Invalid_Key_Newline(t *testing.T) { + input := "barekey\n = 123\n" testgenInvalid(t, input) } -func TestInvalidDatetimeMalformedNoT(t *testing.T) { +func TestTOMLTest_Invalid_Key_NoEol(t *testing.T) { + input := "a = 1 b = 2\n" + testgenInvalid(t, input) +} - input := `no-t = 1987-07-0517:45:00Z` +func TestTOMLTest_Invalid_Key_OpenBracket(t *testing.T) { + input := "[abc = 1\n" testgenInvalid(t, input) } -func TestInvalidDatetimeMalformedWithMilli(t *testing.T) { +func TestTOMLTest_Invalid_Key_PartialQuoted(t *testing.T) { + input := "partial\"quoted\" = 5\n" + testgenInvalid(t, input) +} - input := `with-milli = 1987-07-5T17:45:00.12Z` +func TestTOMLTest_Invalid_Key_SingleOpenBracket(t *testing.T) { + input := "[\n" testgenInvalid(t, input) } -func TestInvalidDuplicateKeyTable(t *testing.T) { +func TestTOMLTest_Invalid_Key_Space(t *testing.T) { + input := "a b = 1\n" + testgenInvalid(t, input) +} - input := `[fruit] -type = "apple" +func TestTOMLTest_Invalid_Key_SpecialCharacter(t *testing.T) { + input := "μ = \"greek small letter mu\"\n" + testgenInvalid(t, input) +} -[fruit.type] -apple = "yes"` +func TestTOMLTest_Invalid_Key_StartBracket(t *testing.T) { + input := "[a]\n[xyz = 5\n[b]\n" testgenInvalid(t, input) } -func TestInvalidDuplicateKeys(t *testing.T) { +func TestTOMLTest_Invalid_Key_TwoEquals(t *testing.T) { + input := "key= = 1\n" + testgenInvalid(t, input) +} - input := `dupe = false -dupe = true` +func TestTOMLTest_Invalid_Key_TwoEquals2(t *testing.T) { + input := "a==1\n" testgenInvalid(t, input) } -func TestInvalidDuplicateTables(t *testing.T) { +func TestTOMLTest_Invalid_Key_TwoEquals3(t *testing.T) { + input := "a=b=1\n" + testgenInvalid(t, input) +} - input := `[a] -[a]` +func TestTOMLTest_Invalid_Key_WithoutValue1(t *testing.T) { + input := "key\n" testgenInvalid(t, input) } -func TestInvalidEmptyImplicitTable(t *testing.T) { +func TestTOMLTest_Invalid_Key_WithoutValue2(t *testing.T) { + input := "key = \n" + testgenInvalid(t, input) +} - input := `[naughty..naughty]` +func TestTOMLTest_Invalid_String_BadByteEscape(t *testing.T) { + input := "naughty = \"\\xAg\"\n" testgenInvalid(t, input) } -func TestInvalidEmptyTable(t *testing.T) { +func TestTOMLTest_Invalid_String_BadCodepoint(t *testing.T) { + input := "invalid-codepoint = \"This string contains a non scalar unicode codepoint \\uD801\"\n" + testgenInvalid(t, input) +} - input := `[]` +func TestTOMLTest_Invalid_String_BadConcat(t *testing.T) { + input := "no_concat = \"first\" \"second\"\n" testgenInvalid(t, input) } -func TestInvalidFloatNoLeadingZero(t *testing.T) { +func TestTOMLTest_Invalid_String_BadEscape(t *testing.T) { + input := "invalid-escape = \"This string has a bad \\a escape character.\"\n" + testgenInvalid(t, input) +} - input := `answer = .12345 -neganswer = -.12345` +func TestTOMLTest_Invalid_String_BadMultiline(t *testing.T) { + input := "multi = \"first line\nsecond line\"\n" testgenInvalid(t, input) } -func TestInvalidFloatNoTrailingDigits(t *testing.T) { +func TestTOMLTest_Invalid_String_BadSlashEscape(t *testing.T) { + input := "invalid-escape = \"This string has a bad \\/ escape character.\"\n" + testgenInvalid(t, input) +} - input := `answer = 1. -neganswer = -1.` +func TestTOMLTest_Invalid_String_BadUniEsc(t *testing.T) { + input := "str = \"val\\ue\"\n" testgenInvalid(t, input) } -func TestInvalidKeyEmpty(t *testing.T) { +func TestTOMLTest_Invalid_String_BasicByteEscapes(t *testing.T) { + input := "answer = \"\\x33\"\n" + testgenInvalid(t, input) +} - input := ` = 1` +func TestTOMLTest_Invalid_String_BasicMultilineOutOfRangeUnicodeEscape1(t *testing.T) { + input := "a = \"\"\"\\UFFFFFFFF\"\"\"\n" testgenInvalid(t, input) } -func TestInvalidKeyHash(t *testing.T) { +func TestTOMLTest_Invalid_String_BasicMultilineOutOfRangeUnicodeEscape2(t *testing.T) { + input := "a = \"\"\"\\U00D80000\"\"\"\n" + testgenInvalid(t, input) +} - input := `a# = 1` +func TestTOMLTest_Invalid_String_BasicMultilineQuotes(t *testing.T) { + input := "str5 = \"\"\"Here are three quotation marks: \"\"\".\"\"\"\n" testgenInvalid(t, input) } -func TestInvalidKeyNewline(t *testing.T) { +func TestTOMLTest_Invalid_String_BasicMultilineUnknownEscape(t *testing.T) { + input := "a = \"\"\"\\@\"\"\"\n" + testgenInvalid(t, input) +} - input := `a -= 1` +func TestTOMLTest_Invalid_String_BasicOutOfRangeUnicodeEscape1(t *testing.T) { + input := "a = \"\\UFFFFFFFF\"\n" testgenInvalid(t, input) } -func TestInvalidKeyOpenBracket(t *testing.T) { +func TestTOMLTest_Invalid_String_BasicOutOfRangeUnicodeEscape2(t *testing.T) { + input := "a = \"\\U00D80000\"\n" + testgenInvalid(t, input) +} - input := `[abc = 1` +func TestTOMLTest_Invalid_String_BasicUnknownEscape(t *testing.T) { + input := "a = \"\\@\"\n" testgenInvalid(t, input) } -func TestInvalidKeySingleOpenBracket(t *testing.T) { +func TestTOMLTest_Invalid_String_LiteralMultilineQuotes1(t *testing.T) { + input := "a = '''6 apostrophes: ''''''\n\n" + testgenInvalid(t, input) +} - input := `[` +func TestTOMLTest_Invalid_String_LiteralMultilineQuotes2(t *testing.T) { + input := "a = '''15 apostrophes: ''''''''''''''''''\n" testgenInvalid(t, input) } -func TestInvalidKeySpace(t *testing.T) { +func TestTOMLTest_Invalid_String_MissingQuotes(t *testing.T) { + input := "name = value\n" + testgenInvalid(t, input) +} - input := `a b = 1` +func TestTOMLTest_Invalid_String_MultilineEscapeSpace(t *testing.T) { + input := "a = \"\"\"\n foo \\ \\n\n bar\"\"\"\n" testgenInvalid(t, input) } -func TestInvalidKeyStartBracket(t *testing.T) { +func TestTOMLTest_Invalid_String_MultilineNoClose2(t *testing.T) { + input := "x=\"\"\"\n" + testgenInvalid(t, input) +} - input := `[a] -[xyz = 5 -[b]` +func TestTOMLTest_Invalid_String_MultilineNoClose(t *testing.T) { + input := "invalid = \"\"\"\n this will fail\n" testgenInvalid(t, input) } -func TestInvalidKeyTwoEquals(t *testing.T) { +func TestTOMLTest_Invalid_String_MultilineQuotes1(t *testing.T) { + input := "a = \"\"\"6 quotes: \"\"\"\"\"\"\n" + testgenInvalid(t, input) +} - input := `key= = 1` +func TestTOMLTest_Invalid_String_MultilineQuotes2(t *testing.T) { + input := "a = \"\"\"6 quotes: \"\"\"\"\"\"\n" testgenInvalid(t, input) } -func TestInvalidStringBadByteEscape(t *testing.T) { +func TestTOMLTest_Invalid_String_NoClose(t *testing.T) { + input := "no-ending-quote = \"One time, at band camp\n" + testgenInvalid(t, input) +} - input := `naughty = "\xAg"` +func TestTOMLTest_Invalid_String_TextAfterString(t *testing.T) { + input := "string = \"Is there life after strings?\" No.\n" testgenInvalid(t, input) } -func TestInvalidStringBadEscape(t *testing.T) { +func TestTOMLTest_Invalid_String_WrongClose(t *testing.T) { + input := "bad-ending-quote = \"double and single'\n" + testgenInvalid(t, input) +} - input := `invalid-escape = "This string has a bad \a escape character."` +func TestTOMLTest_Invalid_Table_ArrayEmpty(t *testing.T) { + input := "[[]]\nname = \"Born to Run\"\n" testgenInvalid(t, input) } -func TestInvalidStringByteEscapes(t *testing.T) { +func TestTOMLTest_Invalid_Table_ArrayImplicit(t *testing.T) { + input := "# This test is a bit tricky. It should fail because the first use of\n# `[[albums.songs]]` without first declaring `albums` implies that `albums`\n# must be a table. The alternative would be quite weird. Namely, it wouldn't\n# comply with the TOML spec: \"Each double-bracketed sub-table will belong to \n# the most *recently* defined table element *above* it.\"\n#\n# This is in contrast to the *valid* test, table-array-implicit where\n# `[[albums.songs]]` works by itself, so long as `[[albums]]` isn't declared\n# later. (Although, `[albums]` could be.)\n[[albums.songs]]\nname = \"Glory Days\"\n\n[[albums]]\nname = \"Born in the USA\"\n" + testgenInvalid(t, input) +} - input := `answer = "\x33"` +func TestTOMLTest_Invalid_Table_ArrayMissingBracket(t *testing.T) { + input := "[[albums]\nname = \"Born to Run\"\n" testgenInvalid(t, input) } -func TestInvalidStringNoClose(t *testing.T) { +func TestTOMLTest_Invalid_Table_DuplicateKeyTable(t *testing.T) { + input := "[fruit]\ntype = \"apple\"\n\n[fruit.type]\napple = \"yes\"\n" + testgenInvalid(t, input) +} - input := `no-ending-quote = "One time, at band camp` +func TestTOMLTest_Invalid_Table_DuplicateTableArray(t *testing.T) { + input := "[tbl]\n[[tbl]]\n" testgenInvalid(t, input) } -func TestInvalidTableArrayImplicit(t *testing.T) { +func TestTOMLTest_Invalid_Table_DuplicateTableArray2(t *testing.T) { + input := "[[tbl]]\n[tbl]\n" + testgenInvalid(t, input) +} - input := "# This test is a bit tricky. It should fail because the first use of\n" + - "# `[[albums.songs]]` without first declaring `albums` implies that `albums`\n" + - "# must be a table. The alternative would be quite weird. Namely, it wouldn't\n" + - "# comply with the TOML spec: \"Each double-bracketed sub-table will belong to \n" + - "# the most *recently* defined table element *above* it.\"\n" + - "#\n" + - "# This is in contrast to the *valid* test, table-array-implicit where\n" + - "# `[[albums.songs]]` works by itself, so long as `[[albums]]` isn't declared\n" + - "# later. (Although, `[albums]` could be.)\n" + - "[[albums.songs]]\n" + - "name = \"Glory Days\"\n" + - "\n" + - "[[albums]]\n" + - "name = \"Born in the USA\"\n" +func TestTOMLTest_Invalid_Table_Duplicate(t *testing.T) { + input := "[a]\nb = 1\n\n[a]\nc = 2\n" testgenInvalid(t, input) } -func TestInvalidTableArrayMalformedBracket(t *testing.T) { +func TestTOMLTest_Invalid_Table_EmptyImplicitTable(t *testing.T) { + input := "[naughty..naughty]\n" + testgenInvalid(t, input) +} - input := `[[albums] -name = "Born to Run"` +func TestTOMLTest_Invalid_Table_Empty(t *testing.T) { + input := "[]\n" testgenInvalid(t, input) } -func TestInvalidTableArrayMalformedEmpty(t *testing.T) { +func TestTOMLTest_Invalid_Table_EqualsSign(t *testing.T) { + input := "[name=bad]\n" + testgenInvalid(t, input) +} - input := `[[]] -name = "Born to Run"` +func TestTOMLTest_Invalid_Table_Injection1(t *testing.T) { + input := "[a.b.c]\n z = 9\n[a]\n b.c.t = \"Using dotted keys to add to [a.b.c] after explicitly defining it above is not allowed\"\n \n# see https://github.com/toml-lang/toml/issues/846\n" testgenInvalid(t, input) } -func TestInvalidTableEmpty(t *testing.T) { +func TestTOMLTest_Invalid_Table_Injection2(t *testing.T) { + input := "[a.b.c.d]\n z = 9\n[a]\n b.c.d.k.t = \"Using dotted keys to add to [a.b.c.d] after explicitly defining it above is not allowed\"\n \n# see https://github.com/toml-lang/toml/issues/846\n" + testgenInvalid(t, input) +} - input := `[]` +func TestTOMLTest_Invalid_Table_Llbrace(t *testing.T) { + input := "[ [table]]\n" testgenInvalid(t, input) } -func TestInvalidTableNestedBracketsClose(t *testing.T) { +func TestTOMLTest_Invalid_Table_NestedBracketsClose(t *testing.T) { + input := "[a]b]\nzyx = 42\n" + testgenInvalid(t, input) +} - input := `[a]b] -zyx = 42` +func TestTOMLTest_Invalid_Table_NestedBracketsOpen(t *testing.T) { + input := "[a[b]\nzyx = 42\n" testgenInvalid(t, input) } -func TestInvalidTableNestedBracketsOpen(t *testing.T) { +func TestTOMLTest_Invalid_Table_QuotedNoClose(t *testing.T) { + input := "[\"where will it end]\nname = value\n" + testgenInvalid(t, input) +} - input := `[a[b] -zyx = 42` +func TestTOMLTest_Invalid_Table_Redefine(t *testing.T) { + input := "# Define b as int, and try to use it as a table: error\n[a]\nb = 1\n\n[a.b]\nc = 2\n" testgenInvalid(t, input) } -func TestInvalidTableWhitespace(t *testing.T) { +func TestTOMLTest_Invalid_Table_Rrbrace(t *testing.T) { + input := "[[table] ]\n" + testgenInvalid(t, input) +} - input := `[invalid key]` +func TestTOMLTest_Invalid_Table_TextAfterTable(t *testing.T) { + input := "[error] this shouldn't be here\n" testgenInvalid(t, input) } -func TestInvalidTableWithPound(t *testing.T) { +func TestTOMLTest_Invalid_Table_Whitespace(t *testing.T) { + input := "[invalid key]\n" + testgenInvalid(t, input) +} - input := `[key#group] -answer = 42` +func TestTOMLTest_Invalid_Table_WithPound(t *testing.T) { + input := "[key#group]\nanswer = 42\n" testgenInvalid(t, input) } -func TestInvalidTextAfterArrayEntries(t *testing.T) { +func TestTOMLTest_Valid_Array_Array(t *testing.T) { + input := "ints = [1, 2, 3, ]\nfloats = [1.1, 2.1, 3.1]\nstrings = [\"a\", \"b\", \"c\"]\ndates = [\n 1987-07-05T17:45:00Z,\n 1979-05-27T07:32:00Z,\n 2006-06-01T11:00:00Z,\n]\ncomments = [\n 1,\n 2, #this is ok\n]\n" + jsonRef := "{\n \"comments\": [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n ],\n \"dates\": [\n {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:00Z\"\n },\n {\n \"type\": \"datetime\",\n \"value\": \"1979-05-27T07:32:00Z\"\n },\n {\n \"type\": \"datetime\",\n \"value\": \"2006-06-01T11:00:00Z\"\n }\n ],\n \"floats\": [\n {\n \"type\": \"float\",\n \"value\": \"1.1\"\n },\n {\n \"type\": \"float\",\n \"value\": \"2.1\"\n },\n {\n \"type\": \"float\",\n \"value\": \"3.1\"\n }\n ],\n \"ints\": [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"3\"\n }\n ],\n \"strings\": [\n {\n \"type\": \"string\",\n \"value\": \"a\"\n },\n {\n \"type\": \"string\",\n \"value\": \"b\"\n },\n {\n \"type\": \"string\",\n \"value\": \"c\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `array = [ - "Is there life after an array separator?", No - "Entry" -]` - testgenInvalid(t, input) +func TestTOMLTest_Valid_Array_Bool(t *testing.T) { + input := "a = [true, false]\n" + jsonRef := "{\n \"a\": [\n {\n \"type\": \"bool\",\n \"value\": \"true\"\n },\n {\n \"type\": \"bool\",\n \"value\": \"false\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) } -func TestInvalidTextAfterInteger(t *testing.T) { +func TestTOMLTest_Valid_Array_Empty(t *testing.T) { + input := "thevoid = [[[[[]]]]]\n" + jsonRef := "{\n \"thevoid\": [\n [\n [\n [\n []\n ]\n ]\n ]\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `answer = 42 the ultimate answer?` - testgenInvalid(t, input) +func TestTOMLTest_Valid_Array_Hetergeneous(t *testing.T) { + input := "mixed = [[1, 2], [\"a\", \"b\"], [1.1, 2.1]]\n" + jsonRef := "{\n \"mixed\": [\n [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n ],\n [\n {\n \"type\": \"string\",\n \"value\": \"a\"\n },\n {\n \"type\": \"string\",\n \"value\": \"b\"\n }\n ],\n [\n {\n \"type\": \"float\",\n \"value\": \"1.1\"\n },\n {\n \"type\": \"float\",\n \"value\": \"2.1\"\n }\n ]\n ]\n}\n" + testgenValid(t, input, jsonRef) } -func TestInvalidTextAfterString(t *testing.T) { +func TestTOMLTest_Valid_Array_MixedIntArray(t *testing.T) { + input := "arrays-and-ints = [1, [\"Arrays are not integers.\"]]\n" + jsonRef := "{\n \"arrays-and-ints\": [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n [\n {\n \"type\": \"string\",\n \"value\": \"Arrays are not integers.\"\n }\n ]\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `string = "Is there life after strings?" No.` - testgenInvalid(t, input) +func TestTOMLTest_Valid_Array_MixedIntFloat(t *testing.T) { + input := "ints-and-floats = [1, 1.1]\n" + jsonRef := "{\n \"ints-and-floats\": [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"float\",\n \"value\": \"1.1\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) } -func TestInvalidTextAfterTable(t *testing.T) { +func TestTOMLTest_Valid_Array_MixedIntString(t *testing.T) { + input := "strings-and-ints = [\"hi\", 42]\n" + jsonRef := "{\n \"strings-and-ints\": [\n {\n \"type\": \"string\",\n \"value\": \"hi\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[error] this shouldn't be here` - testgenInvalid(t, input) +func TestTOMLTest_Valid_Array_MixedStringTable(t *testing.T) { + input := "contributors = [\n \"Foo Bar \",\n { name = \"Baz Qux\", email = \"bazqux@example.com\", url = \"https://example.com/bazqux\" }\n]\n" + jsonRef := "{\n \"contributors\": [\n {\n \"type\": \"string\",\n \"value\": \"Foo Bar \\u003cfoo@example.com\\u003e\"\n },\n {\n \"email\": {\n \"type\": \"string\",\n \"value\": \"bazqux@example.com\"\n },\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Baz Qux\"\n },\n \"url\": {\n \"type\": \"string\",\n \"value\": \"https://example.com/bazqux\"\n }\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) } -func TestInvalidTextBeforeArraySeparator(t *testing.T) { +func TestTOMLTest_Valid_Array_NestedDouble(t *testing.T) { + input := "nest = [\n\t[\n\t\t[\"a\"],\n\t\t[1, 2, [3]]\n\t]\n]\n" + jsonRef := "{\n \"nest\": [\n [\n [\n {\n \"type\": \"string\",\n \"value\": \"a\"\n }\n ],\n [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n },\n [\n {\n \"type\": \"integer\",\n \"value\": \"3\"\n }\n ]\n ]\n ]\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `array = [ - "Is there life before an array separator?" No, - "Entry" -]` - testgenInvalid(t, input) +func TestTOMLTest_Valid_Array_NestedInlineTable(t *testing.T) { + input := "a = [ { b = {} } ]\n" + jsonRef := "{\n \"a\": [\n {\n \"b\": {}\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) } -func TestInvalidTextInArray(t *testing.T) { +func TestTOMLTest_Valid_Array_Nested(t *testing.T) { + input := "nest = [[\"a\"], [\"b\"]]\n" + jsonRef := "{\n \"nest\": [\n [\n {\n \"type\": \"string\",\n \"value\": \"a\"\n }\n ],\n [\n {\n \"type\": \"string\",\n \"value\": \"b\"\n }\n ]\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `array = [ - "Entry 1", - I don't belong, - "Entry 2", -]` - testgenInvalid(t, input) +func TestTOMLTest_Valid_Array_Nospaces(t *testing.T) { + input := "ints = [1,2,3]\n" + jsonRef := "{\n \"ints\": [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"3\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Array_StringQuoteComma2(t *testing.T) { + input := "title = [ \" \\\", \",]\n" + jsonRef := "{\n \"title\": [\n {\n \"type\": \"string\",\n \"value\": \" \\\", \"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Array_StringQuoteComma(t *testing.T) { + input := "title = [\n\"Client: \\\"XXXX\\\", Job: XXXX\",\n\"Code: XXXX\"\n]\n" + jsonRef := "{\n \"title\": [\n {\n \"type\": \"string\",\n \"value\": \"Client: \\\"XXXX\\\", Job: XXXX\"\n },\n {\n \"type\": \"string\",\n \"value\": \"Code: XXXX\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Array_StringWithComma(t *testing.T) { + input := "title = [\n\"Client: XXXX, Job: XXXX\",\n\"Code: XXXX\"\n]\n" + jsonRef := "{\n \"title\": [\n {\n \"type\": \"string\",\n \"value\": \"Client: XXXX, Job: XXXX\"\n },\n {\n \"type\": \"string\",\n \"value\": \"Code: XXXX\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Array_Strings(t *testing.T) { + input := "string_array = [ \"all\", 'strings', \"\"\"are the same\"\"\", '''type''']\n" + jsonRef := "{\n \"string_array\": [\n {\n \"type\": \"string\",\n \"value\": \"all\"\n },\n {\n \"type\": \"string\",\n \"value\": \"strings\"\n },\n {\n \"type\": \"string\",\n \"value\": \"are the same\"\n },\n {\n \"type\": \"string\",\n \"value\": \"type\"\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Array_TableArrayStringBackslash(t *testing.T) { + input := "foo = [ { bar=\"\\\"{{baz}}\\\"\"} ]\n" + jsonRef := "{\n \"foo\": [\n {\n \"bar\": {\n \"type\": \"string\",\n \"value\": \"\\\"{{baz}}\\\"\"\n }\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Bool_Bool(t *testing.T) { + input := "t = true\nf = false\n" + jsonRef := "{\n \"f\": {\n \"type\": \"bool\",\n \"value\": \"false\"\n },\n \"t\": {\n \"type\": \"bool\",\n \"value\": \"true\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Comment_AtEof(t *testing.T) { + input := "# This is a full-line comment\nkey = \"value\" # This is a comment at the end of a line\n" + jsonRef := "{\n \"key\": {\n \"type\": \"string\",\n \"value\": \"value\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Comment_AtEof2(t *testing.T) { + input := "# This is a full-line comment\nkey = \"value\" # This is a comment at the end of a line\n" + jsonRef := "{\n \"key\": {\n \"type\": \"string\",\n \"value\": \"value\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Comment_Everywhere(t *testing.T) { + input := "# Top comment.\n # Top comment.\n# Top comment.\n\n# [no-extraneous-groups-please]\n\n[group] # Comment\nanswer = 42 # Comment\n# no-extraneous-keys-please = 999\n# Inbetween comment.\nmore = [ # Comment\n # What about multiple # comments?\n # Can you handle it?\n #\n # Evil.\n# Evil.\n 42, 42, # Comments within arrays are fun.\n # What about multiple # comments?\n # Can you handle it?\n #\n # Evil.\n# Evil.\n# ] Did I fool you?\n] # Hopefully not.\n\n# Make sure the space between the datetime and \"#\" isn't lexed.\nd = 1979-05-27T07:32:12-07:00 # c\n" + jsonRef := "{\n \"group\": {\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n },\n \"d\": {\n \"type\": \"datetime\",\n \"value\": \"1979-05-27T07:32:12-07:00\"\n },\n \"more\": [\n {\n \"type\": \"integer\",\n \"value\": \"42\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n ]\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Comment_Tricky(t *testing.T) { + input := "[section]#attached comment\n#[notsection]\none = \"11\"#cmt\ntwo = \"22#\"\nthree = '#'\n\nfour = \"\"\"# no comment\n# nor this\n#also not comment\"\"\"#is_comment\n\nfive = 5.5#66\nsix = 6#7\n8 = \"eight\"\n#nine = 99\nten = 10e2#1\neleven = 1.11e1#23\n\n[\"hash#tag\"]\n\"#!\" = \"hash bang\"\narr3 = [ \"#\", '#', \"\"\"###\"\"\" ]\narr4 = [ 1,# 9, 9,\n2#,9\n,#9\n3#]\n,4]\narr5 = [[[[#[\"#\"],\n[\"#\"]]]]#]\n]\ntbl1 = { \"#\" = '}#'}#}}\n\n\n" + jsonRef := "{\n \"hash#tag\": {\n \"#!\": {\n \"type\": \"string\",\n \"value\": \"hash bang\"\n },\n \"arr3\": [\n {\n \"type\": \"string\",\n \"value\": \"#\"\n },\n {\n \"type\": \"string\",\n \"value\": \"#\"\n },\n {\n \"type\": \"string\",\n \"value\": \"###\"\n }\n ],\n \"arr4\": [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"3\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"4\"\n }\n ],\n \"arr5\": [\n [\n [\n [\n [\n {\n \"type\": \"string\",\n \"value\": \"#\"\n }\n ]\n ]\n ]\n ]\n ],\n \"tbl1\": {\n \"#\": {\n \"type\": \"string\",\n \"value\": \"}#\"\n }\n }\n },\n \"section\": {\n \"8\": {\n \"type\": \"string\",\n \"value\": \"eight\"\n },\n \"eleven\": {\n \"type\": \"float\",\n \"value\": \"11.1\"\n },\n \"five\": {\n \"type\": \"float\",\n \"value\": \"5.5\"\n },\n \"four\": {\n \"type\": \"string\",\n \"value\": \"# no comment\\n# nor this\\n#also not comment\"\n },\n \"one\": {\n \"type\": \"string\",\n \"value\": \"11\"\n },\n \"six\": {\n \"type\": \"integer\",\n \"value\": \"6\"\n },\n \"ten\": {\n \"type\": \"float\",\n \"value\": \"1000.0\"\n },\n \"three\": {\n \"type\": \"string\",\n \"value\": \"#\"\n },\n \"two\": {\n \"type\": \"string\",\n \"value\": \"22#\"\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Datetime_Datetime(t *testing.T) { + input := "space = 1987-07-05 17:45:00Z\nlower = 1987-07-05t17:45:00z\n" + jsonRef := "{\n \"lower\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:00Z\"\n },\n \"space\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:00Z\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Datetime_LocalDate(t *testing.T) { + input := "bestdayever = 1987-07-05\n" + jsonRef := "{\n \"bestdayever\": {\n \"type\": \"date-local\",\n \"value\": \"1987-07-05\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Datetime_LocalTime(t *testing.T) { + input := "besttimeever = 17:45:00\nmilliseconds = 10:32:00.555\n" + jsonRef := "{\n \"besttimeever\": {\n \"type\": \"time-local\",\n \"value\": \"17:45:00\"\n },\n \"milliseconds\": {\n \"type\": \"time-local\",\n \"value\": \"10:32:00.555\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Datetime_Local(t *testing.T) { + input := "local = 1987-07-05T17:45:00\nmilli = 1977-12-21T10:32:00.555\nspace = 1987-07-05 17:45:00\n" + jsonRef := "{\n \"local\": {\n \"type\": \"datetime-local\",\n \"value\": \"1987-07-05T17:45:00\"\n },\n \"milli\": {\n \"type\": \"datetime-local\",\n \"value\": \"1977-12-21T10:32:00.555\"\n },\n \"space\": {\n \"type\": \"datetime-local\",\n \"value\": \"1987-07-05T17:45:00\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Datetime_Milliseconds(t *testing.T) { + input := "utc1 = 1987-07-05T17:45:56.123456Z\nutc2 = 1987-07-05T17:45:56.6Z\nwita1 = 1987-07-05T17:45:56.123456+08:00\nwita2 = 1987-07-05T17:45:56.6+08:00\n" + jsonRef := "{\n \"utc1\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56.123456Z\"\n },\n \"utc2\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56.600000Z\"\n },\n \"wita1\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56.123456+08:00\"\n },\n \"wita2\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56.600000+08:00\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Datetime_Timezone(t *testing.T) { + input := "utc = 1987-07-05T17:45:56Z\npdt = 1987-07-05T17:45:56-05:00\nnzst = 1987-07-05T17:45:56+12:00\nnzdt = 1987-07-05T17:45:56+13:00 # DST\n" + jsonRef := "{\n \"nzdt\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56+13:00\"\n },\n \"nzst\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56+12:00\"\n },\n \"pdt\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56-05:00\"\n },\n \"utc\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:56Z\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_EmptyFile(t *testing.T) { + input := "" + jsonRef := "{}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Example(t *testing.T) { + input := "best-day-ever = 1987-07-05T17:45:00Z\n\n[numtheory]\nboring = false\nperfection = [6, 28, 496]\n" + jsonRef := "{\n \"best-day-ever\": {\n \"type\": \"datetime\",\n \"value\": \"1987-07-05T17:45:00Z\"\n },\n \"numtheory\": {\n \"boring\": {\n \"type\": \"bool\",\n \"value\": \"false\"\n },\n \"perfection\": [\n {\n \"type\": \"integer\",\n \"value\": \"6\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"28\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"496\"\n }\n ]\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Float_Exponent(t *testing.T) { + input := "lower = 3e2\nupper = 3E2\nneg = 3e-2\npos = 3E+2\nzero = 3e0\npointlower = 3.1e2\npointupper = 3.1E2\nminustenth = -1E-1\n" + jsonRef := "{\n \"lower\": {\n \"type\": \"float\",\n \"value\": \"300.0\"\n },\n \"minustenth\": {\n \"type\": \"float\",\n \"value\": \"-0.1\"\n },\n \"neg\": {\n \"type\": \"float\",\n \"value\": \"0.03\"\n },\n \"pointlower\": {\n \"type\": \"float\",\n \"value\": \"310.0\"\n },\n \"pointupper\": {\n \"type\": \"float\",\n \"value\": \"310.0\"\n },\n \"pos\": {\n \"type\": \"float\",\n \"value\": \"300.0\"\n },\n \"upper\": {\n \"type\": \"float\",\n \"value\": \"300.0\"\n },\n \"zero\": {\n \"type\": \"float\",\n \"value\": \"3.0\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Float_Float(t *testing.T) { + input := "pi = 3.14\npospi = +3.14\nnegpi = -3.14\nzero-intpart = 0.123\n" + jsonRef := "{\n \"negpi\": {\n \"type\": \"float\",\n \"value\": \"-3.14\"\n },\n \"pi\": {\n \"type\": \"float\",\n \"value\": \"3.14\"\n },\n \"pospi\": {\n \"type\": \"float\",\n \"value\": \"3.14\"\n },\n \"zero-intpart\": {\n \"type\": \"float\",\n \"value\": \"0.123\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Float_InfAndNan(t *testing.T) { + input := "# We don't encode +nan and -nan back with the signs; many languages don't\n# support a sign on NaN (it doesn't really make much sense).\nnan = nan\nnan_neg = -nan\nnan_plus = +nan\ninfinity = inf\ninfinity_neg = -inf\ninfinity_plus = +inf\n" + jsonRef := "{\n \"infinity\": {\n \"type\": \"float\",\n \"value\": \"inf\"\n },\n \"infinity_neg\": {\n \"type\": \"float\",\n \"value\": \"-inf\"\n },\n \"infinity_plus\": {\n \"type\": \"float\",\n \"value\": \"+inf\"\n },\n \"nan\": {\n \"type\": \"float\",\n \"value\": \"nan\"\n },\n \"nan_neg\": {\n \"type\": \"float\",\n \"value\": \"nan\"\n },\n \"nan_plus\": {\n \"type\": \"float\",\n \"value\": \"nan\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Float_Long(t *testing.T) { + input := "longpi = 3.141592653589793\nneglongpi = -3.141592653589793\n" + jsonRef := "{\n \"longpi\": {\n \"type\": \"float\",\n \"value\": \"3.141592653589793\"\n },\n \"neglongpi\": {\n \"type\": \"float\",\n \"value\": \"-3.141592653589793\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Float_Underscore(t *testing.T) { + input := "before = 3_141.5927\nafter = 3141.592_7\nexponent = 3e1_4\n" + jsonRef := "{\n \"after\": {\n \"type\": \"float\",\n \"value\": \"3141.5927\"\n },\n \"before\": {\n \"type\": \"float\",\n \"value\": \"3141.5927\"\n },\n \"exponent\": {\n \"type\": \"float\",\n \"value\": \"3.0e14\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Float_Zero(t *testing.T) { + input := "zero = 0.0\nsigned-pos = +0.0\nsigned-neg = -0.0\nexponent = 0e0\nexponent-two-0 = 0e00\nexponent-signed-pos = +0e0\nexponent-signed-neg = -0e0\n" + jsonRef := "{\n \"zero\": {\n \"type\": \"float\",\n \"value\": \"0\"\n },\n \"signed-pos\": {\n \"type\": \"float\",\n \"value\": \"0\"\n },\n \"signed-neg\": {\n \"type\": \"float\",\n \"value\": \"0\"\n },\n \"exponent\": {\n \"type\": \"float\",\n \"value\": \"0\"\n },\n \"exponent-two-0\": {\n \"type\": \"float\",\n \"value\": \"0\"\n },\n \"exponent-signed-pos\": {\n \"type\": \"float\",\n \"value\": \"0\"\n },\n \"exponent-signed-neg\": {\n \"type\": \"float\",\n \"value\": \"0\"\n }\n}\n" + testgenValid(t, input, jsonRef) } -func TestValidArrayEmpty(t *testing.T) { +func TestTOMLTest_Valid_ImplicitAndExplicitAfter(t *testing.T) { + input := "[a.b.c]\nanswer = 42\n\n[a]\nbetter = 43\n" + jsonRef := "{\n \"a\": {\n \"b\": {\n \"c\": {\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n },\n \"better\": {\n \"type\": \"integer\",\n \"value\": \"43\"\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_ImplicitAndExplicitBefore(t *testing.T) { + input := "[a]\nbetter = 43\n\n[a.b.c]\nanswer = 42\n" + jsonRef := "{\n \"a\": {\n \"b\": {\n \"c\": {\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n },\n \"better\": {\n \"type\": \"integer\",\n \"value\": \"43\"\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `thevoid = [[[[[]]]]]` - jsonRef := `{ - "thevoid": { "type": "array", "value": [ - {"type": "array", "value": [ - {"type": "array", "value": [ - {"type": "array", "value": [ - {"type": "array", "value": []} - ]} - ]} - ]} - ]} -}` +func TestTOMLTest_Valid_ImplicitGroups(t *testing.T) { + input := "[a.b.c]\nanswer = 42\n" + jsonRef := "{\n \"a\": {\n \"b\": {\n \"c\": {\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidArrayNospaces(t *testing.T) { +func TestTOMLTest_Valid_InlineTable_Array(t *testing.T) { + input := "people = [{first_name = \"Bruce\", last_name = \"Springsteen\"},\n {first_name = \"Eric\", last_name = \"Clapton\"},\n {first_name = \"Bob\", last_name = \"Seger\"}]\n" + jsonRef := "{\n \"people\": [\n {\n \"first_name\": {\n \"type\": \"string\",\n \"value\": \"Bruce\"\n },\n \"last_name\": {\n \"type\": \"string\",\n \"value\": \"Springsteen\"\n }\n },\n {\n \"first_name\": {\n \"type\": \"string\",\n \"value\": \"Eric\"\n },\n \"last_name\": {\n \"type\": \"string\",\n \"value\": \"Clapton\"\n }\n },\n {\n \"first_name\": {\n \"type\": \"string\",\n \"value\": \"Bob\"\n },\n \"last_name\": {\n \"type\": \"string\",\n \"value\": \"Seger\"\n }\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `ints = [1,2,3]` - jsonRef := `{ - "ints": { - "type": "array", - "value": [ - {"type": "integer", "value": "1"}, - {"type": "integer", "value": "2"}, - {"type": "integer", "value": "3"} - ] - } -}` +func TestTOMLTest_Valid_InlineTable_Bool(t *testing.T) { + input := "a = {a = true, b = false}\n" + jsonRef := "{\n \"a\": {\n \"a\": {\n \"type\": \"bool\",\n \"value\": \"true\"\n },\n \"b\": {\n \"type\": \"bool\",\n \"value\": \"false\"\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidArraysHetergeneous(t *testing.T) { +func TestTOMLTest_Valid_InlineTable_Empty(t *testing.T) { + input := "empty1 = {}\nempty2 = { }\nempty_in_array = [ { not_empty = 1 }, {} ]\nempty_in_array2 = [{},{not_empty=1}]\nmany_empty = [{},{},{}]\nnested_empty = {\"empty\"={}}\n" + jsonRef := "{\n \"empty1\": {},\n \"empty2\": {},\n \"empty_in_array\": [\n {\n \"not_empty\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n },\n {}\n ],\n \"empty_in_array2\": [\n {},\n {\n \"not_empty\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n ],\n \"many_empty\": [\n {},\n {},\n {}\n ],\n \"nested_empty\": {\n \"empty\": {}\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `mixed = [[1, 2], ["a", "b"], [1.1, 2.1]]` - jsonRef := `{ - "mixed": { - "type": "array", - "value": [ - {"type": "array", "value": [ - {"type": "integer", "value": "1"}, - {"type": "integer", "value": "2"} - ]}, - {"type": "array", "value": [ - {"type": "string", "value": "a"}, - {"type": "string", "value": "b"} - ]}, - {"type": "array", "value": [ - {"type": "float", "value": "1.1"}, - {"type": "float", "value": "2.1"} - ]} - ] - } -}` +func TestTOMLTest_Valid_InlineTable_EndInBool(t *testing.T) { + input := "black = { python=\">3.6\", version=\">=18.9b0\", allow_prereleases=true }\n" + jsonRef := "{\n \"black\": {\n \"allow_prereleases\": {\n \"type\": \"bool\",\n \"value\": \"true\"\n },\n \"python\": {\n \"type\": \"string\",\n \"value\": \"\\u003e3.6\"\n },\n \"version\": {\n \"type\": \"string\",\n \"value\": \"\\u003e=18.9b0\"\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidArraysNested(t *testing.T) { +func TestTOMLTest_Valid_InlineTable_InlineTable(t *testing.T) { + input := "name = { first = \"Tom\", last = \"Preston-Werner\" }\npoint = { x = 1, y = 2 }\nsimple = { a = 1 }\nstr-key = { \"a\" = 1 }\ntable-array = [{ \"a\" = 1 }, { \"b\" = 2 }]\n" + jsonRef := "{\n \"name\": {\n \"first\": {\n \"type\": \"string\",\n \"value\": \"Tom\"\n },\n \"last\": {\n \"type\": \"string\",\n \"value\": \"Preston-Werner\"\n }\n },\n \"point\": {\n \"x\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n \"y\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n },\n \"simple\": {\n \"a\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n },\n \"str-key\": {\n \"a\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n },\n \"table-array\": [\n {\n \"a\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n },\n {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `nest = [["a"], ["b"]]` - jsonRef := `{ - "nest": { - "type": "array", - "value": [ - {"type": "array", "value": [ - {"type": "string", "value": "a"} - ]}, - {"type": "array", "value": [ - {"type": "string", "value": "b"} - ]} - ] - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidArrays(t *testing.T) { - - input := `ints = [1, 2, 3] -floats = [1.1, 2.1, 3.1] -strings = ["a", "b", "c"] -dates = [ - 1987-07-05T17:45:00Z, - 1979-05-27T07:32:00Z, - 2006-06-01T11:00:00Z, -]` - jsonRef := `{ - "ints": { - "type": "array", - "value": [ - {"type": "integer", "value": "1"}, - {"type": "integer", "value": "2"}, - {"type": "integer", "value": "3"} - ] - }, - "floats": { - "type": "array", - "value": [ - {"type": "float", "value": "1.1"}, - {"type": "float", "value": "2.1"}, - {"type": "float", "value": "3.1"} - ] - }, - "strings": { - "type": "array", - "value": [ - {"type": "string", "value": "a"}, - {"type": "string", "value": "b"}, - {"type": "string", "value": "c"} - ] - }, - "dates": { - "type": "array", - "value": [ - {"type": "datetime", "value": "1987-07-05T17:45:00Z"}, - {"type": "datetime", "value": "1979-05-27T07:32:00Z"}, - {"type": "datetime", "value": "2006-06-01T11:00:00Z"} - ] - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidBool(t *testing.T) { - - input := `t = true -f = false` - jsonRef := `{ - "f": {"type": "bool", "value": "false"}, - "t": {"type": "bool", "value": "true"} -}` - testgenValid(t, input, jsonRef) -} - -func TestValidCommentsEverywhere(t *testing.T) { - - input := `# Top comment. - # Top comment. -# Top comment. - -# [no-extraneous-groups-please] - -[group] # Comment -answer = 42 # Comment -# no-extraneous-keys-please = 999 -# In between comment. -more = [ # Comment - # What about multiple # comments? - # Can you handle it? - # - # Evil. -# Evil. - 42, 42, # Comments within arrays are fun. - # What about multiple # comments? - # Can you handle it? - # - # Evil. -# Evil. -# ] Did I fool you? -] # Hopefully not.` - jsonRef := `{ - "group": { - "answer": {"type": "integer", "value": "42"}, - "more": { - "type": "array", - "value": [ - {"type": "integer", "value": "42"}, - {"type": "integer", "value": "42"} - ] - } - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidDatetime(t *testing.T) { - - input := `bestdayever = 1987-07-05T17:45:00Z` - jsonRef := `{ - "bestdayever": {"type": "datetime", "value": "1987-07-05T17:45:00Z"} -}` - testgenValid(t, input, jsonRef) -} - -func TestValidEmpty(t *testing.T) { - - input := `` - jsonRef := `{}` - testgenValid(t, input, jsonRef) -} - -func TestValidExample(t *testing.T) { - - input := `best-day-ever = 1987-07-05T17:45:00Z - -[numtheory] -boring = false -perfection = [6, 28, 496]` - jsonRef := `{ - "best-day-ever": {"type": "datetime", "value": "1987-07-05T17:45:00Z"}, - "numtheory": { - "boring": {"type": "bool", "value": "false"}, - "perfection": { - "type": "array", - "value": [ - {"type": "integer", "value": "6"}, - {"type": "integer", "value": "28"}, - {"type": "integer", "value": "496"} - ] - } - } -}` +func TestTOMLTest_Valid_InlineTable_KeyDotted(t *testing.T) { + input := "inline = {a.b = 42}\n\nmany.dots.here.dot.dot.dot = {a.b.c = 1, a.b.d = 2}\n\na = { a.b = 1 }\nb = { \"a\".\"b\" = 1 }\nc = { a . b = 1 }\nd = { 'a' . \"b\" = 1 }\ne = {a.b=1}\n\n[tbl]\na.b.c = {d.e=1}\n\n[tbl.x]\na.b.c = {d.e=1}\n\n[[arr]]\nt = {a.b=1}\nT = {a.b=1}\n\n[[arr]]\nt = {a.b=2}\nT = {a.b=2}\n" + jsonRef := "{\n \"a\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n },\n \"arr\": [\n {\n \"T\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n },\n \"t\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n }\n },\n {\n \"T\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n }\n },\n \"t\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n }\n }\n }\n ],\n \"b\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n },\n \"c\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n },\n \"d\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n },\n \"e\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n },\n \"inline\": {\n \"a\": {\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n },\n \"many\": {\n \"dots\": {\n \"here\": {\n \"dot\": {\n \"dot\": {\n \"dot\": {\n \"a\": {\n \"b\": {\n \"c\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n \"d\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n }\n }\n }\n }\n }\n }\n }\n },\n \"tbl\": {\n \"a\": {\n \"b\": {\n \"c\": {\n \"d\": {\n \"e\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n }\n }\n },\n \"x\": {\n \"a\": {\n \"b\": {\n \"c\": {\n \"d\": {\n \"e\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n }\n }\n }\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidFloat(t *testing.T) { +func TestTOMLTest_Valid_InlineTable_Multiline(t *testing.T) { + input := "tbl_multiline = { a = 1, b = \"\"\"\nmultiline\n\"\"\", c = \"\"\"and yet\nanother line\"\"\", d = 4 }\n" + jsonRef := "{\n \"tbl_multiline\": {\n \"a\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n \"b\": {\n \"type\": \"string\",\n \"value\": \"multiline\\n\"\n },\n \"c\": {\n \"type\": \"string\",\n \"value\": \"and yet\\nanother line\"\n },\n \"d\": {\n \"type\": \"integer\",\n \"value\": \"4\"\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `pi = 3.14 -negpi = -3.14` - jsonRef := `{ - "pi": {"type": "float", "value": "3.14"}, - "negpi": {"type": "float", "value": "-3.14"} -}` +func TestTOMLTest_Valid_InlineTable_Nest(t *testing.T) { + input := "tbl_tbl_empty = { tbl_0 = {} }\ntbl_tbl_val = { tbl_1 = { one = 1 } }\ntbl_arr_tbl = { arr_tbl = [ { one = 1 } ] }\narr_tbl_tbl = [ { tbl = { one = 1 } } ]\n\n# Array-of-array-of-table is interesting because it can only\n# be represented in inline form.\narr_arr_tbl_empty = [ [ {} ] ]\narr_arr_tbl_val = [ [ { one = 1 } ] ]\narr_arr_tbls = [ [ { one = 1 }, { two = 2 } ] ]\n" + jsonRef := "{\n \"arr_arr_tbl_empty\": [\n [\n {}\n ]\n ],\n \"arr_arr_tbl_val\": [\n [\n {\n \"one\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n ]\n ],\n \"arr_arr_tbls\": [\n [\n {\n \"one\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n },\n {\n \"two\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n }\n ]\n ],\n \"arr_tbl_tbl\": [\n {\n \"tbl\": {\n \"one\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n }\n ],\n \"tbl_arr_tbl\": {\n \"arr_tbl\": [\n {\n \"one\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n ]\n },\n \"tbl_tbl_empty\": {\n \"tbl_0\": {}\n },\n \"tbl_tbl_val\": {\n \"tbl_1\": {\n \"one\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidImplicitAndExplicitAfter(t *testing.T) { +func TestTOMLTest_Valid_Integer_Integer(t *testing.T) { + input := "answer = 42\nposanswer = +42\nneganswer = -42\nzero = 0\n" + jsonRef := "{\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n },\n \"neganswer\": {\n \"type\": \"integer\",\n \"value\": \"-42\"\n },\n \"posanswer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n },\n \"zero\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[a.b.c] -answer = 42 +func TestTOMLTest_Valid_Integer_Literals(t *testing.T) { + input := "bin1 = 0b11010110\nbin2 = 0b1_0_1\n\noct1 = 0o01234567\noct2 = 0o755\noct3 = 0o7_6_5\n\nhex1 = 0xDEADBEEF\nhex2 = 0xdeadbeef\nhex3 = 0xdead_beef\nhex4 = 0x00987\n" + jsonRef := "{\n \"bin1\": {\n \"type\": \"integer\",\n \"value\": \"214\"\n },\n \"bin2\": {\n \"type\": \"integer\",\n \"value\": \"5\"\n },\n \"hex1\": {\n \"type\": \"integer\",\n \"value\": \"3735928559\"\n },\n \"hex2\": {\n \"type\": \"integer\",\n \"value\": \"3735928559\"\n },\n \"hex3\": {\n \"type\": \"integer\",\n \"value\": \"3735928559\"\n },\n \"hex4\": {\n \"type\": \"integer\",\n \"value\": \"2439\"\n },\n \"oct1\": {\n \"type\": \"integer\",\n \"value\": \"342391\"\n },\n \"oct2\": {\n \"type\": \"integer\",\n \"value\": \"493\"\n },\n \"oct3\": {\n \"type\": \"integer\",\n \"value\": \"501\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} -[a] -better = 43` - jsonRef := `{ - "a": { - "better": {"type": "integer", "value": "43"}, - "b": { - "c": { - "answer": {"type": "integer", "value": "42"} - } - } - } -}` +func TestTOMLTest_Valid_Integer_Long(t *testing.T) { + input := "int64-max = 9223372036854775807\nint64-max-neg = -9223372036854775808\n" + jsonRef := "{\n \"int64-max\": {\n \"type\": \"integer\",\n \"value\": \"9223372036854775807\"\n },\n \"int64-max-neg\": {\n \"type\": \"integer\",\n \"value\": \"-9223372036854775808\"\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidImplicitAndExplicitBefore(t *testing.T) { +func TestTOMLTest_Valid_Integer_Underscore(t *testing.T) { + input := "kilo = 1_000\nx = 1_1_1_1\n" + jsonRef := "{\n \"kilo\": {\n \"type\": \"integer\",\n \"value\": \"1000\"\n },\n \"x\": {\n \"type\": \"integer\",\n \"value\": \"1111\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[a] -better = 43 +func TestTOMLTest_Valid_Integer_Zero(t *testing.T) { + input := "d1 = 0\nd2 = +0\nd3 = -0\n\nh1 = 0x0\nh2 = 0x00\nh3 = 0x00000\n\no1 = 0o0\na2 = 0o00\na3 = 0o00000\n\nb1 = 0b0\nb2 = 0b00\nb3 = 0b00000\n" + jsonRef := "{\n \"a2\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"a3\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"b1\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"b2\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"b3\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"d1\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"d2\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"d3\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"h1\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"h2\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"h3\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n },\n \"o1\": {\n \"type\": \"integer\",\n \"value\": \"0\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} -[a.b.c] -answer = 42` - jsonRef := `{ - "a": { - "better": {"type": "integer", "value": "43"}, - "b": { - "c": { - "answer": {"type": "integer", "value": "42"} - } - } - } -}` +func TestTOMLTest_Valid_Key_Alphanum(t *testing.T) { + input := "alpha = \"a\"\n123 = \"num\"\n000111 = \"leading\"\n10e3 = \"false float\"\none1two2 = \"mixed\"\nwith-dash = \"dashed\"\nunder_score = \"___\"\n34-11 = 23\n\n[2018_10]\n001 = 1\n\n[a-a-a]\n_ = false\n" + jsonRef := "{\n \"000111\": {\n \"type\": \"string\",\n \"value\": \"leading\"\n },\n \"10e3\": {\n \"type\": \"string\",\n \"value\": \"false float\"\n },\n \"123\": {\n \"type\": \"string\",\n \"value\": \"num\"\n },\n \"2018_10\": {\n \"001\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n },\n \"34-11\": {\n \"type\": \"integer\",\n \"value\": \"23\"\n },\n \"a-a-a\": {\n \"_\": {\n \"type\": \"bool\",\n \"value\": \"false\"\n }\n },\n \"alpha\": {\n \"type\": \"string\",\n \"value\": \"a\"\n },\n \"one1two2\": {\n \"type\": \"string\",\n \"value\": \"mixed\"\n },\n \"under_score\": {\n \"type\": \"string\",\n \"value\": \"___\"\n },\n \"with-dash\": {\n \"type\": \"string\",\n \"value\": \"dashed\"\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidImplicitGroups(t *testing.T) { +func TestTOMLTest_Valid_Key_CaseSensitive(t *testing.T) { + input := "sectioN = \"NN\"\n\n[section]\nname = \"lower\"\nNAME = \"upper\"\nName = \"capitalized\"\n\n[Section]\nname = \"different section!!\"\n\"μ\" = \"greek small letter mu\"\n\"Μ\" = \"greek capital letter MU\"\nM = \"latin letter M\"\n\n" + jsonRef := "{\n \"Section\": {\n \"M\": {\n \"type\": \"string\",\n \"value\": \"latin letter M\"\n },\n \"name\": {\n \"type\": \"string\",\n \"value\": \"different section!!\"\n },\n \"Μ\": {\n \"type\": \"string\",\n \"value\": \"greek capital letter MU\"\n },\n \"μ\": {\n \"type\": \"string\",\n \"value\": \"greek small letter mu\"\n }\n },\n \"sectioN\": {\n \"type\": \"string\",\n \"value\": \"NN\"\n },\n \"section\": {\n \"NAME\": {\n \"type\": \"string\",\n \"value\": \"upper\"\n },\n \"Name\": {\n \"type\": \"string\",\n \"value\": \"capitalized\"\n },\n \"name\": {\n \"type\": \"string\",\n \"value\": \"lower\"\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[a.b.c] -answer = 42` - jsonRef := `{ - "a": { - "b": { - "c": { - "answer": {"type": "integer", "value": "42"} - } - } - } -}` +func TestTOMLTest_Valid_Key_Dotted(t *testing.T) { + input := "# Note: this file contains literal tab characters.\n\nname.first = \"Arthur\"\n\"name\".'last' = \"Dent\"\n\nmany.dots.here.dot.dot.dot = 42\n\n# Space are ignored, and key parts can be quoted.\ncount.a = 1\ncount . b = 2\n\"count\".\"c\" = 3\n\"count\" . \"d\" = 4\n'count'.'e' = 5\n'count' . 'f' = 6\n\"count\".'g' = 7\n\"count\" . 'h' = 8\ncount.'i' = 9\ncount \t.\t 'j'\t = 10\n\"count\".k = 11\n\"count\" . l = 12\n\n[tbl]\na.b.c = 42.666\n\n[a.few.dots]\npolka.dot = \"again?\"\npolka.dance-with = \"Dot\"\n\n[[arr]]\na.b.c=1\na.b.d=2\n\n[[arr]]\na.b.c=3\na.b.d=4\n" + jsonRef := "{\n \"a\": {\n \"few\": {\n \"dots\": {\n \"polka\": {\n \"dance-with\": {\n \"type\": \"string\",\n \"value\": \"Dot\"\n },\n \"dot\": {\n \"type\": \"string\",\n \"value\": \"again?\"\n }\n }\n }\n }\n },\n \"arr\": [\n {\n \"a\": {\n \"b\": {\n \"c\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n \"d\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n }\n }\n },\n {\n \"a\": {\n \"b\": {\n \"c\": {\n \"type\": \"integer\",\n \"value\": \"3\"\n },\n \"d\": {\n \"type\": \"integer\",\n \"value\": \"4\"\n }\n }\n }\n }\n ],\n \"count\": {\n \"a\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n \"b\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n },\n \"c\": {\n \"type\": \"integer\",\n \"value\": \"3\"\n },\n \"d\": {\n \"type\": \"integer\",\n \"value\": \"4\"\n },\n \"e\": {\n \"type\": \"integer\",\n \"value\": \"5\"\n },\n \"f\": {\n \"type\": \"integer\",\n \"value\": \"6\"\n },\n \"g\": {\n \"type\": \"integer\",\n \"value\": \"7\"\n },\n \"h\": {\n \"type\": \"integer\",\n \"value\": \"8\"\n },\n \"i\": {\n \"type\": \"integer\",\n \"value\": \"9\"\n },\n \"j\": {\n \"type\": \"integer\",\n \"value\": \"10\"\n },\n \"k\": {\n \"type\": \"integer\",\n \"value\": \"11\"\n },\n \"l\": {\n \"type\": \"integer\",\n \"value\": \"12\"\n }\n },\n \"many\": {\n \"dots\": {\n \"here\": {\n \"dot\": {\n \"dot\": {\n \"dot\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n }\n }\n }\n },\n \"name\": {\n \"first\": {\n \"type\": \"string\",\n \"value\": \"Arthur\"\n },\n \"last\": {\n \"type\": \"string\",\n \"value\": \"Dent\"\n }\n },\n \"tbl\": {\n \"a\": {\n \"b\": {\n \"c\": {\n \"type\": \"float\",\n \"value\": \"42.666\"\n }\n }\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidInteger(t *testing.T) { +func TestTOMLTest_Valid_Key_Empty(t *testing.T) { + input := "\"\" = \"blank\"\n" + jsonRef := "{\n \"\": {\n \"type\": \"string\",\n \"value\": \"blank\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `answer = 42 -neganswer = -42` - jsonRef := `{ - "answer": {"type": "integer", "value": "42"}, - "neganswer": {"type": "integer", "value": "-42"} -}` +func TestTOMLTest_Valid_Key_EqualsNospace(t *testing.T) { + input := "answer=42\n" + jsonRef := "{\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidKeyEqualsNospace(t *testing.T) { +func TestTOMLTest_Valid_Key_Escapes(t *testing.T) { + input := "\"\\n\" = \"newline\"\n\"\\u00c0\" = \"latin capital letter A with grave\"\n\"\\\"\" = \"just a quote\"\n\n[\"backsp\\b\\b\"]\n\n[\"\\\"quoted\\\"\"]\nquote = true\n\n[\"a.b\".\"\\u00c0\"]\n" + jsonRef := "{\n \"\\n\": {\n \"type\": \"string\",\n \"value\": \"newline\"\n },\n \"\\\"\": {\n \"type\": \"string\",\n \"value\": \"just a quote\"\n },\n \"\\\"quoted\\\"\": {\n \"quote\": {\n \"type\": \"bool\",\n \"value\": \"true\"\n }\n },\n \"a.b\": {\n \"À\": {}\n },\n \"backsp\\u0008\\u0008\": {},\n \"À\": {\n \"type\": \"string\",\n \"value\": \"latin capital letter A with grave\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `answer=42` - jsonRef := `{ - "answer": {"type": "integer", "value": "42"} -}` +func TestTOMLTest_Valid_Key_NumericDotted(t *testing.T) { + input := "1.2 = 3\n" + jsonRef := "{\n \"1\": {\n \"2\": {\n \"type\": \"integer\",\n \"value\": \"3\"\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidKeySpace(t *testing.T) { +func TestTOMLTest_Valid_Key_Numeric(t *testing.T) { + input := "1 = 1\n" + jsonRef := "{\n \"1\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `"a b" = 1` - jsonRef := `{ - "a b": {"type": "integer", "value": "1"} -}` +func TestTOMLTest_Valid_Key_QuotedDots(t *testing.T) { + input := "plain = 1\n\"with.dot\" = 2\n\n[plain_table]\nplain = 3\n\"with.dot\" = 4\n\n[table.withdot]\nplain = 5\n\"key.with.dots\" = 6\n" + jsonRef := "{\n \"plain\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n \"plain_table\": {\n \"plain\": {\n \"type\": \"integer\",\n \"value\": \"3\"\n },\n \"with.dot\": {\n \"type\": \"integer\",\n \"value\": \"4\"\n }\n },\n \"table\": {\n \"withdot\": {\n \"key.with.dots\": {\n \"type\": \"integer\",\n \"value\": \"6\"\n },\n \"plain\": {\n \"type\": \"integer\",\n \"value\": \"5\"\n }\n }\n },\n \"with.dot\": {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidKeySpecialChars(t *testing.T) { +func TestTOMLTest_Valid_Key_Space(t *testing.T) { + input := "\"a b\" = 1\n" + jsonRef := "{\n \"a b\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} +func TestTOMLTest_Valid_Key_SpecialChars(t *testing.T) { input := "\"~!@$^&*()_+-`1234567890[]|/?><.,;:'\" = 1\n" - jsonRef := "{\n" + - " \"~!@$^&*()_+-`1234567890[]|/?><.,;:'\": {\n" + - " \"type\": \"integer\", \"value\": \"1\"\n" + - " }\n" + - "}\n" - testgenValid(t, input, jsonRef) -} - -func TestValidLongFloat(t *testing.T) { - - input := `longpi = 3.141592653589793 -neglongpi = -3.141592653589793` - jsonRef := `{ - "longpi": {"type": "float", "value": "3.141592653589793"}, - "neglongpi": {"type": "float", "value": "-3.141592653589793"} -}` - testgenValid(t, input, jsonRef) -} - -func TestValidLongInteger(t *testing.T) { - - input := `answer = 9223372036854775807 -neganswer = -9223372036854775808` - jsonRef := `{ - "answer": {"type": "integer", "value": "9223372036854775807"}, - "neganswer": {"type": "integer", "value": "-9223372036854775808"} -}` - testgenValid(t, input, jsonRef) -} - -func TestValidMultilineString(t *testing.T) { - - input := `multiline_empty_one = """""" -multiline_empty_two = """ -""" -multiline_empty_three = """\ - """ -multiline_empty_four = """\ - \ - \ - """ - -equivalent_one = "The quick brown fox jumps over the lazy dog." -equivalent_two = """ -The quick brown \ - - - fox jumps over \ - the lazy dog.""" - -equivalent_three = """\ - The quick brown \ - fox jumps over \ - the lazy dog.\ - """` - jsonRef := `{ - "multiline_empty_one": { - "type": "string", - "value": "" - }, - "multiline_empty_two": { - "type": "string", - "value": "" - }, - "multiline_empty_three": { - "type": "string", - "value": "" - }, - "multiline_empty_four": { - "type": "string", - "value": "" - }, - "equivalent_one": { - "type": "string", - "value": "The quick brown fox jumps over the lazy dog." - }, - "equivalent_two": { - "type": "string", - "value": "The quick brown fox jumps over the lazy dog." - }, - "equivalent_three": { - "type": "string", - "value": "The quick brown fox jumps over the lazy dog." - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidRawMultilineString(t *testing.T) { - - input := `oneline = '''This string has a ' quote character.''' -firstnl = ''' -This string has a ' quote character.''' -multiline = ''' -This string -has ' a quote character -and more than -one newline -in it.'''` - jsonRef := `{ - "oneline": { - "type": "string", - "value": "This string has a ' quote character." - }, - "firstnl": { - "type": "string", - "value": "This string has a ' quote character." - }, - "multiline": { - "type": "string", - "value": "This string\nhas ' a quote character\nand more than\none newline\nin it." - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidRawString(t *testing.T) { - - input := `backspace = 'This string has a \b backspace character.' -tab = 'This string has a \t tab character.' -newline = 'This string has a \n new line character.' -formfeed = 'This string has a \f form feed character.' -carriage = 'This string has a \r carriage return character.' -slash = 'This string has a \/ slash character.' -backslash = 'This string has a \\ backslash character.'` - jsonRef := `{ - "backspace": { - "type": "string", - "value": "This string has a \\b backspace character." - }, - "tab": { - "type": "string", - "value": "This string has a \\t tab character." - }, - "newline": { - "type": "string", - "value": "This string has a \\n new line character." - }, - "formfeed": { - "type": "string", - "value": "This string has a \\f form feed character." - }, - "carriage": { - "type": "string", - "value": "This string has a \\r carriage return character." - }, - "slash": { - "type": "string", - "value": "This string has a \\/ slash character." - }, - "backslash": { - "type": "string", - "value": "This string has a \\\\ backslash character." - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidStringEmpty(t *testing.T) { - - input := `answer = ""` - jsonRef := `{ - "answer": { - "type": "string", - "value": "" - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidStringEscapes(t *testing.T) { - - input := `backspace = "This string has a \b backspace character." -tab = "This string has a \t tab character." -newline = "This string has a \n new line character." -formfeed = "This string has a \f form feed character." -carriage = "This string has a \r carriage return character." -quote = "This string has a \" quote character." -backslash = "This string has a \\ backslash character." -notunicode1 = "This string does not have a unicode \\u escape." -notunicode2 = "This string does not have a unicode \u005Cu escape." -notunicode3 = "This string does not have a unicode \\u0075 escape." -notunicode4 = "This string does not have a unicode \\\u0075 escape."` - jsonRef := `{ - "backspace": { - "type": "string", - "value": "This string has a \u0008 backspace character." - }, - "tab": { - "type": "string", - "value": "This string has a \u0009 tab character." - }, - "newline": { - "type": "string", - "value": "This string has a \u000A new line character." - }, - "formfeed": { - "type": "string", - "value": "This string has a \u000C form feed character." - }, - "carriage": { - "type": "string", - "value": "This string has a \u000D carriage return character." - }, - "quote": { - "type": "string", - "value": "This string has a \u0022 quote character." - }, - "backslash": { - "type": "string", - "value": "This string has a \u005C backslash character." - }, - "notunicode1": { - "type": "string", - "value": "This string does not have a unicode \\u escape." - }, - "notunicode2": { - "type": "string", - "value": "This string does not have a unicode \u005Cu escape." - }, - "notunicode3": { - "type": "string", - "value": "This string does not have a unicode \\u0075 escape." - }, - "notunicode4": { - "type": "string", - "value": "This string does not have a unicode \\\u0075 escape." - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidStringSimple(t *testing.T) { - - input := `answer = "You are not drinking enough whisky."` - jsonRef := `{ - "answer": { - "type": "string", - "value": "You are not drinking enough whisky." - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidStringWithPound(t *testing.T) { - - input := `pound = "We see no # comments here." -poundcomment = "But there are # some comments here." # Did I # mess you up?` - jsonRef := `{ - "pound": {"type": "string", "value": "We see no # comments here."}, - "poundcomment": { - "type": "string", - "value": "But there are # some comments here." - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidTableArrayImplicit(t *testing.T) { - - input := `[[albums.songs]] -name = "Glory Days"` - jsonRef := `{ - "albums": { - "songs": [ - {"name": {"type": "string", "value": "Glory Days"}} - ] - } -}` - testgenValid(t, input, jsonRef) -} - -func TestValidTableArrayMany(t *testing.T) { - - input := `[[people]] -first_name = "Bruce" -last_name = "Springsteen" - -[[people]] -first_name = "Eric" -last_name = "Clapton" - -[[people]] -first_name = "Bob" -last_name = "Seger"` - jsonRef := `{ - "people": [ - { - "first_name": {"type": "string", "value": "Bruce"}, - "last_name": {"type": "string", "value": "Springsteen"} - }, - { - "first_name": {"type": "string", "value": "Eric"}, - "last_name": {"type": "string", "value": "Clapton"} - }, - { - "first_name": {"type": "string", "value": "Bob"}, - "last_name": {"type": "string", "value": "Seger"} - } - ] -}` + jsonRef := "{\n \"~!@$^\\u0026*()_+-`1234567890[]|/?\\u003e\\u003c.,;:'\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_Key_SpecialWord(t *testing.T) { + input := "false = false\ntrue = 1\ninf = 100000000\nnan = \"ceci n'est pas un nombre\"\n\n" + jsonRef := "{\n \"false\": {\n \"type\": \"bool\",\n \"value\": \"false\"\n },\n \"inf\": {\n \"type\": \"integer\",\n \"value\": \"100000000\"\n },\n \"nan\": {\n \"type\": \"string\",\n \"value\": \"ceci n'est pas un nombre\"\n },\n \"true\": {\n \"type\": \"integer\",\n \"value\": \"1\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_NewlineCrlf(t *testing.T) { + input := "os = \"DOS\"\r\nnewline = \"crlf\"\r\n" + jsonRef := "{\n \"newline\": {\n \"type\": \"string\",\n \"value\": \"crlf\"\n },\n \"os\": {\n \"type\": \"string\",\n \"value\": \"DOS\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_NewlineLf(t *testing.T) { + input := "os = \"unix\"\nnewline = \"lf\"\n" + jsonRef := "{\n \"newline\": {\n \"type\": \"string\",\n \"value\": \"lf\"\n },\n \"os\": {\n \"type\": \"string\",\n \"value\": \"unix\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_SpecExample1Compact(t *testing.T) { + input := "#Useless spaces eliminated.\ntitle=\"TOML Example\"\n[owner]\nname=\"Lance Uppercut\"\ndob=1979-05-27T07:32:00-08:00#First class dates\n[database]\nserver=\"192.168.1.1\"\nports=[8001,8001,8002]\nconnection_max=5000\nenabled=true\n[servers]\n[servers.alpha]\nip=\"10.0.0.1\"\ndc=\"eqdc10\"\n[servers.beta]\nip=\"10.0.0.2\"\ndc=\"eqdc10\"\n[clients]\ndata=[[\"gamma\",\"delta\"],[1,2]]\nhosts=[\n\"alpha\",\n\"omega\"\n]\n" + jsonRef := "{\n \"clients\": {\n \"data\": [\n [\n {\n \"type\": \"string\",\n \"value\": \"gamma\"\n },\n {\n \"type\": \"string\",\n \"value\": \"delta\"\n }\n ],\n [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n ]\n ],\n \"hosts\": [\n {\n \"type\": \"string\",\n \"value\": \"alpha\"\n },\n {\n \"type\": \"string\",\n \"value\": \"omega\"\n }\n ]\n },\n \"database\": {\n \"connection_max\": {\n \"type\": \"integer\",\n \"value\": \"5000\"\n },\n \"enabled\": {\n \"type\": \"bool\",\n \"value\": \"true\"\n },\n \"ports\": [\n {\n \"type\": \"integer\",\n \"value\": \"8001\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"8001\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"8002\"\n }\n ],\n \"server\": {\n \"type\": \"string\",\n \"value\": \"192.168.1.1\"\n }\n },\n \"owner\": {\n \"dob\": {\n \"type\": \"datetime\",\n \"value\": \"1979-05-27T07:32:00-08:00\"\n },\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Lance Uppercut\"\n }\n },\n \"servers\": {\n \"alpha\": {\n \"dc\": {\n \"type\": \"string\",\n \"value\": \"eqdc10\"\n },\n \"ip\": {\n \"type\": \"string\",\n \"value\": \"10.0.0.1\"\n }\n },\n \"beta\": {\n \"dc\": {\n \"type\": \"string\",\n \"value\": \"eqdc10\"\n },\n \"ip\": {\n \"type\": \"string\",\n \"value\": \"10.0.0.2\"\n }\n }\n },\n \"title\": {\n \"type\": \"string\",\n \"value\": \"TOML Example\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_SpecExample1(t *testing.T) { + input := "# This is a TOML document. Boom.\n\ntitle = \"TOML Example\"\n\n[owner]\nname = \"Lance Uppercut\"\ndob = 1979-05-27T07:32:00-08:00 # First class dates? Why not?\n\n[database]\nserver = \"192.168.1.1\"\nports = [ 8001, 8001, 8002 ]\nconnection_max = 5000\nenabled = true\n\n[servers]\n\n # You can indent as you please. Tabs or spaces. TOML don't care.\n [servers.alpha]\n ip = \"10.0.0.1\"\n dc = \"eqdc10\"\n\n [servers.beta]\n ip = \"10.0.0.2\"\n dc = \"eqdc10\"\n\n[clients]\ndata = [ [\"gamma\", \"delta\"], [1, 2] ]\n\n# Line breaks are OK when inside arrays\nhosts = [\n \"alpha\",\n \"omega\"\n]\n" + jsonRef := "{\n \"clients\": {\n \"data\": [\n [\n {\n \"type\": \"string\",\n \"value\": \"gamma\"\n },\n {\n \"type\": \"string\",\n \"value\": \"delta\"\n }\n ],\n [\n {\n \"type\": \"integer\",\n \"value\": \"1\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"2\"\n }\n ]\n ],\n \"hosts\": [\n {\n \"type\": \"string\",\n \"value\": \"alpha\"\n },\n {\n \"type\": \"string\",\n \"value\": \"omega\"\n }\n ]\n },\n \"database\": {\n \"connection_max\": {\n \"type\": \"integer\",\n \"value\": \"5000\"\n },\n \"enabled\": {\n \"type\": \"bool\",\n \"value\": \"true\"\n },\n \"ports\": [\n {\n \"type\": \"integer\",\n \"value\": \"8001\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"8001\"\n },\n {\n \"type\": \"integer\",\n \"value\": \"8002\"\n }\n ],\n \"server\": {\n \"type\": \"string\",\n \"value\": \"192.168.1.1\"\n }\n },\n \"owner\": {\n \"dob\": {\n \"type\": \"datetime\",\n \"value\": \"1979-05-27T07:32:00-08:00\"\n },\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Lance Uppercut\"\n }\n },\n \"servers\": {\n \"alpha\": {\n \"dc\": {\n \"type\": \"string\",\n \"value\": \"eqdc10\"\n },\n \"ip\": {\n \"type\": \"string\",\n \"value\": \"10.0.0.1\"\n }\n },\n \"beta\": {\n \"dc\": {\n \"type\": \"string\",\n \"value\": \"eqdc10\"\n },\n \"ip\": {\n \"type\": \"string\",\n \"value\": \"10.0.0.2\"\n }\n }\n },\n \"title\": {\n \"type\": \"string\",\n \"value\": \"TOML Example\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_DoubleQuoteEscape(t *testing.T) { + input := "test = \"\\\"one\\\"\"\n" + jsonRef := "{\n \"test\": {\n \"type\": \"string\",\n \"value\": \"\\\"one\\\"\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_Empty(t *testing.T) { + input := "answer = \"\"\n" + jsonRef := "{\n \"answer\": {\n \"type\": \"string\",\n \"value\": \"\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_EscapeTricky(t *testing.T) { + input := "end_esc = \"String does not end here\\\" but ends here\\\\\"\nlit_end_esc = 'String ends here\\'\n\nmultiline_unicode = \"\"\"\n\\u00a0\"\"\"\n\nmultiline_not_unicode = \"\"\"\n\\\\u0041\"\"\"\n\nmultiline_end_esc = \"\"\"When will it end? \\\"\"\"...\"\"\\\" should be here\\\"\"\"\"\n\nlit_multiline_not_unicode = '''\n\\u007f'''\n\nlit_multiline_end = '''There is no escape\\'''\n" + jsonRef := "{\n \"end_esc\": {\n \"type\": \"string\",\n \"value\": \"String does not end here\\\" but ends here\\\\\"\n },\n \"lit_end_esc\": {\n \"type\": \"string\",\n \"value\": \"String ends here\\\\\"\n },\n \"lit_multiline_end\": {\n \"type\": \"string\",\n \"value\": \"There is no escape\\\\\"\n },\n \"lit_multiline_not_unicode\": {\n \"type\": \"string\",\n \"value\": \"\\\\u007f\"\n },\n \"multiline_end_esc\": {\n \"type\": \"string\",\n \"value\": \"When will it end? \\\"\\\"\\\"...\\\"\\\"\\\" should be here\\\"\"\n },\n \"multiline_not_unicode\": {\n \"type\": \"string\",\n \"value\": \"\\\\u0041\"\n },\n \"multiline_unicode\": {\n \"type\": \"string\",\n \"value\": \"\u00a0\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_EscapedEscape(t *testing.T) { + input := "answer = \"\\\\x64\"\n" + jsonRef := "{\n \"answer\": {\n \"type\": \"string\",\n \"value\": \"\\\\x64\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_Escapes(t *testing.T) { + input := "backspace = \"This string has a \\b backspace character.\"\ntab = \"This string has a \\t tab character.\"\nnewline = \"This string has a \\n new line character.\"\nformfeed = \"This string has a \\f form feed character.\"\ncarriage = \"This string has a \\r carriage return character.\"\nquote = \"This string has a \\\" quote character.\"\nbackslash = \"This string has a \\\\ backslash character.\"\nnotunicode1 = \"This string does not have a unicode \\\\u escape.\"\nnotunicode2 = \"This string does not have a unicode \\u005Cu escape.\"\nnotunicode3 = \"This string does not have a unicode \\\\u0075 escape.\"\nnotunicode4 = \"This string does not have a unicode \\\\\\u0075 escape.\"\ndelete = \"This string has a \\u007F delete control code.\"\nunitseparator = \"This string has a \\u001F unit separator control code.\"\n" + jsonRef := "{\n \"backslash\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\ backslash character.\"\n },\n \"backspace\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\u0008 backspace character.\"\n },\n \"carriage\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\r carriage return character.\"\n },\n \"delete\": {\n \"type\": \"string\",\n \"value\": \"This string has a \u007f delete control code.\"\n },\n \"formfeed\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\u000c form feed character.\"\n },\n \"newline\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\n new line character.\"\n },\n \"notunicode1\": {\n \"type\": \"string\",\n \"value\": \"This string does not have a unicode \\\\u escape.\"\n },\n \"notunicode2\": {\n \"type\": \"string\",\n \"value\": \"This string does not have a unicode \\\\u escape.\"\n },\n \"notunicode3\": {\n \"type\": \"string\",\n \"value\": \"This string does not have a unicode \\\\u0075 escape.\"\n },\n \"notunicode4\": {\n \"type\": \"string\",\n \"value\": \"This string does not have a unicode \\\\u escape.\"\n },\n \"quote\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\" quote character.\"\n },\n \"tab\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\t tab character.\"\n },\n \"unitseparator\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\u001f unit separator control code.\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_MultilineQuotes(t *testing.T) { + input := "# Make sure that quotes inside multiline strings are allowed, including right\n# after the opening '''/\"\"\" and before the closing '''/\"\"\"\n\nlit_one = ''''one quote''''\nlit_two = '''''two quotes'''''\nlit_one_space = ''' 'one quote' '''\nlit_two_space = ''' ''two quotes'' '''\n\none = \"\"\"\"one quote\"\"\"\"\ntwo = \"\"\"\"\"two quotes\"\"\"\"\"\none_space = \"\"\" \"one quote\" \"\"\"\ntwo_space = \"\"\" \"\"two quotes\"\" \"\"\"\n\nmismatch1 = \"\"\"aaa'''bbb\"\"\"\nmismatch2 = '''aaa\"\"\"bbb'''\n" + jsonRef := "{\n \"lit_one\": {\n \"type\": \"string\",\n \"value\": \"'one quote'\"\n },\n \"lit_one_space\": {\n \"type\": \"string\",\n \"value\": \" 'one quote' \"\n },\n \"lit_two\": {\n \"type\": \"string\",\n \"value\": \"''two quotes''\"\n },\n \"lit_two_space\": {\n \"type\": \"string\",\n \"value\": \" ''two quotes'' \"\n },\n \"mismatch1\": {\n \"type\": \"string\",\n \"value\": \"aaa'''bbb\"\n },\n \"mismatch2\": {\n \"type\": \"string\",\n \"value\": \"aaa\\\"\\\"\\\"bbb\"\n },\n \"one\": {\n \"type\": \"string\",\n \"value\": \"\\\"one quote\\\"\"\n },\n \"one_space\": {\n \"type\": \"string\",\n \"value\": \" \\\"one quote\\\" \"\n },\n \"two\": {\n \"type\": \"string\",\n \"value\": \"\\\"\\\"two quotes\\\"\\\"\"\n },\n \"two_space\": {\n \"type\": \"string\",\n \"value\": \" \\\"\\\"two quotes\\\"\\\" \"\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidTableArrayNest(t *testing.T) { +func TestTOMLTest_Valid_String_Multiline(t *testing.T) { + input := "# NOTE: this file includes some literal tab characters.\n\nmultiline_empty_one = \"\"\"\"\"\"\nmultiline_empty_two = \"\"\"\n\"\"\"\nmultiline_empty_three = \"\"\"\\\n \"\"\"\nmultiline_empty_four = \"\"\"\\\n \\\n \\ \n \"\"\"\n\nequivalent_one = \"The quick brown fox jumps over the lazy dog.\"\nequivalent_two = \"\"\"\nThe quick brown \\\n\n\n fox jumps over \\\n the lazy dog.\"\"\"\n\nequivalent_three = \"\"\"\\\n The quick brown \\\n fox jumps over \\\n the lazy dog.\\\n \"\"\"\n\nwhitespace-after-bs = \"\"\"\\\n The quick brown \\\n fox jumps over \\ \n the lazy dog.\\\t\n \"\"\"\n\nno-space = \"\"\"a\\\n b\"\"\"\n\nkeep-ws-before = \"\"\"a \t\\\n b\"\"\"\n\nescape-bs-1 = \"\"\"a \\\\\nb\"\"\"\n\nescape-bs-2 = \"\"\"a \\\\\\\nb\"\"\"\n\nescape-bs-3 = \"\"\"a \\\\\\\\\n b\"\"\"\n" + jsonRef := "{\n \"equivalent_one\": {\n \"type\": \"string\",\n \"value\": \"The quick brown fox jumps over the lazy dog.\"\n },\n \"equivalent_three\": {\n \"type\": \"string\",\n \"value\": \"The quick brown fox jumps over the lazy dog.\"\n },\n \"equivalent_two\": {\n \"type\": \"string\",\n \"value\": \"The quick brown fox jumps over the lazy dog.\"\n },\n \"escape-bs-1\": {\n \"type\": \"string\",\n \"value\": \"a \\\\\\nb\"\n },\n \"escape-bs-2\": {\n \"type\": \"string\",\n \"value\": \"a \\\\b\"\n },\n \"escape-bs-3\": {\n \"type\": \"string\",\n \"value\": \"a \\\\\\\\\\n b\"\n },\n \"keep-ws-before\": {\n \"type\": \"string\",\n \"value\": \"a \\tb\"\n },\n \"multiline_empty_four\": {\n \"type\": \"string\",\n \"value\": \"\"\n },\n \"multiline_empty_one\": {\n \"type\": \"string\",\n \"value\": \"\"\n },\n \"multiline_empty_three\": {\n \"type\": \"string\",\n \"value\": \"\"\n },\n \"multiline_empty_two\": {\n \"type\": \"string\",\n \"value\": \"\"\n },\n \"no-space\": {\n \"type\": \"string\",\n \"value\": \"ab\"\n },\n \"whitespace-after-bs\": {\n \"type\": \"string\",\n \"value\": \"The quick brown fox jumps over the lazy dog.\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_Nl(t *testing.T) { + input := "nl_mid = \"val\\nue\"\nnl_end = \"\"\"value\\n\"\"\"\n\nlit_nl_end = '''value\\n'''\nlit_nl_mid = 'val\\nue'\nlit_nl_uni = 'val\\ue'\n" + jsonRef := "{\n \"lit_nl_end\": {\n \"type\": \"string\",\n \"value\": \"value\\\\n\"\n },\n \"lit_nl_mid\": {\n \"type\": \"string\",\n \"value\": \"val\\\\nue\"\n },\n \"lit_nl_uni\": {\n \"type\": \"string\",\n \"value\": \"val\\\\ue\"\n },\n \"nl_end\": {\n \"type\": \"string\",\n \"value\": \"value\\n\"\n },\n \"nl_mid\": {\n \"type\": \"string\",\n \"value\": \"val\\nue\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} + +func TestTOMLTest_Valid_String_RawMultiline(t *testing.T) { + input := "oneline = '''This string has a ' quote character.'''\nfirstnl = '''\nThis string has a ' quote character.'''\nmultiline = '''\nThis string\nhas ' a quote character\nand more than\none newline\nin it.'''\n" + jsonRef := "{\n \"firstnl\": {\n \"type\": \"string\",\n \"value\": \"This string has a ' quote character.\"\n },\n \"multiline\": {\n \"type\": \"string\",\n \"value\": \"This string\\nhas ' a quote character\\nand more than\\none newline\\nin it.\"\n },\n \"oneline\": {\n \"type\": \"string\",\n \"value\": \"This string has a ' quote character.\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[[albums]] -name = "Born to Run" +func TestTOMLTest_Valid_String_Raw(t *testing.T) { + input := "backspace = 'This string has a \\b backspace character.'\ntab = 'This string has a \\t tab character.'\nnewline = 'This string has a \\n new line character.'\nformfeed = 'This string has a \\f form feed character.'\ncarriage = 'This string has a \\r carriage return character.'\nslash = 'This string has a \\/ slash character.'\nbackslash = 'This string has a \\\\ backslash character.'\n" + jsonRef := "{\n \"backslash\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\\\\\ backslash character.\"\n },\n \"backspace\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\b backspace character.\"\n },\n \"carriage\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\r carriage return character.\"\n },\n \"formfeed\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\f form feed character.\"\n },\n \"newline\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\n new line character.\"\n },\n \"slash\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\/ slash character.\"\n },\n \"tab\": {\n \"type\": \"string\",\n \"value\": \"This string has a \\\\t tab character.\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - [[albums.songs]] - name = "Jungleland" +func TestTOMLTest_Valid_String_Simple(t *testing.T) { + input := "answer = \"You are not drinking enough whisky.\"\n" + jsonRef := "{\n \"answer\": {\n \"type\": \"string\",\n \"value\": \"You are not drinking enough whisky.\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - [[albums.songs]] - name = "Meeting Across the River" +func TestTOMLTest_Valid_String_UnicodeEscape(t *testing.T) { + input := "answer4 = \"\\u03B4\"\nanswer8 = \"\\U000003B4\"\n" + jsonRef := "{\n \"answer4\": {\n \"type\": \"string\",\n \"value\": \"δ\"\n },\n \"answer8\": {\n \"type\": \"string\",\n \"value\": \"δ\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} -[[albums]] -name = "Born in the USA" +func TestTOMLTest_Valid_String_UnicodeLiteral(t *testing.T) { + input := "answer = \"δ\"\n" + jsonRef := "{\n \"answer\": {\n \"type\": \"string\",\n \"value\": \"δ\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - [[albums.songs]] - name = "Glory Days" +func TestTOMLTest_Valid_String_WithPound(t *testing.T) { + input := "pound = \"We see no # comments here.\"\npoundcomment = \"But there are # some comments here.\" # Did I # mess you up?\n" + jsonRef := "{\n \"pound\": {\n \"type\": \"string\",\n \"value\": \"We see no # comments here.\"\n },\n \"poundcomment\": {\n \"type\": \"string\",\n \"value\": \"But there are # some comments here.\"\n }\n}\n" + testgenValid(t, input, jsonRef) +} - [[albums.songs]] - name = "Dancing in the Dark"` - jsonRef := `{ - "albums": [ - { - "name": {"type": "string", "value": "Born to Run"}, - "songs": [ - {"name": {"type": "string", "value": "Jungleland"}}, - {"name": {"type": "string", "value": "Meeting Across the River"}} - ] - }, - { - "name": {"type": "string", "value": "Born in the USA"}, - "songs": [ - {"name": {"type": "string", "value": "Glory Days"}}, - {"name": {"type": "string", "value": "Dancing in the Dark"}} - ] - } - ] -}` +func TestTOMLTest_Valid_Table_ArrayImplicit(t *testing.T) { + input := "[[albums.songs]]\nname = \"Glory Days\"\n" + jsonRef := "{\n \"albums\": {\n \"songs\": [\n {\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Glory Days\"\n }\n }\n ]\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidTableArrayOne(t *testing.T) { +func TestTOMLTest_Valid_Table_ArrayMany(t *testing.T) { + input := "[[people]]\nfirst_name = \"Bruce\"\nlast_name = \"Springsteen\"\n\n[[people]]\nfirst_name = \"Eric\"\nlast_name = \"Clapton\"\n\n[[people]]\nfirst_name = \"Bob\"\nlast_name = \"Seger\"\n" + jsonRef := "{\n \"people\": [\n {\n \"first_name\": {\n \"type\": \"string\",\n \"value\": \"Bruce\"\n },\n \"last_name\": {\n \"type\": \"string\",\n \"value\": \"Springsteen\"\n }\n },\n {\n \"first_name\": {\n \"type\": \"string\",\n \"value\": \"Eric\"\n },\n \"last_name\": {\n \"type\": \"string\",\n \"value\": \"Clapton\"\n }\n },\n {\n \"first_name\": {\n \"type\": \"string\",\n \"value\": \"Bob\"\n },\n \"last_name\": {\n \"type\": \"string\",\n \"value\": \"Seger\"\n }\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[[people]] -first_name = "Bruce" -last_name = "Springsteen"` - jsonRef := `{ - "people": [ - { - "first_name": {"type": "string", "value": "Bruce"}, - "last_name": {"type": "string", "value": "Springsteen"} - } - ] -}` +func TestTOMLTest_Valid_Table_ArrayNest(t *testing.T) { + input := "[[albums]]\nname = \"Born to Run\"\n\n [[albums.songs]]\n name = \"Jungleland\"\n\n [[albums.songs]]\n name = \"Meeting Across the River\"\n\n[[albums]]\nname = \"Born in the USA\"\n \n [[albums.songs]]\n name = \"Glory Days\"\n\n [[albums.songs]]\n name = \"Dancing in the Dark\"\n" + jsonRef := "{\n \"albums\": [\n {\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Born to Run\"\n },\n \"songs\": [\n {\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Jungleland\"\n }\n },\n {\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Meeting Across the River\"\n }\n }\n ]\n },\n {\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Born in the USA\"\n },\n \"songs\": [\n {\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Glory Days\"\n }\n },\n {\n \"name\": {\n \"type\": \"string\",\n \"value\": \"Dancing in the Dark\"\n }\n }\n ]\n }\n ]\n}\n" testgenValid(t, input, jsonRef) } -func TestValidTableEmpty(t *testing.T) { +func TestTOMLTest_Valid_Table_ArrayOne(t *testing.T) { + input := "[[people]]\nfirst_name = \"Bruce\"\nlast_name = \"Springsteen\"\n" + jsonRef := "{\n \"people\": [\n {\n \"first_name\": {\n \"type\": \"string\",\n \"value\": \"Bruce\"\n },\n \"last_name\": {\n \"type\": \"string\",\n \"value\": \"Springsteen\"\n }\n }\n ]\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[a]` - jsonRef := `{ - "a": {} -}` +func TestTOMLTest_Valid_Table_ArrayTableArray(t *testing.T) { + input := "[[a]]\n [[a.b]]\n [a.b.c]\n d = \"val0\"\n [[a.b]]\n [a.b.c]\n d = \"val1\"\n" + jsonRef := "{\n \"a\": [\n {\n \"b\": [\n {\n \"c\": {\n \"d\": {\n \"type\": \"string\",\n \"value\": \"val0\"\n }\n }\n },\n {\n \"c\": {\n \"d\": {\n \"type\": \"string\",\n \"value\": \"val1\"\n }\n }\n }\n ]\n }\n ]\n}\n" testgenValid(t, input, jsonRef) } -func TestValidTableSubEmpty(t *testing.T) { +func TestTOMLTest_Valid_Table_Empty(t *testing.T) { + input := "[a]\n" + jsonRef := "{\n \"a\": {}\n}\n" + testgenValid(t, input, jsonRef) +} - input := `[a] -[a.b]` - jsonRef := `{ - "a": { "b": {} } -}` +func TestTOMLTest_Valid_Table_Keyword(t *testing.T) { + input := "[true]\n\n[false]\n\n[inf]\n\n[nan]\n\n\n" + jsonRef := "{\n \"true\": {},\n \"false\": {},\n \"inf\": {},\n \"nan\": {}\n}\n" testgenValid(t, input, jsonRef) } -func TestValidTableWhitespace(t *testing.T) { +func TestTOMLTest_Valid_Table_Names(t *testing.T) { + input := "[a.b.c]\n[a.\"b.c\"]\n[a.'d.e']\n[a.' x ']\n[ d.e.f ]\n[ g . h . i ]\n[ j . \"ʞ\" . 'l' ]\n\n[x.1.2]\n" + jsonRef := "{\n \"a\": {\n \" x \": {},\n \"b\": {\n \"c\": {}\n },\n \"b.c\": {},\n \"d.e\": {}\n },\n \"d\": {\n \"e\": {\n \"f\": {}\n }\n },\n \"g\": {\n \"h\": {\n \"i\": {}\n }\n },\n \"j\": {\n \"ʞ\": {\n \"l\": {}\n }\n },\n \"x\": {\n \"1\": {\n \"2\": {}\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `["valid key"]` - jsonRef := `{ - "valid key": {} -}` +func TestTOMLTest_Valid_Table_NoEol(t *testing.T) { + input := "[table]\n" + jsonRef := "{\n \"table\": {}\n}\n" testgenValid(t, input, jsonRef) } -func TestValidTableWithPound(t *testing.T) { +func TestTOMLTest_Valid_Table_SubEmpty(t *testing.T) { + input := "[a]\n[a.b]\n" + jsonRef := "{\n \"a\": {\n \"b\": {}\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `["key#group"] -answer = 42` - jsonRef := `{ - "key#group": { - "answer": {"type": "integer", "value": "42"} - } -}` +func TestTOMLTest_Valid_Table_Whitespace(t *testing.T) { + input := "[\"valid key\"]\n" + jsonRef := "{\n \"valid key\": {}\n}\n" testgenValid(t, input, jsonRef) } -func TestValidUnicodeEscape(t *testing.T) { +func TestTOMLTest_Valid_Table_WithLiteralString(t *testing.T) { + input := "['a']\n[a.'\"b\"']\n[a.'\"b\"'.c]\nanswer = 42 \n" + jsonRef := "{\n \"a\": {\n \"\\\"b\\\"\": {\n \"c\": {\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `answer4 = "\u03B4" -answer8 = "\U000003B4"` - jsonRef := `{ - "answer4": {"type": "string", "value": "\u03B4"}, - "answer8": {"type": "string", "value": "\u03B4"} -}` +func TestTOMLTest_Valid_Table_WithPound(t *testing.T) { + input := "[\"key#group\"]\nanswer = 42\n" + jsonRef := "{\n \"key#group\": {\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n}\n" testgenValid(t, input, jsonRef) } -func TestValidUnicodeLiteral(t *testing.T) { +func TestTOMLTest_Valid_Table_WithSingleQuotes(t *testing.T) { + input := "['a']\n[a.'b']\n[a.'b'.c]\nanswer = 42 \n" + jsonRef := "{\n \"a\": {\n \"b\": {\n \"c\": {\n \"answer\": {\n \"type\": \"integer\",\n \"value\": \"42\"\n }\n }\n }\n }\n}\n" + testgenValid(t, input, jsonRef) +} - input := `answer = "δ"` - jsonRef := `{ - "answer": {"type": "string", "value": "δ"} -}` +func TestTOMLTest_Valid_Table_WithoutSuper(t *testing.T) { + input := "# [x] you\n# [x.y] don't\n# [x.y.z] need these\n[x.y.z.w] # for this to work\n[x] # defining a super-table afterwards is ok\n" + jsonRef := "{\n \"x\": {\n \"y\": {\n \"z\": {\n \"w\": {}\n }\n }\n }\n}\n" testgenValid(t, input, jsonRef) }