use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use gspx::{Dataset, ExampleData, GraphKind, KernelPreset, load_ply_laplacian, load_ply_xyz};
use tempfile::{TempDir, tempdir};
fn create_example_data_dir() -> TempDir {
let dir = tempdir().expect("tempdir should be created");
fs::create_dir_all(dir.path().join("MESH")).expect("MESH directory should be created");
fs::create_dir_all(dir.path().join("KERNELS")).expect("KERNELS directory should be created");
fs::write(
dir.path().join("MESH").join("BUNNY.ply"),
r#"ply
format ascii 1.0
element vertex 4
property float x
property float y
property float z
element face 2
property list uchar int vertex_indices
end_header
0 0 0
1 0 0
1 1 0
0 1 0
3 0 1 2
3 0 2 3
"#,
)
.expect("mesh fixture should be written");
fs::write(
dir.path().join("KERNELS").join("MODIFIED_MORLET.json"),
r#"{
"poles": [
{ "q": -1.0, "r": [0.5] },
{ "q": -4.0, "r": [0.25] }
],
"d": [0.1]
}"#,
)
.expect("VF kernel fixture should be written");
fs::write(
dir.path().join("KERNELS").join("SHANNON.json"),
r#"{
"spectrum_bound": 4.0,
"min_lambda": 0.0,
"approximations": [
{ "coeffs": [1.0, 0.25, -0.125] }
]
}"#,
)
.expect("Chebyshev kernel fixture should be written");
dir
}
#[test]
fn example_data_loads_mesh_and_coords_from_local_dir() {
let dir = create_example_data_dir();
let data = ExampleData::from_dir(dir.path()).expect("local example data should open");
let laplacian = data
.graph(Dataset::Bunny, GraphKind::Mesh)
.expect("mesh graph should load from local directory");
let coords = data
.coords(Dataset::Bunny)
.expect("mesh coordinates should load from local directory");
assert_eq!(laplacian.shape(), (4, 4));
assert_eq!(coords.shape(), &[4, 3]);
}
#[test]
fn example_data_loads_kernel_presets_from_local_dir() {
let dir = create_example_data_dir();
let data = ExampleData::from_dir(dir.path()).expect("local example data should open");
let vf = data
.vf_kernel(KernelPreset::ModifiedMorlet)
.expect("VF kernel should load from local directory");
let cheby = data
.cheby_kernel(KernelPreset::Shannon)
.expect("Chebyshev kernel should load from local directory");
assert_eq!(vf.residues.nrows(), vf.poles.len());
assert_eq!(vf.direct.len(), vf.residues.ncols());
assert_eq!(cheby.coefficients.shape(), &[3, 1]);
}
#[test]
fn example_data_rejects_missing_directory() {
let missing = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("target")
.join("resource-tests")
.join("missing-library");
let err = ExampleData::from_dir(&missing).expect_err("missing directory should fail");
assert!(err.to_string().contains("example-data directory not found"));
}
#[test]
fn bunny_mesh_files_parse_when_present() {
let bunny = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("resources")
.join("library")
.join("MESH")
.join("BUNNY.ply");
if !bunny.exists() {
return;
}
let l = load_ply_laplacian(&bunny).expect("bunny laplacian should parse");
let xyz = load_ply_xyz(&bunny).expect("bunny coordinates should parse");
assert_eq!(l.rows(), l.cols());
assert_eq!(l.rows(), xyz.nrows());
assert_eq!(xyz.ncols(), 3);
assert!(l.nnz() > l.rows());
}
#[test]
fn ascii_ply_loaders_parse_fixture() {
let dir = tempdir().expect("tempdir should be created");
let path = dir.path().join("ascii_fixture.ply");
let content = r#"ply
format ascii 1.0
element vertex 4
property float x
property float y
property float z
element face 2
property list uchar int vertex_indices
end_header
0 0 0
1 0 0
1 1 0
0 1 0
3 0 1 2
3 0 2 3
"#;
fs::write(&path, content).expect("ascii ply fixture should be written");
let laplacian = load_ply_laplacian(&path).expect("ascii ply laplacian should load");
let xyz = load_ply_xyz(&path).expect("ascii ply coordinates should load");
assert_eq!(laplacian.shape(), (4, 4));
assert_eq!(xyz.shape(), &[4, 3]);
}
#[test]
fn binary_ply_loaders_parse_fixture_with_fallback_vertex_props() {
let dir = tempdir().expect("tempdir should be created");
let path = dir.path().join("binary_fixture.ply");
let mut file = File::create(&path).expect("binary ply file should be created");
let header = b"ply
format binary_little_endian 1.0
element vertex 3
property float px
property float py
property float pz
element face 1
property list uchar int vertex_indices
end_header
";
file.write_all(header).expect("header should be written");
for value in [0.0f32, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 1.0, 0.0] {
file.write_all(&value.to_le_bytes())
.expect("vertex bytes should be written");
}
file.write_all(&[3u8])
.expect("face arity byte should be written");
for index in [0i32, 1, 2] {
file.write_all(&index.to_le_bytes())
.expect("face index bytes should be written");
}
drop(file);
let laplacian = load_ply_laplacian(&path).expect("binary ply laplacian should load");
let xyz = load_ply_xyz(&path).expect("binary ply coordinates should load");
assert_eq!(laplacian.shape(), (3, 3));
assert_eq!(xyz.shape(), &[3, 3]);
assert_eq!(xyz[[2, 0]], 0.5);
assert_eq!(xyz[[2, 1]], 1.0);
assert_eq!(xyz[[2, 2]], 0.0);
}