z_spec_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2014 The Go Authors.
  2. // See https://code.google.com/p/go/source/browse/CONTRIBUTORS
  3. // Licensed under the same terms as Go itself:
  4. // https://code.google.com/p/go/source/browse/LICENSE
  5. package http2
  6. import (
  7. "encoding/xml"
  8. "fmt"
  9. "io"
  10. "os"
  11. "reflect"
  12. "regexp"
  13. "sort"
  14. "strconv"
  15. "strings"
  16. "testing"
  17. )
  18. // The global map of sentence coverage for the http2 spec.
  19. var defaultSpecCoverage specCoverage
  20. func init() {
  21. f, err := os.Open("testdata/draft-ietf-httpbis-http2.xml")
  22. if err != nil {
  23. panic(err)
  24. }
  25. defaultSpecCoverage = readSpecCov(f)
  26. }
  27. // specCover marks all sentences for section sec in defaultSpecCoverage. Sentences not
  28. // "covered" will be included in report outputed by TestSpecCoverage.
  29. func specCover(sec, sentences string) {
  30. defaultSpecCoverage.cover(sec, sentences)
  31. }
  32. type specPart struct {
  33. section string
  34. sentence string
  35. }
  36. func (ss specPart) Less(oo specPart) bool {
  37. atoi := func(s string) int {
  38. n, err := strconv.Atoi(s)
  39. if err != nil {
  40. panic(err)
  41. }
  42. return n
  43. }
  44. a := strings.Split(ss.section, ".")
  45. b := strings.Split(oo.section, ".")
  46. for i := 0; i < len(a); i++ {
  47. if i >= len(b) {
  48. return false
  49. }
  50. x, y := atoi(a[i]), atoi(b[i])
  51. if x < y {
  52. return true
  53. }
  54. }
  55. return false
  56. }
  57. type bySpecSection []specPart
  58. func (a bySpecSection) Len() int { return len(a) }
  59. func (a bySpecSection) Less(i, j int) bool { return a[i].Less(a[j]) }
  60. func (a bySpecSection) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  61. type specCoverage map[specPart]bool
  62. func readSection(sc specCoverage, d *xml.Decoder, sec []int) {
  63. sub := 0
  64. for {
  65. tk, err := d.Token()
  66. if err != nil {
  67. if err == io.EOF {
  68. return
  69. }
  70. panic(err)
  71. }
  72. switch v := tk.(type) {
  73. case xml.StartElement:
  74. if v.Name.Local == "section" {
  75. sub++
  76. readSection(sc, d, append(sec, sub))
  77. }
  78. case xml.CharData:
  79. if len(sec) == 0 {
  80. break
  81. }
  82. ssec := fmt.Sprintf("%d", sec[0])
  83. for _, n := range sec[1:] {
  84. ssec = fmt.Sprintf("%s.%d", ssec, n)
  85. }
  86. sc.addSentences(ssec, string(v))
  87. case xml.EndElement:
  88. if v.Name.Local == "section" {
  89. return
  90. }
  91. }
  92. }
  93. }
  94. func readSpecCov(r io.Reader) specCoverage {
  95. d := xml.NewDecoder(r)
  96. sc := specCoverage{}
  97. readSection(sc, d, nil)
  98. return sc
  99. }
  100. func (sc specCoverage) addSentences(sec string, sentence string) {
  101. for _, s := range parseSentences(sentence) {
  102. sc[specPart{sec, s}] = false
  103. }
  104. }
  105. func (sc specCoverage) cover(sec string, sentence string) {
  106. for _, s := range parseSentences(sentence) {
  107. p := specPart{sec, s}
  108. if _, ok := sc[p]; !ok {
  109. panic(fmt.Sprintf("Not found in spec: %q, %q", sec, s))
  110. }
  111. sc[specPart{sec, s}] = true
  112. }
  113. }
  114. func parseSentences(sens string) []string {
  115. sens = strings.TrimSpace(sens)
  116. if sens == "" {
  117. return nil
  118. }
  119. rx := regexp.MustCompile("[\t\n\r]")
  120. ss := strings.Split(rx.ReplaceAllString(sens, " "), ". ")
  121. for i, s := range ss {
  122. s = strings.TrimSpace(s)
  123. if !strings.HasSuffix(s, ".") {
  124. s += "."
  125. }
  126. ss[i] = s
  127. }
  128. return ss
  129. }
  130. func TestSpecParseSentences(t *testing.T) {
  131. tests := []struct {
  132. ss string
  133. want []string
  134. }{
  135. {"Sentence 1. Sentence 2.",
  136. []string{
  137. "Sentence 1.",
  138. "Sentence 2.",
  139. }},
  140. {"Sentence 1. \nSentence 2.\tSentence 3.",
  141. []string{
  142. "Sentence 1.",
  143. "Sentence 2.",
  144. "Sentence 3.",
  145. }},
  146. }
  147. for i, tt := range tests {
  148. got := parseSentences(tt.ss)
  149. if !reflect.DeepEqual(got, tt.want) {
  150. t.Errorf("%d: got = %q, want %q", i, got, tt.want)
  151. }
  152. }
  153. }
  154. func TestSpecBuildCoverageTable(t *testing.T) {
  155. testdata := `
  156. <rfc>
  157. <middle>
  158. <section anchor="intro" title="Introduction">
  159. <t>Foo.</t>
  160. <t><t>Sentence 1.
  161. Sentence 2
  162. . Sentence 3.</t></t>
  163. </section>
  164. <section anchor="bar" title="Introduction">
  165. <t>Bar.</t>
  166. <section anchor="bar" title="Introduction">
  167. <t>Baz.</t>
  168. </section>
  169. </section>
  170. </middle>
  171. </rfc>`
  172. got := readSpecCov(strings.NewReader(testdata))
  173. want := specCoverage{
  174. specPart{"1", "Foo."}: false,
  175. specPart{"1", "Sentence 1."}: false,
  176. specPart{"1", "Sentence 2."}: false,
  177. specPart{"1", "Sentence 3."}: false,
  178. specPart{"2", "Bar."}: false,
  179. specPart{"2.1", "Baz."}: false,
  180. }
  181. if !reflect.DeepEqual(got, want) {
  182. t.Errorf("got = %+v, want %+v", got, want)
  183. }
  184. }
  185. func TestSpecUncovered(t *testing.T) {
  186. testdata := `
  187. <rfc>
  188. <middle>
  189. <section anchor="intro" title="Introduction">
  190. <t>Foo.</t>
  191. <t><t>Sentence 1.</t></t>
  192. </section>
  193. </middle>
  194. </rfc>`
  195. sp := readSpecCov(strings.NewReader(testdata))
  196. sp.cover("1", "Foo. Sentence 1.")
  197. want := specCoverage{
  198. specPart{"1", "Foo."}: true,
  199. specPart{"1", "Sentence 1."}: true,
  200. }
  201. if !reflect.DeepEqual(sp, want) {
  202. t.Errorf("got = %+v, want %+v", sp, want)
  203. }
  204. defer func() {
  205. if err := recover(); err == nil {
  206. t.Error("expected panic")
  207. }
  208. }()
  209. sp.cover("1", "Not in spec.")
  210. }
  211. func TestSpecCoverage(t *testing.T) {
  212. var notCovered bySpecSection
  213. for p, covered := range defaultSpecCoverage {
  214. if !covered {
  215. notCovered = append(notCovered, p)
  216. }
  217. }
  218. if len(notCovered) == 0 {
  219. return
  220. }
  221. sort.Sort(notCovered)
  222. const shortLen = 5
  223. if testing.Short() && len(notCovered) > shortLen {
  224. notCovered = notCovered[:shortLen]
  225. }
  226. t.Logf("COVER REPORT:")
  227. for _, p := range notCovered {
  228. t.Errorf("\tSECTION %s: %s", p.section, p.sentence)
  229. }
  230. }