OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / http2 / z_spec_test.go
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package http2
6
7 import (
8         "bytes"
9         "encoding/xml"
10         "flag"
11         "fmt"
12         "io"
13         "os"
14         "reflect"
15         "regexp"
16         "sort"
17         "strconv"
18         "strings"
19         "sync"
20         "testing"
21 )
22
23 var coverSpec = flag.Bool("coverspec", false, "Run spec coverage tests")
24
25 // The global map of sentence coverage for the http2 spec.
26 var defaultSpecCoverage specCoverage
27
28 var loadSpecOnce sync.Once
29
30 func loadSpec() {
31         if f, err := os.Open("testdata/draft-ietf-httpbis-http2.xml"); err != nil {
32                 panic(err)
33         } else {
34                 defaultSpecCoverage = readSpecCov(f)
35                 f.Close()
36         }
37 }
38
39 // covers marks all sentences for section sec in defaultSpecCoverage. Sentences not
40 // "covered" will be included in report outputted by TestSpecCoverage.
41 func covers(sec, sentences string) {
42         loadSpecOnce.Do(loadSpec)
43         defaultSpecCoverage.cover(sec, sentences)
44 }
45
46 type specPart struct {
47         section  string
48         sentence string
49 }
50
51 func (ss specPart) Less(oo specPart) bool {
52         atoi := func(s string) int {
53                 n, err := strconv.Atoi(s)
54                 if err != nil {
55                         panic(err)
56                 }
57                 return n
58         }
59         a := strings.Split(ss.section, ".")
60         b := strings.Split(oo.section, ".")
61         for len(a) > 0 {
62                 if len(b) == 0 {
63                         return false
64                 }
65                 x, y := atoi(a[0]), atoi(b[0])
66                 if x == y {
67                         a, b = a[1:], b[1:]
68                         continue
69                 }
70                 return x < y
71         }
72         if len(b) > 0 {
73                 return true
74         }
75         return false
76 }
77
78 type bySpecSection []specPart
79
80 func (a bySpecSection) Len() int           { return len(a) }
81 func (a bySpecSection) Less(i, j int) bool { return a[i].Less(a[j]) }
82 func (a bySpecSection) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
83
84 type specCoverage struct {
85         coverage map[specPart]bool
86         d        *xml.Decoder
87 }
88
89 func joinSection(sec []int) string {
90         s := fmt.Sprintf("%d", sec[0])
91         for _, n := range sec[1:] {
92                 s = fmt.Sprintf("%s.%d", s, n)
93         }
94         return s
95 }
96
97 func (sc specCoverage) readSection(sec []int) {
98         var (
99                 buf = new(bytes.Buffer)
100                 sub = 0
101         )
102         for {
103                 tk, err := sc.d.Token()
104                 if err != nil {
105                         if err == io.EOF {
106                                 return
107                         }
108                         panic(err)
109                 }
110                 switch v := tk.(type) {
111                 case xml.StartElement:
112                         if skipElement(v) {
113                                 if err := sc.d.Skip(); err != nil {
114                                         panic(err)
115                                 }
116                                 if v.Name.Local == "section" {
117                                         sub++
118                                 }
119                                 break
120                         }
121                         switch v.Name.Local {
122                         case "section":
123                                 sub++
124                                 sc.readSection(append(sec, sub))
125                         case "xref":
126                                 buf.Write(sc.readXRef(v))
127                         }
128                 case xml.CharData:
129                         if len(sec) == 0 {
130                                 break
131                         }
132                         buf.Write(v)
133                 case xml.EndElement:
134                         if v.Name.Local == "section" {
135                                 sc.addSentences(joinSection(sec), buf.String())
136                                 return
137                         }
138                 }
139         }
140 }
141
142 func (sc specCoverage) readXRef(se xml.StartElement) []byte {
143         var b []byte
144         for {
145                 tk, err := sc.d.Token()
146                 if err != nil {
147                         panic(err)
148                 }
149                 switch v := tk.(type) {
150                 case xml.CharData:
151                         if b != nil {
152                                 panic("unexpected CharData")
153                         }
154                         b = []byte(string(v))
155                 case xml.EndElement:
156                         if v.Name.Local != "xref" {
157                                 panic("expected </xref>")
158                         }
159                         if b != nil {
160                                 return b
161                         }
162                         sig := attrSig(se)
163                         switch sig {
164                         case "target":
165                                 return []byte(fmt.Sprintf("[%s]", attrValue(se, "target")))
166                         case "fmt-of,rel,target", "fmt-,,rel,target":
167                                 return []byte(fmt.Sprintf("[%s, %s]", attrValue(se, "target"), attrValue(se, "rel")))
168                         case "fmt-of,sec,target", "fmt-,,sec,target":
169                                 return []byte(fmt.Sprintf("[section %s of %s]", attrValue(se, "sec"), attrValue(se, "target")))
170                         case "fmt-of,rel,sec,target":
171                                 return []byte(fmt.Sprintf("[section %s of %s, %s]", attrValue(se, "sec"), attrValue(se, "target"), attrValue(se, "rel")))
172                         default:
173                                 panic(fmt.Sprintf("unknown attribute signature %q in %#v", sig, fmt.Sprintf("%#v", se)))
174                         }
175                 default:
176                         panic(fmt.Sprintf("unexpected tag %q", v))
177                 }
178         }
179 }
180
181 var skipAnchor = map[string]bool{
182         "intro":    true,
183         "Overview": true,
184 }
185
186 var skipTitle = map[string]bool{
187         "Acknowledgements":            true,
188         "Change Log":                  true,
189         "Document Organization":       true,
190         "Conventions and Terminology": true,
191 }
192
193 func skipElement(s xml.StartElement) bool {
194         switch s.Name.Local {
195         case "artwork":
196                 return true
197         case "section":
198                 for _, attr := range s.Attr {
199                         switch attr.Name.Local {
200                         case "anchor":
201                                 if skipAnchor[attr.Value] || strings.HasPrefix(attr.Value, "changes.since.") {
202                                         return true
203                                 }
204                         case "title":
205                                 if skipTitle[attr.Value] {
206                                         return true
207                                 }
208                         }
209                 }
210         }
211         return false
212 }
213
214 func readSpecCov(r io.Reader) specCoverage {
215         sc := specCoverage{
216                 coverage: map[specPart]bool{},
217                 d:        xml.NewDecoder(r)}
218         sc.readSection(nil)
219         return sc
220 }
221
222 func (sc specCoverage) addSentences(sec string, sentence string) {
223         for _, s := range parseSentences(sentence) {
224                 sc.coverage[specPart{sec, s}] = false
225         }
226 }
227
228 func (sc specCoverage) cover(sec string, sentence string) {
229         for _, s := range parseSentences(sentence) {
230                 p := specPart{sec, s}
231                 if _, ok := sc.coverage[p]; !ok {
232                         panic(fmt.Sprintf("Not found in spec: %q, %q", sec, s))
233                 }
234                 sc.coverage[specPart{sec, s}] = true
235         }
236
237 }
238
239 var whitespaceRx = regexp.MustCompile(`\s+`)
240
241 func parseSentences(sens string) []string {
242         sens = strings.TrimSpace(sens)
243         if sens == "" {
244                 return nil
245         }
246         ss := strings.Split(whitespaceRx.ReplaceAllString(sens, " "), ". ")
247         for i, s := range ss {
248                 s = strings.TrimSpace(s)
249                 if !strings.HasSuffix(s, ".") {
250                         s += "."
251                 }
252                 ss[i] = s
253         }
254         return ss
255 }
256
257 func TestSpecParseSentences(t *testing.T) {
258         tests := []struct {
259                 ss   string
260                 want []string
261         }{
262                 {"Sentence 1. Sentence 2.",
263                         []string{
264                                 "Sentence 1.",
265                                 "Sentence 2.",
266                         }},
267                 {"Sentence 1.  \nSentence 2.\tSentence 3.",
268                         []string{
269                                 "Sentence 1.",
270                                 "Sentence 2.",
271                                 "Sentence 3.",
272                         }},
273         }
274
275         for i, tt := range tests {
276                 got := parseSentences(tt.ss)
277                 if !reflect.DeepEqual(got, tt.want) {
278                         t.Errorf("%d: got = %q, want %q", i, got, tt.want)
279                 }
280         }
281 }
282
283 func TestSpecCoverage(t *testing.T) {
284         if !*coverSpec {
285                 t.Skip()
286         }
287
288         loadSpecOnce.Do(loadSpec)
289
290         var (
291                 list     []specPart
292                 cv       = defaultSpecCoverage.coverage
293                 total    = len(cv)
294                 complete = 0
295         )
296
297         for sp, touched := range defaultSpecCoverage.coverage {
298                 if touched {
299                         complete++
300                 } else {
301                         list = append(list, sp)
302                 }
303         }
304         sort.Stable(bySpecSection(list))
305
306         if testing.Short() && len(list) > 5 {
307                 list = list[:5]
308         }
309
310         for _, p := range list {
311                 t.Errorf("\tSECTION %s: %s", p.section, p.sentence)
312         }
313
314         t.Logf("%d/%d (%d%%) sentences covered", complete, total, (complete/total)*100)
315 }
316
317 func attrSig(se xml.StartElement) string {
318         var names []string
319         for _, attr := range se.Attr {
320                 if attr.Name.Local == "fmt" {
321                         names = append(names, "fmt-"+attr.Value)
322                 } else {
323                         names = append(names, attr.Name.Local)
324                 }
325         }
326         sort.Strings(names)
327         return strings.Join(names, ",")
328 }
329
330 func attrValue(se xml.StartElement, attr string) string {
331         for _, a := range se.Attr {
332                 if a.Name.Local == attr {
333                         return a.Value
334                 }
335         }
336         panic("unknown attribute " + attr)
337 }
338
339 func TestSpecPartLess(t *testing.T) {
340         tests := []struct {
341                 sec1, sec2 string
342                 want       bool
343         }{
344                 {"6.2.1", "6.2", false},
345                 {"6.2", "6.2.1", true},
346                 {"6.10", "6.10.1", true},
347                 {"6.10", "6.1.1", false}, // 10, not 1
348                 {"6.1", "6.1", false},    // equal, so not less
349         }
350         for _, tt := range tests {
351                 got := (specPart{tt.sec1, "foo"}).Less(specPart{tt.sec2, "foo"})
352                 if got != tt.want {
353                         t.Errorf("Less(%q, %q) = %v; want %v", tt.sec1, tt.sec2, got, tt.want)
354                 }
355         }
356 }