...

Source file src/github.com/pelletier/go-toml/tomltree_write_test.go

Documentation: github.com/pelletier/go-toml

     1  package toml
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  type failingWriter struct {
    14  	failAt  int
    15  	written int
    16  	buffer  bytes.Buffer
    17  }
    18  
    19  func (f *failingWriter) Write(p []byte) (n int, err error) {
    20  	count := len(p)
    21  	toWrite := f.failAt - (count + f.written)
    22  	if toWrite < 0 {
    23  		toWrite = 0
    24  	}
    25  	if toWrite > count {
    26  		f.written += count
    27  		f.buffer.Write(p)
    28  		return count, nil
    29  	}
    30  
    31  	f.buffer.Write(p[:toWrite])
    32  	f.written = f.failAt
    33  	return toWrite, fmt.Errorf("failingWriter failed after writing %d bytes", f.written)
    34  }
    35  
    36  func assertErrorString(t *testing.T, expected string, err error) {
    37  	expectedErr := errors.New(expected)
    38  	if err == nil || err.Error() != expectedErr.Error() {
    39  		t.Errorf("expecting error %s, but got %s instead", expected, err)
    40  	}
    41  }
    42  
    43  func TestTreeWriteToEmptyTable(t *testing.T) {
    44  	doc := `[[empty-tables]]
    45  [[empty-tables]]`
    46  
    47  	toml, err := Load(doc)
    48  	if err != nil {
    49  		t.Fatal("Unexpected Load error:", err)
    50  	}
    51  	tomlString, err := toml.ToTomlString()
    52  	if err != nil {
    53  		t.Fatal("Unexpected ToTomlString error:", err)
    54  	}
    55  
    56  	expected := `
    57  [[empty-tables]]
    58  
    59  [[empty-tables]]
    60  `
    61  
    62  	if tomlString != expected {
    63  		t.Fatalf("Expected:\n%s\nGot:\n%s", expected, tomlString)
    64  	}
    65  }
    66  
    67  func TestTreeWriteToTomlString(t *testing.T) {
    68  	toml, err := Load(`name = { first = "Tom", last = "Preston-Werner" }
    69  points = { x = 1, y = 2 }`)
    70  
    71  	if err != nil {
    72  		t.Fatal("Unexpected error:", err)
    73  	}
    74  
    75  	tomlString, _ := toml.ToTomlString()
    76  	reparsedTree, err := Load(tomlString)
    77  
    78  	assertTree(t, reparsedTree, err, map[string]interface{}{
    79  		"name": map[string]interface{}{
    80  			"first": "Tom",
    81  			"last":  "Preston-Werner",
    82  		},
    83  		"points": map[string]interface{}{
    84  			"x": int64(1),
    85  			"y": int64(2),
    86  		},
    87  	})
    88  }
    89  
    90  func TestTreeWriteToTomlStringSimple(t *testing.T) {
    91  	tree, err := Load("[foo]\n\n[[foo.bar]]\na = 42\n\n[[foo.bar]]\na = 69\n")
    92  	if err != nil {
    93  		t.Errorf("Test failed to parse: %v", err)
    94  		return
    95  	}
    96  	result, err := tree.ToTomlString()
    97  	if err != nil {
    98  		t.Errorf("Unexpected error: %s", err)
    99  	}
   100  	expected := "\n[foo]\n\n  [[foo.bar]]\n    a = 42\n\n  [[foo.bar]]\n    a = 69\n"
   101  	if result != expected {
   102  		t.Errorf("Expected got '%s', expected '%s'", result, expected)
   103  	}
   104  }
   105  
   106  func TestTreeWriteToTomlStringKeysOrders(t *testing.T) {
   107  	for i := 0; i < 100; i++ {
   108  		tree, _ := Load(`
   109  		foobar = true
   110  		bar = "baz"
   111  		foo = 1
   112  		[qux]
   113  		  foo = 1
   114  		  bar = "baz2"`)
   115  
   116  		stringRepr, _ := tree.ToTomlString()
   117  
   118  		t.Log("Intermediate string representation:")
   119  		t.Log(stringRepr)
   120  
   121  		r := strings.NewReader(stringRepr)
   122  		toml, err := LoadReader(r)
   123  
   124  		if err != nil {
   125  			t.Fatal("Unexpected error:", err)
   126  		}
   127  
   128  		assertTree(t, toml, err, map[string]interface{}{
   129  			"foobar": true,
   130  			"bar":    "baz",
   131  			"foo":    1,
   132  			"qux": map[string]interface{}{
   133  				"foo": 1,
   134  				"bar": "baz2",
   135  			},
   136  		})
   137  	}
   138  }
   139  
   140  func testMaps(t *testing.T, actual, expected map[string]interface{}) {
   141  	if !reflect.DeepEqual(actual, expected) {
   142  		t.Fatal("trees aren't equal.\n", "Expected:\n", expected, "\nActual:\n", actual)
   143  	}
   144  }
   145  
   146  func TestTreeWriteToMapSimple(t *testing.T) {
   147  	tree, _ := Load("a = 42\nb = 17")
   148  
   149  	expected := map[string]interface{}{
   150  		"a": int64(42),
   151  		"b": int64(17),
   152  	}
   153  
   154  	testMaps(t, tree.ToMap(), expected)
   155  }
   156  
   157  func TestTreeWriteToInvalidTreeSimpleValue(t *testing.T) {
   158  	tree := Tree{values: map[string]interface{}{"foo": int8(1)}}
   159  	_, err := tree.ToTomlString()
   160  	assertErrorString(t, "invalid value type at foo: int8", err)
   161  }
   162  
   163  func TestTreeWriteToInvalidTreeTomlValue(t *testing.T) {
   164  	tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: "", position: Position{}}}}
   165  	_, err := tree.ToTomlString()
   166  	assertErrorString(t, "unsupported value type int8: 1", err)
   167  }
   168  
   169  func TestTreeWriteToInvalidTreeTomlValueArray(t *testing.T) {
   170  	tree := Tree{values: map[string]interface{}{"foo": &tomlValue{value: int8(1), comment: "", position: Position{}}}}
   171  	_, err := tree.ToTomlString()
   172  	assertErrorString(t, "unsupported value type int8: 1", err)
   173  }
   174  
   175  func TestTreeWriteToFailingWriterInSimpleValue(t *testing.T) {
   176  	toml, _ := Load(`a = 2`)
   177  	writer := failingWriter{failAt: 0, written: 0}
   178  	_, err := toml.WriteTo(&writer)
   179  	assertErrorString(t, "failingWriter failed after writing 0 bytes", err)
   180  }
   181  
   182  func TestTreeWriteToFailingWriterInTable(t *testing.T) {
   183  	toml, _ := Load(`
   184  [b]
   185  a = 2`)
   186  	writer := failingWriter{failAt: 2, written: 0}
   187  	_, err := toml.WriteTo(&writer)
   188  	assertErrorString(t, "failingWriter failed after writing 2 bytes", err)
   189  
   190  	writer = failingWriter{failAt: 13, written: 0}
   191  	_, err = toml.WriteTo(&writer)
   192  	assertErrorString(t, "failingWriter failed after writing 13 bytes", err)
   193  }
   194  
   195  func TestTreeWriteToFailingWriterInArray(t *testing.T) {
   196  	toml, _ := Load(`
   197  [[b]]
   198  a = 2`)
   199  	writer := failingWriter{failAt: 2, written: 0}
   200  	_, err := toml.WriteTo(&writer)
   201  	assertErrorString(t, "failingWriter failed after writing 2 bytes", err)
   202  
   203  	writer = failingWriter{failAt: 15, written: 0}
   204  	_, err = toml.WriteTo(&writer)
   205  	assertErrorString(t, "failingWriter failed after writing 15 bytes", err)
   206  }
   207  
   208  func TestTreeWriteToMapExampleFile(t *testing.T) {
   209  	tree, _ := LoadFile("example.toml")
   210  	expected := map[string]interface{}{
   211  		"title": "TOML Example",
   212  		"owner": map[string]interface{}{
   213  			"name":         "Tom Preston-Werner",
   214  			"organization": "GitHub",
   215  			"bio":          "GitHub Cofounder & CEO\nLikes tater tots and beer.",
   216  			"dob":          time.Date(1979, time.May, 27, 7, 32, 0, 0, time.UTC),
   217  		},
   218  		"database": map[string]interface{}{
   219  			"server":         "192.168.1.1",
   220  			"ports":          []interface{}{int64(8001), int64(8001), int64(8002)},
   221  			"connection_max": int64(5000),
   222  			"enabled":        true,
   223  		},
   224  		"servers": map[string]interface{}{
   225  			"alpha": map[string]interface{}{
   226  				"ip": "10.0.0.1",
   227  				"dc": "eqdc10",
   228  			},
   229  			"beta": map[string]interface{}{
   230  				"ip": "10.0.0.2",
   231  				"dc": "eqdc10",
   232  			},
   233  		},
   234  		"clients": map[string]interface{}{
   235  			"data": []interface{}{
   236  				[]interface{}{"gamma", "delta"},
   237  				[]interface{}{int64(1), int64(2)},
   238  			},
   239  			"score": 4e-08,
   240  		},
   241  	}
   242  	testMaps(t, tree.ToMap(), expected)
   243  }
   244  
   245  func TestTreeWriteToMapWithTablesInMultipleChunks(t *testing.T) {
   246  	tree, _ := Load(`
   247  	[[menu.main]]
   248          a = "menu 1"
   249          b = "menu 2"
   250          [[menu.main]]
   251          c = "menu 3"
   252          d = "menu 4"`)
   253  	expected := map[string]interface{}{
   254  		"menu": map[string]interface{}{
   255  			"main": []interface{}{
   256  				map[string]interface{}{"a": "menu 1", "b": "menu 2"},
   257  				map[string]interface{}{"c": "menu 3", "d": "menu 4"},
   258  			},
   259  		},
   260  	}
   261  	treeMap := tree.ToMap()
   262  
   263  	testMaps(t, treeMap, expected)
   264  }
   265  
   266  func TestTreeWriteToMapWithArrayOfInlineTables(t *testing.T) {
   267  	tree, _ := Load(`
   268      	[params]
   269  	language_tabs = [
   270      		{ key = "shell", name = "Shell" },
   271      		{ key = "ruby", name = "Ruby" },
   272      		{ key = "python", name = "Python" }
   273  	]`)
   274  
   275  	expected := map[string]interface{}{
   276  		"params": map[string]interface{}{
   277  			"language_tabs": []interface{}{
   278  				map[string]interface{}{
   279  					"key":  "shell",
   280  					"name": "Shell",
   281  				},
   282  				map[string]interface{}{
   283  					"key":  "ruby",
   284  					"name": "Ruby",
   285  				},
   286  				map[string]interface{}{
   287  					"key":  "python",
   288  					"name": "Python",
   289  				},
   290  			},
   291  		},
   292  	}
   293  
   294  	treeMap := tree.ToMap()
   295  	testMaps(t, treeMap, expected)
   296  }
   297  
   298  func TestTreeWriteToMapWithTableInMixedArray(t *testing.T) {
   299  	tree, _ := Load(`a = [
   300  		"foo",
   301  		[
   302  			"bar",
   303  			{baz = "quux"},
   304  		],
   305  		[
   306  			{a = "b"},
   307  			{c = "d"},
   308  		],
   309  	]`)
   310  	expected := map[string]interface{}{
   311  		"a": []interface{}{
   312  			"foo",
   313  			[]interface{}{
   314  				"bar",
   315  				map[string]interface{}{
   316  					"baz": "quux",
   317  				},
   318  			},
   319  			[]interface{}{
   320  				map[string]interface{}{
   321  					"a": "b",
   322  				},
   323  				map[string]interface{}{
   324  					"c": "d",
   325  				},
   326  			},
   327  		},
   328  	}
   329  	treeMap := tree.ToMap()
   330  
   331  	testMaps(t, treeMap, expected)
   332  }
   333  
   334  func TestTreeWriteToFloat(t *testing.T) {
   335  	tree, err := Load(`a = 3.0`)
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  	str, err := tree.ToTomlString()
   340  	if err != nil {
   341  		t.Fatal(err)
   342  	}
   343  	expected := `a = 3.0`
   344  	if strings.TrimSpace(str) != strings.TrimSpace(expected) {
   345  		t.Fatalf("Expected:\n%s\nGot:\n%s", expected, str)
   346  	}
   347  }
   348  
   349  func TestTreeWriteToSpecialFloat(t *testing.T) {
   350  	expected := `a = +inf
   351  b = -inf
   352  c = nan`
   353  
   354  	tree, err := Load(expected)
   355  	if err != nil {
   356  		t.Fatal(err)
   357  	}
   358  	str, err := tree.ToTomlString()
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	if strings.TrimSpace(str) != strings.TrimSpace(expected) {
   363  		t.Fatalf("Expected:\n%s\nGot:\n%s", expected, str)
   364  	}
   365  }
   366  
   367  func TestOrderedEmptyTrees(t *testing.T) {
   368  	type val struct {
   369  		Key string `toml:"key"`
   370  	}
   371  	type structure struct {
   372  		First val   `toml:"first"`
   373  		Empty []val `toml:"empty"`
   374  	}
   375  	input := structure{First: val{Key: "value"}}
   376  	buf := new(bytes.Buffer)
   377  	err := NewEncoder(buf).Order(OrderPreserve).Encode(input)
   378  	if err != nil {
   379  		t.Fatal("failed to encode input")
   380  	}
   381  	expected := `
   382  [first]
   383    key = "value"
   384  `
   385  	if expected != buf.String() {
   386  		t.Fatal("expected and encoded body aren't equal: ", expected, buf.String())
   387  	}
   388  }
   389  
   390  func TestOrderedNonIncreasedLine(t *testing.T) {
   391  	type NiceMap map[string]string
   392  	type Manifest struct {
   393  		NiceMap `toml:"dependencies"`
   394  		Build   struct {
   395  			BuildCommand string `toml:"build-command"`
   396  		} `toml:"build"`
   397  	}
   398  
   399  	test := &Manifest{}
   400  	test.Build.BuildCommand = "test"
   401  	buf := new(bytes.Buffer)
   402  	if err := NewEncoder(buf).Order(OrderPreserve).Encode(test); err != nil {
   403  		panic(err)
   404  	}
   405  	expected := `
   406  [dependencies]
   407  
   408  [build]
   409    build-command = "test"
   410  `
   411  	if expected != buf.String() {
   412  		t.Fatal("expected and encoded body aren't equal: ", expected, buf.String())
   413  	}
   414  }
   415  
   416  func TestIssue290(t *testing.T) {
   417  	tomlString :=
   418  		`[table]
   419  "127.0.0.1" = "value"
   420  "127.0.0.1:8028" = "value"
   421  "character encoding" = "value"
   422  "ʎǝʞ" = "value"`
   423  
   424  	t1, err := Load(tomlString)
   425  	if err != nil {
   426  		t.Fatal("load err:", err)
   427  	}
   428  
   429  	s, err := t1.ToTomlString()
   430  	if err != nil {
   431  		t.Fatal("ToTomlString err:", err)
   432  	}
   433  
   434  	_, err = Load(s)
   435  	if err != nil {
   436  		t.Fatal("reload err:", err)
   437  	}
   438  }
   439  
   440  func BenchmarkTreeToTomlString(b *testing.B) {
   441  	toml, err := Load(sampleHard)
   442  	if err != nil {
   443  		b.Fatal("Unexpected error:", err)
   444  	}
   445  
   446  	for i := 0; i < b.N; i++ {
   447  		_, err := toml.ToTomlString()
   448  		if err != nil {
   449  			b.Fatal(err)
   450  		}
   451  	}
   452  }
   453  
   454  var sampleHard = `# Test file for TOML
   455  # Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate
   456  # This part you'll really hate
   457  
   458  [the]
   459  test_string = "You'll hate me after this - #"          # " Annoying, isn't it?
   460  
   461      [the.hard]
   462      test_array = [ "] ", " # "]      # ] There you go, parse this!
   463      test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ]
   464      # You didn't think it'd as easy as chucking out the last #, did you?
   465      another_test_string = " Same thing, but with a string #"
   466      harder_test_string = " And when \"'s are in the string, along with # \""   # "and comments are there too"
   467      # Things will get harder
   468  
   469          [the.hard."bit#"]
   470          "what?" = "You don't think some user won't do that?"
   471          multi_line_array = [
   472              "]",
   473              # ] Oh yes I did
   474              ]
   475  
   476  # Each of the following keygroups/key value pairs should produce an error. Uncomment to them to test
   477  
   478  #[error]   if you didn't catch this, your parser is broken
   479  #string = "Anything other than tabs, spaces and newline after a keygroup or key value pair has ended should produce an error unless it is a comment"   like this
   480  #array = [
   481  #         "This might most likely happen in multiline arrays",
   482  #         Like here,
   483  #         "or here,
   484  #         and here"
   485  #         ]     End of array comment, forgot the #
   486  #number = 3.14  pi <--again forgot the #         `
   487  

View as plain text