1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package validate
16
17 import (
18 "encoding/json"
19 "net/http"
20 "os"
21 "path/filepath"
22 "strings"
23 "testing"
24 "time"
25
26 "github.com/go-openapi/spec"
27 "github.com/go-openapi/strfmt"
28 "github.com/go-openapi/swag"
29 "github.com/stretchr/testify/assert"
30 "github.com/stretchr/testify/require"
31 )
32
33
34 type schemaTestT struct {
35 Description string `json:"description"`
36 Schema *spec.Schema `json:"schema"`
37 Tests []struct {
38 Description string `json:"description"`
39 Data interface{} `json:"data"`
40 Valid bool `json:"valid"`
41 }
42 }
43
44 var jsonSchemaFixturesPath = filepath.Join("fixtures", "jsonschema_suite")
45 var schemaFixturesPath = filepath.Join("fixtures", "schemas")
46 var formatFixturesPath = filepath.Join("fixtures", "formats")
47
48 func enabled() []string {
49
50 return []string{
51 "minLength",
52 "maxLength",
53 "pattern",
54 "type",
55 "minimum",
56 "maximum",
57 "multipleOf",
58 "enum",
59 "default",
60 "dependencies",
61 "items",
62 "maxItems",
63 "maxProperties",
64 "minItems",
65 "minProperties",
66 "patternProperties",
67 "required",
68 "additionalItems",
69 "uniqueItems",
70 "properties",
71 "additionalProperties",
72 "allOf",
73 "not",
74 "oneOf",
75 "anyOf",
76 "ref",
77 "definitions",
78 "refRemote",
79 "format",
80 }
81 }
82
83 var optionalFixtures = []string{
84
85
86
87
88
89 }
90
91 var extendedFixtures = []string{
92 "extended-format",
93 }
94
95 func isEnabled(nm string) bool {
96 return swag.ContainsStringsCI(enabled(), nm)
97 }
98
99 func isOptionalEnabled(nm string) bool {
100 return swag.ContainsStringsCI(optionalFixtures, nm)
101 }
102
103 func isExtendedEnabled(nm string) bool {
104 return swag.ContainsStringsCI(extendedFixtures, nm)
105 }
106
107 func TestJSONSchemaSuite(t *testing.T) {
108
109 go func() {
110 svr := &http.Server{
111 ReadTimeout: 5 * time.Second,
112 WriteTimeout: 10 * time.Second,
113 Addr: "localhost:1234",
114 Handler: http.FileServer(http.Dir(jsonSchemaFixturesPath + "/remotes")),
115 }
116 err := svr.ListenAndServe()
117 if err != nil {
118 panic(err.Error())
119 }
120 }()
121
122 files, err := os.ReadDir(jsonSchemaFixturesPath)
123 if err != nil {
124 t.Fatal(err)
125 }
126
127 for _, f := range files {
128 if f.IsDir() {
129 continue
130 }
131 fileName := f.Name()
132 t.Run(fileName, func(t *testing.T) {
133 t.Parallel()
134 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
135 if !isEnabled(specName) {
136 t.Logf("WARNING: fixture from jsonschema-test-suite not enabled: %s", specName)
137 return
138 }
139 t.Log("Running " + specName)
140 b, _ := os.ReadFile(filepath.Join(jsonSchemaFixturesPath, fileName))
141 doTestSchemaSuite(t, b)
142 })
143 }
144 }
145
146 func TestSchemaFixtures(t *testing.T) {
147 files, err := os.ReadDir(schemaFixturesPath)
148 if err != nil {
149 t.Fatal(err)
150 }
151
152 for _, f := range files {
153 if f.IsDir() {
154 continue
155 }
156 fileName := f.Name()
157 t.Run(fileName, func(t *testing.T) {
158 t.Parallel()
159 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
160 t.Log("Running " + specName)
161 b, _ := os.ReadFile(filepath.Join(schemaFixturesPath, fileName))
162 doTestSchemaSuite(t, b)
163 })
164 }
165 }
166
167 func expandOpts(base string) *spec.ExpandOptions {
168 return &spec.ExpandOptions{
169 RelativeBase: base,
170 SkipSchemas: false,
171 ContinueOnError: false,
172 }
173 }
174
175 func TestOptionalJSONSchemaSuite(t *testing.T) {
176 jsonOptionalSchemaFixturesPath := filepath.Join(jsonSchemaFixturesPath, "optional")
177 files, err := os.ReadDir(jsonOptionalSchemaFixturesPath)
178 if err != nil {
179 t.Fatal(err)
180 }
181
182 for _, f := range files {
183 if f.IsDir() {
184 continue
185 }
186 fileName := f.Name()
187 t.Run(fileName, func(t *testing.T) {
188 t.Parallel()
189 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
190 if !isOptionalEnabled(specName) {
191 t.Logf("INFO: fixture from jsonschema-test-suite [optional] not enabled: %s", specName)
192 return
193 }
194 t.Log("Running [optional] " + specName)
195 b, _ := os.ReadFile(filepath.Join(jsonOptionalSchemaFixturesPath, fileName))
196 doTestSchemaSuite(t, b)
197 })
198 }
199 }
200
201
202 func TestFormat_JSONSchemaExtended(t *testing.T) {
203 files, err := os.ReadDir(formatFixturesPath)
204 if err != nil {
205 t.Fatal(err)
206 }
207
208 for _, f := range files {
209 if f.IsDir() {
210 continue
211 }
212 fileName := f.Name()
213 t.Run(fileName, func(t *testing.T) {
214 t.Parallel()
215 specName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
216 if !isExtendedEnabled(specName) {
217 t.Logf("INFO: fixture from extended tests suite [formats] not enabled: %s", specName)
218 return
219 }
220 t.Log("Running [extended formats] " + specName)
221 b, _ := os.ReadFile(filepath.Join(formatFixturesPath, fileName))
222 doTestSchemaSuite(t, b)
223 })
224 }
225 }
226
227 func doTestSchemaSuite(t *testing.T, doc []byte) {
228
229 var testDescriptions []schemaTestT
230 eru := json.Unmarshal(doc, &testDescriptions)
231 require.NoError(t, eru)
232
233 for _, testDescription := range testDescriptions {
234 b, _ := testDescription.Schema.MarshalJSON()
235 tmpFile, err := os.CreateTemp(os.TempDir(), "validate-test")
236 require.NoError(t, err)
237 _, _ = tmpFile.Write(b)
238 tmpFile.Close()
239 defer func() { _ = os.Remove(tmpFile.Name()) }()
240 err = spec.ExpandSchemaWithBasePath(testDescription.Schema, nil, expandOpts(tmpFile.Name()))
241 require.NoError(t, err, testDescription.Description+" should expand cleanly")
242
243 validator := NewSchemaValidator(testDescription.Schema, nil, "data", strfmt.Default)
244 for _, test := range testDescription.Tests {
245 result := validator.Validate(test.Data)
246 assert.NotNil(t, result, test.Description+" should validate")
247
248 if test.Valid {
249 assert.Empty(t, result.Errors, test.Description+" should not have errors")
250 } else {
251 assert.NotEmpty(t, result.Errors, test.Description+" should have errors")
252 }
253 }
254 }
255 }
256
View as plain text