validate_json against consumer-provided JSON Schema (step 6)
- AlkTypeEngine::compile gains a 4th param json_schema: Option<&Value>. When Some, a standard jsonschema::Validator is built from the consumer-provided JSON Schema and stored for the JSON-validation path. When None, validate_json returns AlkTypeError::Schema and is_valid_json returns false (D-BAST-007). - validate_json / is_valid_json signatures unchanged (per semver contract). Behavior: they now validate against the consumer JSON Schema, not a custom-keyword validator built from the alktype schema. The BAST document is not involved in this path. - build_validator repurposed (deferred decision #2): same signature, now builds a standard jsonschema::Validator with no custom keywords. Behavioral break, not a type break. Re-export kept. - Removed the 19 jsonschema::Keyword implementations and the 4 define_*_validator! macros (dead on the bytes path since step 5, now dead on the JSON path too). The is_rfc3339_timestamp helper lives on in bast_validation.rs (already copied there in step 5). - All compile call sites updated to pass None for json_schema (the layout/read/write/validate_bytes tests don't need JSON validation). - New tests: validate_json accepts/rejects against consumer JSON Schema, returns Schema error when no JSON Schema supplied, is_valid_json false when no schema, independence from BAST doc, malformed JSON Schema build error, nested object JSON Schema. Verification: - cargo test --release: 409 pass (332 lib + 77 integration) - cargo clippy --all-targets -- -D warnings: clean - cargo build --target wasm32-unknown-unknown --release: clean - cargo doc --no-deps: clean
This commit is contained in:
1 parent
f853dafaf1
commit
ba7f8e1bad
8 files changed
+352
-1350
No files matched your search
+17
-17
@@ -31,7 +31,7 @@ fn mixed_fixed_struct_doc() -> serde_json::Value {
|
||||
#[test]
|
||||
fn compile_aligned_builds_engine_with_offset_map() -> Result<(), AlkTypeError> {
|
||||
let doc = mixed_fixed_struct_doc();
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
assert_eq!(engine.mode(), LayoutMode::Aligned);
|
||||
assert!(engine.offset_map().is_some());
|
||||
assert!(engine.layout_builder().is_none());
|
||||
@@ -42,7 +42,7 @@ fn compile_aligned_builds_engine_with_offset_map() -> Result<(), AlkTypeError> {
|
||||
#[test]
|
||||
fn compile_packed_builds_engine_with_builder_and_reader() -> Result<(), AlkTypeError> {
|
||||
let doc = mixed_fixed_struct_doc();
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None)?;
|
||||
assert_eq!(engine.mode(), LayoutMode::Packed);
|
||||
assert!(engine.offset_map().is_none());
|
||||
assert!(engine.layout_builder().is_some());
|
||||
@@ -66,21 +66,21 @@ fn compile_resolves_ref_fields() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let _engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed)?;
|
||||
let _engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_returns_schema_error_when_no_defs() {
|
||||
let doc = json!({ "type": "object", "properties": {} });
|
||||
let err = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned).unwrap_err();
|
||||
let err = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None).unwrap_err();
|
||||
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_returns_schema_error_for_missing_root() {
|
||||
let doc = json!({ "$defs": { "Other": { "kind": "struct", "fields": [] } } });
|
||||
let err = AlkTypeEngine::compile(&doc, "Missing", LayoutMode::Aligned).unwrap_err();
|
||||
let err = AlkTypeEngine::compile(&doc, "Missing", LayoutMode::Aligned, None).unwrap_err();
|
||||
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ fn endian_parsed_from_schema_big() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None)?;
|
||||
assert_eq!(engine.endian(), Endian::Big);
|
||||
Ok(())
|
||||
}
|
||||
@@ -110,7 +110,7 @@ fn endian_defaults_to_little() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None)?;
|
||||
assert_eq!(engine.endian(), Endian::Little);
|
||||
Ok(())
|
||||
}
|
||||
@@ -140,7 +140,7 @@ fn read_write_aligned_round_trips_all_fixed_size_kinds() -> Result<(), AlkTypeEr
|
||||
"E": { "kind": "enum", "values": ["A", "B", "C"] }
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let offset_map = engine.offset_map().expect("aligned mode has offset_map");
|
||||
let mut buffer = vec![0u8; offset_map.total_size()];
|
||||
|
||||
@@ -194,7 +194,7 @@ fn read_write_aligned_round_trips_string() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let offset_map = engine.offset_map().expect("aligned mode has offset_map");
|
||||
let mut buffer = vec![0u8; offset_map.total_size() + 64];
|
||||
engine.write_field(&mut buffer, "name", &FieldValue::String("hello world"))?;
|
||||
@@ -215,7 +215,7 @@ fn read_write_aligned_round_trips_bytes() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let offset_map = engine.offset_map().expect("aligned mode has offset_map");
|
||||
let payload = b"the quick brown fox".to_vec();
|
||||
let mut buffer = vec![0u8; offset_map.total_size() + payload.len()];
|
||||
@@ -237,7 +237,7 @@ fn read_field_returns_access_error_in_packed_mode() -> Result<(), AlkTypeError>
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None)?;
|
||||
let buffer = [0u8; 4];
|
||||
let err = engine.read_field(&buffer, "id").unwrap_err();
|
||||
assert!(matches!(err, AlkTypeError::Access { .. }), "got {err:?}");
|
||||
@@ -254,7 +254,7 @@ fn write_field_returns_access_error_in_packed_mode() -> Result<(), AlkTypeError>
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Packed, None)?;
|
||||
let mut buffer = [0u8; 4];
|
||||
let err = engine
|
||||
.write_field(&mut buffer, "id", &FieldValue::U32(1))
|
||||
@@ -273,7 +273,7 @@ fn read_field_returns_offset_error_for_missing_path() -> Result<(), AlkTypeError
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let buffer = [0u8; 8];
|
||||
let err = engine.read_field(&buffer, "missing").unwrap_err();
|
||||
assert!(matches!(err, AlkTypeError::Offset { .. }), "got {err:?}");
|
||||
@@ -290,7 +290,7 @@ fn write_field_returns_offset_error_for_missing_path() -> Result<(), AlkTypeErro
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let mut buffer = [0u8; 8];
|
||||
let err = engine
|
||||
.write_field(&mut buffer, "missing", &FieldValue::U32(1))
|
||||
@@ -311,7 +311,7 @@ fn read_field_returns_error_for_composite_types() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let buffer = [0u8; 8];
|
||||
let err = engine.read_field(&buffer, "vals").unwrap_err();
|
||||
assert!(
|
||||
@@ -331,7 +331,7 @@ fn write_field_returns_access_error_for_composite_value() -> Result<(), AlkTypeE
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let mut buffer = [0u8; 8];
|
||||
let err = engine
|
||||
.write_field(&mut buffer, "id", &FieldValue::Struct { start: 0, end: 4 })
|
||||
@@ -361,7 +361,7 @@ fn read_field_aligned_reads_nested_struct_byte_range() -> Result<(), AlkTypeErro
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let offset_map = engine.offset_map().expect("aligned mode");
|
||||
let mut buffer = vec![0u8; offset_map.total_size()];
|
||||
|
||||
|
||||
@@ -154,14 +154,14 @@ fn write_string_buffer_too_short_returns_access_error() {
|
||||
#[test]
|
||||
fn compile_missing_defs_returns_schema_error() {
|
||||
let doc = json!({ "type": "object", "properties": {} });
|
||||
let err = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned).unwrap_err();
|
||||
let err = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None).unwrap_err();
|
||||
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_missing_root_returns_schema_error() {
|
||||
let doc = json!({ "$defs": { "Other": { "kind": "struct", "fields": [] } } });
|
||||
let err = AlkTypeEngine::compile(&doc, "Missing", LayoutMode::Aligned).unwrap_err();
|
||||
let err = AlkTypeEngine::compile(&doc, "Missing", LayoutMode::Aligned, None).unwrap_err();
|
||||
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ fn fixed_size_round_trip_via_engine_aligned() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let offset_map = engine.offset_map().expect("aligned mode has offset_map");
|
||||
let mut buffer = vec![0u8; offset_map.total_size()];
|
||||
|
||||
@@ -129,7 +129,7 @@ fn string_round_trip_via_engine_aligned() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let offset_map = engine.offset_map().expect("aligned mode has offset_map");
|
||||
let mut buffer = vec![0u8; offset_map.total_size() + 64];
|
||||
engine.write_field(&mut buffer, "name", &FieldValue::String("hello"))?;
|
||||
@@ -254,7 +254,7 @@ fn nested_struct_round_trip_via_engine_aligned() -> Result<(), AlkTypeError> {
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned)?;
|
||||
let engine = AlkTypeEngine::compile(&doc, "S", LayoutMode::Aligned, None)?;
|
||||
let offset_map = engine.offset_map().expect("aligned mode");
|
||||
|
||||
assert_eq!(offset_map.get("header.version").unwrap().start, 0);
|
||||
|
||||
Reference in new issue
Block a user