benchmark_test.go 3.1 KB

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