-
Notifications
You must be signed in to change notification settings - Fork 105
Expand file tree
/
Copy pathnormalizer_fuzz_test.go
More file actions
87 lines (77 loc) · 4.08 KB
/
Copy pathnormalizer_fuzz_test.go
File metadata and controls
87 lines (77 loc) · 4.08 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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package spec
import (
"testing"
"github.com/go-openapi/testify/v2/require"
)
// FuzzNormalizer explores the $ref normalizer with arbitrary ($ref, base) pairs.
//
// The normalizer is the only place in this package where MustCreateRef is handed a URI
// that we built rather than one the caller wrote: a $ref that survives url.Parse but not
// the round-trip through url.URL.String() would panic while merely reading a document.
//
// Beyond that, the properties asserted here are the invariants the expander relies on:
// normalizing yields a canonical URI, normalizing twice changes nothing, and
// denormalizing a canonical $ref yields a shorthand that normalizes back to it.
//
// The last property used to skip a URI that jsonreference spells otherwise than the normalizer
// did. Both now canonicalize the same way - see TestNormalizer_Canonicalization - so it holds
// for every input.
func FuzzNormalizer(f *testing.F) {
for _, seed := range normalizerSeeds() {
f.Add(seed.refPath, seed.base)
}
f.Fuzz(func(t *testing.T, refPath, base string) {
canonicalBase := normalizeBase(base)
requireCanonicalURI(t, canonicalBase)
require.EqualTf(t, canonicalBase, normalizeBase(canonicalBase),
"normalizeBase is not idempotent on base %q", base)
normalized := normalizeURI(refPath, canonicalBase)
requireCanonicalURI(t, normalized)
require.EqualTf(t, normalized, normalizeURI(normalized, canonicalBase),
"normalizeURI is not idempotent on $ref %q against base %q", refPath, canonicalBase)
ref := MustCreateRef(normalized)
denormalized := denormalizeRef(&ref, canonicalBase, "")
require.EqualTf(t, normalized, normalizeURI(denormalized.String(), canonicalBase),
"denormalizing %q against base %q yielded %q, which does not normalize back",
normalized, canonicalBase, denormalized.String())
})
}
// requireCanonicalURI asserts the postcondition shared by normalizeBase and normalizeURI:
// whatever comes out is a parseable, absolute URI, safe to use as a document cache key.
func requireCanonicalURI(t *testing.T, in string) {
t.Helper()
u, err := parseURL(in)
require.NoErrorf(t, err, "the normalizer produced an unparseable URI: %q", in)
require.NotEmptyf(t, u.Scheme, "the normalizer produced a URI with no scheme: %q", in)
}
// normalizerSeeds are the ($ref, base) pairs the fuzzer starts from.
//
// They cover the shapes the normalizer branches on: empty and fragment-only $refs,
// relative and absolute paths, the file and http schemes, query components, percent-escaping,
// the windows spellings (drive letters and UNC shares) and URIs that only repairURI can salvage.
func normalizerSeeds() []struct{ refPath, base string } {
return []struct{ refPath, base string }{
{"", ""},
{"", "/base/path.json"},
{"#", "file:///base/path.json"},
{"#/definitions/Pet", "http://www.example.com/base/path/swagger.json"},
{"#/dir/definitions/Pet", "https://www.example.com:8443/base/path.json?raw=true"},
{"another/base/path.json#/definitions/Pet", "/base/path.json"},
{"./another/base/path.json#/definitions/Pet", "file:///base/path.json"},
{"../other/another.json#/definitions/X", "file:///base/path.json"},
{"/another///base//path.json/", "/base/path.json"},
{"http://www.anotherexample.com/swagger.json#/definitions/Pet", "http://www.example.com/base/path/swagger.json"},
{"https://origin.com/another/file.json?raw=true", "https://www.example.com:8443/base/path.json?raw=true"},
{"Resources [x86].yaml#/definitions/Pets", "https://example.com/base (x86)/Spec.json"},
{"Resources.yaml#/definitions (x86)/Pets", "https://example.com/base/Spec.json"},
{"\x7f\x9a", "file:///base/path.json"},
{"gs://bucket/folder/file.json", "smb://host"},
{`C:\another\Base\path.json#/definitions/Pet`, `file:///c:/base/path.json`},
{`another\base\path.json#/definitions/Pet`, `file:///c:/base/path.json`},
{`\\host\share\another\base\path.json#/definitions/Pet`, `\\host\share@1234\Folder\File.json`},
{`file://E:\Base\sub\File.json`, `file:///.\Base\sub\File.json`},
{`file:/..`, `file:///.`},
}
}