use umd::parse;
use umd::parser::Icons;
#[test]
fn test_table_default_class() {
let input = "| Header |\n|--------|\n| Cell |";
let output = parse(input);
assert!(output.contains(r#"<table class="umd-list-table">"#));
}
#[test]
fn test_blockquote_default_class() {
let input = "> This is a quote";
let output = parse(input);
assert!(output.contains(r#"<blockquote class="umd-blockquote">"#));
}
#[test]
fn test_gfm_alert_note() {
let icons = Icons::default();
let input = "> [!NOTE]\n> This is an informational note";
let output = parse(input);
assert!(output.contains(r#"<aside class="umd-note umd-note-note" role="doc-notice note">"#));
assert!(output.contains(&format!(
r#"<p class="umd-note-title">{} Note</p>"#,
icons.note
)));
assert!(output.contains("This is an informational note"));
}
#[test]
fn test_gfm_alert_warning() {
let icons = Icons::default();
let input = "> [!WARNING]\n> Be careful here";
let output = parse(input);
assert!(output.contains(r#"<aside class="umd-note umd-note-warning">"#));
assert!(output.contains(&format!(
r#"<p class="umd-note-title">{} Warning</p>"#,
icons.warning
)));
}
#[test]
fn test_gfm_alert_tip() {
let icons = Icons::default();
let input = "> [!TIP]\n> Here's a helpful tip";
let output = parse(input);
assert!(output.contains(r#"<aside class="umd-note umd-note-tip" role="doc-tip note">"#));
assert!(output.contains(&format!(
r#"<p class="umd-note-title">{} Tip</p>"#,
icons.tip
)));
}
#[test]
fn test_color_class() {
let input = "&color(blue){Blue text};";
let output = parse(input);
assert!(output.contains(r#"class="umd-color-blue""#));
}
#[test]
fn test_hex_colors_are_disabled_by_default() {
let input = "&color(#FF5733){Custom hex color};";
let output = parse(input);
assert_eq!(output, "<p>Custom hex color</p>");
let mut options = umd::parser::ParserOptions::default();
options.allow_hex_colors = true;
let enabled = umd::parse_with_frontmatter_opts(input, &options).html;
assert!(enabled.contains(r#"style="color: #FF5733""#));
}
#[test]
fn test_color_custom_colors() {
let test_cases = vec![
("&color(blue){Blue text};", r#"class="umd-color-blue""#),
(
"&color(yellow){Yellow text};",
r#"class="umd-color-yellow""#,
),
("&color(teal){Teal text};", r#"class="umd-color-teal""#),
];
for (input, expected) in test_cases {
let output = parse(input);
assert!(
output.contains(expected),
"Failed for input: {} - output: {}",
input,
output
);
}
}
#[test]
fn test_block_color_custom_colors() {
let test_cases = vec![
("COLOR(blue): Blue block", "umd-color-blue"),
("COLOR(yellow): Yellow block", "umd-color-yellow"),
("COLOR(teal): Teal block", "umd-color-teal"),
];
for (input, expected_class) in test_cases {
let output = parse(input);
assert!(
output.contains(&format!(r#"class="{}""#, expected_class)),
"Failed for input: {} - output: {}",
input,
output
);
}
}
#[test]
fn test_color_background_custom_colors() {
let input = "&color(,blue){Text on blue background};";
let output = parse(input);
assert!(output.contains(r#"class="umd-bg-blue""#));
let input = "&color(cyan,yellow){Cyan text on yellow};";
let output = parse(input);
assert!(output.contains(r#"class="umd-color-cyan umd-bg-yellow""#));
}
#[test]
fn test_size_keyword_class() {
let input = "&size(lg){Medium text};";
let output = parse(input);
assert!(output.contains(r#"class="umd-text-size-lg""#));
}
#[test]
fn test_size_custom_value_rejected_by_default() {
let input = "&size(3rem){Large text};";
let output = parse(input);
assert_eq!(output, "<p>Large text</p>");
let mut options = umd::parser::ParserOptions::default();
options.allow_custom_font_size = true;
let enabled = umd::parse_with_frontmatter_opts(input, &options).html;
assert!(enabled.contains(r#"style="font-size: 3rem""#));
}
#[test]
fn test_block_color() {
let input = "COLOR(green): This is a green message";
let output = parse(input);
assert!(output.contains(r#"class="umd-color-green""#));
}
#[test]
fn test_block_size() {
let input = "SIZE(xl): Large heading text";
let output = parse(input);
assert!(output.contains(r#"class="umd-text-size-xl""#));
}
#[test]
fn test_block_alignment() {
let input = "CENTER: Centered text";
let output = parse(input);
assert!(output.contains(r#"class="umd-center""#));
}
#[test]
fn test_block_alignment_start_and_end() {
assert!(parse("START: Start text").contains(r#"class="umd-start""#));
assert!(parse("END: End text").contains(r#"class="umd-end""#));
}
#[test]
fn test_block_vertical_align_logical_names() {
assert!(parse("V-START: Top text").contains(r#"class="umd-v-start""#));
assert!(parse("V-CENTER: Middle text").contains(r#"class="umd-v-center""#));
assert!(parse("V-END: Bottom text").contains(r#"class="umd-v-end""#));
}
#[test]
fn test_block_justify_alignment() {
let input = "JUSTIFY: この文章は両端揃えです";
let output = parse(input);
assert!(output.contains(r#"class="umd-justify""#));
assert!(output.contains("この文章は両端揃えです"));
}
#[test]
fn test_block_truncate() {
let input = "TRUNCATE: 長いテキストは省略表示されます";
let output = parse(input);
assert!(output.contains(r#"class="umd-truncate""#));
assert!(output.contains("長いテキストは省略表示されます"));
}
#[test]
fn test_block_placement_justify_for_umd_table() {
let input = "JUSTIFY:\n| Header1 | Header2 |\n| Cell1 | Cell2 |";
let output = parse(input);
assert!(output.contains("<table"), "output: {}", output);
assert!(output.contains("umd-table"), "output: {}", output);
assert!(output.contains("umd-block-justify"), "output: {}", output);
assert!(!output.contains("<p>JUSTIFY:</p>"));
}
#[test]
fn test_block_placement_center_for_block_plugin() {
let input = "CENTER:\n@callout(info)";
let output = parse(input);
assert!(output.contains("umd-plugin-callout"), "output: {}", output);
assert!(output.contains("umd-block-center"), "output: {}", output);
assert!(!output.contains("CENTER:"));
}
#[test]
fn test_compound_prefixes() {
let input = "SIZE(lg): COLOR(blue): CENTER: Styled text";
let output = parse(input);
assert!(output.contains(r#"class="#));
assert!(output.contains("umd-text-size-lg"));
assert!(output.contains("umd-color-blue"));
assert!(output.contains("umd-center"));
}
#[test]
fn test_table_cell_vertical_alignment_top() {
let input = "| V-START: Header |\n|-------------|\n| Cell |";
let output = parse(input);
assert!(output.contains(r#"class="umd-v-start""#));
}
#[test]
fn test_table_cell_vertical_alignment_middle() {
let input = "| V-CENTER: Data |\n|-------------|\n| Cell |";
let output = parse(input);
assert!(output.contains(r#"class="umd-v-center""#));
}
#[test]
fn test_definition_list() {
let input = ":HTML|HyperText Markup Language\n:CSS|Cascading Style Sheets";
let output = parse(input);
assert!(output.contains("<dl>"));
assert!(output.contains("<dt>HTML</dt>"));
assert!(output.contains("<dd>HyperText Markup Language</dd>"));
assert!(output.contains("<dt>CSS</dt>"));
assert!(output.contains("<dd>Cascading Style Sheets</dd>"));
assert!(output.contains("</dl>"));
}
#[test]
fn test_definition_list_single_item() {
let input = ":JavaScript|A programming language for the web";
let output = parse(input);
assert!(output.contains("<dl>"));
assert!(output.contains("<dt>JavaScript</dt>"));
assert!(output.contains("<dd>A programming language for the web</dd>"));
assert!(output.contains("</dl>"));
}
#[test]
fn test_mixed_features() {
let input = r#"
# Heading
This is &color(blue){important}; text.
| V-START: Header | V-CENTER: Data |
|-------------|--------------|
| Cell 1 | Cell 2 |
:Term|Definition of the term
"#;
let output = parse(input);
assert!(output.contains(r#"class="umd-color-blue""#));
assert!(output.contains(r#"class="umd-table""#));
assert!(output.contains(r#"class="umd-v-start""#));
assert!(output.contains(r#"class="umd-v-center""#));
assert!(output.contains("<dl>"));
assert!(output.contains("<dt>Term</dt>"));
}
#[test]
fn test_strikethrough_compatibility() {
let input = "%%UMD strikethrough%% and ~~GFM strikethrough~~";
let output = parse(input);
assert!(output.contains("<s>UMD strikethrough</s>"));
assert!(output.contains("<del>GFM strikethrough</del>"));
}
#[test]
fn test_media_line_start_treated_as_block() {
let input = "";
let output = parse(input);
assert!(output.contains(r#"<figure class="umd-block-justify">"#));
assert!(output.contains("<picture"));
assert!(output.contains("src=\"image.png\""));
}
#[test]
fn test_end_prefix_places_media_end() {
let input = "END:\n";
let output = parse(input);
assert!(output.contains(r#"<figure class="umd-block-end">"#));
assert!(output.contains("<picture"));
assert!(output.contains("src=\"image.png\""));
assert!(!output.contains("END:"));
}
#[test]
fn test_mermaid_code_block_passthrough() {
let input = "```mermaid\nflowchart TD\n A[Start] --> B[End]\n```";
let output = parse(input);
assert!(output.contains("language-mermaid"));
assert!(output.contains(r#"<figure class="umd-code-block">"#));
assert!(!output.contains("umd-mermaid-diagram"));
assert!(!output.contains("<svg"));
}
#[test]
fn test_code_block_no_syntax_highlighting_in_core() {
let input = "```rust\nfn main() {\n println!(\"hello\");\n}\n```";
let output = parse(input);
assert!(output.contains("language-rust"));
assert!(!output.contains("umd-syntect-highlight"));
assert!(!output.contains("data-highlighted=\"true\""));
assert!(!output.contains("syntect-"));
}
#[test]
fn test_plain_code_block_wrapped_in_umd_code_block_figure() {
let input = "```\nplain text\n```";
let output = parse(input);
assert!(
output.contains(r#"<figure class="umd-code-block">"#),
"output: {}",
output
);
assert!(output.contains("plain text"), "output: {}", output);
}
#[test]
fn test_code_block_with_filename_uses_figure_caption() {
let input = "```rust:src/main.rs\nfn main() {\n println!(\"hello\");\n}\n```";
let output = parse(input);
assert!(
output.contains(r#"<figure class="umd-code-block">"#),
"output: {}",
output
);
assert!(
output.contains(r#"<figcaption class="umd-code-filename">src/main.rs</figcaption>"#),
"output: {}",
output
);
assert!(output.contains("language-rust"), "output: {}", output);
}
#[test]
fn test_code_block_with_filename_without_language() {
let input = "```:config.yml\nkey: value\n```";
let output = parse(input);
assert!(
output.contains(r#"<figure class="umd-code-block">"#),
"output: {}",
output
);
assert!(output.contains("config.yml"), "output: {}", output);
assert!(output.contains("<pre>key: value"), "output: {}", output);
assert!(
!output.contains("language-umd-nolang"),
"output: {}",
output
);
}
#[test]
fn test_start_prefix_places_code_block_at_start() {
let input = "START:\n```rust\nfn main() {}\n```";
let output = parse(input);
assert!(
output.contains(r#"<figure class="umd-code-block umd-block-auto">"#),
"output: {}",
output
);
assert!(!output.contains("START:"), "output: {}", output);
}
#[test]
fn test_center_prefix_places_code_block_centered() {
let input = "CENTER:\n```rust\nfn main() {}\n```";
let output = parse(input);
assert!(
output.contains(r#"<figure class="umd-code-block umd-block-center">"#),
"output: {}",
output
);
}
#[test]
fn test_end_prefix_places_code_block_at_end() {
let input = "END:\n```rust\nfn main() {}\n```";
let output = parse(input);
assert!(
output.contains(r#"<figure class="umd-code-block umd-block-auto umd-block-end">"#),
"output: {}",
output
);
}
#[test]
fn test_table_plugin_removed_falls_back_to_generic_plugin() {
let input = "@table(sm){{\n| H1 | H2 |\n|----|----|\n| A | B |\n}}";
let output = parse(input);
assert!(output.contains(r#"class="umd-plugin umd-plugin-block umd-plugin-table""#));
assert!(output.contains("<data value=\"0\">sm</data>"));
}
#[test]
fn test_math_formula_inline_support() {
let input = "&math(\\frac{a}{b});";
let output = parse(input);
assert!(output.contains("<math"), "output: {}", output);
assert!(
output.contains("<mfrac>") || output.contains("<mrow>"),
"output: {}",
output
);
}
#[test]
fn test_popover_inline_support() {
let input = "テキスト&popover(詳細){短い補足説明です};テキスト";
let output = parse(input);
assert!(
output.contains("command=\"show-popover\""),
"output: {}",
output
);
assert!(
output.contains("commandfor=\"umd-popover-"),
"output: {}",
output
);
assert!(output.contains(" popover>"), "output: {}", output);
assert!(output.contains("短い補足説明です"), "output: {}", output);
}
#[test]
fn test_popover_block_support() {
let input = "@popover(詳細を表示){{\n**重要**\n\n- 項目1\n- 項目2\n}}";
let output = parse(input);
assert!(
output.contains("command=\"show-popover\""),
"output: {}",
output
);
assert!(output.contains("詳細を表示</button>"), "output: {}", output);
assert!(
output.contains("<strong>重要</strong>"),
"output: {}",
output
);
assert!(output.contains("<ul>"), "output: {}", output);
}
#[test]
fn test_math_formula_block_argsonly_support() {
let input = "@math(\\frac{a}{b})";
let output = parse(input);
assert!(output.contains("<math"), "output: {}", output);
assert!(output.contains("display=\"block\""), "output: {}", output);
assert!(
output.contains("<mfrac>") || output.contains("<mrow>"),
"output: {}",
output
);
assert!(!output.contains("umd-plugin-math"), "output: {}", output);
}
#[test]
fn test_math_formula_block_with_content_support() {
let input = "@math(){{\\sum_{i=1}^{n} i}}";
let output = parse(input);
assert!(output.contains("<math"), "output: {}", output);
assert!(output.contains("display=\"block\""), "output: {}", output);
assert!(!output.contains("umd-plugin-math"), "output: {}", output);
}
#[test]
fn test_inline_code_hex_color_adds_swatch() {
let input = "`#ffce44`";
let output = parse(input);
assert!(
output.contains(
r#"<code><span class="inline-code-color" style="background-color: #ffce44;"><iconify-icon icon="ic:baseline-palette" aria-hidden="true"></iconify-icon></span>#ffce44</code>"#
),
"output: {}",
output
);
}
#[test]
fn test_inline_code_function_color_adds_swatch() {
let test_cases = vec![
"rgb(255,0,0)",
"rgba(0,255,0,0.4)",
"hsl(100, 10%, 10%)",
"hsla(100, 24%, 40%, 0.5)",
];
for color in test_cases {
let input = format!("`{}`", color);
let output = parse(&input);
let expected = format!(
r#"<code><span class="inline-code-color" style="background-color: {};"><iconify-icon icon="ic:baseline-palette" aria-hidden="true"></iconify-icon></span>{}</code>"#,
color, color
);
assert!(
output.contains(&expected),
"color: {} output: {}",
color,
output
);
}
}
#[test]
fn test_inline_code_non_color_does_not_add_swatch() {
let input = "`not-a-color`";
let output = parse(input);
assert!(
output.contains("<code>not-a-color</code>"),
"output: {}",
output
);
assert!(!output.contains("inline-code-color"), "output: {}", output);
}