use std::collections::HashMap; use bds_core::model::{Post, PostStatus, Tag, Template, TemplateKind, TemplateStatus}; use bds_core::render::{ RenderCategorySettings, RenderTemplateLookup, TemplateLookupError, render_markdown_to_html, resolve_post_template, }; fn make_post() -> Post { Post { id: "post-1".into(), project_id: "project-1".into(), title: "Post".into(), slug: "post".into(), excerpt: None, content: Some("# Hello".into()), status: PostStatus::Published, author: None, language: Some("en".into()), do_not_translate: false, template_slug: None, file_path: "posts/2026/04/10/post.md".into(), checksum: None, tags: vec![], categories: vec![], published_title: None, published_content: None, published_tags: None, published_categories: None, published_excerpt: None, created_at: 1, updated_at: 1, published_at: Some(1), } } fn make_template(slug: &str) -> Template { Template { id: format!("template-{slug}"), project_id: "project-1".into(), slug: slug.into(), title: slug.into(), kind: TemplateKind::Post, enabled: true, version: 1, file_path: format!("templates/{slug}.liquid"), status: TemplateStatus::Published, content: Some(format!("template:{slug}")), created_at: 1, updated_at: 1, } } fn make_tag(name: &str, post_template_slug: Option<&str>) -> Tag { Tag { id: format!("tag-{name}"), project_id: "project-1".into(), name: name.into(), color: None, post_template_slug: post_template_slug.map(ToOwned::to_owned), created_at: 1, updated_at: 1, } } #[test] fn template_lookup_prefers_post_specific_template() { let mut post = make_post(); post.template_slug = Some("custom".into()); post.tags = vec!["rust".into()]; post.categories = vec!["article".into()]; let templates = vec![ make_template("post"), make_template("tag-template"), make_template("custom"), ]; let tags = vec![make_tag("rust", Some("tag-template"))]; let mut categories = HashMap::new(); categories.insert( "article".into(), RenderCategorySettings { post_template_slug: Some("category-template".into()), }, ); let resolved = resolve_post_template(RenderTemplateLookup { post: &post, templates: &templates, tags: &tags, category_settings: &categories, }) .unwrap(); assert_eq!(resolved.slug, "custom"); } #[test] fn template_lookup_falls_back_to_tag_then_category_then_default() { let mut post = make_post(); post.tags = vec!["rust".into()]; post.categories = vec!["article".into()]; let templates = vec![ make_template("post"), make_template("tag-template"), make_template("category-template"), ]; let tags = vec![make_tag("rust", Some("tag-template"))]; let mut categories = HashMap::new(); categories.insert( "article".into(), RenderCategorySettings { post_template_slug: Some("category-template".into()), }, ); let resolved = resolve_post_template(RenderTemplateLookup { post: &post, templates: &templates, tags: &tags, category_settings: &categories, }) .unwrap(); assert_eq!(resolved.slug, "tag-template"); let category_post = Post { tags: vec![], ..post.clone() }; let resolved = resolve_post_template(RenderTemplateLookup { post: &category_post, templates: &templates, tags: &tags, category_settings: &categories, }) .unwrap(); assert_eq!(resolved.slug, "category-template"); let default_post = Post { tags: vec![], categories: vec![], ..post }; let empty_categories = HashMap::new(); let resolved = resolve_post_template(RenderTemplateLookup { post: &default_post, templates: &templates, tags: &tags, category_settings: &empty_categories, }) .unwrap(); assert_eq!(resolved.slug, "post"); } #[test] fn template_lookup_errors_when_explicit_template_missing() { let mut post = make_post(); post.template_slug = Some("missing".into()); let templates = vec![make_template("post")]; let err = resolve_post_template(RenderTemplateLookup { post: &post, templates: &templates, tags: &[], category_settings: &HashMap::new(), }) .unwrap_err(); assert_eq!( err, TemplateLookupError::MissingExplicitTemplate("missing".into()) ); } #[test] fn markdown_render_produces_html() { let html = render_markdown_to_html("# Hello\n\nA paragraph with **bold** text."); assert!(html.contains("

Hello

")); assert!(html.contains("bold")); }