test(nav): add unit tests for anchor extraction and TOC fallback

- test_anchor_extraction: verify h2-h6 extracted, h1 skipped, IDs slugified
- test_slugify_edge_cases: verify special char handling, spaces, case
- test_toc_config_fallback: verify frontmatter override and config default
This commit is contained in:
Timothy DeHerrera
2026-02-01 09:48:13 -07:00
parent c8c2506e16
commit fc9e75d687
2 changed files with 157 additions and 0 deletions

View File

@@ -393,4 +393,69 @@ mod tests {
assert!(html.contains("src=\"logo.png\""));
assert!(!html.contains("title="));
}
#[test]
fn test_anchor_extraction() {
let md = r#"# Page Title
## Getting Started
Some intro text.
### Installation
Install steps.
## Configuration
Config details.
#### Deep Heading
"#;
let (html, anchors) = markdown_to_html(md);
// h1 should NOT be extracted (page title, not TOC)
assert!(anchors.iter().all(|a| a.level >= 2));
// Should have 4 anchors: h2, h3, h2, h4
assert_eq!(anchors.len(), 4);
// Check first anchor
assert_eq!(anchors[0].id, "getting-started");
assert_eq!(anchors[0].label, "Getting Started");
assert_eq!(anchors[0].level, 2);
// Check h3
assert_eq!(anchors[1].id, "installation");
assert_eq!(anchors[1].level, 3);
// Check second h2
assert_eq!(anchors[2].id, "configuration");
assert_eq!(anchors[2].level, 2);
// Check h4
assert_eq!(anchors[3].id, "deep-heading");
assert_eq!(anchors[3].level, 4);
// Verify IDs are in HTML
assert!(html.contains("id=\"getting-started\""));
assert!(html.contains("id=\"installation\""));
}
#[test]
fn test_slugify_edge_cases() {
// Basic case
assert_eq!(slugify("Hello World"), "hello-world");
// Multiple spaces → single hyphen
assert_eq!(slugify("Hello World"), "hello-world");
// Special characters → hyphen (apostrophe becomes hyphen)
assert_eq!(slugify("What's New?"), "what-s-new");
// Numbers preserved, dot becomes hyphen
assert_eq!(slugify("Version 2.0"), "version-2-0");
// Leading/trailing spaces trimmed
assert_eq!(slugify(" Padded "), "padded");
// Mixed case → lowercase
assert_eq!(slugify("CamelCase"), "camelcase");
// Consecutive special chars → single hyphen
assert_eq!(slugify("A -- B"), "a-b");
}
}

View File

@@ -216,4 +216,96 @@ mod tests {
fn test_relative_prefix_depth_2() {
assert_eq!(relative_prefix("/blog/posts/foo.html"), "../..");
}
#[test]
fn test_toc_config_fallback() {
use crate::content::Frontmatter;
// Create configs with different toc defaults
let config_toc_true = SiteConfig {
title: "Test".to_string(),
author: "Test".to_string(),
base_url: "https://test.com".to_string(),
paths: crate::config::PathsConfig::default(),
nav: crate::config::NavConfig {
nested: false,
toc: true,
},
};
let config_toc_false = SiteConfig {
title: "Test".to_string(),
author: "Test".to_string(),
base_url: "https://test.com".to_string(),
paths: crate::config::PathsConfig::default(),
nav: crate::config::NavConfig {
nested: false,
toc: false,
},
};
// Frontmatter with explicit toc: true
let fm_explicit_true = Frontmatter {
title: "Test".to_string(),
description: None,
date: None,
tags: vec![],
weight: None,
link_to: None,
nav_label: None,
section_type: None,
template: None,
toc: Some(true),
};
// Frontmatter with explicit toc: false
let fm_explicit_false = Frontmatter {
title: "Test".to_string(),
description: None,
date: None,
tags: vec![],
weight: None,
link_to: None,
nav_label: None,
section_type: None,
template: None,
toc: Some(false),
};
// Frontmatter with no toc specified (None)
let fm_none = Frontmatter {
title: "Test".to_string(),
description: None,
date: None,
tags: vec![],
weight: None,
link_to: None,
nav_label: None,
section_type: None,
template: None,
toc: None,
};
// Explicit true overrides config false
let ctx = FrontmatterContext::new(&fm_explicit_true, &config_toc_false);
assert!(
ctx.toc,
"explicit toc: true should override config toc: false"
);
// Explicit false overrides config true
let ctx = FrontmatterContext::new(&fm_explicit_false, &config_toc_true);
assert!(
!ctx.toc,
"explicit toc: false should override config toc: true"
);
// None falls back to config true
let ctx = FrontmatterContext::new(&fm_none, &config_toc_true);
assert!(ctx.toc, "toc: None should fall back to config toc: true");
// None falls back to config false
let ctx = FrontmatterContext::new(&fm_none, &config_toc_false);
assert!(!ctx.toc, "toc: None should fall back to config toc: false");
}
}