use blvm_node::module::registry::manifest::ModuleManifest;
use blvm_node::module::validation::manifest_validator::{ManifestValidator, ValidationResult};
use std::collections::HashMap;
fn create_valid_manifest() -> ModuleManifest {
ModuleManifest {
name: "test-module".to_string(),
version: "1.0.0".to_string(),
description: Some("Test module".to_string()),
author: Some("Test Author".to_string()),
capabilities: Vec::new(),
rpc_overrides: Vec::new(),
dependencies: HashMap::new(),
optional_dependencies: HashMap::new(),
entry_point: "test-module.so".to_string(),
config_schema: HashMap::new(),
binary: None,
downloads: HashMap::new(),
signatures: None,
payment: None,
}
}
#[test]
fn test_manifest_validator_new() {
let validator = ManifestValidator::new();
}
#[test]
fn test_manifest_validator_default() {
let validator = ManifestValidator::default();
}
#[test]
fn test_manifest_validator_valid_manifest() {
let validator = ManifestValidator::new();
let manifest = create_valid_manifest();
let result = validator.validate(&manifest);
assert_eq!(result, ValidationResult::Valid);
}
#[test]
fn test_manifest_validator_empty_name() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
manifest.name = String::new();
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(errors.iter().any(|e| e.contains("name cannot be empty")));
}
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_validator_empty_version() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
manifest.version = String::new();
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(errors.iter().any(|e| e.contains("version cannot be empty")));
}
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_validator_empty_entry_point() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
manifest.entry_point = String::new();
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(
errors
.iter()
.any(|e| e.contains("Entry point cannot be empty"))
);
}
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_validator_invalid_version_format() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
manifest.version = "invalid".to_string();
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(errors.iter().any(|e| e.contains("Invalid version format")));
}
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_validator_valid_version_formats() {
let validator = ManifestValidator::new();
let valid_versions = vec![
"1.0",
"1.0.0",
"2.1.3",
"1.0.0-alpha",
"1.0.0+build",
"1.0.0-alpha+build",
];
for version in valid_versions {
let mut manifest = create_valid_manifest();
manifest.version = version.to_string();
let result = validator.validate(&manifest);
assert_eq!(
result,
ValidationResult::Valid,
"Version {version} should be valid"
);
}
}
#[test]
fn test_manifest_validator_invalid_name_format() {
let validator = ManifestValidator::new();
let invalid_names = vec![
"", "-invalid", "_invalid", "invalid name", "invalid@name", ];
for name in invalid_names {
let mut manifest = create_valid_manifest();
manifest.name = name.to_string();
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(
errors.iter().any(|e| e.contains("Invalid module name")),
"Name '{name}' should be invalid"
);
}
ValidationResult::Valid => panic!("Name '{name}' should be invalid"),
}
}
}
#[test]
fn test_manifest_validator_valid_name_formats() {
let validator = ManifestValidator::new();
let valid_names = vec![
"test-module",
"test_module",
"testModule",
"test123",
"a",
"module-name-with-dashes",
"module_name_with_underscores",
];
for name in valid_names {
let mut manifest = create_valid_manifest();
manifest.name = name.to_string();
let result = validator.validate(&manifest);
assert_eq!(
result,
ValidationResult::Valid,
"Name '{name}' should be valid"
);
}
}
#[test]
fn test_manifest_validator_invalid_capability() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
manifest.capabilities = vec!["invalid-capability".to_string()];
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(errors.iter().any(|e| e.contains("Unknown capability")));
}
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_validator_valid_capabilities() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
manifest.capabilities = vec![
"read_blockchain".to_string(),
"subscribe_events".to_string(),
"queue_inbound_block".to_string(),
];
let result = validator.validate(&manifest);
assert_eq!(result, ValidationResult::Valid);
}
#[test]
fn test_manifest_validator_invalid_dependency_name() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
let mut deps = HashMap::new();
deps.insert("invalid-name!".to_string(), "1.0.0".to_string());
manifest.dependencies = deps;
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(errors.iter().any(|e| e.contains("Invalid dependency name")));
}
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_validator_invalid_dependency_version() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
let mut deps = HashMap::new();
deps.insert("valid-dep".to_string(), "invalid-version".to_string());
manifest.dependencies = deps;
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(
errors
.iter()
.any(|e| e.contains("Invalid dependency version format"))
);
}
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_validator_valid_dependency_versions() {
let validator = ManifestValidator::new();
let valid_versions = vec!["1.0.0", ">=1.0.0", "<=2.0.0", "==1.0.0", "^1.0.0", "~1.0.0"];
for version in valid_versions {
let mut manifest = create_valid_manifest();
let mut deps = HashMap::new();
deps.insert("valid-dep".to_string(), version.to_string());
manifest.dependencies = deps;
let result = validator.validate(&manifest);
assert_eq!(
result,
ValidationResult::Valid,
"Version '{version}' should be valid"
);
}
}
#[test]
fn test_manifest_validator_multiple_errors() {
let validator = ManifestValidator::new();
let mut manifest = create_valid_manifest();
manifest.name = String::new();
manifest.version = "invalid".to_string();
manifest.entry_point = String::new();
let result = validator.validate(&manifest);
match result {
ValidationResult::Invalid(errors) => {
assert!(errors.len() >= 3); }
ValidationResult::Valid => panic!("Should be invalid"),
}
}
#[test]
fn test_manifest_content_without_signatures_strips_table() {
use blvm_node::module::validation::manifest_content_without_signatures;
let input = r#"
name = "test-module"
version = "1.0.0"
entry_point = "test-module.so"
[signatures]
threshold = "1-of-1"
[[signatures.maintainers]]
name = "bob"
public_key = "02bb"
signature = "cafe"
"#;
let stripped = manifest_content_without_signatures(input).unwrap();
let table = toml::from_str::<toml::Value>(&stripped)
.unwrap()
.as_table()
.unwrap()
.clone();
assert!(!table.contains_key("signatures"));
assert_eq!(
table.get("entry_point").unwrap().as_str(),
Some("test-module.so")
);
}
#[test]
fn test_validate_module_signature_unsigned_skips() {
use blvm_node::module::validation::manifest_validator::validate_module_signature;
use std::path::PathBuf;
let manifest = create_valid_manifest();
let binary_path = PathBuf::from("/nonexistent/binary.so");
let result = validate_module_signature(&manifest, &binary_path);
assert!(
result.is_ok(),
"unsigned manifests skip signature verification"
);
}
#[test]
fn test_validate_module_signature_signed_requires_manifest_file() {
use blvm_node::module::registry::manifest::{MaintainerSignature, SignatureSection};
use blvm_node::module::validation::manifest_validator::validate_module_signature;
use std::path::Path;
let mut manifest = create_valid_manifest();
manifest.signatures = Some(SignatureSection {
threshold: Some("1-of-1".to_string()),
maintainers: vec![MaintainerSignature {
name: "alice".to_string(),
public_key: "02".repeat(32),
signature: "00".repeat(64),
}],
});
let temp = tempfile::TempDir::new().unwrap();
let binary = temp.path().join("test-module.so");
std::fs::write(&binary, b"binary").unwrap();
let result = validate_module_signature(&manifest, &binary);
assert!(
result.is_err(),
"signed manifests must fail when module.toml is missing beside the binary"
);
}