014204cfb7
As recommended, an `internal/assert` package was added with a reduced set of assertions. All tests were then refactored to use the internal assertions. When more complex assertions were used, they have been rewritten using logic and the simplified assertions. Fancy formatting for failures was omitted. The `internal/assert/assertions.diff` function could be overwritten for better formatting. That is where diff libraries are used in other test suites. Refs: #872 Co-authored-by: Alex Mikitik <alex.mikitik@oracle.com>
655 lines
11 KiB
Go
655 lines
11 KiB
Go
package benchmark_test
|
|
|
|
import (
|
|
"bytes"
|
|
"io/ioutil"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pelletier/go-toml/v2"
|
|
"github.com/pelletier/go-toml/v2/internal/assert"
|
|
)
|
|
|
|
func TestUnmarshalSimple(t *testing.T) {
|
|
doc := []byte(`A = "hello"`)
|
|
d := struct {
|
|
A string
|
|
}{}
|
|
|
|
err := toml.Unmarshal(doc, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func BenchmarkUnmarshal(b *testing.B) {
|
|
b.Run("SimpleDocument", func(b *testing.B) {
|
|
doc := []byte(`A = "hello"`)
|
|
|
|
b.Run("struct", func(b *testing.B) {
|
|
b.SetBytes(int64(len(doc)))
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
d := struct {
|
|
A string
|
|
}{}
|
|
|
|
err := toml.Unmarshal(doc, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("map", func(b *testing.B) {
|
|
b.SetBytes(int64(len(doc)))
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
d := map[string]interface{}{}
|
|
err := toml.Unmarshal(doc, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("ReferenceFile", func(b *testing.B) {
|
|
bytes, err := ioutil.ReadFile("benchmark.toml")
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
b.Run("struct", func(b *testing.B) {
|
|
b.SetBytes(int64(len(bytes)))
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
d := benchmarkDoc{}
|
|
err := toml.Unmarshal(bytes, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
|
|
b.Run("map", func(b *testing.B) {
|
|
b.SetBytes(int64(len(bytes)))
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
d := map[string]interface{}{}
|
|
err := toml.Unmarshal(bytes, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
b.Run("HugoFrontMatter", func(b *testing.B) {
|
|
b.SetBytes(int64(len(hugoFrontMatterbytes)))
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
d := map[string]interface{}{}
|
|
err := toml.Unmarshal(hugoFrontMatterbytes, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func marshal(v interface{}) ([]byte, error) {
|
|
var b bytes.Buffer
|
|
enc := toml.NewEncoder(&b)
|
|
err := enc.Encode(v)
|
|
return b.Bytes(), err
|
|
}
|
|
|
|
func BenchmarkMarshal(b *testing.B) {
|
|
b.Run("SimpleDocument", func(b *testing.B) {
|
|
doc := []byte(`A = "hello"`)
|
|
|
|
b.Run("struct", func(b *testing.B) {
|
|
d := struct {
|
|
A string
|
|
}{}
|
|
|
|
err := toml.Unmarshal(doc, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
var out []byte
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
out, err = marshal(d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
b.SetBytes(int64(len(out)))
|
|
})
|
|
|
|
b.Run("map", func(b *testing.B) {
|
|
d := map[string]interface{}{}
|
|
err := toml.Unmarshal(doc, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
var out []byte
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
out, err = marshal(d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
b.SetBytes(int64(len(out)))
|
|
})
|
|
})
|
|
|
|
b.Run("ReferenceFile", func(b *testing.B) {
|
|
bytes, err := ioutil.ReadFile("benchmark.toml")
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
b.Run("struct", func(b *testing.B) {
|
|
d := benchmarkDoc{}
|
|
err := toml.Unmarshal(bytes, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
var out []byte
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
out, err = marshal(d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
b.SetBytes(int64(len(out)))
|
|
})
|
|
|
|
b.Run("map", func(b *testing.B) {
|
|
d := map[string]interface{}{}
|
|
err := toml.Unmarshal(bytes, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
var out []byte
|
|
for i := 0; i < b.N; i++ {
|
|
out, err = marshal(d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
b.SetBytes(int64(len(out)))
|
|
})
|
|
})
|
|
|
|
b.Run("HugoFrontMatter", func(b *testing.B) {
|
|
d := map[string]interface{}{}
|
|
err := toml.Unmarshal(hugoFrontMatterbytes, &d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
var out []byte
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
out, err = marshal(d)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
b.SetBytes(int64(len(out)))
|
|
})
|
|
}
|
|
|
|
type benchmarkDoc struct {
|
|
Table struct {
|
|
Key string
|
|
Subtable struct {
|
|
Key string
|
|
}
|
|
Inline struct {
|
|
Name struct {
|
|
First string
|
|
Last string
|
|
}
|
|
Point struct {
|
|
X int64
|
|
Y int64
|
|
}
|
|
}
|
|
}
|
|
String struct {
|
|
Basic struct {
|
|
Basic string
|
|
}
|
|
Multiline struct {
|
|
Key1 string
|
|
Key2 string
|
|
Key3 string
|
|
Continued struct {
|
|
Key1 string
|
|
Key2 string
|
|
Key3 string
|
|
}
|
|
}
|
|
Literal struct {
|
|
Winpath string
|
|
Winpath2 string
|
|
Quoted string
|
|
Regex string
|
|
Multiline struct {
|
|
Regex2 string
|
|
Lines string
|
|
}
|
|
}
|
|
}
|
|
Integer struct {
|
|
Key1 int64
|
|
Key2 int64
|
|
Key3 int64
|
|
Key4 int64
|
|
Underscores struct {
|
|
Key1 int64
|
|
Key2 int64
|
|
Key3 int64
|
|
}
|
|
}
|
|
Float struct {
|
|
Fractional struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
Key3 float64
|
|
}
|
|
Exponent struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
Key3 float64
|
|
}
|
|
Both struct {
|
|
Key float64
|
|
}
|
|
Underscores struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
}
|
|
}
|
|
Boolean struct {
|
|
True bool
|
|
False bool
|
|
}
|
|
Datetime struct {
|
|
Key1 time.Time
|
|
Key2 time.Time
|
|
Key3 time.Time
|
|
}
|
|
Array struct {
|
|
Key1 []int64
|
|
Key2 []string
|
|
Key3 [][]int64
|
|
// TODO: Key4 not supported by go-toml's Unmarshal
|
|
Key4 []interface{}
|
|
Key5 []int64
|
|
Key6 []int64
|
|
}
|
|
Products []struct {
|
|
Name string
|
|
Sku int64
|
|
Color string
|
|
}
|
|
Fruit []struct {
|
|
Name string
|
|
Physical struct {
|
|
Color string
|
|
Shape string
|
|
}
|
|
Variety []struct {
|
|
Name string
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalReferenceFile(t *testing.T) {
|
|
bytes, err := ioutil.ReadFile("benchmark.toml")
|
|
assert.NoError(t, err)
|
|
d := benchmarkDoc{}
|
|
err = toml.Unmarshal(bytes, &d)
|
|
assert.NoError(t, err)
|
|
|
|
expected := benchmarkDoc{
|
|
Table: struct {
|
|
Key string
|
|
Subtable struct{ Key string }
|
|
Inline struct {
|
|
Name struct {
|
|
First string
|
|
Last string
|
|
}
|
|
Point struct {
|
|
X int64
|
|
Y int64
|
|
}
|
|
}
|
|
}{
|
|
Key: "value",
|
|
Subtable: struct{ Key string }{
|
|
Key: "another value",
|
|
},
|
|
// note: x.y.z.w is purposefully missing
|
|
Inline: struct {
|
|
Name struct {
|
|
First string
|
|
Last string
|
|
}
|
|
Point struct {
|
|
X int64
|
|
Y int64
|
|
}
|
|
}{
|
|
Name: struct {
|
|
First string
|
|
Last string
|
|
}{
|
|
First: "Tom",
|
|
Last: "Preston-Werner",
|
|
},
|
|
Point: struct {
|
|
X int64
|
|
Y int64
|
|
}{
|
|
X: 1,
|
|
Y: 2,
|
|
},
|
|
},
|
|
},
|
|
String: struct {
|
|
Basic struct{ Basic string }
|
|
Multiline struct {
|
|
Key1 string
|
|
Key2 string
|
|
Key3 string
|
|
Continued struct {
|
|
Key1 string
|
|
Key2 string
|
|
Key3 string
|
|
}
|
|
}
|
|
Literal struct {
|
|
Winpath string
|
|
Winpath2 string
|
|
Quoted string
|
|
Regex string
|
|
Multiline struct {
|
|
Regex2 string
|
|
Lines string
|
|
}
|
|
}
|
|
}{
|
|
Basic: struct{ Basic string }{
|
|
Basic: "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.",
|
|
},
|
|
Multiline: struct {
|
|
Key1 string
|
|
Key2 string
|
|
Key3 string
|
|
Continued struct {
|
|
Key1 string
|
|
Key2 string
|
|
Key3 string
|
|
}
|
|
}{
|
|
Key1: "One\nTwo",
|
|
Key2: "One\nTwo",
|
|
Key3: "One\nTwo",
|
|
|
|
Continued: struct {
|
|
Key1 string
|
|
Key2 string
|
|
Key3 string
|
|
}{
|
|
Key1: `The quick brown fox jumps over the lazy dog.`,
|
|
Key2: `The quick brown fox jumps over the lazy dog.`,
|
|
Key3: `The quick brown fox jumps over the lazy dog.`,
|
|
},
|
|
},
|
|
Literal: struct {
|
|
Winpath string
|
|
Winpath2 string
|
|
Quoted string
|
|
Regex string
|
|
Multiline struct {
|
|
Regex2 string
|
|
Lines string
|
|
}
|
|
}{
|
|
Winpath: `C:\Users\nodejs\templates`,
|
|
Winpath2: `\\ServerX\admin$\system32\`,
|
|
Quoted: `Tom "Dubs" Preston-Werner`,
|
|
Regex: `<\i\c*\s*>`,
|
|
|
|
Multiline: struct {
|
|
Regex2 string
|
|
Lines string
|
|
}{
|
|
Regex2: `I [dw]on't need \d{2} apples`,
|
|
Lines: `The first newline is
|
|
trimmed in raw strings.
|
|
All other whitespace
|
|
is preserved.
|
|
`,
|
|
},
|
|
},
|
|
},
|
|
Integer: struct {
|
|
Key1 int64
|
|
Key2 int64
|
|
Key3 int64
|
|
Key4 int64
|
|
Underscores struct {
|
|
Key1 int64
|
|
Key2 int64
|
|
Key3 int64
|
|
}
|
|
}{
|
|
Key1: 99,
|
|
Key2: 42,
|
|
Key3: 0,
|
|
Key4: -17,
|
|
|
|
Underscores: struct {
|
|
Key1 int64
|
|
Key2 int64
|
|
Key3 int64
|
|
}{
|
|
Key1: 1000,
|
|
Key2: 5349221,
|
|
Key3: 12345,
|
|
},
|
|
},
|
|
Float: struct {
|
|
Fractional struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
Key3 float64
|
|
}
|
|
Exponent struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
Key3 float64
|
|
}
|
|
Both struct{ Key float64 }
|
|
Underscores struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
}
|
|
}{
|
|
Fractional: struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
Key3 float64
|
|
}{
|
|
Key1: 1.0,
|
|
Key2: 3.1415,
|
|
Key3: -0.01,
|
|
},
|
|
Exponent: struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
Key3 float64
|
|
}{
|
|
Key1: 5e+22,
|
|
Key2: 1e6,
|
|
Key3: -2e-2,
|
|
},
|
|
Both: struct{ Key float64 }{
|
|
Key: 6.626e-34,
|
|
},
|
|
Underscores: struct {
|
|
Key1 float64
|
|
Key2 float64
|
|
}{
|
|
Key1: 9224617.445991228313,
|
|
Key2: 1e100,
|
|
},
|
|
},
|
|
Boolean: struct {
|
|
True bool
|
|
False bool
|
|
}{
|
|
True: true,
|
|
False: false,
|
|
},
|
|
Datetime: struct {
|
|
Key1 time.Time
|
|
Key2 time.Time
|
|
Key3 time.Time
|
|
}{
|
|
Key1: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
|
|
Key2: time.Date(1979, 5, 27, 0, 32, 0, 0, time.FixedZone("", -7*3600)),
|
|
Key3: time.Date(1979, 5, 27, 0, 32, 0, 999999000, time.FixedZone("", -7*3600)),
|
|
},
|
|
Array: struct {
|
|
Key1 []int64
|
|
Key2 []string
|
|
Key3 [][]int64
|
|
Key4 []interface{}
|
|
Key5 []int64
|
|
Key6 []int64
|
|
}{
|
|
Key1: []int64{1, 2, 3},
|
|
Key2: []string{"red", "yellow", "green"},
|
|
Key3: [][]int64{{1, 2}, {3, 4, 5}},
|
|
Key4: []interface{}{
|
|
[]interface{}{int64(1), int64(2)},
|
|
[]interface{}{"a", "b", "c"},
|
|
},
|
|
Key5: []int64{1, 2, 3},
|
|
Key6: []int64{1, 2},
|
|
},
|
|
Products: []struct {
|
|
Name string
|
|
Sku int64
|
|
Color string
|
|
}{
|
|
{
|
|
Name: "Hammer",
|
|
Sku: 738594937,
|
|
},
|
|
{},
|
|
{
|
|
Name: "Nail",
|
|
Sku: 284758393,
|
|
Color: "gray",
|
|
},
|
|
},
|
|
Fruit: []struct {
|
|
Name string
|
|
Physical struct {
|
|
Color string
|
|
Shape string
|
|
}
|
|
Variety []struct{ Name string }
|
|
}{
|
|
{
|
|
Name: "apple",
|
|
Physical: struct {
|
|
Color string
|
|
Shape string
|
|
}{
|
|
Color: "red",
|
|
Shape: "round",
|
|
},
|
|
Variety: []struct{ Name string }{
|
|
{Name: "red delicious"},
|
|
{Name: "granny smith"},
|
|
},
|
|
},
|
|
{
|
|
Name: "banana",
|
|
Variety: []struct{ Name string }{
|
|
{Name: "plantain"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
assert.Equal(t, expected, d)
|
|
}
|
|
|
|
var hugoFrontMatterbytes = []byte(`
|
|
categories = ["Development", "VIM"]
|
|
date = "2012-04-06"
|
|
description = "spf13-vim is a cross platform distribution of vim plugins and resources for Vim."
|
|
slug = "spf13-vim-3-0-release-and-new-website"
|
|
tags = [".vimrc", "plugins", "spf13-vim", "vim"]
|
|
title = "spf13-vim 3.0 release and new website"
|
|
include_toc = true
|
|
show_comments = false
|
|
|
|
[[cascade]]
|
|
background = "yosemite.jpg"
|
|
[cascade._target]
|
|
kind = "page"
|
|
lang = "en"
|
|
path = "/blog/**"
|
|
|
|
[[cascade]]
|
|
background = "goldenbridge.jpg"
|
|
[cascade._target]
|
|
kind = "section"
|
|
`)
|