Repository navigation
Expand file tree
/
Copy pathswagger_fuzz_test.go
More file actions
69 lines (60 loc) · 3.23 KB
/
Copy pathswagger_fuzz_test.go
File metadata and controls
69 lines (60 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package spec
import (
"encoding/json"
"testing"
"github.com/go-openapi/testify/v2/require"
)
// FuzzSwaggerRoundTrip feeds arbitrary JSON documents to the spec model.
//
// A document is the first thing this package sees of an untrusted input, and it lands on some
// two dozen hand-written UnmarshalJSON methods - several of them for union types that switch on
// the shape of the value rather than on a discriminator. This target covers them all at once.
//
// The property is that a document we accepted can be written back and read again unchanged:
// marshalling after unmarshalling is where a union type that guessed wrong shows up.
func FuzzSwaggerRoundTrip(f *testing.F) {
for _, seed := range swaggerSeeds() {
f.Add([]byte(seed))
}
f.Fuzz(func(t *testing.T, data []byte) {
var doc Swagger
if err := json.Unmarshal(data, &doc); err != nil {
return // not a document we claim to accept
}
once, err := json.Marshal(doc)
require.NoErrorf(t, err, "an accepted document did not marshal back: %s", data)
var reread Swagger
require.NoErrorf(t, json.Unmarshal(once, &reread),
"a marshalled document no longer parses: %s", once)
twice, err := json.Marshal(reread)
require.NoErrorf(t, err, "a re-read document did not marshal back: %s", once)
require.EqualTf(t, string(once), string(twice),
"reading a document back changed it, from %s", data)
})
}
// swaggerSeeds are the documents the fuzzer starts from.
//
// They aim at the union types rather than at coverage of the specification: the members that
// accept either an object or a boolean, either one value or an array, either a $ref or a body.
func swaggerSeeds() []string {
return []string{
`{"swagger":"2.0","info":{"title":"t","version":"1"},"paths":{}}`,
`{"paths":{"/x":{"get":{"responses":{"200":{"description":"ok","schema":{"$ref":"#/definitions/A"}}}}}},` +
`"definitions":{"A":{"type":"object","properties":{"a":{"type":"string"}}}}}`,
`{"paths":{"/x":{"$ref":"a.json#/paths/~1y"},"/y":{"parameters":[{"$ref":"#/parameters/p"}]}}}`,
`{"definitions":{"A":{"additionalProperties":true,"items":[{"type":"string"}],"enum":[1,"a",null,{}]}}}`,
`{"definitions":{"A":{"additionalProperties":{"type":"string"},"items":{"type":"integer"},` +
`"type":["string","null"],"required":["a"]}}}`,
`{"definitions":{"A":{"allOf":[{"$ref":"#/definitions/B"}],"not":{"type":"null"},"x-go-name":"A"}}}`,
`{"parameters":{"p":{"name":"p","in":"query","type":"array","items":{"type":"string"},"collectionFormat":"csv"}}}`,
`{"responses":{"r":{"description":"d","headers":{"h":{"type":"array","items":{"type":"number"}}},` +
`"examples":{"application/json":{"a":1}}}}}`,
`{"securityDefinitions":{"k":{"type":"apiKey","name":"n","in":"header"},` +
`"o":{"type":"oauth2","flow":"implicit","authorizationUrl":"https://x/a","scopes":{"s":"d"}}}}`,
`{"security":[{"k":[]},{"o":["s"]}],"tags":[{"name":"t","externalDocs":{"url":"https://x"}}],"x-ext":{"a":[1,2]}}`,
`{"definitions":{"A":{"xml":{"name":"a","attribute":true,"wrapped":false},"default":null,"example":[]}}}`,
`{"$schema":"http://json-schema.org/draft-04/schema#","id":"https://example.com/schema","definitions":{}}`,
}
}