use std::fs;
use std::path::Path;
use markplus_core::parse_document;
use serde_json::Value;
fn load_schema() -> Value {
let schema_path = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("schema")
.join("markplus-ast.v1.schema.json");
let raw = fs::read_to_string(&schema_path)
.unwrap_or_else(|e| panic!("Cannot read schema at {:?}: {}", schema_path, e));
serde_json::from_str(&raw).unwrap_or_else(|e| panic!("Schema is not valid JSON: {}", e))
}
fn assert_valid(schema: &Value, asset_json: &Value, label: &str) {
let validator = jsonschema::validator_for(schema)
.unwrap_or_else(|e| panic!("Schema failed to compile: {}", e));
let mut errors = validator.iter_errors(asset_json).peekable();
if errors.peek().is_some() {
println!(
"FAILING AST: {}",
serde_json::to_string_pretty(asset_json).unwrap()
);
let messages: Vec<String> = errors
.map(|e| format!(" • {} (at {})", e, e.instance_path()))
.collect();
panic!(
"Schema validation failed for {}:\n{}",
label,
messages.join("\n")
);
}
}
fn parse_to_value(path: &Path) -> Value {
let raw = fs::read_to_string(path).unwrap_or_else(|e| panic!("Cannot read {:?}: {}", path, e));
let asset =
parse_document(&raw).unwrap_or_else(|e| panic!("Parse failed for {:?}: {}", path, e));
let json_str = asset.to_json().expect("serialisation failed");
serde_json::from_str(&json_str).expect("round-trip JSON parse failed")
}
#[test]
fn sample_note_rfsoc_mixer_validates() {
let schema = load_schema();
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/samples/note_rfsoc_mixer.md");
let value = parse_to_value(&path);
assert_valid(&schema, &value, "note_rfsoc_mixer.md");
}
#[test]
fn sample_api_reference_validates() {
let schema = load_schema();
let path =
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/samples/md_api_reference_sample.md");
let value = parse_to_value(&path);
assert_valid(&schema, &value, "md_api_reference_sample.md");
}
#[test]
fn sample_release_notes_validates() {
let schema = load_schema();
let path =
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/samples/md_release_notes_sample.md");
let value = parse_to_value(&path);
assert_valid(&schema, &value, "md_release_notes_sample.md");
}
#[test]
fn sample_200kb_validates() {
let schema = load_schema();
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/samples/md_sample_file_200KB.md");
let value = parse_to_value(&path);
assert_valid(&schema, &value, "md_sample_file_200KB.md");
}
#[test]
fn full_feature_document_validates() {
let schema = load_schema();
let md = r#"---
title: Schema Coverage
tags: [test]
---
# Heading 1 { #h1 .class }
## Heading 2
Plain paragraph with **strong**, *em*, ~~del~~, ^sup^, ~sub~, `code`, $math$.
> [!NOTE]
> GFM alert with a [link](url){class=doc}.
> Regular blockquote.
- Tight list item one
- Tight item two
- Nested item
1. Ordered item one
2. Ordered item two
| Left | Center | Right |
| :--- | :----: | ----: |
| a | b | c |
| **x** | y | z |
```python execute=true
print("hello")
```
```mermaid theme=dark
graph TD; A --> B
```
{width=100}
Some :[widget]{tooltip text="hi"} inline.
[^1]: Footnote definition body.
Ref[^1].
- [ ] Task unchecked
- [x] Task checked
$$
\int_0^\infty e^{-x} dx
$$
<em>raw html</em>
"#;
let asset = parse_document(md).expect("parse failed");
let json_str = asset.to_json().expect("serialisation failed");
let value: Value = serde_json::from_str(&json_str).expect("json parse failed");
assert_valid(&schema, &value, "full_feature_document");
}
#[test]
fn site_asset_schema_field_is_1() {
let asset = parse_document("# Hi").unwrap();
let value: Value = serde_json::from_str(&asset.to_json().unwrap()).unwrap();
assert_eq!(value["schema"], 1, "schema field must equal 1");
}
#[test]
fn wrong_schema_version_fails_validation() {
let schema = load_schema();
let invalid = serde_json::json!({ "schema": 99, "ast": [] });
let validator = jsonschema::validator_for(&schema).unwrap();
assert!(
validator.validate(&invalid).is_err(),
"schema version 99 should fail validation"
);
}
#[test]
fn empty_document_validates() {
let schema = load_schema();
let asset = parse_document("").unwrap();
let value: Value = serde_json::from_str(&asset.to_json().unwrap()).unwrap();
assert_valid(&schema, &value, "empty document");
assert_eq!(value["ast"].as_array().unwrap().len(), 0);
}