use liepress::ast::{NodeKind, parse_markdown};
#[test]
fn test_parse_unordered_list() {
let md = "- Item 1\n- Item 2\n- Item 3";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
assert_eq!(children.len(), 1);
match &children[0].kind {
NodeKind::List {
ordered, children, ..
} => {
assert!(!ordered);
assert_eq!(children.len(), 3);
}
_ => panic!("Expected List node"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_ordered_list() {
let md = "1. First\n2. Second\n3. Third";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => match &children[0].kind {
NodeKind::List { ordered, .. } => {
assert!(*ordered);
}
_ => panic!("Expected ordered List"),
},
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_nested_list() {
let md = "- Item 1\n - Sub 1\n - Sub 2\n- Item 2";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
match &children[0].kind {
NodeKind::List {
children: items, ..
} => {
assert_eq!(items.len(), 2);
match &items[0].kind {
NodeKind::ListItem { children } => {
assert!(children.len() > 1);
}
_ => panic!("Expected ListItem"),
}
}
_ => panic!("Expected List"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_code_block() {
let md = "```rust\nfn main() {}\n```";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
assert_eq!(children.len(), 1);
match &children[0].kind {
NodeKind::CodeBlock { lang, code } => {
assert_eq!(lang.as_deref(), Some("rust"));
assert_eq!(code, "fn main() {}");
}
_ => panic!("Expected CodeBlock"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_codeblock_without_lang() {
let md = "```\nsome code\n```";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => match &children[0].kind {
NodeKind::CodeBlock { lang, code } => {
assert!(lang.is_none());
assert_eq!(code, "some code");
}
_ => panic!("Expected CodeBlock"),
},
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_blockquote() {
let md = "> This is a quote";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
assert_eq!(children.len(), 1);
match &children[0].kind {
NodeKind::Blockquote { children } => {
assert!(!children.is_empty());
}
_ => panic!("Expected Blockquote"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_thematic_break() {
let md = "---";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
assert_eq!(children.len(), 1);
match &children[0].kind {
NodeKind::ThematicBreak => {}
_ => panic!("Expected ThematicBreak"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_inline_formatting() {
let md = "**bold** and *italic* and `code`";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
match &children[0].kind {
NodeKind::Paragraph { children } => {
assert!(!children.is_empty());
}
_ => panic!("Expected Paragraph"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_link() {
let md = "[link text](https://example.com)";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => match &children[0].kind {
NodeKind::Paragraph { children } => match &children[0].kind {
NodeKind::Link { url, .. } => {
assert_eq!(url, "https://example.com");
}
_ => panic!("Expected Link"),
},
_ => panic!("Expected Paragraph"),
},
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_image() {
let md = "";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => match &children[0].kind {
NodeKind::Paragraph { children } => match &children[0].kind {
NodeKind::Image { src, alt, .. } => {
assert_eq!(src, "image.png");
assert_eq!(alt, "alt text");
}
_ => panic!("Expected Image"),
},
_ => panic!("Expected Paragraph"),
},
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_unchecked_task_list() {
let md = "- [ ] Buy groceries\n- [ ] Clean the house";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
assert_eq!(children.len(), 1);
match &children[0].kind {
NodeKind::List {
ordered,
children: items,
..
} => {
assert!(!ordered);
assert_eq!(items.len(), 2);
match &items[0].kind {
NodeKind::TaskListItem { checked, children } => {
assert!(!checked, "First item should be unchecked");
assert!(!children.is_empty());
}
_ => panic!("Expected TaskListItem, got {:?}", items[0].kind),
}
match &items[1].kind {
NodeKind::TaskListItem { checked, .. } => {
assert!(!checked, "Second item should be unchecked");
}
_ => panic!("Expected TaskListItem"),
}
}
_ => panic!("Expected List node"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_checked_task_list() {
let md = "- [x] Completed task\n- [X] Another done";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
match &children[0].kind {
NodeKind::List {
children: items, ..
} => {
assert_eq!(items.len(), 2);
match &items[0].kind {
NodeKind::TaskListItem { checked, .. } => {
assert!(*checked, "First item should be checked");
}
_ => panic!("Expected TaskListItem"),
}
match &items[1].kind {
NodeKind::TaskListItem { checked, .. } => {
assert!(*checked, "Second item (with X) should be checked");
}
_ => panic!("Expected TaskListItem"),
}
}
_ => panic!("Expected List node"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_parse_mixed_task_list() {
let md = "- Regular item\n- [x] Task done\n- Another regular\n- [ ] Task pending";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
match &children[0].kind {
NodeKind::List {
children: items, ..
} => {
assert_eq!(items.len(), 4);
assert!(
matches!(items[0].kind, NodeKind::ListItem { .. }),
"Item 0 should be ListItem"
);
match &items[1].kind {
NodeKind::TaskListItem { checked, .. } => assert!(*checked),
_ => panic!("Item 1 should be TaskListItem"),
}
assert!(
matches!(items[2].kind, NodeKind::ListItem { .. }),
"Item 2 should be ListItem"
);
match &items[3].kind {
NodeKind::TaskListItem { checked, .. } => assert!(!*checked),
_ => panic!("Item 3 should be TaskListItem"),
}
}
_ => panic!("Expected List node"),
}
}
_ => panic!("Expected Document root"),
}
}
#[test]
fn test_task_list_text_content() {
use liepress::ast::collect_text;
let md = "- [ ] Buy groceries\n- [x] Pay bills";
let node = parse_markdown(md).unwrap();
let text = collect_text(&node);
assert!(text.contains("Buy groceries"));
assert!(text.contains("Pay bills"));
}
#[test]
fn test_task_list_with_nested_content() {
let md = "- [x] **Bold task**\n- [ ] *Italic subtask*";
let node = parse_markdown(md).unwrap();
match &node.kind {
NodeKind::Document { children } => {
match &children[0].kind {
NodeKind::List {
children: items, ..
} => {
assert_eq!(items.len(), 2);
match &items[0].kind {
NodeKind::TaskListItem { checked, children } => {
assert!(*checked);
assert!(!children.is_empty());
let has_paragraph_with_strong = children.iter().any(|c| {
if let NodeKind::Paragraph {
children: para_children,
} = &c.kind
{
para_children
.iter()
.any(|pc| matches!(pc.kind, NodeKind::Strong { .. }))
} else {
false
}
});
assert!(
has_paragraph_with_strong,
"Task item should contain Paragraph > Strong"
);
}
_ => panic!("Expected TaskListItem"),
}
match &items[1].kind {
NodeKind::TaskListItem { checked, children } => {
assert!(!*checked);
let has_paragraph_with_em = children.iter().any(|c| {
if let NodeKind::Paragraph {
children: para_children,
} = &c.kind
{
para_children
.iter()
.any(|pc| matches!(pc.kind, NodeKind::Emphasis { .. }))
} else {
false
}
});
assert!(
has_paragraph_with_em,
"Task item should contain Paragraph > Emphasis"
);
}
_ => panic!("Expected TaskListItem"),
}
}
_ => panic!("Expected List node"),
}
}
_ => panic!("Expected Document root"),
}
}