#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::needless_raw_string_hashes,
clippy::duration_suboptimal_units,
clippy::branches_sharing_code,
clippy::used_underscore_binding,
clippy::single_char_pattern,
clippy::ignore_without_reason,
clippy::cloned_ref_to_slice_refs,
clippy::doc_overindented_list_items,
clippy::match_wildcard_for_single_variants,
clippy::ignored_unit_patterns,
clippy::needless_collect,
clippy::unnecessary_map_or,
clippy::manual_flatten,
clippy::manual_strip,
clippy::future_not_send,
clippy::unnested_or_patterns,
clippy::no_effect_underscore_binding,
clippy::literal_string_with_formatting_args
)]
use std::collections::HashSet;
use std::fs;
use std::path::Path;
const ACTIVE_ERROR_CODES: &[&str] = &[
"E0001", "E0002", "E0003", "E0004", "E0005", "E0006", "E0007", "E0008", "E0009", "E0010",
"E0011", "E0012", "E0013", "E0014", "E0020", "E0021", "E0022", "E0023", "E0024", "E0025",
"E0027", "E0028", "E0029",
];
const RESERVED_ERROR_CODES: &[&str] = &["E0015", "E0016", "E0017", "E0018", "E0019", "E0026"];
#[test]
fn test_all_active_error_codes_documented() {
let doc_path = Path::new(".specify/specs/140-agent-diataxis/AGENT_CONSTRAINTS.md");
let doc_content = fs::read_to_string(doc_path).unwrap_or_else(|_| {
fs::read_to_string("../../.specify/specs/140-agent-diataxis/AGENT_CONSTRAINTS.md")
.expect("AGENT_CONSTRAINTS.md not found in expected paths")
});
let documented_codes: HashSet<String> = doc_content
.lines()
.filter_map(|line| {
if (line.starts_with("## `E") || line.starts_with("### `E")) && line.ends_with('`') {
let start = line.find('`').unwrap_or(0) + 1;
let end = line.rfind('`').unwrap_or(start);
Some(line[start..end].to_string())
} else {
None
}
})
.collect();
let mut missing_codes = Vec::new();
for code in ACTIVE_ERROR_CODES {
if !documented_codes.contains(*code) {
missing_codes.push(*code);
}
}
assert!(
missing_codes.is_empty(),
"The following error codes are not documented in AGENT_CONSTRAINTS.md: {:?}\n\
Please add sections with format: ## `EXXXX`\n\
Each section must include RULE, REASON, FIX, and CONTEXT fields.",
missing_codes
);
}
#[test]
fn test_documented_codes_have_required_sections() {
let doc_path = Path::new(".specify/specs/140-agent-diataxis/AGENT_CONSTRAINTS.md");
let doc_content = fs::read_to_string(doc_path).unwrap_or_else(|_| {
fs::read_to_string("../../.specify/specs/140-agent-diataxis/AGENT_CONSTRAINTS.md")
.expect("AGENT_CONSTRAINTS.md not found")
});
let lines: Vec<&str> = doc_content.lines().collect();
let mut i = 0;
while i < lines.len() {
let line = lines[i];
if (line.starts_with("## `E") || line.starts_with("### `E")) && line.ends_with('`') {
let mut section = String::from(line);
i += 1;
while i < lines.len() && !lines[i].starts_with("## ") && !lines[i].starts_with("### ") {
section.push('\n');
section.push_str(lines[i]);
i += 1;
}
let section = section;
let first_line = section.lines().next().unwrap_or("");
let code = if let Some(start) = first_line.find('`') {
if let Some(end) = first_line.rfind('`') {
&first_line[start + 1..end]
} else {
""
}
} else {
""
};
if code.is_empty() {
i += 1;
continue;
}
let section_content = section.to_lowercase();
let has_rule = section_content.contains("**rule:**");
let has_reason = section_content.contains("**reason:**");
let has_fix = section_content.contains("**fix:**");
assert!(
has_rule && has_reason && has_fix,
"Error code {} is missing required sections.\n\
Required: **RULE:**, **REASON:**, **FIX:**\n\
Found: rule={}, reason={}, fix={}",
code,
has_rule,
has_reason,
has_fix
);
} else {
i += 1;
}
}
}
#[test]
fn test_no_reserved_codes_emitted() {
let src_path = "crates/ggen-core/src/";
let src_path_alt = "src/";
let mut found_reserved = Vec::new();
for code in RESERVED_ERROR_CODES {
let pattern = format!("error[{}]", code);
use walkdir::WalkDir;
let search_path = if Path::new(src_path).exists() {
src_path
} else {
src_path_alt
};
for entry in WalkDir::new(search_path)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().map_or(false, |ext| ext == "rs"))
{
if let Ok(content) = fs::read_to_string(entry.path()) {
if content.contains(&pattern) {
found_reserved.push((code, entry.path().to_string_lossy().to_string()));
}
}
}
}
assert!(
found_reserved.is_empty(),
"Reserved error codes found in source code (should only appear in documentation):\n{:?}",
found_reserved
);
}
#[test]
fn test_no_orphan_error_codes_in_source() {
let src_path = "crates/ggen-core/src/";
let src_path_alt = "src/";
let mut source_codes = HashSet::new();
use walkdir::WalkDir;
let search_path = if Path::new(src_path).exists() {
src_path
} else {
src_path_alt
};
for entry in WalkDir::new(search_path)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().map_or(false, |ext| ext == "rs"))
{
if let Ok(content) = fs::read_to_string(entry.path()) {
for line in content.lines() {
if let Some(pos) = line.find("error[E") {
if let Some(end) = line[pos..].find(']') {
let code = &line[pos + 6..pos + end];
source_codes.insert(code.to_string());
}
}
}
}
}
let expected_codes: HashSet<String> = ACTIVE_ERROR_CODES
.iter()
.chain(RESERVED_ERROR_CODES.iter())
.map(|s| s.to_string())
.collect();
let orphans: Vec<String> = source_codes
.iter()
.filter(|code| !expected_codes.contains(*code))
.cloned()
.collect();
assert!(
orphans.is_empty(),
"Found error codes in source that are not in ACTIVE_ERROR_CODES or RESERVED_ERROR_CODES: {:?}\n\
Either add them to the constant or remove them from the code.",
orphans
);
}
#[test]
fn test_error_code_sequence_consistency() {
let mut expected_active = HashSet::new();
let mut expected_reserved = HashSet::new();
for i in 1..=14 {
expected_active.insert(format!("E{:04}", i));
}
for i in 15..=19 {
expected_reserved.insert(format!("E{:04}", i));
}
for i in 20..=25 {
expected_active.insert(format!("E{:04}", i));
}
for i in 27..=29 {
expected_active.insert(format!("E{:04}", i));
}
expected_reserved.insert("E0026".to_string());
let actual_active: HashSet<String> = ACTIVE_ERROR_CODES.iter().map(|s| s.to_string()).collect();
assert_eq!(
actual_active, expected_active,
"Active error codes don't match expected sequence"
);
let actual_reserved: HashSet<String> =
RESERVED_ERROR_CODES.iter().map(|s| s.to_string()).collect();
assert_eq!(
actual_reserved, expected_reserved,
"Reserved error codes don't match expected sequence"
);
}
#[test]
fn test_error_codes_from_each_module() {
let module_code_map = vec![
("codegen/merge.rs", "E0001"),
("codegen/executor.rs", "E0001"),
("manifest/validation.rs", "E0010"),
("manifest/validation.rs", "E0011"),
("codegen/pipeline.rs", "E0012"),
("validation/preflight.rs", "E0020"),
("validation/preflight.rs", "E0021"),
];
for (module_path, expected_code) in module_code_map {
let full_path = format!("crates/ggen-core/src/{}", module_path);
let fallback_path = format!("src/{}", module_path);
let content = fs::read_to_string(&full_path)
.or_else(|_| fs::read_to_string(&fallback_path))
.unwrap_or_else(|_| format!("File not found: {} or {}", full_path, fallback_path));
let pattern = format!("error[{}]", expected_code);
assert!(
content.contains(&pattern),
"Expected error code {} not found in {}",
expected_code,
module_path
);
}
}