use oxigdal_cli::util::inspect_file;
type TestResult = anyhow::Result<()>;
const EMPTY_GEOJSON: &str = r#"{"type":"FeatureCollection","features":[]}"#;
fn tmp_fixture(suffix: &str) -> std::path::PathBuf {
let unique = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
let mut p = std::env::temp_dir();
p.push(format!(
"oxigdal_inspect_test_{}_{}_{}",
std::process::id(),
unique,
suffix
));
p
}
fn write_geojson_fixture(suffix: &str) -> TestResult2<std::path::PathBuf> {
let path = tmp_fixture(suffix);
std::fs::write(&path, EMPTY_GEOJSON)?;
Ok(path)
}
type TestResult2<T> = anyhow::Result<T>;
#[test]
fn test_inspect_geojson_summary() -> TestResult {
let path = write_geojson_fixture("summary.geojson")?;
let report = inspect_file(path.to_string_lossy().as_ref(), false)?;
assert!(
report.format.contains("GeoJSON"),
"format should mention GeoJSON, got {}",
report.format
);
assert!(
report.vector.is_some(),
"GeoJSON inspection must produce a vector summary"
);
assert!(
report.raster.is_none(),
"GeoJSON inspection must not produce a raster summary"
);
let vector = report
.vector
.ok_or_else(|| anyhow::anyhow!("vector summary missing"))?;
assert_eq!(
vector.feature_count,
Some(0),
"empty FeatureCollection has zero features"
);
let _ = std::fs::remove_file(&path);
Ok(())
}
#[test]
fn test_inspect_reports_file_size() -> TestResult {
let path = write_geojson_fixture("size.geojson")?;
let expected = std::fs::metadata(&path)?.len();
let report = inspect_file(path.to_string_lossy().as_ref(), false)?;
assert_eq!(
report.file_size, expected,
"reported file_size must equal metadata().len()"
);
assert_eq!(
report.file_size,
EMPTY_GEOJSON.len() as u64,
"fixture size must equal the known content length"
);
let _ = std::fs::remove_file(&path);
Ok(())
}
#[test]
fn test_inspect_detects_extension() -> TestResult {
let path = write_geojson_fixture("ext.geojson")?;
let report = inspect_file(path.to_string_lossy().as_ref(), false)?;
assert_eq!(
report.extension, "geojson",
"extension field must be the lower-cased extension without a dot"
);
let _ = std::fs::remove_file(&path);
Ok(())
}
#[test]
fn test_inspect_nonexistent_file_errors() -> TestResult {
let path = tmp_fixture("does_not_exist.geojson");
assert!(
!path.exists(),
"fixture path must not exist for this test to be meaningful"
);
let result = inspect_file(path.to_string_lossy().as_ref(), false);
assert!(result.is_err(), "inspecting a missing file must return Err");
Ok(())
}
#[test]
fn test_inspect_json_output_is_valid_json() -> TestResult {
let path = write_geojson_fixture("json_valid.geojson")?;
let report = inspect_file(path.to_string_lossy().as_ref(), false)?;
let serialized = serde_json::to_string(&report)?;
let parsed: serde_json::Value = serde_json::from_str(&serialized)?;
assert!(
parsed.is_object(),
"serialized report must be a JSON object"
);
let _ = std::fs::remove_file(&path);
Ok(())
}
#[test]
fn test_inspect_json_output_schema_has_format_field() -> TestResult {
let path = write_geojson_fixture("json_schema.geojson")?;
let report = inspect_file(path.to_string_lossy().as_ref(), false)?;
let serialized = serde_json::to_string(&report)?;
let parsed: serde_json::Value = serde_json::from_str(&serialized)?;
assert!(
parsed.get("format").is_some(),
"serialized report must contain a `format` key"
);
assert_eq!(
parsed.get("format").and_then(|v| v.as_str()),
Some("GeoJSON"),
"the `format` key must carry the detected format"
);
let _ = std::fs::remove_file(&path);
Ok(())
}
#[test]
fn test_inspect_unknown_format_does_not_panic() -> TestResult {
let path = tmp_fixture("junk.xyz");
std::fs::write(&path, b"\x00\x01\x02 not a real geospatial file")?;
let result = inspect_file(path.to_string_lossy().as_ref(), false);
match result {
Ok(report) => assert_eq!(
report.format, "Unknown",
"a recognised-but-unsupported result must report format Unknown"
),
Err(_) => {
}
}
let _ = std::fs::remove_file(&path);
Ok(())
}
#[test]
fn test_inspect_detailed_flag() -> TestResult {
let path = write_geojson_fixture("detailed.geojson")?;
let report = inspect_file(path.to_string_lossy().as_ref(), true)?;
let vector = report
.vector
.ok_or_else(|| anyhow::anyhow!("detailed GeoJSON inspection missing vector summary"))?;
assert_eq!(
vector.layer_count, 1,
"a GeoJSON FeatureCollection is a single layer"
);
let _ = std::fs::remove_file(&path);
Ok(())
}
#[test]
fn test_inspect_geotiff_summary() -> TestResult {
use oxigdal_cli::util::raster;
use oxigdal_core::buffer::RasterBuffer;
use oxigdal_core::types::{GeoTransform, NoDataValue, RasterDataType};
let path = tmp_fixture("raster.tif");
let _ = std::fs::remove_file(&path);
let width = 16u64;
let height = 16u64;
let pixels: Vec<u8> = (0..(width * height) as usize)
.map(|i| (i % 256) as u8)
.collect();
let band = RasterBuffer::new(
pixels,
width,
height,
RasterDataType::UInt8,
NoDataValue::None,
)
.map_err(|e| anyhow::anyhow!("build raster buffer: {e}"))?;
let geo_transform = GeoTransform {
origin_x: 0.0,
origin_y: 16.0,
pixel_width: 1.0,
pixel_height: -1.0,
row_rotation: 0.0,
col_rotation: 0.0,
};
let write_result =
raster::write_multi_band(&path, &[band], Some(geo_transform), Some(4326), None);
if write_result.is_err() {
let gj = write_geojson_fixture("raster_fallback.geojson")?;
let report = inspect_file(gj.to_string_lossy().as_ref(), false)?;
assert!(
!report.is_cloud,
"a local path must report is_cloud = false"
);
let _ = std::fs::remove_file(&gj);
return Ok(());
}
let report = inspect_file(path.to_string_lossy().as_ref(), true)?;
assert_eq!(report.format, "GeoTIFF", "format must be GeoTIFF");
let raster_summary = report
.raster
.ok_or_else(|| anyhow::anyhow!("GeoTIFF inspection missing raster summary"))?;
assert_eq!(raster_summary.width, 16, "raster width must match");
assert_eq!(raster_summary.height, 16, "raster height must match");
assert_eq!(raster_summary.band_count, 1, "single-band raster");
assert!(
report.vector.is_none(),
"GeoTIFF inspection must not produce a vector summary"
);
let _ = std::fs::remove_file(&path);
Ok(())
}