1package yaml_test 2 3import ( 4 "strings" 5 "testing" 6 7 . "gopkg.in/check.v1" 8 "gopkg.in/yaml.v2" 9) 10 11var limitTests = []struct { 12 name string 13 data []byte 14 error string 15}{ 16 { 17 name: "1000kb of maps with 100 aliases", 18 data: []byte(`{a: &a [{a}` + strings.Repeat(`,{a}`, 1000*1024/4-100) + `], b: &b [*a` + strings.Repeat(`,*a`, 99) + `]}`), 19 error: "yaml: document contains excessive aliasing", 20 }, { 21 name: "1000kb of deeply nested slices", 22 data: []byte(strings.Repeat(`[`, 1000*1024)), 23 error: "yaml: exceeded max depth of 10000", 24 }, { 25 name: "1000kb of deeply nested maps", 26 data: []byte("x: " + strings.Repeat(`{`, 1000*1024)), 27 error: "yaml: exceeded max depth of 10000", 28 }, { 29 name: "1000kb of deeply nested indents", 30 data: []byte(strings.Repeat(`- `, 1000*1024)), 31 error: "yaml: exceeded max depth of 10000", 32 }, { 33 name: "1000kb of 1000-indent lines", 34 data: []byte(strings.Repeat(strings.Repeat(`- `, 1000)+"\n", 1024/2)), 35 }, 36 {name: "1kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 1*1024/4-1) + `]`)}, 37 {name: "10kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 10*1024/4-1) + `]`)}, 38 {name: "100kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 100*1024/4-1) + `]`)}, 39 {name: "1000kb of maps", data: []byte(`a: &a [{a}` + strings.Repeat(`,{a}`, 1000*1024/4-1) + `]`)}, 40 {name: "1000kb slice nested at max-depth", data: []byte(strings.Repeat(`[`, 10000) + `1` + strings.Repeat(`,1`, 1000*1024/2-20000-1) + strings.Repeat(`]`, 10000))}, 41 {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))}, 42 {name: "1000kb of 10000-nested lines", data: []byte(strings.Repeat(`- `+strings.Repeat(`[`, 10000)+strings.Repeat(`]`, 10000)+"\n", 1000*1024/20000))}, 43} 44 45func (s *S) TestLimits(c *C) { 46 if testing.Short() { 47 return 48 } 49 for _, tc := range limitTests { 50 var v interface{} 51 err := yaml.Unmarshal(tc.data, &v) 52 if len(tc.error) > 0 { 53 c.Assert(err, ErrorMatches, tc.error, Commentf("testcase: %s", tc.name)) 54 } else { 55 c.Assert(err, IsNil, Commentf("testcase: %s", tc.name)) 56 } 57 } 58} 59 60func Benchmark1000KB100Aliases(b *testing.B) { 61 benchmark(b, "1000kb of maps with 100 aliases") 62} 63func Benchmark1000KBDeeplyNestedSlices(b *testing.B) { 64 benchmark(b, "1000kb of deeply nested slices") 65} 66func Benchmark1000KBDeeplyNestedMaps(b *testing.B) { 67 benchmark(b, "1000kb of deeply nested maps") 68} 69func Benchmark1000KBDeeplyNestedIndents(b *testing.B) { 70 benchmark(b, "1000kb of deeply nested indents") 71} 72func Benchmark1000KB1000IndentLines(b *testing.B) { 73 benchmark(b, "1000kb of 1000-indent lines") 74} 75func Benchmark1KBMaps(b *testing.B) { 76 benchmark(b, "1kb of maps") 77} 78func Benchmark10KBMaps(b *testing.B) { 79 benchmark(b, "10kb of maps") 80} 81func Benchmark100KBMaps(b *testing.B) { 82 benchmark(b, "100kb of maps") 83} 84func Benchmark1000KBMaps(b *testing.B) { 85 benchmark(b, "1000kb of maps") 86} 87 88func BenchmarkDeepSlice(b *testing.B) { 89 benchmark(b, "1000kb slice nested at max-depth") 90} 91 92func BenchmarkDeepFlow(b *testing.B) { 93 benchmark(b, "1000kb slice nested in maps at max-depth") 94} 95 96func Benchmark1000KBMaxDepthNested(b *testing.B) { 97 benchmark(b, "1000kb of 10000-nested lines") 98} 99 100func benchmark(b *testing.B, name string) { 101 for _, t := range limitTests { 102 if t.name != name { 103 continue 104 } 105 106 b.ResetTimer() 107 108 for i := 0; i < b.N; i++ { 109 var v interface{} 110 err := yaml.Unmarshal(t.data, &v) 111 if len(t.error) > 0 { 112 if err == nil { 113 b.Errorf("expected error, got none") 114 } else if err.Error() != t.error { 115 b.Errorf("expected error '%s', got '%s'", t.error, err.Error()) 116 } 117 } else { 118 if err != nil { 119 b.Errorf("unexpected error: %v", err) 120 } 121 } 122 } 123 124 return 125 } 126 127 b.Errorf("testcase %q not found", name) 128} 129