From a1fb9ef6509775cf44f789f2cf54b6540a3099a9 Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Tue, 23 Jun 2026 19:48:38 -0400 Subject: [PATCH] jspg checkpoint --- GEMINI.md | 27 +- fixtures/additionalProperties.json | 246 -------- fixtures/dependencies.json | 14 +- fixtures/dict.json | 284 +++++++++ fixtures/items.json | 923 ---------------------------- fixtures/maxItems.json | 9 +- fixtures/minItems.json | 6 +- fixtures/patternProperties.json | 580 ----------------- fixtures/prefixItems.json | 324 ---------- fixtures/uniqueItems.json | 756 ----------------------- src/database/compile/collection.rs | 22 +- src/database/compile/mod.rs | 40 +- src/database/compose/mod.rs | 78 +-- src/database/object.rs | 15 +- src/database/schema.rs | 8 +- src/tests/fixtures.rs | 782 ++++------------------- src/validator/mod.rs | 1 + src/validator/rules/array.rs | 34 +- src/validator/rules/dict.rs | 76 +++ src/validator/rules/extensible.rs | 87 ++- src/validator/rules/mod.rs | 2 + src/validator/rules/object.rs | 72 --- src/validator/rules/polymorphism.rs | 1 - src/validator/rules/string.rs | 2 + 24 files changed, 588 insertions(+), 3801 deletions(-) delete mode 100644 fixtures/additionalProperties.json create mode 100644 fixtures/dict.json delete mode 100644 fixtures/patternProperties.json delete mode 100644 fixtures/prefixItems.json create mode 100644 src/validator/rules/dict.rs diff --git a/GEMINI.md b/GEMINI.md index ae3961a..caf78a7 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -47,7 +47,22 @@ The core execution engines natively enforce these boundaries: * **Merger**: Strictly bounded to the `Type` Realm. It is philosophically impossible and mathematically illegal to attempt to UPSERT an API endpoint. * **Queryer**: Routes recursively. Safely evaluates API boundary inputs directly from the `Punc` realm, while tracing underlying table targets back through the `Type` realm to physically compile SQL `SELECT` statements. -### Types of Types +### Basic and Structural Types +JSPG models data using a simplified subset of standard JSON Schema types, categorized into primitives and structural types: + +* **Primitives**: + * `string`: Standard string, supporting standard keywords (e.g., `pattern`, `minLength`, `maxLength`) and custom formats (`uuid`, `date-time`, `email`). Empty strings (`""`) are leniently treated as "present but unset". + * `number` & `integer`: Numeric and integer values (e.g., supporting `minimum`, `maximum`). + * `boolean`: Boolean `true` or `false` values. + * `null`: Represents database `NULL` or unset fields. +* **Structural Types**: + * `object`: Represents a structured object with a fixed list of static `properties`. Objects are **strict by default** (raising `STRICT_PROPERTY_VIOLATION` for properties not defined in the schema) unless marked with `"extensible": true`. + * `array`: A homogeneous, one-dimensional collection where every element is validated against the `items` schema. Positional/tuple array validation is not supported, and array strictness checks do not apply. + * `dict`: A dynamic key-value map. It utilizes the `keys` keyword to validate key strings (typically via `pattern`) and the `items` keyword to validate the values. It completely replaces the legacy `additionalProperties` and `patternProperties` keywords. Extensibility is implicitly managed via dynamic keys, so strictness checking does not apply. + +### Types of Types (Complex & Referential Types) +Beyond basic primitives and structures, JSPG maps schemas to their storage and database-referential boundaries: + * **Table-Backed (Entity Types)**: Primarily defined in root `types` schemas. These represent physical Postgres tables. * They are implicitly registered in the Global Registry using their precise key name mapped from the database compilation phase. * The schema conceptually requires a `type` discriminator at runtime so the engine knows what physical variation to interact with. @@ -162,9 +177,11 @@ It evaluates as an **Independent Declarative Rules Engine**. Every `Case` block ``` ### Strict by Default & Extensibility -* **Strictness**: By default, any property not explicitly defined in the schema causes a validation error (effectively enforcing `additionalProperties: false` globally). -* **Extensibility (`extensible: true`)**: To allow a free-for-all of undefined properties, schemas must explicitly declare `"extensible": true`. -* **Structured Additional Properties**: If `additionalProperties: {...}` is defined as a schema, arbitrary keys are allowed so long as their values match the defined type constraint. +* **Strictness**: Strictness is a first-class feature for object schemas. By default, any property present in the JSON instance that is not explicitly defined in the schema's `properties` (or inherited, etc.) causes a `STRICT_PROPERTY_VIOLATION` validation error. +* **Extensibility (`extensible: true`)**: This keyword is valid **only** at the `type: "object"` level. By setting `"extensible": true`, you bypass the strictness checking on the object, allowing arbitrary undefined properties to pass. +* **Type: dict and type: array**: These types are dynamic/homogeneous: + * **`dict`**: Defined with `keys` and `items` schemas. Its keys and values are dynamic, so strictness checking does not apply. `"extensible"` is not applicable at the `dict` level. + * **`array`**: Homogeneous collection of items matching the `items` schema. Validation is homogeneous, so strictness checking does not apply. `"extensible"` is not applicable at the `array` level (tuple-like `prefixItems` are removed). * **Inheritance Boundaries**: Strictness resets when crossing non-primitive `type` boundaries. A schema extending a strict parent remains strict unless it explicitly overrides with `"extensible": true`. ### Format Leniency for Empty Strings @@ -206,7 +223,7 @@ Traits are reusable, non-generating schema fragments used to share properties an } ``` * **Resolution and Merging**: During `Database::new()`, includes are resolved and merged at the raw JSON level: - * **`properties` / `patternProperties`**: Map keys from the host schema override/shadow included traits. + * **`properties`**: Map keys from the host schema override/shadow included traits. * **`required` / `display`**: Lists are merged and deduped. * **`dependencies`**: Merged by combining and deduping lists. * **Scalars / Arrays / Items**: Host definitions completely override included traits. diff --git a/fixtures/additionalProperties.json b/fixtures/additionalProperties.json deleted file mode 100644 index a24cbc1..0000000 --- a/fixtures/additionalProperties.json +++ /dev/null @@ -1,246 +0,0 @@ -[ - { - "description": "additionalProperties validates properties not matched by properties", - "database": { - "types": [ - { - "name": "schema1", - "schemas": { - "schema1": { - "properties": { - "foo": { - "type": "string" - }, - "bar": { - "type": "number" - } - }, - "additionalProperties": { - "type": "boolean" - } - } - } - } - ] - }, - "tests": [ - { - "description": "defined properties are valid", - "data": { - "foo": "value", - "bar": 123 - }, - "schema_id": "schema1", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "additional property matching schema is valid", - "data": { - "foo": "value", - "is_active": true, - "hidden": false - }, - "schema_id": "schema1", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "additional property not matching schema is invalid", - "data": { - "foo": "value", - "is_active": 1 - }, - "schema_id": "schema1", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "boolean" - }, - "details": { - "path": "is_active", - "schema": "schema1" - } - } - ] - } - } - ] - }, - { - "description": "extensible: true with additionalProperties still validates structure", - "database": { - "types": [ - { - "name": "additionalProperties_1_0", - "schemas": { - "additionalProperties_1_0": { - "properties": { - "foo": { - "type": "string" - } - }, - "extensible": true, - "additionalProperties": { - "type": "integer" - } - } - } - } - ] - }, - "tests": [ - { - "description": "additional property matching schema is valid", - "data": { - "foo": "hello", - "count": 5, - "age": 42 - }, - "schema_id": "additionalProperties_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "additional property not matching schema is invalid despite extensible: true", - "data": { - "foo": "hello", - "count": "five" - }, - "schema_id": "additionalProperties_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "count", - "schema": "additionalProperties_1_0" - } - } - ] - } - } - ] - }, - { - "description": "complex additionalProperties with object and array items", - "database": { - "types": [ - { - "name": "schema3", - "schemas": { - "schema3": { - "properties": { - "type": { - "type": "string" - } - }, - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - ] - }, - "tests": [ - { - "description": "valid array of strings", - "data": { - "type": "my_type", - "group_a": [ - "field1", - "field2" - ], - "group_b": [ - "field3" - ] - }, - "schema_id": "schema3", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "invalid array of integers", - "data": { - "type": "my_type", - "group_a": [ - 1, - 2 - ] - }, - "schema_id": "schema3", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "string" - }, - "details": { - "path": "group_a/0", - "schema": "schema3" - } - }, - { - "code": "INVALID_TYPE", - "values": { - "expected": "string" - }, - "details": { - "path": "group_a/1", - "schema": "schema3" - } - } - ] - } - }, - { - "description": "invalid non-array type", - "data": { - "type": "my_type", - "group_a": "field1" - }, - "schema_id": "schema3", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "array" - }, - "details": { - "path": "group_a", - "schema": "schema3" - } - } - ] - } - } - ] - } -] \ No newline at end of file diff --git a/fixtures/dependencies.json b/fixtures/dependencies.json index 4eef978..b647169 100644 --- a/fixtures/dependencies.json +++ b/fixtures/dependencies.json @@ -579,19 +579,7 @@ "schema_id": "schema_schema1", "action": "validate", "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_ITEM_VIOLATION", - "values": { - "index": "0" - }, - "details": { - "path": "0", - "schema": "schema_schema1" - } - } - ] + "success": true } }, { diff --git a/fixtures/dict.json b/fixtures/dict.json new file mode 100644 index 0000000..1de127e --- /dev/null +++ b/fixtures/dict.json @@ -0,0 +1,284 @@ +[ + { + "description": "basic dict type validation", + "database": { + "types": [ + { + "name": "dict_basic", + "schemas": { + "dict_basic": { + "type": "dict" + } + } + } + ] + }, + "tests": [ + { + "description": "valid empty dict", + "data": {}, + "schema_id": "dict_basic", + "action": "validate", + "expect": { + "success": true + } + }, + { + "description": "valid simple dict", + "data": { + "key1": "value1", + "key2": 123, + "key3": true + }, + "schema_id": "dict_basic", + "action": "validate", + "expect": { + "success": true + } + }, + { + "description": "invalid type - array is not dict", + "data": [ + "a", + "b" + ], + "schema_id": "dict_basic", + "action": "validate", + "expect": { + "success": false, + "errors": [ + { + "code": "INVALID_TYPE", + "values": { + "expected": "dict" + }, + "details": { + "path": "", + "schema": "dict_basic" + } + } + ] + } + }, + { + "description": "invalid type - string is not dict", + "data": "not a dict", + "schema_id": "dict_basic", + "action": "validate", + "expect": { + "success": false, + "errors": [ + { + "code": "INVALID_TYPE", + "values": { + "expected": "dict" + }, + "details": { + "path": "", + "schema": "dict_basic" + } + } + ] + } + } + ] + }, + { + "description": "dict keys validation", + "database": { + "types": [ + { + "name": "dict_keys", + "schemas": { + "dict_keys": { + "type": "dict", + "keys": { + "type": "string", + "pattern": "^[a-z]{3}$" + } + } + } + } + ] + }, + "tests": [ + { + "description": "valid 3-letter lowercase keys", + "data": { + "abc": 1, + "xyz": "test" + }, + "schema_id": "dict_keys", + "action": "validate", + "expect": { + "success": true + } + }, + { + "description": "invalid key format", + "data": { + "abc": 1, + "abcd": 2 + }, + "schema_id": "dict_keys", + "action": "validate", + "expect": { + "success": false, + "errors": [ + { + "code": "PATTERN_VIOLATED", + "values": { + "value": "abcd", + "pattern": "^[a-z]{3}$" + }, + "details": { + "path": "keys/abcd", + "schema": "dict_keys" + } + } + ] + } + } + ] + }, + { + "description": "dict items (values) validation", + "database": { + "types": [ + { + "name": "dict_items", + "schemas": { + "dict_items": { + "type": "dict", + "items": { + "type": "integer" + } + } + } + } + ] + }, + "tests": [ + { + "description": "valid integer values", + "data": { + "a": 1, + "b": 100 + }, + "schema_id": "dict_items", + "action": "validate", + "expect": { + "success": true + } + }, + { + "description": "invalid value type", + "data": { + "a": 1, + "b": "string value" + }, + "schema_id": "dict_items", + "action": "validate", + "expect": { + "success": false, + "errors": [ + { + "code": "INVALID_TYPE", + "values": { + "expected": "integer" + }, + "details": { + "path": "b", + "schema": "dict_items" + } + } + ] + } + } + ] + }, + { + "description": "dict keys and items validation combined", + "database": { + "types": [ + { + "name": "dict_combined", + "schemas": { + "dict_combined": { + "type": "dict", + "keys": { + "type": "string", + "pattern": "^[0-9]+$" + }, + "items": { + "type": "boolean" + } + } + } + } + ] + }, + "tests": [ + { + "description": "valid numeric keys and boolean values", + "data": { + "123": true, + "456": false + }, + "schema_id": "dict_combined", + "action": "validate", + "expect": { + "success": true + } + }, + { + "description": "invalid key and valid value", + "data": { + "123": true, + "abc": false + }, + "schema_id": "dict_combined", + "action": "validate", + "expect": { + "success": false, + "errors": [ + { + "code": "PATTERN_VIOLATED", + "values": { + "pattern": "^[0-9]+$", + "value": "abc" + }, + "details": { + "path": "keys/abc", + "schema": "dict_combined" + } + } + ] + } + }, + { + "description": "valid key and invalid value", + "data": { + "123": "not a boolean" + }, + "schema_id": "dict_combined", + "action": "validate", + "expect": { + "success": false, + "errors": [ + { + "code": "INVALID_TYPE", + "values": { + "expected": "boolean" + }, + "details": { + "path": "123", + "schema": "dict_combined" + } + } + ] + } + } + ] + } +] \ No newline at end of file diff --git a/fixtures/items.json b/fixtures/items.json index 33c48fe..32ab0ba 100644 --- a/fixtures/items.json +++ b/fixtures/items.json @@ -213,603 +213,6 @@ } ] }, - { - "description": "items and subitems", - "database": { - "types": [ - { - "name": "items_3_0", - "schemas": { - "items_3_0": { - "type": "array", - "items": false, - "prefixItems": [ - { - "type": "item" - }, - { - "type": "item" - }, - { - "type": "item" - } - ] - } - } - }, - { - "name": "item", - "schemas": { - "item": { - "type": "array", - "items": false, - "prefixItems": [ - { - "type": "sub-item" - }, - { - "type": "sub-item" - } - ] - } - } - }, - { - "name": "sub-item", - "schemas": { - "sub-item": { - "type": "object", - "required": [ - "foo" - ] - } - } - } - ] - }, - "tests": [ - { - "description": "valid items", - "data": [ - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ] - ], - "schema_id": "items_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/1/foo", - "schema": "items_3_0" - } - } - ] - } - }, - { - "description": "too many items", - "data": [ - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ] - ], - "schema_id": "items_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "FALSE_SCHEMA", - "details": { - "path": "3", - "schema": "items_3_0" - } - } - ] - } - }, - { - "description": "too many sub-items", - "data": [ - [ - { - "foo": null - }, - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ] - ], - "schema_id": "items_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "FALSE_SCHEMA", - "details": { - "path": "0/2", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/1/foo", - "schema": "items_3_0" - } - } - ] - } - }, - { - "description": "wrong item", - "data": [ - { - "foo": null - }, - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ] - ], - "schema_id": "items_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "array" - }, - "details": { - "path": "0", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/1/foo", - "schema": "items_3_0" - } - } - ] - } - }, - { - "description": "wrong sub-item", - "data": [ - [ - {}, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ], - [ - { - "foo": null - }, - { - "foo": null - } - ] - ], - "schema_id": "items_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "REQUIRED_FIELD_MISSING", - "values": { - "field_name": "foo" - }, - "details": { - "path": "0/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/1/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "2/1/foo", - "schema": "items_3_0" - } - } - ] - } - }, - { - "description": "fewer items is invalid", - "data": [ - [ - { - "foo": null - } - ], - [ - { - "foo": null - } - ] - ], - "schema_id": "items_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "0/0/foo", - "schema": "items_3_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "foo" - }, - "details": { - "path": "1/0/foo", - "schema": "items_3_0" - } - } - ] - } - } - ] - }, { "description": "nested items", "database": { @@ -1021,282 +424,6 @@ } ] }, - { - "description": "prefixItems with no additional items allowed", - "database": { - "types": [ - { - "name": "items_5_0", - "schemas": { - "items_5_0": { - "prefixItems": [ - {}, - {}, - {} - ], - "items": false - } - } - } - ] - }, - "tests": [ - { - "description": "empty array", - "data": [], - "schema_id": "items_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "fewer number of items present (1)", - "data": [ - 1 - ], - "schema_id": "items_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "fewer number of items present (2)", - "data": [ - 1, - 2 - ], - "schema_id": "items_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "equal number of items present", - "data": [ - 1, - 2, - 3 - ], - "schema_id": "items_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "additional items are not permitted", - "data": [ - 1, - 2, - 3, - 4 - ], - "schema_id": "items_5_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "3", - "schema": "items_5_0" - } - } - ] - } - } - ] - }, - { - "description": "items does not look in applicators, valid case", - "database": { - "types": [ - { - "name": "items_6_0", - "schemas": { - "items_6_0": { - "allOf": [ - { - "prefixItems": [ - { - "minimum": 3 - } - ] - } - ], - "items": { - "minimum": 5 - } - } - } - } - ] - }, - "tests": [ - { - "description": "prefixItems in allOf does not constrain items, invalid case", - "data": [ - 3, - 5 - ], - "schema_id": "items_6_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "MINIMUM_VIOLATED", - "values": { - "limit": "5", - "value": "3" - }, - "details": { - "path": "0", - "schema": "items_6_0" - } - } - ] - } - }, - { - "description": "prefixItems in allOf does not constrain items, valid case", - "data": [ - 5, - 5 - ], - "schema_id": "items_6_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "prefixItems validation adjusts the starting index for items", - "database": { - "types": [ - { - "name": "items_7_0", - "schemas": { - "items_7_0": { - "prefixItems": [ - { - "type": "string" - } - ], - "items": { - "type": "integer" - } - } - } - } - ] - }, - "tests": [ - { - "description": "valid items", - "data": [ - "x", - 2, - 3 - ], - "schema_id": "items_7_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "wrong type of second item", - "data": [ - "x", - "y" - ], - "schema_id": "items_7_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "1", - "schema": "items_7_0" - } - } - ] - } - } - ] - }, - { - "description": "items with heterogeneous array", - "database": { - "types": [ - { - "name": "items_8_0", - "schemas": { - "items_8_0": { - "prefixItems": [ - {} - ], - "items": false - } - } - } - ] - }, - "tests": [ - { - "description": "heterogeneous invalid instance", - "data": [ - "foo", - "bar", - 37 - ], - "schema_id": "items_8_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "1", - "schema": "items_8_0" - } - }, - { - "code": "FALSE_SCHEMA", - "details": { - "path": "2", - "schema": "items_8_0" - } - } - ] - } - }, - { - "description": "valid instance", - "data": [ - null - ], - "schema_id": "items_8_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, { "description": "items with null instance elements", "database": { @@ -1460,56 +587,6 @@ } ] }, - { - "description": "array: strict array", - "database": { - "types": [ - { - "name": "items_13_0", - "schemas": { - "items_13_0": { - "type": "array", - "extensible": false - } - } - } - ] - }, - "tests": [ - { - "description": "empty array is valid", - "data": [], - "schema_id": "items_13_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "array with items is invalid (strict)", - "data": [ - 1 - ], - "schema_id": "items_13_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_ITEM_VIOLATION", - "values": { - "index": "0" - }, - "details": { - "path": "0", - "schema": "items_13_0" - } - } - ] - } - } - ] - }, { "description": "array: items extensible", "database": { diff --git a/fixtures/maxItems.json b/fixtures/maxItems.json index 59752fd..3025568 100644 --- a/fixtures/maxItems.json +++ b/fixtures/maxItems.json @@ -7,8 +7,7 @@ "name": "maxItems_0_0", "schemas": { "maxItems_0_0": { - "maxItems": 2, - "extensible": true + "maxItems": 2 } } } @@ -83,8 +82,7 @@ "name": "maxItems_1_0", "schemas": { "maxItems_1_0": { - "maxItems": 2, - "extensible": true + "maxItems": 2 } } } @@ -138,8 +136,7 @@ "name": "maxItems_2_0", "schemas": { "maxItems_2_0": { - "maxItems": 2, - "extensible": true + "maxItems": 2 } } } diff --git a/fixtures/minItems.json b/fixtures/minItems.json index 356ef40..ed5f123 100644 --- a/fixtures/minItems.json +++ b/fixtures/minItems.json @@ -7,8 +7,7 @@ "name": "minItems_0_0", "schemas": { "minItems_0_0": { - "minItems": 1, - "extensible": true + "minItems": 1 } } } @@ -79,8 +78,7 @@ "name": "minItems_1_0", "schemas": { "minItems_1_0": { - "minItems": 1, - "extensible": true + "minItems": 1 } } } diff --git a/fixtures/patternProperties.json b/fixtures/patternProperties.json deleted file mode 100644 index 765fb26..0000000 --- a/fixtures/patternProperties.json +++ /dev/null @@ -1,580 +0,0 @@ -[ - { - "description": "patternProperties validates properties matching a regex", - "database": { - "types": [ - { - "name": "patternProperties_0_0", - "schemas": { - "patternProperties_0_0": { - "patternProperties": { - "f.*o": { - "type": "integer" - } - }, - "items": {} - } - } - } - ] - }, - "tests": [ - { - "description": "a single valid match is valid", - "data": { - "foo": 1 - }, - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "multiple valid matches is valid", - "data": { - "foo": 1, - "foooooo": 2 - }, - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "a single invalid match is invalid", - "data": { - "foo": "bar", - "fooooo": 2 - }, - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "foo", - "schema": "patternProperties_0_0" - } - } - ] - } - }, - { - "description": "multiple invalid matches is invalid", - "data": { - "foo": "bar", - "foooooo": "baz" - }, - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "foo", - "schema": "patternProperties_0_0" - } - }, - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "foooooo", - "schema": "patternProperties_0_0" - } - } - ] - } - }, - { - "description": "ignores arrays", - "data": [ - "foo" - ], - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "ignores strings", - "data": "foo", - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "ignores other non-objects", - "data": 12, - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "extra property not matching pattern is INVALID (strict by default)", - "data": { - "foo": 1, - "extra": 2 - }, - "schema_id": "patternProperties_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "extra" - }, - "details": { - "path": "extra", - "schema": "patternProperties_0_0" - } - } - ] - } - } - ] - }, - { - "description": "multiple simultaneous patternProperties are validated", - "database": { - "types": [ - { - "name": "patternProperties_1_0", - "schemas": { - "patternProperties_1_0": { - "patternProperties": { - "a*": { - "type": "integer" - }, - "aaa*": { - "maximum": 20 - } - } - } - } - } - ] - }, - "tests": [ - { - "description": "a single valid match is valid", - "data": { - "a": 21 - }, - "schema_id": "patternProperties_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "a simultaneous match is valid", - "data": { - "aaaa": 18 - }, - "schema_id": "patternProperties_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "multiple matches is valid", - "data": { - "a": 21, - "aaaa": 18 - }, - "schema_id": "patternProperties_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "an invalid due to one is invalid", - "data": { - "a": "bar" - }, - "schema_id": "patternProperties_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "a", - "schema": "patternProperties_1_0" - } - } - ] - } - }, - { - "description": "an invalid due to the other is invalid", - "data": { - "aaaa": 31 - }, - "schema_id": "patternProperties_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "MAXIMUM_VIOLATED", - "values": { - "value": "31", - "limit": "20" - }, - "details": { - "path": "aaaa", - "schema": "patternProperties_1_0" - } - } - ] - } - }, - { - "description": "an invalid due to both is invalid", - "data": { - "aaa": "foo", - "aaaa": 31 - }, - "schema_id": "patternProperties_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "aaa", - "schema": "patternProperties_1_0" - } - }, - { - "code": "MAXIMUM_VIOLATED", - "values": { - "limit": "20", - "value": "31" - }, - "details": { - "path": "aaaa", - "schema": "patternProperties_1_0" - } - } - ] - } - } - ] - }, - { - "description": "regexes are not anchored by default and are case sensitive", - "database": { - "types": [ - { - "name": "patternProperties_2_0", - "schemas": { - "patternProperties_2_0": { - "patternProperties": { - "[0-9]{2,}": { - "type": "boolean" - }, - "X_": { - "type": "string" - } - }, - "extensible": true - } - } - } - ] - }, - "tests": [ - { - "description": "non recognized members are ignored", - "data": { - "answer 1": "42" - }, - "schema_id": "patternProperties_2_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "recognized members are accounted for", - "data": { - "a31b": null - }, - "schema_id": "patternProperties_2_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "boolean" - }, - "details": { - "path": "a31b", - "schema": "patternProperties_2_0" - } - } - ] - } - }, - { - "description": "regexes are case sensitive", - "data": { - "a_x_3": 3 - }, - "schema_id": "patternProperties_2_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "regexes are case sensitive, 2", - "data": { - "a_X_3": 3 - }, - "schema_id": "patternProperties_2_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "string" - }, - "details": { - "path": "a_X_3", - "schema": "patternProperties_2_0" - } - } - ] - } - } - ] - }, - { - "description": "patternProperties with boolean schemas", - "database": { - "types": [ - { - "name": "patternProperties_3_0", - "schemas": { - "patternProperties_3_0": { - "patternProperties": { - "f.*": true, - "b.*": false - } - } - } - } - ] - }, - "tests": [ - { - "description": "object with property matching schema true is valid", - "data": { - "foo": 1 - }, - "schema_id": "patternProperties_3_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "object with property matching schema false is invalid", - "data": { - "bar": 2 - }, - "schema_id": "patternProperties_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "bar", - "schema": "patternProperties_3_0" - } - } - ] - } - }, - { - "description": "object with both properties is invalid", - "data": { - "foo": 1, - "bar": 2 - }, - "schema_id": "patternProperties_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "bar", - "schema": "patternProperties_3_0" - } - } - ] - } - }, - { - "description": "object with a property matching both true and false is invalid", - "data": { - "foobar": 1 - }, - "schema_id": "patternProperties_3_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "foobar", - "schema": "patternProperties_3_0" - } - } - ] - } - }, - { - "description": "empty object is valid", - "data": {}, - "schema_id": "patternProperties_3_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "patternProperties with null valued instance properties", - "database": { - "types": [ - { - "name": "patternProperties_4_0", - "schemas": { - "patternProperties_4_0": { - "patternProperties": { - "^.*bar$": { - "type": "null" - } - } - } - } - } - ] - }, - "tests": [ - { - "description": "allows null values", - "data": { - "foobar": null - }, - "schema_id": "patternProperties_4_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "extensible: true allows extra properties NOT matching pattern", - "database": { - "types": [ - { - "name": "patternProperties_5_0", - "schemas": { - "patternProperties_5_0": { - "patternProperties": { - "f.*o": { - "type": "integer" - } - }, - "extensible": true - } - } - } - ] - }, - "tests": [ - { - "description": "extra property not matching pattern is valid", - "data": { - "bar": 1 - }, - "schema_id": "patternProperties_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "property matching pattern MUST still be valid", - "data": { - "foo": "invalid string" - }, - "schema_id": "patternProperties_5_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "foo", - "schema": "patternProperties_5_0" - } - } - ] - } - } - ] - } -] \ No newline at end of file diff --git a/fixtures/prefixItems.json b/fixtures/prefixItems.json deleted file mode 100644 index cd11c4b..0000000 --- a/fixtures/prefixItems.json +++ /dev/null @@ -1,324 +0,0 @@ -[ - { - "description": "a schema given for prefixItems", - "database": { - "types": [ - { - "name": "prefixItems_0_0", - "schemas": { - "prefixItems_0_0": { - "prefixItems": [ - { - "type": "integer" - }, - { - "type": "string" - } - ] - } - } - } - ] - }, - "tests": [ - { - "description": "correct types", - "data": [ - 1, - "foo" - ], - "schema_id": "prefixItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "wrong types", - "data": [ - "foo", - 1 - ], - "schema_id": "prefixItems_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "INVALID_TYPE", - "values": { - "expected": "integer" - }, - "details": { - "path": "0", - "schema": "prefixItems_0_0" - } - }, - { - "code": "INVALID_TYPE", - "values": { - "expected": "string" - }, - "details": { - "path": "1", - "schema": "prefixItems_0_0" - } - } - ] - } - }, - { - "description": "incomplete array of items", - "data": [ - 1 - ], - "schema_id": "prefixItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "array with additional items (invalid due to strictness)", - "data": [ - 1, - "foo", - true - ], - "schema_id": "prefixItems_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_ITEM_VIOLATION", - "values": { - "index": "2" - }, - "details": { - "path": "2", - "schema": "prefixItems_0_0" - } - } - ] - } - }, - { - "description": "empty array", - "data": [], - "schema_id": "prefixItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "JavaScript pseudo-array is valid (invalid due to strict object validation)", - "data": { - "0": "invalid", - "1": "valid", - "length": 2 - }, - "schema_id": "prefixItems_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "0" - }, - "details": { - "path": "0", - "schema": "prefixItems_0_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "1" - }, - "details": { - "path": "1", - "schema": "prefixItems_0_0" - } - }, - { - "code": "STRICT_PROPERTY_VIOLATION", - "values": { - "property_name": "length" - }, - "details": { - "path": "length", - "schema": "prefixItems_0_0" - } - } - ] - } - } - ] - }, - { - "description": "prefixItems with boolean schemas", - "database": { - "types": [ - { - "name": "prefixItems_1_0", - "schemas": { - "prefixItems_1_0": { - "prefixItems": [ - true, - false - ] - } - } - } - ] - }, - "tests": [ - { - "description": "array with one item is valid", - "data": [ - 1 - ], - "schema_id": "prefixItems_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "array with two items is invalid", - "data": [ - 1, - "foo" - ], - "schema_id": "prefixItems_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "1", - "schema": "prefixItems_1_0" - } - } - ] - } - }, - { - "description": "empty array is valid", - "data": [], - "schema_id": "prefixItems_1_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "additional items are allowed by default", - "database": { - "types": [ - { - "name": "prefixItems_2_0", - "schemas": { - "prefixItems_2_0": { - "prefixItems": [ - { - "type": "integer" - } - ], - "extensible": true - } - } - } - ] - }, - "tests": [ - { - "description": "only the first item is validated", - "data": [ - 1, - "foo", - false - ], - "schema_id": "prefixItems_2_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "prefixItems with null instance elements", - "database": { - "types": [ - { - "name": "prefixItems_3_0", - "schemas": { - "prefixItems_3_0": { - "prefixItems": [ - { - "type": "null" - } - ] - } - } - } - ] - }, - "tests": [ - { - "description": "allows null elements", - "data": [ - null - ], - "schema_id": "prefixItems_3_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "extensible: true allows extra items with prefixItems", - "database": { - "types": [ - { - "name": "prefixItems_4_0", - "schemas": { - "prefixItems_4_0": { - "prefixItems": [ - { - "type": "integer" - } - ], - "extensible": true - } - } - } - ] - }, - "tests": [ - { - "description": "extra item is valid", - "data": [ - 1, - "foo" - ], - "schema_id": "prefixItems_4_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - } -] \ No newline at end of file diff --git a/fixtures/uniqueItems.json b/fixtures/uniqueItems.json index 24aef7f..09cb421 100644 --- a/fixtures/uniqueItems.json +++ b/fixtures/uniqueItems.json @@ -316,536 +316,6 @@ } ] } - }, - { - "description": "non-unique array of more than two arrays is invalid", - "data": [ - [ - "foo" - ], - [ - "bar" - ], - [ - "foo" - ] - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_0_0" - } - } - ] - } - }, - { - "description": "1 and true are unique", - "data": [ - 1, - true - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "0 and false are unique", - "data": [ - 0, - false - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[1] and [true] are unique", - "data": [ - [ - 1 - ], - [ - true - ] - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[0] and [false] are unique", - "data": [ - [ - 0 - ], - [ - false - ] - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "nested [1] and [true] are unique", - "data": [ - [ - [ - 1 - ], - "foo" - ], - [ - [ - true - ], - "foo" - ] - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "nested [0] and [false] are unique", - "data": [ - [ - [ - 0 - ], - "foo" - ], - [ - [ - false - ], - "foo" - ] - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "unique heterogeneous types are valid", - "data": [ - {}, - [ - 1 - ], - true, - null, - 1, - "{}" - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "non-unique heterogeneous types are invalid", - "data": [ - {}, - [ - 1 - ], - true, - null, - {}, - 1 - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_0_0" - } - } - ] - } - }, - { - "description": "different objects are unique", - "data": [ - { - "a": 1, - "b": 2 - }, - { - "a": 2, - "b": 1 - } - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "objects are non-unique despite key order", - "data": [ - { - "a": 1, - "b": 2 - }, - { - "b": 2, - "a": 1 - } - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_0_0" - } - } - ] - } - }, - { - "description": "{\"a\": false} and {\"a\": 0} are unique", - "data": [ - { - "a": false - }, - { - "a": 0 - } - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "{\"a\": true} and {\"a\": 1} are unique", - "data": [ - { - "a": true - }, - { - "a": 1 - } - ], - "schema_id": "uniqueItems_0_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "uniqueItems with an array of items", - "database": { - "types": [ - { - "name": "uniqueItems_1_0", - "schemas": { - "uniqueItems_1_0": { - "prefixItems": [ - { - "type": "boolean" - }, - { - "type": "boolean" - } - ], - "uniqueItems": true, - "extensible": true - } - } - } - ] - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [ - false, - true - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[true, false] from items array is valid", - "data": [ - true, - false - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[false, false] from items array is not valid", - "data": [ - false, - false - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_1_0" - } - } - ] - } - }, - { - "description": "[true, true] from items array is not valid", - "data": [ - true, - true - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_1_0" - } - } - ] - } - }, - { - "description": "unique array extended from [false, true] is valid", - "data": [ - false, - true, - "foo", - "bar" - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "unique array extended from [true, false] is valid", - "data": [ - true, - false, - "foo", - "bar" - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "non-unique array extended from [false, true] is not valid", - "data": [ - false, - true, - "foo", - "foo" - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_1_0" - } - } - ] - } - }, - { - "description": "non-unique array extended from [true, false] is not valid", - "data": [ - true, - false, - "foo", - "foo" - ], - "schema_id": "uniqueItems_1_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_1_0" - } - } - ] - } - } - ] - }, - { - "description": "uniqueItems with an array of items and additionalItems=false", - "database": { - "types": [ - { - "name": "uniqueItems_2_0", - "schemas": { - "uniqueItems_2_0": { - "prefixItems": [ - { - "type": "boolean" - }, - { - "type": "boolean" - } - ], - "uniqueItems": true, - "items": false - } - } - } - ] - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [ - false, - true - ], - "schema_id": "uniqueItems_2_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[true, false] from items array is valid", - "data": [ - true, - false - ], - "schema_id": "uniqueItems_2_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[false, false] from items array is not valid", - "data": [ - false, - false - ], - "schema_id": "uniqueItems_2_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_2_0" - } - } - ] - } - }, - { - "description": "[true, true] from items array is not valid", - "data": [ - true, - true - ], - "schema_id": "uniqueItems_2_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "UNIQUE_ITEMS_VIOLATED", - "details": { - "path": "", - "schema": "uniqueItems_2_0" - } - } - ] - } - }, - { - "description": "extra items are invalid even if unique", - "data": [ - false, - true, - null - ], - "schema_id": "uniqueItems_2_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "2", - "schema": "uniqueItems_2_0" - } - } - ] - } } ] }, @@ -1099,232 +569,6 @@ } ] }, - { - "description": "uniqueItems=false with an array of items", - "database": { - "types": [ - { - "name": "uniqueItems_4_0", - "schemas": { - "uniqueItems_4_0": { - "prefixItems": [ - { - "type": "boolean" - }, - { - "type": "boolean" - } - ], - "uniqueItems": false, - "extensible": true - } - } - } - ] - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [ - false, - true - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[true, false] from items array is valid", - "data": [ - true, - false - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[false, false] from items array is valid", - "data": [ - false, - false - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[true, true] from items array is valid", - "data": [ - true, - true - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "unique array extended from [false, true] is valid", - "data": [ - false, - true, - "foo", - "bar" - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "unique array extended from [true, false] is valid", - "data": [ - true, - false, - "foo", - "bar" - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "non-unique array extended from [false, true] is valid", - "data": [ - false, - true, - "foo", - "foo" - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "non-unique array extended from [true, false] is valid", - "data": [ - true, - false, - "foo", - "foo" - ], - "schema_id": "uniqueItems_4_0", - "action": "validate", - "expect": { - "success": true - } - } - ] - }, - { - "description": "uniqueItems=false with an array of items and additionalItems=false", - "database": { - "types": [ - { - "name": "uniqueItems_5_0", - "schemas": { - "uniqueItems_5_0": { - "prefixItems": [ - { - "type": "boolean" - }, - { - "type": "boolean" - } - ], - "uniqueItems": false, - "items": false - } - } - } - ] - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [ - false, - true - ], - "schema_id": "uniqueItems_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[true, false] from items array is valid", - "data": [ - true, - false - ], - "schema_id": "uniqueItems_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[false, false] from items array is valid", - "data": [ - false, - false - ], - "schema_id": "uniqueItems_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "[true, true] from items array is valid", - "data": [ - true, - true - ], - "schema_id": "uniqueItems_5_0", - "action": "validate", - "expect": { - "success": true - } - }, - { - "description": "extra items are invalid even if unique", - "data": [ - false, - true, - null - ], - "schema_id": "uniqueItems_5_0", - "action": "validate", - "expect": { - "success": false, - "errors": [ - { - "code": "FALSE_SCHEMA", - "details": { - "path": "2", - "schema": "uniqueItems_5_0" - } - } - ] - } - } - ] - }, { "description": "extensible: true allows extra items in uniqueItems", "database": { diff --git a/src/database/compile/collection.rs b/src/database/compile/collection.rs index 17530ad..2b6b5b1 100644 --- a/src/database/compile/collection.rs +++ b/src/database/compile/collection.rs @@ -25,9 +25,9 @@ impl Schema { ("identifier".to_string(), id.to_string()), ])), details: ErrorDetails { - path: Some(path.to_string()), - schema: Some(root_id.to_string()), - ..Default::default() + path: Some(path.to_string()), + schema: Some(root_id.to_string()), + ..Default::default() }, }); return; @@ -84,13 +84,6 @@ impl Schema { } } - if let Some(pattern_props) = &schema_arc.obj.pattern_properties { - for (k, v) in pattern_props.iter() { - let next_path = format!("{}/{}", path, k); - Self::collect_schemas(v, root_id, next_path, to_insert, errors); - } - } - let mut map_arr = |arr: &Vec>, sub: &str| { for (i, v) in arr.iter().enumerate() { Self::collect_schemas( @@ -103,10 +96,6 @@ impl Schema { } }; - if let Some(arr) = &schema_arc.obj.prefix_items { - map_arr(arr, "prefixItems"); - } - if let Some(arr) = &schema_arc.obj.one_of { map_arr(arr, "oneOf"); } @@ -123,11 +112,6 @@ impl Schema { } }; - map_opt( - &schema_arc.obj.additional_properties, - false, - "additionalProperties", - ); map_opt(&schema_arc.obj.items, true, "items"); map_opt(&schema_arc.obj.not, false, "not"); map_opt(&schema_arc.obj.contains, false, "contains"); diff --git a/src/database/compile/mod.rs b/src/database/compile/mod.rs index 55c67f5..1f820c7 100644 --- a/src/database/compile/mod.rs +++ b/src/database/compile/mod.rs @@ -39,18 +39,6 @@ impl Schema { } } - if let Some(pattern_props) = &self.obj.pattern_properties { - let mut compiled = Vec::new(); - for (k, v) in pattern_props { - if let Ok(re) = regex::Regex::new(k) { - compiled.push((crate::database::object::CompiledRegex(re), v.clone())); - } - } - if !compiled.is_empty() { - let _ = self.obj.compiled_pattern_properties.set(compiled); - } - } - let mut props = IndexMap::new(); // 1. Resolve INHERITANCE dependencies first @@ -78,10 +66,10 @@ impl Schema { code: "MULTIPLE_INHERITANCE_PROHIBITED".to_string(), values: Some(HashMap::from([("types".to_string(), types.join(", "))])), details: ErrorDetails { - path: Some(path.clone()), - schema: Some(root_id.to_string()), - ..Default::default() - } + path: Some(path.clone()), + schema: Some(root_id.to_string()), + ..Default::default() + }, }); } @@ -140,29 +128,13 @@ impl Schema { if let Some(items) = &self.obj.items { items.compile(db, root_id, format!("{}/items", path), errors); } - if let Some(pattern_props) = &self.obj.pattern_properties { - for (k, child) in pattern_props { - child.compile(db, root_id, format!("{}/{}", path, k), errors); - } - } - if let Some(additional_props) = &self.obj.additional_properties { - additional_props.compile( - db, - root_id, - format!("{}/additionalProperties", path), - errors, - ); - } + if let Some(one_of) = &self.obj.one_of { for (i, child) in one_of.iter().enumerate() { child.compile(db, root_id, format!("{}/oneOf/{}", path, i), errors); } } - if let Some(arr) = &self.obj.prefix_items { - for (i, child) in arr.iter().enumerate() { - child.compile(db, root_id, format!("{}/prefixItems/{}", path, i), errors); - } - } + if let Some(child) = &self.obj.not { child.compile(db, root_id, format!("{}/not", path), errors); } diff --git a/src/database/compose/mod.rs b/src/database/compose/mod.rs index 815d054..3e020e6 100644 --- a/src/database/compose/mod.rs +++ b/src/database/compose/mod.rs @@ -81,7 +81,6 @@ fn resolve_in_place( let mut merged_required = HashSet::new(); let mut merged_display = HashSet::new(); let mut merged_dependencies = serde_json::Map::new(); - let mut merged_pattern_props = serde_json::Map::new(); // Read current values first to let host override included properties if let Some(req) = current.get("required").and_then(|v| v.as_array()) { @@ -103,11 +102,7 @@ fn resolve_in_place( merged_dependencies.insert(k.clone(), v.clone()); } } - if let Some(pat_props) = current.get("patternProperties").and_then(|v| v.as_object()) { - for (k, v) in pat_props { - merged_pattern_props.insert(k.clone(), v.clone()); - } - } + if let Some(props) = current.get("properties").and_then(|v| v.as_object()) { for (k, v) in props { merged_props.insert(k.clone(), v.clone()); @@ -119,7 +114,10 @@ fn resolve_in_place( if visited.contains(inc_name) { errors.push(Error { code: "CIRCULAR_INCLUDE_DETECTED".to_string(), - values: Some(HashMap::from([("include".to_string(), inc_name.to_string())])), + values: Some(HashMap::from([( + "include".to_string(), + inc_name.to_string(), + )])), details: ErrorDetails { schema: Some(schema_id.to_string()), path: Some(path.to_string()), @@ -156,18 +154,6 @@ fn resolve_in_place( } } - // Merge patternProperties (host overrides trait) - if let Some(target_pat_props) = resolved_target - .get("patternProperties") - .and_then(|v| v.as_object()) - { - for (k, v) in target_pat_props { - if !merged_pattern_props.contains_key(k) { - merged_pattern_props.insert(k.clone(), v.clone()); - } - } - } - // Merge required if let Some(target_req) = resolved_target.get("required").and_then(|v| v.as_array()) { for r in target_req { @@ -218,7 +204,6 @@ fn resolve_in_place( if let Some(obj) = current.as_object_mut() { for (k, v) in resolved_target.as_object().unwrap() { if k != "properties" - && k != "patternProperties" && k != "required" && k != "display" && k != "dependencies" @@ -233,7 +218,10 @@ fn resolve_in_place( } else { errors.push(Error { code: "TRAIT_NOT_FOUND".to_string(), - values: Some(HashMap::from([("include".to_string(), inc_name.to_string())])), + values: Some(HashMap::from([( + "include".to_string(), + inc_name.to_string(), + )])), details: ErrorDetails { schema: Some(schema_id.to_string()), path: Some(path.to_string()), @@ -248,12 +236,7 @@ fn resolve_in_place( if !merged_props.is_empty() { obj.insert("properties".to_string(), Value::Object(merged_props)); } - if !merged_pattern_props.is_empty() { - obj.insert( - "patternProperties".to_string(), - Value::Object(merged_pattern_props), - ); - } + if !merged_required.is_empty() { let mut req_vec: Vec = merged_required.into_iter().map(Value::String).collect(); req_vec.sort_by(|a, b| a.as_str().unwrap().cmp(b.as_str().unwrap())); @@ -289,22 +272,7 @@ fn resolve_in_place( ); } } - if let Some(pat_props) = obj - .get_mut("patternProperties") - .and_then(|v| v.as_object_mut()) - { - for (k, v) in pat_props { - resolve_in_place( - v, - traits, - schemas, - errors, - schema_id, - &format!("{}/{}", path, k), - visited, - ); - } - } + if let Some(items) = obj.get_mut("items") { resolve_in_place( items, @@ -316,30 +284,6 @@ fn resolve_in_place( visited, ); } - if let Some(prefix_items) = obj.get_mut("prefixItems").and_then(|v| v.as_array_mut()) { - for (i, v) in prefix_items.iter_mut().enumerate() { - resolve_in_place( - v, - traits, - schemas, - errors, - schema_id, - &format!("{}/prefixItems/{}", path, i), - visited, - ); - } - } - if let Some(additional_props) = obj.get_mut("additionalProperties") { - resolve_in_place( - additional_props, - traits, - schemas, - errors, - schema_id, - &format!("{}/additionalProperties", path), - visited, - ); - } if let Some(one_of) = obj.get_mut("oneOf").and_then(|v| v.as_array_mut()) { for (i, v) in one_of.iter_mut().enumerate() { resolve_in_place( diff --git a/src/database/object.rs b/src/database/object.rs index 5698aca..5540ca1 100644 --- a/src/database/object.rs +++ b/src/database/object.rs @@ -32,12 +32,10 @@ pub struct SchemaObject { // Object Keywords #[serde(skip_serializing_if = "Option::is_none")] pub properties: Option>>, - #[serde(rename = "patternProperties")] + #[serde(rename = "keys")] #[serde(skip_serializing_if = "Option::is_none")] - pub pattern_properties: Option>>, - #[serde(rename = "additionalProperties")] - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_properties: Option>, + pub keys: Option>, + #[serde(rename = "family")] #[serde(skip_serializing_if = "Option::is_none")] pub family: Option, @@ -53,9 +51,6 @@ pub struct SchemaObject { #[serde(rename = "items")] #[serde(skip_serializing_if = "Option::is_none")] pub items: Option>, - #[serde(rename = "prefixItems")] - #[serde(skip_serializing_if = "Option::is_none")] - pub prefix_items: Option>>, // String Validation #[serde(rename = "minLength")] @@ -189,8 +184,6 @@ pub struct SchemaObject { pub compiled_format: OnceLock, #[serde(skip)] pub compiled_pattern: OnceLock, - #[serde(skip)] - pub compiled_pattern_properties: OnceLock)>>, } /// Represents a compiled format validator @@ -263,7 +256,7 @@ where pub fn is_primitive_type(t: &str) -> bool { matches!( t, - "string" | "number" | "integer" | "boolean" | "object" | "array" | "null" + "string" | "number" | "integer" | "boolean" | "object" | "array" | "null" | "dict" ) } diff --git a/src/database/schema.rs b/src/database/schema.rs index 0e78705..50cfde1 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -26,12 +26,10 @@ impl Schema { /// Returns true if the schema acts purely as a type pointer (composition without overriding constraints) pub fn is_proxy(&self) -> bool { self.obj.properties.is_none() - && self.obj.pattern_properties.is_none() - && self.obj.additional_properties.is_none() + && self.obj.keys.is_none() && self.obj.required.is_none() && self.obj.dependencies.is_none() && self.obj.items.is_none() - && self.obj.prefix_items.is_none() && self.obj.contains.is_none() && self.obj.format.is_none() && self.obj.enum_.is_none() @@ -68,12 +66,10 @@ impl<'de> Deserialize<'de> for Schema { // restrict additional properties natively let is_empty = obj.type_.is_none() && obj.properties.is_none() - && obj.pattern_properties.is_none() - && obj.additional_properties.is_none() + && obj.keys.is_none() && obj.required.is_none() && obj.dependencies.is_none() && obj.items.is_none() - && obj.prefix_items.is_none() && obj.contains.is_none() && obj.format.is_none() && obj.enum_.is_none() diff --git a/src/tests/fixtures.rs b/src/tests/fixtures.rs index a7c4136..a1b7d52 100644 --- a/src/tests/fixtures.rs +++ b/src/tests/fixtures.rs @@ -197,84 +197,6 @@ fn test_unique_items_0_14() { crate::tests::runner::run_test_case(&path, 0, 14).unwrap(); } -#[test] -fn test_unique_items_0_15() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 15).unwrap(); -} - -#[test] -fn test_unique_items_0_16() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 16).unwrap(); -} - -#[test] -fn test_unique_items_0_17() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 17).unwrap(); -} - -#[test] -fn test_unique_items_0_18() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 18).unwrap(); -} - -#[test] -fn test_unique_items_0_19() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 19).unwrap(); -} - -#[test] -fn test_unique_items_0_20() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 20).unwrap(); -} - -#[test] -fn test_unique_items_0_21() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 21).unwrap(); -} - -#[test] -fn test_unique_items_0_22() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 22).unwrap(); -} - -#[test] -fn test_unique_items_0_23() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 23).unwrap(); -} - -#[test] -fn test_unique_items_0_24() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 24).unwrap(); -} - -#[test] -fn test_unique_items_0_25() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 25).unwrap(); -} - -#[test] -fn test_unique_items_0_26() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 26).unwrap(); -} - -#[test] -fn test_unique_items_0_27() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 27).unwrap(); -} - #[test] fn test_unique_items_1_0() { let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); @@ -323,6 +245,48 @@ fn test_unique_items_1_7() { crate::tests::runner::run_test_case(&path, 1, 7).unwrap(); } +#[test] +fn test_unique_items_1_8() { + let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 8).unwrap(); +} + +#[test] +fn test_unique_items_1_9() { + let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 9).unwrap(); +} + +#[test] +fn test_unique_items_1_10() { + let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 10).unwrap(); +} + +#[test] +fn test_unique_items_1_11() { + let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 11).unwrap(); +} + +#[test] +fn test_unique_items_1_12() { + let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 12).unwrap(); +} + +#[test] +fn test_unique_items_1_13() { + let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 13).unwrap(); +} + +#[test] +fn test_unique_items_1_14() { + let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 14).unwrap(); +} + #[test] fn test_unique_items_2_0() { let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); @@ -335,204 +299,6 @@ fn test_unique_items_2_1() { crate::tests::runner::run_test_case(&path, 2, 1).unwrap(); } -#[test] -fn test_unique_items_2_2() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 2).unwrap(); -} - -#[test] -fn test_unique_items_2_3() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 3).unwrap(); -} - -#[test] -fn test_unique_items_2_4() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 4).unwrap(); -} - -#[test] -fn test_unique_items_3_0() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 0).unwrap(); -} - -#[test] -fn test_unique_items_3_1() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 1).unwrap(); -} - -#[test] -fn test_unique_items_3_2() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 2).unwrap(); -} - -#[test] -fn test_unique_items_3_3() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 3).unwrap(); -} - -#[test] -fn test_unique_items_3_4() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 4).unwrap(); -} - -#[test] -fn test_unique_items_3_5() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 5).unwrap(); -} - -#[test] -fn test_unique_items_3_6() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 6).unwrap(); -} - -#[test] -fn test_unique_items_3_7() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 7).unwrap(); -} - -#[test] -fn test_unique_items_3_8() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 8).unwrap(); -} - -#[test] -fn test_unique_items_3_9() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 9).unwrap(); -} - -#[test] -fn test_unique_items_3_10() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 10).unwrap(); -} - -#[test] -fn test_unique_items_3_11() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 11).unwrap(); -} - -#[test] -fn test_unique_items_3_12() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 12).unwrap(); -} - -#[test] -fn test_unique_items_3_13() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 13).unwrap(); -} - -#[test] -fn test_unique_items_3_14() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 14).unwrap(); -} - -#[test] -fn test_unique_items_4_0() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 0).unwrap(); -} - -#[test] -fn test_unique_items_4_1() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 1).unwrap(); -} - -#[test] -fn test_unique_items_4_2() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 2).unwrap(); -} - -#[test] -fn test_unique_items_4_3() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 3).unwrap(); -} - -#[test] -fn test_unique_items_4_4() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 4).unwrap(); -} - -#[test] -fn test_unique_items_4_5() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 5).unwrap(); -} - -#[test] -fn test_unique_items_4_6() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 6).unwrap(); -} - -#[test] -fn test_unique_items_4_7() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 7).unwrap(); -} - -#[test] -fn test_unique_items_5_0() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 0).unwrap(); -} - -#[test] -fn test_unique_items_5_1() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 1).unwrap(); -} - -#[test] -fn test_unique_items_5_2() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 2).unwrap(); -} - -#[test] -fn test_unique_items_5_3() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 3).unwrap(); -} - -#[test] -fn test_unique_items_5_4() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 4).unwrap(); -} - -#[test] -fn test_unique_items_6_0() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 6, 0).unwrap(); -} - -#[test] -fn test_unique_items_6_1() { - let path = format!("{}/fixtures/uniqueItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 6, 1).unwrap(); -} - #[test] fn test_filter_0_0() { let path = format!("{}/fixtures/filter.json", env!("CARGO_MANIFEST_DIR")); @@ -581,54 +347,6 @@ fn test_min_items_2_0() { crate::tests::runner::run_test_case(&path, 2, 0).unwrap(); } -#[test] -fn test_additional_properties_0_0() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 0).unwrap(); -} - -#[test] -fn test_additional_properties_0_1() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 1).unwrap(); -} - -#[test] -fn test_additional_properties_0_2() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 2).unwrap(); -} - -#[test] -fn test_additional_properties_1_0() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 0).unwrap(); -} - -#[test] -fn test_additional_properties_1_1() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 1).unwrap(); -} - -#[test] -fn test_additional_properties_2_0() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 0).unwrap(); -} - -#[test] -fn test_additional_properties_2_1() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 1).unwrap(); -} - -#[test] -fn test_additional_properties_2_2() { - let path = format!("{}/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 2).unwrap(); -} - #[test] fn test_dependencies_0_0() { let path = format!("{}/fixtures/dependencies.json", env!("CARGO_MANIFEST_DIR")); @@ -887,6 +605,72 @@ fn test_dependencies_10_0() { crate::tests::runner::run_test_case(&path, 10, 0).unwrap(); } +#[test] +fn test_dict_0_0() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 0, 0).unwrap(); +} + +#[test] +fn test_dict_0_1() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 0, 1).unwrap(); +} + +#[test] +fn test_dict_0_2() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 0, 2).unwrap(); +} + +#[test] +fn test_dict_0_3() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 0, 3).unwrap(); +} + +#[test] +fn test_dict_1_0() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 0).unwrap(); +} + +#[test] +fn test_dict_1_1() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 1, 1).unwrap(); +} + +#[test] +fn test_dict_2_0() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 2, 0).unwrap(); +} + +#[test] +fn test_dict_2_1() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 2, 1).unwrap(); +} + +#[test] +fn test_dict_3_0() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 3, 0).unwrap(); +} + +#[test] +fn test_dict_3_1() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 3, 1).unwrap(); +} + +#[test] +fn test_dict_3_2() { + let path = format!("{}/fixtures/dict.json", env!("CARGO_MANIFEST_DIR")); + crate::tests::runner::run_test_case(&path, 3, 2).unwrap(); +} + #[test] fn test_exclusive_minimum_0_0() { let path = format!("{}/fixtures/exclusiveMinimum.json", env!("CARGO_MANIFEST_DIR")); @@ -1979,72 +1763,18 @@ fn test_items_3_2() { crate::tests::runner::run_test_case(&path, 3, 2).unwrap(); } -#[test] -fn test_items_3_3() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 3).unwrap(); -} - -#[test] -fn test_items_3_4() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 4).unwrap(); -} - -#[test] -fn test_items_3_5() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 5).unwrap(); -} - #[test] fn test_items_4_0() { let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); crate::tests::runner::run_test_case(&path, 4, 0).unwrap(); } -#[test] -fn test_items_4_1() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 1).unwrap(); -} - -#[test] -fn test_items_4_2() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 2).unwrap(); -} - #[test] fn test_items_5_0() { let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); crate::tests::runner::run_test_case(&path, 5, 0).unwrap(); } -#[test] -fn test_items_5_1() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 1).unwrap(); -} - -#[test] -fn test_items_5_2() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 2).unwrap(); -} - -#[test] -fn test_items_5_3() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 3).unwrap(); -} - -#[test] -fn test_items_5_4() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 4).unwrap(); -} - #[test] fn test_items_6_0() { let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); @@ -2088,75 +1818,15 @@ fn test_items_9_0() { } #[test] -fn test_items_10_0() { +fn test_items_9_1() { let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 10, 0).unwrap(); + crate::tests::runner::run_test_case(&path, 9, 1).unwrap(); } #[test] -fn test_items_11_0() { +fn test_items_9_2() { let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 11, 0).unwrap(); -} - -#[test] -fn test_items_11_1() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 11, 1).unwrap(); -} - -#[test] -fn test_items_12_0() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 12, 0).unwrap(); -} - -#[test] -fn test_items_12_1() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 12, 1).unwrap(); -} - -#[test] -fn test_items_13_0() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 13, 0).unwrap(); -} - -#[test] -fn test_items_13_1() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 13, 1).unwrap(); -} - -#[test] -fn test_items_14_0() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 14, 0).unwrap(); -} - -#[test] -fn test_items_14_1() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 14, 1).unwrap(); -} - -#[test] -fn test_items_15_0() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 15, 0).unwrap(); -} - -#[test] -fn test_items_15_1() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 15, 1).unwrap(); -} - -#[test] -fn test_items_15_2() { - let path = format!("{}/fixtures/items.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 15, 2).unwrap(); + crate::tests::runner::run_test_case(&path, 9, 2).unwrap(); } #[test] @@ -3011,78 +2681,6 @@ fn test_exclusive_maximum_0_3() { crate::tests::runner::run_test_case(&path, 0, 3).unwrap(); } -#[test] -fn test_prefix_items_0_0() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 0).unwrap(); -} - -#[test] -fn test_prefix_items_0_1() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 1).unwrap(); -} - -#[test] -fn test_prefix_items_0_2() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 2).unwrap(); -} - -#[test] -fn test_prefix_items_0_3() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 3).unwrap(); -} - -#[test] -fn test_prefix_items_0_4() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 4).unwrap(); -} - -#[test] -fn test_prefix_items_0_5() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 5).unwrap(); -} - -#[test] -fn test_prefix_items_1_0() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 0).unwrap(); -} - -#[test] -fn test_prefix_items_1_1() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 1).unwrap(); -} - -#[test] -fn test_prefix_items_1_2() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 2).unwrap(); -} - -#[test] -fn test_prefix_items_2_0() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 0).unwrap(); -} - -#[test] -fn test_prefix_items_3_0() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 0).unwrap(); -} - -#[test] -fn test_prefix_items_4_0() { - let path = format!("{}/fixtures/prefixItems.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 0).unwrap(); -} - #[test] fn test_primitive_types_0_0() { let path = format!("{}/fixtures/primitiveTypes.json", env!("CARGO_MANIFEST_DIR")); @@ -4241,162 +3839,6 @@ fn test_multiple_of_3_0() { crate::tests::runner::run_test_case(&path, 3, 0).unwrap(); } -#[test] -fn test_pattern_properties_0_0() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 0).unwrap(); -} - -#[test] -fn test_pattern_properties_0_1() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 1).unwrap(); -} - -#[test] -fn test_pattern_properties_0_2() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 2).unwrap(); -} - -#[test] -fn test_pattern_properties_0_3() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 3).unwrap(); -} - -#[test] -fn test_pattern_properties_0_4() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 4).unwrap(); -} - -#[test] -fn test_pattern_properties_0_5() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 5).unwrap(); -} - -#[test] -fn test_pattern_properties_0_6() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 6).unwrap(); -} - -#[test] -fn test_pattern_properties_0_7() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 0, 7).unwrap(); -} - -#[test] -fn test_pattern_properties_1_0() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 0).unwrap(); -} - -#[test] -fn test_pattern_properties_1_1() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 1).unwrap(); -} - -#[test] -fn test_pattern_properties_1_2() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 2).unwrap(); -} - -#[test] -fn test_pattern_properties_1_3() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 3).unwrap(); -} - -#[test] -fn test_pattern_properties_1_4() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 4).unwrap(); -} - -#[test] -fn test_pattern_properties_1_5() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 1, 5).unwrap(); -} - -#[test] -fn test_pattern_properties_2_0() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 0).unwrap(); -} - -#[test] -fn test_pattern_properties_2_1() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 1).unwrap(); -} - -#[test] -fn test_pattern_properties_2_2() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 2).unwrap(); -} - -#[test] -fn test_pattern_properties_2_3() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 2, 3).unwrap(); -} - -#[test] -fn test_pattern_properties_3_0() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 0).unwrap(); -} - -#[test] -fn test_pattern_properties_3_1() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 1).unwrap(); -} - -#[test] -fn test_pattern_properties_3_2() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 2).unwrap(); -} - -#[test] -fn test_pattern_properties_3_3() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 3).unwrap(); -} - -#[test] -fn test_pattern_properties_3_4() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 3, 4).unwrap(); -} - -#[test] -fn test_pattern_properties_4_0() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 4, 0).unwrap(); -} - -#[test] -fn test_pattern_properties_5_0() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 0).unwrap(); -} - -#[test] -fn test_pattern_properties_5_1() { - let path = format!("{}/fixtures/patternProperties.json", env!("CARGO_MANIFEST_DIR")); - crate::tests::runner::run_test_case(&path, 5, 1).unwrap(); -} - #[test] fn test_merge_0_0() { let path = format!("{}/fixtures/merge.json", env!("CARGO_MANIFEST_DIR")); diff --git a/src/validator/mod.rs b/src/validator/mod.rs index 47eb29a..54e13f6 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -37,6 +37,7 @@ impl Validator { "number" => val.is_number(), "integer" => is_integer(val), "object" => val.is_object(), + "dict" => val.is_object(), "array" => val.is_array(), _ => true, } diff --git a/src/validator/rules/array.rs b/src/validator/rules/array.rs index c2c5b29..e34b105 100644 --- a/src/validator/rules/array.rs +++ b/src/validator/rules/array.rs @@ -99,42 +99,10 @@ impl<'a> ValidationContext<'a> { } let len = arr.len(); - let mut validation_index = 0; - - if let Some(ref prefix) = self.schema.prefix_items { - for (i, sub_schema) in prefix.iter().enumerate() { - if i < len { - if let Some(child_instance) = arr.get(i) { - let mut item_path = self.join_path(&i.to_string()); - let is_topological = sub_schema.obj.requires_uuid_path(self.db); - if is_topological { - if let Some(obj) = child_instance.as_object() { - if let Some(id_str) = obj.get("id").and_then(|v| v.as_str()) { - item_path = self.join_path(id_str); - } - } - } - let derived = self.derive( - sub_schema, - child_instance, - &item_path, - HashSet::new(), - self.extensible, - false, - Some(self.instance), - ); - let item_res = derived.validate()?; - result.merge(item_res); - result.evaluated_indices.insert(i); - validation_index += 1; - } - } - } - } if let Some(ref items_schema) = self.schema.items { let is_topological = items_schema.obj.requires_uuid_path(self.db); - for i in validation_index..len { + for i in 0..len { if let Some(child_instance) = arr.get(i) { let mut item_path = self.join_path(&i.to_string()); if is_topological { diff --git a/src/validator/rules/dict.rs b/src/validator/rules/dict.rs new file mode 100644 index 0000000..68b1dc1 --- /dev/null +++ b/src/validator/rules/dict.rs @@ -0,0 +1,76 @@ +use std::collections::{HashMap, HashSet}; + +use serde_json::Value; + +use crate::validator::context::ValidationContext; +use crate::validator::error::ValidationError; +use crate::validator::result::ValidationResult; + +impl<'a> ValidationContext<'a> { + pub(crate) fn validate_dict( + &self, + result: &mut ValidationResult, + ) -> Result { + let current = self.instance; + if let Some(obj) = current.as_object() { + let is_dict = match &self.schema.type_ { + Some(crate::database::object::SchemaTypeOrArray::Single(t)) => t == "dict", + Some(crate::database::object::SchemaTypeOrArray::Multiple(types)) => types.contains(&"dict".to_string()), + None => false, + }; + + if is_dict { + // Mark all keys as evaluated since a dictionary's keys are all dynamic parameters, not structured properties + result.evaluated_keys.extend(obj.keys().cloned()); + + // Validate keys + if let Some(ref keys_schema) = self.schema.keys { + for key in obj.keys() { + let _new_path = self.join_path(&format!("keys/{}", key)); + let val_str = Value::String(key.to_string()); + + let ctx = self.derive( + keys_schema, + &val_str, + &_new_path, + HashSet::new(), + self.extensible, + self.reporter, + None, + ); + + result.merge(ctx.validate()?); + } + } + + // Validate items (values) + if let Some(ref items_schema) = self.schema.items { + for (key, child_instance) in obj { + let new_path = self.join_path(key); + let is_ref = match &items_schema.type_ { + Some(crate::database::object::SchemaTypeOrArray::Single(ref_t)) => { + !crate::database::object::is_primitive_type(ref_t) + } + _ => false, + }; + let next_extensible = if is_ref { false } else { self.extensible }; + + let derived = self.derive( + items_schema, + child_instance, + &new_path, + HashSet::new(), + next_extensible, + false, + Some(self.instance), + ); + let item_res = derived.validate()?; + result.merge(item_res); + } + } + } + } + + Ok(true) + } +} diff --git a/src/validator/rules/extensible.rs b/src/validator/rules/extensible.rs index 928e0bb..2a9dc6f 100644 --- a/src/validator/rules/extensible.rs +++ b/src/validator/rules/extensible.rs @@ -1,5 +1,7 @@ use std::collections::HashMap; +use crate::database::object::{is_primitive_type, SchemaTypeOrArray}; +use crate::database::schema::Schema; use crate::validator::context::ValidationContext; use crate::validator::error::ValidationError; use crate::validator::result::ValidationResult; @@ -16,6 +18,49 @@ impl<'a> ValidationContext<'a> { Ok(true) } + pub(crate) fn schema_expects_primitive(&self, schema: &Schema, primitive: &str) -> bool { + match &schema.type_ { + None => true, // Any type is allowed + Some(SchemaTypeOrArray::Single(t)) => { + if t == primitive { + true + } else if !is_primitive_type(t) { + if primitive == "object" { + true + } else { + // Custom type - resolve recursively + if let Some(parent) = self.db.schemas.get(t) { + self.schema_expects_primitive(parent, primitive) + } else { + false + } + } + } else { + false + } + } + Some(SchemaTypeOrArray::Multiple(types)) => { + types.iter().any(|t| { + if t == primitive { + true + } else if !is_primitive_type(t) { + if primitive == "object" { + true + } else { + if let Some(parent) = self.db.schemas.get(t) { + self.schema_expects_primitive(parent, primitive) + } else { + false + } + } + } else { + false + } + }) + } + } + } + pub(crate) fn validate_strictness( &self, result: &mut ValidationResult, @@ -24,38 +69,18 @@ impl<'a> ValidationContext<'a> { return Ok(true); } - if let Some(obj) = self.instance.as_object() { - for key in obj.keys() { - if !result.evaluated_keys.contains(key) && !self.overrides.contains(key) { - result.errors.push(ValidationError { - code: "STRICT_PROPERTY_VIOLATION".to_string(), - values: Some(HashMap::from([ - ("property_name".to_string(), key.to_string()), - ])), - path: self.join_path(key), - }); - } - } - } - - if let Some(arr) = self.instance.as_array() { - for i in 0..arr.len() { - if !result.evaluated_indices.contains(&i) { - let mut item_path = self.join_path(&i.to_string()); - if let Some(child_instance) = arr.get(i) { - if let Some(obj) = child_instance.as_object() { - if let Some(id_str) = obj.get("id").and_then(|v| v.as_str()) { - item_path = self.join_path(id_str); - } - } + if self.schema_expects_primitive(self.schema, "object") || self.schema_expects_primitive(self.schema, "dict") { + if let Some(obj) = self.instance.as_object() { + for key in obj.keys() { + if !result.evaluated_keys.contains(key) && !self.overrides.contains(key) { + result.errors.push(ValidationError { + code: "STRICT_PROPERTY_VIOLATION".to_string(), + values: Some(HashMap::from([ + ("property_name".to_string(), key.to_string()), + ])), + path: self.join_path(key), + }); } - result.errors.push(ValidationError { - code: "STRICT_ITEM_VIOLATION".to_string(), - values: Some(HashMap::from([ - ("index".to_string(), i.to_string()), - ])), - path: item_path, - }); } } } diff --git a/src/validator/rules/mod.rs b/src/validator/rules/mod.rs index cf52232..81f31ee 100644 --- a/src/validator/rules/mod.rs +++ b/src/validator/rules/mod.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; pub mod array; pub mod cases; pub mod core; +pub mod dict; pub mod extensible; pub mod format; pub mod not; @@ -43,6 +44,7 @@ impl<'a> ValidationContext<'a> { // Complex Structures self.validate_object(&mut result)?; self.validate_array(&mut result)?; + self.validate_dict(&mut result)?; // Multipliers & Conditionals if !self.validate_one_of(&mut result)? { diff --git a/src/validator/rules/object.rs b/src/validator/rules/object.rs index 218ffa6..196a142 100644 --- a/src/validator/rules/object.rs +++ b/src/validator/rules/object.rs @@ -211,80 +211,8 @@ impl<'a> ValidationContext<'a> { } } - if let Some(compiled_pp) = self.schema.compiled_pattern_properties.get() { - for (compiled_re, sub_schema) in compiled_pp { - for (key, child_instance) in obj { - if compiled_re.0.is_match(key) { - let new_path = self.join_path(key); - let is_ref = match &sub_schema.type_ { - Some(crate::database::object::SchemaTypeOrArray::Single(t)) => { - !crate::database::object::is_primitive_type(t) - } - _ => false, - }; - let next_extensible = if is_ref { false } else { self.extensible }; - let derived = self.derive( - sub_schema, - child_instance, - &new_path, - HashSet::new(), - next_extensible, - false, - Some(self.instance), - ); - let item_res = derived.validate()?; - result.merge(item_res); - result.evaluated_keys.insert(key.to_string()); - } - } - } - } - if let Some(ref additional_schema) = self.schema.additional_properties { - for (key, child_instance) in obj { - let mut locally_matched = false; - if let Some(props) = &self.schema.properties - && props.contains_key(&key.to_string()) - { - locally_matched = true; - } - if !locally_matched - && let Some(compiled_pp) = self.schema.compiled_pattern_properties.get() - { - for (compiled_re, _) in compiled_pp { - if compiled_re.0.is_match(key) { - locally_matched = true; - break; - } - } - } - - if !locally_matched { - let new_path = self.join_path(key); - let is_ref = match &additional_schema.type_ { - Some(crate::database::object::SchemaTypeOrArray::Single(t)) => { - !crate::database::object::is_primitive_type(t) - } - _ => false, - }; - let next_extensible = if is_ref { false } else { self.extensible }; - - let derived = self.derive( - additional_schema, - child_instance, - &new_path, - HashSet::new(), - next_extensible, - false, - Some(self.instance), - ); - let item_res = derived.validate()?; - result.merge(item_res); - result.evaluated_keys.insert(key.to_string()); - } - } - } if let Some(ref property_names) = self.schema.property_names { for key in obj.keys() { diff --git a/src/validator/rules/polymorphism.rs b/src/validator/rules/polymorphism.rs index 93d5bfb..d1b89c7 100644 --- a/src/validator/rules/polymorphism.rs +++ b/src/validator/rules/polymorphism.rs @@ -14,7 +14,6 @@ impl<'a> ValidationContext<'a> { let conflicts = self.schema.type_.is_some() || self.schema.properties.is_some() || self.schema.required.is_some() - || self.schema.additional_properties.is_some() || self.schema.items.is_some() || self.schema.cases.is_some() || self.schema.one_of.is_some() diff --git a/src/validator/rules/string.rs b/src/validator/rules/string.rs index a222df2..ee034f7 100644 --- a/src/validator/rules/string.rs +++ b/src/validator/rules/string.rs @@ -42,6 +42,7 @@ impl<'a> ValidationContext<'a> { code: "PATTERN_VIOLATED".to_string(), values: Some(HashMap::from([ ("pattern".to_string(), self.schema.pattern.clone().unwrap_or_default()), + ("value".to_string(), s.to_string()), ])), path: self.path.to_string(), }); @@ -54,6 +55,7 @@ impl<'a> ValidationContext<'a> { code: "PATTERN_VIOLATED".to_string(), values: Some(HashMap::from([ ("pattern".to_string(), pattern.to_string()), + ("value".to_string(), s.to_string()), ])), path: self.path.to_string(), });