blob: f160c873d4bdea252f352754099e2e452a440884 [file] [log] [blame]
package yaml_test
import (
"strings"
"testing"
. "gopkg.in/check.v1"
"gopkg.in/yaml.v2"
)
var limitTests = []struct {
name string
data []byte
error string
}{
{
name: "1000kb of maps with 100 aliases",
data: []byte(`{a: &a [{a}` + strings.Repeat(`,{a}`, 1000*1024/4-100) + `], b: &b [*a` + strings.Repeat(`,*a`, 99) + `]}`),
error: "yaml: document contains excessive aliasing",
}, {
name: "1000kb of deeply nested slices",
data: []byte(strings.Repeat(`[`, 1000*1024)),
error: "yaml: exceeded max depth of 10000",
}, {
name: "1000kb of deeply nested maps",
data: []byte("x: " + strings.Repeat(`{`, 1000*1024)),
error: "yaml: exceeded max depth of 10000",
}, {
name: "1000kb of deeply nested indents",
data: []byte(strings.Repeat(`- `, 1000*1024)),
error: "yaml: exceeded max depth of 10000",
}, {
name: "1000kb of 1000-indent lines",
data: []byte(strings.Repeat(strings.Repeat(`- `, 1000)+"\n", 1024/2)),
},
{name: "1kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 1*1024/4-1) + `]`)},
{name: "10kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 10*1024/4-1) + `]`)},
{name: "100kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 100*1024/4-1) + `]`)},
{name: "1000kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 1000*1024/4-1) + `]`)},
{name: "1000kb slice nested at max-depth", data: []byte(strings.Repeat(`[`, 10000) + `1` + strings.Repeat(`,1`, 1000*1024/2-20000-1) + strings.Repeat(`]`, 10000))},
{name: "1000kb slice nested in maps at max-depth", data: []byte("{a,b:\n" + strings.Repeat(" {a,b:", 10000-2) + ` [1` + strings.Repeat(",1", 1000*1024/2-6*10000-1) + `]` + strings.Repeat(`}`, 10000-1))},
}
func (s *S) TestLimits(c *C) {
if testing.Short() {
return
}
for _, tc := range limitTests {
var v interface{}
err := yaml.Unmarshal(tc.data, &v)
if len(tc.error) > 0 {
c.Assert(err, ErrorMatches, tc.error, Commentf("testcase: %s", tc.name))
} else {
c.Assert(err, IsNil, Commentf("testcase: %s", tc.name))
}
}
}
func Benchmark1000KB100Aliases(b *testing.B) {
benchmark(b, "1000kb of maps with 100 aliases")
}
func Benchmark1000KBDeeplyNestedSlices(b *testing.B) {
benchmark(b, "1000kb of deeply nested slices")
}
func Benchmark1000KBDeeplyNestedMaps(b *testing.B) {
benchmark(b, "1000kb of deeply nested maps")
}
func Benchmark1000KBDeeplyNestedIndents(b *testing.B) {
benchmark(b, "1000kb of deeply nested indents")
}
func Benchmark1000KB1000IndentLines(b *testing.B) {
benchmark(b, "1000kb of 1000-indent lines")
}
func Benchmark1KBMaps(b *testing.B) {
benchmark(b, "1kb of maps")
}
func Benchmark10KBMaps(b *testing.B) {
benchmark(b, "10kb of maps")
}
func Benchmark100KBMaps(b *testing.B) {
benchmark(b, "100kb of maps")
}
func Benchmark1000KBMaps(b *testing.B) {
benchmark(b, "1000kb of maps")
}
func BenchmarkDeepSlice(b *testing.B) {
benchmark(b, "1000kb slice nested at max-depth")
}
func BenchmarkDeepFlow(b *testing.B) {
benchmark(b, "1000kb slice nested in maps at max-depth")
}
func benchmark(b *testing.B, name string) {
for _, t := range limitTests {
if t.name != name {
continue
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
var v interface{}
err := yaml.Unmarshal(t.data, &v)
if len(t.error) > 0 {
if err == nil {
b.Errorf("expected error, got none")
} else if err.Error() != t.error {
b.Errorf("expected error '%s', got '%s'", t.error, err.Error())
}
} else {
if err != nil {
b.Errorf("unexpected error: %v", err)
}
}
}
return
}
b.Errorf("testcase %q not found", name)
}