1
2
3
4 package toml_test
5
6 import (
7 "bytes"
8 "io/fs"
9 "io/ioutil"
10 "os"
11 "path/filepath"
12 "sort"
13 "strings"
14 "testing"
15 "time"
16
17 "github.com/BurntSushi/toml"
18 tomltest "github.com/BurntSushi/toml/internal/toml-test"
19 )
20
21 func BenchmarkDecode(b *testing.B) {
22 files := make(map[string][]string)
23 fs.WalkDir(tomltest.EmbeddedTests(), ".", func(path string, d fs.DirEntry, err error) error {
24 if strings.HasPrefix(path, "valid/") && strings.HasSuffix(path, ".toml") {
25 d, _ := fs.ReadFile(tomltest.EmbeddedTests(), path)
26 g := filepath.Dir(path[6:])
27 if g == "." {
28 g = "top"
29 }
30 files[g] = append(files[g], string(d))
31 }
32 return nil
33 })
34
35 type test struct {
36 group string
37 toml []string
38 }
39 tests := make([]test, 0, len(files))
40 for k, v := range files {
41 tests = append(tests, test{group: k, toml: v})
42 }
43 sort.Slice(tests, func(i, j int) bool { return tests[i].group < tests[j].group })
44
45 b.ResetTimer()
46 for _, tt := range tests {
47 b.Run(tt.group, func(b *testing.B) {
48 b.ResetTimer()
49 for n := 0; n < b.N; n++ {
50 for _, f := range tt.toml {
51 var val map[string]interface{}
52 toml.Decode(f, &val)
53 }
54 }
55 })
56 }
57
58 b.Run("large-doc", func(b *testing.B) {
59 d, err := os.ReadFile("testdata/ja-JP.toml")
60 if err != nil {
61 b.Fatal(err)
62 }
63 doc := string(d)
64
65 b.ResetTimer()
66 for n := 0; n < b.N; n++ {
67 var val map[string]interface{}
68 toml.Decode(doc, &val)
69 }
70 })
71 }
72
73 func BenchmarkEncode(b *testing.B) {
74 files := make(map[string][]map[string]interface{})
75 fs.WalkDir(tomltest.EmbeddedTests(), ".", func(path string, d fs.DirEntry, err error) error {
76 if strings.HasPrefix(path, "valid/") && strings.HasSuffix(path, ".toml") {
77 d, _ := fs.ReadFile(tomltest.EmbeddedTests(), path)
78 g := filepath.Dir(path[6:])
79 if g == "." {
80 g = "top"
81 }
82
83
84 switch path {
85 case "valid/string/escape-esc.toml", "valid/datetime/no-seconds.toml",
86 "valid/string/hex-escape.toml", "valid/inline-table/newline.toml",
87 "valid/key/unicode.toml":
88 return nil
89 }
90
91 var dec map[string]interface{}
92 _, err := toml.Decode(string(d), &dec)
93 if err != nil {
94 b.Fatalf("decode %q: %s", path, err)
95 }
96
97 buf := new(bytes.Buffer)
98 err = toml.NewEncoder(buf).Encode(dec)
99 if err != nil {
100 b.Logf("encode failed for %q (skipping): %s", path, err)
101 return nil
102 }
103
104 files[g] = append(files[g], dec)
105 }
106 return nil
107 })
108
109 type test struct {
110 group string
111 data []map[string]interface{}
112 }
113 tests := make([]test, 0, len(files))
114 for k, v := range files {
115 tests = append(tests, test{group: k, data: v})
116 }
117 sort.Slice(tests, func(i, j int) bool { return tests[i].group < tests[j].group })
118
119 b.ResetTimer()
120 for _, tt := range tests {
121 b.Run(tt.group, func(b *testing.B) {
122 buf := new(bytes.Buffer)
123 buf.Grow(1024 * 64)
124 b.ResetTimer()
125 for n := 0; n < b.N; n++ {
126 for _, f := range tt.data {
127 toml.NewEncoder(buf).Encode(f)
128 }
129 }
130 })
131 }
132 }
133
134 func BenchmarkExample(b *testing.B) {
135 d, err := ioutil.ReadFile("_example/example.toml")
136 if err != nil {
137 b.Fatal(err)
138 }
139 t := string(d)
140
141 var decoded example
142 _, err = toml.Decode(t, &decoded)
143 if err != nil {
144 b.Fatal(err)
145 }
146
147 buf := new(bytes.Buffer)
148 err = toml.NewEncoder(buf).Encode(decoded)
149 if err != nil {
150 b.Fatal(err)
151 }
152
153 b.ResetTimer()
154 b.Run("decode", func(b *testing.B) {
155 for n := 0; n < b.N; n++ {
156 var c example
157 toml.Decode(t, &c)
158 }
159 })
160
161 b.Run("encode", func(b *testing.B) {
162 for n := 0; n < b.N; n++ {
163 buf.Reset()
164 toml.NewEncoder(buf).Encode(decoded)
165 }
166 })
167 }
168
169
170 type (
171 example struct {
172 Title string
173 Integers []int
174 Times []fmtTime
175 Duration []duration
176 Distros []distro
177 Servers map[string]server
178 Characters map[string][]struct {
179 Name string
180 Rank string
181 }
182 }
183
184 server struct {
185 IP string
186 Hostname string
187 Enabled bool
188 }
189
190 distro struct {
191 Name string
192 Packages string
193 }
194
195 duration struct{ time.Duration }
196 fmtTime struct{ time.Time }
197 )
198
199 func (d *duration) UnmarshalText(text []byte) (err error) {
200 d.Duration, err = time.ParseDuration(string(text))
201 return err
202 }
203
204 func (t fmtTime) String() string {
205 f := "2006-01-02 15:04:05.999999999"
206 if t.Time.Hour() == 0 {
207 f = "2006-01-02"
208 }
209 if t.Time.Year() == 0 {
210 f = "15:04:05.999999999"
211 }
212 if t.Time.Location() == time.UTC {
213 f += " UTC"
214 } else {
215 f += " -0700"
216 }
217 return t.Time.Format(`"` + f + `"`)
218 }
219
View as plain text