feat: even more M4 closing

This commit is contained in:
2026-04-13 20:45:29 +02:00
parent 316a218685
commit eca5fafc1c
12 changed files with 521 additions and 9 deletions

View File

@@ -1,6 +1,9 @@
use bds_core::db::queries::project::insert_project;
use bds_core::db::Database;
use bds_core::engine::generation::{PublishedPostSource, generate_starter_site};
use bds_core::engine::generation::{
PublishedPostSource, apply_validation_sections, generate_starter_site,
sections_from_validation_report,
};
use bds_core::engine::validate_site::validate_site;
use bds_core::model::{Post, PostStatus, Project, ProjectMetadata};
use tempfile::TempDir;
@@ -184,4 +187,78 @@ fn site_validation_detects_stale_and_missing_outputs() {
assert!(report.stale_pages.contains(&"index.html".to_string()));
assert!(report.missing_pages.contains(&"feed.xml".to_string()));
assert!(report.extra_pages.is_empty());
}
#[test]
fn apply_validation_repairs_core_section_outputs() {
let (db, dir) = setup();
let metadata = make_metadata();
let post = make_post("hello", 1_710_000_000_000);
bds_core::db::queries::post::insert_post(db.conn(), &post).unwrap();
let posts = vec![PublishedPostSource {
post,
body_markdown: "Hello **world**".into(),
}];
generate_starter_site(db.conn(), dir.path(), "p1", &metadata, &posts, "en").unwrap();
std::fs::write(dir.path().join("index.html"), "tampered").unwrap();
std::fs::remove_file(dir.path().join("feed.xml")).unwrap();
let report = validate_site(db.conn(), dir.path(), "p1").unwrap();
let sections = sections_from_validation_report(&report);
let apply_report = apply_validation_sections(db.conn(), dir.path(), "p1", &metadata, &posts, &sections).unwrap();
let repaired = validate_site(db.conn(), dir.path(), "p1").unwrap();
assert!(!apply_report.written_paths.is_empty() || !apply_report.skipped_paths.is_empty());
assert!(repaired.missing_pages.is_empty());
assert!(repaired.extra_pages.is_empty());
assert!(repaired.stale_pages.is_empty());
}
#[test]
fn apply_validation_removes_extra_section_outputs() {
let (db, dir) = setup();
let metadata = make_metadata();
let post = make_post("hello", 1_710_000_000_000);
bds_core::db::queries::post::insert_post(db.conn(), &post).unwrap();
let posts = vec![PublishedPostSource {
post,
body_markdown: "Hello **world**".into(),
}];
generate_starter_site(db.conn(), dir.path(), "p1", &metadata, &posts, "en").unwrap();
let extra_dir = dir.path().join("tag/ghost");
std::fs::create_dir_all(&extra_dir).unwrap();
std::fs::write(extra_dir.join("index.html"), "ghost").unwrap();
let report = validate_site(db.conn(), dir.path(), "p1").unwrap();
assert!(report.extra_pages.contains(&"tag/ghost/index.html".to_string()));
let sections = sections_from_validation_report(&report);
let apply_report = apply_validation_sections(db.conn(), dir.path(), "p1", &metadata, &posts, &sections).unwrap();
let repaired = validate_site(db.conn(), dir.path(), "p1").unwrap();
assert!(apply_report.deleted_paths.contains(&"tag/ghost/index.html".to_string()));
assert!(repaired.extra_pages.is_empty());
}
#[test]
fn site_validation_uses_html_output_directory_when_present() {
let (db, dir) = setup();
let metadata = make_metadata();
let post = make_post("hello", 1_710_000_000_000);
bds_core::db::queries::post::insert_post(db.conn(), &post).unwrap();
let posts = vec![PublishedPostSource {
post,
body_markdown: "Hello **world**".into(),
}];
let output_dir = dir.path().join("html");
std::fs::create_dir_all(&output_dir).unwrap();
generate_starter_site(db.conn(), &output_dir, "p1", &metadata, &posts, "en").unwrap();
let report = validate_site(db.conn(), dir.path(), "p1").unwrap();
assert!(report.missing_pages.is_empty());
assert!(report.extra_pages.is_empty());
assert!(report.stale_pages.is_empty());
}

View File

@@ -75,6 +75,32 @@ fn generated_write_skips_unchanged_content() {
assert!(fs::read_to_string(dir.path().join("index.html")).unwrap().contains("changed"));
}
#[test]
fn generated_write_rewrites_missing_file_even_when_hash_matches() {
let (db, dir) = setup();
let first = write_generated_file(db.conn(), dir.path(), "p1", "index.html", "hello").unwrap();
fs::remove_file(dir.path().join("index.html")).unwrap();
let second = write_generated_file(db.conn(), dir.path(), "p1", "index.html", "hello").unwrap();
assert_eq!(first, GeneratedWriteOutcome::Written);
assert_eq!(second, GeneratedWriteOutcome::Written);
assert_eq!(fs::read_to_string(dir.path().join("index.html")).unwrap(), "hello");
}
#[test]
fn generated_write_rewrites_stale_file_even_when_db_hash_matches() {
let (db, dir) = setup();
let first = write_generated_file(db.conn(), dir.path(), "p1", "index.html", "hello").unwrap();
fs::write(dir.path().join("index.html"), "tampered").unwrap();
let second = write_generated_file(db.conn(), dir.path(), "p1", "index.html", "hello").unwrap();
assert_eq!(first, GeneratedWriteOutcome::Written);
assert_eq!(second, GeneratedWriteOutcome::Written);
assert_eq!(fs::read_to_string(dir.path().join("index.html")).unwrap(), "hello");
}
#[test]
fn core_generation_paths_include_language_prefixed_variants() {
let paths = build_core_generation_paths("en", &["en".into(), "de".into(), "fr".into()]);