use tiptap_rusty_parser::{Document, MarkSpec, NodeSpec, Schema, ViolationKind};
fn schema() -> Schema {
Schema::new()
.node("doc", NodeSpec::new().content(["paragraph", "heading"]))
.node("paragraph", NodeSpec::new().content(["text"]))
.node(
"heading",
NodeSpec::new()
.content(["text"])
.attrs(["level"])
.required_attrs(["level"]),
)
.node("text", NodeSpec::new().marks(["bold", "italic"]))
.mark("bold", MarkSpec::new())
.mark("italic", MarkSpec::new())
.mark(
"link",
MarkSpec::new().attrs(["href"]).required_attrs(["href"]),
)
}
fn doc(json: &str) -> Document {
Document::from_json_str(json).unwrap()
}
#[test]
fn valid_document() {
let d = doc(r#"{
"type":"doc","content":[
{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"T"}]},
{"type":"paragraph","content":[{"type":"text","text":"a","marks":[{"type":"bold"}]}]}
]}"#);
assert!(d.is_valid(&schema()));
assert_eq!(d.validate(&schema()), vec![]);
}
#[test]
fn unknown_node_type() {
let d = doc(r#"{"type":"doc","content":[{"type":"widget"}]}"#);
let v = d.validate(&schema());
assert!(v
.iter()
.any(|x| x.kind == ViolationKind::UnknownNodeType("widget".into()) && x.path == vec![0]));
}
#[test]
fn missing_node_type() {
let d = doc(r#"{"type":"doc","content":[{"attrs":{}}]}"#);
let v = d.validate(&schema());
assert!(v
.iter()
.any(|x| x.kind == ViolationKind::MissingNodeType && x.path == vec![0]));
}
#[test]
fn disallowed_child() {
let d = doc(r#"{
"type":"doc","content":[
{"type":"paragraph","content":[{"type":"heading","attrs":{"level":1}}]}
]}"#);
let v = d.validate(&schema());
assert!(v.iter().any(|x| x.path == vec![0]
&& x.kind
== ViolationKind::DisallowedChild {
parent: "paragraph".into(),
child: "heading".into()
}));
}
#[test]
fn unknown_and_disallowed_marks() {
let d = doc(r#"{
"type":"doc","content":[
{"type":"paragraph","content":[
{"type":"text","text":"x","marks":[{"type":"strike"}]}
]}
]}"#);
let v = d.validate(&schema());
assert!(v
.iter()
.any(|x| x.kind == ViolationKind::UnknownMark("strike".into())));
}
#[test]
fn disallowed_mark_on_node() {
let d = doc(r#"{
"type":"doc","content":[
{"type":"paragraph","content":[
{"type":"text","text":"x","marks":[{"type":"link","attrs":{"href":"u"}}]}
]}
]}"#);
let v = d.validate(&schema());
assert!(v.iter().any(|x| x.kind
== ViolationKind::DisallowedMark {
node: "text".into(),
mark: "link".into()
}));
}
#[test]
fn missing_required_attr() {
let d = doc(r#"{"type":"doc","content":[{"type":"heading","content":[]}]}"#);
let v = d.validate(&schema());
assert!(v.iter().any(|x| x.path == vec![0]
&& x.kind
== ViolationKind::MissingAttr {
key: "level".into()
}));
}
#[test]
fn unknown_attr() {
let d =
doc(r#"{"type":"doc","content":[{"type":"heading","attrs":{"level":1,"bogus":true}}]}"#);
let v = d.validate(&schema());
assert!(v.iter().any(|x| x.kind
== ViolationKind::UnknownAttr {
key: "bogus".into()
}));
}
#[test]
fn missing_mark_attr() {
let schema = Schema::new()
.node("doc", NodeSpec::new().content(["paragraph"]))
.node("paragraph", NodeSpec::new().content(["text"]))
.node("text", NodeSpec::new().marks(["link"]))
.mark(
"link",
MarkSpec::new().attrs(["href"]).required_attrs(["href"]),
);
let d = doc(r#"{
"type":"doc","content":[
{"type":"paragraph","content":[
{"type":"text","text":"x","marks":[{"type":"link"}]}
]}
]}"#);
let v = d.validate(&schema);
assert!(v
.iter()
.any(|x| x.kind == ViolationKind::MissingAttr { key: "href".into() }));
}
#[test]
fn json_schema_matches_builder() {
let json = r#"{
"nodes": {
"doc": { "content": ["paragraph","heading"] },
"paragraph": { "content": ["text"] },
"heading": { "content": ["text"], "attrs": ["level"], "required_attrs": ["level"] },
"text": { "marks": ["bold","italic"] }
},
"marks": {
"bold": {}, "italic": {},
"link": { "attrs": ["href"], "required_attrs": ["href"] }
}
}"#;
let from_json = Schema::from_json_str(json).unwrap();
let bad = doc(r#"{"type":"doc","content":[{"type":"heading"}]}"#);
assert_eq!(bad.validate(&from_json), bad.validate(&schema()));
assert!(!bad.is_valid(&from_json)); }