use std::fs;
use bookyard_core::{
BookConfig, BookEngine, BookyardConfig, build_folder_tree, create_build_plan,
detect_book_source, insert_book, slugify_book_id,
};
#[test]
fn config_roundtrips_with_defaults() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("bookyard.toml");
let mut config = BookyardConfig::new("Docs");
insert_book(
&mut config,
BookConfig {
id: "term-forge".into(),
title: "TermForge".into(),
source: "docs/term-forge".into(),
engine: BookEngine::MdBook,
folders: vec!["Products/TermForge".into()],
tags: vec!["rust".into()],
order: 10,
},
)
.unwrap();
config.save_to(&path).unwrap();
let raw = fs::read_to_string(&path).unwrap();
assert!(raw.contains("engine = \"mdbook\""));
let loaded = BookyardConfig::load_from(&path).unwrap();
assert_eq!(loaded.workspace.title, "Docs");
assert_eq!(loaded.workspace.output, "bookyard");
assert_eq!(loaded.build.jobs, 4);
assert_eq!(loaded.books[0].id, "term-forge");
assert_eq!(loaded.books[0].folders, vec!["Products/TermForge"]);
}
#[test]
fn insert_book_rejects_duplicate_ids() {
let mut config = BookyardConfig::new("Docs");
let book = BookConfig::new_mdbook("guide", "Guide", "docs/guide", vec!["Guides"]);
insert_book(&mut config, book.clone()).unwrap();
let err = insert_book(&mut config, book).unwrap_err();
assert!(err.to_string().contains("duplicate book id"));
}
#[test]
fn slugifies_book_ids_from_titles_or_paths() {
assert_eq!(slugify_book_id("Term Forge"), "term-forge");
assert_eq!(slugify_book_id("docs/My API Book"), "my-api-book");
assert_eq!(slugify_book_id("!!!"), "book");
}
#[test]
fn builds_folder_tree_from_logical_paths() {
let books = vec![
BookConfig::new_mdbook(
"term-forge",
"TermForge",
"docs/term",
vec!["Products/TermForge"],
),
BookConfig::new_mdbook(
"ink-forge",
"InkForge",
"docs/ink",
vec!["Products/InkForge"],
),
BookConfig::new_mdbook(
"rust-notes",
"Rust Notes",
"docs/rust",
vec!["Knowledge/Rust"],
),
];
let tree = build_folder_tree(&books);
assert_eq!(tree.len(), 2);
assert_eq!(tree[0].path, "Knowledge");
assert_eq!(tree[1].path, "Products");
assert_eq!(tree[1].children.len(), 2);
assert_eq!(tree[1].children[0].path, "Products/InkForge");
assert_eq!(tree[1].children[1].path, "Products/TermForge");
}
#[test]
fn detects_mdbook_sources() {
let dir = tempfile::tempdir().unwrap();
fs::create_dir_all(dir.path().join("src")).unwrap();
fs::write(
dir.path().join("book.toml"),
"[book]\ntitle = \"Example Book\"\n",
)
.unwrap();
let detected = detect_book_source(dir.path()).unwrap();
assert_eq!(detected.engine, BookEngine::MdBook);
assert_eq!(detected.title.as_deref(), Some("Example Book"));
}
#[test]
fn creates_build_plan_for_each_book() {
let mut config = BookyardConfig::new("Docs");
insert_book(
&mut config,
BookConfig::new_mdbook("guide", "Guide", "docs/guide", vec!["Guides"]),
)
.unwrap();
let plan = create_build_plan(std::path::Path::new("repo"), &config).unwrap();
assert_eq!(
plan.output_dir,
std::path::Path::new("repo").join("bookyard")
);
assert_eq!(plan.items.len(), 1);
assert_eq!(
plan.items[0].source_dir,
std::path::Path::new("repo").join("docs/guide")
);
assert_eq!(
plan.items[0].dest_dir,
std::path::Path::new("repo").join("bookyard/books/guide")
);
}