crates/gunnar-public-site/src/tests.rs
//! Unit tests for the small decisions in `lib.rs`.
use super::*;
#[test]
fn the_ai_crawler_policy_defaults_to_allow() {
assert!(ai_crawlers_allowed(None));
assert!(ai_crawlers_allowed(Some("allow")));
assert!(ai_crawlers_allowed(Some("")));
for deny in ["deny", "DENY", " off ", "no", "false", "0"] {
assert!(!ai_crawlers_allowed(Some(deny)), "{deny}");
}
}
/// The owner (2026-10-25): the public site is ON only where it is needed
/// (gunnar.rs); everywhere else, a sold private estate first, the feature
/// built is the airgap default: OFF unless told `on`.
#[test]
fn the_switch_starts_off_unless_told_on() {
for off in [None, Some(""), Some("off"), Some("no"), Some("allow"), Some("maybe")] {
assert!(!switch_starts_on(off), "{off:?}");
}
for on in ["on", " ON ", "yes", "true", "1"] {
assert!(switch_starts_on(Some(on)), "{on}");
}
let s = Switch::new(true);
s.set(false);
assert!(!s.is_on());
}
#[test]
fn only_plain_names_get_a_page() {
for ok in ["gunnar", "gunnar-ui", "a.b_c", "Skidbladnir"] {
assert!(safe_name(ok), "{ok}");
}
for bad in ["", ".", "..", "a/b", "a b", "a%2F", "<x>"] {
assert!(!safe_name(bad), "{bad}");
}
}
#[test]
fn a_request_path_is_decoded_and_its_trailing_slash_dropped() {
assert_eq!(normalise("/").as_deref(), Some("/"));
assert_eq!(normalise("/llms.txt/").as_deref(), Some("/llms.txt"));
assert_eq!(normalise("/a/b%20c").as_deref(), Some("/a/b c"));
assert_eq!(normalise("/%ff"), None);
}
#[test]
fn the_config_is_gunnars_and_its_base_has_no_trailing_slash() {
let c = Config::gunnar("https://gunnar.rs/");
assert_eq!(c.base_url, "https://gunnar.rs");
assert_eq!(c.site_name, "Gunnar");
assert!(c.ai_crawlers);
assert!(c.crawl_delay_secs > 0);
}