1pub use checker::DomainChecker;
34pub use config::{load_env_config, ConfigManager, FileConfig, GenerationConfig};
35pub use error::DomainCheckError;
36pub use protocols::registry::{
37 get_all_known_tlds, get_available_presets, get_preset_tlds, get_preset_tlds_with_custom,
38 get_whois_server, initialize_bootstrap,
39};
40pub use types::{CheckConfig, CheckMethod, DomainInfo, DomainResult, OutputMode};
41pub use utils::expand_domain_inputs;
42
43pub mod generate;
45
46pub use generate::{apply_affixes, estimate_pattern_count, expand_pattern, generate_names};
48pub use types::{GenerateConfig, GenerationResult};
49
50mod checker;
52mod concurrent;
53mod config;
54mod error;
55mod protocols;
56mod types;
57mod utils;
58
59pub type Result<T> = std::result::Result<T, DomainCheckError>;
61
62pub const VERSION: &str = env!("CARGO_PKG_VERSION");
64pub const AUTHOR: &str = env!("CARGO_PKG_AUTHORS");
65
66pub fn init() {
71 }
74
75pub fn info() -> LibraryInfo {
77 LibraryInfo {
78 version: VERSION,
79 author: AUTHOR,
80 features: get_enabled_features(),
81 }
82}
83
84#[derive(Debug, Clone)]
86pub struct LibraryInfo {
87 pub version: &'static str,
88 pub author: &'static str,
89 pub features: Vec<&'static str>,
90}
91
92#[allow(clippy::vec_init_then_push)]
95fn get_enabled_features() -> Vec<&'static str> {
96 let mut features = Vec::new();
97
98 #[cfg(feature = "rdap")]
99 features.push("rdap");
100
101 #[cfg(feature = "whois")]
102 features.push("whois");
103
104 #[cfg(feature = "bootstrap")]
105 features.push("bootstrap");
106
107 #[cfg(feature = "debug")]
108 features.push("debug");
109
110 features
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
120 fn test_version_is_not_empty() {
121 assert!(!VERSION.is_empty());
122 }
123
124 #[test]
125 fn test_version_is_semver() {
126 let parts: Vec<&str> = VERSION.split('.').collect();
127 assert!(parts.len() >= 2, "VERSION should be semver: {}", VERSION);
128 for part in &parts {
129 assert!(
130 part.parse::<u32>().is_ok(),
131 "non-numeric semver part: {}",
132 part
133 );
134 }
135 }
136
137 #[test]
138 fn test_author_is_not_empty() {
139 assert!(!AUTHOR.is_empty());
140 }
141
142 #[test]
145 fn test_init_does_not_panic() {
146 init(); init(); }
149
150 #[test]
153 fn test_info_version_matches_constant() {
154 let info = info();
155 assert_eq!(info.version, VERSION);
156 }
157
158 #[test]
159 fn test_info_author_matches_constant() {
160 let info = info();
161 assert_eq!(info.author, AUTHOR);
162 }
163
164 #[test]
165 fn test_info_has_default_features() {
166 let info = info();
167 assert!(info.features.contains(&"rdap"), "missing rdap feature");
169 assert!(info.features.contains(&"whois"), "missing whois feature");
170 assert!(
171 info.features.contains(&"bootstrap"),
172 "missing bootstrap feature"
173 );
174 }
175
176 #[test]
177 fn test_library_info_debug() {
178 let info = info();
179 let debug = format!("{:?}", info);
180 assert!(debug.contains("LibraryInfo"));
181 assert!(debug.contains(VERSION));
182 }
183
184 #[test]
185 fn test_library_info_clone() {
186 let info = info();
187 let cloned = info.clone();
188 assert_eq!(info.version, cloned.version);
189 assert_eq!(info.author, cloned.author);
190 assert_eq!(info.features, cloned.features);
191 }
192
193 #[test]
196 fn test_result_type_alias_ok() {
197 let result: Result<i32> = Ok(42);
198 assert!(result.is_ok());
199 }
200
201 #[test]
202 fn test_result_type_alias_err() {
203 let result: Result<i32> = Err(DomainCheckError::invalid_domain("bad", "invalid"));
204 assert!(result.is_err());
205 }
206
207 #[test]
210 fn test_check_config_default() {
211 let config = CheckConfig::default();
212 assert!(config.concurrency > 0);
213 }
214
215 #[test]
216 fn test_domain_result_construction() {
217 let result = DomainResult {
218 domain: "example.com".to_string(),
219 available: Some(true),
220 info: None,
221 check_duration: None,
222 method_used: CheckMethod::Rdap,
223 error_message: None,
224 };
225 assert_eq!(result.domain, "example.com");
226 assert_eq!(result.available, Some(true));
227 }
228
229 #[test]
230 fn test_check_method_variants() {
231 let _rdap = CheckMethod::Rdap;
232 let _whois = CheckMethod::Whois;
233 let _unknown = CheckMethod::Unknown;
234 }
235
236 #[test]
237 fn test_output_mode_variants() {
238 let _streaming = OutputMode::Streaming;
239 let _collected = OutputMode::Collected;
240 let _auto = OutputMode::Auto;
241 }
242
243 #[test]
244 fn test_domain_checker_new() {
245 let checker = DomainChecker::new();
246 let config = checker.config();
247 assert!(config.concurrency > 0);
248 }
249}