validator refactor progress
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -817,6 +817,7 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"fluent-uri",
|
"fluent-uri",
|
||||||
"idna",
|
"idna",
|
||||||
|
"indexmap",
|
||||||
"json-pointer",
|
"json-pointer",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|||||||
@ -19,6 +19,7 @@ percent-encoding = "2.3.2"
|
|||||||
uuid = { version = "1.20.0", features = ["v4", "serde"] }
|
uuid = { version = "1.20.0", features = ["v4", "serde"] }
|
||||||
chrono = { version = "0.4.43", features = ["serde"] }
|
chrono = { version = "0.4.43", features = ["serde"] }
|
||||||
json-pointer = "0.3.4"
|
json-pointer = "0.3.4"
|
||||||
|
indexmap = { version = "2.13.0", features = ["serde"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pgrx-tests = "0.16.1"
|
pgrx-tests = "0.16.1"
|
||||||
@ -51,4 +52,4 @@ lto = "fat"
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[package.metadata.jspg]
|
[package.metadata.jspg]
|
||||||
target_draft = "draft2020-12"
|
target_draft = "draft2020-12"
|
||||||
|
|||||||
25
GEMINI.md
25
GEMINI.md
@ -69,19 +69,26 @@ Returns a debug dump of the currently cached schemas (for development/debugging)
|
|||||||
|
|
||||||
JSPG implements specific extensions to the Draft 2020-12 standard to support the Punc architecture's object-oriented needs.
|
JSPG implements specific extensions to the Draft 2020-12 standard to support the Punc architecture's object-oriented needs.
|
||||||
|
|
||||||
### 1. Implicit Keyword Shadowing
|
### 1. The Unified Semantic Graph & Native Inheritance
|
||||||
Standard JSON Schema composition (`allOf`) is additive (Intersection), meaning constraints can only be tightened, not replaced. However, JSPG treats `$ref` differently when it appears alongside other properties to support object-oriented inheritance.
|
JSPG goes beyond Draft 2020-12 to natively understand Object-Oriented inheritance and polymorphism. During the `cache_json_schemas()` phase, JSPG builds a single Directed Acyclic Graph (DAG) using **only** the `$ref` keyword. Every schema that uses `$ref` establishes a parent-to-child relationship.
|
||||||
|
|
||||||
* **Inheritance (`$ref` + `properties`)**: When a schema uses `$ref` *and* defines its own properties, JSPG implements **Smart Merge** (or Shadowing). If a property is defined in the current schema, its constraints take precedence over the inherited constraints for that specific keyword.
|
Furthermore, `jspg` knows which schemas belong directly to database tables (Entities) versus which are ad-hoc API shapes.
|
||||||
* *Example*: If `Entity` defines `type: { const: "entity" }` and `Person` (which refs Entity) defines `type: { const: "person" }`, validation passes for "person". The local `const` shadows the inherited `const`.
|
* **Native `type` Discrimination**: For any schema that traces its ancestry back to the base `entity`, JSPG securely and implicitly manages the `type` property. You do **not** need to explicitly override `"type": {"const": "person"}` in entity subclasses. If a schema `$ref`s `organization`, JSPG automatically allows the incoming `type` to be anything in the `organization` family tree (e.g., `person`, `bot`), but rigidly truncates/masks the data structure to the requested `organization` shape.
|
||||||
* *Granularity*: Shadowing is per-keyword. If `Entity` defined `type: { const: "entity", minLength: 5 }`, `Person` would shadow `const` but still inherit `minLength: 5`.
|
* **Ad-Hoc Objects**: If an ad-hoc schema `$ref`s a base object but does not trace back to `entity`, standard JSON Schema rules apply (no magical `type` tracking).
|
||||||
|
|
||||||
* **Composition (`allOf`)**: When using `allOf`, standard intersection rules apply. No shadowing occurs; all constraints from all branches must pass. This is used for mixins or interfaces.
|
> [!NOTE]
|
||||||
|
> **`$ref` never creates a Union.** When you use `$ref`, you are asking for a single, concrete struct/shape. The schema's strict fields will be rigidly enforced, but the `type` property is permitted to match any valid descendant via the native discrimination.
|
||||||
|
|
||||||
### 2. Virtual Family References (`$family`)
|
### 2. Shape Polymorphism & Virtual Unions (`$family`)
|
||||||
To support polymorphic fields (e.g., a field that accepts any "User" type), JSPG generates virtual schemas representing type hierarchies.
|
To support polymorphic API contracts and deeply nested UI Unions without manually writing massive `oneOf` blocks, JSPG provides the `$family` macro. While `$ref` guarantees a single shape, `$family` asks the code generators for a true Polymorphic Union class.
|
||||||
|
|
||||||
* **Mechanism**: When caching types, if a type defines a `hierarchy` (e.g., `["entity", "organization", "person"]`), JSPG generates a virtual `oneOf` family containing refs to all valid descendants. These can be pointed to exclusively by using `{"$family": "organization"}`. Because `$family` is a macro-pointer that swaps in the virtual union, it **must** be used exclusively in its schema object; you cannot define other properties alongside it.
|
When `{"$family": "organization.light"}` is encountered, JSPG:
|
||||||
|
1. Locates the base `organization` node in the Semantic Graph.
|
||||||
|
2. Recursively walks down to find all descendants via `$ref`.
|
||||||
|
3. **Strictly Filters** the descendants using the exact dot-notation suffix requested. It will only include descendants whose `$id` matches the shape modifier (e.g., `person.light`, `user.light`). If `bot` has no `.light` shape defined, it is securely omitted from the union.
|
||||||
|
4. Generates a virtual `oneOf` array containing those precise `$ref`s.
|
||||||
|
|
||||||
|
This cleanly separates **Database Ancestry** (managed entirely and implicitly by `$ref` for single shapes) from **Shape Variations** (managed explicitly by `$family` to build `oneOf` unions).
|
||||||
|
|
||||||
### 3. Strict by Default & Extensibility
|
### 3. Strict by Default & Extensibility
|
||||||
JSPG enforces a "Secure by Default" philosophy. All schemas are treated as if `unevaluatedProperties: false` (and `unevaluatedItems: false`) is set, unless explicitly overridden.
|
JSPG enforces a "Secure by Default" philosophy. All schemas are treated as if `unevaluatedProperties: false` (and `unevaluatedItems: false`) is set, unless explicitly overridden.
|
||||||
|
|||||||
12
src/database/enum.rs
Normal file
12
src/database/enum.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use crate::database::schema::Schema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Enum {
|
||||||
|
pub name: String,
|
||||||
|
pub module: String,
|
||||||
|
pub source: String,
|
||||||
|
pub values: Vec<String>,
|
||||||
|
pub schemas: Vec<Schema>,
|
||||||
|
}
|
||||||
220
src/database/mod.rs
Normal file
220
src/database/mod.rs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
pub mod r#enum;
|
||||||
|
pub mod formats;
|
||||||
|
pub mod page;
|
||||||
|
pub mod punc;
|
||||||
|
pub mod schema;
|
||||||
|
pub mod r#type;
|
||||||
|
|
||||||
|
use crate::database::r#enum::Enum;
|
||||||
|
use crate::database::punc::Punc;
|
||||||
|
use crate::database::schema::Schema;
|
||||||
|
use crate::database::r#type::Type;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub struct Database {
|
||||||
|
pub enums: HashMap<String, Enum>,
|
||||||
|
pub types: HashMap<String, Type>,
|
||||||
|
pub puncs: HashMap<String, Punc>,
|
||||||
|
pub schemas: HashMap<String, Schema>,
|
||||||
|
pub descendants: HashMap<String, Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Database {
|
||||||
|
pub fn new(val: &serde_json::Value) -> Self {
|
||||||
|
let mut db = Self {
|
||||||
|
enums: HashMap::new(),
|
||||||
|
types: HashMap::new(),
|
||||||
|
puncs: HashMap::new(),
|
||||||
|
schemas: HashMap::new(),
|
||||||
|
descendants: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(arr) = val.get("enums").and_then(|v| v.as_array()) {
|
||||||
|
for item in arr {
|
||||||
|
if let Ok(def) = serde_json::from_value::<Enum>(item.clone()) {
|
||||||
|
db.enums.insert(def.name.clone(), def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = val.get("types").and_then(|v| v.as_array()) {
|
||||||
|
for item in arr {
|
||||||
|
if let Ok(def) = serde_json::from_value::<Type>(item.clone()) {
|
||||||
|
db.types.insert(def.name.clone(), def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = val.get("puncs").and_then(|v| v.as_array()) {
|
||||||
|
for item in arr {
|
||||||
|
if let Ok(def) = serde_json::from_value::<Punc>(item.clone()) {
|
||||||
|
db.puncs.insert(def.name.clone(), def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = val.get("schemas").and_then(|v| v.as_array()) {
|
||||||
|
for (i, item) in arr.iter().enumerate() {
|
||||||
|
if let Ok(mut schema) = serde_json::from_value::<Schema>(item.clone()) {
|
||||||
|
let id = schema
|
||||||
|
.obj
|
||||||
|
.id
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| format!("schema_{}", i));
|
||||||
|
schema.obj.id = Some(id.clone());
|
||||||
|
db.schemas.insert(id, schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = db.compile();
|
||||||
|
db
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Organizes the graph of the database, compiling regex, format functions, and pointing schema references.
|
||||||
|
fn compile(&mut self) -> Result<(), String> {
|
||||||
|
self.collect_schemas();
|
||||||
|
|
||||||
|
// 1. Compile regex and formats sequentially
|
||||||
|
for schema in self.schemas.values_mut() {
|
||||||
|
schema.compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Compute the Unified Semantic Graph (descendants)
|
||||||
|
self.collect_descendents();
|
||||||
|
|
||||||
|
// 3. For any schema representing a Postgres table, cache its allowed subclasses
|
||||||
|
self.compile_allowed_types();
|
||||||
|
|
||||||
|
// 4. Finally, securely link all string $refs into memory pointers (Arc)
|
||||||
|
self.compile_pointers();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_schemas(&mut self) {
|
||||||
|
let mut to_insert = Vec::new();
|
||||||
|
for (_, type_def) in &self.types {
|
||||||
|
for schema in &type_def.schemas {
|
||||||
|
if let Some(id) = &schema.obj.id {
|
||||||
|
to_insert.push((id.clone(), schema.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (_, punc_def) in &self.puncs {
|
||||||
|
for schema in &punc_def.schemas {
|
||||||
|
if let Some(id) = &schema.obj.id {
|
||||||
|
to_insert.push((id.clone(), schema.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (_, enum_def) in &self.enums {
|
||||||
|
for schema in &enum_def.schemas {
|
||||||
|
if let Some(id) = &schema.obj.id {
|
||||||
|
to_insert.push((id.clone(), schema.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (id, schema) in to_insert {
|
||||||
|
self.schemas.insert(id, schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_descendents(&mut self) {
|
||||||
|
let mut direct_children: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
|
||||||
|
// First pass: Find all schemas that have a $ref to another schema
|
||||||
|
let schema_ids: Vec<String> = self.schemas.keys().cloned().collect();
|
||||||
|
for id in schema_ids {
|
||||||
|
if let Some(ref_str) = self.schemas.get(&id).and_then(|s| s.obj.ref_string.clone()) {
|
||||||
|
if self.schemas.contains_key(&ref_str) {
|
||||||
|
direct_children.entry(ref_str).or_default().push(id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now compute descendants for all schemas
|
||||||
|
let mut descendants_map: HashMap<String, Vec<String>> = HashMap::new();
|
||||||
|
for key in self.schemas.keys() {
|
||||||
|
let mut descendants = Vec::new();
|
||||||
|
let mut queue = Vec::new();
|
||||||
|
if let Some(children) = direct_children.get(key) {
|
||||||
|
queue.extend(children.iter().cloned());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visited = std::collections::HashSet::new();
|
||||||
|
while let Some(child) = queue.pop() {
|
||||||
|
if visited.insert(child.clone()) {
|
||||||
|
descendants.push(child.clone());
|
||||||
|
if let Some(grandchildren) = direct_children.get(&child) {
|
||||||
|
queue.extend(grandchildren.iter().cloned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descendants_map.insert(key.clone(), descendants);
|
||||||
|
}
|
||||||
|
self.descendants = descendants_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_allowed_types(&mut self) {
|
||||||
|
// 1. Identify which types act as bases (table-backed schemas)
|
||||||
|
let mut entity_bases = HashMap::new();
|
||||||
|
for type_def in self.types.values() {
|
||||||
|
for type_schema in &type_def.schemas {
|
||||||
|
if let Some(id) = &type_schema.obj.id {
|
||||||
|
entity_bases.insert(id.clone(), type_def.name.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Compute compiled_allowed_types for all descendants of entity bases
|
||||||
|
let mut allowed_types_map: HashMap<String, std::collections::HashSet<String>> = HashMap::new();
|
||||||
|
for base_id in entity_bases.keys() {
|
||||||
|
allowed_types_map.insert(
|
||||||
|
base_id.clone(),
|
||||||
|
self
|
||||||
|
.descendants
|
||||||
|
.get(base_id)
|
||||||
|
.unwrap_or(&vec![])
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
if let Some(descendants) = self.descendants.get(base_id) {
|
||||||
|
let set: std::collections::HashSet<String> = descendants.iter().cloned().collect();
|
||||||
|
for desc_id in descendants {
|
||||||
|
allowed_types_map.insert(desc_id.clone(), set.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Inject types into the schemas
|
||||||
|
let schema_ids: Vec<String> = self.schemas.keys().cloned().collect();
|
||||||
|
for id in schema_ids {
|
||||||
|
if let Some(set) = allowed_types_map.get(&id) {
|
||||||
|
if let Some(schema) = self.schemas.get_mut(&id) {
|
||||||
|
schema.obj.compiled_allowed_types = Some(set.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_pointers(&mut self) {
|
||||||
|
let schema_ids: Vec<String> = self.schemas.keys().cloned().collect();
|
||||||
|
for id in schema_ids {
|
||||||
|
let mut compiled_ref = None;
|
||||||
|
|
||||||
|
if let Some(schema) = self.schemas.get(&id) {
|
||||||
|
if let Some(ref_str) = &schema.obj.ref_string {
|
||||||
|
if let Some(target) = self.schemas.get(ref_str) {
|
||||||
|
compiled_ref = Some(std::sync::Arc::new(target.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(schema) = self.schemas.get_mut(&id) {
|
||||||
|
schema.obj.compiled_ref = compiled_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/database/page.rs
Normal file
35
src/database/page.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use indexmap::IndexMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Page {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub path: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub title: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub sidebar: Option<Sidebar>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub actions: Option<IndexMap<String, Action>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Sidebar {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub category: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub priority: Option<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Action {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub punc: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub navigate: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub present: Option<String>,
|
||||||
|
}
|
||||||
20
src/database/punc.rs
Normal file
20
src/database/punc.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use crate::database::page::Page;
|
||||||
|
use crate::database::schema::Schema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Punc {
|
||||||
|
pub id: String,
|
||||||
|
pub r#type: String,
|
||||||
|
pub name: String,
|
||||||
|
pub module: String,
|
||||||
|
pub source: String,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub public: bool,
|
||||||
|
pub form: bool,
|
||||||
|
pub get: Option<String>,
|
||||||
|
pub page: Option<Page>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub schemas: Vec<Schema>,
|
||||||
|
}
|
||||||
15
src/database/relation.rs
Normal file
15
src/database/relation.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Relation {
|
||||||
|
pub id: String,
|
||||||
|
pub constraint_name: String,
|
||||||
|
pub source_type: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub source_columns: Vec<String>,
|
||||||
|
pub destination_type: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub destination_columns: Vec<String>,
|
||||||
|
pub prefix: Option<String>,
|
||||||
|
}
|
||||||
@ -12,12 +12,6 @@ pub struct SchemaObject {
|
|||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
#[serde(rename = "$ref")]
|
#[serde(rename = "$ref")]
|
||||||
pub ref_string: Option<String>,
|
pub ref_string: Option<String>,
|
||||||
#[serde(rename = "$anchor")]
|
|
||||||
pub anchor: Option<String>,
|
|
||||||
#[serde(rename = "$dynamicAnchor")]
|
|
||||||
pub dynamic_anchor: Option<String>,
|
|
||||||
#[serde(rename = "$dynamicRef")]
|
|
||||||
pub dynamic_ref: Option<String>,
|
|
||||||
/*
|
/*
|
||||||
Note: The `Ref` field in the Go struct is a pointer populated by the linker.
|
Note: The `Ref` field in the Go struct is a pointer populated by the linker.
|
||||||
In Rust, we might handle this differently (e.g., separate lookup or Rc/Arc),
|
In Rust, we might handle this differently (e.g., separate lookup or Rc/Arc),
|
||||||
@ -43,12 +37,6 @@ pub struct SchemaObject {
|
|||||||
// dependencies can be schema dependencies or property dependencies
|
// dependencies can be schema dependencies or property dependencies
|
||||||
pub dependencies: Option<BTreeMap<String, Dependency>>,
|
pub dependencies: Option<BTreeMap<String, Dependency>>,
|
||||||
|
|
||||||
// Definitions (for $ref resolution)
|
|
||||||
#[serde(rename = "$defs")]
|
|
||||||
pub defs: Option<BTreeMap<String, Arc<Schema>>>,
|
|
||||||
#[serde(rename = "definitions")]
|
|
||||||
pub definitions: Option<BTreeMap<String, Arc<Schema>>>,
|
|
||||||
|
|
||||||
// Array Keywords
|
// Array Keywords
|
||||||
#[serde(rename = "items")]
|
#[serde(rename = "items")]
|
||||||
pub items: Option<Arc<Schema>>,
|
pub items: Option<Arc<Schema>>,
|
||||||
@ -83,10 +71,6 @@ pub struct SchemaObject {
|
|||||||
pub max_properties: Option<f64>,
|
pub max_properties: Option<f64>,
|
||||||
#[serde(rename = "propertyNames")]
|
#[serde(rename = "propertyNames")]
|
||||||
pub property_names: Option<Arc<Schema>>,
|
pub property_names: Option<Arc<Schema>>,
|
||||||
#[serde(rename = "dependentRequired")]
|
|
||||||
pub dependent_required: Option<BTreeMap<String, Vec<String>>>,
|
|
||||||
#[serde(rename = "dependentSchemas")]
|
|
||||||
pub dependent_schemas: Option<BTreeMap<String, Arc<Schema>>>,
|
|
||||||
|
|
||||||
// Numeric Validation
|
// Numeric Validation
|
||||||
pub format: Option<String>,
|
pub format: Option<String>,
|
||||||
@ -138,15 +122,42 @@ pub struct SchemaObject {
|
|||||||
|
|
||||||
// Compiled Fields (Hidden from JSON/Serde)
|
// Compiled Fields (Hidden from JSON/Serde)
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub compiled_format: Option<crate::validator::compiler::CompiledFormat>,
|
pub compiled_ref: Option<Arc<Schema>>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub compiled_pattern: Option<crate::validator::compiler::CompiledRegex>,
|
pub compiled_allowed_types: Option<std::collections::HashSet<String>>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub compiled_pattern_properties: Option<Vec<(crate::validator::compiler::CompiledRegex, Arc<Schema>)>>,
|
pub compiled_format: Option<CompiledFormat>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub compiled_registry: Option<Arc<crate::validator::registry::Registry>>,
|
pub compiled_pattern: Option<CompiledRegex>,
|
||||||
|
#[serde(skip)]
|
||||||
|
pub compiled_pattern_properties: Option<Vec<(CompiledRegex, Arc<Schema>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ResolvedRef<'a> {
|
||||||
|
Local(&'a Schema),
|
||||||
|
Global(&'a Schema, &'a Schema),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a compiled format validator
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum CompiledFormat {
|
||||||
|
Func(fn(&serde_json::Value) -> Result<(), Box<dyn std::error::Error + Send + Sync>>),
|
||||||
|
Regex(regex::Regex),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for CompiledFormat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
CompiledFormat::Func(_) => write!(f, "CompiledFormat::Func(...)"),
|
||||||
|
CompiledFormat::Regex(r) => write!(f, "CompiledFormat::Regex({:?})", r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper for compiled regex patterns
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CompiledRegex(pub regex::Regex);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Schema {
|
pub struct Schema {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@ -176,6 +187,129 @@ impl std::ops::DerefMut for Schema {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Schema {
|
||||||
|
pub fn resolve_ref(&self, _ref_string: &str) -> Option<&Arc<Schema>> {
|
||||||
|
// This is vestigial for now. References are global pointers. We will remove this shortly.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(&mut self) {
|
||||||
|
if let Some(format_str) = &self.obj.format {
|
||||||
|
if let Some(fmt) = crate::database::formats::FORMATS.get(format_str.as_str()) {
|
||||||
|
self.obj.compiled_format = Some(crate::database::schema::CompiledFormat::Func(fmt.func));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pattern_str) = &self.obj.pattern {
|
||||||
|
if let Ok(re) = regex::Regex::new(pattern_str) {
|
||||||
|
self.obj.compiled_pattern = Some(crate::database::schema::CompiledRegex(re));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pattern_props) = &self.obj.pattern_properties {
|
||||||
|
let mut compiled = Vec::new();
|
||||||
|
for (k, v) in pattern_props {
|
||||||
|
if let Ok(re) = regex::Regex::new(k) {
|
||||||
|
compiled.push((crate::database::schema::CompiledRegex(re), v.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !compiled.is_empty() {
|
||||||
|
self.obj.compiled_pattern_properties = Some(compiled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crawl children recursively to compile their internals
|
||||||
|
if let Some(props) = &mut self.obj.properties {
|
||||||
|
for (_, v) in props {
|
||||||
|
// Safe deep mutation workaround without unsafe Arc unwrap
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = &mut self.obj.prefix_items {
|
||||||
|
for v in arr.iter_mut() {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = &mut self.obj.all_of {
|
||||||
|
for v in arr.iter_mut() {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = &mut self.obj.any_of {
|
||||||
|
for v in arr.iter_mut() {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = &mut self.obj.one_of {
|
||||||
|
for v in arr.iter_mut() {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.additional_properties {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.items {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.contains {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.property_names {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.not {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.if_ {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.then_ {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = &mut self.obj.else_ {
|
||||||
|
let mut inner = (**v).clone();
|
||||||
|
inner.compile();
|
||||||
|
*v = Arc::new(inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Schema {
|
impl<'de> Deserialize<'de> for Schema {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
35
src/database/type.rs
Normal file
35
src/database/type.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::database::schema::Schema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub struct Type {
|
||||||
|
pub id: String,
|
||||||
|
pub r#type: String,
|
||||||
|
pub name: String,
|
||||||
|
pub module: String,
|
||||||
|
pub source: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub historical: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub sensitive: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub ownable: bool,
|
||||||
|
pub longevity: Option<i32>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub hierarchy: Vec<String>,
|
||||||
|
pub relationship: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub fields: Vec<String>,
|
||||||
|
pub grouped_fields: Option<Value>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub lookup_fields: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub null_fields: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub default_fields: Vec<String>,
|
||||||
|
pub field_types: Option<Value>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub schemas: Vec<Schema>,
|
||||||
|
}
|
||||||
29
src/jspg.rs
Normal file
29
src/jspg.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use crate::database::Database;
|
||||||
|
use crate::merger::Merger;
|
||||||
|
use crate::queryer::Queryer;
|
||||||
|
use crate::validator::Validator;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub struct Jspg {
|
||||||
|
pub database: Arc<Database>,
|
||||||
|
pub validator: Validator,
|
||||||
|
pub queryer: Queryer,
|
||||||
|
pub merger: Merger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Jspg {
|
||||||
|
pub fn new(database_val: &serde_json::Value) -> Self {
|
||||||
|
let database_instance = Database::new(database_val);
|
||||||
|
let database = Arc::new(database_instance);
|
||||||
|
let validator = Validator::new(std::sync::Arc::new(database.schemas.clone()));
|
||||||
|
let queryer = Queryer::new();
|
||||||
|
let merger = Merger::new();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
database,
|
||||||
|
validator,
|
||||||
|
queryer,
|
||||||
|
merger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/lib.rs
105
src/lib.rs
@ -2,7 +2,11 @@ use pgrx::*;
|
|||||||
|
|
||||||
pg_module_magic!();
|
pg_module_magic!();
|
||||||
|
|
||||||
|
pub mod database;
|
||||||
pub mod drop;
|
pub mod drop;
|
||||||
|
pub mod jspg;
|
||||||
|
pub mod merger;
|
||||||
|
pub mod queryer;
|
||||||
pub mod validator;
|
pub mod validator;
|
||||||
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
@ -12,100 +16,38 @@ lazy_static::lazy_static! {
|
|||||||
// Global Atomic Swap Container:
|
// Global Atomic Swap Container:
|
||||||
// - RwLock: To protect the SWAP of the Option.
|
// - RwLock: To protect the SWAP of the Option.
|
||||||
// - Option: Because it starts empty.
|
// - Option: Because it starts empty.
|
||||||
// - Arc: Because multiple running threads might hold the OLD validator while we swap.
|
// - Arc: Because multiple running threads might hold the OLD engine while we swap.
|
||||||
// - Validator: It immutably owns the Registry.
|
// - Jspg: The root semantic engine encapsulating the database metadata, validator, queryer, and merger.
|
||||||
static ref GLOBAL_VALIDATOR: RwLock<Option<Arc<validator::Validator>>> = RwLock::new(None);
|
static ref GLOBAL_JSPG: RwLock<Option<Arc<jspg::Jspg>>> = RwLock::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pg_extern(strict)]
|
#[pg_extern(strict)]
|
||||||
pub fn cache_json_schemas(enums: JsonB, types: JsonB, puncs: JsonB) -> JsonB {
|
pub fn jspg_cache_database(database: JsonB) -> JsonB {
|
||||||
// 1 & 2. Build Registry, Families, and Wrap in Validator all in one shot
|
let new_jspg = crate::jspg::Jspg::new(&database.0);
|
||||||
let new_validator = crate::validator::Validator::from_punc_definition(
|
let new_arc = Arc::new(new_jspg);
|
||||||
Some(&enums.0),
|
|
||||||
Some(&types.0),
|
|
||||||
Some(&puncs.0),
|
|
||||||
);
|
|
||||||
let new_arc = Arc::new(new_validator);
|
|
||||||
|
|
||||||
// 3. ATOMIC SWAP
|
// 3. ATOMIC SWAP
|
||||||
{
|
{
|
||||||
let mut lock = GLOBAL_VALIDATOR.write().unwrap();
|
let mut lock = GLOBAL_JSPG.write().unwrap();
|
||||||
*lock = Some(new_arc);
|
*lock = Some(new_arc);
|
||||||
}
|
}
|
||||||
|
|
||||||
let drop = crate::drop::Drop::success();
|
let drop = crate::drop::Drop::success();
|
||||||
JsonB(serde_json::to_value(drop).unwrap())
|
JsonB(serde_json::to_value(drop).unwrap())
|
||||||
}
|
}
|
||||||
|
// `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)]
|
|
||||||
pub fn mask_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
|
||||||
// 1. Acquire Snapshot
|
|
||||||
let validator_arc = {
|
|
||||||
let lock = GLOBAL_VALIDATOR.read().unwrap();
|
|
||||||
lock.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. Validate (Lock-Free)
|
|
||||||
if let Some(validator) = validator_arc {
|
|
||||||
// We need a mutable copy of the value to mask it
|
|
||||||
let mut mutable_instance = instance.0.clone();
|
|
||||||
|
|
||||||
match validator.mask(schema_id, &mut mutable_instance) {
|
|
||||||
Ok(result) => {
|
|
||||||
// If valid, return the MASKED instance
|
|
||||||
if result.is_valid() {
|
|
||||||
let drop = crate::drop::Drop::success_with_val(mutable_instance);
|
|
||||||
JsonB(serde_json::to_value(drop).unwrap())
|
|
||||||
} else {
|
|
||||||
// If invalid, return errors (Schema Validation Errors)
|
|
||||||
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) => {
|
|
||||||
// Schema Not Found or other fatal error
|
|
||||||
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: "JSON Schemas have not been cached yet. Run cache_json_schemas()".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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_extern(strict, parallel_safe)]
|
#[pg_extern(strict, parallel_safe)]
|
||||||
pub fn validate_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
pub fn validate_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
||||||
// 1. Acquire Snapshot
|
// 1. Acquire Snapshot
|
||||||
let validator_arc = {
|
let jspg_arc = {
|
||||||
let lock = GLOBAL_VALIDATOR.read().unwrap();
|
let lock = GLOBAL_JSPG.read().unwrap();
|
||||||
lock.clone()
|
lock.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2. Validate (Lock-Free)
|
// 2. Validate (Lock-Free)
|
||||||
if let Some(validator) = validator_arc {
|
if let Some(engine) = jspg_arc {
|
||||||
match validator.validate(schema_id, &instance.0) {
|
match engine.validator.validate(schema_id, &instance.0) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
if result.is_valid() {
|
if result.is_valid() {
|
||||||
let drop = crate::drop::Drop::success();
|
let drop = crate::drop::Drop::success();
|
||||||
@ -137,7 +79,7 @@ pub fn validate_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
|||||||
} else {
|
} else {
|
||||||
let error = crate::drop::Error {
|
let error = crate::drop::Error {
|
||||||
code: "VALIDATOR_NOT_INITIALIZED".to_string(),
|
code: "VALIDATOR_NOT_INITIALIZED".to_string(),
|
||||||
message: "JSON Schemas have not been cached yet. Run cache_json_schemas()".to_string(),
|
message: "The JSPG database has not been cached yet. Run jspg_cache_database()".to_string(),
|
||||||
details: crate::drop::ErrorDetails {
|
details: crate::drop::ErrorDetails {
|
||||||
path: "".to_string(),
|
path: "".to_string(),
|
||||||
},
|
},
|
||||||
@ -149,8 +91,11 @@ pub fn validate_json_schema(schema_id: &str, instance: JsonB) -> JsonB {
|
|||||||
|
|
||||||
#[pg_extern(strict, parallel_safe)]
|
#[pg_extern(strict, parallel_safe)]
|
||||||
pub fn json_schema_cached(schema_id: &str) -> bool {
|
pub fn json_schema_cached(schema_id: &str) -> bool {
|
||||||
if let Some(validator) = GLOBAL_VALIDATOR.read().unwrap().as_ref() {
|
if let Some(engine) = GLOBAL_JSPG.read().unwrap().as_ref() {
|
||||||
match validator.validate(schema_id, &serde_json::Value::Null) {
|
match engine
|
||||||
|
.validator
|
||||||
|
.validate(schema_id, &serde_json::Value::Null)
|
||||||
|
{
|
||||||
Err(e) if e.code == "SCHEMA_NOT_FOUND" => false,
|
Err(e) if e.code == "SCHEMA_NOT_FOUND" => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
@ -161,7 +106,7 @@ pub fn json_schema_cached(schema_id: &str) -> bool {
|
|||||||
|
|
||||||
#[pg_extern(strict)]
|
#[pg_extern(strict)]
|
||||||
pub fn clear_json_schemas() -> JsonB {
|
pub fn clear_json_schemas() -> JsonB {
|
||||||
let mut lock = GLOBAL_VALIDATOR.write().unwrap();
|
let mut lock = GLOBAL_JSPG.write().unwrap();
|
||||||
*lock = None;
|
*lock = None;
|
||||||
let drop = crate::drop::Drop::success();
|
let drop = crate::drop::Drop::success();
|
||||||
JsonB(serde_json::to_value(drop).unwrap())
|
JsonB(serde_json::to_value(drop).unwrap())
|
||||||
@ -169,8 +114,8 @@ pub fn clear_json_schemas() -> JsonB {
|
|||||||
|
|
||||||
#[pg_extern(strict, parallel_safe)]
|
#[pg_extern(strict, parallel_safe)]
|
||||||
pub fn show_json_schemas() -> JsonB {
|
pub fn show_json_schemas() -> JsonB {
|
||||||
if let Some(validator) = GLOBAL_VALIDATOR.read().unwrap().as_ref() {
|
if let Some(engine) = GLOBAL_JSPG.read().unwrap().as_ref() {
|
||||||
let mut keys = validator.get_schema_ids();
|
let mut keys = engine.validator.get_schema_ids();
|
||||||
keys.sort();
|
keys.sort();
|
||||||
let drop = crate::drop::Drop::success_with_val(json!(keys));
|
let drop = crate::drop::Drop::success_with_val(json!(keys));
|
||||||
JsonB(serde_json::to_value(drop).unwrap())
|
JsonB(serde_json::to_value(drop).unwrap())
|
||||||
|
|||||||
9
src/merger/mod.rs
Normal file
9
src/merger/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub struct Merger {
|
||||||
|
// To be implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Merger {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/queryer/mod.rs
Normal file
9
src/queryer/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub struct Queryer {
|
||||||
|
// To be implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Queryer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,28 +1,4 @@
|
|||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_anchor_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_anchor_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_anchor_2() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 2).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_anchor_3() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 3).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
#[pg_test]
|
||||||
fn test_content_0() {
|
fn test_content_0() {
|
||||||
let path = format!("{}/tests/fixtures/content.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/content.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -107,54 +83,6 @@ fn test_min_items_2() {
|
|||||||
crate::validator::util::run_test_file_at_index(&path, 2).unwrap();
|
crate::validator::util::run_test_file_at_index(&path, 2).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_2() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 2).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_3() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 3).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_4() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 4).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_5() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 5).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_6() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 6).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_puncs_7() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 7).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
#[pg_test]
|
||||||
fn test_additional_properties_0() {
|
fn test_additional_properties_0() {
|
||||||
let path = format!("{}/tests/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -347,6 +275,18 @@ fn test_any_of_9() {
|
|||||||
crate::validator::util::run_test_file_at_index(&path, 9).unwrap();
|
crate::validator::util::run_test_file_at_index(&path, 9).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_families_0() {
|
||||||
|
let path = format!("{}/tests/fixtures/families.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_families_1() {
|
||||||
|
let path = format!("{}/tests/fixtures/families.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[pg_test]
|
#[pg_test]
|
||||||
fn test_property_names_0() {
|
fn test_property_names_0() {
|
||||||
let path = format!("{}/tests/fixtures/propertyNames.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/propertyNames.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -389,18 +329,6 @@ fn test_property_names_6() {
|
|||||||
crate::validator::util::run_test_file_at_index(&path, 6).unwrap();
|
crate::validator::util::run_test_file_at_index(&path, 6).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_boolean_schema_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/boolean_schema.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_boolean_schema_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/boolean_schema.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
#[pg_test]
|
||||||
fn test_not_0() {
|
fn test_not_0() {
|
||||||
let path = format!("{}/tests/fixtures/not.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/not.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -569,6 +497,30 @@ fn test_items_15() {
|
|||||||
crate::validator::util::run_test_file_at_index(&path, 15).unwrap();
|
crate::validator::util::run_test_file_at_index(&path, 15).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_typed_refs_0() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_typed_refs_1() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_typed_refs_2() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 2).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_typed_refs_3() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 3).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[pg_test]
|
#[pg_test]
|
||||||
fn test_enum_0() {
|
fn test_enum_0() {
|
||||||
let path = format!("{}/tests/fixtures/enum.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/enum.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -1013,6 +965,18 @@ fn test_one_of_12() {
|
|||||||
crate::validator::util::run_test_file_at_index(&path, 12).unwrap();
|
crate::validator::util::run_test_file_at_index(&path, 12).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_boolean_schema_0() {
|
||||||
|
let path = format!("{}/tests/fixtures/booleanSchema.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pg_test]
|
||||||
|
fn test_boolean_schema_1() {
|
||||||
|
let path = format!("{}/tests/fixtures/booleanSchema.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
crate::validator::util::run_test_file_at_index(&path, 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[pg_test]
|
#[pg_test]
|
||||||
fn test_if_then_else_0() {
|
fn test_if_then_else_0() {
|
||||||
let path = format!("{}/tests/fixtures/if-then-else.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/if-then-else.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -1960,129 +1924,3 @@ fn test_contains_8() {
|
|||||||
let path = format!("{}/tests/fixtures/contains.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/contains.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
crate::validator::util::run_test_file_at_index(&path, 8).unwrap();
|
crate::validator::util::run_test_file_at_index(&path, 8).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_2() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 2).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_3() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 3).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_4() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 4).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_5() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 5).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_6() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 6).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_7() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 7).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_8() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 8).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_9() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 9).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_10() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 10).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_11() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 11).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_12() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 12).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_13() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 13).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_14() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 14).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_15() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 15).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_16() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 16).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_17() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 17).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_18() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 18).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_19() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 19).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pg_test]
|
|
||||||
fn test_dynamic_ref_20() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::validator::util::run_test_file_at_index(&path, 20).unwrap();
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,394 +0,0 @@
|
|||||||
use crate::validator::schema::Schema;
|
|
||||||
use regex::Regex;
|
|
||||||
use serde_json::Value;
|
|
||||||
// use std::collections::HashMap;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/// Represents a compiled format validator
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum CompiledFormat {
|
|
||||||
/// A simple function pointer validator
|
|
||||||
Func(fn(&Value) -> Result<(), Box<dyn Error + Send + Sync>>),
|
|
||||||
/// A regex-based validator
|
|
||||||
Regex(Regex),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A wrapper for compiled regex patterns
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct CompiledRegex(pub Regex);
|
|
||||||
|
|
||||||
/// The Compiler is responsible for pre-calculating high-cost schema operations
|
|
||||||
pub struct Compiler;
|
|
||||||
|
|
||||||
impl Compiler {
|
|
||||||
/// Internal: Compiles formats and regexes in-place
|
|
||||||
fn compile_formats_and_regexes(schema: &mut Schema) {
|
|
||||||
// 1. Compile Format
|
|
||||||
if let Some(format_str) = &schema.format {
|
|
||||||
if let Some(fmt) = crate::validator::formats::FORMATS.get(format_str.as_str()) {
|
|
||||||
schema.compiled_format = Some(CompiledFormat::Func(fmt.func));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Compile Pattern (regex)
|
|
||||||
if let Some(pattern_str) = &schema.pattern {
|
|
||||||
if let Ok(re) = Regex::new(pattern_str) {
|
|
||||||
schema.compiled_pattern = Some(CompiledRegex(re));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.5 Compile Pattern Properties
|
|
||||||
if let Some(pp) = &schema.pattern_properties {
|
|
||||||
let mut compiled_pp = Vec::new();
|
|
||||||
for (pattern, sub_schema) in pp {
|
|
||||||
if let Ok(re) = Regex::new(pattern) {
|
|
||||||
compiled_pp.push((CompiledRegex(re), sub_schema.clone()));
|
|
||||||
} else {
|
|
||||||
eprintln!(
|
|
||||||
"Invalid patternProperty regex in schema (compile time): {}",
|
|
||||||
pattern
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !compiled_pp.is_empty() {
|
|
||||||
schema.compiled_pattern_properties = Some(compiled_pp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Recurse
|
|
||||||
Self::compile_recursive(schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn normalize_dependencies(schema: &mut Schema) {
|
|
||||||
if let Some(deps) = schema.dependencies.take() {
|
|
||||||
for (key, dep) in deps {
|
|
||||||
match dep {
|
|
||||||
crate::validator::schema::Dependency::Props(props) => {
|
|
||||||
schema
|
|
||||||
.dependent_required
|
|
||||||
.get_or_insert_with(std::collections::BTreeMap::new)
|
|
||||||
.insert(key, props);
|
|
||||||
}
|
|
||||||
crate::validator::schema::Dependency::Schema(sub_schema) => {
|
|
||||||
schema
|
|
||||||
.dependent_schemas
|
|
||||||
.get_or_insert_with(std::collections::BTreeMap::new)
|
|
||||||
.insert(key, sub_schema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_recursive(schema: &mut Schema) {
|
|
||||||
Self::normalize_dependencies(schema);
|
|
||||||
|
|
||||||
// Compile self
|
|
||||||
if let Some(format_str) = &schema.format {
|
|
||||||
if let Some(fmt) = crate::validator::formats::FORMATS.get(format_str.as_str()) {
|
|
||||||
schema.compiled_format = Some(CompiledFormat::Func(fmt.func));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(pattern_str) = &schema.pattern {
|
|
||||||
if let Ok(re) = Regex::new(pattern_str) {
|
|
||||||
schema.compiled_pattern = Some(CompiledRegex(re));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recurse
|
|
||||||
|
|
||||||
if let Some(defs) = &mut schema.definitions {
|
|
||||||
for s in defs.values_mut() {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(defs) = &mut schema.defs {
|
|
||||||
for s in defs.values_mut() {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(props) = &mut schema.properties {
|
|
||||||
for s in props.values_mut() {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(add_props) = &mut schema.additional_properties {
|
|
||||||
Self::compile_recursive(Arc::make_mut(add_props));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... Recurse logic ...
|
|
||||||
if let Some(items) = &mut schema.items {
|
|
||||||
Self::compile_recursive(Arc::make_mut(items));
|
|
||||||
}
|
|
||||||
if let Some(prefix_items) = &mut schema.prefix_items {
|
|
||||||
for s in prefix_items {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(not) = &mut schema.not {
|
|
||||||
Self::compile_recursive(Arc::make_mut(not));
|
|
||||||
}
|
|
||||||
if let Some(all_of) = &mut schema.all_of {
|
|
||||||
for s in all_of {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(any_of) = &mut schema.any_of {
|
|
||||||
for s in any_of {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(one_of) = &mut schema.one_of {
|
|
||||||
for s in one_of {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(s) = &mut schema.if_ {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
if let Some(s) = &mut schema.then_ {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
if let Some(s) = &mut schema.else_ {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ds) = &mut schema.dependent_schemas {
|
|
||||||
for s in ds.values_mut() {
|
|
||||||
Self::compile_recursive(Arc::make_mut(s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(pn) = &mut schema.property_names {
|
|
||||||
Self::compile_recursive(Arc::make_mut(pn));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Recursively traverses the schema tree to build the local registry index.
|
|
||||||
fn compile_index(
|
|
||||||
schema: &Arc<Schema>,
|
|
||||||
registry: &mut crate::validator::registry::Registry,
|
|
||||||
parent_base: Option<String>,
|
|
||||||
pointer: json_pointer::JsonPointer<String, Vec<String>>,
|
|
||||||
) {
|
|
||||||
// 1. Index using Parent Base (Path from Parent)
|
|
||||||
if let Some(base) = &parent_base {
|
|
||||||
// We use the pointer's string representation (e.g., "/definitions/foo")
|
|
||||||
// and append it to the base.
|
|
||||||
let fragment = pointer.to_string();
|
|
||||||
let ptr_uri = if fragment.is_empty() {
|
|
||||||
base.clone()
|
|
||||||
} else {
|
|
||||||
format!("{}#{}", base, fragment)
|
|
||||||
};
|
|
||||||
registry.insert(ptr_uri, schema.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Determine Current Scope... (unchanged logic)
|
|
||||||
let mut current_base = parent_base.clone();
|
|
||||||
let mut child_pointer = pointer.clone();
|
|
||||||
|
|
||||||
if let Some(id) = &schema.obj.id {
|
|
||||||
let mut new_base = None;
|
|
||||||
if let Ok(_) = url::Url::parse(id) {
|
|
||||||
new_base = Some(id.clone());
|
|
||||||
} else if let Some(base) = ¤t_base {
|
|
||||||
if let Ok(base_url) = url::Url::parse(base) {
|
|
||||||
if let Ok(joined) = base_url.join(id) {
|
|
||||||
new_base = Some(joined.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
new_base = Some(id.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(base) = new_base {
|
|
||||||
// println!("DEBUG: Compiling index for path: {}", base); // Added println
|
|
||||||
registry.insert(base.clone(), schema.clone());
|
|
||||||
current_base = Some(base);
|
|
||||||
child_pointer = json_pointer::JsonPointer::new(vec![]); // Reset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Index by Anchor
|
|
||||||
if let Some(anchor) = &schema.obj.anchor {
|
|
||||||
if let Some(base) = ¤t_base {
|
|
||||||
let anchor_uri = format!("{}#{}", base, anchor);
|
|
||||||
registry.insert(anchor_uri, schema.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Index by Dynamic Anchor
|
|
||||||
if let Some(d_anchor) = &schema.obj.dynamic_anchor {
|
|
||||||
if let Some(base) = ¤t_base {
|
|
||||||
let anchor_uri = format!("{}#{}", base, d_anchor);
|
|
||||||
registry.insert(anchor_uri, schema.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Recurse (unchanged logic structure, just passing registry)
|
|
||||||
if let Some(defs) = schema.defs.as_ref().or(schema.definitions.as_ref()) {
|
|
||||||
let segment = if schema.defs.is_some() {
|
|
||||||
"$defs"
|
|
||||||
} else {
|
|
||||||
"definitions"
|
|
||||||
};
|
|
||||||
for (key, sub_schema) in defs {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push(segment.to_string());
|
|
||||||
let decoded_key = percent_encoding::percent_decode_str(key).decode_utf8_lossy();
|
|
||||||
sub.push(decoded_key.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(props) = &schema.properties {
|
|
||||||
for (key, sub_schema) in props {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("properties".to_string());
|
|
||||||
sub.push(key.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(items) = &schema.items {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("items".to_string());
|
|
||||||
Self::compile_index(items, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(prefix_items) = &schema.prefix_items {
|
|
||||||
for (i, sub_schema) in prefix_items.iter().enumerate() {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("prefixItems".to_string());
|
|
||||||
sub.push(i.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(all_of) = &schema.all_of {
|
|
||||||
for (i, sub_schema) in all_of.iter().enumerate() {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("allOf".to_string());
|
|
||||||
sub.push(i.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(any_of) = &schema.any_of {
|
|
||||||
for (i, sub_schema) in any_of.iter().enumerate() {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("anyOf".to_string());
|
|
||||||
sub.push(i.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(one_of) = &schema.one_of {
|
|
||||||
for (i, sub_schema) in one_of.iter().enumerate() {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("oneOf".to_string());
|
|
||||||
sub.push(i.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(not) = &schema.not {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("not".to_string());
|
|
||||||
Self::compile_index(not, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
if let Some(if_) = &schema.if_ {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("if".to_string());
|
|
||||||
Self::compile_index(if_, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
if let Some(then_) = &schema.then_ {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("then".to_string());
|
|
||||||
Self::compile_index(then_, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
if let Some(else_) = &schema.else_ {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("else".to_string());
|
|
||||||
Self::compile_index(else_, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
if let Some(deps) = &schema.dependent_schemas {
|
|
||||||
for (key, sub_schema) in deps {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("dependentSchemas".to_string());
|
|
||||||
sub.push(key.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(pp) = &schema.pattern_properties {
|
|
||||||
for (key, sub_schema) in pp {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("patternProperties".to_string());
|
|
||||||
sub.push(key.to_string());
|
|
||||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(add_props) = &schema.additional_properties {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("additionalProperties".to_string());
|
|
||||||
Self::compile_index(add_props, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
if let Some(contains) = &schema.contains {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("contains".to_string());
|
|
||||||
Self::compile_index(contains, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
if let Some(property_names) = &schema.property_names {
|
|
||||||
let mut sub = child_pointer.clone();
|
|
||||||
sub.push("propertyNames".to_string());
|
|
||||||
Self::compile_index(property_names, registry, current_base.clone(), sub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile(mut root_schema: Schema, root_id: Option<String>) -> Arc<Schema> {
|
|
||||||
// 1. Compile in-place (formats/regexes/normalization)
|
|
||||||
Self::compile_formats_and_regexes(&mut root_schema);
|
|
||||||
|
|
||||||
// Apply root_id override if schema ID is missing
|
|
||||||
if let Some(rid) = &root_id {
|
|
||||||
if root_schema.obj.id.is_none() {
|
|
||||||
root_schema.obj.id = Some(rid.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Build ID/Pointer Index
|
|
||||||
let mut registry = crate::validator::registry::Registry::new();
|
|
||||||
|
|
||||||
// We need a temporary Arc to satisfy compile_index recursion
|
|
||||||
// But we are modifying root_schema.
|
|
||||||
// This is tricky. compile_index takes &Arc<Schema>.
|
|
||||||
// We should build the index first, THEN attach it.
|
|
||||||
|
|
||||||
let root = Arc::new(root_schema);
|
|
||||||
|
|
||||||
// Default base_uri to ""
|
|
||||||
let base_uri = root_id
|
|
||||||
.clone()
|
|
||||||
.or_else(|| root.obj.id.clone())
|
|
||||||
.or(Some("".to_string()));
|
|
||||||
|
|
||||||
Self::compile_index(
|
|
||||||
&root,
|
|
||||||
&mut registry,
|
|
||||||
base_uri,
|
|
||||||
json_pointer::JsonPointer::new(vec![]),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Also ensure root id is indexed if present
|
|
||||||
if let Some(rid) = root_id {
|
|
||||||
registry.insert(rid, root.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we need to attach this registry to the root schema.
|
|
||||||
// Since root is an Arc, we might need to recreate it if we can't mutate.
|
|
||||||
// Schema struct modifications require &mut.
|
|
||||||
|
|
||||||
let mut final_schema = Arc::try_unwrap(root).unwrap_or_else(|arc| (*arc).clone());
|
|
||||||
final_schema.obj.compiled_registry = Some(Arc::new(registry));
|
|
||||||
|
|
||||||
Arc::new(final_schema)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,44 +1,60 @@
|
|||||||
use crate::validator::schema::Schema;
|
use crate::database::schema::Schema;
|
||||||
use crate::validator::Validator;
|
|
||||||
use crate::validator::error::ValidationError;
|
use crate::validator::error::ValidationError;
|
||||||
use crate::validator::instance::ValidationInstance;
|
|
||||||
use crate::validator::result::ValidationResult;
|
use crate::validator::result::ValidationResult;
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
pub struct ValidationContext<'a, I: ValidationInstance<'a>> {
|
pub struct ValidationContext<'a> {
|
||||||
pub validator: &'a Validator,
|
pub schemas: &'a std::collections::HashMap<String, Schema>,
|
||||||
pub root: &'a Schema,
|
pub root: &'a Schema,
|
||||||
pub schema: &'a Schema,
|
pub schema: &'a Schema,
|
||||||
pub instance: I,
|
pub instance: &'a serde_json::Value,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
pub scope: Vec<String>,
|
|
||||||
pub overrides: HashSet<String>,
|
|
||||||
pub extensible: bool,
|
pub extensible: bool,
|
||||||
pub reporter: bool,
|
pub reporter: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I: ValidationInstance<'a>> ValidationContext<'a, I> {
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub fn resolve_ref(
|
||||||
|
&self,
|
||||||
|
ref_string: &str,
|
||||||
|
) -> Option<(crate::database::schema::ResolvedRef<'a>, String)> {
|
||||||
|
if let Some(local_schema_arc) = self.root.resolve_ref(ref_string) {
|
||||||
|
if ref_string.starts_with('#') {
|
||||||
|
return Some((
|
||||||
|
crate::database::schema::ResolvedRef::Local(local_schema_arc.as_ref()),
|
||||||
|
ref_string.to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will replace all of this with `self.schema.compiled_ref` heavily shortly.
|
||||||
|
// For now, doing a basic map lookup to pass compilation.
|
||||||
|
if let Some(s) = self.schemas.get(ref_string) {
|
||||||
|
return Some((
|
||||||
|
crate::database::schema::ResolvedRef::Global(s, s),
|
||||||
|
ref_string.to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
validator: &'a Validator,
|
schemas: &'a std::collections::HashMap<String, Schema>,
|
||||||
root: &'a Schema,
|
root: &'a Schema,
|
||||||
schema: &'a Schema,
|
schema: &'a Schema,
|
||||||
instance: I,
|
instance: &'a serde_json::Value,
|
||||||
scope: Vec<String>,
|
|
||||||
overrides: HashSet<String>,
|
|
||||||
extensible: bool,
|
extensible: bool,
|
||||||
reporter: bool,
|
reporter: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let effective_extensible = schema.extensible.unwrap_or(extensible);
|
let effective_extensible = schema.extensible.unwrap_or(extensible);
|
||||||
Self {
|
Self {
|
||||||
validator,
|
schemas,
|
||||||
root,
|
root,
|
||||||
schema,
|
schema,
|
||||||
instance,
|
instance,
|
||||||
path: String::new(),
|
path: String::new(),
|
||||||
depth: 0,
|
depth: 0,
|
||||||
scope,
|
|
||||||
overrides,
|
|
||||||
extensible: effective_extensible,
|
extensible: effective_extensible,
|
||||||
reporter,
|
reporter,
|
||||||
}
|
}
|
||||||
@ -47,72 +63,30 @@ impl<'a, I: ValidationInstance<'a>> ValidationContext<'a, I> {
|
|||||||
pub fn derive(
|
pub fn derive(
|
||||||
&self,
|
&self,
|
||||||
schema: &'a Schema,
|
schema: &'a Schema,
|
||||||
instance: I,
|
instance: &'a serde_json::Value,
|
||||||
path: &str,
|
path: &str,
|
||||||
scope: Vec<String>,
|
|
||||||
overrides: HashSet<String>,
|
|
||||||
extensible: bool,
|
extensible: bool,
|
||||||
reporter: bool,
|
reporter: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let effective_extensible = schema.extensible.unwrap_or(extensible);
|
let effective_extensible = schema.extensible.unwrap_or(extensible);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
validator: self.validator,
|
schemas: self.schemas,
|
||||||
root: self.root,
|
root: self.root,
|
||||||
schema,
|
schema,
|
||||||
instance,
|
instance,
|
||||||
path: path.to_string(),
|
path: path.to_string(),
|
||||||
depth: self.depth + 1,
|
depth: self.depth + 1,
|
||||||
scope,
|
|
||||||
overrides,
|
|
||||||
extensible: effective_extensible,
|
extensible: effective_extensible,
|
||||||
reporter,
|
reporter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_for_schema(&self, schema: &'a Schema, reporter: bool) -> Self {
|
pub fn derive_for_schema(&self, schema: &'a Schema, reporter: bool) -> Self {
|
||||||
self.derive(
|
self.derive(schema, self.instance, &self.path, self.extensible, reporter)
|
||||||
schema,
|
|
||||||
self.instance,
|
|
||||||
&self.path,
|
|
||||||
self.scope.clone(),
|
|
||||||
HashSet::new(),
|
|
||||||
self.extensible,
|
|
||||||
reporter,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(&self) -> Result<ValidationResult, ValidationError> {
|
pub fn validate(&self) -> Result<ValidationResult, ValidationError> {
|
||||||
let mut effective_scope = self.scope.clone();
|
|
||||||
|
|
||||||
if let Some(id) = &self.schema.obj.id {
|
|
||||||
let current_base = self.scope.last().map(|s| s.as_str()).unwrap_or("");
|
|
||||||
let mut new_base = id.clone().to_string();
|
|
||||||
if !current_base.is_empty() {
|
|
||||||
if let Ok(base_url) = url::Url::parse(current_base) {
|
|
||||||
if let Ok(joined) = base_url.join(id) {
|
|
||||||
new_base = joined.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
effective_scope.push(new_base);
|
|
||||||
|
|
||||||
let shadow = ValidationContext {
|
|
||||||
validator: self.validator,
|
|
||||||
root: self.root,
|
|
||||||
schema: self.schema,
|
|
||||||
instance: self.instance,
|
|
||||||
path: self.path.clone(),
|
|
||||||
depth: self.depth,
|
|
||||||
scope: effective_scope,
|
|
||||||
overrides: self.overrides.clone(),
|
|
||||||
extensible: self.extensible,
|
|
||||||
reporter: self.reporter,
|
|
||||||
};
|
|
||||||
return shadow.validate_scoped();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.validate_scoped()
|
self.validate_scoped()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,101 +1,29 @@
|
|||||||
pub mod compiler;
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod formats;
|
|
||||||
pub mod instance;
|
|
||||||
pub mod registry;
|
|
||||||
pub mod result;
|
pub mod result;
|
||||||
pub mod rules;
|
pub mod rules;
|
||||||
pub mod schema;
|
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
pub use context::ValidationContext;
|
pub use context::ValidationContext;
|
||||||
pub use error::ValidationError;
|
pub use error::ValidationError;
|
||||||
pub use instance::{MutableInstance, ReadOnlyInstance};
|
|
||||||
pub use result::ValidationResult;
|
pub use result::ValidationResult;
|
||||||
|
|
||||||
use crate::validator::registry::Registry;
|
|
||||||
use crate::validator::schema::Schema;
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub enum ResolvedRef<'a> {
|
|
||||||
Local(&'a Schema),
|
|
||||||
Global(&'a Schema, &'a Schema),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Validator {
|
pub struct Validator {
|
||||||
pub registry: Registry,
|
pub schemas: std::sync::Arc<std::collections::HashMap<String, crate::database::schema::Schema>>,
|
||||||
pub families: std::collections::HashMap<String, Arc<Schema>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Validator {
|
impl Validator {
|
||||||
pub fn from_punc_definition(
|
pub fn new(
|
||||||
enums: Option<&Value>,
|
schemas: std::sync::Arc<std::collections::HashMap<String, crate::database::schema::Schema>>,
|
||||||
types: Option<&Value>,
|
|
||||||
puncs: Option<&Value>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut registry = Registry::new();
|
Self { schemas }
|
||||||
let mut families = std::collections::HashMap::new();
|
|
||||||
|
|
||||||
let mut family_map: std::collections::HashMap<String, std::collections::HashSet<String>> =
|
|
||||||
std::collections::HashMap::new();
|
|
||||||
|
|
||||||
if let Some(Value::Array(arr)) = types {
|
|
||||||
for item in arr {
|
|
||||||
if let Some(name) = item.get("name").and_then(|v| v.as_str()) {
|
|
||||||
if let Some(hierarchy) = item.get("hierarchy").and_then(|v| v.as_array()) {
|
|
||||||
for ancestor in hierarchy {
|
|
||||||
if let Some(anc_str) = ancestor.as_str() {
|
|
||||||
family_map
|
|
||||||
.entry(anc_str.to_string())
|
|
||||||
.or_default()
|
|
||||||
.insert(name.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (family_name, members) in family_map {
|
|
||||||
let object_refs: Vec<Value> = members
|
|
||||||
.iter()
|
|
||||||
.map(|s| serde_json::json!({ "$ref": s }))
|
|
||||||
.collect();
|
|
||||||
let schema_json = serde_json::json!({
|
|
||||||
"oneOf": object_refs
|
|
||||||
});
|
|
||||||
if let Ok(schema) = serde_json::from_value::<Schema>(schema_json) {
|
|
||||||
let compiled = crate::validator::compiler::Compiler::compile(schema, None);
|
|
||||||
families.insert(family_name, compiled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cache_items = |items_val: Option<&Value>| {
|
|
||||||
if let Some(Value::Array(arr)) = items_val {
|
|
||||||
for item in arr {
|
|
||||||
if let Some(Value::Array(schemas)) = item.get("schemas") {
|
|
||||||
for schema_val in schemas {
|
|
||||||
if let Ok(schema) = serde_json::from_value::<Schema>(schema_val.clone()) {
|
|
||||||
registry.add(schema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
cache_items(enums);
|
|
||||||
cache_items(types);
|
|
||||||
cache_items(puncs);
|
|
||||||
|
|
||||||
Self { registry, families }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_schema_ids(&self) -> Vec<String> {
|
pub fn get_schema_ids(&self) -> Vec<String> {
|
||||||
self.registry.schemas.keys().cloned().collect()
|
self.schemas.keys().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_type(t: &str, val: &Value) -> bool {
|
pub fn check_type(t: &str, val: &Value) -> bool {
|
||||||
@ -116,148 +44,14 @@ impl Validator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_ref<'a>(
|
|
||||||
&'a self,
|
|
||||||
root: &'a Schema,
|
|
||||||
ref_string: &str,
|
|
||||||
scope: &str,
|
|
||||||
) -> Option<(ResolvedRef<'a>, String)> {
|
|
||||||
if ref_string.starts_with('#') {
|
|
||||||
if let Some(indexrs) = &root.obj.compiled_registry {
|
|
||||||
if let Some(s) = indexrs.schemas.get(ref_string) {
|
|
||||||
return Some((ResolvedRef::Local(s.as_ref()), ref_string.to_string()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(base) = url::Url::parse(scope) {
|
|
||||||
if let Ok(joined) = base.join(ref_string) {
|
|
||||||
let joined_str = joined.to_string();
|
|
||||||
if let Some(indexrs) = &root.obj.compiled_registry {
|
|
||||||
if let Some(s) = indexrs.schemas.get(&joined_str) {
|
|
||||||
return Some((ResolvedRef::Local(s.as_ref() as &Schema), joined_str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(decoded) = percent_encoding::percent_decode_str(&joined_str).decode_utf8() {
|
|
||||||
let decoded_str = decoded.to_string();
|
|
||||||
if decoded_str != joined_str {
|
|
||||||
if let Some(indexrs) = &root.obj.compiled_registry {
|
|
||||||
if let Some(s) = indexrs.schemas.get(&decoded_str) {
|
|
||||||
return Some((ResolvedRef::Local(s.as_ref() as &Schema), decoded_str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(s) = self.registry.schemas.get(&joined_str) {
|
|
||||||
return Some((ResolvedRef::Global(s.as_ref(), s.as_ref()), joined_str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ref_string.starts_with('#') {
|
|
||||||
let joined_str = format!("{}{}", scope, ref_string);
|
|
||||||
|
|
||||||
if let Some(indexrs) = &root.obj.compiled_registry {
|
|
||||||
if let Some(s) = indexrs.schemas.get(&joined_str) {
|
|
||||||
return Some((ResolvedRef::Local(s.as_ref() as &Schema), joined_str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(decoded) = percent_encoding::percent_decode_str(&joined_str).decode_utf8() {
|
|
||||||
let decoded_str = decoded.to_string();
|
|
||||||
if decoded_str != joined_str {
|
|
||||||
if let Some(indexrs) = &root.obj.compiled_registry {
|
|
||||||
if let Some(s) = indexrs.schemas.get(&decoded_str) {
|
|
||||||
return Some((ResolvedRef::Local(s.as_ref() as &Schema), decoded_str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(s) = self.registry.schemas.get(&joined_str) {
|
|
||||||
return Some((ResolvedRef::Global(s.as_ref(), s.as_ref()), joined_str));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(parsed) = url::Url::parse(ref_string) {
|
|
||||||
let absolute = parsed.to_string();
|
|
||||||
if let Some(indexrs) = &root.obj.compiled_registry {
|
|
||||||
if let Some(s) = indexrs.schemas.get(&absolute) {
|
|
||||||
return Some((ResolvedRef::Local(s.as_ref()), absolute));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let resource_base = if let Some((base, _)) = absolute.split_once('#') {
|
|
||||||
base
|
|
||||||
} else {
|
|
||||||
&absolute
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(compiled) = self.registry.schemas.get(resource_base) {
|
|
||||||
if let Some(indexrs) = &compiled.obj.compiled_registry {
|
|
||||||
if let Some(s) = indexrs.schemas.get(&absolute) {
|
|
||||||
return Some((ResolvedRef::Global(compiled.as_ref(), s.as_ref()), absolute));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(compiled) = self.registry.schemas.get(ref_string) {
|
|
||||||
return Some((
|
|
||||||
ResolvedRef::Global(compiled.as_ref(), compiled.as_ref()),
|
|
||||||
ref_string.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn validate(
|
pub fn validate(
|
||||||
&self,
|
&self,
|
||||||
schema_id: &str,
|
schema_id: &str,
|
||||||
instance: &Value,
|
instance: &Value,
|
||||||
) -> Result<ValidationResult, ValidationError> {
|
) -> Result<ValidationResult, ValidationError> {
|
||||||
if let Some(schema) = self.registry.schemas.get(schema_id) {
|
if let Some(schema) = self.schemas.get(schema_id) {
|
||||||
let ctx = ValidationContext::new(
|
let ctx = ValidationContext::new(&self.schemas, schema, schema, instance, false, false);
|
||||||
self,
|
ctx.validate_scoped()
|
||||||
schema,
|
|
||||||
schema,
|
|
||||||
ReadOnlyInstance(instance),
|
|
||||||
vec![],
|
|
||||||
HashSet::new(),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
ctx.validate()
|
|
||||||
} else {
|
|
||||||
Err(ValidationError {
|
|
||||||
code: "SCHEMA_NOT_FOUND".to_string(),
|
|
||||||
message: format!("Schema {} not found", schema_id),
|
|
||||||
path: "".to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mask(
|
|
||||||
&self,
|
|
||||||
schema_id: &str,
|
|
||||||
instance: &mut Value,
|
|
||||||
) -> Result<ValidationResult, ValidationError> {
|
|
||||||
if let Some(schema) = self.registry.schemas.get(schema_id) {
|
|
||||||
let ctx = ValidationContext::new(
|
|
||||||
self,
|
|
||||||
schema,
|
|
||||||
schema,
|
|
||||||
MutableInstance::new(instance),
|
|
||||||
vec![],
|
|
||||||
HashSet::new(),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let res = ctx.validate()?;
|
|
||||||
Ok(res)
|
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError {
|
Err(ValidationError {
|
||||||
code: "SCHEMA_NOT_FOUND".to_string(),
|
code: "SCHEMA_NOT_FOUND".to_string(),
|
||||||
|
|||||||
@ -1,50 +0,0 @@
|
|||||||
use crate::validator::schema::Schema;
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref REGISTRY: RwLock<Registry> = RwLock::new(Registry::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct Registry {
|
|
||||||
pub schemas: HashMap<String, Arc<Schema>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Registry {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Registry {
|
|
||||||
schemas: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, schema: crate::validator::schema::Schema) {
|
|
||||||
let id = schema
|
|
||||||
.obj
|
|
||||||
.id
|
|
||||||
.clone()
|
|
||||||
.expect("Schema must have an $id to be registered");
|
|
||||||
let compiled = crate::validator::compiler::Compiler::compile(schema, Some(id.clone()));
|
|
||||||
self.schemas.insert(id, compiled);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(&mut self, id: String, schema: Arc<Schema>) {
|
|
||||||
// We allow overwriting for now to support re-compilation in tests/dev
|
|
||||||
self.schemas.insert(id, schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, id: &str) -> Option<Arc<Schema>> {
|
|
||||||
self.schemas.get(id).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.schemas.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.schemas.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
119
src/validator/rules/array.rs
Normal file
119
src/validator/rules/array.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
use serde_json::Value;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_array(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
let current = self.instance;
|
||||||
|
if let Some(arr) = current.as_array() {
|
||||||
|
if let Some(min) = self.schema.min_items {
|
||||||
|
if (arr.len() as f64) < min {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MIN_ITEMS".to_string(),
|
||||||
|
message: "Too few items".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(max) = self.schema.max_items {
|
||||||
|
if (arr.len() as f64) > max {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MAX_ITEMS".to_string(),
|
||||||
|
message: "Too many items".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.schema.unique_items.unwrap_or(false) {
|
||||||
|
let mut seen: Vec<&Value> = Vec::new();
|
||||||
|
for item in arr {
|
||||||
|
if seen.contains(&item) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "UNIQUE_ITEMS_VIOLATED".to_string(),
|
||||||
|
message: "Array has duplicate items".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
seen.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref contains_schema) = self.schema.contains {
|
||||||
|
let mut _match_count = 0;
|
||||||
|
for (i, child_instance) in arr.iter().enumerate() {
|
||||||
|
let derived = self.derive(
|
||||||
|
contains_schema,
|
||||||
|
child_instance,
|
||||||
|
&self.path,
|
||||||
|
self.extensible,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
let check = derived.validate()?;
|
||||||
|
if check.is_valid() {
|
||||||
|
_match_count += 1;
|
||||||
|
result.evaluated_indices.insert(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let min = self.schema.min_contains.unwrap_or(1.0) as usize;
|
||||||
|
if _match_count < min {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "CONTAINS_VIOLATED".to_string(),
|
||||||
|
message: format!("Contains matches {} < min {}", _match_count, min),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if let Some(max) = self.schema.max_contains {
|
||||||
|
if _match_count > max as usize {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "CONTAINS_VIOLATED".to_string(),
|
||||||
|
message: format!("Contains matches {} > max {}", _match_count, max),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let len = arr.len();
|
||||||
|
let mut validation_index = 0;
|
||||||
|
|
||||||
|
if let Some(ref prefix) = self.schema.prefix_items {
|
||||||
|
for (i, sub_schema) in prefix.iter().enumerate() {
|
||||||
|
if i < len {
|
||||||
|
let path = format!("{}/{}", self.path, i);
|
||||||
|
if let Some(child_instance) = arr.get(i) {
|
||||||
|
let derived = self.derive(sub_schema, child_instance, &path, self.extensible, false);
|
||||||
|
let item_res = derived.validate()?;
|
||||||
|
result.merge(item_res);
|
||||||
|
result.evaluated_indices.insert(i);
|
||||||
|
validation_index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref items_schema) = self.schema.items {
|
||||||
|
for i in validation_index..len {
|
||||||
|
let path = format!("{}/{}", self.path, i);
|
||||||
|
if let Some(child_instance) = arr.get(i) {
|
||||||
|
let derived = self.derive(items_schema, child_instance, &path, self.extensible, false);
|
||||||
|
let item_res = derived.validate()?;
|
||||||
|
result.merge(item_res);
|
||||||
|
result.evaluated_indices.insert(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/validator/rules/combinators.rs
Normal file
83
src/validator/rules/combinators.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_combinators(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
if let Some(ref all_of) = self.schema.all_of {
|
||||||
|
for sub in all_of {
|
||||||
|
let derived = self.derive_for_schema(sub, true);
|
||||||
|
let res = derived.validate()?;
|
||||||
|
result.merge(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref any_of) = self.schema.any_of {
|
||||||
|
let mut valid = false;
|
||||||
|
|
||||||
|
for sub in any_of {
|
||||||
|
let derived = self.derive_for_schema(sub, true);
|
||||||
|
let sub_res = derived.validate()?;
|
||||||
|
if sub_res.is_valid() {
|
||||||
|
valid = true;
|
||||||
|
result.merge(sub_res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "ANY_OF_VIOLATED".to_string(),
|
||||||
|
message: "Matches none of anyOf schemas".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref one_of) = self.schema.one_of {
|
||||||
|
let mut valid_count = 0;
|
||||||
|
let mut valid_res = ValidationResult::new();
|
||||||
|
|
||||||
|
for sub in one_of {
|
||||||
|
let derived = self.derive_for_schema(sub, true);
|
||||||
|
let sub_res = derived.validate()?;
|
||||||
|
if sub_res.is_valid() {
|
||||||
|
valid_count += 1;
|
||||||
|
valid_res = sub_res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if valid_count == 1 {
|
||||||
|
result.merge(valid_res);
|
||||||
|
} else if valid_count == 0 {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "ONE_OF_VIOLATED".to_string(),
|
||||||
|
message: "Matches none of oneOf schemas".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "ONE_OF_VIOLATED".to_string(),
|
||||||
|
message: format!("Matches {} of oneOf schemas (expected 1)", valid_count),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref not_schema) = self.schema.not {
|
||||||
|
let derived = self.derive_for_schema(not_schema, true);
|
||||||
|
let sub_res = derived.validate()?;
|
||||||
|
if sub_res.is_valid() {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "NOT_VIOLATED".to_string(),
|
||||||
|
message: "Matched 'not' schema".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/validator/rules/conditionals.rs
Normal file
69
src/validator/rules/conditionals.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_conditionals(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
if let Some(ref if_schema) = self.schema.if_ {
|
||||||
|
let derived_if = self.derive_for_schema(if_schema, true);
|
||||||
|
let if_res = derived_if.validate()?;
|
||||||
|
|
||||||
|
result.evaluated_keys.extend(if_res.evaluated_keys.clone());
|
||||||
|
result
|
||||||
|
.evaluated_indices
|
||||||
|
.extend(if_res.evaluated_indices.clone());
|
||||||
|
|
||||||
|
if if_res.is_valid() {
|
||||||
|
if let Some(ref then_schema) = self.schema.then_ {
|
||||||
|
let derived_then = self.derive_for_schema(then_schema, true);
|
||||||
|
result.merge(derived_then.validate()?);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(ref else_schema) = self.schema.else_ {
|
||||||
|
let derived_else = self.derive_for_schema(else_schema, true);
|
||||||
|
result.merge(derived_else.validate()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate_strictness(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
if self.extensible || self.reporter {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(obj) = self.instance.as_object() {
|
||||||
|
for key in obj.keys() {
|
||||||
|
if !result.evaluated_keys.contains(key) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "STRICT_PROPERTY_VIOLATION".to_string(),
|
||||||
|
message: format!("Unexpected property '{}'", key),
|
||||||
|
path: format!("{}/{}", self.path, key),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = self.instance.as_array() {
|
||||||
|
for i in 0..arr.len() {
|
||||||
|
if !result.evaluated_indices.contains(&i) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "STRICT_ITEM_VIOLATION".to_string(),
|
||||||
|
message: format!("Unexpected item at index {}", i),
|
||||||
|
path: format!("{}/{}", self.path, i),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/validator/rules/core.rs
Normal file
84
src/validator/rules/core.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use crate::validator::Validator;
|
||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_core(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
let current = self.instance;
|
||||||
|
|
||||||
|
if let Some(ref type_) = self.schema.type_ {
|
||||||
|
match type_ {
|
||||||
|
crate::database::schema::SchemaTypeOrArray::Single(t) => {
|
||||||
|
if !Validator::check_type(t, current) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "INVALID_TYPE".to_string(),
|
||||||
|
message: format!("Expected type '{}'", t),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crate::database::schema::SchemaTypeOrArray::Multiple(types) => {
|
||||||
|
let mut valid = false;
|
||||||
|
for t in types {
|
||||||
|
if Validator::check_type(t, current) {
|
||||||
|
valid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "INVALID_TYPE".to_string(),
|
||||||
|
message: format!("Expected one of types {:?}", types),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref const_val) = self.schema.const_ {
|
||||||
|
if !crate::validator::util::equals(current, const_val) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "CONST_VIOLATED".to_string(),
|
||||||
|
message: "Value does not match const".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if let Some(obj) = current.as_object() {
|
||||||
|
result.evaluated_keys.extend(obj.keys().cloned());
|
||||||
|
} else if let Some(arr) = current.as_array() {
|
||||||
|
result.evaluated_indices.extend(0..arr.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref enum_vals) = self.schema.enum_ {
|
||||||
|
let mut found = false;
|
||||||
|
for val in enum_vals {
|
||||||
|
if crate::validator::util::equals(current, val) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "ENUM_MISMATCH".to_string(),
|
||||||
|
message: "Value is not in enum".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if let Some(obj) = current.as_object() {
|
||||||
|
result.evaluated_keys.extend(obj.keys().cloned());
|
||||||
|
} else if let Some(arr) = current.as_array() {
|
||||||
|
result.evaluated_indices.extend(0..arr.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/validator/rules/format.rs
Normal file
44
src/validator/rules/format.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_format(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
let current = self.instance;
|
||||||
|
if let Some(ref compiled_fmt) = self.schema.compiled_format {
|
||||||
|
match compiled_fmt {
|
||||||
|
crate::database::schema::CompiledFormat::Func(f) => {
|
||||||
|
let should = if let Some(s) = current.as_str() {
|
||||||
|
!s.is_empty()
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
if should {
|
||||||
|
if let Err(e) = f(current) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "FORMAT_MISMATCH".to_string(),
|
||||||
|
message: format!("Format error: {}", e),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crate::database::schema::CompiledFormat::Regex(re) => {
|
||||||
|
if let Some(s) = current.as_str() {
|
||||||
|
if !re.is_match(s) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "FORMAT_MISMATCH".to_string(),
|
||||||
|
message: "Format regex mismatch".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
93
src/validator/rules/mod.rs
Normal file
93
src/validator/rules/mod.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use serde_json::Value;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
pub mod array;
|
||||||
|
pub mod combinators;
|
||||||
|
pub mod conditionals;
|
||||||
|
pub mod core;
|
||||||
|
pub mod format;
|
||||||
|
pub mod numeric;
|
||||||
|
pub mod object;
|
||||||
|
pub mod polymorphism;
|
||||||
|
pub mod string;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_scoped(&self) -> Result<ValidationResult, ValidationError> {
|
||||||
|
let mut result = ValidationResult::new();
|
||||||
|
|
||||||
|
// Structural Limits
|
||||||
|
if !self.validate_depth(&mut result)? {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
if !self.validate_always_fail(&mut result)? {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
if !self.validate_family(&mut result)? {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
if !self.validate_refs(&mut result)? {
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core Type Constraints
|
||||||
|
self.validate_core(&mut result)?;
|
||||||
|
self.validate_numeric(&mut result)?;
|
||||||
|
self.validate_string(&mut result)?;
|
||||||
|
self.validate_format(&mut result)?;
|
||||||
|
|
||||||
|
// Complex Structures
|
||||||
|
self.validate_object(&mut result)?;
|
||||||
|
self.validate_array(&mut result)?;
|
||||||
|
|
||||||
|
// Multipliers & Conditionals
|
||||||
|
self.validate_combinators(&mut result)?;
|
||||||
|
self.validate_conditionals(&mut result)?;
|
||||||
|
|
||||||
|
// State Tracking
|
||||||
|
self.validate_extensible(&mut result)?;
|
||||||
|
self.validate_strictness(&mut result)?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_depth(&self, _result: &mut ValidationResult) -> Result<bool, ValidationError> {
|
||||||
|
if self.depth > 100 {
|
||||||
|
Err(ValidationError {
|
||||||
|
code: "RECURSION_LIMIT_EXCEEDED".to_string(),
|
||||||
|
message: "Recursion limit exceeded".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_always_fail(&self, result: &mut ValidationResult) -> Result<bool, ValidationError> {
|
||||||
|
if self.schema.always_fail {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "FALSE_SCHEMA".to_string(),
|
||||||
|
message: "Schema is false".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
// Short-circuit
|
||||||
|
Ok(false)
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_extensible(&self, result: &mut ValidationResult) -> Result<bool, ValidationError> {
|
||||||
|
if self.extensible {
|
||||||
|
if let Some(obj) = self.instance.as_object() {
|
||||||
|
result.evaluated_keys.extend(obj.keys().cloned());
|
||||||
|
} else if let Some(arr) = self.instance.as_array() {
|
||||||
|
result.evaluated_indices.extend(0..arr.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
61
src/validator/rules/numeric.rs
Normal file
61
src/validator/rules/numeric.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_numeric(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
let current = self.instance;
|
||||||
|
if let Some(num) = current.as_f64() {
|
||||||
|
if let Some(min) = self.schema.minimum {
|
||||||
|
if num < min {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MINIMUM_VIOLATED".to_string(),
|
||||||
|
message: format!("Value {} < min {}", num, min),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(max) = self.schema.maximum {
|
||||||
|
if num > max {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MAXIMUM_VIOLATED".to_string(),
|
||||||
|
message: format!("Value {} > max {}", num, max),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ex_min) = self.schema.exclusive_minimum {
|
||||||
|
if num <= ex_min {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "EXCLUSIVE_MINIMUM_VIOLATED".to_string(),
|
||||||
|
message: format!("Value {} <= ex_min {}", num, ex_min),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ex_max) = self.schema.exclusive_maximum {
|
||||||
|
if num >= ex_max {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "EXCLUSIVE_MAXIMUM_VIOLATED".to_string(),
|
||||||
|
message: format!("Value {} >= ex_max {}", num, ex_max),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(multiple_of) = self.schema.multiple_of {
|
||||||
|
let val: f64 = num / multiple_of;
|
||||||
|
if (val - val.round()).abs() > f64::EPSILON {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MULTIPLE_OF_VIOLATED".to_string(),
|
||||||
|
message: format!("Value {} not multiple of {}", num, multiple_of),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
183
src/validator/rules/object.rs
Normal file
183
src/validator/rules/object.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
use serde_json::Value;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_object(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
let current = self.instance;
|
||||||
|
if let Some(obj) = current.as_object() {
|
||||||
|
// Entity Bound Implicit Type Validation
|
||||||
|
if let Some(allowed_types) = &self.schema.obj.compiled_allowed_types {
|
||||||
|
if let Some(type_val) = obj.get("type") {
|
||||||
|
if let Some(type_str) = type_val.as_str() {
|
||||||
|
if allowed_types.contains(type_str) {
|
||||||
|
// Ensure it passes strict mode
|
||||||
|
result.evaluated_keys.insert("type".to_string());
|
||||||
|
} else {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "CONST_VIOLATED".to_string(), // Aligning with original const override errors
|
||||||
|
message: format!(
|
||||||
|
"Type '{}' is not a valid descendant for this entity bound schema",
|
||||||
|
type_str
|
||||||
|
),
|
||||||
|
path: format!("{}/type", self.path),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(min) = self.schema.min_properties {
|
||||||
|
if (obj.len() as f64) < min {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MIN_PROPERTIES".to_string(),
|
||||||
|
message: "Too few properties".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(max) = self.schema.max_properties {
|
||||||
|
if (obj.len() as f64) > max {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MAX_PROPERTIES".to_string(),
|
||||||
|
message: "Too many properties".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ref req) = self.schema.required {
|
||||||
|
for field in req {
|
||||||
|
if !obj.contains_key(field) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "REQUIRED_FIELD_MISSING".to_string(),
|
||||||
|
message: format!("Missing {}", field),
|
||||||
|
path: format!("{}/{}", self.path, field),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(props) = &self.schema.properties {
|
||||||
|
for (key, sub_schema) in props {
|
||||||
|
if let Some(child_instance) = obj.get(key) {
|
||||||
|
let new_path = format!("{}/{}", self.path, key);
|
||||||
|
let is_ref = sub_schema.ref_string.is_some() || sub_schema.obj.compiled_ref.is_some();
|
||||||
|
let next_extensible = if is_ref { false } else { self.extensible };
|
||||||
|
|
||||||
|
let derived = self.derive(
|
||||||
|
sub_schema,
|
||||||
|
child_instance,
|
||||||
|
&new_path,
|
||||||
|
next_extensible,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let mut item_res = derived.validate()?;
|
||||||
|
|
||||||
|
// Entity Bound Implicit Type Interception
|
||||||
|
if key == "type" {
|
||||||
|
if let Some(allowed_types) = &self.schema.obj.compiled_allowed_types {
|
||||||
|
if let Some(instance_type) = child_instance.as_str() {
|
||||||
|
if allowed_types.contains(instance_type) {
|
||||||
|
item_res
|
||||||
|
.errors
|
||||||
|
.retain(|e| e.code != "CONST_VIOLATED" && e.code != "ENUM_VIOLATED");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.merge(item_res);
|
||||||
|
result.evaluated_keys.insert(key.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref compiled_pp) = self.schema.compiled_pattern_properties {
|
||||||
|
for (compiled_re, sub_schema) in compiled_pp {
|
||||||
|
for (key, child_instance) in obj {
|
||||||
|
if compiled_re.0.is_match(key) {
|
||||||
|
let new_path = format!("{}/{}", self.path, key);
|
||||||
|
let is_ref = sub_schema.ref_string.is_some() || sub_schema.obj.compiled_ref.is_some();
|
||||||
|
let next_extensible = if is_ref { false } else { self.extensible };
|
||||||
|
|
||||||
|
let derived = self.derive(
|
||||||
|
sub_schema,
|
||||||
|
child_instance,
|
||||||
|
&new_path,
|
||||||
|
next_extensible,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let item_res = derived.validate()?;
|
||||||
|
result.merge(item_res);
|
||||||
|
result.evaluated_keys.insert(key.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref additional_schema) = self.schema.additional_properties {
|
||||||
|
for (key, child_instance) in obj {
|
||||||
|
let mut locally_matched = false;
|
||||||
|
if let Some(props) = &self.schema.properties {
|
||||||
|
if props.contains_key(&key.to_string()) {
|
||||||
|
locally_matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !locally_matched {
|
||||||
|
if let Some(ref compiled_pp) = self.schema.compiled_pattern_properties {
|
||||||
|
for (compiled_re, _) in compiled_pp {
|
||||||
|
if compiled_re.0.is_match(key) {
|
||||||
|
locally_matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !locally_matched {
|
||||||
|
let new_path = format!("{}/{}", self.path, key);
|
||||||
|
let is_ref = additional_schema.ref_string.is_some()
|
||||||
|
|| additional_schema.obj.compiled_ref.is_some();
|
||||||
|
let next_extensible = if is_ref { false } else { self.extensible };
|
||||||
|
|
||||||
|
let derived = self.derive(
|
||||||
|
additional_schema,
|
||||||
|
child_instance,
|
||||||
|
&new_path,
|
||||||
|
next_extensible,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let item_res = derived.validate()?;
|
||||||
|
result.merge(item_res);
|
||||||
|
result.evaluated_keys.insert(key.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref property_names) = self.schema.property_names {
|
||||||
|
for key in obj.keys() {
|
||||||
|
let _new_path = format!("{}/propertyNames/{}", self.path, key);
|
||||||
|
let val_str = Value::String(key.to_string());
|
||||||
|
|
||||||
|
let ctx = ValidationContext::new(
|
||||||
|
self.schemas,
|
||||||
|
self.root,
|
||||||
|
property_names,
|
||||||
|
&val_str,
|
||||||
|
self.extensible,
|
||||||
|
self.reporter,
|
||||||
|
);
|
||||||
|
|
||||||
|
result.merge(ctx.validate()?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/validator/rules/polymorphism.rs
Normal file
64
src/validator/rules/polymorphism.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_family(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
if self.schema.family.is_some() {
|
||||||
|
let conflicts = self.schema.type_.is_some()
|
||||||
|
|| self.schema.properties.is_some()
|
||||||
|
|| self.schema.required.is_some()
|
||||||
|
|| self.schema.additional_properties.is_some()
|
||||||
|
|| self.schema.items.is_some()
|
||||||
|
|| self.schema.ref_string.is_some()
|
||||||
|
|| self.schema.one_of.is_some()
|
||||||
|
|| self.schema.any_of.is_some()
|
||||||
|
|| self.schema.all_of.is_some()
|
||||||
|
|| self.schema.enum_.is_some()
|
||||||
|
|| self.schema.const_.is_some();
|
||||||
|
|
||||||
|
if conflicts {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "INVALID_SCHEMA".to_string(),
|
||||||
|
message: "$family must be used exclusively without other constraints".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
// Short-circuit: the schema formulation is broken
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Family specific runtime validation will go here later if needed
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate_refs(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
// 1. Core $ref logic fully transitioned to memory pointer resolutions.
|
||||||
|
if let Some(_ref_str) = &self.schema.ref_string {
|
||||||
|
if let Some(global_schema) = &self.schema.compiled_ref {
|
||||||
|
let mut shadow = self.derive(
|
||||||
|
global_schema,
|
||||||
|
self.instance,
|
||||||
|
&self.path,
|
||||||
|
self.extensible,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
shadow.root = global_schema;
|
||||||
|
result.merge(shadow.validate()?);
|
||||||
|
} else {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "REF_RESOLUTION_FAILED".to_string(),
|
||||||
|
message: format!("Reference pointer was not compiled inside Database graph"),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/validator/rules/string.rs
Normal file
53
src/validator/rules/string.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use crate::validator::context::ValidationContext;
|
||||||
|
use crate::validator::error::ValidationError;
|
||||||
|
use crate::validator::result::ValidationResult;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
impl<'a> ValidationContext<'a> {
|
||||||
|
pub(crate) fn validate_string(
|
||||||
|
&self,
|
||||||
|
result: &mut ValidationResult,
|
||||||
|
) -> Result<bool, ValidationError> {
|
||||||
|
let current = self.instance;
|
||||||
|
if let Some(s) = current.as_str() {
|
||||||
|
if let Some(min) = self.schema.min_length {
|
||||||
|
if (s.chars().count() as f64) < min {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MIN_LENGTH_VIOLATED".to_string(),
|
||||||
|
message: format!("Length < min {}", min),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(max) = self.schema.max_length {
|
||||||
|
if (s.chars().count() as f64) > max {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "MAX_LENGTH_VIOLATED".to_string(),
|
||||||
|
message: format!("Length > max {}", max),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ref compiled_re) = self.schema.compiled_pattern {
|
||||||
|
if !compiled_re.0.is_match(s) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "PATTERN_VIOLATED".to_string(),
|
||||||
|
message: format!("Pattern mismatch {:?}", self.schema.pattern),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if let Some(ref pattern) = self.schema.pattern {
|
||||||
|
if let Ok(re) = Regex::new(pattern) {
|
||||||
|
if !re.is_match(s) {
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: "PATTERN_VIOLATED".to_string(),
|
||||||
|
message: format!("Pattern mismatch {}", pattern),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,11 +5,7 @@ use std::fs;
|
|||||||
struct TestSuite {
|
struct TestSuite {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
description: String,
|
description: String,
|
||||||
schema: Option<serde_json::Value>,
|
database: serde_json::Value,
|
||||||
// Support JSPG-style test suites with explicit types/enums/puncs
|
|
||||||
types: Option<serde_json::Value>,
|
|
||||||
enums: Option<serde_json::Value>,
|
|
||||||
puncs: Option<serde_json::Value>,
|
|
||||||
tests: Vec<TestCase>,
|
tests: Vec<TestCase>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,9 +16,6 @@ struct TestCase {
|
|||||||
valid: bool,
|
valid: bool,
|
||||||
// Support explicit schema ID target for test case
|
// Support explicit schema ID target for test case
|
||||||
schema_id: Option<String>,
|
schema_id: Option<String>,
|
||||||
// Expected output for masking tests
|
|
||||||
#[allow(dead_code)]
|
|
||||||
expected: Option<serde_json::Value>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// use crate::validator::registry::REGISTRY; // No longer used directly for tests!
|
// use crate::validator::registry::REGISTRY; // No longer used directly for tests!
|
||||||
@ -50,64 +43,34 @@ pub fn run_test_file_at_index(path: &str, index: usize) -> Result<(), String> {
|
|||||||
let group = &suite[index];
|
let group = &suite[index];
|
||||||
let mut failures = Vec::<String>::new();
|
let mut failures = Vec::<String>::new();
|
||||||
|
|
||||||
// Create Validator Instance and parse enums, types, and puncs automatically
|
let db_json = group.database.clone();
|
||||||
let mut validator = Validator::from_punc_definition(
|
let db = crate::database::Database::new(&db_json);
|
||||||
group.enums.as_ref(),
|
let validator = Validator::new(std::sync::Arc::new(db.schemas));
|
||||||
group.types.as_ref(),
|
|
||||||
group.puncs.as_ref(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3. Register root 'schemas' if present (generic test support)
|
|
||||||
// Some tests use a raw 'schema' or 'schemas' field at the group level
|
|
||||||
if let Some(schema_val) = &group.schema {
|
|
||||||
match serde_json::from_value::<crate::validator::schema::Schema>(schema_val.clone()) {
|
|
||||||
Ok(mut schema) => {
|
|
||||||
let id_clone = schema.obj.id.clone();
|
|
||||||
if id_clone.is_some() {
|
|
||||||
validator.registry.add(schema);
|
|
||||||
} else {
|
|
||||||
// Fallback ID if none provided in schema
|
|
||||||
let id = format!("test:{}:{}", path, index);
|
|
||||||
schema.obj.id = Some(id);
|
|
||||||
validator.registry.add(schema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!(
|
|
||||||
"DEBUG: FAILED to deserialize group schema for index {}: {}",
|
|
||||||
index, e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Run Tests
|
// 4. Run Tests
|
||||||
for (_test_index, test) in group.tests.iter().enumerate() {
|
for (_test_index, test) in group.tests.iter().enumerate() {
|
||||||
let mut schema_id = test.schema_id.clone();
|
let mut schema_id = test.schema_id.clone();
|
||||||
|
|
||||||
// If no explicit schema_id, try to infer from the single schema in the group
|
// If no explicit schema_id, infer from the database structure
|
||||||
if schema_id.is_none() {
|
if schema_id.is_none() {
|
||||||
if let Some(s) = &group.schema {
|
if let Some(schemas) = db_json.get("schemas").and_then(|v| v.as_array()) {
|
||||||
// If 'schema' is a single object, use its ID or "root"
|
if let Some(first) = schemas.first() {
|
||||||
if let Some(obj) = s.as_object() {
|
if let Some(id) = first.get("$id").and_then(|v| v.as_str()) {
|
||||||
if let Some(id_val) = obj.get("$id") {
|
schema_id = Some(id.to_string());
|
||||||
schema_id = id_val.as_str().map(|s| s.to_string());
|
} else {
|
||||||
|
schema_id = Some("schema_0".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if schema_id.is_none() {
|
|
||||||
schema_id = Some(format!("test:{}:{}", path, index));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Default to the first punc if present (for puncs.json style)
|
if schema_id.is_none() {
|
||||||
if schema_id.is_none() {
|
if let Some(puncs) = db_json.get("puncs").and_then(|v| v.as_array()) {
|
||||||
if let Some(Value::Array(puncs)) = &group.puncs {
|
if let Some(first_punc) = puncs.first() {
|
||||||
if let Some(first_punc) = puncs.first() {
|
if let Some(schemas) = first_punc.get("schemas").and_then(|v| v.as_array()) {
|
||||||
if let Some(Value::Array(schemas)) = first_punc.get("schemas") {
|
if let Some(first) = schemas.first() {
|
||||||
if let Some(first_schema) = schemas.first() {
|
if let Some(id) = first.get("$id").and_then(|v| v.as_str()) {
|
||||||
if let Some(id) = first_schema.get("$id").and_then(|v| v.as_str()) {
|
schema_id = Some(id.to_string());
|
||||||
schema_id = Some(id.to_string());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,42 +90,16 @@ pub fn run_test_file_at_index(path: &str, index: usize) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(expected) = &test.expected {
|
if got_valid != test.valid {
|
||||||
// Masking Test
|
let error_msg = match &result {
|
||||||
let mut data_for_mask = test.data.clone();
|
Ok(res) => format!("{:?}", res.errors),
|
||||||
match validator.mask(&sid, &mut data_for_mask) {
|
Err(e) => format!("Execution Error: {:?}", e),
|
||||||
Ok(_) => {
|
};
|
||||||
if !equals(&data_for_mask, expected) {
|
|
||||||
let msg = format!(
|
|
||||||
"Masking Test '{}' failed.\nExpected: {:?}\nGot: {:?}",
|
|
||||||
test.description, expected, data_for_mask
|
|
||||||
);
|
|
||||||
eprintln!("{}", msg);
|
|
||||||
failures.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
let msg = format!(
|
|
||||||
"Masking Test '{}' failed with execution error: {:?}",
|
|
||||||
test.description, e
|
|
||||||
);
|
|
||||||
eprintln!("{}", msg);
|
|
||||||
failures.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Standard Validation Test
|
|
||||||
if got_valid != test.valid {
|
|
||||||
let error_msg = match &result {
|
|
||||||
Ok(res) => format!("{:?}", res.errors),
|
|
||||||
Err(e) => format!("Execution Error: {:?}", e),
|
|
||||||
};
|
|
||||||
|
|
||||||
failures.push(format!(
|
failures.push(format!(
|
||||||
"[{}] Test '{}' failed. Expected: {}, Got: {}. Errors: {}",
|
"[{}] Test '{}' failed. Expected: {}, Got: {}. Errors: {}",
|
||||||
group.description, test.description, test.valid, got_valid, error_msg
|
group.description, test.description, test.valid, got_valid, error_msg
|
||||||
));
|
));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
failures.push(format!(
|
failures.push(format!(
|
||||||
@ -178,96 +115,6 @@ pub fn run_test_file_at_index(path: &str, index: usize) -> Result<(), String> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn run_test_file(path: &str) -> 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));
|
|
||||||
|
|
||||||
let mut failures = Vec::<String>::new();
|
|
||||||
for (group_index, group) in suite.into_iter().enumerate() {
|
|
||||||
// Create Validator Instance and parse enums, types, and puncs automatically
|
|
||||||
let mut validator = Validator::from_punc_definition(
|
|
||||||
group.enums.as_ref(),
|
|
||||||
group.types.as_ref(),
|
|
||||||
group.puncs.as_ref(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let unique_id = format!("test:{}:{}", path, group_index);
|
|
||||||
|
|
||||||
// Register main 'schema' if present (Standard style)
|
|
||||||
if let Some(ref schema_val) = group.schema {
|
|
||||||
let mut schema: crate::validator::schema::Schema =
|
|
||||||
serde_json::from_value(schema_val.clone()).expect("Failed to parse test schema");
|
|
||||||
|
|
||||||
// If schema has no ID, assign unique_id and use add() or manual insert?
|
|
||||||
// Compiler needs ID. Registry::add needs ID.
|
|
||||||
if schema.obj.id.is_none() {
|
|
||||||
schema.obj.id = Some(unique_id.clone());
|
|
||||||
}
|
|
||||||
validator.registry.add(schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
for test in group.tests {
|
|
||||||
// Use explicit schema_id from test, or default to unique_id
|
|
||||||
let schema_id = test.schema_id.as_deref().unwrap_or(&unique_id).to_string();
|
|
||||||
|
|
||||||
let result = validator.validate(&schema_id, &test.data);
|
|
||||||
|
|
||||||
if test.valid {
|
|
||||||
match result {
|
|
||||||
Ok(res) => {
|
|
||||||
if !res.is_valid() {
|
|
||||||
let msg = format!(
|
|
||||||
"Test failed (expected valid): {}\nSchema: {:?}\nData: {:?}\nErrors: {:?}",
|
|
||||||
test.description,
|
|
||||||
group.schema, // We might need to find the actual schema used if schema_id is custom
|
|
||||||
test.data,
|
|
||||||
res.errors
|
|
||||||
);
|
|
||||||
eprintln!("{}", msg);
|
|
||||||
failures.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
let msg = format!(
|
|
||||||
"Test failed (expected valid) but got execution error: {}\nSchema: {:?}\nData: {:?}\nError: {:?}",
|
|
||||||
test.description, group.schema, test.data, e
|
|
||||||
);
|
|
||||||
eprintln!("{}", msg);
|
|
||||||
failures.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match result {
|
|
||||||
Ok(res) => {
|
|
||||||
if res.is_valid() {
|
|
||||||
let msg = format!(
|
|
||||||
"Test failed (expected invalid): {}\nSchema: {:?}\nData: {:?}",
|
|
||||||
test.description, group.schema, test.data
|
|
||||||
);
|
|
||||||
eprintln!("{}", msg);
|
|
||||||
failures.push(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
// Expected invalid, got error (which implies invalid/failure), so this is PASS.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !failures.is_empty() {
|
|
||||||
return Err(format!(
|
|
||||||
"{} tests failed in file {}:\n\n{}",
|
|
||||||
failures.len(),
|
|
||||||
path,
|
|
||||||
failures.join("\n\n")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_integer(v: &Value) -> bool {
|
pub fn is_integer(v: &Value) -> bool {
|
||||||
match v {
|
match v {
|
||||||
|
|||||||
62
test_err.log
Normal file
62
test_err.log
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
Compiling jspg v0.1.0 (/Users/awgneo/Repositories/thoughtpatterns/cellular/jspg)
|
||||||
|
Finished `test` profile [unoptimized + debuginfo] target(s) in 26.14s
|
||||||
|
Running unittests src/lib.rs (target/debug/deps/jspg-99ace086c3537f5a)
|
||||||
|
|
||||||
|
running 1 test
|
||||||
|
[32m[1m Using[0m[39m [37m[1mPgConfig("pg18")[0m[39m and `pg_config` from [36m/opt/homebrew/opt/postgresql@18/bin/pg_config[39m
|
||||||
|
[32m[1m Building[0m[39m extension with features [36mpg_test pg18[39m
|
||||||
|
[32m[1m Running[0m[39m command [36m"/opt/homebrew/bin/cargo" "build" "--lib" "--features" "pg_test pg18" "--no-default-features" "--message-format=json-render-diagnostics"[39m
|
||||||
|
Compiling jspg v0.1.0 (/Users/awgneo/Repositories/thoughtpatterns/cellular/jspg)
|
||||||
|
Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.10s
|
||||||
|
[32m[1m Installing[0m[39m extension
|
||||||
|
[32m[1m Copying[0m[39m control file to [36m/opt/homebrew/share/postgresql@18/extension/jspg.control[39m
|
||||||
|
[32m[1m Copying[0m[39m shared library to [36m/opt/homebrew/lib/postgresql@18/jspg.dylib[39m
|
||||||
|
[32m[1m Discovered[0m[39m [36m[1m351[0m[39m SQL entities: [36m[1m1[0m[39m schemas ([36m[1m1[0m[39m unique), [36m[1m350[0m[39m functions, [36m[1m0[0m[39m types, [36m[1m0[0m[39m enums, [36m[1m0[0m[39m sqls, [36m[1m0[0m[39m ords, [36m[1m0[0m[39m hashes, [36m[1m0[0m[39m aggregates, [36m[1m0[0m[39m triggers
|
||||||
|
[32m[1m Rebuilding[0m[39m [36mpgrx_embed[39m, in debug mode, for SQL generation with features [36mpg_test pg18[39m
|
||||||
|
Compiling jspg v0.1.0 (/Users/awgneo/Repositories/thoughtpatterns/cellular/jspg)
|
||||||
|
Finished `dev` profile [unoptimized + debuginfo] target(s) in 10.63s
|
||||||
|
[32m[1m Writing[0m[39m SQL entities to /opt/homebrew/share/postgresql@18/extension/jspg--0.1.0.sql
|
||||||
|
[32m[1m Finished[0m[39m installing jspg
|
||||||
|
[36m[2026-03-01 22:54:19.068 EST] [82952] [69a509eb.14408]: LOG: starting PostgreSQL 18.1 (Homebrew) on aarch64-apple-darwin25.2.0, compiled by Apple clang version 17.0.0 (clang-1700.6.3.2), 64-bit[39m
|
||||||
|
[36m[2026-03-01 22:54:19.070 EST] [82952] [69a509eb.14408]: LOG: listening on IPv6 address "::1", port 32218[39m
|
||||||
|
[36m[2026-03-01 22:54:19.070 EST] [82952] [69a509eb.14408]: LOG: listening on IPv4 address "127.0.0.1", port 32218[39m
|
||||||
|
[36m[2026-03-01 22:54:19.071 EST] [82952] [69a509eb.14408]: LOG: listening on Unix socket "/Users/awgneo/Repositories/thoughtpatterns/cellular/jspg/target/test-pgdata/.s.PGSQL.32218"[39m
|
||||||
|
[36m[2026-03-01 22:54:19.077 EST] [82958] [69a509eb.1440e]: LOG: database system was shut down at 2026-03-01 22:49:02 EST[39m
|
||||||
|
[32m[1m Creating[0m[39m database [36m[1mpgrx_tests[0m[39m
|
||||||
|
|
||||||
|
thread 'tests::pg_test_typed_refs_0' (29092254) panicked at /Users/awgneo/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/pgrx-tests-0.16.1/src/framework.rs:166:9:
|
||||||
|
|
||||||
|
|
||||||
|
Postgres Messages:
|
||||||
|
[37m[2m[2026-03-01 22:54:19.068 EST] [82952] [69a509eb.14408]: LOG: starting PostgreSQL 18.1 (Homebrew) on aarch64-apple-darwin25.2.0, compiled by Apple clang version 17.0.0 (clang-1700.6.3.2), 64-bit
|
||||||
|
[2026-03-01 22:54:19.070 EST] [82952] [69a509eb.14408]: LOG: listening on IPv6 address "::1", port 32218
|
||||||
|
[2026-03-01 22:54:19.070 EST] [82952] [69a509eb.14408]: LOG: listening on IPv4 address "127.0.0.1", port 32218
|
||||||
|
[2026-03-01 22:54:19.071 EST] [82952] [69a509eb.14408]: LOG: listening on Unix socket "/Users/awgneo/Repositories/thoughtpatterns/cellular/jspg/target/test-pgdata/.s.PGSQL.32218"
|
||||||
|
[2026-03-01 22:54:19.081 EST] [82952] [69a509eb.14408]: LOG: database system is ready to accept connections
|
||||||
|
[0m[39m
|
||||||
|
|
||||||
|
Test Function Messages:
|
||||||
|
[36m[2026-03-01 22:54:20.058 EST] [82982] [69a509ec.14426]: LOG: statement: START TRANSACTION
|
||||||
|
[2026-03-01 22:54:20.058 EST] [82982] [69a509ec.14426]: LOG: statement: SELECT "tests"."test_typed_refs_0"();
|
||||||
|
[2026-03-01 22:54:20.062 EST] [82982] [69a509ec.14426]: ERROR: called `Result::unwrap()` on an `Err` value: "[Entity inheritance and native type discrimination] Test 'Valid person against organization schema (implicit type allowance)' failed. Expected: true, Got: false. Errors: [ValidationError { code: \"CONST_VIOLATED\", message: \"Value does not match const\", path: \"/type\" }, ValidationError { code: \"STRICT_PROPERTY_VIOLATION\", message: \"Unexpected property 'first_name'\", path: \"/first_name\" }, ValidationError { code: \"STRICT_PROPERTY_VIOLATION\", message: \"Unexpected property 'first_name'\", path: \"/first_name\" }, ValidationError { code: \"STRICT_PROPERTY_VIOLATION\", message: \"Unexpected property 'first_name'\", path: \"/first_name\" }]\n[Entity inheritance and native type discrimination] Test 'Valid organization against organization schema' failed. Expected: true, Got: false. Errors: [ValidationError { code: \"CONST_VIOLATED\", message: \"Value does not match const\", path: \"/type\" }]\n[Entity inheritance and native type discrimination] Test 'Invalid entity against organization schema (ancestor not allowed)' failed. Expected: false, Got: true. Errors: []"
|
||||||
|
[2026-03-01 22:54:20.062 EST] [82982] [69a509ec.14426]: STATEMENT: SELECT "tests"."test_typed_refs_0"();
|
||||||
|
[2026-03-01 22:54:20.062 EST] [82982] [69a509ec.14426]: LOG: statement: ROLLBACK
|
||||||
|
[39m
|
||||||
|
|
||||||
|
Client Error:
|
||||||
|
[31m[1mcalled `Result::unwrap()` on an `Err` value: "[Entity inheritance and native type discrimination] Test 'Valid person against organization schema (implicit type allowance)' failed. Expected: true, Got: false. Errors: [ValidationError { code: \"CONST_VIOLATED\", message: \"Value does not match const\", path: \"/type\" }, ValidationError { code: \"STRICT_PROPERTY_VIOLATION\", message: \"Unexpected property 'first_name'\", path: \"/first_name\" }, ValidationError { code: \"STRICT_PROPERTY_VIOLATION\", message: \"Unexpected property 'first_name'\", path: \"/first_name\" }, ValidationError { code: \"STRICT_PROPERTY_VIOLATION\", message: \"Unexpected property 'first_name'\", path: \"/first_name\" }]\n[Entity inheritance and native type discrimination] Test 'Valid organization against organization schema' failed. Expected: true, Got: false. Errors: [ValidationError { code: \"CONST_VIOLATED\", message: \"Value does not match const\", path: \"/type\" }]\n[Entity inheritance and native type discrimination] Test 'Invalid entity against organization schema (ancestor not allowed)' failed. Expected: false, Got: true. Errors: []"[0m[39m
|
||||||
|
postgres location: [37m[2mfixtures.rs[0m[39m
|
||||||
|
rust location: [33m<unknown>[39m
|
||||||
|
|
||||||
|
|
||||||
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
|
test tests::pg_test_typed_refs_0 ... FAILED
|
||||||
|
|
||||||
|
failures:
|
||||||
|
|
||||||
|
failures:
|
||||||
|
tests::pg_test_typed_refs_0
|
||||||
|
|
||||||
|
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 343 filtered out; finished in 21.82s
|
||||||
|
|
||||||
|
error: test failed, to rerun pass `--lib`
|
||||||
@ -1,29 +1,5 @@
|
|||||||
use jspg::validator::util;
|
use jspg::validator::util;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_anchor_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_anchor_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_anchor_2() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 2).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_anchor_3() {
|
|
||||||
let path = format!("{}/tests/fixtures/anchor.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 3).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_content_0() {
|
fn test_content_0() {
|
||||||
let path = format!("{}/tests/fixtures/content.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/content.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -108,54 +84,6 @@ fn test_min_items_2() {
|
|||||||
util::run_test_file_at_index(&path, 2).unwrap();
|
util::run_test_file_at_index(&path, 2).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_2() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 2).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_3() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 3).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_4() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 4).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_5() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 5).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_6() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 6).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_puncs_7() {
|
|
||||||
let path = format!("{}/tests/fixtures/puncs.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 7).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_additional_properties_0() {
|
fn test_additional_properties_0() {
|
||||||
let path = format!("{}/tests/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/additionalProperties.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -348,6 +276,18 @@ fn test_any_of_9() {
|
|||||||
util::run_test_file_at_index(&path, 9).unwrap();
|
util::run_test_file_at_index(&path, 9).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_families_0() {
|
||||||
|
let path = format!("{}/tests/fixtures/families.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_families_1() {
|
||||||
|
let path = format!("{}/tests/fixtures/families.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_property_names_0() {
|
fn test_property_names_0() {
|
||||||
let path = format!("{}/tests/fixtures/propertyNames.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/propertyNames.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -390,18 +330,6 @@ fn test_property_names_6() {
|
|||||||
util::run_test_file_at_index(&path, 6).unwrap();
|
util::run_test_file_at_index(&path, 6).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_boolean_schema_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/boolean_schema.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_boolean_schema_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/boolean_schema.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_not_0() {
|
fn test_not_0() {
|
||||||
let path = format!("{}/tests/fixtures/not.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/not.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -570,6 +498,30 @@ fn test_items_15() {
|
|||||||
util::run_test_file_at_index(&path, 15).unwrap();
|
util::run_test_file_at_index(&path, 15).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_typed_refs_0() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_typed_refs_1() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_typed_refs_2() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 2).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_typed_refs_3() {
|
||||||
|
let path = format!("{}/tests/fixtures/typedRefs.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 3).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enum_0() {
|
fn test_enum_0() {
|
||||||
let path = format!("{}/tests/fixtures/enum.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/enum.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -1014,6 +966,18 @@ fn test_one_of_12() {
|
|||||||
util::run_test_file_at_index(&path, 12).unwrap();
|
util::run_test_file_at_index(&path, 12).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_boolean_schema_0() {
|
||||||
|
let path = format!("{}/tests/fixtures/booleanSchema.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 0).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_boolean_schema_1() {
|
||||||
|
let path = format!("{}/tests/fixtures/booleanSchema.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
|
util::run_test_file_at_index(&path, 1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_if_then_else_0() {
|
fn test_if_then_else_0() {
|
||||||
let path = format!("{}/tests/fixtures/if-then-else.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/if-then-else.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -1961,129 +1925,3 @@ fn test_contains_8() {
|
|||||||
let path = format!("{}/tests/fixtures/contains.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/tests/fixtures/contains.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
util::run_test_file_at_index(&path, 8).unwrap();
|
util::run_test_file_at_index(&path, 8).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_0() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_1() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_2() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 2).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_3() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 3).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_4() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 4).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_5() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 5).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_6() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 6).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_7() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 7).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_8() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 8).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_9() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 9).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_10() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 10).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_11() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 11).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_12() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 12).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_13() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 13).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_14() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 14).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_15() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 15).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_16() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 16).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_17() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 17).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_18() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 18).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_19() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 19).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_dynamic_ref_20() {
|
|
||||||
let path = format!("{}/tests/fixtures/dynamicRef.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
util::run_test_file_at_index(&path, 20).unwrap();
|
|
||||||
}
|
|
||||||
|
|||||||
80
tests/fixtures/additionalProperties.json
vendored
80
tests/fixtures/additionalProperties.json
vendored
@ -1,19 +1,23 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "additionalProperties validates properties not matched by properties",
|
"description": "additionalProperties validates properties not matched by properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "string"
|
"properties": {
|
||||||
},
|
"foo": {
|
||||||
"bar": {
|
"type": "string"
|
||||||
"type": "number"
|
},
|
||||||
|
"bar": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"additionalProperties": {
|
|
||||||
"type": "boolean"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -45,17 +49,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true with additionalProperties still validates structure",
|
"description": "extensible: true with additionalProperties still validates structure",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensible": true,
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": true,
|
|
||||||
"additionalProperties": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -79,19 +87,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "complex additionalProperties with object and array items",
|
"description": "complex additionalProperties with object and array items",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"type": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"additionalProperties": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
414
tests/fixtures/allOf.json
vendored
414
tests/fixtures/allOf.json
vendored
@ -1,27 +1,31 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "allOf",
|
"description": "allOf",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": {
|
"allOf": [
|
||||||
"type": "integer"
|
{
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"bar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"foo": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"foo"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -61,39 +65,43 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with base schema",
|
"description": "allOf with base schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
|
||||||
"bar": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"baz": {},
|
|
||||||
"foo": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"bar"
|
|
||||||
],
|
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"baz": {},
|
||||||
"foo": {
|
"foo": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"foo"
|
"bar"
|
||||||
]
|
],
|
||||||
},
|
"allOf": [
|
||||||
{
|
{
|
||||||
"properties": {
|
"properties": {
|
||||||
"baz": {
|
"foo": {
|
||||||
"type": "null"
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"baz": {
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"baz"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"baz"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -143,14 +151,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf simple types",
|
"description": "allOf simple types",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"maximum": 30
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"allOf": [
|
||||||
{
|
{
|
||||||
"minimum": 20
|
"maximum": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -169,11 +181,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with boolean schemas, all true",
|
"description": "allOf with boolean schemas, all true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
true
|
"allOf": [
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -186,11 +202,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with boolean schemas, some false",
|
"description": "allOf with boolean schemas, some false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false
|
"allOf": [
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -203,11 +223,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with boolean schemas, all false",
|
"description": "allOf with boolean schemas, all false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
{
|
||||||
false,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false
|
"allOf": [
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -220,10 +244,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with one empty schema",
|
"description": "allOf with one empty schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
{
|
||||||
{}
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"allOf": [
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -236,11 +264,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with two empty schemas",
|
"description": "allOf with two empty schemas",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
{
|
||||||
{},
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
{}
|
"allOf": [
|
||||||
|
{},
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -253,12 +285,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with the first empty schema",
|
"description": "allOf with the first empty schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{},
|
|
||||||
{
|
{
|
||||||
"type": "number"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"allOf": [
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -277,13 +313,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with the last empty schema",
|
"description": "allOf with the last empty schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"type": "number"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"allOf": [
|
||||||
{}
|
{
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -301,13 +341,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "nested allOf, to check validation semantics",
|
"description": "nested allOf, to check validation semantics",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
"type": "null"
|
"allOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -328,21 +372,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf combined with anyOf, oneOf",
|
"description": "allOf combined with anyOf, oneOf",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"multipleOf": 2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"allOf": [
|
||||||
],
|
{
|
||||||
"anyOf": [
|
"multipleOf": 2
|
||||||
{
|
}
|
||||||
"multipleOf": 3
|
],
|
||||||
}
|
"anyOf": [
|
||||||
],
|
{
|
||||||
"oneOf": [
|
"multipleOf": 3
|
||||||
{
|
}
|
||||||
"multipleOf": 5
|
],
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"multipleOf": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -391,31 +439,35 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in allOf",
|
"description": "extensible: true allows extra properties in allOf",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": {
|
"allOf": [
|
||||||
"type": "integer"
|
{
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
],
|
||||||
"required": [
|
"extensible": true
|
||||||
"bar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"foo": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"foo"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -431,22 +483,26 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "strict by default with allOf properties",
|
"description": "strict by default with allOf properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo": {
|
"allOf": [
|
||||||
"const": 1
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"const": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"const": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"bar": {
|
|
||||||
"const": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -472,23 +528,27 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allOf with nested extensible: true (partial looseness)",
|
"description": "allOf with nested extensible: true (partial looseness)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo": {
|
"allOf": [
|
||||||
"const": 1
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"const": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"extensible": true,
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"const": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"extensible": true,
|
|
||||||
"properties": {
|
|
||||||
"bar": {
|
|
||||||
"const": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -506,31 +566,35 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "strictness: allOf composition with strict refs",
|
"description": "strictness: allOf composition with strict refs",
|
||||||
"schema": {
|
"database": {
|
||||||
"allOf": [
|
"schemas": [
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/partA"
|
"allOf": [
|
||||||
},
|
{
|
||||||
{
|
"$ref": "#/$defs/partA"
|
||||||
"$ref": "#/$defs/partB"
|
},
|
||||||
}
|
{
|
||||||
],
|
"$ref": "#/$defs/partB"
|
||||||
"$defs": {
|
|
||||||
"partA": {
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
}
|
],
|
||||||
},
|
"$defs": {
|
||||||
"partB": {
|
"partA": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"partB": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
120
tests/fixtures/anchor.json
vendored
120
tests/fixtures/anchor.json
vendored
@ -1,120 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"description": "Location-independent identifier",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$ref": "#foo",
|
|
||||||
"$defs": {
|
|
||||||
"A": {
|
|
||||||
"$anchor": "foo",
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"data": 1,
|
|
||||||
"description": "match",
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": "a",
|
|
||||||
"description": "mismatch",
|
|
||||||
"valid": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Location-independent identifier with absolute URI",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$ref": "http://localhost:1234/draft2020-12/bar#foo",
|
|
||||||
"$defs": {
|
|
||||||
"A": {
|
|
||||||
"$id": "http://localhost:1234/draft2020-12/bar",
|
|
||||||
"$anchor": "foo",
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"data": 1,
|
|
||||||
"description": "match",
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": "a",
|
|
||||||
"description": "mismatch",
|
|
||||||
"valid": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Location-independent identifier with base URI change in subschema",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "http://localhost:1234/draft2020-12/root",
|
|
||||||
"$ref": "http://localhost:1234/draft2020-12/nested.json#foo",
|
|
||||||
"$defs": {
|
|
||||||
"A": {
|
|
||||||
"$id": "nested.json",
|
|
||||||
"$defs": {
|
|
||||||
"B": {
|
|
||||||
"$anchor": "foo",
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"data": 1,
|
|
||||||
"description": "match",
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": "a",
|
|
||||||
"description": "mismatch",
|
|
||||||
"valid": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "same $anchor with different base uri",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"$id": "http://localhost:1234/draft2020-12/foobar",
|
|
||||||
"$defs": {
|
|
||||||
"A": {
|
|
||||||
"$id": "child1",
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$id": "child2",
|
|
||||||
"$anchor": "my_anchor",
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$anchor": "my_anchor",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"$ref": "child1#my_anchor"
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "$ref resolves to /$defs/A/allOf/1",
|
|
||||||
"data": "a",
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "$ref does not resolve to /$defs/A/allOf/0",
|
|
||||||
"data": 1,
|
|
||||||
"valid": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
204
tests/fixtures/anyOf.json
vendored
204
tests/fixtures/anyOf.json
vendored
@ -1,14 +1,18 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "anyOf",
|
"description": "anyOf",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"minimum": 2
|
"type": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -37,15 +41,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "anyOf with base schema",
|
"description": "anyOf with base schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "string",
|
|
||||||
"anyOf": [
|
|
||||||
{
|
{
|
||||||
"maxLength": 2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"type": "string",
|
||||||
{
|
"anyOf": [
|
||||||
"minLength": 4
|
{
|
||||||
|
"maxLength": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minLength": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -69,11 +77,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "anyOf with boolean schemas, all true",
|
"description": "anyOf with boolean schemas, all true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
true
|
"anyOf": [
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -86,11 +98,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "anyOf with boolean schemas, some true",
|
"description": "anyOf with boolean schemas, some true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false
|
"anyOf": [
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -103,11 +119,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "anyOf with boolean schemas, all false",
|
"description": "anyOf with boolean schemas, all false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
{
|
||||||
false,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false
|
"anyOf": [
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -120,27 +140,31 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "anyOf complex types",
|
"description": "anyOf complex types",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": {
|
"anyOf": [
|
||||||
"type": "integer"
|
{
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"bar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"foo": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"foo"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -180,13 +204,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "anyOf with one empty schema",
|
"description": "anyOf with one empty schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
|
||||||
{
|
{
|
||||||
"type": "number"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"anyOf": [
|
||||||
{}
|
{
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -204,13 +232,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "nested anyOf, to check validation semantics",
|
"description": "nested anyOf, to check validation semantics",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
|
||||||
{
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"type": "null"
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -231,17 +263,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in anyOf",
|
"description": "extensible: true allows extra properties in anyOf",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"anyOf": [
|
||||||
{
|
{
|
||||||
"minimum": 2
|
"type": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -255,22 +291,26 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "strict by default with anyOf properties",
|
"description": "strict by default with anyOf properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"anyOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo": {
|
"anyOf": [
|
||||||
"const": 1
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"const": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"const": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"bar": {
|
|
||||||
"const": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "boolean schema 'true'",
|
"description": "boolean schema 'true'",
|
||||||
"schema": true,
|
"database": {
|
||||||
|
"schemas": [
|
||||||
|
true
|
||||||
|
]
|
||||||
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "number is valid",
|
"description": "number is valid",
|
||||||
@ -56,7 +60,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "boolean schema 'false'",
|
"description": "boolean schema 'false'",
|
||||||
"schema": false,
|
"database": {
|
||||||
|
"schemas": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "number is invalid",
|
"description": "number is invalid",
|
||||||
218
tests/fixtures/const.json
vendored
218
tests/fixtures/const.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "const validation",
|
"description": "const validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": 2
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -25,16 +29,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with object",
|
"description": "const with object",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": {
|
{
|
||||||
"foo": "bar",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"baz": "bax"
|
"const": {
|
||||||
},
|
"foo": "bar",
|
||||||
"properties": {
|
"baz": "bax"
|
||||||
"foo": {},
|
},
|
||||||
"baz": {}
|
"properties": {
|
||||||
}
|
"foo": {},
|
||||||
|
"baz": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -72,11 +80,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with array",
|
"description": "const with array",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": [
|
|
||||||
{
|
{
|
||||||
"foo": "bar"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": [
|
||||||
|
{
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -110,9 +122,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with null",
|
"description": "const with null",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": null
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": null
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -129,9 +145,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with false does not match 0",
|
"description": "const with false does not match 0",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": false
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -153,9 +173,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with true does not match 1",
|
"description": "const with true does not match 1",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": true
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -177,10 +201,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with [false] does not match [0]",
|
"description": "const with [false] does not match [0]",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": [
|
{
|
||||||
false
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -209,10 +237,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with [true] does not match [1]",
|
"description": "const with [true] does not match [1]",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": [
|
{
|
||||||
true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": [
|
||||||
|
true
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -241,11 +273,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with {\"a\": false} does not match {\"a\": 0}",
|
"description": "const with {\"a\": false} does not match {\"a\": 0}",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": {
|
{
|
||||||
"a": false
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"const": {
|
||||||
|
"a": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -273,11 +309,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with {\"a\": true} does not match {\"a\": 1}",
|
"description": "const with {\"a\": true} does not match {\"a\": 1}",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": {
|
{
|
||||||
"a": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"const": {
|
||||||
|
"a": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -305,9 +345,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with 0 does not match other zero-like types",
|
"description": "const with 0 does not match other zero-like types",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": 0
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -344,9 +388,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with 1 does not match true",
|
"description": "const with 1 does not match true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": 1
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -368,9 +416,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "const with -2.0 matches integer and float types",
|
"description": "const with -2.0 matches integer and float types",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": -2.0
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": -2.0
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -402,9 +454,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "float and integers are equal up to 64-bit representation limits",
|
"description": "float and integers are equal up to 64-bit representation limits",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": 9007199254740992
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": 9007199254740992
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -431,9 +487,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "nul characters in strings",
|
"description": "nul characters in strings",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": "hello\u0000there"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": "hello\u0000there"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -450,10 +510,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "characters with the same visual representation but different codepoint",
|
"description": "characters with the same visual representation but different codepoint",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": "μ",
|
{
|
||||||
"$comment": "U+03BC"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": "μ",
|
||||||
|
"$comment": "U+03BC"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -472,10 +536,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "characters with the same visual representation, but different number of codepoints",
|
"description": "characters with the same visual representation, but different number of codepoints",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": "ä",
|
{
|
||||||
"$comment": "U+00E4"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"const": "ä",
|
||||||
|
"$comment": "U+00E4"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -494,12 +562,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in const object match",
|
"description": "extensible: true allows extra properties in const object match",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"const": {
|
{
|
||||||
"a": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"const": {
|
||||||
"extensible": true
|
"a": 1
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
132
tests/fixtures/contains.json
vendored
132
tests/fixtures/contains.json
vendored
@ -1,12 +1,16 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "contains keyword validation",
|
"description": "contains keyword validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"minimum": 5
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"items": true
|
"minimum": 5
|
||||||
|
},
|
||||||
|
"items": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -60,12 +64,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "contains keyword with const keyword",
|
"description": "contains keyword with const keyword",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 5
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"items": true
|
"const": 5
|
||||||
|
},
|
||||||
|
"items": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -101,9 +109,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "contains keyword with boolean schema true",
|
"description": "contains keyword with boolean schema true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": true
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"contains": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -122,9 +134,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "contains keyword with boolean schema false",
|
"description": "contains keyword with boolean schema false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": false
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"contains": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -148,14 +164,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "items + contains",
|
"description": "items + contains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"items": {
|
{
|
||||||
"multipleOf": 2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"items": {
|
||||||
"contains": {
|
"multipleOf": 2
|
||||||
"multipleOf": 3
|
},
|
||||||
}
|
"contains": {
|
||||||
|
"multipleOf": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -196,12 +216,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "contains with false if subschema",
|
"description": "contains with false if subschema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"if": false,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"else": true
|
"contains": {
|
||||||
}
|
"if": false,
|
||||||
|
"else": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -220,11 +244,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "contains with null instance elements",
|
"description": "contains with null instance elements",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"type": "null"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"contains": {
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -238,12 +266,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows non-matching items in contains",
|
"description": "extensible: true allows non-matching items in contains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"extensible": true
|
"const": 1
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -258,11 +290,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "strict by default: non-matching items in contains are invalid",
|
"description": "strict by default: non-matching items in contains are invalid",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"contains": {
|
||||||
|
"const": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
68
tests/fixtures/content.json
vendored
68
tests/fixtures/content.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "validation of string-encoded content based on media type",
|
"description": "validation of string-encoded content based on media type",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contentMediaType": "application/json"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"contentMediaType": "application/json"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -25,9 +29,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of binary string-encoding",
|
"description": "validation of binary string-encoding",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contentEncoding": "base64"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"contentEncoding": "base64"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -49,10 +57,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of binary-encoded media type documents",
|
"description": "validation of binary-encoded media type documents",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contentMediaType": "application/json",
|
{
|
||||||
"contentEncoding": "base64"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"contentMediaType": "application/json",
|
||||||
|
"contentEncoding": "base64"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -79,24 +91,28 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of binary-encoded media type documents with schema",
|
"description": "validation of binary-encoded media type documents with schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contentMediaType": "application/json",
|
{
|
||||||
"contentEncoding": "base64",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"contentSchema": {
|
"contentMediaType": "application/json",
|
||||||
"type": "object",
|
"contentEncoding": "base64",
|
||||||
"required": [
|
"contentSchema": {
|
||||||
"foo"
|
"type": "object",
|
||||||
],
|
"required": [
|
||||||
"properties": {
|
"foo"
|
||||||
"foo": {
|
],
|
||||||
"type": "string"
|
"properties": {
|
||||||
},
|
"foo": {
|
||||||
"boo": {
|
"type": "string"
|
||||||
"type": "integer"
|
},
|
||||||
|
"boo": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
576
tests/fixtures/dependencies.json
vendored
Normal file
576
tests/fixtures/dependencies.json
vendored
Normal file
@ -0,0 +1,576 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "nondependant",
|
||||||
|
"data": {
|
||||||
|
"foo": 1
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "with dependency",
|
||||||
|
"data": {
|
||||||
|
"foo": 1,
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "missing dependency",
|
||||||
|
"data": {
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ignores arrays",
|
||||||
|
"data": [
|
||||||
|
"bar"
|
||||||
|
],
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ignores strings",
|
||||||
|
"data": "foobar",
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ignores other non-objects",
|
||||||
|
"data": 12,
|
||||||
|
"valid": 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": {},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "object with one property",
|
||||||
|
"data": {
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "non-object is valid",
|
||||||
|
"data": 1,
|
||||||
|
"valid": 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": {},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "nondependants",
|
||||||
|
"data": {
|
||||||
|
"foo": 1,
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "with dependencies",
|
||||||
|
"data": {
|
||||||
|
"foo": 1,
|
||||||
|
"bar": 2,
|
||||||
|
"quux": 3
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "missing dependency",
|
||||||
|
"data": {
|
||||||
|
"foo": 1,
|
||||||
|
"quux": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "missing other dependency",
|
||||||
|
"data": {
|
||||||
|
"bar": 1,
|
||||||
|
"quux": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "missing both dependencies",
|
||||||
|
"data": {
|
||||||
|
"quux": 1
|
||||||
|
},
|
||||||
|
"valid": 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
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "quoted quotes",
|
||||||
|
"data": {
|
||||||
|
"foo'bar": 1,
|
||||||
|
"foo\"bar": 2
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "CRLF missing dependent",
|
||||||
|
"data": {
|
||||||
|
"foo\nbar": 1,
|
||||||
|
"foo": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "quoted quotes missing dependent",
|
||||||
|
"data": {
|
||||||
|
"foo\"bar": 2
|
||||||
|
},
|
||||||
|
"valid": 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
|
||||||
|
},
|
||||||
|
"valid": 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
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "no dependency",
|
||||||
|
"data": {
|
||||||
|
"foo": "quux"
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "wrong type",
|
||||||
|
"data": {
|
||||||
|
"foo": "quux",
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "wrong type other",
|
||||||
|
"data": {
|
||||||
|
"foo": 2,
|
||||||
|
"bar": "quux"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "wrong type both",
|
||||||
|
"data": {
|
||||||
|
"foo": "quux",
|
||||||
|
"bar": "quux"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ignores arrays (invalid in strict mode)",
|
||||||
|
"data": [
|
||||||
|
"bar"
|
||||||
|
],
|
||||||
|
"valid": false,
|
||||||
|
"expect_errors": [
|
||||||
|
{
|
||||||
|
"code": "STRICT_ITEM_VIOLATION"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ignores strings",
|
||||||
|
"data": "foobar",
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "ignores other non-objects",
|
||||||
|
"data": 12,
|
||||||
|
"valid": 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"
|
||||||
|
],
|
||||||
|
"valid": 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
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "object with property having schema false is invalid",
|
||||||
|
"data": {
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "object with both properties is invalid",
|
||||||
|
"data": {
|
||||||
|
"foo": 1,
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "empty object is valid",
|
||||||
|
"data": {},
|
||||||
|
"valid": 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
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "quoted quote",
|
||||||
|
"data": {
|
||||||
|
"foo'bar": {
|
||||||
|
"foo\"bar": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "quoted tab invalid under dependent schema",
|
||||||
|
"data": {
|
||||||
|
"foo\tbar": 1,
|
||||||
|
"a": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "quoted quote invalid under dependent schema",
|
||||||
|
"data": {
|
||||||
|
"foo'bar": 1
|
||||||
|
},
|
||||||
|
"valid": 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
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "matches dependency (invalid in strict mode - bar not allowed if foo missing)",
|
||||||
|
"data": {
|
||||||
|
"bar": 1
|
||||||
|
},
|
||||||
|
"valid": false,
|
||||||
|
"expect_errors": [
|
||||||
|
{
|
||||||
|
"code": "STRICT_PROPERTY_VIOLATION"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "matches both",
|
||||||
|
"data": {
|
||||||
|
"foo": 1,
|
||||||
|
"bar": 2
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "no dependency",
|
||||||
|
"data": {
|
||||||
|
"baz": 1
|
||||||
|
},
|
||||||
|
"valid": 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
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
220
tests/fixtures/dependentRequired.json
vendored
220
tests/fixtures/dependentRequired.json
vendored
@ -1,220 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"description": "single dependency",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"dependentRequired": {
|
|
||||||
"bar": [
|
|
||||||
"foo"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "neither",
|
|
||||||
"data": {},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "nondependant",
|
|
||||||
"data": {
|
|
||||||
"foo": 1
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "with dependency",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "missing dependency",
|
|
||||||
"data": {
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "ignores arrays",
|
|
||||||
"data": [
|
|
||||||
"bar"
|
|
||||||
],
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "ignores strings",
|
|
||||||
"data": "foobar",
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "ignores other non-objects",
|
|
||||||
"data": 12,
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "empty dependents",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"dependentRequired": {
|
|
||||||
"bar": []
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "empty object",
|
|
||||||
"data": {},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "object with one property",
|
|
||||||
"data": {
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "non-object is valid",
|
|
||||||
"data": 1,
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "multiple dependents required",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"dependentRequired": {
|
|
||||||
"quux": [
|
|
||||||
"foo",
|
|
||||||
"bar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "neither",
|
|
||||||
"data": {},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "nondependants",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "with dependencies",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"bar": 2,
|
|
||||||
"quux": 3
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "missing dependency",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"quux": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "missing other dependency",
|
|
||||||
"data": {
|
|
||||||
"bar": 1,
|
|
||||||
"quux": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "missing both dependencies",
|
|
||||||
"data": {
|
|
||||||
"quux": 1
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "dependencies with escaped characters",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"dependentRequired": {
|
|
||||||
"foo\nbar": [
|
|
||||||
"foo\rbar"
|
|
||||||
],
|
|
||||||
"foo\"bar": [
|
|
||||||
"foo'bar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "CRLF",
|
|
||||||
"data": {
|
|
||||||
"foo\nbar": 1,
|
|
||||||
"foo\rbar": 2
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "quoted quotes",
|
|
||||||
"data": {
|
|
||||||
"foo'bar": 1,
|
|
||||||
"foo\"bar": 2
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "CRLF missing dependent",
|
|
||||||
"data": {
|
|
||||||
"foo\nbar": 1,
|
|
||||||
"foo": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "quoted quotes missing dependent",
|
|
||||||
"data": {
|
|
||||||
"foo\"bar": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "extensible: true allows extra properties in dependentRequired",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"dependentRequired": {
|
|
||||||
"bar": [
|
|
||||||
"foo"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "extra property is valid",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"bar": 2,
|
|
||||||
"baz": 3
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
303
tests/fixtures/dependentSchemas.json
vendored
303
tests/fixtures/dependentSchemas.json
vendored
@ -1,303 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"description": "single dependency (STRICT)",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"properties": {
|
|
||||||
"foo": true,
|
|
||||||
"bar": true
|
|
||||||
},
|
|
||||||
"dependentSchemas": {
|
|
||||||
"bar": {
|
|
||||||
"properties": {
|
|
||||||
"foo": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"bar": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "valid",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "no dependency",
|
|
||||||
"data": {
|
|
||||||
"foo": "quux"
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "wrong type",
|
|
||||||
"data": {
|
|
||||||
"foo": "quux",
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "wrong type other",
|
|
||||||
"data": {
|
|
||||||
"foo": 2,
|
|
||||||
"bar": "quux"
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "wrong type both",
|
|
||||||
"data": {
|
|
||||||
"foo": "quux",
|
|
||||||
"bar": "quux"
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "ignores arrays (invalid in strict mode)",
|
|
||||||
"data": [
|
|
||||||
"bar"
|
|
||||||
],
|
|
||||||
"valid": false,
|
|
||||||
"expect_errors": [
|
|
||||||
{
|
|
||||||
"code": "STRICT_ITEM_VIOLATION"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "ignores strings (invalid in strict mode - wait, strings are scalars, strict only checks obj/arr)",
|
|
||||||
"data": "foobar",
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "ignores other non-objects",
|
|
||||||
"data": 12,
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "single dependency (EXTENSIBLE)",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"properties": {
|
|
||||||
"foo": true,
|
|
||||||
"bar": true
|
|
||||||
},
|
|
||||||
"dependentSchemas": {
|
|
||||||
"bar": {
|
|
||||||
"properties": {
|
|
||||||
"foo": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"bar": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "ignores arrays (valid in extensible mode)",
|
|
||||||
"data": [
|
|
||||||
"bar"
|
|
||||||
],
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "boolean subschemas",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"properties": {
|
|
||||||
"foo": true,
|
|
||||||
"bar": true
|
|
||||||
},
|
|
||||||
"dependentSchemas": {
|
|
||||||
"foo": true,
|
|
||||||
"bar": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "object with property having schema true is valid",
|
|
||||||
"data": {
|
|
||||||
"foo": 1
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "object with property having schema false is invalid",
|
|
||||||
"data": {
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "object with both properties is invalid",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "empty object is valid",
|
|
||||||
"data": {},
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "dependencies with escaped characters",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"properties": {
|
|
||||||
"foo\tbar": true,
|
|
||||||
"foo'bar": true,
|
|
||||||
"a": true,
|
|
||||||
"b": true,
|
|
||||||
"c": true
|
|
||||||
},
|
|
||||||
"dependentSchemas": {
|
|
||||||
"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
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "quoted quote",
|
|
||||||
"data": {
|
|
||||||
"foo'bar": {
|
|
||||||
"foo\"bar": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "quoted tab invalid under dependent schema",
|
|
||||||
"data": {
|
|
||||||
"foo\tbar": 1,
|
|
||||||
"a": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "quoted quote invalid under dependent schema",
|
|
||||||
"data": {
|
|
||||||
"foo'bar": 1
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "dependent subschema incompatible with root (STRICT)",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"properties": {
|
|
||||||
"foo": {},
|
|
||||||
"baz": true
|
|
||||||
},
|
|
||||||
"dependentSchemas": {
|
|
||||||
"foo": {
|
|
||||||
"properties": {
|
|
||||||
"bar": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "matches root",
|
|
||||||
"data": {
|
|
||||||
"foo": 1
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "matches dependency (invalid in strict mode - bar not allowed if foo missing)",
|
|
||||||
"data": {
|
|
||||||
"bar": 1
|
|
||||||
},
|
|
||||||
"valid": false,
|
|
||||||
"expect_errors": [
|
|
||||||
{
|
|
||||||
"code": "STRICT_PROPERTY_VIOLATION"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "matches both",
|
|
||||||
"data": {
|
|
||||||
"foo": 1,
|
|
||||||
"bar": 2
|
|
||||||
},
|
|
||||||
"valid": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "no dependency",
|
|
||||||
"data": {
|
|
||||||
"baz": 1
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "dependent subschema incompatible with root (EXTENSIBLE)",
|
|
||||||
"schema": {
|
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
||||||
"properties": {
|
|
||||||
"foo": {},
|
|
||||||
"baz": true
|
|
||||||
},
|
|
||||||
"dependentSchemas": {
|
|
||||||
"foo": {
|
|
||||||
"properties": {
|
|
||||||
"bar": {}
|
|
||||||
},
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "matches dependency (valid in extensible mode)",
|
|
||||||
"data": {
|
|
||||||
"bar": 1
|
|
||||||
},
|
|
||||||
"valid": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
1111
tests/fixtures/dynamicRef.json
vendored
1111
tests/fixtures/dynamicRef.json
vendored
File diff suppressed because it is too large
Load Diff
72
tests/fixtures/emptyString.json
vendored
72
tests/fixtures/emptyString.json
vendored
@ -1,41 +1,45 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "empty string is valid for all types (except const)",
|
"description": "empty string is valid for all types (except const)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"obj": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "object"
|
"properties": {
|
||||||
},
|
"obj": {
|
||||||
"arr": {
|
"type": "object"
|
||||||
"type": "array"
|
},
|
||||||
},
|
"arr": {
|
||||||
"str": {
|
"type": "array"
|
||||||
"type": "string"
|
},
|
||||||
},
|
"str": {
|
||||||
"int": {
|
"type": "string"
|
||||||
"type": "integer"
|
},
|
||||||
},
|
"int": {
|
||||||
"num": {
|
"type": "integer"
|
||||||
"type": "number"
|
},
|
||||||
},
|
"num": {
|
||||||
"bool": {
|
"type": "number"
|
||||||
"type": "boolean"
|
},
|
||||||
},
|
"bool": {
|
||||||
"nul": {
|
"type": "boolean"
|
||||||
"type": "null"
|
},
|
||||||
},
|
"nul": {
|
||||||
"fmt": {
|
"type": "null"
|
||||||
"type": "string",
|
},
|
||||||
"format": "uuid"
|
"fmt": {
|
||||||
},
|
"type": "string",
|
||||||
"con": {
|
"format": "uuid"
|
||||||
"const": "value"
|
},
|
||||||
},
|
"con": {
|
||||||
"con_empty": {
|
"const": "value"
|
||||||
"const": ""
|
},
|
||||||
|
"con_empty": {
|
||||||
|
"const": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
244
tests/fixtures/enum.json
vendored
244
tests/fixtures/enum.json
vendored
@ -1,12 +1,16 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "simple enum validation",
|
"description": "simple enum validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
1,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
2,
|
"enum": [
|
||||||
3
|
1,
|
||||||
|
2,
|
||||||
|
3
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -24,20 +28,24 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "heterogeneous enum validation",
|
"description": "heterogeneous enum validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
|
||||||
6,
|
|
||||||
"foo",
|
|
||||||
[],
|
|
||||||
true,
|
|
||||||
{
|
{
|
||||||
"foo": 12
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"enum": [
|
||||||
|
6,
|
||||||
|
"foo",
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"foo": 12
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"foo": {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"properties": {
|
|
||||||
"foo": {}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -76,11 +84,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "heterogeneous enum-with-null validation",
|
"description": "heterogeneous enum-with-null validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
6,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
null
|
"enum": [
|
||||||
|
6,
|
||||||
|
null
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -103,23 +115,27 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enums in properties",
|
"description": "enums in properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "object",
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo": {
|
"type": "object",
|
||||||
"enum": [
|
"properties": {
|
||||||
"foo"
|
"foo": {
|
||||||
]
|
"enum": [
|
||||||
},
|
"foo"
|
||||||
"bar": {
|
]
|
||||||
"enum": [
|
},
|
||||||
|
"bar": {
|
||||||
|
"enum": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
"bar"
|
"bar"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"bar"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -170,11 +186,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with escaped characters",
|
"description": "enum with escaped characters",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
"foo\nbar",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo\rbar"
|
"enum": [
|
||||||
|
"foo\nbar",
|
||||||
|
"foo\rbar"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -197,10 +217,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with false does not match 0",
|
"description": "enum with false does not match 0",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
false
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"enum": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -223,12 +247,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with [false] does not match [0]",
|
"description": "enum with [false] does not match [0]",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
[
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false
|
"enum": [
|
||||||
]
|
[
|
||||||
|
false
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -257,10 +285,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with true does not match 1",
|
"description": "enum with true does not match 1",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"enum": [
|
||||||
|
true
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -283,12 +315,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with [true] does not match [1]",
|
"description": "enum with [true] does not match [1]",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
[
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
true
|
"enum": [
|
||||||
]
|
[
|
||||||
|
true
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -317,10 +353,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with 0 does not match false",
|
"description": "enum with 0 does not match false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
0
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"enum": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -343,12 +383,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with [0] does not match [false]",
|
"description": "enum with [0] does not match [false]",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
[
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
0
|
"enum": [
|
||||||
]
|
[
|
||||||
|
0
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -377,10 +421,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with 1 does not match true",
|
"description": "enum with 1 does not match true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"enum": [
|
||||||
|
1
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -403,12 +451,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "enum with [1] does not match [true]",
|
"description": "enum with [1] does not match [true]",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
[
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
1
|
"enum": [
|
||||||
]
|
[
|
||||||
|
1
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -437,10 +489,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "nul characters in strings",
|
"description": "nul characters in strings",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
{
|
||||||
"hello\u0000there"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"enum": [
|
||||||
|
"hello\u0000there"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -458,14 +514,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in enum object match",
|
"description": "extensible: true allows extra properties in enum object match",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"enum": [
|
|
||||||
{
|
{
|
||||||
"foo": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"enum": [
|
||||||
|
{
|
||||||
|
"foo": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
12
tests/fixtures/exclusiveMaximum.json
vendored
12
tests/fixtures/exclusiveMaximum.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "exclusiveMaximum validation",
|
"description": "exclusiveMaximum validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"exclusiveMaximum": 3.0
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"exclusiveMaximum": 3.0
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -28,4 +32,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
12
tests/fixtures/exclusiveMinimum.json
vendored
12
tests/fixtures/exclusiveMinimum.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "exclusiveMinimum validation",
|
"description": "exclusiveMinimum validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"exclusiveMinimum": 1.1
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"exclusiveMinimum": 1.1
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -28,4 +32,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
202
tests/fixtures/families.json
vendored
Normal file
202
tests/fixtures/families.json
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"description": "Entity families with dot patterns",
|
||||||
|
"database": {
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name": "entity",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity"
|
||||||
|
],
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "entity",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "entity"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$id": "entity.light",
|
||||||
|
"$ref": "entity"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "organization",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity",
|
||||||
|
"organization"
|
||||||
|
],
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "organization",
|
||||||
|
"$ref": "entity",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "person",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity",
|
||||||
|
"organization",
|
||||||
|
"person"
|
||||||
|
],
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "person",
|
||||||
|
"$ref": "organization",
|
||||||
|
"properties": {
|
||||||
|
"first_name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$id": "person.light",
|
||||||
|
"$ref": "person"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"puncs": [
|
||||||
|
{
|
||||||
|
"name": "get_entities",
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "get_entities.response",
|
||||||
|
"$family": "entity"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "get_light_entities",
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "get_light_entities.response",
|
||||||
|
"$family": "entity.light"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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": "Dot pattern family matches entity.light",
|
||||||
|
"schema_id": "get_light_entities.response",
|
||||||
|
"data": {
|
||||||
|
"id": "3",
|
||||||
|
"type": "entity"
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Dot pattern family matches person.light",
|
||||||
|
"schema_id": "get_light_entities.response",
|
||||||
|
"data": {
|
||||||
|
"id": "4",
|
||||||
|
"type": "person",
|
||||||
|
"name": "ACME",
|
||||||
|
"first_name": "John"
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Dot pattern family excludes organization (missing .light schema, constraint violation)",
|
||||||
|
"schema_id": "get_light_entities.response",
|
||||||
|
"data": {
|
||||||
|
"id": "5",
|
||||||
|
"type": "organization",
|
||||||
|
"name": "ACME"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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 does not implicitly match descendants (no magical implicit hierarchy on normal ad-hoc schemas)",
|
||||||
|
"schema_id": "get_widgets.response",
|
||||||
|
"data": {
|
||||||
|
"id": "1",
|
||||||
|
"widget_type": "special",
|
||||||
|
"special_feature": "yes"
|
||||||
|
},
|
||||||
|
"valid": false,
|
||||||
|
"expect_errors": [
|
||||||
|
{
|
||||||
|
"code": "FAMILY_MISMATCH",
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
240
tests/fixtures/format.json
vendored
240
tests/fixtures/format.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "validation of date-time strings",
|
"description": "validation of date-time strings",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "date-time"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "date-time"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -140,9 +144,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of date strings",
|
"description": "validation of date strings",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "date"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "date"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -389,9 +397,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of duration strings",
|
"description": "validation of duration strings",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "duration"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "duration"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -528,9 +540,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "\\a is not an ECMA 262 control escape",
|
"description": "\\a is not an ECMA 262 control escape",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "regex"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "regex"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -542,9 +558,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of e-mail addresses",
|
"description": "validation of e-mail addresses",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "email"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "email"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -671,9 +691,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of host names",
|
"description": "validation of host names",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "hostname"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "hostname"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -801,9 +825,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of A-label (punycode) host names",
|
"description": "validation of A-label (punycode) host names",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "hostname"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "hostname"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1030,9 +1058,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of an internationalized e-mail addresses",
|
"description": "validation of an internationalized e-mail addresses",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "idn-email"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "idn-email"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1089,9 +1121,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of internationalized host names",
|
"description": "validation of internationalized host names",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "idn-hostname"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "idn-hostname"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1430,9 +1466,13 @@
|
|||||||
"quote": "Whenever dots are used as label separators, the following characters MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61(halfwidth ideographic full stop)"
|
"quote": "Whenever dots are used as label separators, the following characters MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61(halfwidth ideographic full stop)"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "idn-hostname"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "idn-hostname"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1539,9 +1579,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of IP addresses",
|
"description": "validation of IP addresses",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "ipv4"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "ipv4"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1629,9 +1673,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of IPv6 addresses",
|
"description": "validation of IPv6 addresses",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "ipv6"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "ipv6"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1838,9 +1886,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of IRI References",
|
"description": "validation of IRI References",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "iri-reference"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "iri-reference"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1912,9 +1964,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of IRIs",
|
"description": "validation of IRIs",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "iri"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "iri"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1996,9 +2052,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of JSON-pointers (JSON String Representation)",
|
"description": "validation of JSON-pointers (JSON String Representation)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "json-pointer"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "json-pointer"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2195,9 +2255,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of regular expressions",
|
"description": "validation of regular expressions",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "regex"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "regex"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2244,9 +2308,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of Relative JSON Pointers (RJP)",
|
"description": "validation of Relative JSON Pointers (RJP)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "relative-json-pointer"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "relative-json-pointer"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2343,9 +2411,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of time strings",
|
"description": "validation of time strings",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "time"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "time"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2582,9 +2654,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "unknown format",
|
"description": "unknown format",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "unknown"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "unknown"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2626,9 +2702,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of URI References",
|
"description": "validation of URI References",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "uri-reference"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "uri-reference"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2710,9 +2790,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "format: uri-template",
|
"description": "format: uri-template",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "uri-template"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "uri-template"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2769,9 +2853,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validation of URIs",
|
"description": "validation of URIs",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "uri"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "uri"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2958,9 +3046,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "uuid format",
|
"description": "uuid format",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "uuid"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "uuid"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -3077,9 +3169,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "period format",
|
"description": "period format",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"format": "period"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"format": "period"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
330
tests/fixtures/if-then-else.json
vendored
330
tests/fixtures/if-then-else.json
vendored
@ -1,11 +1,15 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "ignore if without then or else",
|
"description": "ignore if without then or else",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": {
|
{
|
||||||
"const": 0
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"if": {
|
||||||
|
"const": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -22,11 +26,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "ignore then without if",
|
"description": "ignore then without if",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"then": {
|
{
|
||||||
"const": 0
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"then": {
|
||||||
|
"const": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -43,11 +51,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "ignore else without if",
|
"description": "ignore else without if",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"else": {
|
{
|
||||||
"const": 0
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"else": {
|
||||||
|
"const": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -64,14 +76,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "if and then without else",
|
"description": "if and then without else",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": {
|
{
|
||||||
"exclusiveMaximum": 0
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"if": {
|
||||||
"then": {
|
"exclusiveMaximum": 0
|
||||||
"minimum": -10
|
},
|
||||||
}
|
"then": {
|
||||||
|
"minimum": -10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -93,14 +109,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "if and else without then",
|
"description": "if and else without then",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": {
|
{
|
||||||
"exclusiveMaximum": 0
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"if": {
|
||||||
"else": {
|
"exclusiveMaximum": 0
|
||||||
"multipleOf": 2
|
},
|
||||||
}
|
"else": {
|
||||||
|
"multipleOf": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -122,17 +142,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "validate against correct branch, then vs else",
|
"description": "validate against correct branch, then vs else",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": {
|
{
|
||||||
"exclusiveMaximum": 0
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"if": {
|
||||||
"then": {
|
"exclusiveMaximum": 0
|
||||||
"minimum": -10
|
},
|
||||||
},
|
"then": {
|
||||||
"else": {
|
"minimum": -10
|
||||||
"multipleOf": 2
|
},
|
||||||
}
|
"else": {
|
||||||
|
"multipleOf": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -159,23 +183,27 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "non-interference across combined schemas",
|
"description": "non-interference across combined schemas",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"if": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"exclusiveMaximum": 0
|
"allOf": [
|
||||||
}
|
{
|
||||||
},
|
"if": {
|
||||||
{
|
"exclusiveMaximum": 0
|
||||||
"then": {
|
}
|
||||||
"minimum": -10
|
},
|
||||||
}
|
{
|
||||||
},
|
"then": {
|
||||||
{
|
"minimum": -10
|
||||||
"else": {
|
}
|
||||||
"multipleOf": 2
|
},
|
||||||
}
|
{
|
||||||
|
"else": {
|
||||||
|
"multipleOf": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -194,15 +222,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "if with boolean schema true",
|
"description": "if with boolean schema true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": true,
|
{
|
||||||
"then": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"const": "then"
|
"if": true,
|
||||||
},
|
"then": {
|
||||||
"else": {
|
"const": "then"
|
||||||
"const": "else"
|
},
|
||||||
}
|
"else": {
|
||||||
|
"const": "else"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -219,15 +251,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "if with boolean schema false",
|
"description": "if with boolean schema false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": false,
|
{
|
||||||
"then": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"const": "then"
|
"if": false,
|
||||||
},
|
"then": {
|
||||||
"else": {
|
"const": "then"
|
||||||
"const": "else"
|
},
|
||||||
}
|
"else": {
|
||||||
|
"const": "else"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -244,17 +280,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "if appears at the end when serialized (keyword processing sequence)",
|
"description": "if appears at the end when serialized (keyword processing sequence)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"then": {
|
{
|
||||||
"const": "yes"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"then": {
|
||||||
"else": {
|
"const": "yes"
|
||||||
"const": "other"
|
},
|
||||||
},
|
"else": {
|
||||||
"if": {
|
"const": "other"
|
||||||
"maxLength": 4
|
},
|
||||||
}
|
"if": {
|
||||||
|
"maxLength": 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -281,11 +321,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "then: false fails when condition matches",
|
"description": "then: false fails when condition matches",
|
||||||
"schema": {
|
"database": {
|
||||||
"if": {
|
"schemas": [
|
||||||
"const": 1
|
{
|
||||||
},
|
"if": {
|
||||||
"then": false
|
"const": 1
|
||||||
|
},
|
||||||
|
"then": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -302,11 +346,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "else: false fails when condition does not match",
|
"description": "else: false fails when condition does not match",
|
||||||
"schema": {
|
"database": {
|
||||||
"if": {
|
"schemas": [
|
||||||
"const": 1
|
{
|
||||||
},
|
"if": {
|
||||||
"else": false
|
"const": 1
|
||||||
|
},
|
||||||
|
"else": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -323,29 +371,33 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in if-then-else",
|
"description": "extensible: true allows extra properties in if-then-else",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": {
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo": {
|
"if": {
|
||||||
"const": 1
|
"properties": {
|
||||||
}
|
"foo": {
|
||||||
},
|
"const": 1
|
||||||
"required": [
|
}
|
||||||
"foo"
|
},
|
||||||
]
|
"required": [
|
||||||
},
|
"foo"
|
||||||
"then": {
|
]
|
||||||
"properties": {
|
},
|
||||||
"bar": {
|
"then": {
|
||||||
"const": 2
|
"properties": {
|
||||||
}
|
"bar": {
|
||||||
},
|
"const": 2
|
||||||
"required": [
|
}
|
||||||
"bar"
|
},
|
||||||
]
|
"required": [
|
||||||
},
|
"bar"
|
||||||
"extensible": true
|
]
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -361,25 +413,29 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "strict by default with if-then properties",
|
"description": "strict by default with if-then properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"if": {
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo": {
|
"if": {
|
||||||
"const": 1
|
"properties": {
|
||||||
}
|
"foo": {
|
||||||
},
|
"const": 1
|
||||||
"required": [
|
}
|
||||||
"foo"
|
},
|
||||||
]
|
"required": [
|
||||||
},
|
"foo"
|
||||||
"then": {
|
]
|
||||||
"properties": {
|
},
|
||||||
"bar": {
|
"then": {
|
||||||
"const": 2
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"const": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
288
tests/fixtures/items.json
vendored
288
tests/fixtures/items.json
vendored
@ -1,11 +1,15 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "a schema given for items",
|
"description": "a schema given for items",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"items": {
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -44,9 +48,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "items with boolean schema (true)",
|
"description": "items with boolean schema (true)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"items": true
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"items": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -67,9 +75,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "items with boolean schema (false)",
|
"description": "items with boolean schema (false)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"items": false
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"items": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -90,39 +102,43 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "items and subitems",
|
"description": "items and subitems",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"$defs": {
|
{
|
||||||
"item": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$defs": {
|
||||||
|
"item": {
|
||||||
|
"type": "array",
|
||||||
|
"items": false,
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/sub-item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/sub-item"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sub-item": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": false,
|
"items": false,
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/sub-item"
|
"$ref": "#/$defs/item"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/sub-item"
|
"$ref": "#/$defs/item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/item"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"sub-item": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"foo"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "array",
|
|
||||||
"items": false,
|
|
||||||
"prefixItems": [
|
|
||||||
{
|
|
||||||
"$ref": "#/$defs/item"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/$defs/item"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$ref": "#/$defs/item"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -301,21 +317,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "nested items",
|
"description": "nested items",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "array",
|
{
|
||||||
"items": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "number"
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -418,14 +438,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "prefixItems with no additional items allowed",
|
"description": "prefixItems with no additional items allowed",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
{
|
||||||
{},
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
{},
|
"prefixItems": [
|
||||||
{}
|
{},
|
||||||
],
|
{},
|
||||||
"items": false
|
{}
|
||||||
|
],
|
||||||
|
"items": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -471,20 +495,24 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "items does not look in applicators, valid case",
|
"description": "items does not look in applicators, valid case",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"allOf": [
|
|
||||||
{
|
{
|
||||||
"prefixItems": [
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"allOf": [
|
||||||
{
|
{
|
||||||
"minimum": 3
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"minimum": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"items": {
|
||||||
|
"minimum": 5
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"items": {
|
|
||||||
"minimum": 5
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -507,16 +535,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "prefixItems validation adjusts the starting index for items",
|
"description": "prefixItems validation adjusts the starting index for items",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "string"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"items": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -540,12 +572,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "items with heterogeneous array",
|
"description": "items with heterogeneous array",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
{
|
||||||
{}
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
],
|
"prefixItems": [
|
||||||
"items": false
|
{}
|
||||||
|
],
|
||||||
|
"items": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -568,11 +604,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "items with null instance elements",
|
"description": "items with null instance elements",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"items": {
|
{
|
||||||
"type": "null"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"items": {
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -586,10 +626,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items (when items is false)",
|
"description": "extensible: true allows extra items (when items is false)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"items": false,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"items": false,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -603,12 +647,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties for items",
|
"description": "extensible: true allows extra properties for items",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"items": {
|
{
|
||||||
"minimum": 5
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"items": {
|
||||||
"extensible": true
|
"minimum": 5
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -630,10 +678,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "array: simple extensible array",
|
"description": "array: simple extensible array",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "array",
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "array",
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -653,10 +705,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "array: strict array",
|
"description": "array: strict array",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "array",
|
{
|
||||||
"extensible": false
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "array",
|
||||||
|
"extensible": false
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -675,12 +731,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "array: items extensible",
|
"description": "array: items extensible",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "array",
|
{
|
||||||
"items": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"extensible": true
|
"type": "array",
|
||||||
}
|
"items": {
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -701,13 +761,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "array: items strict",
|
"description": "array: items strict",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "array",
|
{
|
||||||
"items": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "object",
|
"type": "array",
|
||||||
"extensible": false
|
"items": {
|
||||||
}
|
"type": "object",
|
||||||
|
"extensible": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
114
tests/fixtures/masking.json
vendored
114
tests/fixtures/masking.json
vendored
@ -1,21 +1,25 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "Masking Properties",
|
"description": "Masking Properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$id": "mask_properties",
|
"schemas": [
|
||||||
"type": "object",
|
{
|
||||||
"properties": {
|
"$id": "mask_properties",
|
||||||
"foo": {
|
"type": "object",
|
||||||
"type": "string"
|
"properties": {
|
||||||
},
|
"foo": {
|
||||||
"bar": {
|
"type": "string"
|
||||||
"type": "integer"
|
},
|
||||||
|
"bar": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
],
|
||||||
|
"extensible": false
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"required": [
|
|
||||||
"foo"
|
|
||||||
],
|
|
||||||
"extensible": false
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -58,21 +62,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Masking Nested Objects",
|
"description": "Masking Nested Objects",
|
||||||
"schema": {
|
"database": {
|
||||||
"$id": "mask_nested",
|
"schemas": [
|
||||||
"type": "object",
|
{
|
||||||
"properties": {
|
"$id": "mask_nested",
|
||||||
"meta": {
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"meta": {
|
||||||
"type": "integer"
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensible": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extensible": false
|
"extensible": false
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": false
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -95,18 +103,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Masking Arrays",
|
"description": "Masking Arrays",
|
||||||
"schema": {
|
"database": {
|
||||||
"$id": "mask_arrays",
|
"schemas": [
|
||||||
"type": "object",
|
{
|
||||||
"properties": {
|
"$id": "mask_arrays",
|
||||||
"tags": {
|
"type": "object",
|
||||||
"type": "array",
|
"properties": {
|
||||||
"items": {
|
"tags": {
|
||||||
"type": "string"
|
"type": "array",
|
||||||
}
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensible": false
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": false
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -129,23 +141,27 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Masking Tuple Arrays (prefixItems)",
|
"description": "Masking Tuple Arrays (prefixItems)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$id": "mask_tuple",
|
"schemas": [
|
||||||
"type": "object",
|
{
|
||||||
"properties": {
|
"$id": "mask_tuple",
|
||||||
"coord": {
|
"type": "object",
|
||||||
"type": "array",
|
"properties": {
|
||||||
"prefixItems": [
|
"coord": {
|
||||||
{
|
"type": "array",
|
||||||
"type": "number"
|
"prefixItems": [
|
||||||
},
|
{
|
||||||
{
|
"type": "number"
|
||||||
"type": "number"
|
},
|
||||||
|
{
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
|
"extensible": false
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": false
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
86
tests/fixtures/maxContains.json
vendored
86
tests/fixtures/maxContains.json
vendored
@ -1,10 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "maxContains without contains is ignored",
|
"description": "maxContains without contains is ignored",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxContains": 1,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxContains": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -26,13 +30,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxContains with contains",
|
"description": "maxContains with contains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"maxContains": 1,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"maxContains": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -76,13 +84,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxContains with contains, value with a decimal",
|
"description": "maxContains with contains, value with a decimal",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"maxContains": 1.0,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"maxContains": 1.0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -104,14 +116,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minContains < maxContains",
|
"description": "minContains < maxContains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"minContains": 1,
|
"const": 1
|
||||||
"maxContains": 3,
|
},
|
||||||
"extensible": true
|
"minContains": 1,
|
||||||
|
"maxContains": 3,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -141,13 +157,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows non-matching items in maxContains",
|
"description": "extensible: true allows non-matching items in maxContains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"maxContains": 1,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"maxContains": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
36
tests/fixtures/maxItems.json
vendored
36
tests/fixtures/maxItems.json
vendored
@ -1,10 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "maxItems validation",
|
"description": "maxItems validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxItems": 2,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxItems": 2,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -40,10 +44,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxItems validation with a decimal",
|
"description": "maxItems validation with a decimal",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxItems": 2.0,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxItems": 2.0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -66,10 +74,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items in maxItems (but counted)",
|
"description": "extensible: true allows extra items in maxItems (but counted)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxItems": 2,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxItems": 2,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
22
tests/fixtures/maxLength.json
vendored
22
tests/fixtures/maxLength.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "maxLength validation",
|
"description": "maxLength validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxLength": 2
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxLength": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -35,9 +39,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxLength validation with a decimal",
|
"description": "maxLength validation with a decimal",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxLength": 2.0
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxLength": 2.0
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -52,4 +60,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
48
tests/fixtures/maxProperties.json
vendored
48
tests/fixtures/maxProperties.json
vendored
@ -1,10 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "maxProperties validation",
|
"description": "maxProperties validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxProperties": 2,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxProperties": 2,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -54,10 +58,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxProperties validation with a decimal",
|
"description": "maxProperties validation with a decimal",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxProperties": 2.0,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxProperties": 2.0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -80,10 +88,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxProperties = 0 means the object is empty",
|
"description": "maxProperties = 0 means the object is empty",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxProperties": 0,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxProperties": 0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -102,10 +114,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in maxProperties (though maxProperties still counts them!)",
|
"description": "extensible: true allows extra properties in maxProperties (though maxProperties still counts them!)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maxProperties": 2,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maxProperties": 2,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
24
tests/fixtures/maximum.json
vendored
24
tests/fixtures/maximum.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "maximum validation",
|
"description": "maximum validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maximum": 3.0
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maximum": 3.0
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -30,11 +34,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maximum validation with unsigned integer",
|
"description": "maximum validation with unsigned integer",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"maximum": 300
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"maximum": 300
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "below the maximum is invalid",
|
"description": "below the maximum is invalid",
|
||||||
"data": 299.97,
|
"data": 299.97,
|
||||||
@ -57,4 +65,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
150
tests/fixtures/merge.json
vendored
150
tests/fixtures/merge.json
vendored
@ -1,23 +1,27 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "merging: properties accumulate",
|
"description": "merging: properties accumulate",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"$defs": {
|
{
|
||||||
"base": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$defs": {
|
||||||
|
"base": {
|
||||||
|
"properties": {
|
||||||
|
"base_prop": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$ref": "#/$defs/base",
|
||||||
"properties": {
|
"properties": {
|
||||||
"base_prop": {
|
"child_prop": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"$ref": "#/$defs/base",
|
|
||||||
"properties": {
|
|
||||||
"child_prop": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -46,28 +50,32 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "merging: required fields accumulate",
|
"description": "merging: required fields accumulate",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"$defs": {
|
{
|
||||||
"base": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$defs": {
|
||||||
|
"base": {
|
||||||
|
"properties": {
|
||||||
|
"a": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"a"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$ref": "#/$defs/base",
|
||||||
"properties": {
|
"properties": {
|
||||||
"a": {
|
"b": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"a"
|
"b"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$ref": "#/$defs/base",
|
|
||||||
"properties": {
|
|
||||||
"b": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"b"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -109,36 +117,40 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "merging: dependencies accumulate",
|
"description": "merging: dependencies accumulate",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"$defs": {
|
{
|
||||||
"base": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$defs": {
|
||||||
|
"base": {
|
||||||
|
"properties": {
|
||||||
|
"trigger": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"base_dep": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"trigger": [
|
||||||
|
"base_dep"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$ref": "#/$defs/base",
|
||||||
"properties": {
|
"properties": {
|
||||||
"trigger": {
|
"child_dep": {
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"base_dep": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"trigger": [
|
"trigger": [
|
||||||
"base_dep"
|
"child_dep"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"$ref": "#/$defs/base",
|
|
||||||
"properties": {
|
|
||||||
"child_dep": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"trigger": [
|
|
||||||
"child_dep"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -182,32 +194,36 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "merging: form and display do NOT merge",
|
"description": "merging: form and display do NOT merge",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"$defs": {
|
{
|
||||||
"base": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$defs": {
|
||||||
|
"base": {
|
||||||
|
"properties": {
|
||||||
|
"a": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"b": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"form": [
|
||||||
|
"a",
|
||||||
|
"b"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$ref": "#/$defs/base",
|
||||||
"properties": {
|
"properties": {
|
||||||
"a": {
|
"c": {
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"b": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"form": [
|
"form": [
|
||||||
"a",
|
"c"
|
||||||
"b"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$ref": "#/$defs/base",
|
|
||||||
"properties": {
|
|
||||||
"c": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"form": [
|
|
||||||
"c"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
|
|||||||
162
tests/fixtures/minContains.json
vendored
162
tests/fixtures/minContains.json
vendored
@ -1,10 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "minContains without contains is ignored",
|
"description": "minContains without contains is ignored",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minContains": 1,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minContains": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -23,13 +27,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minContains=1 with contains",
|
"description": "minContains=1 with contains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"minContains": 1,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"minContains": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -71,13 +79,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minContains=2 with contains",
|
"description": "minContains=2 with contains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"minContains": 2,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"minContains": 2,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -130,13 +142,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minContains=2 with contains with a decimal value",
|
"description": "minContains=2 with contains with a decimal value",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"minContains": 2.0,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"minContains": 2.0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -158,14 +174,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxContains = minContains",
|
"description": "maxContains = minContains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"maxContains": 2,
|
"const": 1
|
||||||
"minContains": 2,
|
},
|
||||||
"extensible": true
|
"maxContains": 2,
|
||||||
|
"minContains": 2,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -201,14 +221,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "maxContains < minContains",
|
"description": "maxContains < minContains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"maxContains": 1,
|
"const": 1
|
||||||
"minContains": 3,
|
},
|
||||||
"extensible": true
|
"maxContains": 1,
|
||||||
|
"minContains": 3,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -244,13 +268,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minContains = 0",
|
"description": "minContains = 0",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"minContains": 0,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"minContains": 0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -269,14 +297,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minContains = 0 with maxContains",
|
"description": "minContains = 0 with maxContains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"minContains": 0,
|
"const": 1
|
||||||
"maxContains": 1,
|
},
|
||||||
"extensible": true
|
"minContains": 0,
|
||||||
|
"maxContains": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -303,13 +335,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows non-matching items in minContains",
|
"description": "extensible: true allows non-matching items in minContains",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"contains": {
|
{
|
||||||
"const": 1
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"contains": {
|
||||||
"minContains": 1,
|
"const": 1
|
||||||
"extensible": true
|
},
|
||||||
|
"minContains": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
36
tests/fixtures/minItems.json
vendored
36
tests/fixtures/minItems.json
vendored
@ -1,10 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "minItems validation",
|
"description": "minItems validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minItems": 1,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minItems": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -36,10 +40,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minItems validation with a decimal",
|
"description": "minItems validation with a decimal",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minItems": 1.0,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minItems": 1.0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -59,10 +67,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items in minItems",
|
"description": "extensible: true allows extra items in minItems",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minItems": 1,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minItems": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
22
tests/fixtures/minLength.json
vendored
22
tests/fixtures/minLength.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "minLength validation",
|
"description": "minLength validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minLength": 2
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minLength": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -35,9 +39,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minLength validation with a decimal",
|
"description": "minLength validation with a decimal",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minLength": 2.0
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minLength": 2.0
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -52,4 +60,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
36
tests/fixtures/minProperties.json
vendored
36
tests/fixtures/minProperties.json
vendored
@ -1,10 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "minProperties validation",
|
"description": "minProperties validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minProperties": 1,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minProperties": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -46,10 +50,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minProperties validation with a decimal",
|
"description": "minProperties validation with a decimal",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minProperties": 1.0,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minProperties": 1.0,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -69,10 +77,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in minProperties",
|
"description": "extensible: true allows extra properties in minProperties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minProperties": 1,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minProperties": 1,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
22
tests/fixtures/minimum.json
vendored
22
tests/fixtures/minimum.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "minimum validation",
|
"description": "minimum validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minimum": 1.1
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minimum": 1.1
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -30,9 +34,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "minimum validation with signed integer",
|
"description": "minimum validation with signed integer",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"minimum": -2
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"minimum": -2
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -72,4 +80,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
42
tests/fixtures/multipleOf.json
vendored
42
tests/fixtures/multipleOf.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "by int",
|
"description": "by int",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"multipleOf": 2
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"multipleOf": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -25,9 +29,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "by number",
|
"description": "by number",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"multipleOf": 1.5
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"multipleOf": 1.5
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -49,9 +57,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "by small number",
|
"description": "by small number",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"multipleOf": 0.0001
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"multipleOf": 0.0001
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -68,10 +80,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "small multiple of large integer",
|
"description": "small multiple of large integer",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "integer",
|
{
|
||||||
"multipleOf": 1e-8
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "integer",
|
||||||
|
"multipleOf": 1e-8
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
196
tests/fixtures/not.json
vendored
196
tests/fixtures/not.json
vendored
@ -1,11 +1,15 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "not",
|
"description": "not",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": {
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"not": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -22,14 +26,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "not multiple types",
|
"description": "not multiple types",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": {
|
{
|
||||||
"type": [
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"integer",
|
"not": {
|
||||||
"boolean"
|
"type": [
|
||||||
]
|
"integer",
|
||||||
}
|
"boolean"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -51,17 +59,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "not more complex schema",
|
"description": "not more complex schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": {
|
{
|
||||||
"type": "object",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"properties": {
|
"not": {
|
||||||
"foo": {
|
"type": "object",
|
||||||
"type": "string"
|
"properties": {
|
||||||
}
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -87,13 +99,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "forbidden property",
|
"description": "forbidden property",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"not": {}
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"not": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -113,9 +129,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "forbid everything with empty schema",
|
"description": "forbid everything with empty schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": {}
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"not": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -171,9 +191,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "forbid everything with boolean schema true",
|
"description": "forbid everything with boolean schema true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": true
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"not": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -229,10 +253,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "allow everything with boolean schema false",
|
"description": "allow everything with boolean schema false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": false,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"not": false,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -288,11 +316,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "double negation",
|
"description": "double negation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": {
|
{
|
||||||
"not": {}
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"not": {
|
||||||
|
"not": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -304,12 +336,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in not",
|
"description": "extensible: true allows extra properties in not",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": {
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"not": {
|
||||||
"extensible": true
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -323,11 +359,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: false (default) forbids extra properties in not",
|
"description": "extensible: false (default) forbids extra properties in not",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"not": {
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"not": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -341,17 +381,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "property next to not (extensible: true)",
|
"description": "property next to not (extensible: true)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"bar": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"not": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"not": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -366,16 +410,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "property next to not (extensible: false)",
|
"description": "property next to not (extensible: false)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"bar": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"not": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"not": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
330
tests/fixtures/oneOf.json
vendored
330
tests/fixtures/oneOf.json
vendored
@ -1,14 +1,18 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "oneOf",
|
"description": "oneOf",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"minimum": 2
|
"type": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minimum": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -37,15 +41,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with base schema",
|
"description": "oneOf with base schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "string",
|
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"minLength": 2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"type": "string",
|
||||||
{
|
"oneOf": [
|
||||||
"maxLength": 4
|
{
|
||||||
|
"minLength": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"maxLength": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -69,12 +77,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with boolean schemas, all true",
|
"description": "oneOf with boolean schemas, all true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
true,
|
"oneOf": [
|
||||||
true
|
true,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -87,12 +99,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with boolean schemas, one true",
|
"description": "oneOf with boolean schemas, one true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false,
|
"oneOf": [
|
||||||
false
|
true,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -105,12 +121,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with boolean schemas, more than one true",
|
"description": "oneOf with boolean schemas, more than one true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
true,
|
"oneOf": [
|
||||||
false
|
true,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -123,12 +143,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with boolean schemas, all false",
|
"description": "oneOf with boolean schemas, all false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
{
|
||||||
false,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false,
|
"oneOf": [
|
||||||
false
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -141,27 +165,31 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf complex types",
|
"description": "oneOf complex types",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": {
|
"oneOf": [
|
||||||
"type": "integer"
|
{
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"bar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"foo": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"foo"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -201,13 +229,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with empty schema",
|
"description": "oneOf with empty schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"type": "number"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"oneOf": [
|
||||||
{}
|
{
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -225,25 +257,29 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with required",
|
"description": "oneOf with required",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"foo": true,
|
|
||||||
"bar": true,
|
|
||||||
"baz": true
|
|
||||||
},
|
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"required": [
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo",
|
"type": "object",
|
||||||
"bar"
|
"properties": {
|
||||||
]
|
"foo": true,
|
||||||
},
|
"bar": true,
|
||||||
{
|
"baz": true
|
||||||
"required": [
|
},
|
||||||
"foo",
|
"oneOf": [
|
||||||
"baz"
|
{
|
||||||
|
"required": [
|
||||||
|
"foo",
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"required": [
|
||||||
|
"foo",
|
||||||
|
"baz"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -294,21 +330,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with required (extensible)",
|
"description": "oneOf with required (extensible)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "object",
|
|
||||||
"extensible": true,
|
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"required": [
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo",
|
"type": "object",
|
||||||
"bar"
|
"extensible": true,
|
||||||
]
|
"oneOf": [
|
||||||
},
|
{
|
||||||
{
|
"required": [
|
||||||
"required": [
|
"foo",
|
||||||
"foo",
|
"bar"
|
||||||
"baz"
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"required": [
|
||||||
|
"foo",
|
||||||
|
"baz"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -359,24 +399,28 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "oneOf with missing optional property",
|
"description": "oneOf with missing optional property",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": true,
|
"oneOf": [
|
||||||
"baz": true
|
{
|
||||||
},
|
"properties": {
|
||||||
"required": [
|
"bar": true,
|
||||||
"bar"
|
"baz": true
|
||||||
]
|
},
|
||||||
},
|
"required": [
|
||||||
{
|
"bar"
|
||||||
"properties": {
|
]
|
||||||
"foo": true
|
},
|
||||||
},
|
{
|
||||||
"required": [
|
"properties": {
|
||||||
"foo"
|
"foo": true
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -415,13 +459,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "nested oneOf, to check validation semantics",
|
"description": "nested oneOf, to check validation semantics",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"type": "null"
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -442,31 +490,35 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in oneOf",
|
"description": "extensible: true allows extra properties in oneOf",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"oneOf": [
|
|
||||||
{
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": {
|
"oneOf": [
|
||||||
"type": "integer"
|
{
|
||||||
|
"properties": {
|
||||||
|
"bar": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"bar"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
],
|
||||||
"required": [
|
"extensible": true
|
||||||
"bar"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"foo": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"foo"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
22
tests/fixtures/pattern.json
vendored
22
tests/fixtures/pattern.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "pattern validation",
|
"description": "pattern validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"pattern": "^a*$"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"pattern": "^a*$"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -50,9 +54,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "pattern is not anchored",
|
"description": "pattern is not anchored",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"pattern": "a+"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"pattern": "a+"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -62,4 +70,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
114
tests/fixtures/patternProperties.json
vendored
114
tests/fixtures/patternProperties.json
vendored
@ -1,14 +1,18 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "patternProperties validates properties matching a regex",
|
"description": "patternProperties validates properties matching a regex",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"patternProperties": {
|
{
|
||||||
"f.*o": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "integer"
|
"patternProperties": {
|
||||||
|
"f.*o": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"items": {}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"items": {}
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -71,16 +75,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "multiple simultaneous patternProperties are validated",
|
"description": "multiple simultaneous patternProperties are validated",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"patternProperties": {
|
{
|
||||||
"a*": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "integer"
|
"patternProperties": {
|
||||||
},
|
"a*": {
|
||||||
"aaa*": {
|
"type": "integer"
|
||||||
"maximum": 20
|
},
|
||||||
|
"aaa*": {
|
||||||
|
"maximum": 20
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -131,17 +139,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "regexes are not anchored by default and are case sensitive",
|
"description": "regexes are not anchored by default and are case sensitive",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"patternProperties": {
|
{
|
||||||
"[0-9]{2,}": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "boolean"
|
"patternProperties": {
|
||||||
},
|
"[0-9]{2,}": {
|
||||||
"X_": {
|
"type": "boolean"
|
||||||
"type": "string"
|
},
|
||||||
|
"X_": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -176,12 +188,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "patternProperties with boolean schemas",
|
"description": "patternProperties with boolean schemas",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"patternProperties": {
|
{
|
||||||
"f.*": true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"b.*": false
|
"patternProperties": {
|
||||||
}
|
"f.*": true,
|
||||||
|
"b.*": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -222,13 +238,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "patternProperties with null valued instance properties",
|
"description": "patternProperties with null valued instance properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"patternProperties": {
|
{
|
||||||
"^.*bar$": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "null"
|
"patternProperties": {
|
||||||
|
"^.*bar$": {
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -242,14 +262,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties NOT matching pattern",
|
"description": "extensible: true allows extra properties NOT matching pattern",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"patternProperties": {
|
{
|
||||||
"f.*o": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "integer"
|
"patternProperties": {
|
||||||
|
"f.*o": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
76
tests/fixtures/prefixItems.json
vendored
76
tests/fixtures/prefixItems.json
vendored
@ -1,14 +1,18 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "a schema given for prefixItems",
|
"description": "a schema given for prefixItems",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "string"
|
"type": "integer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -63,11 +67,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "prefixItems with boolean schemas",
|
"description": "prefixItems with boolean schemas",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
{
|
||||||
true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
false
|
"prefixItems": [
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -95,14 +103,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "additional items are allowed by default",
|
"description": "additional items are allowed by default",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -118,11 +130,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "prefixItems with null instance elements",
|
"description": "prefixItems with null instance elements",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "null"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -138,14 +154,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items with prefixItems",
|
"description": "extensible: true allows extra items with prefixItems",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"prefixItems": [
|
||||||
|
{
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
294
tests/fixtures/properties.json
vendored
294
tests/fixtures/properties.json
vendored
@ -1,16 +1,20 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "object properties validation",
|
"description": "object properties validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "integer"
|
"properties": {
|
||||||
},
|
"foo": {
|
||||||
"bar": {
|
"type": "integer"
|
||||||
"type": "string"
|
},
|
||||||
|
"bar": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -56,12 +60,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "properties with boolean schema",
|
"description": "properties with boolean schema",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": true,
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": false
|
"properties": {
|
||||||
}
|
"foo": true,
|
||||||
|
"bar": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -95,28 +103,32 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "properties with escaped characters",
|
"description": "properties with escaped characters",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo\nbar": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "number"
|
"properties": {
|
||||||
},
|
"foo\nbar": {
|
||||||
"foo\"bar": {
|
"type": "number"
|
||||||
"type": "number"
|
},
|
||||||
},
|
"foo\"bar": {
|
||||||
"foo\\bar": {
|
"type": "number"
|
||||||
"type": "number"
|
},
|
||||||
},
|
"foo\\bar": {
|
||||||
"foo\rbar": {
|
"type": "number"
|
||||||
"type": "number"
|
},
|
||||||
},
|
"foo\rbar": {
|
||||||
"foo\tbar": {
|
"type": "number"
|
||||||
"type": "number"
|
},
|
||||||
},
|
"foo\tbar": {
|
||||||
"foo\fbar": {
|
"type": "number"
|
||||||
"type": "number"
|
},
|
||||||
|
"foo\fbar": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -147,13 +159,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "properties with null valued instance properties",
|
"description": "properties with null valued instance properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "null"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -168,23 +184,27 @@
|
|||||||
{
|
{
|
||||||
"description": "properties whose names are Javascript object property names",
|
"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.",
|
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"__proto__": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"toString": {
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"length": {
|
"__proto__": {
|
||||||
"type": "string"
|
"type": "number"
|
||||||
|
},
|
||||||
|
"toString": {
|
||||||
|
"properties": {
|
||||||
|
"length": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"constructor": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"constructor": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -242,14 +262,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties",
|
"description": "extensible: true allows extra properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "integer"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -264,13 +288,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "strict by default: extra properties invalid",
|
"description": "strict by default: extra properties invalid",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -285,17 +313,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "inheritance: nested object inherits strictness from strict parent",
|
"description": "inheritance: nested object inherits strictness from strict parent",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"nested": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"nested": {
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -312,18 +344,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "override: nested object allows extra properties if extensible: true",
|
"description": "override: nested object allows extra properties if extensible: true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"nested": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"extensible": true,
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"nested": {
|
||||||
"type": "string"
|
"extensible": true,
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -340,18 +376,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "inheritance: nested object inherits looseness from loose parent",
|
"description": "inheritance: nested object inherits looseness from loose parent",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"extensible": true,
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"nested": {
|
"extensible": true,
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"nested": {
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -368,19 +408,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "override: nested object enforces strictness if extensible: false",
|
"description": "override: nested object enforces strictness if extensible: false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"extensible": true,
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"nested": {
|
"extensible": true,
|
||||||
"extensible": false,
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"nested": {
|
||||||
"type": "string"
|
"extensible": false,
|
||||||
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -397,20 +441,24 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "arrays: inline items inherit strictness from strict parent",
|
"description": "arrays: inline items inherit strictness from strict parent",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"list": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"type": "array",
|
"properties": {
|
||||||
"items": {
|
"list": {
|
||||||
"properties": {
|
"type": "array",
|
||||||
"foo": {
|
"items": {
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -429,21 +477,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "arrays: inline items inherit looseness from loose parent",
|
"description": "arrays: inline items inherit looseness from loose parent",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"extensible": true,
|
{
|
||||||
"properties": {
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"list": {
|
"extensible": true,
|
||||||
"type": "array",
|
"properties": {
|
||||||
"items": {
|
"list": {
|
||||||
"properties": {
|
"type": "array",
|
||||||
"foo": {
|
"items": {
|
||||||
"type": "string"
|
"properties": {
|
||||||
|
"foo": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
110
tests/fixtures/propertyNames.json
vendored
110
tests/fixtures/propertyNames.json
vendored
@ -1,12 +1,16 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "propertyNames validation",
|
"description": "propertyNames validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"propertyNames": {
|
{
|
||||||
"maxLength": 3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"propertyNames": {
|
||||||
"extensible": true
|
"maxLength": 3
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -54,12 +58,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "propertyNames validation with pattern",
|
"description": "propertyNames validation with pattern",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"propertyNames": {
|
{
|
||||||
"pattern": "^a+$"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"propertyNames": {
|
||||||
"extensible": true
|
"pattern": "^a+$"
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -87,10 +95,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "propertyNames with boolean schema true",
|
"description": "propertyNames with boolean schema true",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"propertyNames": true,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"propertyNames": true,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -109,10 +121,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "propertyNames with boolean schema false",
|
"description": "propertyNames with boolean schema false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"propertyNames": false,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"propertyNames": false,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -131,12 +147,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "propertyNames with const",
|
"description": "propertyNames with const",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"propertyNames": {
|
{
|
||||||
"const": "foo"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"propertyNames": {
|
||||||
"extensible": true
|
"const": "foo"
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -162,15 +182,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "propertyNames with enum",
|
"description": "propertyNames with enum",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"propertyNames": {
|
{
|
||||||
"enum": [
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo",
|
"propertyNames": {
|
||||||
"bar"
|
"enum": [
|
||||||
]
|
"foo",
|
||||||
},
|
"bar"
|
||||||
"extensible": true
|
]
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -204,12 +228,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties (checked by propertyNames)",
|
"description": "extensible: true allows extra properties (checked by propertyNames)",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"propertyNames": {
|
{
|
||||||
"maxLength": 3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"propertyNames": {
|
||||||
"extensible": true
|
"maxLength": 3
|
||||||
|
},
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
1414
tests/fixtures/puncs.json
vendored
1414
tests/fixtures/puncs.json
vendored
File diff suppressed because it is too large
Load Diff
1186
tests/fixtures/ref.json
vendored
1186
tests/fixtures/ref.json
vendored
File diff suppressed because it is too large
Load Diff
112
tests/fixtures/required.json
vendored
112
tests/fixtures/required.json
vendored
@ -1,14 +1,18 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "required validation",
|
"description": "required validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {},
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"bar": {}
|
"properties": {
|
||||||
},
|
"foo": {},
|
||||||
"required": [
|
"bar": {}
|
||||||
"foo"
|
},
|
||||||
|
"required": [
|
||||||
|
"foo"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -55,11 +59,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "required default validation",
|
"description": "required default validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {}
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
}
|
"properties": {
|
||||||
|
"foo": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -71,12 +79,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "required with empty array",
|
"description": "required with empty array",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"properties": {
|
{
|
||||||
"foo": {}
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"properties": {
|
||||||
"required": []
|
"foo": {}
|
||||||
|
},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -88,17 +100,21 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "required with escaped characters",
|
"description": "required with escaped characters",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"required": [
|
{
|
||||||
"foo\nbar",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"foo\"bar",
|
"required": [
|
||||||
"foo\\bar",
|
"foo\nbar",
|
||||||
"foo\rbar",
|
"foo\"bar",
|
||||||
"foo\tbar",
|
"foo\\bar",
|
||||||
"foo\fbar"
|
"foo\rbar",
|
||||||
],
|
"foo\tbar",
|
||||||
"extensible": true
|
"foo\fbar"
|
||||||
|
],
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -126,14 +142,18 @@
|
|||||||
{
|
{
|
||||||
"description": "required properties whose names are Javascript object property names",
|
"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.",
|
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"required": [
|
{
|
||||||
"__proto__",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"toString",
|
"required": [
|
||||||
"constructor"
|
"__proto__",
|
||||||
],
|
"toString",
|
||||||
"extensible": true
|
"constructor"
|
||||||
|
],
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -191,12 +211,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in required",
|
"description": "extensible: true allows extra properties in required",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"required": [
|
{
|
||||||
"foo"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
],
|
"required": [
|
||||||
"extensible": true
|
"foo"
|
||||||
|
],
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
146
tests/fixtures/type.json
vendored
146
tests/fixtures/type.json
vendored
@ -1,9 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "integer type matches integers",
|
"description": "integer type matches integers",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "integer"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -55,9 +59,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "number type matches numbers",
|
"description": "number type matches numbers",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "number"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -109,9 +117,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "string type matches strings",
|
"description": "string type matches strings",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "string"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -163,9 +175,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "object type matches objects",
|
"description": "object type matches objects",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "object"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -207,9 +223,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "array type matches arrays",
|
"description": "array type matches arrays",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "array"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -251,9 +271,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "boolean type matches booleans",
|
"description": "boolean type matches booleans",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "boolean"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -310,9 +334,13 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "null type matches only the null object",
|
"description": "null type matches only the null object",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "null"
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -369,11 +397,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "multiple types can be specified in an array",
|
"description": "multiple types can be specified in an array",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": [
|
{
|
||||||
"integer",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"string"
|
"type": [
|
||||||
|
"integer",
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -416,10 +448,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "type as array with one item",
|
"description": "type as array with one item",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": [
|
{
|
||||||
"string"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": [
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
@ -437,13 +473,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "type: array or object",
|
"description": "type: array or object",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": [
|
{
|
||||||
"array",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"object"
|
"type": [
|
||||||
],
|
"array",
|
||||||
"items": {}
|
"object"
|
||||||
|
],
|
||||||
|
"items": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -479,14 +519,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "type: array, object or null",
|
"description": "type: array, object or null",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": [
|
{
|
||||||
"array",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"object",
|
"type": [
|
||||||
"null"
|
"array",
|
||||||
],
|
"object",
|
||||||
"items": {}
|
"null"
|
||||||
|
],
|
||||||
|
"items": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -522,10 +566,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties",
|
"description": "extensible: true allows extra properties",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"type": "object",
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"type": "object",
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
343
tests/fixtures/typedRefs.json
vendored
Normal file
343
tests/fixtures/typedRefs.json
vendored
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"description": "Entities extending entities",
|
||||||
|
"database": {
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name": "entity",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity"
|
||||||
|
],
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "entity",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "entity"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "organization",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity",
|
||||||
|
"organization"
|
||||||
|
],
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "organization",
|
||||||
|
"$ref": "entity",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "person",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity",
|
||||||
|
"organization",
|
||||||
|
"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)",
|
||||||
|
"schema_id": "save_org.request",
|
||||||
|
"data": {
|
||||||
|
"id": "1",
|
||||||
|
"type": "person",
|
||||||
|
"name": "ACME"
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Valid organization against organization schema",
|
||||||
|
"schema_id": "save_org.request",
|
||||||
|
"data": {
|
||||||
|
"id": "2",
|
||||||
|
"type": "organization",
|
||||||
|
"name": "ACME"
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Invalid entity against organization schema (ancestor not allowed)",
|
||||||
|
"schema_id": "save_org.request",
|
||||||
|
"data": {
|
||||||
|
"id": "3",
|
||||||
|
"type": "entity"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Invalid generic type against organization schema",
|
||||||
|
"schema_id": "save_org.request",
|
||||||
|
"data": {
|
||||||
|
"id": "4",
|
||||||
|
"type": "generic_thing"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Ad-hocs extending entities (still entities with type magic)",
|
||||||
|
"database": {
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name": "entity",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity"
|
||||||
|
],
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "entity",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "entity"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "person",
|
||||||
|
"hierarchy": [
|
||||||
|
"entity",
|
||||||
|
"person"
|
||||||
|
],
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "person",
|
||||||
|
"$ref": "entity",
|
||||||
|
"properties": {
|
||||||
|
"first_name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"puncs": [
|
||||||
|
{
|
||||||
|
"name": "save_person_light",
|
||||||
|
"schemas": [
|
||||||
|
{
|
||||||
|
"$id": "person.light",
|
||||||
|
"$ref": "person",
|
||||||
|
"extensible": false,
|
||||||
|
"properties": {
|
||||||
|
"first_name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$id": "save_person_light.request",
|
||||||
|
"$ref": "person.light"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"description": "Valid person against person.light ad-hoc schema",
|
||||||
|
"schema_id": "save_person_light.request",
|
||||||
|
"data": {
|
||||||
|
"id": "1",
|
||||||
|
"type": "person",
|
||||||
|
"first_name": "John"
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Invalid person against person.light (strictness violation)",
|
||||||
|
"schema_id": "save_person_light.request",
|
||||||
|
"data": {
|
||||||
|
"id": "1",
|
||||||
|
"type": "person",
|
||||||
|
"first_name": "John",
|
||||||
|
"extra": "bad"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Invalid entity against person.light ad-hoc schema (ancestor not allowed)",
|
||||||
|
"schema_id": "save_person_light.request",
|
||||||
|
"data": {
|
||||||
|
"id": "1",
|
||||||
|
"type": "entity",
|
||||||
|
"first_name": "John"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"valid": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Invalid base address against us_address",
|
||||||
|
"schema_id": "save_address.request",
|
||||||
|
"data": {
|
||||||
|
"street": "123 Main",
|
||||||
|
"city": "Anytown"
|
||||||
|
},
|
||||||
|
"valid": 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"
|
||||||
|
},
|
||||||
|
"valid": 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"
|
||||||
|
},
|
||||||
|
"valid": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
132
tests/fixtures/uniqueItems.json
vendored
132
tests/fixtures/uniqueItems.json
vendored
@ -1,10 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"description": "uniqueItems validation",
|
"description": "uniqueItems validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"uniqueItems": true,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"uniqueItems": true,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -352,18 +356,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "uniqueItems with an array of items",
|
"description": "uniqueItems with an array of items",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"uniqueItems": true,
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"uniqueItems": true,
|
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -442,18 +450,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "uniqueItems with an array of items and additionalItems=false",
|
"description": "uniqueItems with an array of items and additionalItems=false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"uniqueItems": true,
|
||||||
|
"items": false
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"uniqueItems": true,
|
|
||||||
"items": false
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -501,10 +513,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "uniqueItems=false validation",
|
"description": "uniqueItems=false validation",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"uniqueItems": false,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"uniqueItems": false,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -683,18 +699,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "uniqueItems=false with an array of items",
|
"description": "uniqueItems=false with an array of items",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"uniqueItems": false,
|
||||||
|
"extensible": true
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"uniqueItems": false,
|
|
||||||
"extensible": true
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -773,18 +793,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "uniqueItems=false with an array of items and additionalItems=false",
|
"description": "uniqueItems=false with an array of items and additionalItems=false",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"prefixItems": [
|
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
},
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"uniqueItems": false,
|
||||||
|
"items": false
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"uniqueItems": false,
|
|
||||||
"items": false
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -832,10 +856,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items in uniqueItems",
|
"description": "extensible: true allows extra items in uniqueItems",
|
||||||
"schema": {
|
"database": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"schemas": [
|
||||||
"uniqueItems": true,
|
{
|
||||||
"extensible": true
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"uniqueItems": true,
|
||||||
|
"extensible": true
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
28
tests/lib.rs
28
tests/lib.rs
@ -1,4 +1,4 @@
|
|||||||
use jspg::*;
|
use ::jspg::*;
|
||||||
use pgrx::JsonB;
|
use pgrx::JsonB;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
@ -22,20 +22,22 @@ fn test_library_api() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 2. Cache schemas
|
// 2. Cache schemas
|
||||||
let puncs = json!([]);
|
let db_json = json!({
|
||||||
let types = json!([{
|
"puncs": [],
|
||||||
"schemas": [{
|
"enums": [],
|
||||||
"$id": "test_schema",
|
"types": [{
|
||||||
"type": "object",
|
"schemas": [{
|
||||||
"properties": {
|
"$id": "test_schema",
|
||||||
"name": { "type": "string" }
|
"type": "object",
|
||||||
},
|
"properties": {
|
||||||
"required": ["name"]
|
"name": { "type": "string" }
|
||||||
|
},
|
||||||
|
"required": ["name"]
|
||||||
|
}]
|
||||||
}]
|
}]
|
||||||
}]);
|
});
|
||||||
let enums = json!([]);
|
|
||||||
|
|
||||||
let cache_drop = cache_json_schemas(JsonB(enums), JsonB(types), JsonB(puncs));
|
let cache_drop = jspg_cache_database(JsonB(db_json));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache_drop.0,
|
cache_drop.0,
|
||||||
json!({
|
json!({
|
||||||
|
|||||||
Reference in New Issue
Block a user