use sha2::{Digest, Sha256};
use std::path::{Path, PathBuf};
use std::process::Command;
fn workspace_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.to_path_buf()
}
fn hash_dir(dir: &Path) -> String {
hash_dir_except(dir, &[])
}
fn hash_dir_except(dir: &Path, skip: &[&str]) -> String {
let mut files: Vec<(String, Vec<u8>)> = Vec::new();
collect(dir, dir, &mut files);
files.retain(|(rel, _)| !skip.contains(&rel.as_str()));
files.sort_by(|a, b| a.0.cmp(&b.0));
let mut h = Sha256::new();
for (rel, content) in &files {
h.update(rel.as_bytes());
h.update(b"\0");
h.update(content);
}
h.finalize().iter().map(|b| format!("{b:02x}")).collect()
}
fn collect(base: &Path, dir: &Path, out: &mut Vec<(String, Vec<u8>)>) {
for entry in std::fs::read_dir(dir).unwrap().flatten() {
let path = entry.path();
if path.is_dir() {
collect(base, &path, out);
} else {
let rel = path.strip_prefix(base).unwrap().to_string_lossy().into_owned();
out.push((rel, std::fs::read(&path).unwrap()));
}
}
}
#[test]
fn cimmodel_codegen_stable() {
let root = workspace_root();
let out = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cimmodel");
let _ = std::fs::remove_dir_all(&out);
std::fs::create_dir_all(&out).unwrap();
let status = Command::new(env!("CARGO_BIN_EXE_cimgen"))
.current_dir(&root)
.arg("--output")
.arg(&out)
.arg("--skip-shacl")
.arg("--skip-python-stubs")
.status()
.unwrap();
assert!(status.success(), "cimgen exited with failure");
let hash = hash_dir(&out);
assert_eq!(hash, "655d958b74d0f9975c26f9fc4d2fbfde518406f986286ab84e7efc07b6f86484", "cimmodel output drifted — rerun to update hash");
}
#[test]
fn nc_shapes_codegen_stable() {
let root = workspace_root();
let structs_out = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cimmodel-ncshapes");
let shacl_out = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cimvalidation-ncshapes");
let _ = std::fs::remove_dir_all(&structs_out);
let _ = std::fs::remove_dir_all(&shacl_out);
std::fs::create_dir_all(&structs_out).unwrap();
std::fs::create_dir_all(&shacl_out).unwrap();
let status = Command::new(env!("CARGO_BIN_EXE_cimgen"))
.current_dir(&root)
.arg("--output")
.arg(&structs_out)
.arg("--shacl-output")
.arg(&shacl_out)
.arg("--skip-python-stubs")
.status()
.unwrap();
assert!(status.success(), "cimgen exited with failure");
let mut h = Sha256::new();
h.update(std::fs::read(shacl_out.join("nc_shapes.rs")).unwrap());
h.update(std::fs::read(shacl_out.join("nc_profiles.rs")).unwrap());
let hash: String = h.finalize().iter().map(|b| format!("{b:02x}")).collect();
assert_eq!(hash, "8eab0fb8aeb3147c9c0e45842a4c83818fc4688a6de17bfccc4dc6ee8d08e0ce", "NC shape table drifted — rerun to update hash");
}
#[test]
fn cgmes_shapes_codegen_stable() {
let root = workspace_root();
let structs_out = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cimmodel-cgmesshapes");
let shacl_out = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cimvalidation-cgmesshapes");
let _ = std::fs::remove_dir_all(&structs_out);
let _ = std::fs::remove_dir_all(&shacl_out);
std::fs::create_dir_all(&structs_out).unwrap();
std::fs::create_dir_all(&shacl_out).unwrap();
let status = Command::new(env!("CARGO_BIN_EXE_cimgen"))
.current_dir(&root)
.arg("--output")
.arg(&structs_out)
.arg("--shacl-output")
.arg(&shacl_out)
.arg("--skip-python-stubs")
.status()
.unwrap();
assert!(status.success(), "cimgen exited with failure");
let mut h = Sha256::new();
h.update(std::fs::read(shacl_out.join("cgmes_shapes.rs")).unwrap());
h.update(std::fs::read(shacl_out.join("cgmes_profiles.rs")).unwrap());
let hash: String = h.finalize().iter().map(|b| format!("{b:02x}")).collect();
assert_eq!(hash, "b5d34de7f05d21ca601cdd8055e8434601384336948c870c909aff0dec18bf27", "CGMES shape table drifted — rerun to update hash");
}
#[test]
fn nc_classes_codegen_stable() {
let root = workspace_root();
let out = Path::new(env!("CARGO_TARGET_TMPDIR")).join("cimmodel-nc");
let _ = std::fs::remove_dir_all(&out);
std::fs::create_dir_all(&out).unwrap();
let status = Command::new(env!("CARGO_BIN_EXE_cimgen"))
.current_dir(&root)
.arg("--output")
.arg(&out)
.arg("--skip-shacl")
.arg("--skip-python-stubs")
.status()
.unwrap();
assert!(status.success(), "cimgen exited with failure");
let mut h = Sha256::new();
h.update(std::fs::read(out.join("nc_classes.rs")).unwrap());
let hash: String = h.finalize().iter().map(|b| format!("{b:02x}")).collect();
assert_eq!(hash, "0fe987cab0155b15c7e52ebe254f33fc1a7b789655e539e0e7aeda856b722ee9", "NC class table drifted — rerun to update hash");
}