Skip to content

Commit

Permalink
Added tests for Serde
Browse files Browse the repository at this point in the history
  • Loading branch information
h7kanna committed Sep 17, 2024
1 parent fa8f906 commit 335647b
Show file tree
Hide file tree
Showing 2 changed files with 334 additions and 16 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ serde = { version = "1", features = ["derive"], optional = true }
[dev-dependencies]
env_logger = "0.11"
criterion = "0.5"
jaq-core = { version = "2.0.0-alpha" }
jaq-json = { version = "1.0.0-alpha", features = ["serde_json"] }
jaq-std = { version = "2.0.0-alpha" }
pretty_assertions = "1"
serde_json = { version = "1" }
swc_core = { version = "0.100", features = [
Expand Down
347 changes: 331 additions & 16 deletions tests/serde.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use markdown::mdast::Node;
use markdown::message::Message;
mod test_utils;

#[allow(unused)]
#[derive(Debug)]
enum Error {
Mdast(Message),
Assert(String),
Mdast(markdown::message::Message),
Serde(serde_json::Error),
}

#[cfg_attr(feature = "serde", test)]
fn serde() -> Result<(), Error> {
let source = markdown::to_mdast(
r#"---
fn serde_root() -> Result<(), Error> {
let source = r#"---
title: Serde
---
Expand Down Expand Up @@ -101,22 +100,338 @@ Here's a simple footnote,[^1] and here's a longer one.[^bignote]
Add as many paragraphs as you like.
"#,
&markdown::ParseOptions {
"#;

assert_jq(source, ".type", "root", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_blockquote() -> Result<(), Error> {
let source = r#"> a
"#;
assert_jq(source, ".children[0].type", "blockquote", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_footnote_definition() -> Result<(), Error> {
assert_jq("[^a]: b", ".children[0].type", "footnoteDefinition", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_mdx_jsx_flow_element() -> Result<(), Error> {
assert_jq("<a />", ".children[0].type", "mdxJsxFlowElement", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_mdx_jsx_flow_element_attributes() -> Result<(), Error> {
assert_jq(
"<a {...b}/>",
".children[0].attributes[0].value",
"...b",
None,
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_mdx_jsx_flow_element_attributes_expressions() -> Result<(), Error> {
let source = r#"<Test id={id} class="test" />"#;
assert_jq(
source,
".children[0].attributes[0].type",
"mdxJsxAttribute",
None,
)?;
assert_jq(source, ".children[0].attributes[0].name", "id", None)?;
assert_jq(
source,
".children[0].attributes[0].value.type",
"mdxJsxAttributeValueExpression",
None,
)?;
assert_jq(source, ".children[0].attributes[1].name", "class", None)?;
assert_jq(source, ".children[0].attributes[1].value", "test", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_list() -> Result<(), Error> {
assert_jq("* a", ".children[0].type", "list", None)?;
assert_jq("* a", ".children[0].children[0].type", "listItem", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_mdxjs_esm() -> Result<(), Error> {
let source = r#"
import Test from 'test';
"#;
assert_jq(source, ".children[0].type", "mdxjsEsm", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_toml() -> Result<(), Error> {
let source = r#"+++
a: b
+++
"#;
assert_jq(source, ".children[0].type", "toml", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_yaml() -> Result<(), Error> {
let source = r#"---
a: b
---
"#;
assert_jq(source, ".children[0].type", "yaml", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_break() -> Result<(), Error> {
let source = r#"a\
b
"#;
assert_jq(source, ".children[0].children[1].type", "break", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_inline_code() -> Result<(), Error> {
assert_jq("`a`", ".children[0].children[0].type", "inlineCode", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_inline_math() -> Result<(), Error> {
assert_jq("$a$", ".children[0].children[0].type", "inlineMath", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_delete() -> Result<(), Error> {
assert_jq("~~a~~", ".children[0].children[0].type", "delete", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_emphasis() -> Result<(), Error> {
assert_jq("*a*", ".children[0].children[0].type", "emphasis", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_mdx_text_expression() -> Result<(), Error> {
assert_jq(
"a {b}",
".children[0].children[1].type",
"mdxTextExpression",
None,
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_footnote_reference() -> Result<(), Error> {
let source = r#"Refer to [^a]
[^a]: b
"#;
assert_jq(
source,
".children[0].children[1].type",
"footnoteReference",
None,
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_html() -> Result<(), Error> {
assert_jq(
"<a>",
".children[0].type",
"html",
Some(markdown::ParseOptions {
constructs: markdown::Constructs::gfm(),
..markdown::ParseOptions::gfm()
}),
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_image() -> Result<(), Error> {
assert_jq("![a](b)", ".children[0].children[0].type", "image", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_image_reference() -> Result<(), Error> {
let source = r#"[x]: y
a ![x] b
"#;
assert_jq(
source,
".children[1].children[1].type",
"imageReference",
None,
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_mdx_jsx_text_element() -> Result<(), Error> {
assert_jq(
"text <b />",
".children[0].children[1].type",
"mdxJsxTextElement",
None,
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_link() -> Result<(), Error> {
assert_jq("link [a](b)", ".children[0].children[1].type", "link", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_link_reference() -> Result<(), Error> {
let source = r#"[x]: y
a [x] b
"#;
assert_jq(
source,
".children[1].children[1].type",
"linkReference",
None,
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_strong() -> Result<(), Error> {
assert_jq("**a**", ".children[0].children[0].type", "strong", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_text() -> Result<(), Error> {
assert_jq("a", ".children[0].children[0].type", "text", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_code() -> Result<(), Error> {
let source = r#"~~~
let a = b;
~~~
"#;
assert_jq(source, ".children[0].type", "code", None)?;
let source = r#"```
let a = b;
```
"#;
assert_jq(source, ".children[0].type", "code", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_math() -> Result<(), Error> {
let source = r#"$$
1 + 1 = 2
$$
"#;
assert_jq(source, ".children[0].type", "math", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_mdx_flow_expression() -> Result<(), Error> {
assert_jq("{a}", ".children[0].type", "mdxFlowExpression", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_heading() -> Result<(), Error> {
assert_jq("# a", ".children[0].type", "heading", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_table() -> Result<(), Error> {
let source = r#"| a | b |
|-----|-----|
| c11 | c12 |
| c21 | c22 |
"#;
assert_jq(source, ".children[0].type", "table", None)?;
assert_jq(source, ".children[0].children[0].type", "tableRow", None)?;
assert_jq(
source,
".children[0].children[0].children[0].type",
"tableCell",
None,
)
}

#[cfg_attr(feature = "serde", test)]
fn serde_thematic_break() -> Result<(), Error> {
assert_jq("***", ".children[0].type", "thematicBreak", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_definition() -> Result<(), Error> {
assert_jq("[a]: b", ".children[0].type", "definition", None)
}

#[cfg_attr(feature = "serde", test)]
fn serde_paragraph() -> Result<(), Error> {
assert_jq("a", ".children[0].type", "paragraph", None)
}

/// Assert serde of Mdast constructs
#[cfg(feature = "serde")]
fn assert_jq(
input: &str,
query: &str,
expected: &str,
options: Option<markdown::ParseOptions>,
) -> Result<(), Error> {
use jaq_core::{load, Ctx, Native, RcIter};
use jaq_json::Val;
use load::{Arena, File, Loader};
use serde_json::{json, Value};
// Parse Mdast with default options of MDX and GFM
use test_utils::swc::{parse_esm, parse_expression};
let source = markdown::to_mdast(
input,
&options.unwrap_or(markdown::ParseOptions {
constructs: markdown::Constructs {
frontmatter: true,
gfm_autolink_literal: true,
gfm_footnote_definition: true,
gfm_label_start_footnote: true,
gfm_strikethrough: true,
gfm_table: true,
gfm_task_list_item: true,
math_flow: true,
math_text: true,
..markdown::Constructs::mdx()
},
mdx_esm_parse: Some(Box::new(parse_esm)),
mdx_expression_parse: Some(Box::new(parse_expression)),
..markdown::ParseOptions::gfm()
},
}),
)
.map_err(Error::Mdast)?;

let value: String = serde_json::to_string(&source).map_err(Error::Serde)?;

let target: Node = serde_json::from_slice(value.as_bytes()).map_err(Error::Serde)?;

pretty_assertions::assert_eq!(source, target);

// Serialize to JSON
let source_value: Value = serde_json::to_value(&source).map_err(Error::Serde)?;
/*
println!(
"{}",
serde_json::to_string_pretty(&source).map_err(Error::Serde)?
);
*/
// Parse JSON with JQL using https://github.com/01mf02/jaq
let program = File {
path: "".into(),
code: query,
};
let loader = Loader::new([]);
let arena = Arena::default();
let modules = loader.load(&arena, program).unwrap();
let filter = jaq_core::Compiler::<_, Native<_>>::default()
.compile(modules)
.unwrap();
let inputs = RcIter::new(core::iter::empty());
let mut output = filter.run((Ctx::new([], &inputs), source_value.clone().into()));
// Assert serialization of construct
pretty_assertions::assert_eq!(output.next(), Some(Ok(Val::from(json!(expected)))));
pretty_assertions::assert_eq!(output.next(), None);
// Assert deserialization
pretty_assertions::assert_eq!(
source,
serde_json::from_value(source_value).map_err(Error::Serde)?
);
Ok(())
}

0 comments on commit 335647b

Please sign in to comment.