Compare commits

...

2 Commits

Author SHA1 Message Date
2c74d0a1a6 passing all tests 2026-03-11 17:26:45 -04:00
44be75f5d4 queryer merger test progress 2026-03-11 05:18:01 -04:00
106 changed files with 31385 additions and 19710 deletions

View File

@ -8,9 +8,11 @@ Read over this entire workflow and commit to every section of work in a task lis
Please analyze the files and directories and do not use cat, find, or the terminal to discover or read in any of these files. Analyze every file mentioned. If a directory is mentioned or a /*, please analyze the directory, every single file at its root, and recursively analyze every subdirectory and every single file in every subdirectory to capture not just critical files, but the entirety of what is requested. I state again, DO NOT just review a cherry picking of files in any folder or wildcard specified. Review 100% of all files discovered recursively!
Section 1: Documentation
Section 1: Various Documentation
- GEMINI.md at the root
- GEMINI.md at the root (JSPG doc)
- api/punc/GEMINI.md
- api/punc/generator/GEMINI.md
Section 2: Flow file for cmd interface
@ -22,7 +24,14 @@ Section 3: Source
Section 4: Test Fixtures
- Just review some of the *.json files in tests/fixtures/*
Just review some of the *.json files in fixtures/ at the root
- fixtures/allOf.json
- fixtures/ref.json
- fixtures/contains.json
- fixtures/queryer.json
- fixtures/merger.json
- fixtures/merge.json
Section 5: Build
@ -36,14 +45,19 @@ Section 7: Some PUNC Syntax
Now, review some punc type and enum source in the api project with api/ these files:
- punc/sql/tables.sql
- punc/sql/domains.sql
- punc/sql/indexes.sql
- punc/sql/functions/entity.sql
- punc/sql/functions/puncs.sql
- punc/sql/puncs/entity.sql
- punc/sql/puncs/persons.sql
- punc/sql/puncs/puncs.sql
- punc/sql/puncs/job.sql
- api/punc/sql/tables.sql
- api/punc/sql/domains.sql
- api/punc/sql/indexes.sql
- api/punc/sql/functions/entity.sql
- api/punc/sql/functions/puncs.sql
- api/punc/sql/puncs/entity.sql
- api/punc/sql/puncs/persons.sql
- api/punc/sql/puncs/puncs.sql
- api/punc/sql/puncs/job.sql
- api/contact/sql/tables.sql
- api/contact/sql/domains.sql
- api/contact/sql/indexes.sql
- api/contact/sql/domains.sql
- api/contact/sql/puncs/contacts.sql
Now you are ready to help me work on this extension.

View File

@ -44,18 +44,22 @@ JSPG implements specific extensions to the Draft 2020-12 standard to support the
* **Shape Polymorphism (`$family`)**: Auto-expands polymorphic API lists based on an abstract Descendants Graph. If `{"$family": "widget"}` is used, JSPG evaluates the JSON against every schema that `$ref`s widget.
* **Strict Matches & Depth Heuristic**: Polymorphic structures MUST match exactly **one** schema permutation. If multiple inherited struct permutations pass, JSPG applies the **Depth Heuristic Tie-Breaker**, selecting the candidate deepest in the inheritance tree.
#### B. Strict by Default & Extensibility
#### B. Dot-Notation Schema Resolution & Database Mapping
* **The Dot Convention**: When a schema represents a specific variation or shape of an underlying physical database `Type` (e.g., a "summary" of a "person"), its `$id` must adhere to a dot-notation suffix convention (e.g., `summary.person` or `full.person`).
* **Entity Resolution**: The framework (Validator, Queryer, Merger) dynamically determines the backing PostgreSQL table structure by splitting the schema's `$id` (or `$ref`) by `.` and extracting the **last segment** (`next_back()`). If the last segment matches a known Database Type (like `person`), the framework natively applies that table's inheritance rules, variations, and physical foreign keys to the schema graph, regardless of the prefix.
#### C. 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.
* **Inheritance Boundaries**: Strictness resets when crossing `$ref` boundaries. A schema extending a strict parent remains strict unless it explicitly overrides with `"extensible": true`.
#### C. Implicit Keyword Shadowing
#### D. Implicit Keyword Shadowing
* **Inheritance (`$ref` + properties)**: Unlike standard JSON Schema, when a schema uses `$ref` alongside local properties, JSPG implements **Smart Merge**. Local constraints natively take precedence over (shadow) inherited constraints for the same keyword.
* *Example*: If `entity` has `type: {const: "entity"}`, but `person` defines `type: {const: "person"}`, the local `person` const cleanly overrides the inherited one.
* **Composition (`allOf`)**: When evaluating `allOf`, standard intersection rules apply seamlessly. No shadowing occurs, meaning all constraints from all branches must pass.
#### D. Format Leniency for Empty Strings
#### E. Format Leniency for Empty Strings
To simplify frontend form validation, format validators specifically for `uuid`, `date-time`, and `email` explicitly allow empty strings (`""`), treating them as "present but unset".
---
@ -85,10 +89,36 @@ The Merger provides an automated, high-performance graph synchronization engine
The Queryer transforms Postgres into a pre-compiled Semantic Query Engine via the `jspg_query(schema_id text, cue jsonb)` API, designed to serve the exact shape of Punc responses directly via SQL.
### Core Features
* **Schema-to-SQL Compilation**: Compiles JSON Schema ASTs spanning deep arrays directly into static, pre-planned SQL multi-JOIN queries.
* **Schema-to-SQL Compilation**: Compiles JSON Schema ASTs spanning deep arrays directly into static, pre-planned SQL multi-JOIN queries. This explicitly features the `Smart Merge` evaluation engine which natively translates properties through `allOf` and `$ref` inheritances, mapping JSON fields specifically to their physical database table aliases during translation.
* **DashMap SQL Caching**: Executes compiled SQL via Postgres SPI execution, securely caching the static string compilation templates per schema permutation inside the `GLOBAL_JSPG` application memory, drastically reducing repetitive schema crawling.
* **Dynamic Filtering**: Binds parameters natively through `cue.filters` objects. Dynamically handles string formatting (e.g. parsing `uuid` or formatting date-times) and safely escapes complex combinations utilizing `ILIKE` operations correctly mapped to the originating structural table.
* **The Stem Engine**: Rather than over-fetching heavy Entity payloads and trimming them, Punc Framework Websockets depend on isolated subgraphs defined as **Stems**.
* During initialization, the generator auto-discovers graph boundaries (Stems) inside the schema tree.
* The Queryer prepares dedicated SQL execution templates tailored precisely for that exact `Stem` path (e.g. executing `get_dashboard` queried specifically for the `/owner` stem).
* These Stem outputs instantly hydrate targeted Go Bitsets, providing `O(1)` real-time routing for fractional data payloads without any application-layer overhead.
### 4. The Stem Engine
Rather than over-fetching heavy Entity payloads and trimming them, Punc Framework Websockets depend on isolated subgraphs defined as **Stems**.
A `Stem` is **not a JSON Pointer** or a physical path string (like `/properties/contacts/items/phone_number`). It is simply a declaration of an **Entity Type boundary** that exists somewhere within the compiled JSON Schema graph.
Because `pg_notify` (Beats) fire rigidly from physical Postgres tables (e.g. `{"type": "phone_number"}`), the Go Framework only ever needs to know: "Does the schema `with_contacts.person` contain the `phone_number` Entity anywhere inside its tree?"
* **Initialization:** During startup (`jspg_stems()`), the database crawls all Schemas and maps out every physical Entity Type it references. It builds a flat dictionary of `Schema ID -> [Entity Types]` (e.g. `with_contacts.person -> ["person", "contact", "phone_number", "email_address"]`).
* **Relationship Path Squashing:** When calculating nested string paths structurally to discover these boundaries, JSPG intentionally **omits** properties natively named `target` or `source` if they belong to a native database `relationship` table override. This ensures paths like `phone_numbers/contact/target` correctly register their beat resolution pattern as `phone_numbers/contact/phone_number`.
* **The Go Router**: The Golang Punc framework uses this exact mapping to register WebSocket Beat frequencies exclusively on the Entity types discovered.
* **The Queryer Execution**: When the Go framework asks JSPG to hydrate a partial `phone_number` stem for the `with_contacts.person` schema, instead of jumping through string paths, the SQL Compiler simply reaches into the Schema's AST using the `phone_number` Type string, pulls out exactly that entity's mapping rules, and returns a fully correlated `SELECT` block! This natively handles nested array properties injected via `oneOf` or array references efficiently bypassing runtime powerset expansion.
* **Performance:** These Stem execution structures are fully statically compiled via SPI and map perfectly to `O(1)` real-time routing logic on the application tier.
## 5. Testing & Execution Architecture
JSPG implements a strict separation of concerns to bypass the need to boot a full PostgreSQL cluster for unit and integration testing. Because `pgrx::spi::Spi` directly links to PostgreSQL C-headers, building the library with `cargo test` on macOS natively normally results in fatal `dyld` crashes.
To solve this, JSPG introduces the `DatabaseExecutor` trait inside `src/database/executors/`:
* **`SpiExecutor` (`pgrx.rs`)**: The production evaluator that is conditionally compiled (`#[cfg(not(test))]`). It unwraps standard `pgrx::spi` connections to the database.
* **`MockExecutor` (`mock.rs`)**: The testing evaluator that is conditionally compiled (`#[cfg(test)]`). It absorbs SQL calls and captures parameter bindings in memory without executing them.
### Universal Test Harness (`src/tests/`)
JSPG abandons the standard `cargo pgrx test` model in favor of native OS testing for a >1000x speed increase (`~0.05s` execution).
1. **JSON Fixtures**: All core interactions are defined abstractly as JSON arrays in `fixtures/`. Each file contains suites of `TestCase` objects with an `action` flag (`validate`, `merge`, `query`).
2. **`build.rs` Generator**: The build script traverses the JSON fixtures, extracts their structural identities, and generates standard `#[test]` blocks into `src/tests/fixtures.rs`.
3. **Modular Test Dispatcher**: The `src/tests/types/` module deserializes the abstract JSON test payloads into `Suite`, `Case`, and `Expect` data structures.
4. **Unit Context Execution**: When `cargo test` executes, the `Runner` feeds the JSON payloads directly into `case.execute(db)`. Because the tests run natively inside the module via `#cfg(test)`, the Rust compiler globally erases `pgrx` C-linkage, instantiates the `MockExecutor`, and allows for pure structural evaluation of complex database logic completely in memory.

View File

@ -21,22 +21,15 @@ fn to_safe_identifier(name: &str) -> String {
}
fn main() {
println!("cargo:rerun-if-changed=tests/fixtures");
println!("cargo:rerun-if-changed=fixtures");
println!("cargo:rerun-if-changed=Cargo.toml");
// File 1: src/tests/fixtures.rs for #[pg_test]
let pg_dest_path = Path::new("src/tests/fixtures.rs");
let mut pg_file = File::create(pg_dest_path).unwrap();
// File 2: tests/fixtures.rs for standard #[test] integration
let std_dest_path = Path::new("tests/fixtures.rs");
// File: src/tests/fixtures.rs for standard #[test] integration
let std_dest_path = Path::new("src/tests/fixtures.rs");
let mut std_file = File::create(std_dest_path).unwrap();
// Write headers
writeln!(std_file, "use jspg::validator::util;").unwrap();
// Walk tests/fixtures directly
let fixtures_path = "tests/fixtures";
let fixtures_path = "fixtures";
if Path::new(fixtures_path).exists() {
for entry in fs::read_dir(fixtures_path).unwrap() {
let entry = entry.unwrap();
@ -70,50 +63,30 @@ fn main() {
.unwrap()
.as_array()
.expect("Tests must be an array");
let safe_filename = to_safe_identifier(file_name);
for (t_idx, test) in tests.iter().enumerate() {
let t_obj = test.as_object().expect("Test case must be an object");
if !t_obj.contains_key("description")
|| !t_obj.contains_key("data")
|| !t_obj.contains_key("valid")
|| !t_obj.contains_key("schema_id")
{
if !t_obj.contains_key("description") {
panic!(
"File {} suite {} test {} is missing required case fields (description, data, valid, schema_id)",
"File {} suite {} test {} is missing required case fields (description)",
file_name, i, t_idx
);
}
}
// Use deterministic names: test_{filename}_{index}
let safe_filename = to_safe_identifier(file_name);
let fn_name = format!("test_{}_{}", safe_filename, i);
// Use deterministic names: test_{filename}_{suite_idx}_{test_idx}
let fn_name = format!("test_{}_{}_{}", safe_filename, i, t_idx);
// Write to src/tests.rs (PG Test)
// CARGO_MANIFEST_DIR is used to find the absolute path to fixtures at runtime
write!(
pg_file,
r#"
#[pg_test]
fn {}() {{
let path = format!("{{}}/tests/fixtures/{}.json", env!("CARGO_MANIFEST_DIR"));
crate::validator::util::run_test_file_at_index(&path, {}).unwrap();
}}
"#,
fn_name, file_name, i
)
.unwrap();
// Write to tests/tests.rs (Std Test)
// Write to src/tests/fixtures.rs (Std Test)
write!(
std_file,
r#"
#[test]
fn {}() {{
let path = format!("{{}}/tests/fixtures/{}.json", env!("CARGO_MANIFEST_DIR"));
util::run_test_file_at_index(&path, {}).unwrap();
let path = format!("{{}}/fixtures/{}.json", env!("CARGO_MANIFEST_DIR"));
crate::tests::runner::run_test_case(&path, {}, {}).unwrap();
}}
"#,
fn_name, file_name, i
fn_name, file_name, i, t_idx
)
.unwrap();
}
@ -121,4 +94,5 @@ fn {}() {{
}
}
}
}
}

View File

@ -0,0 +1,176 @@
[
{
"description": "additionalProperties validates properties not matched by properties",
"database": {
"schemas": [
{
"$id": "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
}
}
]
},
{
"description": "extensible: true with additionalProperties still validates structure",
"database": {
"schemas": [
{
"properties": {
"foo": {
"type": "string"
}
},
"extensible": true,
"additionalProperties": {
"type": "integer"
},
"$id": "additionalProperties_1_0"
}
]
},
"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
}
}
]
},
{
"description": "complex additionalProperties with object and array items",
"database": {
"schemas": [
{
"$id": "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
}
},
{
"description": "invalid non-array type",
"data": {
"type": "my_type",
"group_a": "field1"
},
"schema_id": "schema3",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

677
fixtures/allOf.json Normal file
View File

@ -0,0 +1,677 @@
[
{
"description": "allOf",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"$id": "allOf_0_0"
}
]
},
"tests": [
{
"description": "allOf",
"data": {
"foo": "baz",
"bar": 2
},
"schema_id": "allOf_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "mismatch second",
"data": {
"foo": "baz"
},
"schema_id": "allOf_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "mismatch first",
"data": {
"bar": 2
},
"schema_id": "allOf_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "wrong type",
"data": {
"foo": "baz",
"bar": "quux"
},
"schema_id": "allOf_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allOf with base schema",
"database": {
"schemas": [
{
"properties": {
"bar": {
"type": "integer"
},
"baz": {},
"foo": {
"type": "string"
}
},
"required": [
"bar"
],
"allOf": [
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
},
{
"properties": {
"baz": {
"type": "null"
}
},
"required": [
"baz"
]
}
],
"$id": "allOf_1_0"
}
]
},
"tests": [
{
"description": "valid",
"data": {
"foo": "quux",
"bar": 2,
"baz": null
},
"schema_id": "allOf_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "mismatch base schema",
"data": {
"foo": "quux",
"baz": null
},
"schema_id": "allOf_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "mismatch first allOf",
"data": {
"bar": 2,
"baz": null
},
"schema_id": "allOf_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "mismatch second allOf",
"data": {
"foo": "quux",
"bar": 2
},
"schema_id": "allOf_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "mismatch both",
"data": {
"bar": 2
},
"schema_id": "allOf_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allOf simple types",
"database": {
"schemas": [
{
"allOf": [
{
"maximum": 30
},
{
"minimum": 20
}
],
"$id": "allOf_2_0"
}
]
},
"tests": [
{
"description": "valid",
"data": 25,
"schema_id": "allOf_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "mismatch one",
"data": 35,
"schema_id": "allOf_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allOf with boolean schemas, all true",
"database": {
"schemas": [
{
"allOf": [
true,
true
],
"$id": "allOf_3_0"
}
]
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"schema_id": "allOf_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "allOf with boolean schemas, some false",
"database": {
"schemas": [
{
"allOf": [
true,
false
],
"$id": "allOf_4_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"schema_id": "allOf_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allOf with boolean schemas, all false",
"database": {
"schemas": [
{
"allOf": [
false,
false
],
"$id": "allOf_5_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"schema_id": "allOf_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allOf with one empty schema",
"database": {
"schemas": [
{
"allOf": [
{}
],
"$id": "allOf_6_0"
}
]
},
"tests": [
{
"description": "any data is valid",
"data": 1,
"schema_id": "allOf_6_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "allOf with two empty schemas",
"database": {
"schemas": [
{
"allOf": [
{},
{}
],
"$id": "allOf_7_0"
}
]
},
"tests": [
{
"description": "any data is valid",
"data": 1,
"schema_id": "allOf_7_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "allOf with the first empty schema",
"database": {
"schemas": [
{
"allOf": [
{},
{
"type": "number"
}
],
"$id": "allOf_8_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"schema_id": "allOf_8_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "string is invalid",
"data": "foo",
"schema_id": "allOf_8_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allOf with the last empty schema",
"database": {
"schemas": [
{
"allOf": [
{
"type": "number"
},
{}
],
"$id": "allOf_9_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"schema_id": "allOf_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "string is invalid",
"data": "foo",
"schema_id": "allOf_9_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "nested allOf, to check validation semantics",
"database": {
"schemas": [
{
"allOf": [
{
"allOf": [
{
"type": "null"
}
]
}
],
"$id": "allOf_10_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"schema_id": "allOf_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "anything non-null is invalid",
"data": 123,
"schema_id": "allOf_10_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in allOf",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"extensible": true,
"$id": "allOf_12_0"
}
]
},
"tests": [
{
"description": "extra property is valid",
"data": {
"foo": "baz",
"bar": 2,
"qux": 3
},
"schema_id": "allOf_12_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "strict by default with allOf properties",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"foo": {
"const": 1
}
}
},
{
"properties": {
"bar": {
"const": 2
}
}
}
],
"$id": "allOf_13_0"
}
]
},
"tests": [
{
"description": "validates merged properties",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "allOf_13_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "fails on extra property z explicitly",
"data": {
"foo": 1,
"bar": 2,
"z": 3
},
"schema_id": "allOf_13_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allOf with nested extensible: true (partial looseness)",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"foo": {
"const": 1
}
}
},
{
"extensible": true,
"properties": {
"bar": {
"const": 2
}
}
}
],
"$id": "allOf_14_0"
}
]
},
"tests": [
{
"description": "extensible subschema doesn't make root extensible if root is strict",
"data": {
"foo": 1,
"bar": 2,
"z": 3
},
"schema_id": "allOf_14_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "strictness: allOf composition with strict refs",
"database": {
"schemas": [
{
"allOf": [
{
"$ref": "partA"
},
{
"$ref": "partB"
}
],
"$id": "allOf_15_0"
},
{
"$id": "partA",
"properties": {
"id": {
"type": "string"
}
}
},
{
"$id": "partB",
"properties": {
"name": {
"type": "string"
}
}
}
]
},
"tests": [
{
"description": "merged instance is valid",
"data": {
"id": "1",
"name": "Me"
},
"schema_id": "allOf_15_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "extra property is invalid (root is strict)",
"data": {
"id": "1",
"name": "Me",
"extra": 1
},
"schema_id": "allOf_15_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "partA mismatch is invalid",
"data": {
"id": 1,
"name": "Me"
},
"schema_id": "allOf_15_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

197
fixtures/booleanSchema.json Normal file
View File

@ -0,0 +1,197 @@
[
{
"description": "boolean schema 'true'",
"database": {
"schemas": [
{
"$id": "booleanSchema_0_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "string is valid",
"data": "foo",
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boolean true is valid",
"data": true,
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boolean false is valid",
"data": false,
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "null is valid",
"data": null,
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object is valid",
"data": {
"foo": "bar"
},
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array is valid",
"data": [
"foo"
],
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty array is valid",
"data": [],
"schema_id": "booleanSchema_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "boolean schema 'false'",
"database": {
"schemas": [
{
"not": {},
"$id": "booleanSchema_1_0"
}
]
},
"tests": [
{
"description": "number is invalid",
"data": 1,
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "string is invalid",
"data": "foo",
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "boolean true is invalid",
"data": true,
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "boolean false is invalid",
"data": false,
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is invalid",
"data": null,
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "object is invalid",
"data": {
"foo": "bar"
},
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is invalid",
"data": {},
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "array is invalid",
"data": [
"foo"
],
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "booleanSchema_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

818
fixtures/const.json Normal file
View File

@ -0,0 +1,818 @@
[
{
"description": "const validation",
"database": {
"schemas": [
{
"const": 2,
"$id": "const_0_0"
}
]
},
"tests": [
{
"description": "same value is valid",
"data": 2,
"schema_id": "const_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "another value is invalid",
"data": 5,
"schema_id": "const_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "another type is invalid",
"data": "a",
"schema_id": "const_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with object",
"database": {
"schemas": [
{
"const": {
"foo": "bar",
"baz": "bax"
},
"properties": {
"foo": {},
"baz": {}
},
"$id": "const_1_0"
}
]
},
"tests": [
{
"description": "same object is valid",
"data": {
"foo": "bar",
"baz": "bax"
},
"schema_id": "const_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "same object with different property order is valid",
"data": {
"baz": "bax",
"foo": "bar"
},
"schema_id": "const_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "another object is invalid",
"data": {
"foo": "bar"
},
"schema_id": "const_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "another type is invalid",
"data": [
1,
2
],
"schema_id": "const_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with array",
"database": {
"schemas": [
{
"const": [
{
"foo": "bar"
}
],
"$id": "const_2_0"
}
]
},
"tests": [
{
"description": "same array is valid",
"data": [
{
"foo": "bar"
}
],
"schema_id": "const_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "another array item is invalid",
"data": [
2
],
"schema_id": "const_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "array with additional items is invalid",
"data": [
1,
2,
3
],
"schema_id": "const_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with null",
"database": {
"schemas": [
{
"const": null,
"$id": "const_3_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"schema_id": "const_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "not null is invalid",
"data": 0,
"schema_id": "const_3_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with false does not match 0",
"database": {
"schemas": [
{
"const": false,
"$id": "const_4_0"
}
]
},
"tests": [
{
"description": "false is valid",
"data": false,
"schema_id": "const_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "integer zero is invalid",
"data": 0,
"schema_id": "const_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "float zero is invalid",
"data": 0,
"schema_id": "const_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with true does not match 1",
"database": {
"schemas": [
{
"const": true,
"$id": "const_5_0"
}
]
},
"tests": [
{
"description": "true is valid",
"data": true,
"schema_id": "const_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "integer one is invalid",
"data": 1,
"schema_id": "const_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "float one is invalid",
"data": 1,
"schema_id": "const_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with [false] does not match [0]",
"database": {
"schemas": [
{
"const": [
false
],
"$id": "const_6_0"
}
]
},
"tests": [
{
"description": "[false] is valid",
"data": [
false
],
"schema_id": "const_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "[0] is invalid",
"data": [
0
],
"schema_id": "const_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "[0.0] is invalid",
"data": [
0
],
"schema_id": "const_6_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with [true] does not match [1]",
"database": {
"schemas": [
{
"const": [
true
],
"$id": "const_7_0"
}
]
},
"tests": [
{
"description": "[true] is valid",
"data": [
true
],
"schema_id": "const_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "[1] is invalid",
"data": [
1
],
"schema_id": "const_7_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "[1.0] is invalid",
"data": [
1
],
"schema_id": "const_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with {\"a\": false} does not match {\"a\": 0}",
"database": {
"schemas": [
{
"const": {
"a": false
},
"$id": "const_8_0"
}
]
},
"tests": [
{
"description": "{\"a\": false} is valid",
"data": {
"a": false
},
"schema_id": "const_8_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "{\"a\": 0} is invalid",
"data": {
"a": 0
},
"schema_id": "const_8_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "{\"a\": 0.0} is invalid",
"data": {
"a": 0
},
"schema_id": "const_8_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with {\"a\": true} does not match {\"a\": 1}",
"database": {
"schemas": [
{
"const": {
"a": true
},
"$id": "const_9_0"
}
]
},
"tests": [
{
"description": "{\"a\": true} is valid",
"data": {
"a": true
},
"schema_id": "const_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "{\"a\": 1} is invalid",
"data": {
"a": 1
},
"schema_id": "const_9_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "{\"a\": 1.0} is invalid",
"data": {
"a": 1
},
"schema_id": "const_9_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with 0 does not match other zero-like types",
"database": {
"schemas": [
{
"const": 0,
"$id": "const_10_0"
}
]
},
"tests": [
{
"description": "false is invalid",
"data": false,
"schema_id": "const_10_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "integer zero is valid",
"data": 0,
"schema_id": "const_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "float zero is valid",
"data": 0,
"schema_id": "const_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty object is invalid",
"data": {},
"schema_id": "const_10_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "const_10_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty string is invalid",
"data": "",
"schema_id": "const_10_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "const with 1 does not match true",
"database": {
"schemas": [
{
"const": 1,
"$id": "const_11_0"
}
]
},
"tests": [
{
"description": "true is invalid",
"data": true,
"schema_id": "const_11_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "integer one is valid",
"data": 1,
"schema_id": "const_11_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "float one is valid",
"data": 1,
"schema_id": "const_11_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "const with -2.0 matches integer and float types",
"database": {
"schemas": [
{
"const": -2,
"$id": "const_12_0"
}
]
},
"tests": [
{
"description": "integer -2 is valid",
"data": -2,
"schema_id": "const_12_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "integer 2 is invalid",
"data": 2,
"schema_id": "const_12_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "float -2.0 is valid",
"data": -2,
"schema_id": "const_12_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "float 2.0 is invalid",
"data": 2,
"schema_id": "const_12_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "float -2.00001 is invalid",
"data": -2.00001,
"schema_id": "const_12_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "float and integers are equal up to 64-bit representation limits",
"database": {
"schemas": [
{
"const": 9007199254740992,
"$id": "const_13_0"
}
]
},
"tests": [
{
"description": "integer is valid",
"data": 9007199254740992,
"schema_id": "const_13_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "integer minus one is invalid",
"data": 9007199254740991,
"schema_id": "const_13_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "float is valid",
"data": 9007199254740992,
"schema_id": "const_13_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "float minus one is invalid",
"data": 9007199254740991,
"schema_id": "const_13_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "nul characters in strings",
"database": {
"schemas": [
{
"const": "hello\u0000there",
"$id": "const_14_0"
}
]
},
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"schema_id": "const_14_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"schema_id": "const_14_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "characters with the same visual representation but different codepoint",
"database": {
"schemas": [
{
"const": "μ",
"$comment": "U+03BC",
"$id": "const_15_0"
}
]
},
"tests": [
{
"description": "character uses the same codepoint",
"data": "μ",
"comment": "U+03BC",
"schema_id": "const_15_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "character looks the same but uses a different codepoint",
"data": "µ",
"comment": "U+00B5",
"schema_id": "const_15_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "characters with the same visual representation, but different number of codepoints",
"database": {
"schemas": [
{
"const": "ä",
"$comment": "U+00E4",
"$id": "const_16_0"
}
]
},
"tests": [
{
"description": "character uses the same codepoint",
"data": "ä",
"comment": "U+00E4",
"schema_id": "const_16_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "character looks the same but uses combining marks",
"data": "ä",
"comment": "a, U+0308",
"schema_id": "const_16_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in const object match",
"database": {
"schemas": [
{
"const": {
"a": 1
},
"extensible": true,
"$id": "const_17_0"
}
]
},
"tests": [
{
"description": "extra property ignored during strict check, but const check still applies (mismatch)",
"data": {
"a": 1,
"b": 2
},
"schema_id": "const_17_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "extra property match in const (this is effectively impossible if data has extra props not in const, it implicitly fails const check unless we assume const check ignored extra props? No, const check is strict. So this test is just to show strictness passes.)",
"data": {
"a": 1
},
"schema_id": "const_17_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

418
fixtures/contains.json Normal file
View File

@ -0,0 +1,418 @@
[
{
"description": "contains keyword validation",
"database": {
"schemas": [
{
"contains": {
"minimum": 5
},
"items": true,
"$id": "contains_0_0"
}
]
},
"tests": [
{
"description": "array with item matching schema (5) is valid (items: true)",
"data": [
3,
4,
5
],
"schema_id": "contains_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array with item matching schema (6) is valid (items: true)",
"data": [
3,
4,
6
],
"schema_id": "contains_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array with two items matching schema (5, 6) is valid (items: true)",
"data": [
3,
4,
5,
6
],
"schema_id": "contains_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array without items matching schema is invalid",
"data": [
2,
3,
4
],
"schema_id": "contains_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "contains_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "not array is valid",
"data": {},
"schema_id": "contains_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "contains keyword with const keyword",
"database": {
"schemas": [
{
"contains": {
"const": 5
},
"items": true,
"$id": "contains_1_0"
}
]
},
"tests": [
{
"description": "array with item 5 is valid (items: true)",
"data": [
3,
4,
5
],
"schema_id": "contains_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array with two items 5 is valid (items: true)",
"data": [
3,
4,
5,
5
],
"schema_id": "contains_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array without item 5 is invalid",
"data": [
1,
2,
3,
4
],
"schema_id": "contains_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "contains keyword with boolean schema true",
"database": {
"schemas": [
{
"contains": true,
"$id": "contains_2_0"
}
]
},
"tests": [
{
"description": "any non-empty array is valid",
"data": [
"foo"
],
"schema_id": "contains_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "contains_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "contains keyword with boolean schema false",
"database": {
"schemas": [
{
"contains": false,
"$id": "contains_3_0"
}
]
},
"tests": [
{
"description": "any non-empty array is invalid",
"data": [
"foo"
],
"schema_id": "contains_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "contains_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "non-arrays are valid",
"data": "contains does not apply to strings",
"schema_id": "contains_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "items + contains",
"database": {
"schemas": [
{
"items": {
"multipleOf": 2
},
"contains": {
"multipleOf": 3
},
"$id": "contains_4_0"
}
]
},
"tests": [
{
"description": "matches items, does not match contains",
"data": [
2,
4,
8
],
"schema_id": "contains_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "does not match items, matches contains",
"data": [
3,
6,
9
],
"schema_id": "contains_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "matches both items and contains",
"data": [
6,
12
],
"schema_id": "contains_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "matches neither items nor contains",
"data": [
1,
5
],
"schema_id": "contains_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "contains with false if subschema",
"database": {
"schemas": [
{
"contains": {
"if": false,
"else": true
},
"$id": "contains_5_0"
}
]
},
"tests": [
{
"description": "any non-empty array is valid",
"data": [
"foo"
],
"schema_id": "contains_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "contains_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "contains with null instance elements",
"database": {
"schemas": [
{
"contains": {
"type": "null"
},
"$id": "contains_6_0"
}
]
},
"tests": [
{
"description": "allows null items",
"data": [
null
],
"schema_id": "contains_6_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "extensible: true allows non-matching items in contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"extensible": true,
"$id": "contains_7_0"
}
]
},
"tests": [
{
"description": "extra items acceptable",
"data": [
1,
2
],
"schema_id": "contains_7_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "strict by default: non-matching items in contains are invalid",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"$id": "contains_8_0"
}
]
},
"tests": [
{
"description": "extra items cause failure",
"data": [
1,
2
],
"schema_id": "contains_8_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "only matching items is valid",
"data": [
1,
1
],
"schema_id": "contains_8_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

232
fixtures/content.json Normal file
View File

@ -0,0 +1,232 @@
[
{
"description": "validation of string-encoded content based on media type",
"database": {
"schemas": [
{
"contentMediaType": "application/json",
"$id": "content_0_0"
}
]
},
"tests": [
{
"description": "a valid JSON document",
"data": "{\"foo\": \"bar\"}",
"schema_id": "content_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an invalid JSON document; validates true",
"data": "{:}",
"schema_id": "content_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores non-strings",
"data": 100,
"schema_id": "content_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "validation of binary string-encoding",
"database": {
"schemas": [
{
"contentEncoding": "base64",
"$id": "content_1_0"
}
]
},
"tests": [
{
"description": "a valid base64 string",
"data": "eyJmb28iOiAiYmFyIn0K",
"schema_id": "content_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an invalid base64 string (% is not a valid character); validates true",
"data": "eyJmb28iOi%iYmFyIn0K",
"schema_id": "content_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores non-strings",
"data": 100,
"schema_id": "content_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "validation of binary-encoded media type documents",
"database": {
"schemas": [
{
"contentMediaType": "application/json",
"contentEncoding": "base64",
"$id": "content_2_0"
}
]
},
"tests": [
{
"description": "a valid base64-encoded JSON document",
"data": "eyJmb28iOiAiYmFyIn0K",
"schema_id": "content_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a validly-encoded invalid JSON document; validates true",
"data": "ezp9Cg==",
"schema_id": "content_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an invalid base64 string that is valid JSON; validates true",
"data": "{}",
"schema_id": "content_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores non-strings",
"data": 100,
"schema_id": "content_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "validation of binary-encoded media type documents with schema",
"database": {
"schemas": [
{
"contentMediaType": "application/json",
"contentEncoding": "base64",
"contentSchema": {
"type": "object",
"required": [
"foo"
],
"properties": {
"foo": {
"type": "string"
},
"boo": {
"type": "integer"
}
}
},
"$id": "content_3_0"
}
]
},
"tests": [
{
"description": "a valid base64-encoded JSON document",
"data": "eyJmb28iOiAiYmFyIn0K",
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "another valid base64-encoded JSON document",
"data": "eyJib28iOiAyMCwgImZvbyI6ICJiYXoifQ==",
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an invalid base64-encoded JSON document; validates true",
"data": "eyJib28iOiAyMH0=",
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an empty object as a base64-encoded JSON document; validates true",
"data": "e30=",
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an empty array as a base64-encoded JSON document",
"data": "W10=",
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a validly-encoded invalid JSON document; validates true",
"data": "ezp9Cg==",
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an invalid base64 string that is valid JSON; validates true",
"data": "{}",
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores non-strings",
"data": 100,
"schema_id": "content_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

748
fixtures/dependencies.json Normal file
View File

@ -0,0 +1,748 @@
[
{
"description": "single dependency (required)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema1",
"dependencies": {
"bar": [
"foo"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "neither",
"data": {},
"schema_id": "schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "nondependant",
"data": {
"foo": 1
},
"schema_id": "schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "with dependency",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "missing dependency",
"data": {
"bar": 2
},
"schema_id": "schema1",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores arrays",
"data": [
"bar"
],
"schema_id": "schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores strings",
"data": "foobar",
"schema_id": "schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "schema1",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "empty dependents",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema2",
"dependencies": {
"bar": []
},
"extensible": true
}
]
},
"tests": [
{
"description": "empty object",
"data": {},
"schema_id": "schema2",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with one property",
"data": {
"bar": 2
},
"schema_id": "schema2",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "non-object is valid",
"data": 1,
"schema_id": "schema2",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "multiple dependents required",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema3",
"dependencies": {
"quux": [
"foo",
"bar"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "neither",
"data": {},
"schema_id": "schema3",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "nondependants",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "schema3",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "with dependencies",
"data": {
"foo": 1,
"bar": 2,
"quux": 3
},
"schema_id": "schema3",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "missing dependency",
"data": {
"foo": 1,
"quux": 2
},
"schema_id": "schema3",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "missing other dependency",
"data": {
"bar": 1,
"quux": 2
},
"schema_id": "schema3",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "missing both dependencies",
"data": {
"quux": 1
},
"schema_id": "schema3",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "dependencies with escaped characters",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema4",
"dependencies": {
"foo\nbar": [
"foo\rbar"
],
"foo\"bar": [
"foo'bar"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "CRLF",
"data": {
"foo\nbar": 1,
"foo\rbar": 2
},
"schema_id": "schema4",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "quoted quotes",
"data": {
"foo'bar": 1,
"foo\"bar": 2
},
"schema_id": "schema4",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "CRLF missing dependent",
"data": {
"foo\nbar": 1,
"foo": 2
},
"schema_id": "schema4",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "quoted quotes missing dependent",
"data": {
"foo\"bar": 2
},
"schema_id": "schema4",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in dependentRequired",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema5",
"dependencies": {
"bar": [
"foo"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "extra property is valid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"schema_id": "schema5",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "single dependency (schemas, STRICT)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema1",
"properties": {
"foo": true,
"bar": true
},
"dependencies": {
"bar": {
"properties": {
"foo": {
"type": "integer"
},
"bar": {
"type": "integer"
}
}
}
}
}
]
},
"tests": [
{
"description": "valid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "no dependency",
"data": {
"foo": "quux"
},
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "wrong type",
"data": {
"foo": "quux",
"bar": 2
},
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "wrong type other",
"data": {
"foo": 2,
"bar": "quux"
},
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "wrong type both",
"data": {
"foo": "quux",
"bar": "quux"
},
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores arrays (invalid in strict mode)",
"data": [
"bar"
],
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "STRICT_ITEM_VIOLATION"
}
]
}
},
{
"description": "ignores strings",
"data": "foobar",
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "schema_schema1",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "single dependency (schemas, EXTENSIBLE)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema2",
"properties": {
"foo": true,
"bar": true
},
"dependencies": {
"bar": {
"properties": {
"foo": {
"type": "integer"
},
"bar": {
"type": "integer"
}
}
}
},
"extensible": true
}
]
},
"tests": [
{
"description": "ignores arrays (valid in extensible mode)",
"data": [
"bar"
],
"schema_id": "schema_schema2",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "boolean subschemas",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema3",
"properties": {
"foo": true,
"bar": true
},
"dependencies": {
"foo": true,
"bar": false
}
}
]
},
"tests": [
{
"description": "object with property having schema true is valid",
"data": {
"foo": 1
},
"schema_id": "schema_schema3",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with property having schema false is invalid",
"data": {
"bar": 2
},
"schema_id": "schema_schema3",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "object with both properties is invalid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "schema_schema3",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "schema_schema3",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "dependencies with escaped characters",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema4",
"properties": {
"foo\tbar": true,
"foo'bar": true,
"a": true,
"b": true,
"c": true
},
"dependencies": {
"foo\tbar": {
"minProperties": 4,
"extensible": true
},
"foo'bar": {
"required": [
"foo\"bar"
]
}
}
}
]
},
"tests": [
{
"description": "quoted tab",
"data": {
"foo\tbar": 1,
"a": 2,
"b": 3,
"c": 4
},
"schema_id": "schema_schema4",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "quoted quote",
"data": {
"foo'bar": {
"foo\"bar": 1
}
},
"schema_id": "schema_schema4",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "quoted tab invalid under dependent schema",
"data": {
"foo\tbar": 1,
"a": 2
},
"schema_id": "schema_schema4",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "quoted quote invalid under dependent schema",
"data": {
"foo'bar": 1
},
"schema_id": "schema_schema4",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "dependent subschema incompatible with root (STRICT)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema5",
"properties": {
"foo": {},
"baz": true
},
"dependencies": {
"foo": {
"properties": {
"bar": {}
}
}
}
}
]
},
"tests": [
{
"description": "matches root",
"data": {
"foo": 1
},
"schema_id": "schema_schema5",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "matches dependency (invalid in strict mode - bar not allowed if foo missing)",
"data": {
"bar": 1
},
"schema_id": "schema_schema5",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "STRICT_PROPERTY_VIOLATION"
}
]
}
},
{
"description": "matches both",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "schema_schema5",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "no dependency",
"data": {
"baz": 1
},
"schema_id": "schema_schema5",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "dependent subschema incompatible with root (EXTENSIBLE)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema6",
"properties": {
"foo": {},
"baz": true
},
"dependencies": {
"foo": {
"properties": {
"bar": {}
},
"additionalProperties": false
}
},
"extensible": true
}
]
},
"tests": [
{
"description": "matches dependency (valid in extensible mode)",
"data": {
"bar": 1
},
"schema_id": "schema_schema6",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

163
fixtures/emptyString.json Normal file
View File

@ -0,0 +1,163 @@
[
{
"description": "empty string is valid for all types (except const)",
"database": {
"schemas": [
{
"properties": {
"obj": {
"type": "object"
},
"arr": {
"type": "array"
},
"str": {
"type": "string"
},
"int": {
"type": "integer"
},
"num": {
"type": "number"
},
"bool": {
"type": "boolean"
},
"nul": {
"type": "null"
},
"fmt": {
"type": "string",
"format": "uuid"
},
"con": {
"const": "value"
},
"con_empty": {
"const": ""
}
},
"$id": "emptyString_0_0"
}
]
},
"tests": [
{
"description": "empty string valid for object",
"data": {
"obj": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string valid for array",
"data": {
"arr": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string valid for string",
"data": {
"str": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string valid for integer",
"data": {
"int": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string valid for number",
"data": {
"num": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string valid for boolean",
"data": {
"bool": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string valid for null",
"data": {
"nul": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string valid for format",
"data": {
"fmt": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty string INVALID for const (unless const is empty string)",
"data": {
"con": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "CONST_VIOLATED",
"path": "/con"
}
]
}
},
{
"description": "empty string VALID for const if const IS empty string",
"data": {
"con_empty": ""
},
"schema_id": "emptyString_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

736
fixtures/enum.json Normal file
View File

@ -0,0 +1,736 @@
[
{
"description": "simple enum validation",
"database": {
"schemas": [
{
"enum": [
1,
2,
3
],
"$id": "enum_0_0"
}
]
},
"tests": [
{
"description": "one of the enum is valid",
"data": 1,
"schema_id": "enum_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "something else is invalid",
"data": 4,
"schema_id": "enum_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "heterogeneous enum validation",
"database": {
"schemas": [
{
"enum": [
6,
"foo",
[],
true,
{
"foo": 12
}
],
"properties": {
"foo": {}
},
"$id": "enum_1_0"
}
]
},
"tests": [
{
"description": "one of the enum is valid",
"data": [],
"schema_id": "enum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "something else is invalid",
"data": null,
"schema_id": "enum_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "objects are deep compared",
"data": {
"foo": false
},
"schema_id": "enum_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "valid object matches",
"data": {
"foo": 12
},
"schema_id": "enum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "extra properties in object is invalid",
"data": {
"foo": 12,
"boo": 42
},
"schema_id": "enum_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "heterogeneous enum-with-null validation",
"database": {
"schemas": [
{
"enum": [
6,
null
],
"$id": "enum_2_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"schema_id": "enum_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "number is valid",
"data": 6,
"schema_id": "enum_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "something else is invalid",
"data": "test",
"schema_id": "enum_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "enums in properties",
"database": {
"schemas": [
{
"type": "object",
"properties": {
"foo": {
"enum": [
"foo"
]
},
"bar": {
"enum": [
"bar"
]
}
},
"required": [
"bar"
],
"$id": "enum_3_0"
}
]
},
"tests": [
{
"description": "both properties are valid",
"data": {
"foo": "foo",
"bar": "bar"
},
"schema_id": "enum_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "wrong foo value",
"data": {
"foo": "foot",
"bar": "bar"
},
"schema_id": "enum_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "wrong bar value",
"data": {
"foo": "foo",
"bar": "bart"
},
"schema_id": "enum_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "missing optional property is valid",
"data": {
"bar": "bar"
},
"schema_id": "enum_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "missing required property is invalid",
"data": {
"foo": "foo"
},
"schema_id": "enum_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "missing all properties is invalid",
"data": {},
"schema_id": "enum_3_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "enum with escaped characters",
"database": {
"schemas": [
{
"enum": [
"foo\nbar",
"foo\rbar"
],
"$id": "enum_4_0"
}
]
},
"tests": [
{
"description": "member 1 is valid",
"data": "foo\nbar",
"schema_id": "enum_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "member 2 is valid",
"data": "foo\rbar",
"schema_id": "enum_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "another string is invalid",
"data": "abc",
"schema_id": "enum_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "enum with false does not match 0",
"database": {
"schemas": [
{
"enum": [
false
],
"$id": "enum_5_0"
}
]
},
"tests": [
{
"description": "false is valid",
"data": false,
"schema_id": "enum_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "integer zero is invalid",
"data": 0,
"schema_id": "enum_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "float zero is invalid",
"data": 0,
"schema_id": "enum_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "enum with [false] does not match [0]",
"database": {
"schemas": [
{
"enum": [
[
false
]
],
"$id": "enum_6_0"
}
]
},
"tests": [
{
"description": "[false] is valid",
"data": [
false
],
"schema_id": "enum_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "[0] is invalid",
"data": [
0
],
"schema_id": "enum_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "[0.0] is invalid",
"data": [
0
],
"schema_id": "enum_6_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "enum with true does not match 1",
"database": {
"schemas": [
{
"enum": [
true
],
"$id": "enum_7_0"
}
]
},
"tests": [
{
"description": "true is valid",
"data": true,
"schema_id": "enum_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "integer one is invalid",
"data": 1,
"schema_id": "enum_7_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "float one is invalid",
"data": 1,
"schema_id": "enum_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "enum with [true] does not match [1]",
"database": {
"schemas": [
{
"enum": [
[
true
]
],
"$id": "enum_8_0"
}
]
},
"tests": [
{
"description": "[true] is valid",
"data": [
true
],
"schema_id": "enum_8_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "[1] is invalid",
"data": [
1
],
"schema_id": "enum_8_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "[1.0] is invalid",
"data": [
1
],
"schema_id": "enum_8_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "enum with 0 does not match false",
"database": {
"schemas": [
{
"enum": [
0
],
"$id": "enum_9_0"
}
]
},
"tests": [
{
"description": "false is invalid",
"data": false,
"schema_id": "enum_9_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "integer zero is valid",
"data": 0,
"schema_id": "enum_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "float zero is valid",
"data": 0,
"schema_id": "enum_9_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "enum with [0] does not match [false]",
"database": {
"schemas": [
{
"enum": [
[
0
]
],
"$id": "enum_10_0"
}
]
},
"tests": [
{
"description": "[false] is invalid",
"data": [
false
],
"schema_id": "enum_10_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "[0] is valid",
"data": [
0
],
"schema_id": "enum_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "[0.0] is valid",
"data": [
0
],
"schema_id": "enum_10_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "enum with 1 does not match true",
"database": {
"schemas": [
{
"enum": [
1
],
"$id": "enum_11_0"
}
]
},
"tests": [
{
"description": "true is invalid",
"data": true,
"schema_id": "enum_11_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "integer one is valid",
"data": 1,
"schema_id": "enum_11_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "float one is valid",
"data": 1,
"schema_id": "enum_11_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "enum with [1] does not match [true]",
"database": {
"schemas": [
{
"enum": [
[
1
]
],
"$id": "enum_12_0"
}
]
},
"tests": [
{
"description": "[true] is invalid",
"data": [
true
],
"schema_id": "enum_12_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "[1] is valid",
"data": [
1
],
"schema_id": "enum_12_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "[1.0] is valid",
"data": [
1
],
"schema_id": "enum_12_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "nul characters in strings",
"database": {
"schemas": [
{
"enum": [
"hello\u0000there"
],
"$id": "enum_13_0"
}
]
},
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"schema_id": "enum_13_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"schema_id": "enum_13_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in enum object match",
"database": {
"schemas": [
{
"enum": [
{
"foo": 1
}
],
"extensible": true,
"$id": "enum_14_0"
}
]
},
"tests": [
{
"description": "extra property ignored during strict check, but enum check still applies (mismatch here)",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "enum_14_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "extra property ignored during strict check, enum match succeeds",
"data": {
"foo": 1
},
"schema_id": "enum_14_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

View File

@ -0,0 +1,51 @@
[
{
"description": "exclusiveMaximum validation",
"database": {
"schemas": [
{
"exclusiveMaximum": 3,
"$id": "exclusiveMaximum_0_0"
}
]
},
"tests": [
{
"description": "below the exclusiveMaximum is valid",
"data": 2.2,
"schema_id": "exclusiveMaximum_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point is invalid",
"data": 3,
"schema_id": "exclusiveMaximum_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "above the exclusiveMaximum is invalid",
"data": 3.5,
"schema_id": "exclusiveMaximum_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-numbers",
"data": "x",
"schema_id": "exclusiveMaximum_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

View File

@ -0,0 +1,51 @@
[
{
"description": "exclusiveMinimum validation",
"database": {
"schemas": [
{
"exclusiveMinimum": 1.1,
"$id": "exclusiveMinimum_0_0"
}
]
},
"tests": [
{
"description": "above the exclusiveMinimum is valid",
"data": 1.2,
"schema_id": "exclusiveMinimum_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point is invalid",
"data": 1.1,
"schema_id": "exclusiveMinimum_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "below the exclusiveMinimum is invalid",
"data": 0.6,
"schema_id": "exclusiveMinimum_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-numbers",
"data": "x",
"schema_id": "exclusiveMinimum_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

217
fixtures/families.json Normal file
View File

@ -0,0 +1,217 @@
[
{
"description": "Entity families via pure $ref graph",
"database": {
"types": [
{
"name": "entity",
"variations": [
"entity",
"organization",
"person"
],
"schemas": [
{
"$id": "entity",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
{
"$id": "light.entity",
"$ref": "entity"
}
]
},
{
"name": "organization",
"variations": [
"organization",
"person"
],
"schemas": [
{
"$id": "organization",
"$ref": "entity",
"properties": {
"name": {
"type": "string"
}
}
}
]
},
{
"name": "person",
"variations": [
"person"
],
"schemas": [
{
"$id": "person",
"$ref": "organization",
"properties": {
"first_name": {
"type": "string"
}
}
},
{
"$id": "light.person",
"$ref": "light.entity"
}
]
}
],
"puncs": [
{
"name": "get_entities",
"schemas": [
{
"$id": "get_entities.response",
"$family": "entity"
}
]
},
{
"name": "get_light_entities",
"schemas": [
{
"$id": "get_light_entities.response",
"$family": "light.entity"
}
]
}
]
},
"tests": [
{
"description": "Family matches base entity",
"schema_id": "get_entities.response",
"data": {
"id": "1",
"type": "entity"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Family matches descendant person",
"schema_id": "get_entities.response",
"data": {
"id": "2",
"type": "person",
"name": "ACME",
"first_name": "John"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Graph family matches light.entity",
"schema_id": "get_light_entities.response",
"data": {
"id": "3",
"type": "entity"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Graph family matches light.person (because it $refs light.entity)",
"schema_id": "get_light_entities.response",
"data": {
"id": "4",
"type": "person"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Graph family excludes organization (missing light. schema that $refs light.entity)",
"schema_id": "get_light_entities.response",
"data": {
"id": "5",
"type": "organization",
"name": "ACME"
},
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "FAMILY_MISMATCH",
"path": ""
}
]
}
}
]
},
{
"description": "Ad-hoc non-entity families (using normal json-schema object structures)",
"database": {
"puncs": [
{
"name": "get_widgets",
"schemas": [
{
"$id": "widget",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"widget_type": {
"type": "string"
}
}
},
{
"$id": "special_widget",
"$ref": "widget",
"properties": {
"special_feature": {
"type": "string"
}
}
},
{
"$id": "get_widgets.response",
"$family": "widget"
}
]
}
]
},
"tests": [
{
"description": "Ad-hoc family matches strictly by shape (no magic variations for base schemas)",
"schema_id": "get_widgets.response",
"data": {
"id": "1",
"widget_type": "special",
"special_feature": "yes"
},
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

5456
fixtures/format.json Normal file

File diff suppressed because it is too large Load Diff

594
fixtures/if-then-else.json Normal file
View File

@ -0,0 +1,594 @@
[
{
"description": "ignore if without then or else",
"database": {
"schemas": [
{
"if": {
"const": 0
},
"$id": "if-then-else_0_0"
}
]
},
"tests": [
{
"description": "valid when valid against lone if",
"data": 0,
"schema_id": "if-then-else_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "valid when invalid against lone if",
"data": "hello",
"schema_id": "if-then-else_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "ignore then without if",
"database": {
"schemas": [
{
"then": {
"const": 0
},
"$id": "if-then-else_1_0"
}
]
},
"tests": [
{
"description": "valid when valid against lone then",
"data": 0,
"schema_id": "if-then-else_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "valid when invalid against lone then",
"data": "hello",
"schema_id": "if-then-else_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "ignore else without if",
"database": {
"schemas": [
{
"else": {
"const": 0
},
"$id": "if-then-else_2_0"
}
]
},
"tests": [
{
"description": "valid when valid against lone else",
"data": 0,
"schema_id": "if-then-else_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "valid when invalid against lone else",
"data": "hello",
"schema_id": "if-then-else_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "if and then without else",
"database": {
"schemas": [
{
"if": {
"exclusiveMaximum": 0
},
"then": {
"minimum": -10
},
"$id": "if-then-else_3_0"
}
]
},
"tests": [
{
"description": "valid through then",
"data": -1,
"schema_id": "if-then-else_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid through then",
"data": -100,
"schema_id": "if-then-else_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "valid when if test fails",
"data": 3,
"schema_id": "if-then-else_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "if and else without then",
"database": {
"schemas": [
{
"if": {
"exclusiveMaximum": 0
},
"else": {
"multipleOf": 2
},
"$id": "if-then-else_4_0"
}
]
},
"tests": [
{
"description": "valid when if test passes",
"data": -1,
"schema_id": "if-then-else_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "valid through else",
"data": 4,
"schema_id": "if-then-else_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid through else",
"data": 3,
"schema_id": "if-then-else_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "validate against correct branch, then vs else",
"database": {
"schemas": [
{
"if": {
"exclusiveMaximum": 0
},
"then": {
"minimum": -10
},
"else": {
"multipleOf": 2
},
"$id": "if-then-else_5_0"
}
]
},
"tests": [
{
"description": "valid through then",
"data": -1,
"schema_id": "if-then-else_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid through then",
"data": -100,
"schema_id": "if-then-else_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "valid through else",
"data": 4,
"schema_id": "if-then-else_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid through else",
"data": 3,
"schema_id": "if-then-else_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "non-interference across combined schemas",
"database": {
"schemas": [
{
"allOf": [
{
"if": {
"exclusiveMaximum": 0
}
},
{
"then": {
"minimum": -10
}
},
{
"else": {
"multipleOf": 2
}
}
],
"$id": "if-then-else_6_0"
}
]
},
"tests": [
{
"description": "valid, but would have been invalid through then",
"data": -100,
"schema_id": "if-then-else_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "valid, but would have been invalid through else",
"data": 3,
"schema_id": "if-then-else_6_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "if with boolean schema true",
"database": {
"schemas": [
{
"if": true,
"then": {
"const": "then"
},
"else": {
"const": "else"
},
"$id": "if-then-else_7_0"
}
]
},
"tests": [
{
"description": "boolean schema true in if always chooses the then path (valid)",
"data": "then",
"schema_id": "if-then-else_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boolean schema true in if always chooses the then path (invalid)",
"data": "else",
"schema_id": "if-then-else_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "if with boolean schema false",
"database": {
"schemas": [
{
"if": false,
"then": {
"const": "then"
},
"else": {
"const": "else"
},
"$id": "if-then-else_8_0"
}
]
},
"tests": [
{
"description": "boolean schema false in if always chooses the else path (invalid)",
"data": "then",
"schema_id": "if-then-else_8_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "boolean schema false in if always chooses the else path (valid)",
"data": "else",
"schema_id": "if-then-else_8_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "if appears at the end when serialized (keyword processing sequence)",
"database": {
"schemas": [
{
"then": {
"const": "yes"
},
"else": {
"const": "other"
},
"if": {
"maxLength": 4
},
"$id": "if-then-else_9_0"
}
]
},
"tests": [
{
"description": "yes redirects to then and passes",
"data": "yes",
"schema_id": "if-then-else_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "other redirects to else and passes",
"data": "other",
"schema_id": "if-then-else_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "no redirects to then and fails",
"data": "no",
"schema_id": "if-then-else_9_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "invalid redirects to else and fails",
"data": "invalid",
"schema_id": "if-then-else_9_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "then: false fails when condition matches",
"database": {
"schemas": [
{
"if": {
"const": 1
},
"then": false,
"$id": "if-then-else_10_0"
}
]
},
"tests": [
{
"description": "matches if → then=false → invalid",
"data": 1,
"schema_id": "if-then-else_10_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "does not match if → then ignored → valid",
"data": 2,
"schema_id": "if-then-else_10_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "else: false fails when condition does not match",
"database": {
"schemas": [
{
"if": {
"const": 1
},
"else": false,
"$id": "if-then-else_11_0"
}
]
},
"tests": [
{
"description": "matches if → else ignored → valid",
"data": 1,
"schema_id": "if-then-else_11_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "does not match if → else executes → invalid",
"data": 2,
"schema_id": "if-then-else_11_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in if-then-else",
"database": {
"schemas": [
{
"if": {
"properties": {
"foo": {
"const": 1
}
},
"required": [
"foo"
]
},
"then": {
"properties": {
"bar": {
"const": 2
}
},
"required": [
"bar"
]
},
"extensible": true,
"$id": "if-then-else_12_0"
}
]
},
"tests": [
{
"description": "extra property is valid (matches if and then)",
"data": {
"foo": 1,
"bar": 2,
"extra": "prop"
},
"schema_id": "if-then-else_12_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "strict by default with if-then properties",
"database": {
"schemas": [
{
"if": {
"properties": {
"foo": {
"const": 1
}
},
"required": [
"foo"
]
},
"then": {
"properties": {
"bar": {
"const": 2
}
}
},
"$id": "if-then-else_13_0"
}
]
},
"tests": [
{
"description": "valid match (foo + bar)",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "if-then-else_13_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "fails on extra property z explicitly",
"data": {
"foo": 1,
"bar": 2,
"z": 3
},
"schema_id": "if-then-else_13_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

966
fixtures/items.json Normal file
View File

@ -0,0 +1,966 @@
[
{
"description": "a schema given for items",
"database": {
"schemas": [
{
"items": {
"type": "integer"
},
"$id": "items_0_0"
}
]
},
"tests": [
{
"description": "valid items",
"data": [
1,
2,
3
],
"schema_id": "items_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "wrong type of items",
"data": [
1,
"x"
],
"schema_id": "items_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "non-arrays are invalid",
"data": {
"foo": "bar"
},
"schema_id": "items_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "JavaScript pseudo-arrays are invalid",
"data": {
"0": "invalid",
"length": 1
},
"schema_id": "items_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "items with boolean schema (true)",
"database": {
"schemas": [
{
"items": true,
"$id": "items_1_0"
}
]
},
"tests": [
{
"description": "any array is valid",
"data": [
1,
"foo",
true
],
"schema_id": "items_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty array is valid",
"data": [],
"schema_id": "items_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "items with boolean schema (false)",
"database": {
"schemas": [
{
"items": false,
"$id": "items_2_0"
}
]
},
"tests": [
{
"description": "any non-empty array is invalid",
"data": [
1,
"foo",
true
],
"schema_id": "items_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty array is valid",
"data": [],
"schema_id": "items_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "items and subitems",
"database": {
"schemas": [
{
"type": "array",
"items": false,
"prefixItems": [
{
"$ref": "item"
},
{
"$ref": "item"
},
{
"$ref": "item"
}
],
"$id": "items_3_0"
},
{
"$id": "item",
"type": "array",
"items": false,
"prefixItems": [
{
"$ref": "sub-item"
},
{
"$ref": "sub-item"
}
]
},
{
"$id": "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
}
},
{
"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
}
},
{
"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
}
},
{
"description": "wrong item",
"data": [
{
"foo": null
},
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
]
],
"schema_id": "items_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"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
}
},
{
"description": "fewer items is invalid",
"data": [
[
{
"foo": null
}
],
[
{
"foo": null
}
]
],
"schema_id": "items_3_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "nested items",
"database": {
"schemas": [
{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "number"
}
}
}
},
"$id": "items_4_0"
}
]
},
"tests": [
{
"description": "valid nested array",
"data": [
[
[
[
1
]
],
[
[
2
],
[
3
]
]
],
[
[
[
4
],
[
5
],
[
6
]
]
]
],
"schema_id": "items_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "nested array with invalid type",
"data": [
[
[
[
"1"
]
],
[
[
2
],
[
3
]
]
],
[
[
[
4
],
[
5
],
[
6
]
]
]
],
"schema_id": "items_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "not deep enough",
"data": [
[
[
1
],
[
2
],
[
3
]
],
[
[
4
],
[
5
],
[
6
]
]
],
"schema_id": "items_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "prefixItems with no additional items allowed",
"database": {
"schemas": [
{
"prefixItems": [
{},
{},
{}
],
"items": false,
"$id": "items_5_0"
}
]
},
"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
}
}
]
},
{
"description": "items does not look in applicators, valid case",
"database": {
"schemas": [
{
"allOf": [
{
"prefixItems": [
{
"minimum": 3
}
]
}
],
"items": {
"minimum": 5
},
"$id": "items_6_0"
}
]
},
"tests": [
{
"description": "prefixItems in allOf does not constrain items, invalid case",
"data": [
3,
5
],
"schema_id": "items_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"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": {
"schemas": [
{
"prefixItems": [
{
"type": "string"
}
],
"items": {
"type": "integer"
},
"$id": "items_7_0"
}
]
},
"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
}
}
]
},
{
"description": "items with heterogeneous array",
"database": {
"schemas": [
{
"prefixItems": [
{}
],
"items": false,
"$id": "items_8_0"
}
]
},
"tests": [
{
"description": "heterogeneous invalid instance",
"data": [
"foo",
"bar",
37
],
"schema_id": "items_8_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "valid instance",
"data": [
null
],
"schema_id": "items_8_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "items with null instance elements",
"database": {
"schemas": [
{
"items": {
"type": "null"
},
"$id": "items_9_0"
}
]
},
"tests": [
{
"description": "allows null elements",
"data": [
null
],
"schema_id": "items_9_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "extensible: true allows extra items (when items is false)",
"database": {
"schemas": [
{
"items": false,
"extensible": true,
"$id": "items_10_0"
}
]
},
"tests": [
{
"description": "extra item is valid",
"data": [
1
],
"schema_id": "items_10_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties for items",
"database": {
"schemas": [
{
"items": {
"minimum": 5
},
"extensible": true,
"$id": "items_11_0"
}
]
},
"tests": [
{
"description": "valid item is valid",
"data": [
5,
6
],
"schema_id": "items_11_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid item (less than min) is invalid even with extensible: true",
"data": [
4
],
"schema_id": "items_11_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "array: simple extensible array",
"database": {
"schemas": [
{
"type": "array",
"extensible": true,
"$id": "items_12_0"
}
]
},
"tests": [
{
"description": "empty array is valid",
"data": [],
"schema_id": "items_12_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array with items is valid (extensible)",
"data": [
1,
"foo"
],
"schema_id": "items_12_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "array: strict array",
"database": {
"schemas": [
{
"type": "array",
"extensible": false,
"$id": "items_13_0"
}
]
},
"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
}
}
]
},
{
"description": "array: items extensible",
"database": {
"schemas": [
{
"type": "array",
"items": {
"extensible": true
},
"$id": "items_14_0"
}
]
},
"tests": [
{
"description": "empty array is valid",
"data": [],
"schema_id": "items_14_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array with items is valid (items explicitly allowed to be anything extensible)",
"data": [
1,
"foo",
{}
],
"schema_id": "items_14_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "array: items strict",
"database": {
"schemas": [
{
"type": "array",
"items": {
"type": "object",
"extensible": false
},
"$id": "items_15_0"
}
]
},
"tests": [
{
"description": "empty array is valid (empty objects)",
"data": [
{}
],
"schema_id": "items_15_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array with strict object items is valid",
"data": [
{}
],
"schema_id": "items_15_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array with invalid strict object items (extra property)",
"data": [
{
"extra": 1
}
],
"schema_id": "items_15_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

235
fixtures/maxContains.json Normal file
View File

@ -0,0 +1,235 @@
[
{
"description": "maxContains without contains is ignored",
"database": {
"schemas": [
{
"maxContains": 1,
"extensible": true,
"$id": "maxContains_0_0"
}
]
},
"tests": [
{
"description": "one item valid against lone maxContains",
"data": [
1
],
"schema_id": "maxContains_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "two items still valid against lone maxContains",
"data": [
1,
2
],
"schema_id": "maxContains_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "maxContains with contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"extensible": true,
"$id": "maxContains_1_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"schema_id": "maxContains_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all elements match, valid maxContains",
"data": [
1
],
"schema_id": "maxContains_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "all elements match, invalid maxContains",
"data": [
1,
1
],
"schema_id": "maxContains_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "some elements match, valid maxContains",
"data": [
1,
2
],
"schema_id": "maxContains_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "some elements match, invalid maxContains",
"data": [
1,
2,
1
],
"schema_id": "maxContains_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "maxContains with contains, value with a decimal",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"extensible": true,
"$id": "maxContains_2_0"
}
]
},
"tests": [
{
"description": "one element matches, valid maxContains",
"data": [
1
],
"schema_id": "maxContains_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too many elements match, invalid maxContains",
"data": [
1,
1
],
"schema_id": "maxContains_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "minContains < maxContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 1,
"maxContains": 3,
"extensible": true,
"$id": "maxContains_3_0"
}
]
},
"tests": [
{
"description": "actual < minContains < maxContains",
"data": [],
"schema_id": "maxContains_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "minContains < actual < maxContains",
"data": [
1,
1
],
"schema_id": "maxContains_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "minContains < maxContains < actual",
"data": [
1,
1,
1,
1
],
"schema_id": "maxContains_3_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows non-matching items in maxContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"extensible": true,
"$id": "maxContains_4_0"
}
]
},
"tests": [
{
"description": "extra items disregarded for maxContains",
"data": [
1,
2
],
"schema_id": "maxContains_4_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

126
fixtures/maxItems.json Normal file
View File

@ -0,0 +1,126 @@
[
{
"description": "maxItems validation",
"database": {
"schemas": [
{
"maxItems": 2,
"extensible": true,
"$id": "maxItems_0_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": [
1
],
"schema_id": "maxItems_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "exact length is valid",
"data": [
1,
2
],
"schema_id": "maxItems_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too long is invalid",
"data": [
1,
2,
3
],
"schema_id": "maxItems_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-arrays",
"data": "foobar",
"schema_id": "maxItems_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "maxItems validation with a decimal",
"database": {
"schemas": [
{
"maxItems": 2,
"extensible": true,
"$id": "maxItems_1_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": [
1
],
"schema_id": "maxItems_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too long is invalid",
"data": [
1,
2,
3
],
"schema_id": "maxItems_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra items in maxItems (but counted)",
"database": {
"schemas": [
{
"maxItems": 2,
"extensible": true,
"$id": "maxItems_2_0"
}
]
},
"tests": [
{
"description": "extra item counted towards maxItems",
"data": [
1,
2,
3
],
"schema_id": "maxItems_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

91
fixtures/maxLength.json Normal file
View File

@ -0,0 +1,91 @@
[
{
"description": "maxLength validation",
"database": {
"schemas": [
{
"maxLength": 2,
"$id": "maxLength_0_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": "f",
"schema_id": "maxLength_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "exact length is valid",
"data": "fo",
"schema_id": "maxLength_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too long is invalid",
"data": "foo",
"schema_id": "maxLength_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-strings",
"data": 100,
"schema_id": "maxLength_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "two graphemes is long enough",
"data": "💩💩",
"schema_id": "maxLength_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "maxLength validation with a decimal",
"database": {
"schemas": [
{
"maxLength": 2,
"$id": "maxLength_1_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": "f",
"schema_id": "maxLength_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too long is invalid",
"data": "foo",
"schema_id": "maxLength_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

193
fixtures/maxProperties.json Normal file
View File

@ -0,0 +1,193 @@
[
{
"description": "maxProperties validation",
"database": {
"schemas": [
{
"maxProperties": 2,
"extensible": true,
"$id": "maxProperties_0_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": {
"foo": 1
},
"schema_id": "maxProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "exact length is valid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "maxProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too long is invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"schema_id": "maxProperties_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores arrays",
"data": [
1,
2,
3
],
"schema_id": "maxProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores strings",
"data": "foobar",
"schema_id": "maxProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "maxProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "maxProperties validation with a decimal",
"database": {
"schemas": [
{
"maxProperties": 2,
"extensible": true,
"$id": "maxProperties_1_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": {
"foo": 1
},
"schema_id": "maxProperties_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too long is invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"schema_id": "maxProperties_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "maxProperties = 0 means the object is empty",
"database": {
"schemas": [
{
"maxProperties": 0,
"extensible": true,
"$id": "maxProperties_2_0"
}
]
},
"tests": [
{
"description": "no properties is valid",
"data": {},
"schema_id": "maxProperties_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "one property is invalid",
"data": {
"foo": 1
},
"schema_id": "maxProperties_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in maxProperties (though maxProperties still counts them!)",
"database": {
"schemas": [
{
"maxProperties": 2,
"extensible": true,
"$id": "maxProperties_3_0"
}
]
},
"tests": [
{
"description": "extra property is counted towards maxProperties",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"schema_id": "maxProperties_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "extra property is valid if below maxProperties",
"data": {
"foo": 1
},
"schema_id": "maxProperties_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

100
fixtures/maximum.json Normal file
View File

@ -0,0 +1,100 @@
[
{
"description": "maximum validation",
"database": {
"schemas": [
{
"maximum": 3,
"$id": "maximum_0_0"
}
]
},
"tests": [
{
"description": "below the maximum is valid",
"data": 2.6,
"schema_id": "maximum_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point is valid",
"data": 3,
"schema_id": "maximum_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "above the maximum is invalid",
"data": 3.5,
"schema_id": "maximum_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-numbers",
"data": "x",
"schema_id": "maximum_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "maximum validation with unsigned integer",
"database": {
"schemas": [
{
"maximum": 300,
"$id": "maximum_1_0"
}
]
},
"tests": [
{
"description": "below the maximum is invalid",
"data": 299.97,
"schema_id": "maximum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point integer is valid",
"data": 300,
"schema_id": "maximum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point float is valid",
"data": 300,
"schema_id": "maximum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "above the maximum is invalid",
"data": 300.5,
"schema_id": "maximum_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

274
fixtures/merge.json Normal file
View File

@ -0,0 +1,274 @@
[
{
"description": "merging: properties accumulate",
"database": {
"schemas": [
{
"$id": "base_0",
"properties": {
"base_prop": {
"type": "string"
}
}
},
{
"$ref": "base_0",
"properties": {
"child_prop": {
"type": "string"
}
},
"$id": "merge_0_0"
}
]
},
"tests": [
{
"description": "valid with both properties",
"data": {
"base_prop": "a",
"child_prop": "b"
},
"schema_id": "merge_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid when base property has wrong type",
"data": {
"base_prop": 1,
"child_prop": "b"
},
"schema_id": "merge_0_0",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "TYPE_MISMATCH",
"path": "/base_prop"
}
]
}
}
]
},
{
"description": "merging: required fields accumulate",
"database": {
"schemas": [
{
"$id": "base_1",
"properties": {
"a": {
"type": "string"
}
},
"required": [
"a"
]
},
{
"$ref": "base_1",
"properties": {
"b": {
"type": "string"
}
},
"required": [
"b"
],
"$id": "merge_1_0"
}
]
},
"tests": [
{
"description": "valid when both present",
"data": {
"a": "ok",
"b": "ok"
},
"schema_id": "merge_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid when base required missing",
"data": {
"b": "ok"
},
"schema_id": "merge_1_0",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "REQUIRED_FIELD_MISSING",
"path": "/a"
}
]
}
},
{
"description": "invalid when child required missing",
"data": {
"a": "ok"
},
"schema_id": "merge_1_0",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "REQUIRED_FIELD_MISSING",
"path": "/b"
}
]
}
}
]
},
{
"description": "merging: dependencies accumulate",
"database": {
"schemas": [
{
"$id": "base_2",
"properties": {
"trigger": {
"type": "string"
},
"base_dep": {
"type": "string"
}
},
"dependencies": {
"trigger": [
"base_dep"
]
}
},
{
"$ref": "base_2",
"properties": {
"child_dep": {
"type": "string"
}
},
"dependencies": {
"trigger": [
"child_dep"
]
},
"$id": "merge_2_0"
}
]
},
"tests": [
{
"description": "valid with all deps",
"data": {
"trigger": "go",
"base_dep": "ok",
"child_dep": "ok"
},
"schema_id": "merge_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "invalid missing base dep",
"data": {
"trigger": "go",
"child_dep": "ok"
},
"schema_id": "merge_2_0",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "DEPENDENCY_FAILED",
"path": "/base_dep"
}
]
}
},
{
"description": "invalid missing child dep",
"data": {
"trigger": "go",
"base_dep": "ok"
},
"schema_id": "merge_2_0",
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "DEPENDENCY_FAILED",
"path": "/child_dep"
}
]
}
}
]
},
{
"description": "merging: form and display do NOT merge",
"database": {
"schemas": [
{
"$id": "base_3",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
}
},
"form": [
"a",
"b"
]
},
{
"$ref": "base_3",
"properties": {
"c": {
"type": "string"
}
},
"form": [
"c"
],
"$id": "merge_3_0"
}
]
},
"tests": [
{
"description": "child schema validation",
"data": {
"a": "ok",
"b": "ok",
"c": "ok"
},
"comment": "Verifies validator handles the unmerged metadata correctly (ignores it or handles replacement)",
"schema_id": "merge_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

1059
fixtures/merger.json Normal file

File diff suppressed because it is too large Load Diff

477
fixtures/minContains.json Normal file
View File

@ -0,0 +1,477 @@
[
{
"description": "minContains without contains is ignored",
"database": {
"schemas": [
{
"minContains": 1,
"extensible": true,
"$id": "minContains_0_0"
}
]
},
"tests": [
{
"description": "one item valid against lone minContains",
"data": [
1
],
"schema_id": "minContains_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "zero items still valid against lone minContains",
"data": [],
"schema_id": "minContains_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "minContains=1 with contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 1,
"extensible": true,
"$id": "minContains_1_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"schema_id": "minContains_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "no elements match",
"data": [
2
],
"schema_id": "minContains_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "single element matches, valid minContains",
"data": [
1
],
"schema_id": "minContains_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "some elements match, valid minContains",
"data": [
1,
2
],
"schema_id": "minContains_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "all elements match, valid minContains",
"data": [
1,
1
],
"schema_id": "minContains_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "minContains=2 with contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 2,
"extensible": true,
"$id": "minContains_2_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"schema_id": "minContains_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all elements match, invalid minContains",
"data": [
1
],
"schema_id": "minContains_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "some elements match, invalid minContains",
"data": [
1,
2
],
"schema_id": "minContains_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all elements match, valid minContains (exactly as needed)",
"data": [
1,
1
],
"schema_id": "minContains_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "all elements match, valid minContains (more than needed)",
"data": [
1,
1,
1
],
"schema_id": "minContains_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "some elements match, valid minContains",
"data": [
1,
2,
1
],
"schema_id": "minContains_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "minContains=2 with contains with a decimal value",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 2,
"extensible": true,
"$id": "minContains_3_0"
}
]
},
"tests": [
{
"description": "one element matches, invalid minContains",
"data": [
1
],
"schema_id": "minContains_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "both elements match, valid minContains",
"data": [
1,
1
],
"schema_id": "minContains_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "maxContains = minContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 2,
"minContains": 2,
"extensible": true,
"$id": "minContains_4_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"schema_id": "minContains_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all elements match, invalid minContains",
"data": [
1
],
"schema_id": "minContains_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all elements match, invalid maxContains",
"data": [
1,
1,
1
],
"schema_id": "minContains_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all elements match, valid maxContains and minContains",
"data": [
1,
1
],
"schema_id": "minContains_4_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "maxContains < minContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"minContains": 3,
"extensible": true,
"$id": "minContains_5_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"schema_id": "minContains_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "invalid minContains",
"data": [
1
],
"schema_id": "minContains_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "invalid maxContains",
"data": [
1,
1,
1
],
"schema_id": "minContains_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "invalid maxContains and minContains",
"data": [
1,
1
],
"schema_id": "minContains_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "minContains = 0",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 0,
"extensible": true,
"$id": "minContains_6_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"schema_id": "minContains_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "minContains = 0 makes contains always pass",
"data": [
2
],
"schema_id": "minContains_6_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "minContains = 0 with maxContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 0,
"maxContains": 1,
"extensible": true,
"$id": "minContains_7_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"schema_id": "minContains_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "not more than maxContains",
"data": [
1
],
"schema_id": "minContains_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too many",
"data": [
1,
1
],
"schema_id": "minContains_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows non-matching items in minContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 1,
"extensible": true,
"$id": "minContains_8_0"
}
]
},
"tests": [
{
"description": "extra items disregarded for minContains",
"data": [
1,
2
],
"schema_id": "minContains_8_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

117
fixtures/minItems.json Normal file
View File

@ -0,0 +1,117 @@
[
{
"description": "minItems validation",
"database": {
"schemas": [
{
"minItems": 1,
"extensible": true,
"$id": "minItems_0_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": [
1,
2
],
"schema_id": "minItems_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "exact length is valid",
"data": [
1
],
"schema_id": "minItems_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too short is invalid",
"data": [],
"schema_id": "minItems_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-arrays",
"data": "",
"schema_id": "minItems_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "minItems validation with a decimal",
"database": {
"schemas": [
{
"minItems": 1,
"extensible": true,
"$id": "minItems_1_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": [
1,
2
],
"schema_id": "minItems_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too short is invalid",
"data": [],
"schema_id": "minItems_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra items in minItems",
"database": {
"schemas": [
{
"minItems": 1,
"extensible": true,
"$id": "minItems_2_0"
}
]
},
"tests": [
{
"description": "extra item counted towards minItems",
"data": [
1
],
"schema_id": "minItems_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

91
fixtures/minLength.json Normal file
View File

@ -0,0 +1,91 @@
[
{
"description": "minLength validation",
"database": {
"schemas": [
{
"minLength": 2,
"$id": "minLength_0_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": "foo",
"schema_id": "minLength_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "exact length is valid",
"data": "fo",
"schema_id": "minLength_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too short is invalid",
"data": "f",
"schema_id": "minLength_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-strings",
"data": 1,
"schema_id": "minLength_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "one grapheme is not long enough",
"data": "💩",
"schema_id": "minLength_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "minLength validation with a decimal",
"database": {
"schemas": [
{
"minLength": 2,
"$id": "minLength_1_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": "foo",
"schema_id": "minLength_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too short is invalid",
"data": "f",
"schema_id": "minLength_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

135
fixtures/minProperties.json Normal file
View File

@ -0,0 +1,135 @@
[
{
"description": "minProperties validation",
"database": {
"schemas": [
{
"minProperties": 1,
"extensible": true,
"$id": "minProperties_0_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "minProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "exact length is valid",
"data": {
"foo": 1
},
"schema_id": "minProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too short is invalid",
"data": {},
"schema_id": "minProperties_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores arrays",
"data": [],
"schema_id": "minProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores strings",
"data": "",
"schema_id": "minProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "minProperties_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "minProperties validation with a decimal",
"database": {
"schemas": [
{
"minProperties": 1,
"extensible": true,
"$id": "minProperties_1_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "minProperties_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "too short is invalid",
"data": {},
"schema_id": "minProperties_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in minProperties",
"database": {
"schemas": [
{
"minProperties": 1,
"extensible": true,
"$id": "minProperties_2_0"
}
]
},
"tests": [
{
"description": "extra property counts towards minProperties",
"data": {
"foo": 1
},
"schema_id": "minProperties_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

127
fixtures/minimum.json Normal file
View File

@ -0,0 +1,127 @@
[
{
"description": "minimum validation",
"database": {
"schemas": [
{
"minimum": 1.1,
"$id": "minimum_0_0"
}
]
},
"tests": [
{
"description": "above the minimum is valid",
"data": 2.6,
"schema_id": "minimum_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point is valid",
"data": 1.1,
"schema_id": "minimum_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "below the minimum is invalid",
"data": 0.6,
"schema_id": "minimum_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-numbers",
"data": "x",
"schema_id": "minimum_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "minimum validation with signed integer",
"database": {
"schemas": [
{
"minimum": -2,
"$id": "minimum_1_0"
}
]
},
"tests": [
{
"description": "negative above the minimum is valid",
"data": -1,
"schema_id": "minimum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "positive above the minimum is valid",
"data": 0,
"schema_id": "minimum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point is valid",
"data": -2,
"schema_id": "minimum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boundary point with float is valid",
"data": -2,
"schema_id": "minimum_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "float below the minimum is invalid",
"data": -2.0001,
"schema_id": "minimum_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "int below the minimum is invalid",
"data": -3,
"schema_id": "minimum_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-numbers",
"data": "x",
"schema_id": "minimum_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

136
fixtures/multipleOf.json Normal file
View File

@ -0,0 +1,136 @@
[
{
"description": "by int",
"database": {
"schemas": [
{
"multipleOf": 2,
"$id": "multipleOf_0_0"
}
]
},
"tests": [
{
"description": "int by int",
"data": 10,
"schema_id": "multipleOf_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "int by int fail",
"data": 7,
"schema_id": "multipleOf_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores non-numbers",
"data": "foo",
"schema_id": "multipleOf_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "by number",
"database": {
"schemas": [
{
"multipleOf": 1.5,
"$id": "multipleOf_1_0"
}
]
},
"tests": [
{
"description": "zero is multiple of anything",
"data": 0,
"schema_id": "multipleOf_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "4.5 is multiple of 1.5",
"data": 4.5,
"schema_id": "multipleOf_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "35 is not multiple of 1.5",
"data": 35,
"schema_id": "multipleOf_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "by small number",
"database": {
"schemas": [
{
"multipleOf": 0.0001,
"$id": "multipleOf_2_0"
}
]
},
"tests": [
{
"description": "0.0075 is multiple of 0.0001",
"data": 0.0075,
"schema_id": "multipleOf_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "0.00751 is not multiple of 0.0001",
"data": 0.00751,
"schema_id": "multipleOf_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "small multiple of large integer",
"database": {
"schemas": [
{
"type": "integer",
"multipleOf": 1e-8,
"$id": "multipleOf_3_0"
}
]
},
"tests": [
{
"description": "any integer is a multiple of 1e-8",
"data": 12391239123,
"schema_id": "multipleOf_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

618
fixtures/not.json Normal file
View File

@ -0,0 +1,618 @@
[
{
"description": "not",
"database": {
"schemas": [
{
"not": {
"type": "integer"
},
"$id": "not_0_0"
}
]
},
"tests": [
{
"description": "allowed",
"data": "foo",
"schema_id": "not_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "disallowed",
"data": 1,
"schema_id": "not_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "not multiple types",
"database": {
"schemas": [
{
"not": {
"type": [
"integer",
"boolean"
]
},
"$id": "not_1_0"
}
]
},
"tests": [
{
"description": "valid",
"data": "foo",
"schema_id": "not_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "mismatch",
"data": 1,
"schema_id": "not_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "other mismatch",
"data": true,
"schema_id": "not_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "not more complex schema",
"database": {
"schemas": [
{
"not": {
"type": "object",
"properties": {
"foo": {
"type": "string"
}
}
},
"extensible": true,
"$id": "not_2_0"
}
]
},
"tests": [
{
"description": "match",
"data": 1,
"schema_id": "not_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "other match",
"data": {
"foo": 1
},
"schema_id": "not_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "mismatch",
"data": {
"foo": "bar"
},
"schema_id": "not_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "forbidden property",
"database": {
"schemas": [
{
"properties": {
"foo": {
"not": {}
}
},
"$id": "not_3_0"
}
]
},
"tests": [
{
"description": "property present",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "not_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "not_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "forbid everything with empty schema",
"database": {
"schemas": [
{
"not": {},
"$id": "not_4_0"
}
]
},
"tests": [
{
"description": "number is invalid",
"data": 1,
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "string is invalid",
"data": "foo",
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "boolean true is invalid",
"data": true,
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "boolean false is invalid",
"data": false,
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is invalid",
"data": null,
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "object is invalid",
"data": {
"foo": "bar"
},
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is invalid",
"data": {},
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "array is invalid",
"data": [
"foo"
],
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "not_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "forbid everything with boolean schema true",
"database": {
"schemas": [
{
"not": true,
"$id": "not_5_0"
}
]
},
"tests": [
{
"description": "number is invalid",
"data": 1,
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "string is invalid",
"data": "foo",
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "boolean true is invalid",
"data": true,
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "boolean false is invalid",
"data": false,
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is invalid",
"data": null,
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "object is invalid",
"data": {
"foo": "bar"
},
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is invalid",
"data": {},
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "array is invalid",
"data": [
"foo"
],
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty array is invalid",
"data": [],
"schema_id": "not_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "allow everything with boolean schema false",
"database": {
"schemas": [
{
"not": false,
"extensible": true,
"$id": "not_6_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "string is valid",
"data": "foo",
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boolean true is valid",
"data": true,
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "boolean false is valid",
"data": false,
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "null is valid",
"data": null,
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object is valid",
"data": {
"foo": "bar"
},
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "array is valid",
"data": [
"foo"
],
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty array is valid",
"data": [],
"schema_id": "not_6_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "double negation",
"database": {
"schemas": [
{
"not": {
"not": {}
},
"$id": "not_7_0"
}
]
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"schema_id": "not_7_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "extensible: true allows extra properties in not",
"database": {
"schemas": [
{
"not": {
"type": "integer"
},
"extensible": true,
"$id": "not_8_0"
}
]
},
"tests": [
{
"description": "extra property is valid (not integer matches)",
"data": {
"foo": 1
},
"schema_id": "not_8_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "extensible: false (default) forbids extra properties in not",
"database": {
"schemas": [
{
"not": {
"type": "integer"
},
"$id": "not_9_0"
}
]
},
"tests": [
{
"description": "extra property is invalid due to strictness",
"data": {
"foo": 1
},
"schema_id": "not_9_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "property next to not (extensible: true)",
"database": {
"schemas": [
{
"properties": {
"bar": {
"type": "string"
}
},
"not": {
"type": "integer"
},
"extensible": true,
"$id": "not_10_0"
}
]
},
"tests": [
{
"description": "extra property allowed",
"data": {
"bar": "baz",
"foo": 1
},
"schema_id": "not_10_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "property next to not (extensible: false)",
"database": {
"schemas": [
{
"properties": {
"bar": {
"type": "string"
}
},
"not": {
"type": "integer"
},
"$id": "not_11_0"
}
]
},
"tests": [
{
"description": "extra property forbidden",
"data": {
"bar": "baz",
"foo": 1
},
"schema_id": "not_11_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "defined property allowed",
"data": {
"bar": "baz"
},
"schema_id": "not_11_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

670
fixtures/oneOf.json Normal file
View File

@ -0,0 +1,670 @@
[
{
"description": "oneOf",
"database": {
"schemas": [
{
"oneOf": [
{
"type": "integer"
},
{
"minimum": 2
}
],
"$id": "oneOf_0_0"
}
]
},
"tests": [
{
"description": "first oneOf valid",
"data": 1,
"schema_id": "oneOf_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "second oneOf valid",
"data": 2.5,
"schema_id": "oneOf_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "both oneOf valid",
"data": 3,
"schema_id": "oneOf_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "neither oneOf valid",
"data": 1.5,
"schema_id": "oneOf_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf with base schema",
"database": {
"schemas": [
{
"type": "string",
"oneOf": [
{
"minLength": 2
},
{
"maxLength": 4
}
],
"$id": "oneOf_1_0"
}
]
},
"tests": [
{
"description": "mismatch base schema",
"data": 3,
"schema_id": "oneOf_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "one oneOf valid",
"data": "foobar",
"schema_id": "oneOf_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "both oneOf valid",
"data": "foo",
"schema_id": "oneOf_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf with boolean schemas, all true",
"database": {
"schemas": [
{
"oneOf": [
true,
true,
true
],
"$id": "oneOf_2_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"schema_id": "oneOf_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf with boolean schemas, one true",
"database": {
"schemas": [
{
"oneOf": [
true,
false,
false
],
"$id": "oneOf_3_0"
}
]
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"schema_id": "oneOf_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "oneOf with boolean schemas, more than one true",
"database": {
"schemas": [
{
"oneOf": [
true,
true,
false
],
"$id": "oneOf_4_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"schema_id": "oneOf_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf with boolean schemas, all false",
"database": {
"schemas": [
{
"oneOf": [
false,
false,
false
],
"$id": "oneOf_5_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"schema_id": "oneOf_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf complex types",
"database": {
"schemas": [
{
"oneOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"$id": "oneOf_6_0"
}
]
},
"tests": [
{
"description": "first oneOf valid (complex)",
"data": {
"bar": 2
},
"schema_id": "oneOf_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "second oneOf valid (complex)",
"data": {
"foo": "baz"
},
"schema_id": "oneOf_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "both oneOf valid (complex)",
"data": {
"foo": "baz",
"bar": 2
},
"schema_id": "oneOf_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "neither oneOf valid (complex)",
"data": {
"foo": 2,
"bar": "quux"
},
"schema_id": "oneOf_6_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf with empty schema",
"database": {
"schemas": [
{
"oneOf": [
{
"type": "number"
},
{}
],
"$id": "oneOf_7_0"
}
]
},
"tests": [
{
"description": "one valid - valid",
"data": "foo",
"schema_id": "oneOf_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "both valid - invalid",
"data": 123,
"schema_id": "oneOf_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf with required",
"database": {
"schemas": [
{
"type": "object",
"properties": {
"foo": true,
"bar": true,
"baz": true
},
"oneOf": [
{
"required": [
"foo",
"bar"
]
},
{
"required": [
"foo",
"baz"
]
}
],
"$id": "oneOf_8_0"
}
]
},
"tests": [
{
"description": "both invalid - invalid",
"data": {
"bar": 2
},
"schema_id": "oneOf_8_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "first valid - valid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "oneOf_8_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "second valid - valid",
"data": {
"foo": 1,
"baz": 3
},
"schema_id": "oneOf_8_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "both valid - invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"schema_id": "oneOf_8_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "extra property invalid (strict)",
"data": {
"foo": 1,
"bar": 2,
"extra": 3
},
"schema_id": "oneOf_8_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "oneOf with required (extensible)",
"database": {
"schemas": [
{
"type": "object",
"extensible": true,
"oneOf": [
{
"required": [
"foo",
"bar"
]
},
{
"required": [
"foo",
"baz"
]
}
],
"$id": "oneOf_9_0"
}
]
},
"tests": [
{
"description": "both invalid - invalid",
"data": {
"bar": 2
},
"schema_id": "oneOf_9_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "first valid - valid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "oneOf_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "second valid - valid",
"data": {
"foo": 1,
"baz": 3
},
"schema_id": "oneOf_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "both valid - invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"schema_id": "oneOf_9_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "extra properties are valid (extensible)",
"data": {
"foo": 1,
"bar": 2,
"extra": "value"
},
"schema_id": "oneOf_9_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "oneOf with missing optional property",
"database": {
"schemas": [
{
"oneOf": [
{
"properties": {
"bar": true,
"baz": true
},
"required": [
"bar"
]
},
{
"properties": {
"foo": true
},
"required": [
"foo"
]
}
],
"$id": "oneOf_10_0"
}
]
},
"tests": [
{
"description": "first oneOf valid",
"data": {
"bar": 8
},
"schema_id": "oneOf_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "second oneOf valid",
"data": {
"foo": "foo"
},
"schema_id": "oneOf_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "both oneOf valid",
"data": {
"foo": "foo",
"bar": 8
},
"schema_id": "oneOf_10_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "neither oneOf valid",
"data": {
"baz": "quux"
},
"schema_id": "oneOf_10_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "nested oneOf, to check validation semantics",
"database": {
"schemas": [
{
"oneOf": [
{
"oneOf": [
{
"type": "null"
}
]
}
],
"$id": "oneOf_11_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"schema_id": "oneOf_11_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "anything non-null is invalid",
"data": 123,
"schema_id": "oneOf_11_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties in oneOf",
"database": {
"schemas": [
{
"oneOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"extensible": true,
"$id": "oneOf_12_0"
}
]
},
"tests": [
{
"description": "extra property is valid (matches first option)",
"data": {
"bar": 2,
"extra": "prop"
},
"schema_id": "oneOf_12_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

109
fixtures/pattern.json Normal file
View File

@ -0,0 +1,109 @@
[
{
"description": "pattern validation",
"database": {
"schemas": [
{
"pattern": "^a*$",
"$id": "pattern_0_0"
}
]
},
"tests": [
{
"description": "a matching pattern is valid",
"data": "aaa",
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a non-matching pattern is invalid",
"data": "abc",
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores booleans",
"data": true,
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores integers",
"data": 123,
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores floats",
"data": 1,
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores objects",
"data": {},
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores arrays",
"data": [],
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores null",
"data": null,
"schema_id": "pattern_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "pattern is not anchored",
"database": {
"schemas": [
{
"pattern": "a+",
"$id": "pattern_1_0"
}
]
},
"tests": [
{
"description": "matches a substring",
"data": "xxaayy",
"schema_id": "pattern_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

View File

@ -0,0 +1,399 @@
[
{
"description": "patternProperties validates properties matching a regex",
"database": {
"schemas": [
{
"patternProperties": {
"f.*o": {
"type": "integer"
}
},
"items": {},
"$id": "patternProperties_0_0"
}
]
},
"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
}
},
{
"description": "multiple invalid matches is invalid",
"data": {
"foo": "bar",
"foooooo": "baz"
},
"schema_id": "patternProperties_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"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
}
}
]
},
{
"description": "multiple simultaneous patternProperties are validated",
"database": {
"schemas": [
{
"patternProperties": {
"a*": {
"type": "integer"
},
"aaa*": {
"maximum": 20
}
},
"$id": "patternProperties_1_0"
}
]
},
"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
}
},
{
"description": "an invalid due to the other is invalid",
"data": {
"aaaa": 31
},
"schema_id": "patternProperties_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an invalid due to both is invalid",
"data": {
"aaa": "foo",
"aaaa": 31
},
"schema_id": "patternProperties_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "regexes are not anchored by default and are case sensitive",
"database": {
"schemas": [
{
"patternProperties": {
"[0-9]{2,}": {
"type": "boolean"
},
"X_": {
"type": "string"
}
},
"extensible": true,
"$id": "patternProperties_2_0"
}
]
},
"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
}
},
{
"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
}
}
]
},
{
"description": "patternProperties with boolean schemas",
"database": {
"schemas": [
{
"patternProperties": {
"f.*": true,
"b.*": false
},
"$id": "patternProperties_3_0"
}
]
},
"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
}
},
{
"description": "object with both properties is invalid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "patternProperties_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"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
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "patternProperties_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "patternProperties with null valued instance properties",
"database": {
"schemas": [
{
"patternProperties": {
"^.*bar$": {
"type": "null"
}
},
"$id": "patternProperties_4_0"
}
]
},
"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": {
"schemas": [
{
"patternProperties": {
"f.*o": {
"type": "integer"
}
},
"extensible": true,
"$id": "patternProperties_5_0"
}
]
},
"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
}
}
]
}
]

229
fixtures/prefixItems.json Normal file
View File

@ -0,0 +1,229 @@
[
{
"description": "a schema given for prefixItems",
"database": {
"schemas": [
{
"prefixItems": [
{
"type": "integer"
},
{
"type": "string"
}
],
"$id": "prefixItems_0_0"
}
]
},
"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
}
},
{
"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
}
},
{
"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
}
}
]
},
{
"description": "prefixItems with boolean schemas",
"database": {
"schemas": [
{
"prefixItems": [
true,
false
],
"$id": "prefixItems_1_0"
}
]
},
"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
}
},
{
"description": "empty array is valid",
"data": [],
"schema_id": "prefixItems_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "additional items are allowed by default",
"database": {
"schemas": [
{
"prefixItems": [
{
"type": "integer"
}
],
"extensible": true,
"$id": "prefixItems_2_0"
}
]
},
"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": {
"schemas": [
{
"prefixItems": [
{
"type": "null"
}
],
"$id": "prefixItems_3_0"
}
]
},
"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": {
"schemas": [
{
"prefixItems": [
{
"type": "integer"
}
],
"extensible": true,
"$id": "prefixItems_4_0"
}
]
},
"tests": [
{
"description": "extra item is valid",
"data": [
1,
"foo"
],
"schema_id": "prefixItems_4_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

627
fixtures/properties.json Normal file
View File

@ -0,0 +1,627 @@
[
{
"description": "object properties validation",
"database": {
"schemas": [
{
"properties": {
"foo": {
"type": "integer"
},
"bar": {
"type": "string"
}
},
"$id": "properties_0_0"
}
]
},
"tests": [
{
"description": "both properties present and valid is valid",
"data": {
"foo": 1,
"bar": "baz"
},
"schema_id": "properties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "one property invalid is invalid",
"data": {
"foo": 1,
"bar": {}
},
"schema_id": "properties_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "both properties invalid is invalid",
"data": {
"foo": [],
"bar": {}
},
"schema_id": "properties_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "doesn't invalidate other properties",
"data": {},
"schema_id": "properties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores arrays",
"data": [],
"schema_id": "properties_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "properties_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "properties with boolean schema",
"database": {
"schemas": [
{
"properties": {
"foo": true,
"bar": false
},
"$id": "properties_1_0"
}
]
},
"tests": [
{
"description": "no property present is valid",
"data": {},
"schema_id": "properties_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "only 'true' property present is valid",
"data": {
"foo": 1
},
"schema_id": "properties_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "only 'false' property present is invalid",
"data": {
"bar": 2
},
"schema_id": "properties_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "both properties present is invalid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "properties_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "properties with escaped characters",
"database": {
"schemas": [
{
"properties": {
"foo\nbar": {
"type": "number"
},
"foo\"bar": {
"type": "number"
},
"foo\\bar": {
"type": "number"
},
"foo\rbar": {
"type": "number"
},
"foo\tbar": {
"type": "number"
},
"foo\fbar": {
"type": "number"
}
},
"$id": "properties_2_0"
}
]
},
"tests": [
{
"description": "object with all numbers is valid",
"data": {
"foo\nbar": 1,
"foo\"bar": 1,
"foo\\bar": 1,
"foo\rbar": 1,
"foo\tbar": 1,
"foo\fbar": 1
},
"schema_id": "properties_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with strings is invalid",
"data": {
"foo\nbar": "1",
"foo\"bar": "1",
"foo\\bar": "1",
"foo\rbar": "1",
"foo\tbar": "1",
"foo\fbar": "1"
},
"schema_id": "properties_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "properties with null valued instance properties",
"database": {
"schemas": [
{
"properties": {
"foo": {
"type": "null"
}
},
"$id": "properties_3_0"
}
]
},
"tests": [
{
"description": "allows null values",
"data": {
"foo": null
},
"schema_id": "properties_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "properties whose names are Javascript object property names",
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
"database": {
"schemas": [
{
"properties": {
"__proto__": {
"type": "number"
},
"toString": {
"properties": {
"length": {
"type": "string"
}
}
},
"constructor": {
"type": "number"
}
},
"$id": "properties_4_0"
}
]
},
"tests": [
{
"description": "ignores arrays",
"data": [],
"schema_id": "properties_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "properties_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "none of the properties mentioned",
"data": {},
"schema_id": "properties_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "__proto__ not valid",
"data": {
"__proto__": "foo"
},
"schema_id": "properties_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "toString not valid",
"data": {
"toString": {
"length": 37
}
},
"schema_id": "properties_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "constructor not valid",
"data": {
"constructor": {
"length": 37
}
},
"schema_id": "properties_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all present and valid",
"data": {
"__proto__": 12,
"toString": {
"length": "foo"
},
"constructor": 37
},
"schema_id": "properties_4_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "extensible: true allows extra properties",
"database": {
"schemas": [
{
"properties": {
"foo": {
"type": "integer"
}
},
"extensible": true,
"$id": "properties_5_0"
}
]
},
"tests": [
{
"description": "extra property is valid",
"data": {
"foo": 1,
"bar": "baz"
},
"schema_id": "properties_5_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "strict by default: extra properties invalid",
"database": {
"schemas": [
{
"properties": {
"foo": {
"type": "string"
}
},
"$id": "properties_6_0"
}
]
},
"tests": [
{
"description": "extra property is invalid",
"data": {
"foo": "bar",
"extra": 1
},
"schema_id": "properties_6_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "inheritance: nested object inherits strictness from strict parent",
"database": {
"schemas": [
{
"properties": {
"nested": {
"properties": {
"foo": {
"type": "string"
}
}
}
},
"$id": "properties_7_0"
}
]
},
"tests": [
{
"description": "nested extra property is invalid",
"data": {
"nested": {
"foo": "bar",
"extra": 1
}
},
"schema_id": "properties_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "override: nested object allows extra properties if extensible: true",
"database": {
"schemas": [
{
"properties": {
"nested": {
"extensible": true,
"properties": {
"foo": {
"type": "string"
}
}
}
},
"$id": "properties_8_0"
}
]
},
"tests": [
{
"description": "nested extra property is valid",
"data": {
"nested": {
"foo": "bar",
"extra": 1
}
},
"schema_id": "properties_8_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "inheritance: nested object inherits looseness from loose parent",
"database": {
"schemas": [
{
"extensible": true,
"properties": {
"nested": {
"properties": {
"foo": {
"type": "string"
}
}
}
},
"$id": "properties_9_0"
}
]
},
"tests": [
{
"description": "nested extra property is valid",
"data": {
"nested": {
"foo": "bar",
"extra": 1
}
},
"schema_id": "properties_9_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "override: nested object enforces strictness if extensible: false",
"database": {
"schemas": [
{
"extensible": true,
"properties": {
"nested": {
"extensible": false,
"properties": {
"foo": {
"type": "string"
}
}
}
},
"$id": "properties_10_0"
}
]
},
"tests": [
{
"description": "nested extra property is invalid",
"data": {
"nested": {
"foo": "bar",
"extra": 1
}
},
"schema_id": "properties_10_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "arrays: inline items inherit strictness from strict parent",
"database": {
"schemas": [
{
"properties": {
"list": {
"type": "array",
"items": {
"properties": {
"foo": {
"type": "string"
}
}
}
}
},
"$id": "properties_11_0"
}
]
},
"tests": [
{
"description": "array item with extra property is invalid (strict parent)",
"data": {
"list": [
{
"foo": "bar",
"extra": 1
}
]
},
"schema_id": "properties_11_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "arrays: inline items inherit looseness from loose parent",
"database": {
"schemas": [
{
"extensible": true,
"properties": {
"list": {
"type": "array",
"items": {
"properties": {
"foo": {
"type": "string"
}
}
}
}
},
"$id": "properties_12_0"
}
]
},
"tests": [
{
"description": "array item with extra property is valid (loose parent)",
"data": {
"list": [
{
"foo": "bar",
"extra": 1
}
]
},
"schema_id": "properties_12_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

347
fixtures/propertyNames.json Normal file
View File

@ -0,0 +1,347 @@
[
{
"description": "propertyNames validation",
"database": {
"schemas": [
{
"propertyNames": {
"maxLength": 3
},
"extensible": true,
"$id": "propertyNames_0_0"
}
]
},
"tests": [
{
"description": "all property names valid",
"data": {
"f": {},
"foo": {}
},
"schema_id": "propertyNames_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "some property names invalid",
"data": {
"foo": {},
"foobar": {}
},
"schema_id": "propertyNames_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "object without properties is valid",
"data": {},
"schema_id": "propertyNames_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores arrays",
"data": [
1,
2,
3,
4
],
"schema_id": "propertyNames_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores strings",
"data": "foobar",
"schema_id": "propertyNames_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "propertyNames_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "propertyNames validation with pattern",
"database": {
"schemas": [
{
"propertyNames": {
"pattern": "^a+$"
},
"extensible": true,
"$id": "propertyNames_1_0"
}
]
},
"tests": [
{
"description": "matching property names valid",
"data": {
"a": {},
"aa": {},
"aaa": {}
},
"schema_id": "propertyNames_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "non-matching property name is invalid",
"data": {
"aaA": {}
},
"schema_id": "propertyNames_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "object without properties is valid",
"data": {},
"schema_id": "propertyNames_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "propertyNames with boolean schema true",
"database": {
"schemas": [
{
"propertyNames": true,
"extensible": true,
"$id": "propertyNames_2_0"
}
]
},
"tests": [
{
"description": "object with any properties is valid",
"data": {
"foo": 1
},
"schema_id": "propertyNames_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "propertyNames_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "propertyNames with boolean schema false",
"database": {
"schemas": [
{
"propertyNames": false,
"extensible": true,
"$id": "propertyNames_3_0"
}
]
},
"tests": [
{
"description": "object with any properties is invalid",
"data": {
"foo": 1
},
"schema_id": "propertyNames_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "propertyNames_3_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "propertyNames with const",
"database": {
"schemas": [
{
"propertyNames": {
"const": "foo"
},
"extensible": true,
"$id": "propertyNames_4_0"
}
]
},
"tests": [
{
"description": "object with property foo is valid",
"data": {
"foo": 1
},
"schema_id": "propertyNames_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with any other property is invalid",
"data": {
"bar": 1
},
"schema_id": "propertyNames_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "propertyNames_4_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "propertyNames with enum",
"database": {
"schemas": [
{
"propertyNames": {
"enum": [
"foo",
"bar"
]
},
"extensible": true,
"$id": "propertyNames_5_0"
}
]
},
"tests": [
{
"description": "object with property foo is valid",
"data": {
"foo": 1
},
"schema_id": "propertyNames_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with property foo and bar is valid",
"data": {
"foo": 1,
"bar": 1
},
"schema_id": "propertyNames_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with any other property is invalid",
"data": {
"baz": 1
},
"schema_id": "propertyNames_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "empty object is valid",
"data": {},
"schema_id": "propertyNames_5_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "extensible: true allows extra properties (checked by propertyNames)",
"database": {
"schemas": [
{
"propertyNames": {
"maxLength": 3
},
"extensible": true,
"$id": "propertyNames_6_0"
}
]
},
"tests": [
{
"description": "extra property with valid name is valid",
"data": {
"foo": 1
},
"schema_id": "propertyNames_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "extra property with invalid name is invalid",
"data": {
"foobar": 1
},
"schema_id": "propertyNames_6_0",
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

599
fixtures/queryer.json Normal file
View File

@ -0,0 +1,599 @@
[
{
"description": "Basic Queryer Execution",
"database": {
"puncs": [],
"enums": [],
"relations": [],
"types": [
{
"name": "entity",
"hierarchy": [
"entity"
],
"grouped_fields": {
"entity": [
"id",
"name",
"archived",
"amount",
"created_at"
]
},
"field_types": {
"id": "uuid",
"name": "text",
"archived": "boolean",
"amount": "numeric",
"created_at": "timestamptz"
},
"schemas": [
{
"$id": "entity",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string"
},
"archived": {
"type": "boolean"
},
"amount": {
"type": "number"
},
"created_at": {
"type": "string",
"format": "date-time"
}
}
}
]
}
]
},
"tests": [
{
"description": "Should execute a blanket SELECT query when no filters are present",
"action": "query",
"schema_id": "entity",
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('amount', t1_obj_t1.amount, 'archived', t1_obj_t1.archived, 'created_at', t1_obj_t1.created_at, 'id', t1_obj_t1.id, 'name', t1_obj_t1.name) FROM agreego.entity t1_obj_t1 WHERE NOT t1_obj_t1.archived)"
]
}
},
{
"description": "Should execute a blanket SELECT query isolating root stems directly",
"action": "query",
"schema_id": "entity",
"stem": "",
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('amount', t1_obj_t1.amount, 'archived', t1_obj_t1.archived, 'created_at', t1_obj_t1.created_at, 'id', t1_obj_t1.id, 'name', t1_obj_t1.name) FROM agreego.entity t1_obj_t1 WHERE NOT t1_obj_t1.archived)"
]
}
},
{
"description": "Should bind parameters with proper casting and ILIKE for generated generic SELECT string when using some filters",
"action": "query",
"schema_id": "entity",
"filters": {
"name": "Jane%",
"archived": false
},
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('amount', t1_obj_t1.amount, 'archived', t1_obj_t1.archived, 'created_at', t1_obj_t1.created_at, 'id', t1_obj_t1.id, 'name', t1_obj_t1.name) FROM agreego.entity t1_obj_t1 WHERE NOT t1_obj_t1.archived AND t1_obj_t1.archived = ($1#>>'{}')::boolean AND t1_obj_t1.name ILIKE $2#>>'{}')"
]
}
},
{
"description": "Should bind all parameters with proper casting for complex generic SELECT string",
"action": "query",
"schema_id": "entity",
"filters": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Jane%",
"amount": 100,
"created_at": "2023-01-01T00:00:00Z",
"archived": false
},
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('amount', t1_obj_t1.amount, 'archived', t1_obj_t1.archived, 'created_at', t1_obj_t1.created_at, 'id', t1_obj_t1.id, 'name', t1_obj_t1.name) FROM agreego.entity t1_obj_t1 WHERE NOT t1_obj_t1.archived AND t1_obj_t1.amount = ($1#>>'{}')::numeric AND t1_obj_t1.archived = ($2#>>'{}')::boolean AND t1_obj_t1.created_at = ($3#>>'{}')::timestamptz AND t1_obj_t1.id = ($4#>>'{}')::uuid AND t1_obj_t1.name ILIKE $5#>>'{}')"
]
}
}
]
},
{
"description": "Complex Nested Queryer Execution",
"database": {
"puncs": [],
"enums": [],
"relations": [
{
"type": "relation",
"id": "00000000-0000-0000-0000-000000000001",
"constraint": "fk_contact_person",
"source_type": "contact",
"source_columns": [
"source_id"
],
"destination_type": "person",
"destination_columns": [
"id"
]
},
{
"type": "relation",
"id": "00000000-0000-0000-0000-000000000002",
"constraint": "fk_contact_phone",
"source_type": "contact",
"source_columns": [
"target_id"
],
"destination_type": "phone_number",
"destination_columns": [
"id"
]
}
],
"types": [
{
"name": "entity",
"hierarchy": [
"entity"
],
"fields": [
"id",
"type",
"archived"
],
"grouped_fields": {
"entity": [
"id",
"type",
"archived"
]
},
"field_types": {
"id": "uuid",
"type": "text",
"archived": "boolean"
},
"schemas": [
{
"$id": "entity",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"type": {
"type": "string"
},
"archived": {
"type": "boolean"
}
}
}
]
},
{
"name": "person",
"hierarchy": [
"person",
"entity"
],
"fields": [
"id",
"type",
"archived",
"first_name",
"last_name"
],
"grouped_fields": {
"entity": [
"id",
"type",
"archived"
],
"person": [
"first_name",
"last_name"
]
},
"field_types": {
"id": "uuid",
"type": "text",
"archived": "boolean",
"first_name": "text",
"last_name": "text"
},
"schemas": [
{
"$id": "base.person",
"$ref": "entity",
"properties": {
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
}
}
},
{
"$id": "full.person",
"$ref": "base.person",
"properties": {
"phone_numbers": {
"type": "array",
"items": {
"$ref": "contact",
"properties": {
"target": {
"$ref": "phone_number"
}
}
}
},
"email_addresses": {
"type": "array",
"items": {
"$ref": "contact",
"properties": {
"target": {
"$ref": "email_address"
}
}
}
},
"addresses": {
"type": "array",
"items": {
"$ref": "contact",
"properties": {
"target": {
"$ref": "address"
}
}
}
},
"contacts": {
"type": "array",
"items": {
"$ref": "contact",
"properties": {
"target": {
"oneOf": [
{
"$ref": "phone_number"
},
{
"$ref": "email_address"
},
{
"$ref": "address"
}
]
}
}
}
}
}
}
]
},
{
"name": "relationship",
"relationship": true,
"hierarchy": [
"relationship",
"entity"
],
"fields": [
"id",
"type",
"archived",
"source_id",
"source_type",
"target_id",
"target_type"
],
"grouped_fields": {
"entity": [
"id",
"type",
"archived"
],
"relationship": [
"source_id",
"source_type",
"target_id",
"target_type"
]
},
"field_types": {
"id": "uuid",
"type": "text",
"archived": "boolean",
"source_id": "uuid",
"source_type": "text",
"target_id": "uuid",
"target_type": "text"
},
"schemas": [
{
"$id": "relationship",
"$ref": "entity",
"properties": {}
}
]
},
{
"name": "contact",
"relationship": true,
"hierarchy": [
"contact",
"relationship",
"entity"
],
"fields": [
"id",
"type",
"archived",
"source_id",
"source_type",
"target_id",
"target_type",
"is_primary"
],
"grouped_fields": {
"entity": [
"id",
"type",
"archived"
],
"relationship": [
"source_id",
"source_type",
"target_id",
"target_type"
],
"contact": [
"is_primary"
]
},
"field_types": {
"id": "uuid",
"type": "text",
"archived": "boolean",
"source_id": "uuid",
"source_type": "text",
"target_id": "uuid",
"target_type": "text",
"is_primary": "boolean"
},
"schemas": [
{
"$id": "contact",
"$ref": "relationship",
"properties": {
"is_primary": {
"type": "boolean"
}
}
}
]
},
{
"name": "phone_number",
"hierarchy": [
"phone_number",
"entity"
],
"fields": [
"id",
"type",
"archived",
"number"
],
"grouped_fields": {
"entity": [
"id",
"type",
"archived"
],
"phone_number": [
"number"
]
},
"field_types": {
"id": "uuid",
"type": "text",
"archived": "boolean",
"number": "text"
},
"schemas": [
{
"$id": "phone_number",
"$ref": "entity",
"properties": {
"number": {
"type": "string"
}
}
}
]
},
{
"name": "email_address",
"hierarchy": [
"email_address",
"entity"
],
"fields": [
"id",
"type",
"archived",
"address"
],
"grouped_fields": {
"entity": [
"id",
"type",
"archived"
],
"email_address": [
"address"
]
},
"field_types": {
"id": "uuid",
"type": "text",
"archived": "boolean",
"address": "text"
},
"schemas": [
{
"$id": "email_address",
"$ref": "entity",
"properties": {
"address": {
"type": "string"
}
}
}
]
},
{
"name": "address",
"hierarchy": [
"address",
"entity"
],
"fields": [
"id",
"type",
"archived",
"city"
],
"grouped_fields": {
"entity": [
"id",
"type",
"archived"
],
"address": [
"city"
]
},
"field_types": {
"id": "uuid",
"type": "text",
"archived": "boolean",
"city": "text"
},
"schemas": [
{
"$id": "address",
"$ref": "entity",
"properties": {
"city": {
"type": "string"
}
}
}
]
}
]
},
"tests": [
{
"description": "Should execute table multi-joins on inheritance for basic schema",
"action": "query",
"schema_id": "base.person",
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('archived', t1_obj_t2.archived, 'first_name', t1_obj_t1.first_name, 'id', t1_obj_t2.id, 'last_name', t1_obj_t1.last_name, 'type', t1_obj_t2.type) FROM agreego.person t1_obj_t1 JOIN agreego.entity t1_obj_t2 ON t1_obj_t2.id = t1_obj_t1.id WHERE NOT t1_obj_t1.archived)"
]
}
},
{
"description": "Should render a massive query handling full nested tree generation and JSON aggregation for complex relationships",
"action": "query",
"schema_id": "full.person",
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('addresses', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_addresses_t3.archived, 'id', t1_obj_t2_addresses_t3.id, 'is_primary', t1_obj_t2_addresses_t1.is_primary, 'target', (SELECT jsonb_build_object('archived', t1_obj_t2_addresses_t3_target_t2.archived, 'city', t1_obj_t2_addresses_t3_target_t1.city, 'id', t1_obj_t2_addresses_t3_target_t2.id, 'type', t1_obj_t2_addresses_t3_target_t2.type) FROM agreego.address t1_obj_t2_addresses_t3_target_t1 JOIN agreego.entity t1_obj_t2_addresses_t3_target_t2 ON t1_obj_t2_addresses_t3_target_t2.id = t1_obj_t2_addresses_t3_target_t1.id WHERE NOT t1_obj_t2_addresses_t3_target_t1.archived AND t1_obj_t2_addresses_t3_target_t1.parent_id = t1_obj_t2_addresses_t3.id), 'type', t1_obj_t2_addresses_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_addresses_t1 JOIN agreego.relationship t1_obj_t2_addresses_t2 ON t1_obj_t2_addresses_t2.id = t1_obj_t2_addresses_t1.id JOIN agreego.entity t1_obj_t2_addresses_t3 ON t1_obj_t2_addresses_t3.id = t1_obj_t2_addresses_t2.id WHERE NOT t1_obj_t2_addresses_t1.archived AND t1_obj_t2_addresses_t1.parent_id = t1_obj_t2.id), 'archived', t1_obj_t2.archived, 'contacts', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_contacts_t3.archived, 'id', t1_obj_t2_contacts_t3.id, 'is_primary', t1_obj_t2_contacts_t1.is_primary, 'target', t1_obj_t2_contacts_t3.target, 'type', t1_obj_t2_contacts_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_contacts_t1 JOIN agreego.relationship t1_obj_t2_contacts_t2 ON t1_obj_t2_contacts_t2.id = t1_obj_t2_contacts_t1.id JOIN agreego.entity t1_obj_t2_contacts_t3 ON t1_obj_t2_contacts_t3.id = t1_obj_t2_contacts_t2.id WHERE NOT t1_obj_t2_contacts_t1.archived AND t1_obj_t2_contacts_t1.parent_id = t1_obj_t2.id), 'email_addresses', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_email_addresses_t3.archived, 'id', t1_obj_t2_email_addresses_t3.id, 'is_primary', t1_obj_t2_email_addresses_t1.is_primary, 'target', (SELECT jsonb_build_object('address', t1_obj_t2_email_addresses_t3_target_t1.address, 'archived', t1_obj_t2_email_addresses_t3_target_t2.archived, 'id', t1_obj_t2_email_addresses_t3_target_t2.id, 'type', t1_obj_t2_email_addresses_t3_target_t2.type) FROM agreego.email_address t1_obj_t2_email_addresses_t3_target_t1 JOIN agreego.entity t1_obj_t2_email_addresses_t3_target_t2 ON t1_obj_t2_email_addresses_t3_target_t2.id = t1_obj_t2_email_addresses_t3_target_t1.id WHERE NOT t1_obj_t2_email_addresses_t3_target_t1.archived AND t1_obj_t2_email_addresses_t3_target_t1.parent_id = t1_obj_t2_email_addresses_t3.id), 'type', t1_obj_t2_email_addresses_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_email_addresses_t1 JOIN agreego.relationship t1_obj_t2_email_addresses_t2 ON t1_obj_t2_email_addresses_t2.id = t1_obj_t2_email_addresses_t1.id JOIN agreego.entity t1_obj_t2_email_addresses_t3 ON t1_obj_t2_email_addresses_t3.id = t1_obj_t2_email_addresses_t2.id WHERE NOT t1_obj_t2_email_addresses_t1.archived AND t1_obj_t2_email_addresses_t1.parent_id = t1_obj_t2.id), 'first_name', t1_obj_t1.first_name, 'id', t1_obj_t2.id, 'last_name', t1_obj_t1.last_name, 'phone_numbers', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_phone_numbers_t3.archived, 'id', t1_obj_t2_phone_numbers_t3.id, 'is_primary', t1_obj_t2_phone_numbers_t1.is_primary, 'target', (SELECT jsonb_build_object('archived', t1_obj_t2_phone_numbers_t3_target_t2.archived, 'id', t1_obj_t2_phone_numbers_t3_target_t2.id, 'number', t1_obj_t2_phone_numbers_t3_target_t1.number, 'type', t1_obj_t2_phone_numbers_t3_target_t2.type) FROM agreego.phone_number t1_obj_t2_phone_numbers_t3_target_t1 JOIN agreego.entity t1_obj_t2_phone_numbers_t3_target_t2 ON t1_obj_t2_phone_numbers_t3_target_t2.id = t1_obj_t2_phone_numbers_t3_target_t1.id WHERE NOT t1_obj_t2_phone_numbers_t3_target_t1.archived AND t1_obj_t2_phone_numbers_t3_target_t1.parent_id = t1_obj_t2_phone_numbers_t3.id), 'type', t1_obj_t2_phone_numbers_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_phone_numbers_t1 JOIN agreego.relationship t1_obj_t2_phone_numbers_t2 ON t1_obj_t2_phone_numbers_t2.id = t1_obj_t2_phone_numbers_t1.id JOIN agreego.entity t1_obj_t2_phone_numbers_t3 ON t1_obj_t2_phone_numbers_t3.id = t1_obj_t2_phone_numbers_t2.id WHERE NOT t1_obj_t2_phone_numbers_t1.archived AND t1_obj_t2_phone_numbers_t1.parent_id = t1_obj_t2.id), 'type', t1_obj_t2.type) FROM agreego.person t1_obj_t1 JOIN agreego.entity t1_obj_t2 ON t1_obj_t2.id = t1_obj_t1.id WHERE NOT t1_obj_t1.archived)"
]
}
},
{
"description": "Should attach structural filters against the root entity object regardless of how deep the select statement builds child join maps",
"action": "query",
"schema_id": "full.person",
"filters": {
"first_name": "Jane%",
"last_name": "%Doe%",
"archived": true
},
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('addresses', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_addresses_t3.archived, 'id', t1_obj_t2_addresses_t3.id, 'is_primary', t1_obj_t2_addresses_t1.is_primary, 'target', (SELECT jsonb_build_object('archived', t1_obj_t2_addresses_t3_target_t2.archived, 'city', t1_obj_t2_addresses_t3_target_t1.city, 'id', t1_obj_t2_addresses_t3_target_t2.id, 'type', t1_obj_t2_addresses_t3_target_t2.type) FROM agreego.address t1_obj_t2_addresses_t3_target_t1 JOIN agreego.entity t1_obj_t2_addresses_t3_target_t2 ON t1_obj_t2_addresses_t3_target_t2.id = t1_obj_t2_addresses_t3_target_t1.id WHERE NOT t1_obj_t2_addresses_t3_target_t1.archived AND t1_obj_t2_addresses_t3_target_t1.parent_id = t1_obj_t2_addresses_t3.id), 'type', t1_obj_t2_addresses_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_addresses_t1 JOIN agreego.relationship t1_obj_t2_addresses_t2 ON t1_obj_t2_addresses_t2.id = t1_obj_t2_addresses_t1.id JOIN agreego.entity t1_obj_t2_addresses_t3 ON t1_obj_t2_addresses_t3.id = t1_obj_t2_addresses_t2.id WHERE NOT t1_obj_t2_addresses_t1.archived AND t1_obj_t2_addresses_t1.parent_id = t1_obj_t2.id), 'archived', t1_obj_t2.archived, 'contacts', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_contacts_t3.archived, 'id', t1_obj_t2_contacts_t3.id, 'is_primary', t1_obj_t2_contacts_t1.is_primary, 'target', t1_obj_t2_contacts_t3.target, 'type', t1_obj_t2_contacts_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_contacts_t1 JOIN agreego.relationship t1_obj_t2_contacts_t2 ON t1_obj_t2_contacts_t2.id = t1_obj_t2_contacts_t1.id JOIN agreego.entity t1_obj_t2_contacts_t3 ON t1_obj_t2_contacts_t3.id = t1_obj_t2_contacts_t2.id WHERE NOT t1_obj_t2_contacts_t1.archived AND t1_obj_t2_contacts_t1.parent_id = t1_obj_t2.id), 'email_addresses', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_email_addresses_t3.archived, 'id', t1_obj_t2_email_addresses_t3.id, 'is_primary', t1_obj_t2_email_addresses_t1.is_primary, 'target', (SELECT jsonb_build_object('address', t1_obj_t2_email_addresses_t3_target_t1.address, 'archived', t1_obj_t2_email_addresses_t3_target_t2.archived, 'id', t1_obj_t2_email_addresses_t3_target_t2.id, 'type', t1_obj_t2_email_addresses_t3_target_t2.type) FROM agreego.email_address t1_obj_t2_email_addresses_t3_target_t1 JOIN agreego.entity t1_obj_t2_email_addresses_t3_target_t2 ON t1_obj_t2_email_addresses_t3_target_t2.id = t1_obj_t2_email_addresses_t3_target_t1.id WHERE NOT t1_obj_t2_email_addresses_t3_target_t1.archived AND t1_obj_t2_email_addresses_t3_target_t1.parent_id = t1_obj_t2_email_addresses_t3.id), 'type', t1_obj_t2_email_addresses_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_email_addresses_t1 JOIN agreego.relationship t1_obj_t2_email_addresses_t2 ON t1_obj_t2_email_addresses_t2.id = t1_obj_t2_email_addresses_t1.id JOIN agreego.entity t1_obj_t2_email_addresses_t3 ON t1_obj_t2_email_addresses_t3.id = t1_obj_t2_email_addresses_t2.id WHERE NOT t1_obj_t2_email_addresses_t1.archived AND t1_obj_t2_email_addresses_t1.parent_id = t1_obj_t2.id), 'first_name', t1_obj_t1.first_name, 'id', t1_obj_t2.id, 'last_name', t1_obj_t1.last_name, 'phone_numbers', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', t1_obj_t2_phone_numbers_t3.archived, 'id', t1_obj_t2_phone_numbers_t3.id, 'is_primary', t1_obj_t2_phone_numbers_t1.is_primary, 'target', (SELECT jsonb_build_object('archived', t1_obj_t2_phone_numbers_t3_target_t2.archived, 'id', t1_obj_t2_phone_numbers_t3_target_t2.id, 'number', t1_obj_t2_phone_numbers_t3_target_t1.number, 'type', t1_obj_t2_phone_numbers_t3_target_t2.type) FROM agreego.phone_number t1_obj_t2_phone_numbers_t3_target_t1 JOIN agreego.entity t1_obj_t2_phone_numbers_t3_target_t2 ON t1_obj_t2_phone_numbers_t3_target_t2.id = t1_obj_t2_phone_numbers_t3_target_t1.id WHERE NOT t1_obj_t2_phone_numbers_t3_target_t1.archived AND t1_obj_t2_phone_numbers_t3_target_t1.parent_id = t1_obj_t2_phone_numbers_t3.id), 'type', t1_obj_t2_phone_numbers_t3.type)), '[]'::jsonb) FROM agreego.contact t1_obj_t2_phone_numbers_t1 JOIN agreego.relationship t1_obj_t2_phone_numbers_t2 ON t1_obj_t2_phone_numbers_t2.id = t1_obj_t2_phone_numbers_t1.id JOIN agreego.entity t1_obj_t2_phone_numbers_t3 ON t1_obj_t2_phone_numbers_t3.id = t1_obj_t2_phone_numbers_t2.id WHERE NOT t1_obj_t2_phone_numbers_t1.archived AND t1_obj_t2_phone_numbers_t1.parent_id = t1_obj_t2.id), 'type', t1_obj_t2.type) FROM agreego.person t1_obj_t1 JOIN agreego.entity t1_obj_t2 ON t1_obj_t2.id = t1_obj_t1.id WHERE NOT t1_obj_t1.archived AND t1_obj_t2.archived = ($1#>>'{}')::boolean AND t1_obj_t1.first_name ILIKE $2#>>'{}' AND t1_obj_t1.last_name ILIKE $3#>>'{}')"
]
}
},
{
"description": "Should extract the targeted subset payload specifically for a high-level nested list",
"action": "query",
"schema_id": "full.person",
"stem": "phone_numbers/contact",
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('archived', t1_obj_t3.archived, 'id', t1_obj_t3.id, 'is_primary', t1_obj_t1.is_primary, 'type', t1_obj_t3.type) FROM agreego.contact t1_obj_t1 JOIN agreego.relationship t1_obj_t2 ON t1_obj_t2.id = t1_obj_t1.id JOIN agreego.entity t1_obj_t3 ON t1_obj_t3.id = t1_obj_t2.id WHERE NOT t1_obj_t1.archived)"
]
}
},
{
"description": "Should successfully execute nested path extraction for targeted root subgraphs on beats",
"action": "query",
"schema_id": "full.person",
"stem": "phone_numbers/contact/phone_number",
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('archived', t1_obj_t2.archived, 'id', t1_obj_t2.id, 'number', t1_obj_t1.number, 'type', t1_obj_t2.type) FROM agreego.phone_number t1_obj_t1 JOIN agreego.entity t1_obj_t2 ON t1_obj_t2.id = t1_obj_t1.id WHERE NOT t1_obj_t1.archived)"
]
}
},
{
"description": "Should successfully resolve unique execution plans across nested properties inside relationships containing oneOf configurations",
"action": "query",
"schema_id": "full.person",
"stem": "contacts/contact/email_address",
"expect": {
"success": true,
"sql": [
"(SELECT jsonb_build_object('address', t1_obj_t1.address, 'archived', t1_obj_t2.archived, 'id', t1_obj_t2.id, 'type', t1_obj_t2.type) FROM agreego.email_address t1_obj_t1 JOIN agreego.entity t1_obj_t2 ON t1_obj_t2.id = t1_obj_t1.id WHERE NOT t1_obj_t1.archived)"
]
}
}
]
}
]

929
fixtures/ref.json Normal file
View File

@ -0,0 +1,929 @@
[
{
"description": "nested refs",
"database": {
"schemas": [
{
"$ref": "c_212",
"$id": "ref_4_0"
},
{
"$id": "a_212",
"type": "integer"
},
{
"$id": "b_212",
"$ref": "a_212"
},
{
"$id": "c_212",
"$ref": "b_212"
}
]
},
"tests": [
{
"description": "nested ref valid",
"data": 5,
"schema_id": "ref_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "nested ref invalid",
"data": "a",
"schema_id": "ref_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "ref applies alongside sibling keywords",
"database": {
"schemas": [
{
"properties": {
"foo": {
"$ref": "reffed_248",
"maxItems": 2
}
},
"$id": "ref_5_0"
},
{
"$id": "reffed_248",
"type": "array"
}
]
},
"tests": [
{
"description": "ref valid, maxItems valid",
"data": {
"foo": []
},
"schema_id": "ref_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ref valid, maxItems invalid",
"data": {
"foo": [
1,
2,
3
]
},
"schema_id": "ref_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ref invalid",
"data": {
"foo": "string"
},
"schema_id": "ref_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "property named $ref that is not a reference",
"database": {
"schemas": [
{
"properties": {
"$ref": {
"type": "string"
}
},
"$id": "ref_6_0"
}
]
},
"tests": [
{
"description": "property named $ref valid",
"data": {
"$ref": "a"
},
"schema_id": "ref_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "property named $ref invalid",
"data": {
"$ref": 2
},
"schema_id": "ref_6_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "property named $ref, containing an actual $ref",
"database": {
"schemas": [
{
"properties": {
"$ref": {
"$ref": "is-string_344"
}
},
"$id": "ref_7_0"
},
{
"$id": "is-string_344",
"type": "string"
}
]
},
"tests": [
{
"description": "property named $ref valid",
"data": {
"$ref": "a"
},
"schema_id": "ref_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "property named $ref invalid",
"data": {
"$ref": 2
},
"schema_id": "ref_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "$ref to boolean schema true",
"database": {
"schemas": [
{
"$ref": "bool_378",
"$id": "ref_8_0"
},
{
"$id": "bool_378",
"extensible": true
}
]
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"schema_id": "ref_8_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "$ref to boolean schema false",
"database": {
"schemas": [
{
"$ref": "bool_400",
"$id": "ref_9_0"
},
{
"$id": "bool_400",
"extensible": false,
"not": {}
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"schema_id": "ref_9_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "refs with quote",
"database": {
"schemas": [
{
"properties": {
"foo\"bar": {
"$ref": "foo%22bar_550"
}
},
"$id": "ref_11_0"
},
{
"$id": "foo%22bar_550",
"type": "number"
}
]
},
"tests": [
{
"description": "object with numbers is valid",
"data": {
"foo\"bar": 1
},
"schema_id": "ref_11_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with strings is invalid",
"data": {
"foo\"bar": "1"
},
"schema_id": "ref_11_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "$ref boundary resets to loose",
"database": {
"schemas": [
{
"$ref": "target_1465",
"$id": "ref_35_0"
},
{
"$id": "target_1465",
"properties": {
"foo": {
"type": "string"
}
}
}
]
},
"tests": [
{
"description": "extra property in ref target is invalid (strict by default)",
"data": {
"foo": "bar",
"extra": 1
},
"schema_id": "ref_35_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "$ref target can enforce strictness",
"database": {
"schemas": [
{
"$ref": "target_1496",
"$id": "ref_36_0"
},
{
"$id": "target_1496",
"extensible": false,
"properties": {
"foo": {
"type": "string"
}
}
}
]
},
"tests": [
{
"description": "extra property in ref target is invalid",
"data": {
"foo": "bar",
"extra": 1
},
"schema_id": "ref_36_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "strictness: boundary reset at $ref",
"database": {
"schemas": [
{
"extensible": true,
"properties": {
"inline_child": {
"properties": {
"a": {
"type": "integer"
}
}
},
"ref_child": {
"$ref": "strict_node_1544"
},
"extensible_ref_child": {
"$ref": "extensible_node_1551"
}
},
"$id": "ref_37_0"
},
{
"$id": "strict_node_1544",
"properties": {
"b": {
"type": "integer"
}
}
},
{
"$id": "extensible_node_1551",
"extensible": true,
"properties": {
"c": {
"type": "integer"
}
}
}
]
},
"tests": [
{
"description": "inline child inherits looseness",
"data": {
"inline_child": {
"a": 1,
"extra": 2
}
},
"schema_id": "ref_37_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ref child resets to strict (default)",
"data": {
"ref_child": {
"b": 1,
"extra": 2
}
},
"schema_id": "ref_37_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ref child with explicit extensible=true is loose",
"data": {
"extensible_ref_child": {
"c": 1,
"extra": 2
}
},
"schema_id": "ref_37_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "arrays: ref items inherit strictness (reset at boundary)",
"database": {
"schemas": [
{
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "strict_node_1614"
}
}
},
"$id": "ref_38_0"
},
{
"$id": "strict_node_1614",
"properties": {
"a": {
"type": "integer"
}
}
}
]
},
"tests": [
{
"description": "ref item with extra property is invalid (strict by default)",
"data": {
"list": [
{
"a": 1,
"extra": 2
}
]
},
"schema_id": "ref_38_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "implicit keyword shadowing",
"database": {
"schemas": [
{
"$ref": "parent_1648",
"properties": {
"type": {
"const": "child"
},
"age": {
"minimum": 15
}
},
"$id": "ref_39_0"
},
{
"$id": "parent_1648",
"type": "object",
"properties": {
"type": {
"const": "parent"
},
"age": {
"minimum": 10,
"maximum": 20
}
},
"required": [
"type",
"age"
]
}
]
},
"tests": [
{
"description": "child type overrides parent type",
"data": {
"type": "child",
"age": 15
},
"schema_id": "ref_39_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "parent type is now invalid (shadowed)",
"data": {
"type": "parent",
"age": 15
},
"schema_id": "ref_39_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "child min age (15) is enforced",
"data": {
"type": "child",
"age": 12
},
"schema_id": "ref_39_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "parent max age (20) is shadowed (replaced) by child definition",
"data": {
"type": "child",
"age": 21
},
"schema_id": "ref_39_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "Entities extending entities (Physical Birth)",
"database": {
"types": [
{
"name": "entity",
"variations": [
"entity",
"organization",
"person"
],
"schemas": [
{
"$id": "entity",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
}
}
}
]
},
{
"name": "organization",
"variations": [
"organization",
"person"
],
"schemas": [
{
"$id": "organization",
"$ref": "entity",
"properties": {
"name": {
"type": "string"
}
}
}
]
},
{
"name": "person",
"variations": [
"person"
],
"schemas": [
{
"$id": "person",
"$ref": "organization",
"properties": {
"first_name": {
"type": "string"
}
}
}
]
}
],
"puncs": [
{
"name": "save_org",
"schemas": [
{
"$id": "save_org.request",
"$ref": "organization"
}
]
}
]
},
"tests": [
{
"description": "Valid person against organization schema (implicit type allowance from physical hierarchy)",
"schema_id": "save_org.request",
"data": {
"id": "1",
"type": "person",
"name": "ACME"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Valid organization against organization schema",
"schema_id": "save_org.request",
"data": {
"id": "2",
"type": "organization",
"name": "ACME"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Invalid entity against organization schema (ancestor not allowed)",
"schema_id": "save_org.request",
"data": {
"id": "3",
"type": "entity"
},
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "TYPE_MISMATCH",
"path": "/type"
}
]
}
}
]
},
{
"description": "Viral Infection: Ad-hocs inheriting entity boundaries via $ref",
"database": {
"types": [
{
"name": "entity",
"variations": [
"entity",
"person"
],
"schemas": [
{
"$id": "entity",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
}
}
}
]
},
{
"name": "person",
"variations": [
"person"
],
"schemas": [
{
"$id": "person",
"$ref": "entity",
"properties": {
"first_name": {
"type": "string"
}
}
},
{
"$id": "light.person",
"$ref": "entity",
"properties": {
"first_name": {
"type": "string"
}
}
}
]
}
],
"puncs": [
{
"name": "save_person_light",
"schemas": [
{
"$id": "save_person_light.request",
"$ref": "light.person",
"properties": {
"extra_request_field": {
"type": "string"
}
}
}
]
}
]
},
"tests": [
{
"description": "Valid person against ad-hoc request schema (request virally inherited person variations)",
"schema_id": "save_person_light.request",
"data": {
"id": "1",
"type": "person",
"first_name": "John",
"extra_request_field": "test"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Invalid entity against ad-hoc request schema (viral inheritance enforces person boundary)",
"schema_id": "save_person_light.request",
"data": {
"id": "1",
"type": "entity",
"first_name": "John"
},
"action": "validate",
"expect": {
"success": false,
"errors": [
{
"code": "TYPE_MISMATCH",
"path": "/type"
}
]
}
}
]
},
{
"description": "Ad-hocs extending ad-hocs (No type property)",
"database": {
"puncs": [
{
"name": "save_address",
"schemas": [
{
"$id": "address",
"type": "object",
"properties": {
"street": {
"type": "string"
},
"city": {
"type": "string"
}
}
},
{
"$id": "us_address",
"$ref": "address",
"properties": {
"state": {
"type": "string"
},
"zip": {
"type": "string"
}
}
},
{
"$id": "save_address.request",
"$ref": "us_address"
}
]
}
]
},
"tests": [
{
"description": "Valid us_address",
"schema_id": "save_address.request",
"data": {
"street": "123 Main",
"city": "Anytown",
"state": "CA",
"zip": "12345"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Invalid base address against us_address",
"schema_id": "save_address.request",
"data": {
"street": "123 Main",
"city": "Anytown"
},
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "Ad-hocs extending ad-hocs (with string type property, no magic)",
"database": {
"puncs": [
{
"name": "save_config",
"schemas": [
{
"$id": "config_base",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "config_base"
},
"setting": {
"type": "string"
}
}
},
{
"$id": "config_advanced",
"$ref": "config_base",
"properties": {
"type": {
"type": "string",
"const": "config_advanced"
},
"advanced_setting": {
"type": "string"
}
}
},
{
"$id": "save_config.request",
"$ref": "config_base"
}
]
}
]
},
"tests": [
{
"description": "Valid config_base against config_base",
"schema_id": "save_config.request",
"data": {
"type": "config_base",
"setting": "on"
},
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "Invalid config_advanced against config_base (no type magic, const is strictly 'config_base')",
"schema_id": "save_config.request",
"data": {
"type": "config_advanced",
"setting": "on",
"advanced_setting": "off"
},
"action": "validate",
"expect": {
"success": false
}
}
]
}
]

312
fixtures/required.json Normal file
View File

@ -0,0 +1,312 @@
[
{
"description": "required validation",
"database": {
"schemas": [
{
"properties": {
"foo": {},
"bar": {}
},
"required": [
"foo"
],
"$id": "required_0_0"
}
]
},
"tests": [
{
"description": "present required property is valid",
"data": {
"foo": 1
},
"schema_id": "required_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "non-present required property is invalid",
"data": {
"bar": 1
},
"schema_id": "required_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "ignores arrays",
"data": [],
"schema_id": "required_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores strings",
"data": "",
"schema_id": "required_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "required_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores null",
"data": null,
"schema_id": "required_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores boolean",
"data": true,
"schema_id": "required_0_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "required default validation",
"database": {
"schemas": [
{
"properties": {
"foo": {}
},
"$id": "required_1_0"
}
]
},
"tests": [
{
"description": "not required by default",
"data": {},
"schema_id": "required_1_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "required with empty array",
"database": {
"schemas": [
{
"properties": {
"foo": {}
},
"required": [],
"$id": "required_2_0"
}
]
},
"tests": [
{
"description": "property not required",
"data": {},
"schema_id": "required_2_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "required with escaped characters",
"database": {
"schemas": [
{
"required": [
"foo\nbar",
"foo\"bar",
"foo\\bar",
"foo\rbar",
"foo\tbar",
"foo\fbar"
],
"extensible": true,
"$id": "required_3_0"
}
]
},
"tests": [
{
"description": "object with all properties present is valid",
"data": {
"foo\nbar": 1,
"foo\"bar": 1,
"foo\\bar": 1,
"foo\rbar": 1,
"foo\tbar": 1,
"foo\fbar": 1
},
"schema_id": "required_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object with some properties missing is invalid",
"data": {
"foo\nbar": "1",
"foo\"bar": "1"
},
"schema_id": "required_3_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "required properties whose names are Javascript object property names",
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
"database": {
"schemas": [
{
"required": [
"__proto__",
"toString",
"constructor"
],
"extensible": true,
"$id": "required_4_0"
}
]
},
"tests": [
{
"description": "ignores arrays",
"data": [],
"schema_id": "required_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "ignores other non-objects",
"data": 12,
"schema_id": "required_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "none of the properties mentioned",
"data": {},
"schema_id": "required_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "__proto__ present",
"data": {
"__proto__": "foo"
},
"schema_id": "required_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "toString present",
"data": {
"toString": {
"length": 37
}
},
"schema_id": "required_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "constructor present",
"data": {
"constructor": {
"length": 37
}
},
"schema_id": "required_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "all present",
"data": {
"__proto__": 12,
"toString": {
"length": "foo"
},
"constructor": 37
},
"schema_id": "required_4_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "extensible: true allows extra properties in required",
"database": {
"schemas": [
{
"required": [
"foo"
],
"extensible": true,
"$id": "required_5_0"
}
]
},
"tests": [
{
"description": "extra property is valid",
"data": {
"foo": 1,
"bar": 2
},
"schema_id": "required_5_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

912
fixtures/type.json Normal file
View File

@ -0,0 +1,912 @@
[
{
"description": "integer type matches integers",
"database": {
"schemas": [
{
"type": "integer",
"$id": "type_0_0"
}
]
},
"tests": [
{
"description": "an integer is an integer",
"data": 1,
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a float with zero fractional part is an integer",
"data": 1,
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a float is not an integer",
"data": 1.1,
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is not an integer",
"data": "foo",
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is still not an integer, even if it looks like one",
"data": "1",
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an object is not an integer",
"data": {},
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an array is not an integer",
"data": [],
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a boolean is not an integer",
"data": true,
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is not an integer",
"data": null,
"schema_id": "type_0_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "number type matches numbers",
"database": {
"schemas": [
{
"type": "number",
"$id": "type_1_0"
}
]
},
"tests": [
{
"description": "an integer is a number",
"data": 1,
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a float with zero fractional part is a number (and an integer)",
"data": 1,
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a float is a number",
"data": 1.1,
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a string is not a number",
"data": "foo",
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is still not a number, even if it looks like one",
"data": "1",
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an object is not a number",
"data": {},
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an array is not a number",
"data": [],
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a boolean is not a number",
"data": true,
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is not a number",
"data": null,
"schema_id": "type_1_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "string type matches strings",
"database": {
"schemas": [
{
"type": "string",
"$id": "type_2_0"
}
]
},
"tests": [
{
"description": "1 is not a string",
"data": 1,
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a float is not a string",
"data": 1.1,
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is a string",
"data": "foo",
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a string is still a string, even if it looks like a number",
"data": "1",
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an empty string is still a string",
"data": "",
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an object is not a string",
"data": {},
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an array is not a string",
"data": [],
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a boolean is not a string",
"data": true,
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is not a string",
"data": null,
"schema_id": "type_2_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "object type matches objects",
"database": {
"schemas": [
{
"type": "object",
"$id": "type_3_0"
}
]
},
"tests": [
{
"description": "an integer is not an object",
"data": 1,
"schema_id": "type_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a float is not an object",
"data": 1.1,
"schema_id": "type_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is not an object",
"data": "foo",
"schema_id": "type_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an object is an object",
"data": {},
"schema_id": "type_3_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an array is not an object",
"data": [],
"schema_id": "type_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a boolean is not an object",
"data": true,
"schema_id": "type_3_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is not an object",
"data": null,
"schema_id": "type_3_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "array type matches arrays",
"database": {
"schemas": [
{
"type": "array",
"$id": "type_4_0"
}
]
},
"tests": [
{
"description": "an integer is not an array",
"data": 1,
"schema_id": "type_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a float is not an array",
"data": 1.1,
"schema_id": "type_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is not an array",
"data": "foo",
"schema_id": "type_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an object is not an array",
"data": {},
"schema_id": "type_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an array is an array",
"data": [],
"schema_id": "type_4_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a boolean is not an array",
"data": true,
"schema_id": "type_4_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is not an array",
"data": null,
"schema_id": "type_4_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "boolean type matches booleans",
"database": {
"schemas": [
{
"type": "boolean",
"$id": "type_5_0"
}
]
},
"tests": [
{
"description": "an integer is not a boolean",
"data": 1,
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "zero is not a boolean",
"data": 0,
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a float is not a boolean",
"data": 1.1,
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is not a boolean",
"data": "foo",
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an empty string is a null",
"data": "",
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an object is not a boolean",
"data": {},
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an array is not a boolean",
"data": [],
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "true is a boolean",
"data": true,
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "false is a boolean",
"data": false,
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "null is not a boolean",
"data": null,
"schema_id": "type_5_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "null type matches only the null object",
"database": {
"schemas": [
{
"type": "null",
"$id": "type_6_0"
}
]
},
"tests": [
{
"description": "an integer is not null",
"data": 1,
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a float is not null",
"data": 1.1,
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "zero is not null",
"data": 0,
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a string is not null",
"data": "foo",
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an empty string is null",
"data": "",
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "an object is not null",
"data": {},
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an array is not null",
"data": [],
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "true is not null",
"data": true,
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "false is not null",
"data": false,
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is null",
"data": null,
"schema_id": "type_6_0",
"action": "validate",
"expect": {
"success": true
}
}
]
},
{
"description": "multiple types can be specified in an array",
"database": {
"schemas": [
{
"type": [
"integer",
"string"
],
"$id": "type_7_0"
}
]
},
"tests": [
{
"description": "an integer is valid",
"data": 1,
"schema_id": "type_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a string is valid",
"data": "foo",
"schema_id": "type_7_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "a float is invalid",
"data": 1.1,
"schema_id": "type_7_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an object is invalid",
"data": {},
"schema_id": "type_7_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "an array is invalid",
"data": [],
"schema_id": "type_7_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "a boolean is invalid",
"data": true,
"schema_id": "type_7_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is invalid",
"data": null,
"schema_id": "type_7_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "type as array with one item",
"database": {
"schemas": [
{
"type": [
"string"
],
"$id": "type_8_0"
}
]
},
"tests": [
{
"description": "string is valid",
"data": "foo",
"schema_id": "type_8_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "number is invalid",
"data": 123,
"schema_id": "type_8_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "type: array or object",
"database": {
"schemas": [
{
"type": [
"array",
"object"
],
"items": {},
"$id": "type_9_0"
}
]
},
"tests": [
{
"description": "array is valid",
"data": [
1,
2,
3
],
"schema_id": "type_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object is valid",
"data": {},
"schema_id": "type_9_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "number is invalid",
"data": 123,
"schema_id": "type_9_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "string is invalid",
"data": "foo",
"schema_id": "type_9_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "null is invalid",
"data": null,
"schema_id": "type_9_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "type: array, object or null",
"database": {
"schemas": [
{
"type": [
"array",
"object",
"null"
],
"items": {},
"$id": "type_10_0"
}
]
},
"tests": [
{
"description": "array is valid",
"data": [
1,
2,
3
],
"schema_id": "type_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "object is valid",
"data": {},
"schema_id": "type_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "null is valid",
"data": null,
"schema_id": "type_10_0",
"action": "validate",
"expect": {
"success": true
}
},
{
"description": "number is invalid",
"data": 123,
"schema_id": "type_10_0",
"action": "validate",
"expect": {
"success": false
}
},
{
"description": "string is invalid",
"data": "foo",
"schema_id": "type_10_0",
"action": "validate",
"expect": {
"success": false
}
}
]
},
{
"description": "extensible: true allows extra properties",
"database": {
"schemas": [
{
"type": "object",
"extensible": true,
"$id": "type_11_0"
}
]
},
"tests": [
{
"description": "extra property is valid",
"data": {
"foo": 1
},
"schema_id": "type_11_0",
"action": "validate",
"expect": {
"success": true
}
}
]
}
]

1171
fixtures/uniqueItems.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
const fs = require('fs');
const path = require('path');
const fixturesDir = path.join(__dirname, 'tests', 'fixtures');
function processFile(filePath) {
const content = fs.readFileSync(filePath, 'utf8');
let data;
try {
data = JSON.parse(content);
} catch (e) {
console.error(`Skipping ${filePath} due to parse error`);
return;
}
let modified = false;
data.forEach(suite => {
if (suite.tests) {
suite.tests.forEach(test => {
if (test.valid !== undefined || test.expect_errors !== undefined) {
if (!test.expect) {
test.expect = {};
}
if (test.valid !== undefined) {
test.expect.success = test.valid;
delete test.valid;
}
if (test.expect_errors !== undefined) {
test.expect.errors = test.expect_errors;
delete test.expect_errors;
}
modified = true;
}
});
}
});
if (modified) {
fs.writeFileSync(filePath, JSON.stringify(data, null, 4));
console.log(`Migrated ${filePath}`);
}
}
function walkDir(dir) {
const files = fs.readdirSync(dir);
files.forEach(file => {
const fullPath = path.join(dir, file);
if (fs.statSync(fullPath).isDirectory()) {
walkDir(fullPath);
} else if (fullPath.endsWith('.json')) {
processFile(fullPath);
}
});
}
walkDir(fixturesDir);
console.log('Done migrating fixtures!');

View File

@ -0,0 +1,88 @@
use crate::database::executors::DatabaseExecutor;
use serde_json::Value;
#[cfg(test)]
use std::cell::RefCell;
#[cfg(test)]
pub struct MockState {
pub captured_queries: Vec<String>,
pub query_responses: Vec<Result<Value, String>>,
pub execute_responses: Vec<Result<(), String>>,
}
#[cfg(test)]
impl MockState {
pub fn new() -> Self {
Self {
captured_queries: Default::default(),
query_responses: Default::default(),
execute_responses: Default::default(),
}
}
}
#[cfg(test)]
thread_local! {
pub static MOCK_STATE: RefCell<MockState> = RefCell::new(MockState::new());
}
#[cfg(test)]
pub struct MockExecutor {}
#[cfg(test)]
impl MockExecutor {
pub fn new() -> Self {
Self {}
}
}
#[cfg(test)]
impl DatabaseExecutor for MockExecutor {
fn query(&self, sql: &str, _args: Option<&[Value]>) -> Result<Value, String> {
println!("DEBUG SQL QUERY: {}", sql);
MOCK_STATE.with(|state| {
let mut s = state.borrow_mut();
s.captured_queries.push(sql.to_string());
if s.query_responses.is_empty() {
return Ok(Value::Array(vec![]));
}
s.query_responses.remove(0)
})
}
fn execute(&self, sql: &str, _args: Option<&[Value]>) -> Result<(), String> {
println!("DEBUG SQL EXECUTE: {}", sql);
MOCK_STATE.with(|state| {
let mut s = state.borrow_mut();
s.captured_queries.push(sql.to_string());
if s.execute_responses.is_empty() {
return Ok(());
}
s.execute_responses.remove(0)
})
}
fn auth_user_id(&self) -> Result<String, String> {
Ok("00000000-0000-0000-0000-000000000000".to_string())
}
fn timestamp(&self) -> Result<String, String> {
Ok("2026-03-10T00:00:00Z".to_string())
}
#[cfg(test)]
fn get_queries(&self) -> Vec<String> {
MOCK_STATE.with(|state| state.borrow().captured_queries.clone())
}
#[cfg(test)]
fn reset_mocks(&self) {
MOCK_STATE.with(|state| {
let mut s = state.borrow_mut();
s.captured_queries.clear();
s.query_responses.clear();
s.execute_responses.clear();
});
}
}

View File

@ -0,0 +1,28 @@
pub mod mock;
#[cfg(not(test))]
pub mod pgrx;
use serde_json::Value;
/// An abstraction over database execution to allow for isolated unit testing
/// without a live Postgres SPI connection.
pub trait DatabaseExecutor: Send + Sync {
/// Executes a query expecting a single JSONB return, representing rows.
fn query(&self, sql: &str, args: Option<&[Value]>) -> Result<Value, String>;
/// Executes an operation (INSERT, UPDATE, DELETE, or pg_notify) that does not return rows.
fn execute(&self, sql: &str, args: Option<&[Value]>) -> Result<(), String>;
/// Returns the current authenticated user's ID
fn auth_user_id(&self) -> Result<String, String>;
/// Returns the current transaction timestamp
fn timestamp(&self) -> Result<String, String>;
#[cfg(test)]
fn get_queries(&self) -> Vec<String>;
#[cfg(test)]
fn reset_mocks(&self);
}

View File

@ -1,22 +1,7 @@
use crate::database::executors::DatabaseExecutor;
use pgrx::prelude::*;
use serde_json::Value;
/// An abstraction over database execution to allow for isolated unit testing
/// without a live Postgres SPI connection.
pub trait DatabaseExecutor: Send + Sync {
/// Executes a query expecting a single JSONB return, representing rows.
fn query(&self, sql: &str, args: Option<&[Value]>) -> Result<Value, String>;
/// Executes an operation (INSERT, UPDATE, DELETE, or pg_notify) that does not return rows.
fn execute(&self, sql: &str, args: Option<&[Value]>) -> Result<(), String>;
/// Returns the current authenticated user's ID
fn auth_user_id(&self) -> Result<String, String>;
/// Returns the current transaction timestamp
fn timestamp(&self) -> Result<String, String>;
}
/// The production executor that wraps `pgrx::spi::Spi`.
pub struct SpiExecutor;

View File

@ -1,5 +1,5 @@
pub mod r#enum;
pub mod executor;
pub mod executors;
pub mod formats;
pub mod page;
pub mod punc;
@ -7,14 +7,26 @@ pub mod relation;
pub mod schema;
pub mod r#type;
use crate::database::r#enum::Enum;
use crate::database::executor::{DatabaseExecutor, SpiExecutor};
use crate::database::punc::{Punc, Stem};
use crate::database::relation::Relation;
use crate::database::schema::Schema;
use crate::database::r#type::Type;
// External mock exports inside the executor sub-folder
use r#enum::Enum;
use executors::DatabaseExecutor;
#[cfg(not(test))]
use executors::pgrx::SpiExecutor;
#[cfg(test)]
use executors::mock::MockExecutor;
pub mod stem;
use punc::Punc;
use relation::Relation;
use schema::Schema;
use serde_json::Value;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use stem::Stem;
use r#type::Type;
pub struct Database {
pub enums: HashMap<String, Enum>,
@ -22,22 +34,28 @@ pub struct Database {
pub puncs: HashMap<String, Punc>,
pub relations: HashMap<String, Relation>,
pub schemas: HashMap<String, Schema>,
// Map of Schema ID -> { Entity Type -> Target Subschema Arc }
pub stems: HashMap<String, HashMap<String, Arc<Stem>>>,
pub descendants: HashMap<String, Vec<String>>,
pub depths: HashMap<String, usize>,
pub executor: Box<dyn DatabaseExecutor + Send + Sync>,
}
impl Database {
pub fn new(val: &serde_json::Value) -> Self {
pub fn new(val: &serde_json::Value) -> Result<Self, crate::drop::Drop> {
let mut db = Self {
enums: HashMap::new(),
types: HashMap::new(),
relations: HashMap::new(),
puncs: HashMap::new(),
schemas: HashMap::new(),
stems: HashMap::new(),
descendants: HashMap::new(),
depths: HashMap::new(),
#[cfg(not(test))]
executor: Box::new(SpiExecutor::new()),
#[cfg(test)]
executor: Box::new(MockExecutor::new()),
};
if let Some(arr) = val.get("enums").and_then(|v| v.as_array()) {
@ -58,9 +76,12 @@ impl Database {
if let Some(arr) = val.get("relations").and_then(|v| v.as_array()) {
for item in arr {
if let Ok(def) = serde_json::from_value::<Relation>(item.clone()) {
match serde_json::from_value::<Relation>(item.clone()) {
Ok(def) => {
db.relations.insert(def.constraint.clone(), def);
}
Err(e) => println!("DATABASE RELATION PARSE FAILED: {:?}", e),
}
}
}
@ -86,8 +107,8 @@ impl Database {
}
}
let _ = db.compile();
db
db.compile()?;
Ok(db)
}
/// Override the default executor for unit testing
@ -117,12 +138,12 @@ impl Database {
}
/// Organizes the graph of the database, compiling regex, format functions, and caching relationships.
fn compile(&mut self) -> Result<(), String> {
pub fn compile(&mut self) -> Result<(), crate::drop::Drop> {
self.collect_schemas();
self.collect_depths();
self.collect_descendants();
self.compile_schemas();
self.collect_stems();
self.collect_stems()?;
Ok(())
}
@ -229,88 +250,78 @@ impl Database {
}
}
fn collect_stems(&mut self) {
let mut st_map: HashMap<String, Vec<Stem>> = HashMap::new();
for (name, _) in &self.puncs {
let mut stems = Vec::new();
let response_id = format!("{}.response", name);
if let Some(resp_schema) = self.schemas.get(&response_id) {
fn collect_stems(&mut self) -> Result<(), crate::drop::Drop> {
let mut db_stems: HashMap<String, HashMap<String, Arc<Stem>>> = HashMap::new();
let mut errors: Vec<crate::drop::Error> = Vec::new();
let schema_ids: Vec<String> = self.schemas.keys().cloned().collect();
for schema_id in schema_ids {
if let Some(schema) = self.schemas.get(&schema_id) {
let mut inner_map = HashMap::new();
Self::discover_stems(
&self.types,
&self.schemas,
&self.relations,
&response_id,
resp_schema,
self,
&schema_id,
schema,
String::from(""),
None,
None,
&mut stems,
&mut inner_map,
&mut errors,
);
}
st_map.insert(name.clone(), stems);
}
for (name, stems) in st_map {
if let Some(p) = self.puncs.get_mut(&name) {
p.stems = stems;
if !inner_map.is_empty() {
println!("SCHEMA: {} STEMS: {:?}", schema_id, inner_map.keys());
db_stems.insert(schema_id, inner_map);
}
}
}
self.stems = db_stems;
if !errors.is_empty() {
return Err(crate::drop::Drop::with_errors(errors));
}
Ok(())
}
fn discover_stems(
types: &HashMap<String, Type>,
schemas: &HashMap<String, Schema>,
relations: &HashMap<String, Relation>,
_schema_id: &str,
db: &Database,
root_schema_id: &str,
schema: &Schema,
current_path: String,
mut current_path: String,
parent_type: Option<String>,
property_name: Option<String>,
stems: &mut Vec<Stem>,
inner_map: &mut HashMap<String, Arc<Stem>>,
errors: &mut Vec<crate::drop::Error>,
) {
let mut is_entity = false;
let mut entity_type = String::new();
// Check if this schema resolves to an Entity
let mut current_ref = schema.obj.r#ref.clone();
let mut depth = 0;
while let Some(r) = current_ref {
if types.contains_key(&r) {
is_entity = true;
entity_type = r.clone();
break;
}
if let Some(s) = schemas.get(&r) {
current_ref = s.obj.r#ref.clone();
} else {
break;
}
depth += 1;
if depth > 20 {
break;
} // prevent infinite loop
let mut examine_id = None;
if let Some(ref r) = schema.obj.r#ref {
examine_id = Some(r.clone());
} else if let Some(ref id) = schema.obj.id {
examine_id = Some(id.clone());
}
if is_entity {
let final_path = if current_path.is_empty() {
"/".to_string()
} else {
current_path.clone()
};
if let Some(target) = examine_id {
let parts: Vec<&str> = target.split('.').collect();
if let Some(last_seg) = parts.last() {
if db.types.contains_key(*last_seg) {
is_entity = true;
entity_type = last_seg.to_string();
}
}
}
let mut relation_col = None;
if is_entity {
if let (Some(pt), Some(prop)) = (&parent_type, &property_name) {
let expected_col = format!("{}_id", prop);
let mut found = false;
// Try to find the exact relation from the database schema
for rel in relations.values() {
if rel.source_type == *pt && rel.destination_type == entity_type {
if rel.source_columns.contains(&expected_col) {
relation_col = Some(expected_col.clone());
found = true;
break;
}
} else if rel.source_type == entity_type && rel.destination_type == *pt {
for rel in db.relations.values() {
if (rel.source_type == *pt && rel.destination_type == entity_type)
|| (rel.source_type == entity_type && rel.destination_type == *pt)
{
if rel.source_columns.contains(&expected_col) {
relation_col = Some(expected_col.clone());
found = true;
@ -318,64 +329,128 @@ impl Database {
}
}
}
if !found {
// Fallback guess if explicit matching fails
relation_col = Some(expected_col);
}
}
stems.push(Stem {
path: final_path,
let stem = Stem {
r#type: entity_type.clone(),
relation: relation_col,
schema: Arc::new(schema.clone()),
};
let mut branch_path = current_path.clone();
if !current_path.is_empty() {
branch_path = format!("{}/{}", current_path, entity_type);
}
if inner_map.contains_key(&branch_path) {
errors.push(crate::drop::Error {
code: "STEM_COLLISION".to_string(),
message: format!("The stem path `{}` resolves to multiple Entity boundaries. This usually occurs during un-wrapped $family or oneOf polymorphic schemas where multiple Entities are directly assigned to the same property. To fix this, encapsulate the polymorphic branch.", branch_path),
details: crate::drop::ErrorDetails {
path: root_schema_id.to_string(),
},
});
}
// Pass the new parent downwards
inner_map.insert(branch_path.clone(), Arc::new(stem));
// Update current_path for structural children
current_path = branch_path;
}
let next_parent = if is_entity {
Some(entity_type.clone())
} else {
parent_type.clone()
};
// Properties branch
if let Some(props) = &schema.obj.properties {
for (k, v) in props {
let next_path = format!(
"{}/{}",
if current_path.is_empty() {
""
} else {
&current_path
},
k
);
// Bypass target and source properties if we are in a relationship
if let Some(parent_str) = &next_parent {
if let Some(pt) = db.types.get(parent_str) {
if pt.relationship && (k == "target" || k == "source") {
Self::discover_stems(
types,
schemas,
relations,
"",
db,
root_schema_id,
v,
current_path.clone(),
next_parent.clone(),
Some(k.clone()),
inner_map,
errors,
);
continue;
}
}
}
// Standard Property Pathing
let next_path = if current_path.is_empty() {
k.clone()
} else {
format!("{}/{}", current_path, k)
};
Self::discover_stems(
db,
root_schema_id,
v,
next_path,
next_parent.clone(),
Some(k.clone()),
stems,
inner_map,
errors,
);
}
}
// Array Item branch
if let Some(items) = &schema.obj.items {
Self::discover_stems(
types,
schemas,
relations,
"",
db,
root_schema_id,
items,
current_path.clone(),
next_parent.clone(),
property_name.clone(),
stems,
inner_map,
errors,
);
}
// Polymorphism branch
if let Some(arr) = &schema.obj.one_of {
for v in arr {
Self::discover_stems(
db,
root_schema_id,
v.as_ref(),
current_path.clone(),
next_parent.clone(),
property_name.clone(),
inner_map,
errors,
);
}
}
if let Some(arr) = &schema.obj.all_of {
for v in arr {
Self::discover_stems(
db,
root_schema_id,
v.as_ref(),
current_path.clone(),
next_parent.clone(),
property_name.clone(),
inner_map,
errors,
);
}
}
}
}

View File

@ -2,14 +2,6 @@ use crate::database::page::Page;
use crate::database::schema::Schema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Stem {
pub path: String,
pub r#type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub relation: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct Punc {
@ -25,6 +17,4 @@ pub struct Punc {
pub page: Option<Page>,
#[serde(default)]
pub schemas: Vec<Schema>,
#[serde(default)]
pub stems: Vec<Stem>,
}

View File

@ -5,6 +5,14 @@ use std::sync::Arc;
// Schema mirrors the Go Punc Generator's schema struct for consistency.
// It is an order-preserving representation of a JSON Schema.
pub fn deserialize_some<'de, D>(deserializer: D) -> Result<Option<Value>, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = Value::deserialize(deserializer)?;
Ok(Some(v))
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SchemaObject {
// Core Schema Keywords
@ -79,7 +87,7 @@ pub struct SchemaObject {
#[serde(
default,
rename = "const",
deserialize_with = "crate::validator::util::deserialize_some"
deserialize_with = "crate::database::schema::deserialize_some"
)]
pub const_: Option<Value>,
@ -96,8 +104,6 @@ pub struct SchemaObject {
// Combining Keywords
#[serde(rename = "allOf")]
pub all_of: Option<Vec<Arc<Schema>>>,
#[serde(rename = "anyOf")]
pub any_of: Option<Vec<Arc<Schema>>>,
#[serde(rename = "oneOf")]
pub one_of: Option<Vec<Arc<Schema>>>,
#[serde(rename = "not")]
@ -238,9 +244,6 @@ impl Schema {
if let Some(arr) = &mut self.obj.all_of {
map_arr(arr);
}
if let Some(arr) = &mut self.obj.any_of {
map_arr(arr);
}
if let Some(arr) = &mut self.obj.one_of {
map_arr(arr);
}
@ -300,7 +303,6 @@ impl<'de> Deserialize<'de> for Schema {
&& obj.enum_.is_none()
&& obj.const_.is_none()
&& obj.all_of.is_none()
&& obj.any_of.is_none()
&& obj.one_of.is_none()
&& obj.not.is_none()
&& obj.if_.is_none()

17
src/database/stem.rs Normal file
View File

@ -0,0 +1,17 @@
use crate::database::schema::Schema;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Stem {
pub r#type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub relation: Option<String>,
// The actual database schema node mapping for
// O(1) jump table execution for queryer.
//
// Automatically skipped from `jspg_stems()` JSON payload output.
#[serde(skip)]
pub schema: Arc<Schema>,
}

View File

@ -12,18 +12,18 @@ pub struct Jspg {
}
impl Jspg {
pub fn new(database_val: &serde_json::Value) -> Self {
let database_instance = Database::new(database_val);
pub fn new(database_val: &serde_json::Value) -> Result<Self, crate::drop::Drop> {
let database_instance = Database::new(database_val)?;
let database = Arc::new(database_instance);
let validator = Validator::new(database.clone());
let queryer = Queryer::new(database.clone());
let merger = Merger::new(database.clone());
Self {
Ok(Self {
database,
validator,
queryer,
merger,
}
})
}
}

View File

@ -1,7 +1,12 @@
#[cfg(not(test))]
use pgrx::*;
#[cfg(not(test))]
pg_module_magic!();
#[cfg(test)]
pub struct JsonB(pub serde_json::Value);
pub mod database;
pub mod drop;
pub mod jspg;
@ -20,9 +25,22 @@ lazy_static::lazy_static! {
static ref GLOBAL_JSPG: RwLock<Option<Arc<jspg::Jspg>>> = RwLock::new(None);
}
#[pg_extern(strict)]
fn jspg_failure() -> JsonB {
let error = crate::drop::Error {
code: "ENGINE_NOT_INITIALIZED".to_string(),
message: "JSPG extension has not been initialized via jspg_setup".to_string(),
details: crate::drop::ErrorDetails {
path: "".to_string(),
},
};
let drop = crate::drop::Drop::with_errors(vec![error]);
JsonB(serde_json::to_value(drop).unwrap())
}
#[cfg_attr(not(test), pg_extern(strict))]
pub fn jspg_setup(database: JsonB) -> JsonB {
let new_jspg = crate::jspg::Jspg::new(&database.0);
match crate::jspg::Jspg::new(&database.0) {
Ok(new_jspg) => {
let new_arc = Arc::new(new_jspg);
// 3. ATOMIC SWAP
@ -33,9 +51,12 @@ pub fn jspg_setup(database: JsonB) -> JsonB {
let drop = crate::drop::Drop::success();
JsonB(serde_json::to_value(drop).unwrap())
}
Err(drop) => JsonB(serde_json::to_value(drop).unwrap()),
}
}
#[pg_extern]
#[cfg_attr(not(test), pg_extern)]
pub fn jspg_merge(data: JsonB) -> JsonB {
// Try to acquire a read lock to get a clone of the Engine Arc
let engine_opt = {
@ -44,35 +65,15 @@ pub fn jspg_merge(data: JsonB) -> JsonB {
};
match engine_opt {
Some(engine) => match engine.merger.merge(data.0) {
Ok(result) => JsonB(result),
Err(e) => {
let error = crate::drop::Error {
code: "MERGE_FAILED".to_string(),
message: e,
details: crate::drop::ErrorDetails {
path: "".to_string(),
},
};
let drop = crate::drop::Drop::with_errors(vec![error]);
JsonB(serde_json::to_value(drop).unwrap())
}
},
None => {
let error = crate::drop::Error {
code: "VALIDATOR_NOT_INITIALIZED".to_string(),
message: "The JSPG database has not been cached yet. Run jspg_setup()".to_string(),
details: crate::drop::ErrorDetails {
path: "".to_string(),
},
};
let drop = crate::drop::Drop::with_errors(vec![error]);
Some(engine) => {
let drop = engine.merger.merge(data.0);
JsonB(serde_json::to_value(drop).unwrap())
}
None => jspg_failure(),
}
}
#[pg_extern]
#[cfg_attr(not(test), pg_extern)]
pub fn jspg_query(schema_id: &str, stem: Option<&str>, filters: Option<JsonB>) -> JsonB {
let engine_opt = {
let lock = GLOBAL_JSPG.read().unwrap();
@ -80,38 +81,19 @@ pub fn jspg_query(schema_id: &str, stem: Option<&str>, filters: Option<JsonB>) -
};
match engine_opt {
Some(engine) => match engine
Some(engine) => {
let drop = engine
.queryer
.query(schema_id, stem, filters.as_ref().map(|f| &f.0))
{
Ok(res) => JsonB(res),
Err(e) => {
let error = crate::drop::Error {
code: "QUERY_FAILED".to_string(),
message: e,
details: crate::drop::ErrorDetails {
path: schema_id.to_string(),
},
};
JsonB(serde_json::to_value(crate::drop::Drop::with_errors(vec![error])).unwrap())
}
},
None => {
let error = crate::drop::Error {
code: "ENGINE_NOT_INITIALIZED".to_string(),
message: "JSPG extension has not been initialized via jspg_setup".to_string(),
details: crate::drop::ErrorDetails {
path: "".to_string(),
},
};
JsonB(serde_json::to_value(crate::drop::Drop::with_errors(vec![error])).unwrap())
.query(schema_id, stem, filters.as_ref().map(|f| &f.0));
JsonB(serde_json::to_value(drop).unwrap())
}
None => jspg_failure(),
}
}
// `mask_json_schema` has been removed as the mask architecture is fully replaced by Spi string queries during DB interactions.
#[pg_extern(strict, parallel_safe)]
#[cfg_attr(not(test), pg_extern(strict, parallel_safe))]
pub fn jspg_validate(schema_id: &str, instance: JsonB) -> JsonB {
// 1. Acquire Snapshot
let jspg_arc = {
@ -121,50 +103,17 @@ pub fn jspg_validate(schema_id: &str, instance: JsonB) -> JsonB {
// 2. Validate (Lock-Free)
if let Some(engine) = jspg_arc {
match engine.validator.validate(schema_id, &instance.0) {
Ok(result) => {
if result.is_valid() {
let drop = crate::drop::Drop::success();
let drop = engine.validator.validate(schema_id, &instance.0);
JsonB(serde_json::to_value(drop).unwrap())
} else {
let errors: Vec<crate::drop::Error> = result
.errors
.into_iter()
.map(|e| crate::drop::Error {
code: e.code,
message: e.message,
details: crate::drop::ErrorDetails { path: e.path },
})
.collect();
let drop = crate::drop::Drop::with_errors(errors);
JsonB(serde_json::to_value(drop).unwrap())
}
}
Err(e) => {
let error = crate::drop::Error {
code: e.code,
message: e.message,
details: crate::drop::ErrorDetails { path: e.path },
};
let drop = crate::drop::Drop::with_errors(vec![error]);
JsonB(serde_json::to_value(drop).unwrap())
}
}
} else {
let error = crate::drop::Error {
code: "VALIDATOR_NOT_INITIALIZED".to_string(),
message: "The JSPG database has not been cached yet. Run jspg_setup()".to_string(),
details: crate::drop::ErrorDetails {
path: "".to_string(),
},
};
let drop = crate::drop::Drop::with_errors(vec![error]);
JsonB(serde_json::to_value(drop).unwrap())
jspg_failure()
}
}
#[pg_extern]
pub fn jspg_get_punc_stems(punc_name: &str) -> JsonB {
#[cfg_attr(not(test), pg_extern)]
pub fn jspg_stems() -> JsonB {
use serde_json::{Map, Value};
let engine_opt = {
let lock = GLOBAL_JSPG.read().unwrap();
lock.clone()
@ -172,17 +121,13 @@ pub fn jspg_get_punc_stems(punc_name: &str) -> JsonB {
match engine_opt {
Some(engine) => {
if let Some(punc) = engine.database.puncs.get(punc_name) {
JsonB(serde_json::to_value(&punc.stems).unwrap_or(serde_json::Value::Array(vec![])))
} else {
JsonB(serde_json::Value::Array(vec![]))
JsonB(serde_json::to_value(&engine.database.stems).unwrap_or(Value::Object(Map::new())))
}
}
None => JsonB(serde_json::Value::Array(vec![])),
None => JsonB(Value::Object(Map::new())),
}
}
#[pg_extern(strict)]
#[cfg_attr(not(test), pg_extern(strict))]
pub fn jspg_teardown() -> JsonB {
let mut lock = GLOBAL_JSPG.write().unwrap();
*lock = None;
@ -190,21 +135,5 @@ pub fn jspg_teardown() -> JsonB {
JsonB(serde_json::to_value(drop).unwrap())
}
#[cfg(any(test, feature = "pg_test"))]
#[pg_schema]
mod tests {
use pgrx::prelude::*;
include!("tests/fixtures.rs");
}
#[cfg(test)]
pub mod pg_test {
pub fn setup(_options: Vec<&str>) {
// perform any initialization common to all tests
}
pub fn postgresql_conf_options() -> Vec<&'static str> {
// return any postgresql.conf settings that are required for your tests
vec![]
}
}
pub mod tests;

File diff suppressed because it is too large Load Diff

View File

@ -23,86 +23,34 @@ impl SqlCompiler {
.get(schema_id)
.ok_or_else(|| format!("Schema not found: {}", schema_id))?;
let resolved_arc;
let target_schema = if let Some(path) = stem_path.filter(|p| !p.is_empty() && *p != "/") {
self.resolve_stem(schema, path)?
if let Some(stems_map) = self.db.stems.get(schema_id) {
if let Some(stem) = stems_map.get(path) {
resolved_arc = stem.schema.clone();
} else {
return Err(format!(
"Stem entity type '{}' not found in schema '{}'",
path, schema_id
));
}
} else {
return Err(format!(
"Stem entity type '{}' not found in schema '{}'",
path, schema_id
));
}
resolved_arc.as_ref()
} else {
schema
};
// 1. We expect the top level to typically be an Object or Array
let (sql, _) = self.walk_schema(target_schema, "t1", None, filter_keys)?;
// We expect the top level to typically be an Object or Array
let is_stem_query = stem_path.is_some();
let (sql, _) = self.walk_schema(target_schema, "t1", None, filter_keys, is_stem_query, 0)?;
Ok(sql)
}
fn resolve_stem<'a>(
&'a self,
mut schema: &'a crate::database::schema::Schema,
path: &str,
) -> Result<&'a crate::database::schema::Schema, String> {
let parts: Vec<&str> = path.trim_start_matches('/').split('/').collect();
for part in parts {
let mut current = schema;
let mut depth = 0;
while let Some(r) = &current.obj.r#ref {
if let Some(s) = self.db.schemas.get(r) {
current = s;
} else {
break;
}
depth += 1;
if depth > 20 {
break;
}
}
if current.obj.properties.is_none() && current.obj.items.is_some() {
if let Some(items) = &current.obj.items {
current = items;
let mut depth2 = 0;
while let Some(r) = &current.obj.r#ref {
if let Some(s) = self.db.schemas.get(r) {
current = s;
} else {
break;
}
depth2 += 1;
if depth2 > 20 {
break;
}
}
}
}
if let Some(props) = &current.obj.properties {
if let Some(next_schema) = props.get(part) {
schema = next_schema;
} else {
return Err(format!("Stem part '{}' not found in schema", part));
}
} else {
return Err(format!(
"Cannot resolve stem part '{}': not an object",
part
));
}
}
let mut current = schema;
let mut depth = 0;
while let Some(r) = &current.obj.r#ref {
if let Some(s) = self.db.schemas.get(r) {
current = s;
} else {
break;
}
depth += 1;
if depth > 20 {
break;
}
}
Ok(current)
}
/// Recursively walks the schema AST emitting native PostgreSQL jsonb mapping
/// Returns a tuple of (SQL_String, Field_Type)
fn walk_schema(
@ -111,6 +59,8 @@ impl SqlCompiler {
parent_alias: &str,
prop_name_context: Option<&str>,
filter_keys: &[String],
is_stem_query: bool,
depth: usize,
) -> Result<(String, String), String> {
// Determine the base schema type (could be an array, object, or literal)
match &schema.obj.type_ {
@ -119,6 +69,9 @@ impl SqlCompiler {
if let Some(items) = &schema.obj.items {
if let Some(ref_id) = &items.obj.r#ref {
if let Some(type_def) = self.db.types.get(ref_id) {
if is_stem_query && depth > 0 {
return Ok(("".to_string(), "abort".to_string()));
}
return self.compile_entity_node(
items,
type_def,
@ -126,11 +79,19 @@ impl SqlCompiler {
prop_name_context,
true,
filter_keys,
is_stem_query,
depth,
);
}
}
let (item_sql, _) =
self.walk_schema(items, parent_alias, prop_name_context, filter_keys)?;
let (item_sql, _) = self.walk_schema(
items,
parent_alias,
prop_name_context,
filter_keys,
is_stem_query,
depth + 1,
)?;
return Ok((
format!("(SELECT jsonb_agg({}) FROM TODO)", item_sql),
"array".to_string(),
@ -143,10 +104,20 @@ impl SqlCompiler {
))
}
_ => {
// Handle Objects & Direct Refs
if let Some(ref_id) = &schema.obj.r#ref {
// If it's a $ref, check if it points to an Entity Type
if let Some(type_def) = self.db.types.get(ref_id) {
// Determine if this schema represents a Database Entity
let mut resolved_type = None;
// Target is generally a specific schema (e.g. 'base.person'), but it tells us what physical
// database table hierarchy it maps to via the `schema.id` prefix/suffix convention.
if let Some(lookup_key) = schema.obj.id.as_ref().or(schema.obj.r#ref.as_ref()) {
let base_type_name = lookup_key.split('.').next_back().unwrap_or("").to_string();
resolved_type = self.db.types.get(&base_type_name);
}
if let Some(type_def) = resolved_type {
if is_stem_query && depth > 0 {
return Ok(("".to_string(), "abort".to_string()));
}
return self.compile_entity_node(
schema,
type_def,
@ -154,18 +125,36 @@ impl SqlCompiler {
prop_name_context,
false,
filter_keys,
is_stem_query,
depth,
);
}
// Handle Direct Refs
if let Some(ref_id) = &schema.obj.r#ref {
// If it's just an ad-hoc struct ref, we should resolve it
if let Some(target_schema) = self.db.schemas.get(ref_id) {
return self.walk_schema(target_schema, parent_alias, prop_name_context, filter_keys);
return self.walk_schema(
target_schema,
parent_alias,
prop_name_context,
filter_keys,
is_stem_query,
depth,
);
}
return Err(format!("Unresolved $ref: {}", ref_id));
}
// Just an inline object definition?
if let Some(props) = &schema.obj.properties {
return self.compile_inline_object(props, parent_alias, filter_keys);
return self.compile_inline_object(
props,
parent_alias,
filter_keys,
is_stem_query,
depth,
);
}
// Literal fallback
@ -181,6 +170,27 @@ impl SqlCompiler {
}
}
fn get_merged_properties(
&self,
schema: &crate::database::schema::Schema,
) -> std::collections::BTreeMap<String, Arc<crate::database::schema::Schema>> {
let mut props = std::collections::BTreeMap::new();
if let Some(ref_id) = &schema.obj.r#ref {
if let Some(parent_schema) = self.db.schemas.get(ref_id) {
props.extend(self.get_merged_properties(parent_schema));
}
}
if let Some(local_props) = &schema.obj.properties {
for (k, v) in local_props {
props.insert(k.clone(), v.clone());
}
}
props
}
fn compile_entity_node(
&self,
schema: &crate::database::schema::Schema,
@ -189,6 +199,8 @@ impl SqlCompiler {
prop_name: Option<&str>,
is_array: bool,
filter_keys: &[String],
is_stem_query: bool,
depth: usize,
) -> Result<(String, String), String> {
// We are compiling a query block for an Entity.
let mut select_args = Vec::new();
@ -220,8 +232,8 @@ impl SqlCompiler {
// grouped_fields is { "person": ["first_name", ...], "user": ["password"], ... }
let grouped_fields = type_def.grouped_fields.as_ref().and_then(|v| v.as_object());
if let Some(props) = &schema.obj.properties {
for (prop_key, prop_schema) in props {
let merged_props = self.get_merged_properties(schema);
for (prop_key, prop_schema) in &merged_props {
// Find which table owns this property
// Find which table owns this property
let mut owner_alias = table_aliases
@ -245,10 +257,20 @@ impl SqlCompiler {
// Now we know `owner_alias`, e.g., `parent_t1` or `parent_t3`.
// Walk the property to get its SQL value
let (val_sql, _) =
self.walk_schema(prop_schema, &owner_alias, Some(prop_key), filter_keys)?;
select_args.push(format!("'{}', {}", prop_key, val_sql));
let (val_sql, val_type) = self.walk_schema(
prop_schema,
&owner_alias,
Some(prop_key),
filter_keys,
is_stem_query,
depth + 1,
)?;
if val_type == "abort" {
continue;
}
select_args.push(format!("'{}', {}", prop_key, val_sql));
}
let jsonb_obj_sql = if select_args.is_empty() {
@ -266,7 +288,7 @@ impl SqlCompiler {
where_clauses.push(format!("NOT {}.archived", base_alias));
// Filter Mapping - Only append filters if this is the ROOT table query (i.e. parent_alias is "t1")
// Because cue.filters operates strictly on top-level root properties right now.
if parent_alias == "t1" && prop_name.is_none() {
if parent_alias == "t1" {
for (i, filter_key) in filter_keys.iter().enumerate() {
// Find which table owns this filter key
let mut filter_alias = base_alias.clone(); // default to root table (e.g. t3 entity)
@ -288,23 +310,36 @@ impl SqlCompiler {
let mut is_ilike = false;
let mut cast = "";
// Check schema for filter_key to determine datatype operation
// Use PostgreSQL column type metadata for exact argument casting
if let Some(field_types) = type_def.field_types.as_ref().and_then(|v| v.as_object()) {
if let Some(pg_type_val) = field_types.get(filter_key) {
if let Some(pg_type) = pg_type_val.as_str() {
if pg_type == "uuid" {
cast = "::uuid";
} else if pg_type == "boolean" || pg_type == "bool" {
cast = "::boolean";
} else if pg_type.contains("timestamp")
|| pg_type == "timestamptz"
|| pg_type == "date"
{
cast = "::timestamptz";
} else if pg_type == "numeric"
|| pg_type.contains("int")
|| pg_type == "real"
|| pg_type == "double precision"
{
cast = "::numeric";
} else if pg_type == "text" || pg_type.contains("char") {
// Determine if this is an enum in the schema locally to avoid ILIKE on strict enums
let mut is_enum = false;
if let Some(props) = &schema.obj.properties {
if let Some(ps) = props.get(filter_key) {
let is_enum = ps.obj.enum_.is_some();
if let Some(crate::database::schema::SchemaTypeOrArray::Single(t)) = &ps.obj.type_ {
if t == "string" {
if ps.obj.format.as_deref() == Some("uuid") {
cast = "::uuid";
} else if ps.obj.format.as_deref() == Some("date-time") {
cast = "::timestamptz";
} else if !is_enum {
is_enum = ps.obj.enum_.is_some();
}
}
if !is_enum {
is_ilike = true;
}
} else if t == "boolean" {
cast = "::boolean";
} else if t == "integer" || t == "number" {
cast = "::numeric";
}
}
}
@ -357,10 +392,22 @@ impl SqlCompiler {
props: &std::collections::BTreeMap<String, std::sync::Arc<crate::database::schema::Schema>>,
parent_alias: &str,
filter_keys: &[String],
is_stem_query: bool,
depth: usize,
) -> Result<(String, String), String> {
let mut build_args = Vec::new();
for (k, v) in props {
let (child_sql, _) = self.walk_schema(v, parent_alias, Some(k), filter_keys)?;
let (child_sql, val_type) = self.walk_schema(
v,
parent_alias,
Some(k),
filter_keys,
is_stem_query,
depth + 1,
)?;
if val_type == "abort" {
continue;
}
build_args.push(format!("'{}', {}", k, child_sql));
}
let combined = format!("jsonb_build_object({})", build_args.join(", "));

View File

@ -18,13 +18,12 @@ impl Queryer {
}
}
/// Entrypoint to execute a dynamically compiled query based on a schema
pub fn query(
&self,
schema_id: &str,
stem_opt: Option<&str>,
filters: Option<&serde_json::Value>,
) -> Result<serde_json::Value, String> {
) -> crate::drop::Drop {
let filters_map: Option<&serde_json::Map<String, serde_json::Value>> =
filters.and_then(|f| f.as_object());
@ -45,9 +44,21 @@ impl Queryer {
} else {
// Compile the massive base SQL string
let compiler = compiler::SqlCompiler::new(self.db.clone());
let compiled_sql = compiler.compile(schema_id, stem_opt, &filter_keys)?;
match compiler.compile(schema_id, stem_opt, &filter_keys) {
Ok(compiled_sql) => {
self.cache.insert(cache_key.clone(), compiled_sql.clone());
compiled_sql
}
Err(e) => {
return crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: "QUERY_COMPILATION_FAILED".to_string(),
message: e,
details: crate::drop::ErrorDetails {
path: schema_id.to_string(),
},
}]);
}
}
};
// 2. Prepare the execution arguments from the filters
@ -62,22 +73,29 @@ impl Queryer {
}
// 3. Execute via Database Executor
let fetched = match self.db.query(&sql, Some(&args)) {
match self.db.query(&sql, Some(&args)) {
Ok(serde_json::Value::Array(table)) => {
if table.is_empty() {
Ok(serde_json::Value::Null)
crate::drop::Drop::success_with_val(serde_json::Value::Null)
} else {
// We expect the query to return a single JSONB column, already unpacked from row[0]
Ok(table.first().unwrap().clone())
crate::drop::Drop::success_with_val(table.first().unwrap().clone())
}
}
Ok(other) => Err(format!(
"Expected array from generic query, got: {:?}",
other
)),
Err(e) => Err(format!("SPI error in queryer: {}", e)),
}?;
Ok(fetched)
Ok(other) => crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: "QUERY_FAILED".to_string(),
message: format!("Expected array from generic query, got: {:?}", other),
details: crate::drop::ErrorDetails {
path: schema_id.to_string(),
},
}]),
Err(e) => crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: "QUERY_FAILED".to_string(),
message: format!("SPI error in queryer: {}", e),
details: crate::drop::ErrorDetails {
path: schema_id.to_string(),
},
}]),
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
use ::jspg::*;
use pgrx::JsonB;
use crate::*;
pub mod runner;
pub mod types;
use serde_json::json;
pub mod database;
// Database module tests moved to src/database/executors/mock.rs
#[test]
fn test_library_api() {
@ -15,8 +16,8 @@ fn test_library_api() {
json!({
"type": "drop",
"errors": [{
"code": "VALIDATOR_NOT_INITIALIZED",
"message": "The JSPG database has not been cached yet. Run jspg_setup()",
"code": "ENGINE_NOT_INITIALIZED",
"message": "JSPG extension has not been initialized via jspg_setup",
"details": { "path": "" }
}]
})
@ -89,3 +90,5 @@ fn test_library_api() {
})
);
}
include!("fixtures.rs");

154
src/tests/runner.rs Normal file
View File

@ -0,0 +1,154 @@
use serde::Deserialize;
use std::collections::HashMap;
use std::fs;
use std::sync::{Arc, OnceLock, RwLock};
#[derive(Debug, Deserialize)]
pub struct TestSuite {
#[allow(dead_code)]
pub description: String,
pub database: serde_json::Value,
pub tests: Vec<TestCase>,
}
use crate::tests::types::TestCase;
use serde_json::Value;
pub fn deserialize_some<'de, D>(deserializer: D) -> Result<Option<Value>, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = Value::deserialize(deserializer)?;
Ok(Some(v))
}
// Type alias for easier reading
type CompiledSuite = Arc<Vec<(TestSuite, Arc<crate::database::Database>)>>;
// Global cache mapping filename -> Vector of (Parsed JSON suite, Compiled Database)
static CACHE: OnceLock<RwLock<HashMap<String, CompiledSuite>>> = OnceLock::new();
fn get_cached_file(path: &str) -> CompiledSuite {
let cache_lock = CACHE.get_or_init(|| RwLock::new(HashMap::new()));
let file_data = {
let read_guard = cache_lock.read().unwrap();
read_guard.get(path).cloned()
};
match file_data {
Some(data) => data,
None => {
let mut write_guard = cache_lock.write().unwrap();
// double check in case another thread compiled while we waited for lock
if let Some(data) = write_guard.get(path) {
data.clone()
} else {
let content =
fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read file: {}", path));
let suites: Vec<TestSuite> = serde_json::from_str(&content)
.unwrap_or_else(|e| panic!("Failed to parse JSON in {}: {}", path, e));
let mut compiled_suites = Vec::new();
for suite in suites {
let db_result = crate::database::Database::new(&suite.database);
if let Err(drop) = db_result {
let error_messages: Vec<String> = drop
.errors
.into_iter()
.map(|e| format!("Error {} at path {}: {}", e.code, e.details.path, e.message))
.collect();
panic!(
"System Setup Compilation failed for {}:\n{}",
path,
error_messages.join("\n")
);
}
compiled_suites.push((suite, Arc::new(db_result.unwrap())));
}
let new_data = Arc::new(compiled_suites);
write_guard.insert(path.to_string(), new_data.clone());
new_data
}
}
}
}
pub fn run_test_case(path: &str, suite_idx: usize, case_idx: usize) -> Result<(), String> {
let file_data = get_cached_file(path);
if suite_idx >= file_data.len() {
panic!("Suite Index {} out of bounds for file {}", suite_idx, path);
}
let (group, db) = &file_data[suite_idx];
if case_idx >= group.tests.len() {
panic!(
"Case Index {} out of bounds for suite {} in file {}",
case_idx, suite_idx, path
);
}
let test = &group.tests[case_idx];
let mut failures = Vec::<String>::new();
// 4. Run Tests
// Provide fallback for legacy expectations if `expect` block was missing despite migration script
let _expected_success = test
.expect
.as_ref()
.map(|e| e.success)
.unwrap_or(test.valid.unwrap_or(false));
let _expected_errors = test
.expect
.as_ref()
.and_then(|e| e.errors.clone())
.unwrap_or(test.expect_errors.clone().unwrap_or(vec![]));
match test.action.as_str() {
"validate" => {
let result = test.run_validate(db.clone());
if let Err(e) = result {
println!("TEST VALIDATE ERROR FOR '{}': {}", test.description, e);
failures.push(format!(
"[{}] Validate Test '{}' failed. Error: {}",
group.description, test.description, e
));
}
}
"merge" => {
let result = test.run_merge(db.clone());
if let Err(e) = result {
println!("TEST MERGE ERROR FOR '{}': {}", test.description, e);
failures.push(format!(
"[{}] Merge Test '{}' failed. Error: {}",
group.description, test.description, e
));
}
}
"query" => {
let result = test.run_query(db.clone());
if let Err(e) = result {
println!("TEST QUERY ERROR FOR '{}': {}", test.description, e);
failures.push(format!(
"[{}] Query Test '{}' failed. Error: {}",
group.description, test.description, e
));
}
}
_ => {
failures.push(format!(
"[{}] Unknown action '{}' for test '{}'",
group.description, test.action, test.description
));
}
}
if !failures.is_empty() {
return Err(failures.join("\n"));
}
Ok(())
}

167
src/tests/types/case.rs Normal file
View File

@ -0,0 +1,167 @@
use super::expect::ExpectBlock;
use crate::database::Database;
use serde::Deserialize;
use serde_json::Value;
use std::sync::Arc;
#[derive(Debug, Deserialize)]
pub struct TestCase {
pub description: String,
#[serde(default = "default_action")]
pub action: String, // "validate", "merge", or "query"
// For Validate & Query
#[serde(default)]
pub schema_id: String,
// For Query
#[serde(default)]
pub stem: Option<String>,
#[serde(default)]
pub filters: Option<serde_json::Value>,
// For Merge & Validate
#[serde(default)]
pub data: Option<serde_json::Value>,
// For Merge & Query mocks
#[serde(default)]
pub mocks: Option<serde_json::Value>,
pub expect: Option<ExpectBlock>,
// Legacy support for older tests to avoid migrating them all instantly
pub valid: Option<bool>,
pub expect_errors: Option<Vec<serde_json::Value>>,
}
fn default_action() -> String {
"validate".to_string()
}
impl TestCase {
pub fn execute(&self, db: Arc<Database>) -> Result<(), String> {
match self.action.as_str() {
"validate" => self.run_validate(db),
"merge" => self.run_merge(db),
"query" => self.run_query(db),
_ => Err(format!(
"Unknown action '{}' for test '{}'",
self.action, self.description
)),
}
}
pub fn run_validate(&self, db: Arc<Database>) -> Result<(), String> {
use crate::validator::Validator;
let validator = Validator::new(db);
let expected_success = self
.expect
.as_ref()
.map(|e| e.success)
.unwrap_or(self.valid.unwrap_or(false));
// _expected_errors is preserved for future diffing if needed
let _expected_errors = self
.expect
.as_ref()
.and_then(|e| e.errors.clone())
.unwrap_or(self.expect_errors.clone().unwrap_or(vec![]));
let schema_id = &self.schema_id;
if !validator.db.schemas.contains_key(schema_id) {
return Err(format!(
"Missing Schema: Cannot find schema ID '{}'",
schema_id
));
}
let test_data = self.data.clone().unwrap_or(Value::Null);
let result = validator.validate(schema_id, &test_data);
let got_valid = result.errors.is_empty();
if got_valid != expected_success {
let error_msg = if result.errors.is_empty() {
"None".to_string()
} else {
format!("{:?}", result.errors)
};
return Err(format!(
"Expected: {}, Got: {}. Errors: {}",
expected_success, got_valid, error_msg
));
}
Ok(())
}
pub fn run_merge(&self, db: Arc<Database>) -> Result<(), String> {
use crate::merger::Merger;
let merger = Merger::new(db.clone());
let test_data = self.data.clone().unwrap_or(Value::Null);
let result = merger.merge(test_data);
let expected_success = self.expect.as_ref().map(|e| e.success).unwrap_or(false);
let got_success = result.errors.is_empty();
let error_msg = if result.errors.is_empty() {
"None".to_string()
} else {
format!("{:?}", result.errors)
};
let return_val = if expected_success != got_success {
Err(format!(
"Merge Expected: {}, Got: {}. Errors: {}",
expected_success, got_success, error_msg
))
} else if let Some(expect) = &self.expect {
let queries = db.executor.get_queries();
expect.assert_sql(&queries)
} else {
Ok(())
};
db.executor.reset_mocks();
return_val
}
pub fn run_query(&self, db: Arc<Database>) -> Result<(), String> {
use crate::queryer::Queryer;
let queryer = Queryer::new(db.clone());
let stem_opt = self.stem.as_deref();
let result = queryer.query(&self.schema_id, stem_opt, self.filters.as_ref());
let expected_success = self.expect.as_ref().map(|e| e.success).unwrap_or(false);
let got_success = result.errors.is_empty();
let error_msg = if result.errors.is_empty() {
"None".to_string()
} else {
format!("{:?}", result.errors)
};
let return_val = if expected_success != got_success {
Err(format!(
"Query Expected: {}, Got: {}. Errors: {}",
expected_success, got_success, error_msg
))
} else if let Some(expect) = &self.expect {
let queries = db.executor.get_queries();
expect.assert_sql(&queries)
} else {
Ok(())
};
db.executor.reset_mocks();
return_val
}
}

122
src/tests/types/expect.rs Normal file
View File

@ -0,0 +1,122 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct ExpectBlock {
pub success: bool,
pub result: Option<serde_json::Value>,
pub errors: Option<Vec<serde_json::Value>>,
#[serde(default)]
pub sql: Option<Vec<String>>,
}
impl ExpectBlock {
/// Advanced SQL execution assertion algorithm ported from `assert.go`.
/// This compares two arrays of strings, one containing {{uuid:name}} or {{timestamp}} placeholders,
/// and the other containing actual executed database queries. It ensures that placeholder UUIDs
/// are consistently mapped to the same actual UUIDs across all lines, and strictly validates line-by-line sequences.
pub fn assert_sql(&self, actual: &[String]) -> Result<(), String> {
let patterns = match &self.sql {
Some(s) => s,
None => return Ok(()),
};
if patterns.len() != actual.len() {
return Err(format!(
"Length mismatch: expected {} SQL executions, got {}.\nActual Execution Log:\n{}",
patterns.len(),
actual.len(),
actual.join("\n")
));
}
use regex::Regex;
use std::collections::HashMap;
let types = HashMap::from([
(
"uuid",
r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
),
(
"timestamp",
r"\d{4}-\d{2}-\d{2}(?:[ T])\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?(?:Z|\+\d{2}(?::\d{2})?)?",
),
("integer", r"-?\d+"),
("float", r"-?\d+\.\d+"),
("text", r"(?:''|[^'])*"),
("json", r"(?:''|[^'])*"),
]);
let mut seen: HashMap<String, String> = HashMap::new();
let system_uuid = "00000000-0000-0000-0000-000000000000";
// Placeholder regex: {{type:name}} or {{type}}
let ph_rx = Regex::new(r"\{\{([a-z]+)(?:[:]([^}]+))?\}\}").unwrap();
for (i, pattern_str) in patterns.iter().enumerate() {
let aline = &actual[i];
let mut pp = regex::escape(pattern_str);
pp = pp.replace(r"\{\{", "{{").replace(r"\}\}", "}}");
let mut cap_names = HashMap::new(); // cg_X -> var_name
let mut group_idx = 0;
let mut final_rx_str = String::new();
let mut last_match = 0;
let pp_clone = pp.clone();
for caps in ph_rx.captures_iter(&pp_clone) {
let full_match = caps.get(0).unwrap();
final_rx_str.push_str(&pp[last_match..full_match.start()]);
let type_name = caps.get(1).unwrap().as_str();
let var_name = caps.get(2).map(|m| m.as_str());
if let Some(name) = var_name {
if let Some(val) = seen.get(name) {
final_rx_str.push_str(&regex::escape(val));
} else {
let type_pattern = types.get(type_name).unwrap_or(&".*?");
let cg_name = format!("cg_{}", group_idx);
final_rx_str.push_str(&format!("(?P<{}>{})", cg_name, type_pattern));
cap_names.insert(cg_name, name.to_string());
group_idx += 1;
}
} else {
let type_pattern = types.get(type_name).unwrap_or(&".*?");
final_rx_str.push_str(&format!("(?:{})", type_pattern));
}
last_match = full_match.end();
}
final_rx_str.push_str(&pp[last_match..]);
let final_rx = match Regex::new(&format!("^{}$", final_rx_str)) {
Ok(r) => r,
Err(e) => return Err(format!("Bad constructed regex: {} -> {}", final_rx_str, e)),
};
if let Some(captures) = final_rx.captures(aline) {
for (cg_name, var_name) in cap_names {
if let Some(m) = captures.name(&cg_name) {
let matched_str = m.as_str();
if matched_str != system_uuid {
seen.insert(var_name, matched_str.to_string());
}
}
}
} else {
return Err(format!(
"Line mismatched at execution sequence {}.\nExpected Pattern: {}\nActual SQL: {}\nRegex used: {}\nVariables Mapped: {:?}",
i + 1,
pattern_str,
aline,
final_rx_str,
seen
));
}
}
Ok(())
}
}

7
src/tests/types/mod.rs Normal file
View File

@ -0,0 +1,7 @@
pub mod case;
pub mod expect;
pub mod suite;
pub use case::TestCase;
pub use expect::ExpectBlock;
pub use suite::TestSuite;

10
src/tests/types/suite.rs Normal file
View File

@ -0,0 +1,10 @@
use super::case::TestCase;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct TestSuite {
#[allow(dead_code)]
pub description: String,
pub database: serde_json::Value,
pub tests: Vec<TestCase>,
}

View File

@ -4,7 +4,6 @@ pub mod context;
pub mod error;
pub mod result;
pub mod rules;
pub mod util;
pub use context::ValidationContext;
pub use error::ValidationError;
@ -46,11 +45,7 @@ impl Validator {
}
}
pub fn validate(
&self,
schema_id: &str,
instance: &Value,
) -> Result<ValidationResult, ValidationError> {
pub fn validate(&self, schema_id: &str, instance: &Value) -> crate::drop::Drop {
if let Some(schema) = self.db.schemas.get(schema_id) {
let ctx = ValidationContext::new(
&self.db,
@ -61,13 +56,37 @@ impl Validator {
false,
false,
);
ctx.validate_scoped()
match ctx.validate_scoped() {
Ok(result) => {
if result.is_valid() {
crate::drop::Drop::success()
} else {
Err(ValidationError {
let errors: Vec<crate::drop::Error> = result
.errors
.into_iter()
.map(|e| crate::drop::Error {
code: e.code,
message: e.message,
details: crate::drop::ErrorDetails { path: e.path },
})
.collect();
crate::drop::Drop::with_errors(errors)
}
}
Err(e) => crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: e.code,
message: e.message,
details: crate::drop::ErrorDetails { path: e.path },
}]),
}
} else {
crate::drop::Drop::with_errors(vec![crate::drop::Error {
code: "SCHEMA_NOT_FOUND".to_string(),
message: format!("Schema {} not found", schema_id),
details: crate::drop::ErrorDetails {
path: "".to_string(),
})
},
}])
}
}
}

View File

@ -1,127 +0,0 @@
use serde::Deserialize;
use std::fs;
#[derive(Debug, Deserialize)]
struct TestSuite {
#[allow(dead_code)]
description: String,
database: serde_json::Value,
tests: Vec<TestCase>,
}
#[derive(Debug, Deserialize)]
pub struct TestCase {
pub description: String,
#[serde(default = "default_action")]
pub action: String, // "validate", "merge", or "query"
// For Validate & Query
#[serde(default)]
pub schema_id: String,
// For Query
#[serde(default)]
pub stem: Option<String>,
#[serde(default)]
pub filters: Option<serde_json::Value>,
// For Merge & Validate
#[serde(default)]
pub data: Option<serde_json::Value>,
// For Merge & Query mocks
#[serde(default)]
pub mocks: Option<serde_json::Value>,
pub expect: Option<ExpectBlock>,
// Legacy support for older tests to avoid migrating them all instantly
pub valid: Option<bool>,
pub expect_errors: Option<Vec<serde_json::Value>>,
}
fn default_action() -> String {
"validate".to_string()
}
#[derive(Debug, Deserialize)]
pub struct ExpectBlock {
pub success: bool,
pub result: Option<serde_json::Value>,
pub errors: Option<Vec<serde_json::Value>>,
pub sql_patterns: Option<Vec<String>>,
}
// use crate::validator::registry::REGISTRY; // No longer used directly for tests!
use crate::validator::Validator;
use serde_json::Value;
pub fn deserialize_some<'de, D>(deserializer: D) -> Result<Option<Value>, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = Value::deserialize(deserializer)?;
Ok(Some(v))
}
pub fn run_test_file_at_index(path: &str, index: usize) -> Result<(), String> {
let content =
fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read file: {}", path));
let suite: Vec<TestSuite> = serde_json::from_str(&content)
.unwrap_or_else(|e| panic!("Failed to parse JSON in {}: {}", path, e));
if index >= suite.len() {
panic!("Index {} out of bounds for file {}", index, path);
}
let group = &suite[index];
let mut failures = Vec::<String>::new();
let db_json = group.database.clone();
let db = crate::database::Database::new(&db_json);
let validator = Validator::new(std::sync::Arc::new(db));
// 4. Run Tests
for test in group.tests.iter() {
let schema_id = &test.schema_id;
if !validator.db.schemas.contains_key(schema_id) {
failures.push(format!(
"[{}] Missing Schema: Cannot find schema ID '{}'",
group.description, schema_id
));
continue;
}
let result = validator.validate(schema_id, &test.data);
let (got_valid, _errors) = match &result {
Ok(res) => (res.is_valid(), &res.errors),
Err(_e) => {
// If we encounter an execution error (e.g. Schema Not Found),
// we treat it as a test failure.
(false, &vec![])
}
};
if got_valid != test.valid {
let error_msg = match &result {
Ok(res) => format!("{:?}", res.errors),
Err(e) => format!("Execution Error: {:?}", e),
};
failures.push(format!(
"[{}] Test '{}' failed. Expected: {}, Got: {}. Errors: {}",
group.description, test.description, test.valid, got_valid, error_msg
));
}
}
if !failures.is_empty() {
return Err(failures.join("\n"));
}
Ok(())
}

View File

@ -1,43 +0,0 @@
use jspg::database::executor::DatabaseExecutor;
use serde_json::Value;
use std::sync::Mutex;
pub struct MockExecutor {
pub query_responses: Mutex<Vec<Result<Value, String>>>,
pub execute_responses: Mutex<Vec<Result<(), String>>>,
}
impl MockExecutor {
pub fn new() -> Self {
Self {
query_responses: Mutex::new(Vec::new()),
execute_responses: Mutex::new(Vec::new()),
}
}
}
impl DatabaseExecutor for MockExecutor {
fn query(&self, _sql: &str, _args: Option<&[Value]>) -> Result<Value, String> {
let mut responses = self.query_responses.lock().unwrap();
if responses.is_empty() {
return Ok(Value::Array(vec![]));
}
responses.remove(0)
}
fn execute(&self, _sql: &str, _args: Option<&[Value]>) -> Result<(), String> {
let mut responses = self.execute_responses.lock().unwrap();
if responses.is_empty() {
return Ok(());
}
responses.remove(0)
}
fn auth_user_id(&self) -> Result<String, String> {
Ok("00000000-0000-0000-0000-000000000000".to_string())
}
fn timestamp(&self) -> Result<String, String> {
Ok("2026-03-10T00:00:00Z".to_string())
}
}

View File

@ -1 +0,0 @@
pub mod executor;

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +0,0 @@
[
{
"description": "additionalProperties validates properties not matched by properties",
"database": {
"schemas": [
{
"$id": "schema1",
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "number"
}
},
"additionalProperties": {
"type": "boolean"
}
}
]
},
"tests": [
{
"description": "defined properties are valid",
"data": {
"foo": "value",
"bar": 123
},
"valid": true,
"schema_id": "schema1"
},
{
"description": "additional property matching schema is valid",
"data": {
"foo": "value",
"is_active": true,
"hidden": false
},
"valid": true,
"schema_id": "schema1"
},
{
"description": "additional property not matching schema is invalid",
"data": {
"foo": "value",
"is_active": 1
},
"valid": false,
"schema_id": "schema1"
}
]
},
{
"description": "extensible: true with additionalProperties still validates structure",
"database": {
"schemas": [
{
"properties": {
"foo": {
"type": "string"
}
},
"extensible": true,
"additionalProperties": {
"type": "integer"
},
"$id": "additionalProperties_1_0"
}
]
},
"tests": [
{
"description": "additional property matching schema is valid",
"data": {
"foo": "hello",
"count": 5,
"age": 42
},
"valid": true,
"schema_id": "additionalProperties_1_0"
},
{
"description": "additional property not matching schema is invalid despite extensible: true",
"data": {
"foo": "hello",
"count": "five"
},
"valid": false,
"schema_id": "additionalProperties_1_0"
}
]
},
{
"description": "complex additionalProperties with object and array items",
"database": {
"schemas": [
{
"$id": "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"
]
},
"valid": true,
"schema_id": "schema3"
},
{
"description": "invalid array of integers",
"data": {
"type": "my_type",
"group_a": [
1,
2
]
},
"valid": false,
"schema_id": "schema3"
},
{
"description": "invalid non-array type",
"data": {
"type": "my_type",
"group_a": "field1"
},
"valid": false,
"schema_id": "schema3"
}
]
}
]

View File

@ -1,590 +0,0 @@
[
{
"description": "allOf",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"$id": "allOf_0_0"
}
]
},
"tests": [
{
"description": "allOf",
"data": {
"foo": "baz",
"bar": 2
},
"valid": true,
"schema_id": "allOf_0_0"
},
{
"description": "mismatch second",
"data": {
"foo": "baz"
},
"valid": false,
"schema_id": "allOf_0_0"
},
{
"description": "mismatch first",
"data": {
"bar": 2
},
"valid": false,
"schema_id": "allOf_0_0"
},
{
"description": "wrong type",
"data": {
"foo": "baz",
"bar": "quux"
},
"valid": false,
"schema_id": "allOf_0_0"
}
]
},
{
"description": "allOf with base schema",
"database": {
"schemas": [
{
"properties": {
"bar": {
"type": "integer"
},
"baz": {},
"foo": {
"type": "string"
}
},
"required": [
"bar"
],
"allOf": [
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
},
{
"properties": {
"baz": {
"type": "null"
}
},
"required": [
"baz"
]
}
],
"$id": "allOf_1_0"
}
]
},
"tests": [
{
"description": "valid",
"data": {
"foo": "quux",
"bar": 2,
"baz": null
},
"valid": true,
"schema_id": "allOf_1_0"
},
{
"description": "mismatch base schema",
"data": {
"foo": "quux",
"baz": null
},
"valid": false,
"schema_id": "allOf_1_0"
},
{
"description": "mismatch first allOf",
"data": {
"bar": 2,
"baz": null
},
"valid": false,
"schema_id": "allOf_1_0"
},
{
"description": "mismatch second allOf",
"data": {
"foo": "quux",
"bar": 2
},
"valid": false,
"schema_id": "allOf_1_0"
},
{
"description": "mismatch both",
"data": {
"bar": 2
},
"valid": false,
"schema_id": "allOf_1_0"
}
]
},
{
"description": "allOf simple types",
"database": {
"schemas": [
{
"allOf": [
{
"maximum": 30
},
{
"minimum": 20
}
],
"$id": "allOf_2_0"
}
]
},
"tests": [
{
"description": "valid",
"data": 25,
"valid": true,
"schema_id": "allOf_2_0"
},
{
"description": "mismatch one",
"data": 35,
"valid": false,
"schema_id": "allOf_2_0"
}
]
},
{
"description": "allOf with boolean schemas, all true",
"database": {
"schemas": [
{
"allOf": [
true,
true
],
"$id": "allOf_3_0"
}
]
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true,
"schema_id": "allOf_3_0"
}
]
},
{
"description": "allOf with boolean schemas, some false",
"database": {
"schemas": [
{
"allOf": [
true,
false
],
"$id": "allOf_4_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false,
"schema_id": "allOf_4_0"
}
]
},
{
"description": "allOf with boolean schemas, all false",
"database": {
"schemas": [
{
"allOf": [
false,
false
],
"$id": "allOf_5_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false,
"schema_id": "allOf_5_0"
}
]
},
{
"description": "allOf with one empty schema",
"database": {
"schemas": [
{
"allOf": [
{}
],
"$id": "allOf_6_0"
}
]
},
"tests": [
{
"description": "any data is valid",
"data": 1,
"valid": true,
"schema_id": "allOf_6_0"
}
]
},
{
"description": "allOf with two empty schemas",
"database": {
"schemas": [
{
"allOf": [
{},
{}
],
"$id": "allOf_7_0"
}
]
},
"tests": [
{
"description": "any data is valid",
"data": 1,
"valid": true,
"schema_id": "allOf_7_0"
}
]
},
{
"description": "allOf with the first empty schema",
"database": {
"schemas": [
{
"allOf": [
{},
{
"type": "number"
}
],
"$id": "allOf_8_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"valid": true,
"schema_id": "allOf_8_0"
},
{
"description": "string is invalid",
"data": "foo",
"valid": false,
"schema_id": "allOf_8_0"
}
]
},
{
"description": "allOf with the last empty schema",
"database": {
"schemas": [
{
"allOf": [
{
"type": "number"
},
{}
],
"$id": "allOf_9_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"valid": true,
"schema_id": "allOf_9_0"
},
{
"description": "string is invalid",
"data": "foo",
"valid": false,
"schema_id": "allOf_9_0"
}
]
},
{
"description": "nested allOf, to check validation semantics",
"database": {
"schemas": [
{
"allOf": [
{
"allOf": [
{
"type": "null"
}
]
}
],
"$id": "allOf_10_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true,
"schema_id": "allOf_10_0"
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false,
"schema_id": "allOf_10_0"
}
]
},
{
"description": "extensible: true allows extra properties in allOf",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"extensible": true,
"$id": "allOf_12_0"
}
]
},
"tests": [
{
"description": "extra property is valid",
"data": {
"foo": "baz",
"bar": 2,
"qux": 3
},
"valid": true,
"schema_id": "allOf_12_0"
}
]
},
{
"description": "strict by default with allOf properties",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"foo": {
"const": 1
}
}
},
{
"properties": {
"bar": {
"const": 2
}
}
}
],
"$id": "allOf_13_0"
}
]
},
"tests": [
{
"description": "validates merged properties",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "allOf_13_0"
},
{
"description": "fails on extra property z explicitly",
"data": {
"foo": 1,
"bar": 2,
"z": 3
},
"valid": false,
"schema_id": "allOf_13_0"
}
]
},
{
"description": "allOf with nested extensible: true (partial looseness)",
"database": {
"schemas": [
{
"allOf": [
{
"properties": {
"foo": {
"const": 1
}
}
},
{
"extensible": true,
"properties": {
"bar": {
"const": 2
}
}
}
],
"$id": "allOf_14_0"
}
]
},
"tests": [
{
"description": "extensible subschema doesn't make root extensible if root is strict",
"data": {
"foo": 1,
"bar": 2,
"z": 3
},
"valid": true,
"schema_id": "allOf_14_0"
}
]
},
{
"description": "strictness: allOf composition with strict refs",
"database": {
"schemas": [
{
"allOf": [
{
"$ref": "partA"
},
{
"$ref": "partB"
}
],
"$id": "allOf_15_0"
},
{
"$id": "partA",
"properties": {
"id": {
"type": "string"
}
}
},
{
"$id": "partB",
"properties": {
"name": {
"type": "string"
}
}
}
]
},
"tests": [
{
"description": "merged instance is valid",
"data": {
"id": "1",
"name": "Me"
},
"valid": true,
"schema_id": "allOf_15_0"
},
{
"description": "extra property is invalid (root is strict)",
"data": {
"id": "1",
"name": "Me",
"extra": 1
},
"valid": false,
"schema_id": "allOf_15_0"
},
{
"description": "partA mismatch is invalid",
"data": {
"id": 1,
"name": "Me"
},
"valid": false,
"schema_id": "allOf_15_0"
}
]
}
]

View File

@ -1,143 +0,0 @@
[
{
"description": "boolean schema 'true'",
"database": {
"schemas": [
{
"$id": "booleanSchema_0_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "string is valid",
"data": "foo",
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "boolean true is valid",
"data": true,
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "boolean false is valid",
"data": false,
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "null is valid",
"data": null,
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "object is valid",
"data": {
"foo": "bar"
},
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "empty object is valid",
"data": {},
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "array is valid",
"data": [
"foo"
],
"valid": true,
"schema_id": "booleanSchema_0_0"
},
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "booleanSchema_0_0"
}
]
},
{
"description": "boolean schema 'false'",
"database": {
"schemas": [
{
"not": {},
"$id": "booleanSchema_1_0"
}
]
},
"tests": [
{
"description": "number is invalid",
"data": 1,
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "string is invalid",
"data": "foo",
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "boolean true is invalid",
"data": true,
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "boolean false is invalid",
"data": false,
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "null is invalid",
"data": null,
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "object is invalid",
"data": {
"foo": "bar"
},
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "empty object is invalid",
"data": {},
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "array is invalid",
"data": [
"foo"
],
"valid": false,
"schema_id": "booleanSchema_1_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "booleanSchema_1_0"
}
]
}
]

View File

@ -1,650 +0,0 @@
[
{
"description": "const validation",
"database": {
"schemas": [
{
"const": 2,
"$id": "const_0_0"
}
]
},
"tests": [
{
"description": "same value is valid",
"data": 2,
"valid": true,
"schema_id": "const_0_0"
},
{
"description": "another value is invalid",
"data": 5,
"valid": false,
"schema_id": "const_0_0"
},
{
"description": "another type is invalid",
"data": "a",
"valid": false,
"schema_id": "const_0_0"
}
]
},
{
"description": "const with object",
"database": {
"schemas": [
{
"const": {
"foo": "bar",
"baz": "bax"
},
"properties": {
"foo": {},
"baz": {}
},
"$id": "const_1_0"
}
]
},
"tests": [
{
"description": "same object is valid",
"data": {
"foo": "bar",
"baz": "bax"
},
"valid": true,
"schema_id": "const_1_0"
},
{
"description": "same object with different property order is valid",
"data": {
"baz": "bax",
"foo": "bar"
},
"valid": true,
"schema_id": "const_1_0"
},
{
"description": "another object is invalid",
"data": {
"foo": "bar"
},
"valid": false,
"schema_id": "const_1_0"
},
{
"description": "another type is invalid",
"data": [
1,
2
],
"valid": false,
"schema_id": "const_1_0"
}
]
},
{
"description": "const with array",
"database": {
"schemas": [
{
"const": [
{
"foo": "bar"
}
],
"$id": "const_2_0"
}
]
},
"tests": [
{
"description": "same array is valid",
"data": [
{
"foo": "bar"
}
],
"valid": true,
"schema_id": "const_2_0"
},
{
"description": "another array item is invalid",
"data": [
2
],
"valid": false,
"schema_id": "const_2_0"
},
{
"description": "array with additional items is invalid",
"data": [
1,
2,
3
],
"valid": false,
"schema_id": "const_2_0"
}
]
},
{
"description": "const with null",
"database": {
"schemas": [
{
"const": null,
"$id": "const_3_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true,
"schema_id": "const_3_0"
},
{
"description": "not null is invalid",
"data": 0,
"valid": false,
"schema_id": "const_3_0"
}
]
},
{
"description": "const with false does not match 0",
"database": {
"schemas": [
{
"const": false,
"$id": "const_4_0"
}
]
},
"tests": [
{
"description": "false is valid",
"data": false,
"valid": true,
"schema_id": "const_4_0"
},
{
"description": "integer zero is invalid",
"data": 0,
"valid": false,
"schema_id": "const_4_0"
},
{
"description": "float zero is invalid",
"data": 0,
"valid": false,
"schema_id": "const_4_0"
}
]
},
{
"description": "const with true does not match 1",
"database": {
"schemas": [
{
"const": true,
"$id": "const_5_0"
}
]
},
"tests": [
{
"description": "true is valid",
"data": true,
"valid": true,
"schema_id": "const_5_0"
},
{
"description": "integer one is invalid",
"data": 1,
"valid": false,
"schema_id": "const_5_0"
},
{
"description": "float one is invalid",
"data": 1,
"valid": false,
"schema_id": "const_5_0"
}
]
},
{
"description": "const with [false] does not match [0]",
"database": {
"schemas": [
{
"const": [
false
],
"$id": "const_6_0"
}
]
},
"tests": [
{
"description": "[false] is valid",
"data": [
false
],
"valid": true,
"schema_id": "const_6_0"
},
{
"description": "[0] is invalid",
"data": [
0
],
"valid": false,
"schema_id": "const_6_0"
},
{
"description": "[0.0] is invalid",
"data": [
0
],
"valid": false,
"schema_id": "const_6_0"
}
]
},
{
"description": "const with [true] does not match [1]",
"database": {
"schemas": [
{
"const": [
true
],
"$id": "const_7_0"
}
]
},
"tests": [
{
"description": "[true] is valid",
"data": [
true
],
"valid": true,
"schema_id": "const_7_0"
},
{
"description": "[1] is invalid",
"data": [
1
],
"valid": false,
"schema_id": "const_7_0"
},
{
"description": "[1.0] is invalid",
"data": [
1
],
"valid": false,
"schema_id": "const_7_0"
}
]
},
{
"description": "const with {\"a\": false} does not match {\"a\": 0}",
"database": {
"schemas": [
{
"const": {
"a": false
},
"$id": "const_8_0"
}
]
},
"tests": [
{
"description": "{\"a\": false} is valid",
"data": {
"a": false
},
"valid": true,
"schema_id": "const_8_0"
},
{
"description": "{\"a\": 0} is invalid",
"data": {
"a": 0
},
"valid": false,
"schema_id": "const_8_0"
},
{
"description": "{\"a\": 0.0} is invalid",
"data": {
"a": 0
},
"valid": false,
"schema_id": "const_8_0"
}
]
},
{
"description": "const with {\"a\": true} does not match {\"a\": 1}",
"database": {
"schemas": [
{
"const": {
"a": true
},
"$id": "const_9_0"
}
]
},
"tests": [
{
"description": "{\"a\": true} is valid",
"data": {
"a": true
},
"valid": true,
"schema_id": "const_9_0"
},
{
"description": "{\"a\": 1} is invalid",
"data": {
"a": 1
},
"valid": false,
"schema_id": "const_9_0"
},
{
"description": "{\"a\": 1.0} is invalid",
"data": {
"a": 1
},
"valid": false,
"schema_id": "const_9_0"
}
]
},
{
"description": "const with 0 does not match other zero-like types",
"database": {
"schemas": [
{
"const": 0,
"$id": "const_10_0"
}
]
},
"tests": [
{
"description": "false is invalid",
"data": false,
"valid": false,
"schema_id": "const_10_0"
},
{
"description": "integer zero is valid",
"data": 0,
"valid": true,
"schema_id": "const_10_0"
},
{
"description": "float zero is valid",
"data": 0,
"valid": true,
"schema_id": "const_10_0"
},
{
"description": "empty object is invalid",
"data": {},
"valid": false,
"schema_id": "const_10_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "const_10_0"
},
{
"description": "empty string is invalid",
"data": "",
"valid": false,
"schema_id": "const_10_0"
}
]
},
{
"description": "const with 1 does not match true",
"database": {
"schemas": [
{
"const": 1,
"$id": "const_11_0"
}
]
},
"tests": [
{
"description": "true is invalid",
"data": true,
"valid": false,
"schema_id": "const_11_0"
},
{
"description": "integer one is valid",
"data": 1,
"valid": true,
"schema_id": "const_11_0"
},
{
"description": "float one is valid",
"data": 1,
"valid": true,
"schema_id": "const_11_0"
}
]
},
{
"description": "const with -2.0 matches integer and float types",
"database": {
"schemas": [
{
"const": -2,
"$id": "const_12_0"
}
]
},
"tests": [
{
"description": "integer -2 is valid",
"data": -2,
"valid": true,
"schema_id": "const_12_0"
},
{
"description": "integer 2 is invalid",
"data": 2,
"valid": false,
"schema_id": "const_12_0"
},
{
"description": "float -2.0 is valid",
"data": -2,
"valid": true,
"schema_id": "const_12_0"
},
{
"description": "float 2.0 is invalid",
"data": 2,
"valid": false,
"schema_id": "const_12_0"
},
{
"description": "float -2.00001 is invalid",
"data": -2.00001,
"valid": false,
"schema_id": "const_12_0"
}
]
},
{
"description": "float and integers are equal up to 64-bit representation limits",
"database": {
"schemas": [
{
"const": 9007199254740992,
"$id": "const_13_0"
}
]
},
"tests": [
{
"description": "integer is valid",
"data": 9007199254740992,
"valid": true,
"schema_id": "const_13_0"
},
{
"description": "integer minus one is invalid",
"data": 9007199254740991,
"valid": false,
"schema_id": "const_13_0"
},
{
"description": "float is valid",
"data": 9007199254740992,
"valid": true,
"schema_id": "const_13_0"
},
{
"description": "float minus one is invalid",
"data": 9007199254740991,
"valid": false,
"schema_id": "const_13_0"
}
]
},
{
"description": "nul characters in strings",
"database": {
"schemas": [
{
"const": "hello\u0000there",
"$id": "const_14_0"
}
]
},
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"valid": true,
"schema_id": "const_14_0"
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"valid": false,
"schema_id": "const_14_0"
}
]
},
{
"description": "characters with the same visual representation but different codepoint",
"database": {
"schemas": [
{
"const": "μ",
"$comment": "U+03BC",
"$id": "const_15_0"
}
]
},
"tests": [
{
"description": "character uses the same codepoint",
"data": "μ",
"comment": "U+03BC",
"valid": true,
"schema_id": "const_15_0"
},
{
"description": "character looks the same but uses a different codepoint",
"data": "µ",
"comment": "U+00B5",
"valid": false,
"schema_id": "const_15_0"
}
]
},
{
"description": "characters with the same visual representation, but different number of codepoints",
"database": {
"schemas": [
{
"const": "ä",
"$comment": "U+00E4",
"$id": "const_16_0"
}
]
},
"tests": [
{
"description": "character uses the same codepoint",
"data": "ä",
"comment": "U+00E4",
"valid": true,
"schema_id": "const_16_0"
},
{
"description": "character looks the same but uses combining marks",
"data": "ä",
"comment": "a, U+0308",
"valid": false,
"schema_id": "const_16_0"
}
]
},
{
"description": "extensible: true allows extra properties in const object match",
"database": {
"schemas": [
{
"const": {
"a": 1
},
"extensible": true,
"$id": "const_17_0"
}
]
},
"tests": [
{
"description": "extra property ignored during strict check, but const check still applies (mismatch)",
"data": {
"a": 1,
"b": 2
},
"valid": false,
"schema_id": "const_17_0"
},
{
"description": "extra property match in const (this is effectively impossible if data has extra props not in const, it implicitly fails const check unless we assume const check ignored extra props? No, const check is strict. So this test is just to show strictness passes.)",
"data": {
"a": 1
},
"valid": true,
"schema_id": "const_17_0"
}
]
}
]

View File

@ -1,346 +0,0 @@
[
{
"description": "contains keyword validation",
"database": {
"schemas": [
{
"contains": {
"minimum": 5
},
"items": true,
"$id": "contains_0_0"
}
]
},
"tests": [
{
"description": "array with item matching schema (5) is valid (items: true)",
"data": [
3,
4,
5
],
"valid": true,
"schema_id": "contains_0_0"
},
{
"description": "array with item matching schema (6) is valid (items: true)",
"data": [
3,
4,
6
],
"valid": true,
"schema_id": "contains_0_0"
},
{
"description": "array with two items matching schema (5, 6) is valid (items: true)",
"data": [
3,
4,
5,
6
],
"valid": true,
"schema_id": "contains_0_0"
},
{
"description": "array without items matching schema is invalid",
"data": [
2,
3,
4
],
"valid": false,
"schema_id": "contains_0_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "contains_0_0"
},
{
"description": "not array is valid",
"data": {},
"valid": true,
"schema_id": "contains_0_0"
}
]
},
{
"description": "contains keyword with const keyword",
"database": {
"schemas": [
{
"contains": {
"const": 5
},
"items": true,
"$id": "contains_1_0"
}
]
},
"tests": [
{
"description": "array with item 5 is valid (items: true)",
"data": [
3,
4,
5
],
"valid": true,
"schema_id": "contains_1_0"
},
{
"description": "array with two items 5 is valid (items: true)",
"data": [
3,
4,
5,
5
],
"valid": true,
"schema_id": "contains_1_0"
},
{
"description": "array without item 5 is invalid",
"data": [
1,
2,
3,
4
],
"valid": false,
"schema_id": "contains_1_0"
}
]
},
{
"description": "contains keyword with boolean schema true",
"database": {
"schemas": [
{
"contains": true,
"$id": "contains_2_0"
}
]
},
"tests": [
{
"description": "any non-empty array is valid",
"data": [
"foo"
],
"valid": true,
"schema_id": "contains_2_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "contains_2_0"
}
]
},
{
"description": "contains keyword with boolean schema false",
"database": {
"schemas": [
{
"contains": false,
"$id": "contains_3_0"
}
]
},
"tests": [
{
"description": "any non-empty array is invalid",
"data": [
"foo"
],
"valid": false,
"schema_id": "contains_3_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "contains_3_0"
},
{
"description": "non-arrays are valid",
"data": "contains does not apply to strings",
"valid": true,
"schema_id": "contains_3_0"
}
]
},
{
"description": "items + contains",
"database": {
"schemas": [
{
"items": {
"multipleOf": 2
},
"contains": {
"multipleOf": 3
},
"$id": "contains_4_0"
}
]
},
"tests": [
{
"description": "matches items, does not match contains",
"data": [
2,
4,
8
],
"valid": false,
"schema_id": "contains_4_0"
},
{
"description": "does not match items, matches contains",
"data": [
3,
6,
9
],
"valid": false,
"schema_id": "contains_4_0"
},
{
"description": "matches both items and contains",
"data": [
6,
12
],
"valid": true,
"schema_id": "contains_4_0"
},
{
"description": "matches neither items nor contains",
"data": [
1,
5
],
"valid": false,
"schema_id": "contains_4_0"
}
]
},
{
"description": "contains with false if subschema",
"database": {
"schemas": [
{
"contains": {
"if": false,
"else": true
},
"$id": "contains_5_0"
}
]
},
"tests": [
{
"description": "any non-empty array is valid",
"data": [
"foo"
],
"valid": true,
"schema_id": "contains_5_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "contains_5_0"
}
]
},
{
"description": "contains with null instance elements",
"database": {
"schemas": [
{
"contains": {
"type": "null"
},
"$id": "contains_6_0"
}
]
},
"tests": [
{
"description": "allows null items",
"data": [
null
],
"valid": true,
"schema_id": "contains_6_0"
}
]
},
{
"description": "extensible: true allows non-matching items in contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"extensible": true,
"$id": "contains_7_0"
}
]
},
"tests": [
{
"description": "extra items acceptable",
"data": [
1,
2
],
"valid": true,
"schema_id": "contains_7_0"
}
]
},
{
"description": "strict by default: non-matching items in contains are invalid",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"$id": "contains_8_0"
}
]
},
"tests": [
{
"description": "extra items cause failure",
"data": [
1,
2
],
"valid": false,
"schema_id": "contains_8_0"
},
{
"description": "only matching items is valid",
"data": [
1,
1
],
"valid": true,
"schema_id": "contains_8_0"
}
]
}
]

View File

@ -1,178 +0,0 @@
[
{
"description": "validation of string-encoded content based on media type",
"database": {
"schemas": [
{
"contentMediaType": "application/json",
"$id": "content_0_0"
}
]
},
"tests": [
{
"description": "a valid JSON document",
"data": "{\"foo\": \"bar\"}",
"valid": true,
"schema_id": "content_0_0"
},
{
"description": "an invalid JSON document; validates true",
"data": "{:}",
"valid": true,
"schema_id": "content_0_0"
},
{
"description": "ignores non-strings",
"data": 100,
"valid": true,
"schema_id": "content_0_0"
}
]
},
{
"description": "validation of binary string-encoding",
"database": {
"schemas": [
{
"contentEncoding": "base64",
"$id": "content_1_0"
}
]
},
"tests": [
{
"description": "a valid base64 string",
"data": "eyJmb28iOiAiYmFyIn0K",
"valid": true,
"schema_id": "content_1_0"
},
{
"description": "an invalid base64 string (% is not a valid character); validates true",
"data": "eyJmb28iOi%iYmFyIn0K",
"valid": true,
"schema_id": "content_1_0"
},
{
"description": "ignores non-strings",
"data": 100,
"valid": true,
"schema_id": "content_1_0"
}
]
},
{
"description": "validation of binary-encoded media type documents",
"database": {
"schemas": [
{
"contentMediaType": "application/json",
"contentEncoding": "base64",
"$id": "content_2_0"
}
]
},
"tests": [
{
"description": "a valid base64-encoded JSON document",
"data": "eyJmb28iOiAiYmFyIn0K",
"valid": true,
"schema_id": "content_2_0"
},
{
"description": "a validly-encoded invalid JSON document; validates true",
"data": "ezp9Cg==",
"valid": true,
"schema_id": "content_2_0"
},
{
"description": "an invalid base64 string that is valid JSON; validates true",
"data": "{}",
"valid": true,
"schema_id": "content_2_0"
},
{
"description": "ignores non-strings",
"data": 100,
"valid": true,
"schema_id": "content_2_0"
}
]
},
{
"description": "validation of binary-encoded media type documents with schema",
"database": {
"schemas": [
{
"contentMediaType": "application/json",
"contentEncoding": "base64",
"contentSchema": {
"type": "object",
"required": [
"foo"
],
"properties": {
"foo": {
"type": "string"
},
"boo": {
"type": "integer"
}
}
},
"$id": "content_3_0"
}
]
},
"tests": [
{
"description": "a valid base64-encoded JSON document",
"data": "eyJmb28iOiAiYmFyIn0K",
"valid": true,
"schema_id": "content_3_0"
},
{
"description": "another valid base64-encoded JSON document",
"data": "eyJib28iOiAyMCwgImZvbyI6ICJiYXoifQ==",
"valid": true,
"schema_id": "content_3_0"
},
{
"description": "an invalid base64-encoded JSON document; validates true",
"data": "eyJib28iOiAyMH0=",
"valid": true,
"schema_id": "content_3_0"
},
{
"description": "an empty object as a base64-encoded JSON document; validates true",
"data": "e30=",
"valid": true,
"schema_id": "content_3_0"
},
{
"description": "an empty array as a base64-encoded JSON document",
"data": "W10=",
"valid": true,
"schema_id": "content_3_0"
},
{
"description": "a validly-encoded invalid JSON document; validates true",
"data": "ezp9Cg==",
"valid": true,
"schema_id": "content_3_0"
},
{
"description": "an invalid base64 string that is valid JSON; validates true",
"data": "{}",
"valid": true,
"schema_id": "content_3_0"
},
{
"description": "ignores non-strings",
"data": 100,
"valid": true,
"schema_id": "content_3_0"
}
]
}
]

View File

@ -1,619 +0,0 @@
[
{
"description": "single dependency (required)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema1",
"dependencies": {
"bar": [
"foo"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "neither",
"data": {},
"valid": true,
"schema_id": "schema1"
},
{
"description": "nondependant",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "schema1"
},
{
"description": "with dependency",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "schema1"
},
{
"description": "missing dependency",
"data": {
"bar": 2
},
"valid": false,
"schema_id": "schema1"
},
{
"description": "ignores arrays",
"data": [
"bar"
],
"valid": true,
"schema_id": "schema1"
},
{
"description": "ignores strings",
"data": "foobar",
"valid": true,
"schema_id": "schema1"
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true,
"schema_id": "schema1"
}
]
},
{
"description": "empty dependents",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema2",
"dependencies": {
"bar": []
},
"extensible": true
}
]
},
"tests": [
{
"description": "empty object",
"data": {},
"valid": true,
"schema_id": "schema2"
},
{
"description": "object with one property",
"data": {
"bar": 2
},
"valid": true,
"schema_id": "schema2"
},
{
"description": "non-object is valid",
"data": 1,
"valid": true,
"schema_id": "schema2"
}
]
},
{
"description": "multiple dependents required",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema3",
"dependencies": {
"quux": [
"foo",
"bar"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "neither",
"data": {},
"valid": true,
"schema_id": "schema3"
},
{
"description": "nondependants",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "schema3"
},
{
"description": "with dependencies",
"data": {
"foo": 1,
"bar": 2,
"quux": 3
},
"valid": true,
"schema_id": "schema3"
},
{
"description": "missing dependency",
"data": {
"foo": 1,
"quux": 2
},
"valid": false,
"schema_id": "schema3"
},
{
"description": "missing other dependency",
"data": {
"bar": 1,
"quux": 2
},
"valid": false,
"schema_id": "schema3"
},
{
"description": "missing both dependencies",
"data": {
"quux": 1
},
"valid": false,
"schema_id": "schema3"
}
]
},
{
"description": "dependencies with escaped characters",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema4",
"dependencies": {
"foo\nbar": [
"foo\rbar"
],
"foo\"bar": [
"foo'bar"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "CRLF",
"data": {
"foo\nbar": 1,
"foo\rbar": 2
},
"valid": true,
"schema_id": "schema4"
},
{
"description": "quoted quotes",
"data": {
"foo'bar": 1,
"foo\"bar": 2
},
"valid": true,
"schema_id": "schema4"
},
{
"description": "CRLF missing dependent",
"data": {
"foo\nbar": 1,
"foo": 2
},
"valid": false,
"schema_id": "schema4"
},
{
"description": "quoted quotes missing dependent",
"data": {
"foo\"bar": 2
},
"valid": false,
"schema_id": "schema4"
}
]
},
{
"description": "extensible: true allows extra properties in dependentRequired",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema5",
"dependencies": {
"bar": [
"foo"
]
},
"extensible": true
}
]
},
"tests": [
{
"description": "extra property is valid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"valid": true,
"schema_id": "schema5"
}
]
},
{
"description": "single dependency (schemas, STRICT)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema1",
"properties": {
"foo": true,
"bar": true
},
"dependencies": {
"bar": {
"properties": {
"foo": {
"type": "integer"
},
"bar": {
"type": "integer"
}
}
}
}
}
]
},
"tests": [
{
"description": "valid",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "schema_schema1"
},
{
"description": "no dependency",
"data": {
"foo": "quux"
},
"valid": true,
"schema_id": "schema_schema1"
},
{
"description": "wrong type",
"data": {
"foo": "quux",
"bar": 2
},
"valid": false,
"schema_id": "schema_schema1"
},
{
"description": "wrong type other",
"data": {
"foo": 2,
"bar": "quux"
},
"valid": false,
"schema_id": "schema_schema1"
},
{
"description": "wrong type both",
"data": {
"foo": "quux",
"bar": "quux"
},
"valid": false,
"schema_id": "schema_schema1"
},
{
"description": "ignores arrays (invalid in strict mode)",
"data": [
"bar"
],
"valid": false,
"expect_errors": [
{
"code": "STRICT_ITEM_VIOLATION"
}
],
"schema_id": "schema_schema1"
},
{
"description": "ignores strings",
"data": "foobar",
"valid": true,
"schema_id": "schema_schema1"
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true,
"schema_id": "schema_schema1"
}
]
},
{
"description": "single dependency (schemas, EXTENSIBLE)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema2",
"properties": {
"foo": true,
"bar": true
},
"dependencies": {
"bar": {
"properties": {
"foo": {
"type": "integer"
},
"bar": {
"type": "integer"
}
}
}
},
"extensible": true
}
]
},
"tests": [
{
"description": "ignores arrays (valid in extensible mode)",
"data": [
"bar"
],
"valid": true,
"schema_id": "schema_schema2"
}
]
},
{
"description": "boolean subschemas",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema3",
"properties": {
"foo": true,
"bar": true
},
"dependencies": {
"foo": true,
"bar": false
}
}
]
},
"tests": [
{
"description": "object with property having schema true is valid",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "schema_schema3"
},
{
"description": "object with property having schema false is invalid",
"data": {
"bar": 2
},
"valid": false,
"schema_id": "schema_schema3"
},
{
"description": "object with both properties is invalid",
"data": {
"foo": 1,
"bar": 2
},
"valid": false,
"schema_id": "schema_schema3"
},
{
"description": "empty object is valid",
"data": {},
"valid": true,
"schema_id": "schema_schema3"
}
]
},
{
"description": "dependencies with escaped characters",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema4",
"properties": {
"foo\tbar": true,
"foo'bar": true,
"a": true,
"b": true,
"c": true
},
"dependencies": {
"foo\tbar": {
"minProperties": 4,
"extensible": true
},
"foo'bar": {
"required": [
"foo\"bar"
]
}
}
}
]
},
"tests": [
{
"description": "quoted tab",
"data": {
"foo\tbar": 1,
"a": 2,
"b": 3,
"c": 4
},
"valid": true,
"schema_id": "schema_schema4"
},
{
"description": "quoted quote",
"data": {
"foo'bar": {
"foo\"bar": 1
}
},
"valid": false,
"schema_id": "schema_schema4"
},
{
"description": "quoted tab invalid under dependent schema",
"data": {
"foo\tbar": 1,
"a": 2
},
"valid": false,
"schema_id": "schema_schema4"
},
{
"description": "quoted quote invalid under dependent schema",
"data": {
"foo'bar": 1
},
"valid": false,
"schema_id": "schema_schema4"
}
]
},
{
"description": "dependent subschema incompatible with root (STRICT)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema5",
"properties": {
"foo": {},
"baz": true
},
"dependencies": {
"foo": {
"properties": {
"bar": {}
}
}
}
}
]
},
"tests": [
{
"description": "matches root",
"data": {
"foo": 1
},
"valid": false,
"schema_id": "schema_schema5"
},
{
"description": "matches dependency (invalid in strict mode - bar not allowed if foo missing)",
"data": {
"bar": 1
},
"valid": false,
"expect_errors": [
{
"code": "STRICT_PROPERTY_VIOLATION"
}
],
"schema_id": "schema_schema5"
},
{
"description": "matches both",
"data": {
"foo": 1,
"bar": 2
},
"valid": false,
"schema_id": "schema_schema5"
},
{
"description": "no dependency",
"data": {
"baz": 1
},
"valid": true,
"schema_id": "schema_schema5"
}
]
},
{
"description": "dependent subschema incompatible with root (EXTENSIBLE)",
"database": {
"schemas": [
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema_schema6",
"properties": {
"foo": {},
"baz": true
},
"dependencies": {
"foo": {
"properties": {
"bar": {}
},
"additionalProperties": false
}
},
"extensible": true
}
]
},
"tests": [
{
"description": "matches dependency (valid in extensible mode)",
"data": {
"bar": 1
},
"valid": true,
"schema_id": "schema_schema6"
}
]
}
]

View File

@ -1,133 +0,0 @@
[
{
"description": "empty string is valid for all types (except const)",
"database": {
"schemas": [
{
"properties": {
"obj": {
"type": "object"
},
"arr": {
"type": "array"
},
"str": {
"type": "string"
},
"int": {
"type": "integer"
},
"num": {
"type": "number"
},
"bool": {
"type": "boolean"
},
"nul": {
"type": "null"
},
"fmt": {
"type": "string",
"format": "uuid"
},
"con": {
"const": "value"
},
"con_empty": {
"const": ""
}
},
"$id": "emptyString_0_0"
}
]
},
"tests": [
{
"description": "empty string valid for object",
"data": {
"obj": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string valid for array",
"data": {
"arr": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string valid for string",
"data": {
"str": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string valid for integer",
"data": {
"int": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string valid for number",
"data": {
"num": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string valid for boolean",
"data": {
"bool": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string valid for null",
"data": {
"nul": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string valid for format",
"data": {
"fmt": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
},
{
"description": "empty string INVALID for const (unless const is empty string)",
"data": {
"con": ""
},
"valid": false,
"expect_errors": [
{
"code": "CONST_VIOLATED",
"path": "/con"
}
],
"schema_id": "emptyString_0_0"
},
{
"description": "empty string VALID for const if const IS empty string",
"data": {
"con_empty": ""
},
"valid": true,
"schema_id": "emptyString_0_0"
}
]
}
]

View File

@ -1,595 +0,0 @@
[
{
"description": "simple enum validation",
"database": {
"schemas": [
{
"enum": [
1,
2,
3
],
"$id": "enum_0_0"
}
]
},
"tests": [
{
"description": "one of the enum is valid",
"data": 1,
"valid": true,
"schema_id": "enum_0_0"
},
{
"description": "something else is invalid",
"data": 4,
"valid": false,
"schema_id": "enum_0_0"
}
]
},
{
"description": "heterogeneous enum validation",
"database": {
"schemas": [
{
"enum": [
6,
"foo",
[],
true,
{
"foo": 12
}
],
"properties": {
"foo": {}
},
"$id": "enum_1_0"
}
]
},
"tests": [
{
"description": "one of the enum is valid",
"data": [],
"valid": true,
"schema_id": "enum_1_0"
},
{
"description": "something else is invalid",
"data": null,
"valid": false,
"schema_id": "enum_1_0"
},
{
"description": "objects are deep compared",
"data": {
"foo": false
},
"valid": false,
"schema_id": "enum_1_0"
},
{
"description": "valid object matches",
"data": {
"foo": 12
},
"valid": true,
"schema_id": "enum_1_0"
},
{
"description": "extra properties in object is invalid",
"data": {
"foo": 12,
"boo": 42
},
"valid": false,
"schema_id": "enum_1_0"
}
]
},
{
"description": "heterogeneous enum-with-null validation",
"database": {
"schemas": [
{
"enum": [
6,
null
],
"$id": "enum_2_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true,
"schema_id": "enum_2_0"
},
{
"description": "number is valid",
"data": 6,
"valid": true,
"schema_id": "enum_2_0"
},
{
"description": "something else is invalid",
"data": "test",
"valid": false,
"schema_id": "enum_2_0"
}
]
},
{
"description": "enums in properties",
"database": {
"schemas": [
{
"type": "object",
"properties": {
"foo": {
"enum": [
"foo"
]
},
"bar": {
"enum": [
"bar"
]
}
},
"required": [
"bar"
],
"$id": "enum_3_0"
}
]
},
"tests": [
{
"description": "both properties are valid",
"data": {
"foo": "foo",
"bar": "bar"
},
"valid": true,
"schema_id": "enum_3_0"
},
{
"description": "wrong foo value",
"data": {
"foo": "foot",
"bar": "bar"
},
"valid": false,
"schema_id": "enum_3_0"
},
{
"description": "wrong bar value",
"data": {
"foo": "foo",
"bar": "bart"
},
"valid": false,
"schema_id": "enum_3_0"
},
{
"description": "missing optional property is valid",
"data": {
"bar": "bar"
},
"valid": true,
"schema_id": "enum_3_0"
},
{
"description": "missing required property is invalid",
"data": {
"foo": "foo"
},
"valid": false,
"schema_id": "enum_3_0"
},
{
"description": "missing all properties is invalid",
"data": {},
"valid": false,
"schema_id": "enum_3_0"
}
]
},
{
"description": "enum with escaped characters",
"database": {
"schemas": [
{
"enum": [
"foo\nbar",
"foo\rbar"
],
"$id": "enum_4_0"
}
]
},
"tests": [
{
"description": "member 1 is valid",
"data": "foo\nbar",
"valid": true,
"schema_id": "enum_4_0"
},
{
"description": "member 2 is valid",
"data": "foo\rbar",
"valid": true,
"schema_id": "enum_4_0"
},
{
"description": "another string is invalid",
"data": "abc",
"valid": false,
"schema_id": "enum_4_0"
}
]
},
{
"description": "enum with false does not match 0",
"database": {
"schemas": [
{
"enum": [
false
],
"$id": "enum_5_0"
}
]
},
"tests": [
{
"description": "false is valid",
"data": false,
"valid": true,
"schema_id": "enum_5_0"
},
{
"description": "integer zero is invalid",
"data": 0,
"valid": false,
"schema_id": "enum_5_0"
},
{
"description": "float zero is invalid",
"data": 0,
"valid": false,
"schema_id": "enum_5_0"
}
]
},
{
"description": "enum with [false] does not match [0]",
"database": {
"schemas": [
{
"enum": [
[
false
]
],
"$id": "enum_6_0"
}
]
},
"tests": [
{
"description": "[false] is valid",
"data": [
false
],
"valid": true,
"schema_id": "enum_6_0"
},
{
"description": "[0] is invalid",
"data": [
0
],
"valid": false,
"schema_id": "enum_6_0"
},
{
"description": "[0.0] is invalid",
"data": [
0
],
"valid": false,
"schema_id": "enum_6_0"
}
]
},
{
"description": "enum with true does not match 1",
"database": {
"schemas": [
{
"enum": [
true
],
"$id": "enum_7_0"
}
]
},
"tests": [
{
"description": "true is valid",
"data": true,
"valid": true,
"schema_id": "enum_7_0"
},
{
"description": "integer one is invalid",
"data": 1,
"valid": false,
"schema_id": "enum_7_0"
},
{
"description": "float one is invalid",
"data": 1,
"valid": false,
"schema_id": "enum_7_0"
}
]
},
{
"description": "enum with [true] does not match [1]",
"database": {
"schemas": [
{
"enum": [
[
true
]
],
"$id": "enum_8_0"
}
]
},
"tests": [
{
"description": "[true] is valid",
"data": [
true
],
"valid": true,
"schema_id": "enum_8_0"
},
{
"description": "[1] is invalid",
"data": [
1
],
"valid": false,
"schema_id": "enum_8_0"
},
{
"description": "[1.0] is invalid",
"data": [
1
],
"valid": false,
"schema_id": "enum_8_0"
}
]
},
{
"description": "enum with 0 does not match false",
"database": {
"schemas": [
{
"enum": [
0
],
"$id": "enum_9_0"
}
]
},
"tests": [
{
"description": "false is invalid",
"data": false,
"valid": false,
"schema_id": "enum_9_0"
},
{
"description": "integer zero is valid",
"data": 0,
"valid": true,
"schema_id": "enum_9_0"
},
{
"description": "float zero is valid",
"data": 0,
"valid": true,
"schema_id": "enum_9_0"
}
]
},
{
"description": "enum with [0] does not match [false]",
"database": {
"schemas": [
{
"enum": [
[
0
]
],
"$id": "enum_10_0"
}
]
},
"tests": [
{
"description": "[false] is invalid",
"data": [
false
],
"valid": false,
"schema_id": "enum_10_0"
},
{
"description": "[0] is valid",
"data": [
0
],
"valid": true,
"schema_id": "enum_10_0"
},
{
"description": "[0.0] is valid",
"data": [
0
],
"valid": true,
"schema_id": "enum_10_0"
}
]
},
{
"description": "enum with 1 does not match true",
"database": {
"schemas": [
{
"enum": [
1
],
"$id": "enum_11_0"
}
]
},
"tests": [
{
"description": "true is invalid",
"data": true,
"valid": false,
"schema_id": "enum_11_0"
},
{
"description": "integer one is valid",
"data": 1,
"valid": true,
"schema_id": "enum_11_0"
},
{
"description": "float one is valid",
"data": 1,
"valid": true,
"schema_id": "enum_11_0"
}
]
},
{
"description": "enum with [1] does not match [true]",
"database": {
"schemas": [
{
"enum": [
[
1
]
],
"$id": "enum_12_0"
}
]
},
"tests": [
{
"description": "[true] is invalid",
"data": [
true
],
"valid": false,
"schema_id": "enum_12_0"
},
{
"description": "[1] is valid",
"data": [
1
],
"valid": true,
"schema_id": "enum_12_0"
},
{
"description": "[1.0] is valid",
"data": [
1
],
"valid": true,
"schema_id": "enum_12_0"
}
]
},
{
"description": "nul characters in strings",
"database": {
"schemas": [
{
"enum": [
"hello\u0000there"
],
"$id": "enum_13_0"
}
]
},
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"valid": true,
"schema_id": "enum_13_0"
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"valid": false,
"schema_id": "enum_13_0"
}
]
},
{
"description": "extensible: true allows extra properties in enum object match",
"database": {
"schemas": [
{
"enum": [
{
"foo": 1
}
],
"extensible": true,
"$id": "enum_14_0"
}
]
},
"tests": [
{
"description": "extra property ignored during strict check, but enum check still applies (mismatch here)",
"data": {
"foo": 1,
"bar": 2
},
"valid": false,
"schema_id": "enum_14_0"
},
{
"description": "extra property ignored during strict check, enum match succeeds",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "enum_14_0"
}
]
}
]

View File

@ -1,39 +0,0 @@
[
{
"description": "exclusiveMaximum validation",
"database": {
"schemas": [
{
"exclusiveMaximum": 3,
"$id": "exclusiveMaximum_0_0"
}
]
},
"tests": [
{
"description": "below the exclusiveMaximum is valid",
"data": 2.2,
"valid": true,
"schema_id": "exclusiveMaximum_0_0"
},
{
"description": "boundary point is invalid",
"data": 3,
"valid": false,
"schema_id": "exclusiveMaximum_0_0"
},
{
"description": "above the exclusiveMaximum is invalid",
"data": 3.5,
"valid": false,
"schema_id": "exclusiveMaximum_0_0"
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true,
"schema_id": "exclusiveMaximum_0_0"
}
]
}
]

View File

@ -1,39 +0,0 @@
[
{
"description": "exclusiveMinimum validation",
"database": {
"schemas": [
{
"exclusiveMinimum": 1.1,
"$id": "exclusiveMinimum_0_0"
}
]
},
"tests": [
{
"description": "above the exclusiveMinimum is valid",
"data": 1.2,
"valid": true,
"schema_id": "exclusiveMinimum_0_0"
},
{
"description": "boundary point is invalid",
"data": 1.1,
"valid": false,
"schema_id": "exclusiveMinimum_0_0"
},
{
"description": "below the exclusiveMinimum is invalid",
"data": 0.6,
"valid": false,
"schema_id": "exclusiveMinimum_0_0"
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true,
"schema_id": "exclusiveMinimum_0_0"
}
]
}
]

View File

@ -1,199 +0,0 @@
[
{
"description": "Entity families via pure $ref graph",
"database": {
"types": [
{
"name": "entity",
"variations": [
"entity",
"organization",
"person"
],
"schemas": [
{
"$id": "entity",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
{
"$id": "light.entity",
"$ref": "entity"
}
]
},
{
"name": "organization",
"variations": [
"organization",
"person"
],
"schemas": [
{
"$id": "organization",
"$ref": "entity",
"properties": {
"name": {
"type": "string"
}
}
}
]
},
{
"name": "person",
"variations": [
"person"
],
"schemas": [
{
"$id": "person",
"$ref": "organization",
"properties": {
"first_name": {
"type": "string"
}
}
},
{
"$id": "light.person",
"$ref": "light.entity"
}
]
}
],
"puncs": [
{
"name": "get_entities",
"schemas": [
{
"$id": "get_entities.response",
"$family": "entity"
}
]
},
{
"name": "get_light_entities",
"schemas": [
{
"$id": "get_light_entities.response",
"$family": "light.entity"
}
]
}
]
},
"tests": [
{
"description": "Family matches base entity",
"schema_id": "get_entities.response",
"data": {
"id": "1",
"type": "entity"
},
"valid": true
},
{
"description": "Family matches descendant person",
"schema_id": "get_entities.response",
"data": {
"id": "2",
"type": "person",
"name": "ACME",
"first_name": "John"
},
"valid": true
},
{
"description": "Graph family matches light.entity",
"schema_id": "get_light_entities.response",
"data": {
"id": "3",
"type": "entity"
},
"valid": true
},
{
"description": "Graph family matches light.person (because it $refs light.entity)",
"schema_id": "get_light_entities.response",
"data": {
"id": "4",
"type": "person"
},
"valid": true
},
{
"description": "Graph family excludes organization (missing light. schema that $refs light.entity)",
"schema_id": "get_light_entities.response",
"data": {
"id": "5",
"type": "organization",
"name": "ACME"
},
"valid": false,
"expect_errors": [
{
"code": "FAMILY_MISMATCH",
"path": ""
}
]
}
]
},
{
"description": "Ad-hoc non-entity families (using normal json-schema object structures)",
"database": {
"puncs": [
{
"name": "get_widgets",
"schemas": [
{
"$id": "widget",
"type": "object",
"properties": {
"id": {
"type": "string"
},
"widget_type": {
"type": "string"
}
}
},
{
"$id": "special_widget",
"$ref": "widget",
"properties": {
"special_feature": {
"type": "string"
}
}
},
{
"$id": "get_widgets.response",
"$family": "widget"
}
]
}
]
},
"tests": [
{
"description": "Ad-hoc family matches strictly by shape (no magic variations for base schemas)",
"schema_id": "get_widgets.response",
"data": {
"id": "1",
"widget_type": "special",
"special_feature": "yes"
},
"valid": true
}
]
}
]

File diff suppressed because it is too large Load Diff

View File

@ -1,495 +0,0 @@
[
{
"description": "ignore if without then or else",
"database": {
"schemas": [
{
"if": {
"const": 0
},
"$id": "if-then-else_0_0"
}
]
},
"tests": [
{
"description": "valid when valid against lone if",
"data": 0,
"valid": true,
"schema_id": "if-then-else_0_0"
},
{
"description": "valid when invalid against lone if",
"data": "hello",
"valid": true,
"schema_id": "if-then-else_0_0"
}
]
},
{
"description": "ignore then without if",
"database": {
"schemas": [
{
"then": {
"const": 0
},
"$id": "if-then-else_1_0"
}
]
},
"tests": [
{
"description": "valid when valid against lone then",
"data": 0,
"valid": true,
"schema_id": "if-then-else_1_0"
},
{
"description": "valid when invalid against lone then",
"data": "hello",
"valid": true,
"schema_id": "if-then-else_1_0"
}
]
},
{
"description": "ignore else without if",
"database": {
"schemas": [
{
"else": {
"const": 0
},
"$id": "if-then-else_2_0"
}
]
},
"tests": [
{
"description": "valid when valid against lone else",
"data": 0,
"valid": true,
"schema_id": "if-then-else_2_0"
},
{
"description": "valid when invalid against lone else",
"data": "hello",
"valid": true,
"schema_id": "if-then-else_2_0"
}
]
},
{
"description": "if and then without else",
"database": {
"schemas": [
{
"if": {
"exclusiveMaximum": 0
},
"then": {
"minimum": -10
},
"$id": "if-then-else_3_0"
}
]
},
"tests": [
{
"description": "valid through then",
"data": -1,
"valid": true,
"schema_id": "if-then-else_3_0"
},
{
"description": "invalid through then",
"data": -100,
"valid": false,
"schema_id": "if-then-else_3_0"
},
{
"description": "valid when if test fails",
"data": 3,
"valid": true,
"schema_id": "if-then-else_3_0"
}
]
},
{
"description": "if and else without then",
"database": {
"schemas": [
{
"if": {
"exclusiveMaximum": 0
},
"else": {
"multipleOf": 2
},
"$id": "if-then-else_4_0"
}
]
},
"tests": [
{
"description": "valid when if test passes",
"data": -1,
"valid": true,
"schema_id": "if-then-else_4_0"
},
{
"description": "valid through else",
"data": 4,
"valid": true,
"schema_id": "if-then-else_4_0"
},
{
"description": "invalid through else",
"data": 3,
"valid": false,
"schema_id": "if-then-else_4_0"
}
]
},
{
"description": "validate against correct branch, then vs else",
"database": {
"schemas": [
{
"if": {
"exclusiveMaximum": 0
},
"then": {
"minimum": -10
},
"else": {
"multipleOf": 2
},
"$id": "if-then-else_5_0"
}
]
},
"tests": [
{
"description": "valid through then",
"data": -1,
"valid": true,
"schema_id": "if-then-else_5_0"
},
{
"description": "invalid through then",
"data": -100,
"valid": false,
"schema_id": "if-then-else_5_0"
},
{
"description": "valid through else",
"data": 4,
"valid": true,
"schema_id": "if-then-else_5_0"
},
{
"description": "invalid through else",
"data": 3,
"valid": false,
"schema_id": "if-then-else_5_0"
}
]
},
{
"description": "non-interference across combined schemas",
"database": {
"schemas": [
{
"allOf": [
{
"if": {
"exclusiveMaximum": 0
}
},
{
"then": {
"minimum": -10
}
},
{
"else": {
"multipleOf": 2
}
}
],
"$id": "if-then-else_6_0"
}
]
},
"tests": [
{
"description": "valid, but would have been invalid through then",
"data": -100,
"valid": true,
"schema_id": "if-then-else_6_0"
},
{
"description": "valid, but would have been invalid through else",
"data": 3,
"valid": true,
"schema_id": "if-then-else_6_0"
}
]
},
{
"description": "if with boolean schema true",
"database": {
"schemas": [
{
"if": true,
"then": {
"const": "then"
},
"else": {
"const": "else"
},
"$id": "if-then-else_7_0"
}
]
},
"tests": [
{
"description": "boolean schema true in if always chooses the then path (valid)",
"data": "then",
"valid": true,
"schema_id": "if-then-else_7_0"
},
{
"description": "boolean schema true in if always chooses the then path (invalid)",
"data": "else",
"valid": false,
"schema_id": "if-then-else_7_0"
}
]
},
{
"description": "if with boolean schema false",
"database": {
"schemas": [
{
"if": false,
"then": {
"const": "then"
},
"else": {
"const": "else"
},
"$id": "if-then-else_8_0"
}
]
},
"tests": [
{
"description": "boolean schema false in if always chooses the else path (invalid)",
"data": "then",
"valid": false,
"schema_id": "if-then-else_8_0"
},
{
"description": "boolean schema false in if always chooses the else path (valid)",
"data": "else",
"valid": true,
"schema_id": "if-then-else_8_0"
}
]
},
{
"description": "if appears at the end when serialized (keyword processing sequence)",
"database": {
"schemas": [
{
"then": {
"const": "yes"
},
"else": {
"const": "other"
},
"if": {
"maxLength": 4
},
"$id": "if-then-else_9_0"
}
]
},
"tests": [
{
"description": "yes redirects to then and passes",
"data": "yes",
"valid": true,
"schema_id": "if-then-else_9_0"
},
{
"description": "other redirects to else and passes",
"data": "other",
"valid": true,
"schema_id": "if-then-else_9_0"
},
{
"description": "no redirects to then and fails",
"data": "no",
"valid": false,
"schema_id": "if-then-else_9_0"
},
{
"description": "invalid redirects to else and fails",
"data": "invalid",
"valid": false,
"schema_id": "if-then-else_9_0"
}
]
},
{
"description": "then: false fails when condition matches",
"database": {
"schemas": [
{
"if": {
"const": 1
},
"then": false,
"$id": "if-then-else_10_0"
}
]
},
"tests": [
{
"description": "matches if → then=false → invalid",
"data": 1,
"valid": false,
"schema_id": "if-then-else_10_0"
},
{
"description": "does not match if → then ignored → valid",
"data": 2,
"valid": true,
"schema_id": "if-then-else_10_0"
}
]
},
{
"description": "else: false fails when condition does not match",
"database": {
"schemas": [
{
"if": {
"const": 1
},
"else": false,
"$id": "if-then-else_11_0"
}
]
},
"tests": [
{
"description": "matches if → else ignored → valid",
"data": 1,
"valid": true,
"schema_id": "if-then-else_11_0"
},
{
"description": "does not match if → else executes → invalid",
"data": 2,
"valid": false,
"schema_id": "if-then-else_11_0"
}
]
},
{
"description": "extensible: true allows extra properties in if-then-else",
"database": {
"schemas": [
{
"if": {
"properties": {
"foo": {
"const": 1
}
},
"required": [
"foo"
]
},
"then": {
"properties": {
"bar": {
"const": 2
}
},
"required": [
"bar"
]
},
"extensible": true,
"$id": "if-then-else_12_0"
}
]
},
"tests": [
{
"description": "extra property is valid (matches if and then)",
"data": {
"foo": 1,
"bar": 2,
"extra": "prop"
},
"valid": true,
"schema_id": "if-then-else_12_0"
}
]
},
{
"description": "strict by default with if-then properties",
"database": {
"schemas": [
{
"if": {
"properties": {
"foo": {
"const": 1
}
},
"required": [
"foo"
]
},
"then": {
"properties": {
"bar": {
"const": 2
}
}
},
"$id": "if-then-else_13_0"
}
]
},
"tests": [
{
"description": "valid match (foo + bar)",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "if-then-else_13_0"
},
{
"description": "fails on extra property z explicitly",
"data": {
"foo": 1,
"bar": 2,
"z": 3
},
"valid": false,
"schema_id": "if-then-else_13_0"
}
]
}
]

View File

@ -1,843 +0,0 @@
[
{
"description": "a schema given for items",
"database": {
"schemas": [
{
"items": {
"type": "integer"
},
"$id": "items_0_0"
}
]
},
"tests": [
{
"description": "valid items",
"data": [
1,
2,
3
],
"valid": true,
"schema_id": "items_0_0"
},
{
"description": "wrong type of items",
"data": [
1,
"x"
],
"valid": false,
"schema_id": "items_0_0"
},
{
"description": "non-arrays are invalid",
"data": {
"foo": "bar"
},
"valid": false,
"schema_id": "items_0_0"
},
{
"description": "JavaScript pseudo-arrays are invalid",
"data": {
"0": "invalid",
"length": 1
},
"valid": false,
"schema_id": "items_0_0"
}
]
},
{
"description": "items with boolean schema (true)",
"database": {
"schemas": [
{
"items": true,
"$id": "items_1_0"
}
]
},
"tests": [
{
"description": "any array is valid",
"data": [
1,
"foo",
true
],
"valid": true,
"schema_id": "items_1_0"
},
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "items_1_0"
}
]
},
{
"description": "items with boolean schema (false)",
"database": {
"schemas": [
{
"items": false,
"$id": "items_2_0"
}
]
},
"tests": [
{
"description": "any non-empty array is invalid",
"data": [
1,
"foo",
true
],
"valid": false,
"schema_id": "items_2_0"
},
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "items_2_0"
}
]
},
{
"description": "items and subitems",
"database": {
"schemas": [
{
"type": "array",
"items": false,
"prefixItems": [
{
"$ref": "item"
},
{
"$ref": "item"
},
{
"$ref": "item"
}
],
"$id": "items_3_0"
},
{
"$id": "item",
"type": "array",
"items": false,
"prefixItems": [
{
"$ref": "sub-item"
},
{
"$ref": "sub-item"
}
]
},
{
"$id": "sub-item",
"type": "object",
"required": [
"foo"
]
}
]
},
"tests": [
{
"description": "valid items",
"data": [
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
]
],
"valid": false,
"schema_id": "items_3_0"
},
{
"description": "too many items",
"data": [
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
]
],
"valid": false,
"schema_id": "items_3_0"
},
{
"description": "too many sub-items",
"data": [
[
{
"foo": null
},
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
]
],
"valid": false,
"schema_id": "items_3_0"
},
{
"description": "wrong item",
"data": [
{
"foo": null
},
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
]
],
"valid": false,
"schema_id": "items_3_0"
},
{
"description": "wrong sub-item",
"data": [
[
{},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
],
[
{
"foo": null
},
{
"foo": null
}
]
],
"valid": false,
"schema_id": "items_3_0"
},
{
"description": "fewer items is invalid",
"data": [
[
{
"foo": null
}
],
[
{
"foo": null
}
]
],
"valid": false,
"schema_id": "items_3_0"
}
]
},
{
"description": "nested items",
"database": {
"schemas": [
{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "number"
}
}
}
},
"$id": "items_4_0"
}
]
},
"tests": [
{
"description": "valid nested array",
"data": [
[
[
[
1
]
],
[
[
2
],
[
3
]
]
],
[
[
[
4
],
[
5
],
[
6
]
]
]
],
"valid": true,
"schema_id": "items_4_0"
},
{
"description": "nested array with invalid type",
"data": [
[
[
[
"1"
]
],
[
[
2
],
[
3
]
]
],
[
[
[
4
],
[
5
],
[
6
]
]
]
],
"valid": false,
"schema_id": "items_4_0"
},
{
"description": "not deep enough",
"data": [
[
[
1
],
[
2
],
[
3
]
],
[
[
4
],
[
5
],
[
6
]
]
],
"valid": false,
"schema_id": "items_4_0"
}
]
},
{
"description": "prefixItems with no additional items allowed",
"database": {
"schemas": [
{
"prefixItems": [
{},
{},
{}
],
"items": false,
"$id": "items_5_0"
}
]
},
"tests": [
{
"description": "empty array",
"data": [],
"valid": true,
"schema_id": "items_5_0"
},
{
"description": "fewer number of items present (1)",
"data": [
1
],
"valid": true,
"schema_id": "items_5_0"
},
{
"description": "fewer number of items present (2)",
"data": [
1,
2
],
"valid": true,
"schema_id": "items_5_0"
},
{
"description": "equal number of items present",
"data": [
1,
2,
3
],
"valid": true,
"schema_id": "items_5_0"
},
{
"description": "additional items are not permitted",
"data": [
1,
2,
3,
4
],
"valid": false,
"schema_id": "items_5_0"
}
]
},
{
"description": "items does not look in applicators, valid case",
"database": {
"schemas": [
{
"allOf": [
{
"prefixItems": [
{
"minimum": 3
}
]
}
],
"items": {
"minimum": 5
},
"$id": "items_6_0"
}
]
},
"tests": [
{
"description": "prefixItems in allOf does not constrain items, invalid case",
"data": [
3,
5
],
"valid": false,
"schema_id": "items_6_0"
},
{
"description": "prefixItems in allOf does not constrain items, valid case",
"data": [
5,
5
],
"valid": true,
"schema_id": "items_6_0"
}
]
},
{
"description": "prefixItems validation adjusts the starting index for items",
"database": {
"schemas": [
{
"prefixItems": [
{
"type": "string"
}
],
"items": {
"type": "integer"
},
"$id": "items_7_0"
}
]
},
"tests": [
{
"description": "valid items",
"data": [
"x",
2,
3
],
"valid": true,
"schema_id": "items_7_0"
},
{
"description": "wrong type of second item",
"data": [
"x",
"y"
],
"valid": false,
"schema_id": "items_7_0"
}
]
},
{
"description": "items with heterogeneous array",
"database": {
"schemas": [
{
"prefixItems": [
{}
],
"items": false,
"$id": "items_8_0"
}
]
},
"tests": [
{
"description": "heterogeneous invalid instance",
"data": [
"foo",
"bar",
37
],
"valid": false,
"schema_id": "items_8_0"
},
{
"description": "valid instance",
"data": [
null
],
"valid": true,
"schema_id": "items_8_0"
}
]
},
{
"description": "items with null instance elements",
"database": {
"schemas": [
{
"items": {
"type": "null"
},
"$id": "items_9_0"
}
]
},
"tests": [
{
"description": "allows null elements",
"data": [
null
],
"valid": true,
"schema_id": "items_9_0"
}
]
},
{
"description": "extensible: true allows extra items (when items is false)",
"database": {
"schemas": [
{
"items": false,
"extensible": true,
"$id": "items_10_0"
}
]
},
"tests": [
{
"description": "extra item is valid",
"data": [
1
],
"valid": false,
"schema_id": "items_10_0"
}
]
},
{
"description": "extensible: true allows extra properties for items",
"database": {
"schemas": [
{
"items": {
"minimum": 5
},
"extensible": true,
"$id": "items_11_0"
}
]
},
"tests": [
{
"description": "valid item is valid",
"data": [
5,
6
],
"valid": true,
"schema_id": "items_11_0"
},
{
"description": "invalid item (less than min) is invalid even with extensible: true",
"data": [
4
],
"valid": false,
"schema_id": "items_11_0"
}
]
},
{
"description": "array: simple extensible array",
"database": {
"schemas": [
{
"type": "array",
"extensible": true,
"$id": "items_12_0"
}
]
},
"tests": [
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "items_12_0"
},
{
"description": "array with items is valid (extensible)",
"data": [
1,
"foo"
],
"valid": true,
"schema_id": "items_12_0"
}
]
},
{
"description": "array: strict array",
"database": {
"schemas": [
{
"type": "array",
"extensible": false,
"$id": "items_13_0"
}
]
},
"tests": [
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "items_13_0"
},
{
"description": "array with items is invalid (strict)",
"data": [
1
],
"valid": false,
"schema_id": "items_13_0"
}
]
},
{
"description": "array: items extensible",
"database": {
"schemas": [
{
"type": "array",
"items": {
"extensible": true
},
"$id": "items_14_0"
}
]
},
"tests": [
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "items_14_0"
},
{
"description": "array with items is valid (items explicitly allowed to be anything extensible)",
"data": [
1,
"foo",
{}
],
"valid": true,
"schema_id": "items_14_0"
}
]
},
{
"description": "array: items strict",
"database": {
"schemas": [
{
"type": "array",
"items": {
"type": "object",
"extensible": false
},
"$id": "items_15_0"
}
]
},
"tests": [
{
"description": "empty array is valid (empty objects)",
"data": [
{}
],
"valid": true,
"schema_id": "items_15_0"
},
{
"description": "array with strict object items is valid",
"data": [
{}
],
"valid": true,
"schema_id": "items_15_0"
},
{
"description": "array with invalid strict object items (extra property)",
"data": [
{
"extra": 1
}
],
"valid": false,
"schema_id": "items_15_0"
}
]
}
]

View File

@ -1,196 +0,0 @@
[
{
"description": "maxContains without contains is ignored",
"database": {
"schemas": [
{
"maxContains": 1,
"extensible": true,
"$id": "maxContains_0_0"
}
]
},
"tests": [
{
"description": "one item valid against lone maxContains",
"data": [
1
],
"valid": true,
"schema_id": "maxContains_0_0"
},
{
"description": "two items still valid against lone maxContains",
"data": [
1,
2
],
"valid": true,
"schema_id": "maxContains_0_0"
}
]
},
{
"description": "maxContains with contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"extensible": true,
"$id": "maxContains_1_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"valid": false,
"schema_id": "maxContains_1_0"
},
{
"description": "all elements match, valid maxContains",
"data": [
1
],
"valid": true,
"schema_id": "maxContains_1_0"
},
{
"description": "all elements match, invalid maxContains",
"data": [
1,
1
],
"valid": false,
"schema_id": "maxContains_1_0"
},
{
"description": "some elements match, valid maxContains",
"data": [
1,
2
],
"valid": true,
"schema_id": "maxContains_1_0"
},
{
"description": "some elements match, invalid maxContains",
"data": [
1,
2,
1
],
"valid": false,
"schema_id": "maxContains_1_0"
}
]
},
{
"description": "maxContains with contains, value with a decimal",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"extensible": true,
"$id": "maxContains_2_0"
}
]
},
"tests": [
{
"description": "one element matches, valid maxContains",
"data": [
1
],
"valid": true,
"schema_id": "maxContains_2_0"
},
{
"description": "too many elements match, invalid maxContains",
"data": [
1,
1
],
"valid": false,
"schema_id": "maxContains_2_0"
}
]
},
{
"description": "minContains < maxContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 1,
"maxContains": 3,
"extensible": true,
"$id": "maxContains_3_0"
}
]
},
"tests": [
{
"description": "actual < minContains < maxContains",
"data": [],
"valid": false,
"schema_id": "maxContains_3_0"
},
{
"description": "minContains < actual < maxContains",
"data": [
1,
1
],
"valid": true,
"schema_id": "maxContains_3_0"
},
{
"description": "minContains < maxContains < actual",
"data": [
1,
1,
1,
1
],
"valid": false,
"schema_id": "maxContains_3_0"
}
]
},
{
"description": "extensible: true allows non-matching items in maxContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"extensible": true,
"$id": "maxContains_4_0"
}
]
},
"tests": [
{
"description": "extra items disregarded for maxContains",
"data": [
1,
2
],
"valid": true,
"schema_id": "maxContains_4_0"
}
]
}
]

View File

@ -1,105 +0,0 @@
[
{
"description": "maxItems validation",
"database": {
"schemas": [
{
"maxItems": 2,
"extensible": true,
"$id": "maxItems_0_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": [
1
],
"valid": true,
"schema_id": "maxItems_0_0"
},
{
"description": "exact length is valid",
"data": [
1,
2
],
"valid": true,
"schema_id": "maxItems_0_0"
},
{
"description": "too long is invalid",
"data": [
1,
2,
3
],
"valid": false,
"schema_id": "maxItems_0_0"
},
{
"description": "ignores non-arrays",
"data": "foobar",
"valid": true,
"schema_id": "maxItems_0_0"
}
]
},
{
"description": "maxItems validation with a decimal",
"database": {
"schemas": [
{
"maxItems": 2,
"extensible": true,
"$id": "maxItems_1_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": [
1
],
"valid": true,
"schema_id": "maxItems_1_0"
},
{
"description": "too long is invalid",
"data": [
1,
2,
3
],
"valid": false,
"schema_id": "maxItems_1_0"
}
]
},
{
"description": "extensible: true allows extra items in maxItems (but counted)",
"database": {
"schemas": [
{
"maxItems": 2,
"extensible": true,
"$id": "maxItems_2_0"
}
]
},
"tests": [
{
"description": "extra item counted towards maxItems",
"data": [
1,
2,
3
],
"valid": false,
"schema_id": "maxItems_2_0"
}
]
}
]

View File

@ -1,70 +0,0 @@
[
{
"description": "maxLength validation",
"database": {
"schemas": [
{
"maxLength": 2,
"$id": "maxLength_0_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": "f",
"valid": true,
"schema_id": "maxLength_0_0"
},
{
"description": "exact length is valid",
"data": "fo",
"valid": true,
"schema_id": "maxLength_0_0"
},
{
"description": "too long is invalid",
"data": "foo",
"valid": false,
"schema_id": "maxLength_0_0"
},
{
"description": "ignores non-strings",
"data": 100,
"valid": true,
"schema_id": "maxLength_0_0"
},
{
"description": "two graphemes is long enough",
"data": "💩💩",
"valid": true,
"schema_id": "maxLength_0_0"
}
]
},
{
"description": "maxLength validation with a decimal",
"database": {
"schemas": [
{
"maxLength": 2,
"$id": "maxLength_1_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": "f",
"valid": true,
"schema_id": "maxLength_1_0"
},
{
"description": "too long is invalid",
"data": "foo",
"valid": false,
"schema_id": "maxLength_1_0"
}
]
}
]

View File

@ -1,157 +0,0 @@
[
{
"description": "maxProperties validation",
"database": {
"schemas": [
{
"maxProperties": 2,
"extensible": true,
"$id": "maxProperties_0_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "maxProperties_0_0"
},
{
"description": "exact length is valid",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "maxProperties_0_0"
},
{
"description": "too long is invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"valid": false,
"schema_id": "maxProperties_0_0"
},
{
"description": "ignores arrays",
"data": [
1,
2,
3
],
"valid": true,
"schema_id": "maxProperties_0_0"
},
{
"description": "ignores strings",
"data": "foobar",
"valid": true,
"schema_id": "maxProperties_0_0"
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true,
"schema_id": "maxProperties_0_0"
}
]
},
{
"description": "maxProperties validation with a decimal",
"database": {
"schemas": [
{
"maxProperties": 2,
"extensible": true,
"$id": "maxProperties_1_0"
}
]
},
"tests": [
{
"description": "shorter is valid",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "maxProperties_1_0"
},
{
"description": "too long is invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"valid": false,
"schema_id": "maxProperties_1_0"
}
]
},
{
"description": "maxProperties = 0 means the object is empty",
"database": {
"schemas": [
{
"maxProperties": 0,
"extensible": true,
"$id": "maxProperties_2_0"
}
]
},
"tests": [
{
"description": "no properties is valid",
"data": {},
"valid": true,
"schema_id": "maxProperties_2_0"
},
{
"description": "one property is invalid",
"data": {
"foo": 1
},
"valid": false,
"schema_id": "maxProperties_2_0"
}
]
},
{
"description": "extensible: true allows extra properties in maxProperties (though maxProperties still counts them!)",
"database": {
"schemas": [
{
"maxProperties": 2,
"extensible": true,
"$id": "maxProperties_3_0"
}
]
},
"tests": [
{
"description": "extra property is counted towards maxProperties",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"valid": false,
"schema_id": "maxProperties_3_0"
},
{
"description": "extra property is valid if below maxProperties",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "maxProperties_3_0"
}
]
}
]

View File

@ -1,76 +0,0 @@
[
{
"description": "maximum validation",
"database": {
"schemas": [
{
"maximum": 3,
"$id": "maximum_0_0"
}
]
},
"tests": [
{
"description": "below the maximum is valid",
"data": 2.6,
"valid": true,
"schema_id": "maximum_0_0"
},
{
"description": "boundary point is valid",
"data": 3,
"valid": true,
"schema_id": "maximum_0_0"
},
{
"description": "above the maximum is invalid",
"data": 3.5,
"valid": false,
"schema_id": "maximum_0_0"
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true,
"schema_id": "maximum_0_0"
}
]
},
{
"description": "maximum validation with unsigned integer",
"database": {
"schemas": [
{
"maximum": 300,
"$id": "maximum_1_0"
}
]
},
"tests": [
{
"description": "below the maximum is invalid",
"data": 299.97,
"valid": true,
"schema_id": "maximum_1_0"
},
{
"description": "boundary point integer is valid",
"data": 300,
"valid": true,
"schema_id": "maximum_1_0"
},
{
"description": "boundary point float is valid",
"data": 300,
"valid": true,
"schema_id": "maximum_1_0"
},
{
"description": "above the maximum is invalid",
"data": 300.5,
"valid": false,
"schema_id": "maximum_1_0"
}
]
}
]

View File

@ -1,247 +0,0 @@
[
{
"description": "merging: properties accumulate",
"database": {
"schemas": [
{
"$id": "base_0",
"properties": {
"base_prop": {
"type": "string"
}
}
},
{
"$ref": "base_0",
"properties": {
"child_prop": {
"type": "string"
}
},
"$id": "merge_0_0"
}
]
},
"tests": [
{
"description": "valid with both properties",
"data": {
"base_prop": "a",
"child_prop": "b"
},
"valid": true,
"schema_id": "merge_0_0"
},
{
"description": "invalid when base property has wrong type",
"data": {
"base_prop": 1,
"child_prop": "b"
},
"valid": false,
"expect_errors": [
{
"code": "TYPE_MISMATCH",
"path": "/base_prop"
}
],
"schema_id": "merge_0_0"
}
]
},
{
"description": "merging: required fields accumulate",
"database": {
"schemas": [
{
"$id": "base_1",
"properties": {
"a": {
"type": "string"
}
},
"required": [
"a"
]
},
{
"$ref": "base_1",
"properties": {
"b": {
"type": "string"
}
},
"required": [
"b"
],
"$id": "merge_1_0"
}
]
},
"tests": [
{
"description": "valid when both present",
"data": {
"a": "ok",
"b": "ok"
},
"valid": true,
"schema_id": "merge_1_0"
},
{
"description": "invalid when base required missing",
"data": {
"b": "ok"
},
"valid": false,
"expect_errors": [
{
"code": "REQUIRED_FIELD_MISSING",
"path": "/a"
}
],
"schema_id": "merge_1_0"
},
{
"description": "invalid when child required missing",
"data": {
"a": "ok"
},
"valid": false,
"expect_errors": [
{
"code": "REQUIRED_FIELD_MISSING",
"path": "/b"
}
],
"schema_id": "merge_1_0"
}
]
},
{
"description": "merging: dependencies accumulate",
"database": {
"schemas": [
{
"$id": "base_2",
"properties": {
"trigger": {
"type": "string"
},
"base_dep": {
"type": "string"
}
},
"dependencies": {
"trigger": [
"base_dep"
]
}
},
{
"$ref": "base_2",
"properties": {
"child_dep": {
"type": "string"
}
},
"dependencies": {
"trigger": [
"child_dep"
]
},
"$id": "merge_2_0"
}
]
},
"tests": [
{
"description": "valid with all deps",
"data": {
"trigger": "go",
"base_dep": "ok",
"child_dep": "ok"
},
"valid": true,
"schema_id": "merge_2_0"
},
{
"description": "invalid missing base dep",
"data": {
"trigger": "go",
"child_dep": "ok"
},
"valid": false,
"expect_errors": [
{
"code": "DEPENDENCY_FAILED",
"path": "/base_dep"
}
],
"schema_id": "merge_2_0"
},
{
"description": "invalid missing child dep",
"data": {
"trigger": "go",
"base_dep": "ok"
},
"valid": false,
"expect_errors": [
{
"code": "DEPENDENCY_FAILED",
"path": "/child_dep"
}
],
"schema_id": "merge_2_0"
}
]
},
{
"description": "merging: form and display do NOT merge",
"database": {
"schemas": [
{
"$id": "base_3",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
}
},
"form": [
"a",
"b"
]
},
{
"$ref": "base_3",
"properties": {
"c": {
"type": "string"
}
},
"form": [
"c"
],
"$id": "merge_3_0"
}
]
},
"tests": [
{
"description": "child schema validation",
"data": {
"a": "ok",
"b": "ok",
"c": "ok"
},
"valid": true,
"comment": "Verifies validator handles the unmerged metadata correctly (ignores it or handles replacement)",
"schema_id": "merge_3_0"
}
]
}
]

View File

@ -1,390 +0,0 @@
[
{
"description": "minContains without contains is ignored",
"database": {
"schemas": [
{
"minContains": 1,
"extensible": true,
"$id": "minContains_0_0"
}
]
},
"tests": [
{
"description": "one item valid against lone minContains",
"data": [
1
],
"valid": true,
"schema_id": "minContains_0_0"
},
{
"description": "zero items still valid against lone minContains",
"data": [],
"valid": true,
"schema_id": "minContains_0_0"
}
]
},
{
"description": "minContains=1 with contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 1,
"extensible": true,
"$id": "minContains_1_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"valid": false,
"schema_id": "minContains_1_0"
},
{
"description": "no elements match",
"data": [
2
],
"valid": false,
"schema_id": "minContains_1_0"
},
{
"description": "single element matches, valid minContains",
"data": [
1
],
"valid": true,
"schema_id": "minContains_1_0"
},
{
"description": "some elements match, valid minContains",
"data": [
1,
2
],
"valid": true,
"schema_id": "minContains_1_0"
},
{
"description": "all elements match, valid minContains",
"data": [
1,
1
],
"valid": true,
"schema_id": "minContains_1_0"
}
]
},
{
"description": "minContains=2 with contains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 2,
"extensible": true,
"$id": "minContains_2_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"valid": false,
"schema_id": "minContains_2_0"
},
{
"description": "all elements match, invalid minContains",
"data": [
1
],
"valid": false,
"schema_id": "minContains_2_0"
},
{
"description": "some elements match, invalid minContains",
"data": [
1,
2
],
"valid": false,
"schema_id": "minContains_2_0"
},
{
"description": "all elements match, valid minContains (exactly as needed)",
"data": [
1,
1
],
"valid": true,
"schema_id": "minContains_2_0"
},
{
"description": "all elements match, valid minContains (more than needed)",
"data": [
1,
1,
1
],
"valid": true,
"schema_id": "minContains_2_0"
},
{
"description": "some elements match, valid minContains",
"data": [
1,
2,
1
],
"valid": true,
"schema_id": "minContains_2_0"
}
]
},
{
"description": "minContains=2 with contains with a decimal value",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 2,
"extensible": true,
"$id": "minContains_3_0"
}
]
},
"tests": [
{
"description": "one element matches, invalid minContains",
"data": [
1
],
"valid": false,
"schema_id": "minContains_3_0"
},
{
"description": "both elements match, valid minContains",
"data": [
1,
1
],
"valid": true,
"schema_id": "minContains_3_0"
}
]
},
{
"description": "maxContains = minContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 2,
"minContains": 2,
"extensible": true,
"$id": "minContains_4_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"valid": false,
"schema_id": "minContains_4_0"
},
{
"description": "all elements match, invalid minContains",
"data": [
1
],
"valid": false,
"schema_id": "minContains_4_0"
},
{
"description": "all elements match, invalid maxContains",
"data": [
1,
1,
1
],
"valid": false,
"schema_id": "minContains_4_0"
},
{
"description": "all elements match, valid maxContains and minContains",
"data": [
1,
1
],
"valid": true,
"schema_id": "minContains_4_0"
}
]
},
{
"description": "maxContains < minContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"maxContains": 1,
"minContains": 3,
"extensible": true,
"$id": "minContains_5_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"valid": false,
"schema_id": "minContains_5_0"
},
{
"description": "invalid minContains",
"data": [
1
],
"valid": false,
"schema_id": "minContains_5_0"
},
{
"description": "invalid maxContains",
"data": [
1,
1,
1
],
"valid": false,
"schema_id": "minContains_5_0"
},
{
"description": "invalid maxContains and minContains",
"data": [
1,
1
],
"valid": false,
"schema_id": "minContains_5_0"
}
]
},
{
"description": "minContains = 0",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 0,
"extensible": true,
"$id": "minContains_6_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"valid": true,
"schema_id": "minContains_6_0"
},
{
"description": "minContains = 0 makes contains always pass",
"data": [
2
],
"valid": true,
"schema_id": "minContains_6_0"
}
]
},
{
"description": "minContains = 0 with maxContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 0,
"maxContains": 1,
"extensible": true,
"$id": "minContains_7_0"
}
]
},
"tests": [
{
"description": "empty data",
"data": [],
"valid": true,
"schema_id": "minContains_7_0"
},
{
"description": "not more than maxContains",
"data": [
1
],
"valid": true,
"schema_id": "minContains_7_0"
},
{
"description": "too many",
"data": [
1,
1
],
"valid": false,
"schema_id": "minContains_7_0"
}
]
},
{
"description": "extensible: true allows non-matching items in minContains",
"database": {
"schemas": [
{
"contains": {
"const": 1
},
"minContains": 1,
"extensible": true,
"$id": "minContains_8_0"
}
]
},
"tests": [
{
"description": "extra items disregarded for minContains",
"data": [
1,
2
],
"valid": true,
"schema_id": "minContains_8_0"
}
]
}
]

View File

@ -1,96 +0,0 @@
[
{
"description": "minItems validation",
"database": {
"schemas": [
{
"minItems": 1,
"extensible": true,
"$id": "minItems_0_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": [
1,
2
],
"valid": true,
"schema_id": "minItems_0_0"
},
{
"description": "exact length is valid",
"data": [
1
],
"valid": true,
"schema_id": "minItems_0_0"
},
{
"description": "too short is invalid",
"data": [],
"valid": false,
"schema_id": "minItems_0_0"
},
{
"description": "ignores non-arrays",
"data": "",
"valid": true,
"schema_id": "minItems_0_0"
}
]
},
{
"description": "minItems validation with a decimal",
"database": {
"schemas": [
{
"minItems": 1,
"extensible": true,
"$id": "minItems_1_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": [
1,
2
],
"valid": true,
"schema_id": "minItems_1_0"
},
{
"description": "too short is invalid",
"data": [],
"valid": false,
"schema_id": "minItems_1_0"
}
]
},
{
"description": "extensible: true allows extra items in minItems",
"database": {
"schemas": [
{
"minItems": 1,
"extensible": true,
"$id": "minItems_2_0"
}
]
},
"tests": [
{
"description": "extra item counted towards minItems",
"data": [
1
],
"valid": true,
"schema_id": "minItems_2_0"
}
]
}
]

View File

@ -1,70 +0,0 @@
[
{
"description": "minLength validation",
"database": {
"schemas": [
{
"minLength": 2,
"$id": "minLength_0_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": "foo",
"valid": true,
"schema_id": "minLength_0_0"
},
{
"description": "exact length is valid",
"data": "fo",
"valid": true,
"schema_id": "minLength_0_0"
},
{
"description": "too short is invalid",
"data": "f",
"valid": false,
"schema_id": "minLength_0_0"
},
{
"description": "ignores non-strings",
"data": 1,
"valid": true,
"schema_id": "minLength_0_0"
},
{
"description": "one grapheme is not long enough",
"data": "💩",
"valid": false,
"schema_id": "minLength_0_0"
}
]
},
{
"description": "minLength validation with a decimal",
"database": {
"schemas": [
{
"minLength": 2,
"$id": "minLength_1_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": "foo",
"valid": true,
"schema_id": "minLength_1_0"
},
{
"description": "too short is invalid",
"data": "f",
"valid": false,
"schema_id": "minLength_1_0"
}
]
}
]

View File

@ -1,108 +0,0 @@
[
{
"description": "minProperties validation",
"database": {
"schemas": [
{
"minProperties": 1,
"extensible": true,
"$id": "minProperties_0_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "minProperties_0_0"
},
{
"description": "exact length is valid",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "minProperties_0_0"
},
{
"description": "too short is invalid",
"data": {},
"valid": false,
"schema_id": "minProperties_0_0"
},
{
"description": "ignores arrays",
"data": [],
"valid": true,
"schema_id": "minProperties_0_0"
},
{
"description": "ignores strings",
"data": "",
"valid": true,
"schema_id": "minProperties_0_0"
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true,
"schema_id": "minProperties_0_0"
}
]
},
{
"description": "minProperties validation with a decimal",
"database": {
"schemas": [
{
"minProperties": 1,
"extensible": true,
"$id": "minProperties_1_0"
}
]
},
"tests": [
{
"description": "longer is valid",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "minProperties_1_0"
},
{
"description": "too short is invalid",
"data": {},
"valid": false,
"schema_id": "minProperties_1_0"
}
]
},
{
"description": "extensible: true allows extra properties in minProperties",
"database": {
"schemas": [
{
"minProperties": 1,
"extensible": true,
"$id": "minProperties_2_0"
}
]
},
"tests": [
{
"description": "extra property counts towards minProperties",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "minProperties_2_0"
}
]
}
]

View File

@ -1,94 +0,0 @@
[
{
"description": "minimum validation",
"database": {
"schemas": [
{
"minimum": 1.1,
"$id": "minimum_0_0"
}
]
},
"tests": [
{
"description": "above the minimum is valid",
"data": 2.6,
"valid": true,
"schema_id": "minimum_0_0"
},
{
"description": "boundary point is valid",
"data": 1.1,
"valid": true,
"schema_id": "minimum_0_0"
},
{
"description": "below the minimum is invalid",
"data": 0.6,
"valid": false,
"schema_id": "minimum_0_0"
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true,
"schema_id": "minimum_0_0"
}
]
},
{
"description": "minimum validation with signed integer",
"database": {
"schemas": [
{
"minimum": -2,
"$id": "minimum_1_0"
}
]
},
"tests": [
{
"description": "negative above the minimum is valid",
"data": -1,
"valid": true,
"schema_id": "minimum_1_0"
},
{
"description": "positive above the minimum is valid",
"data": 0,
"valid": true,
"schema_id": "minimum_1_0"
},
{
"description": "boundary point is valid",
"data": -2,
"valid": true,
"schema_id": "minimum_1_0"
},
{
"description": "boundary point with float is valid",
"data": -2,
"valid": true,
"schema_id": "minimum_1_0"
},
{
"description": "float below the minimum is invalid",
"data": -2.0001,
"valid": false,
"schema_id": "minimum_1_0"
},
{
"description": "int below the minimum is invalid",
"data": -3,
"valid": false,
"schema_id": "minimum_1_0"
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true,
"schema_id": "minimum_1_0"
}
]
}
]

View File

@ -1,109 +0,0 @@
[
{
"description": "by int",
"database": {
"schemas": [
{
"multipleOf": 2,
"$id": "multipleOf_0_0"
}
]
},
"tests": [
{
"description": "int by int",
"data": 10,
"valid": true,
"schema_id": "multipleOf_0_0"
},
{
"description": "int by int fail",
"data": 7,
"valid": false,
"schema_id": "multipleOf_0_0"
},
{
"description": "ignores non-numbers",
"data": "foo",
"valid": true,
"schema_id": "multipleOf_0_0"
}
]
},
{
"description": "by number",
"database": {
"schemas": [
{
"multipleOf": 1.5,
"$id": "multipleOf_1_0"
}
]
},
"tests": [
{
"description": "zero is multiple of anything",
"data": 0,
"valid": true,
"schema_id": "multipleOf_1_0"
},
{
"description": "4.5 is multiple of 1.5",
"data": 4.5,
"valid": true,
"schema_id": "multipleOf_1_0"
},
{
"description": "35 is not multiple of 1.5",
"data": 35,
"valid": false,
"schema_id": "multipleOf_1_0"
}
]
},
{
"description": "by small number",
"database": {
"schemas": [
{
"multipleOf": 0.0001,
"$id": "multipleOf_2_0"
}
]
},
"tests": [
{
"description": "0.0075 is multiple of 0.0001",
"data": 0.0075,
"valid": true,
"schema_id": "multipleOf_2_0"
},
{
"description": "0.00751 is not multiple of 0.0001",
"data": 0.00751,
"valid": false,
"schema_id": "multipleOf_2_0"
}
]
},
{
"description": "small multiple of large integer",
"database": {
"schemas": [
{
"type": "integer",
"multipleOf": 1e-8,
"$id": "multipleOf_3_0"
}
]
},
"tests": [
{
"description": "any integer is a multiple of 1e-8",
"data": 12391239123,
"valid": true,
"schema_id": "multipleOf_3_0"
}
]
}
]

View File

@ -1,489 +0,0 @@
[
{
"description": "not",
"database": {
"schemas": [
{
"not": {
"type": "integer"
},
"$id": "not_0_0"
}
]
},
"tests": [
{
"description": "allowed",
"data": "foo",
"valid": true,
"schema_id": "not_0_0"
},
{
"description": "disallowed",
"data": 1,
"valid": false,
"schema_id": "not_0_0"
}
]
},
{
"description": "not multiple types",
"database": {
"schemas": [
{
"not": {
"type": [
"integer",
"boolean"
]
},
"$id": "not_1_0"
}
]
},
"tests": [
{
"description": "valid",
"data": "foo",
"valid": true,
"schema_id": "not_1_0"
},
{
"description": "mismatch",
"data": 1,
"valid": false,
"schema_id": "not_1_0"
},
{
"description": "other mismatch",
"data": true,
"valid": false,
"schema_id": "not_1_0"
}
]
},
{
"description": "not more complex schema",
"database": {
"schemas": [
{
"not": {
"type": "object",
"properties": {
"foo": {
"type": "string"
}
}
},
"extensible": true,
"$id": "not_2_0"
}
]
},
"tests": [
{
"description": "match",
"data": 1,
"valid": true,
"schema_id": "not_2_0"
},
{
"description": "other match",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "not_2_0"
},
{
"description": "mismatch",
"data": {
"foo": "bar"
},
"valid": false,
"schema_id": "not_2_0"
}
]
},
{
"description": "forbidden property",
"database": {
"schemas": [
{
"properties": {
"foo": {
"not": {}
}
},
"$id": "not_3_0"
}
]
},
"tests": [
{
"description": "property present",
"data": {
"foo": 1,
"bar": 2
},
"valid": false,
"schema_id": "not_3_0"
},
{
"description": "empty object is valid",
"data": {},
"valid": true,
"schema_id": "not_3_0"
}
]
},
{
"description": "forbid everything with empty schema",
"database": {
"schemas": [
{
"not": {},
"$id": "not_4_0"
}
]
},
"tests": [
{
"description": "number is invalid",
"data": 1,
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "string is invalid",
"data": "foo",
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "boolean true is invalid",
"data": true,
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "boolean false is invalid",
"data": false,
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "null is invalid",
"data": null,
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "object is invalid",
"data": {
"foo": "bar"
},
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "empty object is invalid",
"data": {},
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "array is invalid",
"data": [
"foo"
],
"valid": false,
"schema_id": "not_4_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "not_4_0"
}
]
},
{
"description": "forbid everything with boolean schema true",
"database": {
"schemas": [
{
"not": true,
"$id": "not_5_0"
}
]
},
"tests": [
{
"description": "number is invalid",
"data": 1,
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "string is invalid",
"data": "foo",
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "boolean true is invalid",
"data": true,
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "boolean false is invalid",
"data": false,
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "null is invalid",
"data": null,
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "object is invalid",
"data": {
"foo": "bar"
},
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "empty object is invalid",
"data": {},
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "array is invalid",
"data": [
"foo"
],
"valid": false,
"schema_id": "not_5_0"
},
{
"description": "empty array is invalid",
"data": [],
"valid": false,
"schema_id": "not_5_0"
}
]
},
{
"description": "allow everything with boolean schema false",
"database": {
"schemas": [
{
"not": false,
"extensible": true,
"$id": "not_6_0"
}
]
},
"tests": [
{
"description": "number is valid",
"data": 1,
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "string is valid",
"data": "foo",
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "boolean true is valid",
"data": true,
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "boolean false is valid",
"data": false,
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "null is valid",
"data": null,
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "object is valid",
"data": {
"foo": "bar"
},
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "empty object is valid",
"data": {},
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "array is valid",
"data": [
"foo"
],
"valid": true,
"schema_id": "not_6_0"
},
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "not_6_0"
}
]
},
{
"description": "double negation",
"database": {
"schemas": [
{
"not": {
"not": {}
},
"$id": "not_7_0"
}
]
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true,
"schema_id": "not_7_0"
}
]
},
{
"description": "extensible: true allows extra properties in not",
"database": {
"schemas": [
{
"not": {
"type": "integer"
},
"extensible": true,
"$id": "not_8_0"
}
]
},
"tests": [
{
"description": "extra property is valid (not integer matches)",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "not_8_0"
}
]
},
{
"description": "extensible: false (default) forbids extra properties in not",
"database": {
"schemas": [
{
"not": {
"type": "integer"
},
"$id": "not_9_0"
}
]
},
"tests": [
{
"description": "extra property is invalid due to strictness",
"data": {
"foo": 1
},
"valid": false,
"schema_id": "not_9_0"
}
]
},
{
"description": "property next to not (extensible: true)",
"database": {
"schemas": [
{
"properties": {
"bar": {
"type": "string"
}
},
"not": {
"type": "integer"
},
"extensible": true,
"$id": "not_10_0"
}
]
},
"tests": [
{
"description": "extra property allowed",
"data": {
"bar": "baz",
"foo": 1
},
"valid": true,
"schema_id": "not_10_0"
}
]
},
{
"description": "property next to not (extensible: false)",
"database": {
"schemas": [
{
"properties": {
"bar": {
"type": "string"
}
},
"not": {
"type": "integer"
},
"$id": "not_11_0"
}
]
},
"tests": [
{
"description": "extra property forbidden",
"data": {
"bar": "baz",
"foo": 1
},
"valid": false,
"schema_id": "not_11_0"
},
{
"description": "defined property allowed",
"data": {
"bar": "baz"
},
"valid": true,
"schema_id": "not_11_0"
}
]
}
]

View File

@ -1,568 +0,0 @@
[
{
"description": "oneOf",
"database": {
"schemas": [
{
"oneOf": [
{
"type": "integer"
},
{
"minimum": 2
}
],
"$id": "oneOf_0_0"
}
]
},
"tests": [
{
"description": "first oneOf valid",
"data": 1,
"valid": true,
"schema_id": "oneOf_0_0"
},
{
"description": "second oneOf valid",
"data": 2.5,
"valid": true,
"schema_id": "oneOf_0_0"
},
{
"description": "both oneOf valid",
"data": 3,
"valid": false,
"schema_id": "oneOf_0_0"
},
{
"description": "neither oneOf valid",
"data": 1.5,
"valid": false,
"schema_id": "oneOf_0_0"
}
]
},
{
"description": "oneOf with base schema",
"database": {
"schemas": [
{
"type": "string",
"oneOf": [
{
"minLength": 2
},
{
"maxLength": 4
}
],
"$id": "oneOf_1_0"
}
]
},
"tests": [
{
"description": "mismatch base schema",
"data": 3,
"valid": false,
"schema_id": "oneOf_1_0"
},
{
"description": "one oneOf valid",
"data": "foobar",
"valid": true,
"schema_id": "oneOf_1_0"
},
{
"description": "both oneOf valid",
"data": "foo",
"valid": false,
"schema_id": "oneOf_1_0"
}
]
},
{
"description": "oneOf with boolean schemas, all true",
"database": {
"schemas": [
{
"oneOf": [
true,
true,
true
],
"$id": "oneOf_2_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false,
"schema_id": "oneOf_2_0"
}
]
},
{
"description": "oneOf with boolean schemas, one true",
"database": {
"schemas": [
{
"oneOf": [
true,
false,
false
],
"$id": "oneOf_3_0"
}
]
},
"tests": [
{
"description": "any value is valid",
"data": "foo",
"valid": true,
"schema_id": "oneOf_3_0"
}
]
},
{
"description": "oneOf with boolean schemas, more than one true",
"database": {
"schemas": [
{
"oneOf": [
true,
true,
false
],
"$id": "oneOf_4_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false,
"schema_id": "oneOf_4_0"
}
]
},
{
"description": "oneOf with boolean schemas, all false",
"database": {
"schemas": [
{
"oneOf": [
false,
false,
false
],
"$id": "oneOf_5_0"
}
]
},
"tests": [
{
"description": "any value is invalid",
"data": "foo",
"valid": false,
"schema_id": "oneOf_5_0"
}
]
},
{
"description": "oneOf complex types",
"database": {
"schemas": [
{
"oneOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"$id": "oneOf_6_0"
}
]
},
"tests": [
{
"description": "first oneOf valid (complex)",
"data": {
"bar": 2
},
"valid": true,
"schema_id": "oneOf_6_0"
},
{
"description": "second oneOf valid (complex)",
"data": {
"foo": "baz"
},
"valid": true,
"schema_id": "oneOf_6_0"
},
{
"description": "both oneOf valid (complex)",
"data": {
"foo": "baz",
"bar": 2
},
"valid": false,
"schema_id": "oneOf_6_0"
},
{
"description": "neither oneOf valid (complex)",
"data": {
"foo": 2,
"bar": "quux"
},
"valid": false,
"schema_id": "oneOf_6_0"
}
]
},
{
"description": "oneOf with empty schema",
"database": {
"schemas": [
{
"oneOf": [
{
"type": "number"
},
{}
],
"$id": "oneOf_7_0"
}
]
},
"tests": [
{
"description": "one valid - valid",
"data": "foo",
"valid": true,
"schema_id": "oneOf_7_0"
},
{
"description": "both valid - invalid",
"data": 123,
"valid": false,
"schema_id": "oneOf_7_0"
}
]
},
{
"description": "oneOf with required",
"database": {
"schemas": [
{
"type": "object",
"properties": {
"foo": true,
"bar": true,
"baz": true
},
"oneOf": [
{
"required": [
"foo",
"bar"
]
},
{
"required": [
"foo",
"baz"
]
}
],
"$id": "oneOf_8_0"
}
]
},
"tests": [
{
"description": "both invalid - invalid",
"data": {
"bar": 2
},
"valid": false,
"schema_id": "oneOf_8_0"
},
{
"description": "first valid - valid",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "oneOf_8_0"
},
{
"description": "second valid - valid",
"data": {
"foo": 1,
"baz": 3
},
"valid": true,
"schema_id": "oneOf_8_0"
},
{
"description": "both valid - invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"valid": false,
"schema_id": "oneOf_8_0"
},
{
"description": "extra property invalid (strict)",
"data": {
"foo": 1,
"bar": 2,
"extra": 3
},
"valid": false,
"schema_id": "oneOf_8_0"
}
]
},
{
"description": "oneOf with required (extensible)",
"database": {
"schemas": [
{
"type": "object",
"extensible": true,
"oneOf": [
{
"required": [
"foo",
"bar"
]
},
{
"required": [
"foo",
"baz"
]
}
],
"$id": "oneOf_9_0"
}
]
},
"tests": [
{
"description": "both invalid - invalid",
"data": {
"bar": 2
},
"valid": false,
"schema_id": "oneOf_9_0"
},
{
"description": "first valid - valid",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"schema_id": "oneOf_9_0"
},
{
"description": "second valid - valid",
"data": {
"foo": 1,
"baz": 3
},
"valid": true,
"schema_id": "oneOf_9_0"
},
{
"description": "both valid - invalid",
"data": {
"foo": 1,
"bar": 2,
"baz": 3
},
"valid": false,
"schema_id": "oneOf_9_0"
},
{
"description": "extra properties are valid (extensible)",
"data": {
"foo": 1,
"bar": 2,
"extra": "value"
},
"valid": true,
"schema_id": "oneOf_9_0"
}
]
},
{
"description": "oneOf with missing optional property",
"database": {
"schemas": [
{
"oneOf": [
{
"properties": {
"bar": true,
"baz": true
},
"required": [
"bar"
]
},
{
"properties": {
"foo": true
},
"required": [
"foo"
]
}
],
"$id": "oneOf_10_0"
}
]
},
"tests": [
{
"description": "first oneOf valid",
"data": {
"bar": 8
},
"valid": true,
"schema_id": "oneOf_10_0"
},
{
"description": "second oneOf valid",
"data": {
"foo": "foo"
},
"valid": true,
"schema_id": "oneOf_10_0"
},
{
"description": "both oneOf valid",
"data": {
"foo": "foo",
"bar": 8
},
"valid": false,
"schema_id": "oneOf_10_0"
},
{
"description": "neither oneOf valid",
"data": {
"baz": "quux"
},
"valid": false,
"schema_id": "oneOf_10_0"
}
]
},
{
"description": "nested oneOf, to check validation semantics",
"database": {
"schemas": [
{
"oneOf": [
{
"oneOf": [
{
"type": "null"
}
]
}
],
"$id": "oneOf_11_0"
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true,
"schema_id": "oneOf_11_0"
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false,
"schema_id": "oneOf_11_0"
}
]
},
{
"description": "extensible: true allows extra properties in oneOf",
"database": {
"schemas": [
{
"oneOf": [
{
"properties": {
"bar": {
"type": "integer"
}
},
"required": [
"bar"
]
},
{
"properties": {
"foo": {
"type": "string"
}
},
"required": [
"foo"
]
}
],
"extensible": true,
"$id": "oneOf_12_0"
}
]
},
"tests": [
{
"description": "extra property is valid (matches first option)",
"data": {
"bar": 2,
"extra": "prop"
},
"valid": true,
"schema_id": "oneOf_12_0"
}
]
}
]

View File

@ -1,82 +0,0 @@
[
{
"description": "pattern validation",
"database": {
"schemas": [
{
"pattern": "^a*$",
"$id": "pattern_0_0"
}
]
},
"tests": [
{
"description": "a matching pattern is valid",
"data": "aaa",
"valid": true,
"schema_id": "pattern_0_0"
},
{
"description": "a non-matching pattern is invalid",
"data": "abc",
"valid": false,
"schema_id": "pattern_0_0"
},
{
"description": "ignores booleans",
"data": true,
"valid": true,
"schema_id": "pattern_0_0"
},
{
"description": "ignores integers",
"data": 123,
"valid": true,
"schema_id": "pattern_0_0"
},
{
"description": "ignores floats",
"data": 1,
"valid": true,
"schema_id": "pattern_0_0"
},
{
"description": "ignores objects",
"data": {},
"valid": true,
"schema_id": "pattern_0_0"
},
{
"description": "ignores arrays",
"data": [],
"valid": true,
"schema_id": "pattern_0_0"
},
{
"description": "ignores null",
"data": null,
"valid": true,
"schema_id": "pattern_0_0"
}
]
},
{
"description": "pattern is not anchored",
"database": {
"schemas": [
{
"pattern": "a+",
"$id": "pattern_1_0"
}
]
},
"tests": [
{
"description": "matches a substring",
"data": "xxaayy",
"valid": true,
"schema_id": "pattern_1_0"
}
]
}
]

View File

@ -1,321 +0,0 @@
[
{
"description": "patternProperties validates properties matching a regex",
"database": {
"schemas": [
{
"patternProperties": {
"f.*o": {
"type": "integer"
}
},
"items": {},
"$id": "patternProperties_0_0"
}
]
},
"tests": [
{
"description": "a single valid match is valid",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "patternProperties_0_0"
},
{
"description": "multiple valid matches is valid",
"data": {
"foo": 1,
"foooooo": 2
},
"valid": true,
"schema_id": "patternProperties_0_0"
},
{
"description": "a single invalid match is invalid",
"data": {
"foo": "bar",
"fooooo": 2
},
"valid": false,
"schema_id": "patternProperties_0_0"
},
{
"description": "multiple invalid matches is invalid",
"data": {
"foo": "bar",
"foooooo": "baz"
},
"valid": false,
"schema_id": "patternProperties_0_0"
},
{
"description": "ignores arrays",
"data": [
"foo"
],
"valid": true,
"schema_id": "patternProperties_0_0"
},
{
"description": "ignores strings",
"data": "foo",
"valid": true,
"schema_id": "patternProperties_0_0"
},
{
"description": "ignores other non-objects",
"data": 12,
"valid": true,
"schema_id": "patternProperties_0_0"
},
{
"description": "extra property not matching pattern is INVALID (strict by default)",
"data": {
"foo": 1,
"extra": 2
},
"valid": false,
"schema_id": "patternProperties_0_0"
}
]
},
{
"description": "multiple simultaneous patternProperties are validated",
"database": {
"schemas": [
{
"patternProperties": {
"a*": {
"type": "integer"
},
"aaa*": {
"maximum": 20
}
},
"$id": "patternProperties_1_0"
}
]
},
"tests": [
{
"description": "a single valid match is valid",
"data": {
"a": 21
},
"valid": true,
"schema_id": "patternProperties_1_0"
},
{
"description": "a simultaneous match is valid",
"data": {
"aaaa": 18
},
"valid": true,
"schema_id": "patternProperties_1_0"
},
{
"description": "multiple matches is valid",
"data": {
"a": 21,
"aaaa": 18
},
"valid": true,
"schema_id": "patternProperties_1_0"
},
{
"description": "an invalid due to one is invalid",
"data": {
"a": "bar"
},
"valid": false,
"schema_id": "patternProperties_1_0"
},
{
"description": "an invalid due to the other is invalid",
"data": {
"aaaa": 31
},
"valid": false,
"schema_id": "patternProperties_1_0"
},
{
"description": "an invalid due to both is invalid",
"data": {
"aaa": "foo",
"aaaa": 31
},
"valid": false,
"schema_id": "patternProperties_1_0"
}
]
},
{
"description": "regexes are not anchored by default and are case sensitive",
"database": {
"schemas": [
{
"patternProperties": {
"[0-9]{2,}": {
"type": "boolean"
},
"X_": {
"type": "string"
}
},
"extensible": true,
"$id": "patternProperties_2_0"
}
]
},
"tests": [
{
"description": "non recognized members are ignored",
"data": {
"answer 1": "42"
},
"valid": true,
"schema_id": "patternProperties_2_0"
},
{
"description": "recognized members are accounted for",
"data": {
"a31b": null
},
"valid": false,
"schema_id": "patternProperties_2_0"
},
{
"description": "regexes are case sensitive",
"data": {
"a_x_3": 3
},
"valid": true,
"schema_id": "patternProperties_2_0"
},
{
"description": "regexes are case sensitive, 2",
"data": {
"a_X_3": 3
},
"valid": false,
"schema_id": "patternProperties_2_0"
}
]
},
{
"description": "patternProperties with boolean schemas",
"database": {
"schemas": [
{
"patternProperties": {
"f.*": true,
"b.*": false
},
"$id": "patternProperties_3_0"
}
]
},
"tests": [
{
"description": "object with property matching schema true is valid",
"data": {
"foo": 1
},
"valid": true,
"schema_id": "patternProperties_3_0"
},
{
"description": "object with property matching schema false is invalid",
"data": {
"bar": 2
},
"valid": false,
"schema_id": "patternProperties_3_0"
},
{
"description": "object with both properties is invalid",
"data": {
"foo": 1,
"bar": 2
},
"valid": false,
"schema_id": "patternProperties_3_0"
},
{
"description": "object with a property matching both true and false is invalid",
"data": {
"foobar": 1
},
"valid": false,
"schema_id": "patternProperties_3_0"
},
{
"description": "empty object is valid",
"data": {},
"valid": true,
"schema_id": "patternProperties_3_0"
}
]
},
{
"description": "patternProperties with null valued instance properties",
"database": {
"schemas": [
{
"patternProperties": {
"^.*bar$": {
"type": "null"
}
},
"$id": "patternProperties_4_0"
}
]
},
"tests": [
{
"description": "allows null values",
"data": {
"foobar": null
},
"valid": true,
"schema_id": "patternProperties_4_0"
}
]
},
{
"description": "extensible: true allows extra properties NOT matching pattern",
"database": {
"schemas": [
{
"patternProperties": {
"f.*o": {
"type": "integer"
}
},
"extensible": true,
"$id": "patternProperties_5_0"
}
]
},
"tests": [
{
"description": "extra property not matching pattern is valid",
"data": {
"bar": 1
},
"valid": true,
"schema_id": "patternProperties_5_0"
},
{
"description": "property matching pattern MUST still be valid",
"data": {
"foo": "invalid string"
},
"valid": false,
"schema_id": "patternProperties_5_0"
}
]
}
]

View File

@ -1,193 +0,0 @@
[
{
"description": "a schema given for prefixItems",
"database": {
"schemas": [
{
"prefixItems": [
{
"type": "integer"
},
{
"type": "string"
}
],
"$id": "prefixItems_0_0"
}
]
},
"tests": [
{
"description": "correct types",
"data": [
1,
"foo"
],
"valid": true,
"schema_id": "prefixItems_0_0"
},
{
"description": "wrong types",
"data": [
"foo",
1
],
"valid": false,
"schema_id": "prefixItems_0_0"
},
{
"description": "incomplete array of items",
"data": [
1
],
"valid": true,
"schema_id": "prefixItems_0_0"
},
{
"description": "array with additional items (invalid due to strictness)",
"data": [
1,
"foo",
true
],
"valid": false,
"schema_id": "prefixItems_0_0"
},
{
"description": "empty array",
"data": [],
"valid": true,
"schema_id": "prefixItems_0_0"
},
{
"description": "JavaScript pseudo-array is valid (invalid due to strict object validation)",
"data": {
"0": "invalid",
"1": "valid",
"length": 2
},
"valid": false,
"schema_id": "prefixItems_0_0"
}
]
},
{
"description": "prefixItems with boolean schemas",
"database": {
"schemas": [
{
"prefixItems": [
true,
false
],
"$id": "prefixItems_1_0"
}
]
},
"tests": [
{
"description": "array with one item is valid",
"data": [
1
],
"valid": true,
"schema_id": "prefixItems_1_0"
},
{
"description": "array with two items is invalid",
"data": [
1,
"foo"
],
"valid": false,
"schema_id": "prefixItems_1_0"
},
{
"description": "empty array is valid",
"data": [],
"valid": true,
"schema_id": "prefixItems_1_0"
}
]
},
{
"description": "additional items are allowed by default",
"database": {
"schemas": [
{
"prefixItems": [
{
"type": "integer"
}
],
"extensible": true,
"$id": "prefixItems_2_0"
}
]
},
"tests": [
{
"description": "only the first item is validated",
"data": [
1,
"foo",
false
],
"valid": true,
"schema_id": "prefixItems_2_0"
}
]
},
{
"description": "prefixItems with null instance elements",
"database": {
"schemas": [
{
"prefixItems": [
{
"type": "null"
}
],
"$id": "prefixItems_3_0"
}
]
},
"tests": [
{
"description": "allows null elements",
"data": [
null
],
"valid": true,
"schema_id": "prefixItems_3_0"
}
]
},
{
"description": "extensible: true allows extra items with prefixItems",
"database": {
"schemas": [
{
"prefixItems": [
{
"type": "integer"
}
],
"extensible": true,
"$id": "prefixItems_4_0"
}
]
},
"tests": [
{
"description": "extra item is valid",
"data": [
1,
"foo"
],
"valid": true,
"schema_id": "prefixItems_4_0"
}
]
}
]

Some files were not shown because too many files have changed in this diff Show More