use metadol::reflect::{FieldInfo, MethodInfo, TypeInfo, TypeKind, TypeRegistry};
#[test]
fn test_create_record_type() {
let user_type = TypeInfo::record("User")
.with_field(FieldInfo::new("id", "Int64"))
.with_field(FieldInfo::new("name", "String"))
.with_field(FieldInfo::new("email", "String").optional())
.with_doc("Represents a system user");
assert_eq!(user_type.name(), "User");
assert_eq!(user_type.kind(), TypeKind::Record);
assert_eq!(user_type.fields().len(), 3);
assert!(user_type.field("email").unwrap().is_optional());
}
#[test]
fn test_create_generic_type() {
let list_type = TypeInfo::generic("List")
.with_type_param("T")
.with_method(MethodInfo::new("push").with_param("item", "T"))
.with_method(MethodInfo::new("pop").returns("Option<T>"))
.with_method(MethodInfo::new("len").returns("Int64").pure());
assert_eq!(list_type.kind(), TypeKind::Generic);
assert_eq!(list_type.type_params(), &["T"]);
assert_eq!(list_type.methods().len(), 3);
assert!(list_type.method("len").unwrap().is_pure());
}
#[test]
fn test_type_inheritance() {
let admin_type = TypeInfo::record("Admin")
.with_parent("User")
.with_field(FieldInfo::new("permissions", "Array<String>"))
.implements("Authenticatable")
.implements("Authorizable");
assert_eq!(admin_type.parent(), Some("User"));
assert!(admin_type.traits().contains(&"Authenticatable".to_string()));
assert!(admin_type.traits().contains(&"Authorizable".to_string()));
}
#[test]
fn test_function_type() {
let handler_type = TypeInfo::function("EventHandler").with_method(
MethodInfo::new("handle")
.with_param("event", "Event")
.returns("Result<(), Error>"),
);
assert_eq!(handler_type.kind(), TypeKind::Function);
}
#[test]
fn test_field_with_all_options() {
let field = FieldInfo::new("status", "Status")
.optional()
.mutable()
.with_doc("Current status of the entity")
.with_default("Status::Pending");
assert_eq!(field.name(), "status");
assert_eq!(field.type_name(), "Status");
assert!(field.is_optional());
assert!(field.is_mutable());
assert_eq!(field.doc(), Some("Current status of the entity"));
assert_eq!(field.default(), Some("Status::Pending"));
}
#[test]
fn test_required_immutable_field() {
let field = FieldInfo::new("id", "UUID");
assert!(!field.is_optional());
assert!(!field.is_mutable());
assert!(field.doc().is_none());
assert!(field.default().is_none());
}
#[test]
fn test_method_with_multiple_params() {
let method = MethodInfo::new("transfer")
.with_param("from", "Account")
.with_param("to", "Account")
.with_param("amount", "Decimal")
.returns("Result<Transaction, Error>")
.with_doc("Transfers funds between accounts");
assert_eq!(method.name(), "transfer");
assert_eq!(method.params().len(), 3);
assert_eq!(
method.params()[0],
("from".to_string(), "Account".to_string())
);
assert_eq!(method.return_type(), "Result<Transaction, Error>");
}
#[test]
fn test_static_method() {
let method = MethodInfo::new("from_json")
.with_param("json", "String")
.returns("User")
.static_method()
.pure();
assert!(method.is_static());
assert!(method.is_pure());
}
#[test]
fn test_registry_with_primitives() {
let registry = TypeRegistry::with_primitives();
assert!(registry.lookup("Void").is_some());
assert!(registry.lookup("Bool").is_some());
assert!(registry.lookup("Int8").is_some());
assert!(registry.lookup("Int16").is_some());
assert!(registry.lookup("Int32").is_some());
assert!(registry.lookup("Int64").is_some());
assert!(registry.lookup("UInt8").is_some());
assert!(registry.lookup("UInt16").is_some());
assert!(registry.lookup("UInt32").is_some());
assert!(registry.lookup("UInt64").is_some());
assert!(registry.lookup("Float32").is_some());
assert!(registry.lookup("Float64").is_some());
assert!(registry.lookup("String").is_some());
assert_eq!(
registry.lookup("Int32").unwrap().kind(),
TypeKind::Primitive
);
}
#[test]
fn test_registry_register_and_lookup() {
let mut registry = TypeRegistry::new();
let product = TypeInfo::record("Product")
.with_field(FieldInfo::new("name", "String"))
.with_field(FieldInfo::new("price", "Decimal"));
registry.register(product);
let found = registry.lookup("Product");
assert!(found.is_some());
assert_eq!(found.unwrap().fields().len(), 2);
}
#[test]
fn test_registry_type_hierarchy() {
let mut registry = TypeRegistry::new();
registry.register(TypeInfo::record("Entity"));
registry.register(TypeInfo::record("User").with_parent("Entity"));
registry.register(TypeInfo::record("Admin").with_parent("User"));
registry.register(TypeInfo::record("Product").with_parent("Entity"));
let entity_subtypes = registry.subtypes("Entity");
assert_eq!(entity_subtypes.len(), 2);
let user_subtypes = registry.subtypes("User");
assert_eq!(user_subtypes.len(), 1); }
#[test]
fn test_registry_trait_implementors() {
let mut registry = TypeRegistry::new();
registry.register(
TypeInfo::record("User")
.implements("Serializable")
.implements("Validatable"),
);
registry.register(TypeInfo::record("Product").implements("Serializable"));
registry.register(TypeInfo::record("Order"));
let serializable = registry.implementors("Serializable");
assert_eq!(serializable.len(), 2);
let validatable = registry.implementors("Validatable");
assert_eq!(validatable.len(), 1);
}
#[test]
fn test_registry_iteration() {
let mut registry = TypeRegistry::new();
registry.register(TypeInfo::record("A"));
registry.register(TypeInfo::record("B"));
registry.register(TypeInfo::record("C"));
let names: Vec<&str> = registry.type_names().collect();
assert_eq!(names.len(), 3);
assert!(names.contains(&"A"));
assert!(names.contains(&"B"));
assert!(names.contains(&"C"));
}
#[test]
fn test_registry_remove_and_clear() {
let mut registry = TypeRegistry::new();
registry.register(TypeInfo::record("Temp1"));
registry.register(TypeInfo::record("Temp2"));
assert_eq!(registry.len(), 2);
let removed = registry.remove("Temp1");
assert!(removed.is_some());
assert_eq!(removed.unwrap().name(), "Temp1");
assert_eq!(registry.len(), 1);
registry.clear();
assert!(registry.is_empty());
}
#[test]
fn test_domain_model_registration() {
let mut registry = TypeRegistry::with_primitives();
registry.register(
TypeInfo::record("Address")
.with_field(FieldInfo::new("street", "String"))
.with_field(FieldInfo::new("city", "String"))
.with_field(FieldInfo::new("zip", "String"))
.with_doc("Physical address"),
);
registry.register(
TypeInfo::record("Customer")
.with_field(FieldInfo::new("id", "Int64"))
.with_field(FieldInfo::new("name", "String"))
.with_field(FieldInfo::new("billing_address", "Address"))
.with_field(FieldInfo::new("shipping_address", "Address").optional())
.implements("Entity")
.implements("Auditable"),
);
registry.register(
TypeInfo::record("Order")
.with_field(FieldInfo::new("id", "Int64"))
.with_field(FieldInfo::new("customer_id", "Int64"))
.with_field(FieldInfo::new("total", "Decimal"))
.with_field(FieldInfo::new("status", "OrderStatus"))
.with_method(MethodInfo::new("place").returns("Result<(), Error>"))
.with_method(MethodInfo::new("cancel").returns("Result<(), Error>"))
.implements("Entity")
.implements("Auditable"),
);
let customer = registry.lookup("Customer").unwrap();
assert!(customer.field("billing_address").is_some());
assert!(customer.field("shipping_address").unwrap().is_optional());
let auditables = registry.implementors("Auditable");
assert_eq!(auditables.len(), 2);
}
#[test]
fn test_serialization_metadata() {
let mut registry = TypeRegistry::new();
registry.register(
TypeInfo::record("Config")
.with_field(FieldInfo::new("host", "String").with_default("\"localhost\""))
.with_field(FieldInfo::new("port", "Int32").with_default("8080"))
.with_field(FieldInfo::new("timeout_ms", "Int64").optional()),
);
let config = registry.lookup("Config").unwrap();
for field in config.fields() {
if field.is_optional() {
assert_eq!(field.name(), "timeout_ms");
} else if field.default().is_some() {
assert!(field.name() == "host" || field.name() == "port");
}
}
}
#[test]
fn test_reflect_type_function() {
use metadol::reflect::reflect_type;
let mut registry = TypeRegistry::with_primitives();
registry.register(TypeInfo::record("MyType"));
let info = reflect_type(®istry, "MyType");
assert_eq!(info.name(), "MyType");
assert_eq!(info.kind(), TypeKind::Record);
let int_info = reflect_type(®istry, "Int32");
assert_eq!(int_info.kind(), TypeKind::Primitive);
let unknown = reflect_type(®istry, "NonExistent");
assert_eq!(unknown.kind(), TypeKind::Unknown);
}