#![allow(missing_docs)]
#![cfg(feature = "test-fault-injection")]
#![allow(clippy::unwrap_used, clippy::expect_used)]
use serial_test::serial;
use ssg::cache::BuildCache;
use ssg::cmd::SsgConfig;
use ssg::plugin::{Plugin, PluginContext};
use ssg::plugins::MinifyPlugin;
use ssg::scaffold::scaffold_project_at;
use std::fs;
use tempfile::tempdir;
struct FailGuard<'a>(&'a str);
impl Drop for FailGuard<'_> {
fn drop(&mut self) {
let _ = fail::cfg(self.0, "off");
}
}
fn run_scaffold_with_failpoint(name: &str) -> anyhow::Error {
let _guard = FailGuard(name);
fail::cfg(name, "return").expect("activate failpoint");
let dir = tempdir().expect("tempdir");
scaffold_project_at("fault-test-site", dir.path())
.expect_err("scaffold should fail when failpoint is active")
}
#[test]
#[serial]
fn scaffold_fault_create_dir_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::create-dir");
assert!(format!("{err:?}").contains("scaffold::create-dir"));
}
#[test]
#[serial]
fn scaffold_fault_write_config_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-config");
assert!(format!("{err:?}").contains("scaffold::write-config"));
}
#[test]
#[serial]
fn scaffold_fault_write_index_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-index");
assert!(format!("{err:?}").contains("scaffold::write-index"));
}
#[test]
#[serial]
fn scaffold_fault_write_about_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-about");
assert!(format!("{err:?}").contains("scaffold::write-about"));
}
#[test]
#[serial]
fn scaffold_fault_write_post_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-post");
assert!(format!("{err:?}").contains("scaffold::write-post"));
}
#[test]
#[serial]
fn scaffold_fault_write_base_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-base");
assert!(format!("{err:?}").contains("scaffold::write-base"));
}
#[test]
#[serial]
fn scaffold_fault_write_page_tpl_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-page-tpl");
assert!(format!("{err:?}").contains("scaffold::write-page-tpl"));
}
#[test]
#[serial]
fn scaffold_fault_write_post_tpl_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-post-tpl");
assert!(format!("{err:?}").contains("scaffold::write-post-tpl"));
}
#[test]
#[serial]
fn scaffold_fault_write_index_tpl_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-index-tpl");
assert!(format!("{err:?}").contains("scaffold::write-index-tpl"));
}
#[test]
#[serial]
fn scaffold_fault_write_css_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-css");
assert!(format!("{err:?}").contains("scaffold::write-css"));
}
#[test]
#[serial]
fn scaffold_fault_write_nav_returns_err() {
let err = run_scaffold_with_failpoint("scaffold::write-nav");
assert!(format!("{err:?}").contains("scaffold::write-nav"));
}
#[test]
#[serial]
fn cmd_fault_symlink_metadata_returns_err() {
let _guard = FailGuard("cmd::symlink-metadata");
fail::cfg("cmd::symlink-metadata", "return").expect("activate failpoint");
let dir = tempdir().expect("tempdir");
let mut config = SsgConfig::default();
config.content_dir = dir.path().to_path_buf();
config.output_dir = dir.path().to_path_buf();
config.template_dir = dir.path().to_path_buf();
let err = config.validate().expect_err("validate should fail");
let msg = format!("{err:?}");
assert!(
msg.contains("injected: cmd::symlink-metadata"),
"expected injected error, got: {msg}"
);
}
#[test]
#[serial]
fn cache_fault_read_returns_err() {
let _guard = FailGuard("cache::read");
fail::cfg("cache::read", "return").expect("activate failpoint");
let dir = tempdir().expect("tempdir");
let cache_path = dir.path().join("cache.json");
fs::write(&cache_path, "{}").expect("seed cache file");
let err = BuildCache::load(&cache_path)
.expect_err("load should fail when cache::read failpoint is active");
assert!(format!("{err:?}").contains("injected: cache::read"));
}
#[test]
#[serial]
fn cache_fault_parse_returns_err() {
let _guard = FailGuard("cache::parse");
fail::cfg("cache::parse", "return").expect("activate failpoint");
let dir = tempdir().expect("tempdir");
let cache_path = dir.path().join("cache.json");
fs::write(&cache_path, r#"{"fingerprints":{}}"#).expect("seed");
let err = BuildCache::load(&cache_path)
.expect_err("load should fail when cache::parse failpoint is active");
assert!(format!("{err:?}").contains("injected: cache::parse"));
}
#[test]
#[serial]
fn cache_fault_write_returns_err() {
let _guard = FailGuard("cache::write");
fail::cfg("cache::write", "return").expect("activate failpoint");
let dir = tempdir().expect("tempdir");
let cache_path = dir.path().join("cache.json");
let cache = BuildCache::new(&cache_path);
let err = cache
.save()
.expect_err("save should fail when cache::write failpoint is active");
assert!(format!("{err:?}").contains("injected: cache::write"));
}
#[test]
#[serial]
fn plugins_fault_minify_read_returns_err() {
let _guard = FailGuard("plugins::minify-read");
fail::cfg("plugins::minify-read", "return").expect("activate failpoint");
let dir = tempdir().expect("tempdir");
let site = dir.path().to_path_buf();
fs::write(site.join("index.html"), "<p>x</p>").expect("seed html");
let ctx = PluginContext::new(&site, &site, &site, &site);
let err = MinifyPlugin
.after_compile(&ctx)
.expect_err("after_compile should fail when read failpoint is active");
assert!(format!("{err:?}").contains("injected: plugins::minify-read"));
}
#[test]
#[serial]
fn plugins_fault_minify_write_returns_err() {
let _guard = FailGuard("plugins::minify-write");
fail::cfg("plugins::minify-write", "return").expect("activate failpoint");
let dir = tempdir().expect("tempdir");
let site = dir.path().to_path_buf();
fs::write(site.join("index.html"), "<p>x</p>").expect("seed html");
let ctx = PluginContext::new(&site, &site, &site, &site);
let err = MinifyPlugin
.after_compile(&ctx)
.expect_err("after_compile should fail when write failpoint is active");
assert!(format!("{err:?}").contains("injected: plugins::minify-write"));
}