use crate::error::GermanicResult;
use crate::types::{GRM_MAGIC, GrmHeader};
pub fn validate_grm(data: &[u8]) -> GermanicResult<GrmValidation> {
if data.len() < 4 {
return Ok(GrmValidation {
valid: false,
schema_id: None,
error: Some("File too short for magic bytes".to_string()),
});
}
if data[0..4] != GRM_MAGIC {
return Ok(GrmValidation {
valid: false,
schema_id: None,
error: Some(format!(
"Invalid magic bytes: {:02X?} (expected: {:02X?})",
&data[0..4],
&GRM_MAGIC
)),
});
}
match GrmHeader::from_bytes(data) {
Ok((header, header_len)) => {
let payload = &data[header_len..];
if payload.is_empty() {
return Ok(GrmValidation {
valid: false,
schema_id: Some(header.schema_id),
error: Some("Header valid but payload is empty".to_string()),
});
}
if payload.len() < 8 {
return Ok(GrmValidation {
valid: false,
schema_id: Some(header.schema_id),
error: Some(format!(
"Payload too short for valid FlatBuffer: {} bytes (minimum: 8)",
payload.len()
)),
});
}
Ok(GrmValidation {
valid: true,
schema_id: Some(header.schema_id),
error: None,
})
}
Err(e) => Ok(GrmValidation {
valid: false,
schema_id: None,
error: Some(format!("Header error: {}", e)),
}),
}
}
#[derive(Debug, Clone)]
pub struct GrmValidation {
pub valid: bool,
pub schema_id: Option<String>,
pub error: Option<String>,
}
pub fn validate_json<S>(json: &str) -> GermanicResult<S>
where
S: serde::de::DeserializeOwned + crate::schema::Validate,
{
let schema: S = serde_json::from_str(json)?;
schema.validate()?;
Ok(schema)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_grm_too_short() {
let data = [0x47, 0x52, 0x4D]; let result = validate_grm(&data).unwrap();
assert!(!result.valid);
assert!(result.error.unwrap().contains("too short"));
}
#[test]
fn test_validate_grm_invalid_magic() {
let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let result = validate_grm(&data).unwrap();
assert!(!result.valid);
assert!(result.error.unwrap().contains("magic"));
}
#[test]
fn test_validate_grm_empty_payload() {
let header = GrmHeader::new("test.v1");
let bytes = header.to_bytes().unwrap();
let result = validate_grm(&bytes).unwrap();
assert!(!result.valid);
assert!(result.error.unwrap().contains("payload is empty"));
}
#[test]
fn test_validate_grm_payload_too_short() {
let header = GrmHeader::new("test.v1");
let mut bytes = header.to_bytes().unwrap();
bytes.extend_from_slice(&[0x00; 4]); let result = validate_grm(&bytes).unwrap();
assert!(!result.valid);
assert!(result.error.unwrap().contains("Payload too short"));
}
#[test]
fn test_validate_grm_valid() {
let header = GrmHeader::new("test.v1");
let mut bytes = header.to_bytes().unwrap();
bytes.extend_from_slice(&[0x00; 16]); let result = validate_grm(&bytes).unwrap();
assert!(result.valid);
assert_eq!(result.schema_id, Some("test.v1".to_string()));
}
}