#[cfg(test)]
mod tests {
use crate::rndc_types::*;
#[test]
fn test_dns_class_as_str() {
assert_eq!(DnsClass::IN.as_str(), "IN");
assert_eq!(DnsClass::CH.as_str(), "CH");
assert_eq!(DnsClass::HS.as_str(), "HS");
}
#[test]
fn test_dns_class_default() {
let class: DnsClass = Default::default();
assert_eq!(class, DnsClass::IN);
}
#[test]
fn test_zone_type_as_str() {
assert_eq!(ZoneType::Primary.as_str(), "primary");
assert_eq!(ZoneType::Secondary.as_str(), "secondary");
assert_eq!(ZoneType::Stub.as_str(), "stub");
assert_eq!(ZoneType::Forward.as_str(), "forward");
assert_eq!(ZoneType::Hint.as_str(), "hint");
assert_eq!(ZoneType::Mirror.as_str(), "mirror");
assert_eq!(ZoneType::Delegation.as_str(), "delegation-only");
assert_eq!(ZoneType::Redirect.as_str(), "redirect");
}
#[test]
fn test_zone_type_parse_modern() {
assert_eq!(ZoneType::parse("primary"), Some(ZoneType::Primary));
assert_eq!(ZoneType::parse("secondary"), Some(ZoneType::Secondary));
assert_eq!(ZoneType::parse("stub"), Some(ZoneType::Stub));
assert_eq!(ZoneType::parse("forward"), Some(ZoneType::Forward));
assert_eq!(ZoneType::parse("hint"), Some(ZoneType::Hint));
assert_eq!(ZoneType::parse("mirror"), Some(ZoneType::Mirror));
assert_eq!(
ZoneType::parse("delegation-only"),
Some(ZoneType::Delegation)
);
assert_eq!(ZoneType::parse("redirect"), Some(ZoneType::Redirect));
}
#[test]
fn test_zone_type_parse_legacy() {
assert_eq!(ZoneType::parse("master"), Some(ZoneType::Primary));
assert_eq!(ZoneType::parse("slave"), Some(ZoneType::Secondary));
}
#[test]
fn test_zone_type_parse_invalid() {
assert_eq!(ZoneType::parse("invalid"), None);
assert_eq!(ZoneType::parse(""), None);
}
#[test]
fn test_notify_mode_as_str() {
assert_eq!(NotifyMode::Yes.as_str(), "yes");
assert_eq!(NotifyMode::No.as_str(), "no");
assert_eq!(NotifyMode::Explicit.as_str(), "explicit");
assert_eq!(NotifyMode::MasterOnly.as_str(), "master-only");
assert_eq!(NotifyMode::PrimaryOnly.as_str(), "primary-only");
}
#[test]
fn test_notify_mode_parse() {
assert_eq!(NotifyMode::parse("yes"), Some(NotifyMode::Yes));
assert_eq!(NotifyMode::parse("no"), Some(NotifyMode::No));
assert_eq!(NotifyMode::parse("explicit"), Some(NotifyMode::Explicit));
assert_eq!(
NotifyMode::parse("master-only"),
Some(NotifyMode::MasterOnly)
);
assert_eq!(
NotifyMode::parse("primary-only"),
Some(NotifyMode::PrimaryOnly)
);
assert_eq!(NotifyMode::parse("invalid"), None);
}
#[test]
fn test_forward_mode_as_str() {
assert_eq!(ForwardMode::Only.as_str(), "only");
assert_eq!(ForwardMode::First.as_str(), "first");
}
#[test]
fn test_forward_mode_parse() {
assert_eq!(ForwardMode::parse("only"), Some(ForwardMode::Only));
assert_eq!(ForwardMode::parse("first"), Some(ForwardMode::First));
assert_eq!(ForwardMode::parse("invalid"), None);
}
#[test]
fn test_auto_dnssec_mode_as_str() {
assert_eq!(AutoDnssecMode::Off.as_str(), "off");
assert_eq!(AutoDnssecMode::Maintain.as_str(), "maintain");
assert_eq!(AutoDnssecMode::Create.as_str(), "create");
}
#[test]
fn test_auto_dnssec_mode_parse() {
assert_eq!(AutoDnssecMode::parse("off"), Some(AutoDnssecMode::Off));
assert_eq!(
AutoDnssecMode::parse("maintain"),
Some(AutoDnssecMode::Maintain)
);
assert_eq!(
AutoDnssecMode::parse("create"),
Some(AutoDnssecMode::Create)
);
assert_eq!(AutoDnssecMode::parse("invalid"), None);
}
#[test]
fn test_check_names_mode_as_str() {
assert_eq!(CheckNamesMode::Fail.as_str(), "fail");
assert_eq!(CheckNamesMode::Warn.as_str(), "warn");
assert_eq!(CheckNamesMode::Ignore.as_str(), "ignore");
}
#[test]
fn test_check_names_mode_parse() {
assert_eq!(CheckNamesMode::parse("fail"), Some(CheckNamesMode::Fail));
assert_eq!(CheckNamesMode::parse("warn"), Some(CheckNamesMode::Warn));
assert_eq!(
CheckNamesMode::parse("ignore"),
Some(CheckNamesMode::Ignore)
);
assert_eq!(CheckNamesMode::parse("invalid"), None);
}
#[test]
fn test_masterfile_format_as_str() {
assert_eq!(MasterfileFormat::Text.as_str(), "text");
assert_eq!(MasterfileFormat::Raw.as_str(), "raw");
assert_eq!(MasterfileFormat::Map.as_str(), "map");
}
#[test]
fn test_masterfile_format_parse() {
assert_eq!(
MasterfileFormat::parse("text"),
Some(MasterfileFormat::Text)
);
assert_eq!(MasterfileFormat::parse("raw"), Some(MasterfileFormat::Raw));
assert_eq!(MasterfileFormat::parse("map"), Some(MasterfileFormat::Map));
assert_eq!(MasterfileFormat::parse("invalid"), None);
}
#[test]
fn test_primary_spec_new() {
let addr = "192.168.1.1".parse().unwrap();
let spec = PrimarySpec::new(addr);
assert_eq!(spec.address, addr);
assert_eq!(spec.port, None);
}
#[test]
fn test_primary_spec_with_port() {
let addr = "192.168.1.1".parse().unwrap();
let spec = PrimarySpec::with_port(addr, 5353);
assert_eq!(spec.address, addr);
assert_eq!(spec.port, Some(5353));
}
#[test]
fn test_forwarder_spec_new() {
let addr = "8.8.8.8".parse().unwrap();
let spec = ForwarderSpec::new(addr);
assert_eq!(spec.address, addr);
assert_eq!(spec.port, None);
assert_eq!(spec.tls_config, None);
}
#[test]
fn test_forwarder_spec_with_port() {
let addr = "8.8.8.8".parse().unwrap();
let spec = ForwarderSpec::with_port(addr, 853);
assert_eq!(spec.address, addr);
assert_eq!(spec.port, Some(853));
assert_eq!(spec.tls_config, None);
}
#[test]
fn test_forwarder_spec_with_tls() {
let addr = "8.8.8.8".parse().unwrap();
let spec = ForwarderSpec::with_tls(addr, "tls-config".to_string());
assert_eq!(spec.address, addr);
assert_eq!(spec.port, None);
assert_eq!(spec.tls_config, Some("tls-config".to_string()));
}
#[test]
fn test_zone_config_new() {
let config = ZoneConfig::new("example.com".to_string(), ZoneType::Primary);
assert_eq!(config.zone_name, "example.com");
assert_eq!(config.zone_type, ZoneType::Primary);
assert_eq!(config.class, DnsClass::IN);
assert_eq!(config.file, None);
assert_eq!(config.primaries, None);
assert_eq!(config.also_notify, None);
assert_eq!(config.raw_options.len(), 0);
}
#[test]
fn test_to_rndc_block_minimal() {
let config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
let block = config.to_rndc_block();
assert!(block.contains("type primary"));
assert!(block.starts_with("{ "));
assert!(block.ends_with("; };"));
}
#[test]
fn test_to_rndc_block_with_file() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.file = Some("/var/cache/bind/test.com.zone".to_string());
let block = config.to_rndc_block();
assert!(block.contains("type primary"));
assert!(block.contains(r#"file "/var/cache/bind/test.com.zone""#));
}
#[test]
fn test_to_rndc_block_with_primaries() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Secondary);
config.primaries = Some(vec![
PrimarySpec::new("192.168.1.1".parse().unwrap()),
PrimarySpec::with_port("192.168.1.2".parse().unwrap(), 5353),
]);
let block = config.to_rndc_block();
assert!(block.contains("type secondary"));
assert!(block.contains("primaries { 192.168.1.1; 192.168.1.2 port 5353; }"));
}
#[test]
fn test_to_rndc_block_with_also_notify() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.also_notify = Some(vec![
"10.0.0.1".parse().unwrap(),
"10.0.0.2".parse().unwrap(),
]);
let block = config.to_rndc_block();
assert!(block.contains("also-notify { 10.0.0.1; 10.0.0.2; }"));
}
#[test]
fn test_to_rndc_block_with_allow_transfer() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.allow_transfer = Some(vec!["10.1.1.1".parse().unwrap()]);
let block = config.to_rndc_block();
assert!(block.contains("allow-transfer { 10.1.1.1; }"));
}
#[test]
fn test_to_rndc_block_with_allow_update_ips() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.allow_update = Some(vec!["10.2.2.2".parse().unwrap()]);
let block = config.to_rndc_block();
assert!(block.contains("allow-update { 10.2.2.2; }"));
}
#[test]
fn test_to_rndc_block_with_allow_update_raw() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.allow_update_raw = Some(r#"{ key "update-key"; };"#.to_string());
let block = config.to_rndc_block();
assert!(block.contains("allow-update { key \"update-key\"; }"));
assert!(!block.contains(";;")); }
#[test]
fn test_to_rndc_block_prefers_raw_over_ips() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.allow_update = Some(vec!["10.1.1.1".parse().unwrap()]);
config.allow_update_raw = Some(r#"{ key "mykey"; };"#.to_string());
let block = config.to_rndc_block();
assert!(block.contains("allow-update { key \"mykey\"; }"));
assert!(!block.contains("10.1.1.1"));
}
#[test]
fn test_to_rndc_block_with_notify_mode() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.notify = Some(NotifyMode::Explicit);
let block = config.to_rndc_block();
assert!(block.contains("notify explicit"));
}
#[test]
fn test_to_rndc_block_with_forwarders() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Forward);
config.forwarders = Some(vec![
ForwarderSpec::new("8.8.8.8".parse().unwrap()),
ForwarderSpec::with_port("8.8.4.4".parse().unwrap(), 853),
]);
let block = config.to_rndc_block();
assert!(block.contains("forwarders { 8.8.8.8; 8.8.4.4 port 853; }"));
}
#[test]
fn test_to_rndc_block_with_raw_options() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config
.raw_options
.insert("zone-statistics".to_string(), "full".to_string());
config
.raw_options
.insert("check-names".to_string(), "warn".to_string());
let block = config.to_rndc_block();
assert!(block.contains("zone-statistics full"));
assert!(block.contains("check-names warn"));
assert!(!block.contains(";;"));
}
#[test]
fn test_to_rndc_block_raw_options_no_double_semicolons() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config
.raw_options
.insert("option1".to_string(), "value1;".to_string()); config
.raw_options
.insert("option2".to_string(), "value2".to_string());
let block = config.to_rndc_block();
assert!(!block.contains(";;"));
assert!(block.contains("option1 value1"));
assert!(block.contains("option2 value2"));
}
#[test]
fn test_to_rndc_block_comprehensive() {
let mut config = ZoneConfig::new("example.com".to_string(), ZoneType::Primary);
config.file = Some("/var/cache/bind/example.com.zone".to_string());
config.also_notify = Some(vec!["10.1.1.1".parse().unwrap()]);
config.allow_transfer = Some(vec!["10.2.2.2".parse().unwrap()]);
config.allow_update_raw = Some(r#"{ key "mykey"; };"#.to_string());
config.notify = Some(NotifyMode::Yes);
config.max_transfer_time_in = Some(3600);
config.inline_signing = Some(true);
config.check_names = Some(CheckNamesMode::Warn);
config
.raw_options
.insert("zone-statistics".to_string(), "yes".to_string());
let block = config.to_rndc_block();
assert!(block.contains("type primary"));
assert!(block.contains(r#"file "/var/cache/bind/example.com.zone""#));
assert!(block.contains("also-notify { 10.1.1.1; }"));
assert!(block.contains("allow-transfer { 10.2.2.2; }"));
assert!(block.contains("allow-update { key \"mykey\"; }"));
assert!(block.contains("notify yes"));
assert!(block.contains("max-transfer-time-in 3600"));
assert!(block.contains("inline-signing yes"));
assert!(block.contains("check-names warn"));
assert!(block.contains("zone-statistics yes"));
assert!(!block.contains(";;"));
}
#[test]
fn test_zone_config_equality() {
let config1 = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
let config2 = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
assert_eq!(config1, config2);
}
#[test]
fn test_zone_config_inequality_zone_name() {
let config1 = ZoneConfig::new("test1.com".to_string(), ZoneType::Primary);
let config2 = ZoneConfig::new("test2.com".to_string(), ZoneType::Primary);
assert_ne!(config1, config2);
}
#[test]
fn test_zone_config_inequality_zone_type() {
let config1 = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
let config2 = ZoneConfig::new("test.com".to_string(), ZoneType::Secondary);
assert_ne!(config1, config2);
}
#[test]
fn test_zone_config_clone() {
let mut config1 = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config1.file = Some("/var/cache/bind/test.com.zone".to_string());
config1
.raw_options
.insert("test".to_string(), "value".to_string());
let config2 = config1.clone();
assert_eq!(config1, config2);
assert_eq!(
config2.file,
Some("/var/cache/bind/test.com.zone".to_string())
);
assert_eq!(config2.raw_options.get("test"), Some(&"value".to_string()));
}
#[test]
fn test_boolean_serialization_true() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.inline_signing = Some(true);
config.check_integrity = Some(true);
config.multi_master = Some(true);
let block = config.to_rndc_block();
assert!(block.contains("inline-signing yes"));
assert!(block.contains("check-integrity yes"));
assert!(block.contains("multi-master yes"));
}
#[test]
fn test_boolean_serialization_false() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.inline_signing = Some(false);
config.check_integrity = Some(false);
config.multi_master = Some(false);
let block = config.to_rndc_block();
assert!(block.contains("inline-signing no"));
assert!(block.contains("check-integrity no"));
assert!(block.contains("multi-master no"));
}
#[test]
fn test_empty_collections_not_serialized() {
let mut config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
config.also_notify = Some(vec![]);
config.allow_transfer = Some(vec![]);
config.allow_update = Some(vec![]);
let block = config.to_rndc_block();
assert!(!block.contains("also-notify"));
assert!(!block.contains("allow-transfer"));
assert!(!block.contains("allow-update"));
}
#[test]
fn test_empty_raw_options_not_serialized() {
let config = ZoneConfig::new("test.com".to_string(), ZoneType::Primary);
let block = config.to_rndc_block();
assert!(block.contains("type primary"));
assert_eq!(block, "{ type primary; };");
}
}