package yaml_test import ( "strings" "testing" . "gopkg.in/check.v1" "gopkg.in/yaml.v2" ) type testcase struct { name string data []byte error string } func testcases() []testcase { return []testcase{ { 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) + `]`)}, } } func (s *S) TestLimits(c *C) { if testing.Short() { return } for _, tc := range testcases() { 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 benchmark(b *testing.B, name string) { var tc testcase for _, t := range testcases() { if t.name == name { tc = t break } } if tc.name != name { b.Errorf("testcase %q not found", name) return } b.ResetTimer() for i := 0; i < b.N; i++ { var v interface{} err := yaml.Unmarshal(tc.data, &v) if len(tc.error) > 0 { if err == nil { b.Errorf("expected error, got none") } else if err.Error() != tc.error { b.Errorf("expected error '%s', got '%s'", tc.error, err.Error()) } } else { if err != nil { b.Errorf("unexpected error: %v", err) } } } }