github.com/icyphox/x@v0.0.355-0.20220311094250-029bd783e8b8/jsonschemax/keys_test.go (about) 1 package jsonschemax 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "testing" 10 11 "github.com/ory/x/snapshotx" 12 13 "github.com/pkg/errors" 14 15 "github.com/stretchr/testify/require" 16 17 "github.com/ory/jsonschema/v3" 18 ) 19 20 const recursiveSchema = `{ 21 "$schema": "http://json-schema.org/draft-07/schema#", 22 "$id": "test.json", 23 "definitions": { 24 "foo": { 25 "type": "object", 26 "properties": { 27 "bars": { 28 "type": "string", 29 "format": "email", 30 "pattern": ".*" 31 }, 32 "bar": { 33 "$ref": "#/definitions/bar" 34 } 35 }, 36 "required":["bars"] 37 }, 38 "bar": { 39 "type": "object", 40 "properties": { 41 "foos": { 42 "type": "string", 43 "minLength": 1, 44 "maxLength": 10 45 }, 46 "foo": { 47 "$ref": "#/definitions/foo" 48 } 49 } 50 } 51 }, 52 "type": "object", 53 "properties": { 54 "bar": { 55 "$ref": "#/definitions/bar" 56 } 57 } 58 }` 59 60 func readFile(t *testing.T, path string) string { 61 schema, err := ioutil.ReadFile(path) 62 require.NoError(t, err) 63 return string(schema) 64 } 65 66 const fooExtensionName = "fooExtension" 67 68 type ( 69 extensionConfig struct { 70 NotAJSONSchemaKey string `json:"not-a-json-schema-key"` 71 } 72 ) 73 74 func fooExtensionCompile(_ jsonschema.CompilerContext, m map[string]interface{}) (interface{}, error) { 75 if raw, ok := m[fooExtensionName]; ok { 76 var b bytes.Buffer 77 if err := json.NewEncoder(&b).Encode(raw); err != nil { 78 return nil, errors.WithStack(err) 79 } 80 81 var e extensionConfig 82 if err := json.NewDecoder(&b).Decode(&e); err != nil { 83 return nil, errors.WithStack(err) 84 } 85 86 return &e, nil 87 } 88 return nil, nil 89 } 90 91 func fooExtensionValidate(_ jsonschema.ValidationContext, _, _ interface{}) error { 92 return nil 93 } 94 95 func (ec *extensionConfig) EnhancePath(p Path) map[string]interface{} { 96 if ec.NotAJSONSchemaKey != "" { 97 fmt.Printf("enhancing path: %s with custom property %s\n", p.Name, ec.NotAJSONSchemaKey) 98 return map[string]interface{}{ 99 ec.NotAJSONSchemaKey: p.Name, 100 } 101 } 102 return nil 103 } 104 105 func TestListPathsWithRecursion(t *testing.T) { 106 for k, tc := range []struct { 107 recursion uint8 108 expected interface{} 109 }{ 110 { 111 recursion: 5, 112 }, 113 } { 114 t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { 115 c := jsonschema.NewCompiler() 116 require.NoError(t, c.AddResource("test.json", bytes.NewBufferString(recursiveSchema))) 117 actual, err := ListPathsWithRecursion(context.Background(), "test.json", c, tc.recursion) 118 require.NoError(t, err) 119 120 snapshotx.SnapshotTExcept(t, actual, nil) 121 }) 122 } 123 } 124 125 func TestListPaths(t *testing.T) { 126 for k, tc := range []struct { 127 schema string 128 expectErr bool 129 extension *jsonschema.Extension 130 }{ 131 { 132 schema: readFile(t, "./stub/.oathkeeper.schema.json"), 133 }, 134 { 135 schema: readFile(t, "./stub/nested-simple-array.schema.json"), 136 }, 137 { 138 schema: readFile(t, "./stub/config.schema.json"), 139 }, 140 { 141 schema: readFile(t, "./stub/nested-array.schema.json"), 142 }, 143 { 144 // this should fail because of recursion 145 schema: recursiveSchema, 146 expectErr: true, 147 }, 148 { 149 schema: `{ 150 "$schema": "http://json-schema.org/draft-07/schema#", 151 "$id": "test.json", 152 "oneOf": [ 153 { 154 "type": "object", 155 "properties": { 156 "list": { 157 "type": "array", 158 "items": { 159 "type": "string" 160 } 161 }, 162 "foo": { 163 "default": false, 164 "type": "boolean" 165 }, 166 "bar": { 167 "type": "boolean", 168 "default": "asdf", 169 "readOnly": true 170 } 171 } 172 }, 173 { 174 "type": "object", 175 "properties": { 176 "foo": { 177 "type": "boolean" 178 } 179 } 180 } 181 ] 182 }`, 183 }, 184 { 185 schema: `{ 186 "$schema": "http://json-schema.org/draft-07/schema#", 187 "$id": "test.json", 188 "type": "object", 189 "required": ["foo"], 190 "properties": { 191 "foo": { 192 "type": "boolean" 193 }, 194 "bar": { 195 "type": "string", 196 "fooExtension": { 197 "not-a-json-schema-key": "foobar" 198 } 199 } 200 } 201 }`, 202 extension: &jsonschema.Extension{ 203 Meta: nil, 204 Compile: fooExtensionCompile, 205 Validate: fooExtensionValidate, 206 }, 207 }, 208 { 209 schema: `{ 210 "$schema": "http://json-schema.org/draft-07/schema#", 211 "$id": "test.json", 212 "type": "object", 213 "definitions": { 214 "foo": { 215 "type": "string" 216 } 217 }, 218 "properties": { 219 "bar": { 220 "type": "array", 221 "items": { 222 "$ref": "#/definitions/foo" 223 } 224 } 225 } 226 }`, 227 }, 228 { 229 schema: `{ 230 "$schema": "http://json-schema.org/draft-07/schema#", 231 "$id": "test.json", 232 "type": "object", 233 "definitions": { 234 "foo": { 235 "type": "string" 236 }, 237 "bar": { 238 "type": "array", 239 "items": { 240 "$ref": "#/definitions/foo" 241 }, 242 "required": ["foo"] 243 } 244 }, 245 "properties": { 246 "baz": { 247 "type": "array", 248 "items": { 249 "$ref": "#/definitions/bar" 250 } 251 } 252 } 253 }`, 254 }, 255 { 256 schema: `{ 257 "$schema": "http://json-schema.org/draft-07/schema#", 258 "$id": "test.json", 259 "type": "object", 260 "definitions": { 261 "foo": { 262 "type": "string" 263 }, 264 "bar": { 265 "type": "object", 266 "properties": { 267 "foo": { 268 "$ref": "#/definitions/foo" 269 } 270 }, 271 "required": ["foo"] 272 } 273 }, 274 "properties": { 275 "baz": { 276 "type": "array", 277 "items": { 278 "$ref": "#/definitions/bar" 279 } 280 } 281 } 282 }`, 283 }, 284 } { 285 t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { 286 c := jsonschema.NewCompiler() 287 if tc.extension != nil { 288 c.Extensions[fooExtensionName] = *tc.extension 289 } 290 291 require.NoError(t, c.AddResource("test.json", bytes.NewBufferString(tc.schema))) 292 actual, err := ListPathsWithArraysIncluded(context.Background(), "test.json", c) 293 if tc.expectErr { 294 require.Error(t, err, "%+v", actual) 295 return 296 } 297 require.NoError(t, err) 298 299 snapshotx.SnapshotTExcept(t, actual, nil) 300 }) 301 } 302 }