use crate::{
metadata::tables::{
CodedIndex, CodedIndexType, MethodDefBuilder, TableId, TypeAttributes, TypeDefBuilder,
},
test::{create_test_assembly_with_error, get_testfile_mscorlib, TestAssembly},
Error, Result,
};
pub fn owned_inheritance_validator_file_factory() -> Result<Vec<TestAssembly>> {
let mut assemblies = Vec::new();
let Some(clean_testfile) = get_testfile_mscorlib() else {
return Err(Error::Other(
"mscorlib.dll not available - test cannot run".to_string(),
));
};
assemblies.push(TestAssembly::new(&clean_testfile, true));
assemblies.push(create_assembly_with_sealed_type_inheritance()?);
assemblies.push(create_assembly_with_interface_inheritance_violation()?);
assemblies.push(create_assembly_with_accessibility_violation()?);
assemblies.push(create_assembly_with_abstract_concrete_violation()?);
Ok(assemblies)
}
pub fn create_assembly_with_circular_inheritance() -> Result<TestAssembly> {
create_test_assembly_with_error(
get_testfile_mscorlib,
"inheritance chain depth exceeds",
|assembly| {
let mut previous_token = None;
for i in 0..50 {
let mut builder = TypeDefBuilder::new()
.name(format!("DeepInheritanceType{i}"))
.namespace("Test.DeepInheritance")
.flags(TypeAttributes::CLASS | TypeAttributes::PUBLIC);
if let Some(parent_token) = previous_token {
builder = builder.extends(CodedIndex::new(
TableId::TypeDef,
parent_token,
CodedIndexType::TypeDefOrRef,
));
}
let current_token = builder.build(assembly)?;
previous_token = Some(
current_token
.token()
.expect("TypeDef token should be resolved")
.row(),
);
}
Ok(())
},
)
}
pub fn create_assembly_with_sealed_type_inheritance() -> Result<TestAssembly> {
create_test_assembly_with_error(
get_testfile_mscorlib,
"cannot inherit from sealed type",
|assembly| {
let sealed_base_token = TypeDefBuilder::new()
.name("SealedBaseType")
.namespace("Test.Sealed")
.flags(TypeAttributes::CLASS | TypeAttributes::PUBLIC | TypeAttributes::SEALED)
.build(assembly)?;
TypeDefBuilder::new()
.name("DerivedFromSealed")
.namespace("Test.Sealed")
.flags(TypeAttributes::CLASS | TypeAttributes::PUBLIC)
.extends(CodedIndex::new(
TableId::TypeDef,
sealed_base_token
.token()
.expect("TypeDef token should be resolved")
.row(),
CodedIndexType::TypeDefOrRef,
))
.build(assembly)?;
Ok(())
},
)
}
pub fn create_assembly_with_interface_inheritance_violation() -> Result<TestAssembly> {
create_test_assembly_with_error(
get_testfile_mscorlib,
"cannot inherit from interface",
|assembly| {
let interface_token = TypeDefBuilder::new()
.name("ITestInterface")
.namespace("Test.Interface")
.flags(
TypeAttributes::INTERFACE | TypeAttributes::ABSTRACT | TypeAttributes::PUBLIC,
)
.build(assembly)?;
TypeDefBuilder::new()
.name("ClassInheritingFromInterface")
.namespace("Test.Interface")
.flags(TypeAttributes::CLASS | TypeAttributes::PUBLIC)
.extends(CodedIndex::new(
TableId::TypeDef,
interface_token
.token()
.expect("TypeDef token should be resolved")
.row(),
CodedIndexType::TypeDefOrRef,
))
.build(assembly)?;
Ok(())
},
)
}
pub fn create_assembly_with_accessibility_violation() -> Result<TestAssembly> {
create_test_assembly_with_error(
get_testfile_mscorlib,
"cannot inherit from less accessible base type",
|assembly| {
let internal_base_token = TypeDefBuilder::new()
.name("InternalBaseType")
.namespace("Test.Accessibility")
.flags(TypeAttributes::CLASS | TypeAttributes::NOT_PUBLIC) .build(assembly)?;
TypeDefBuilder::new()
.name("PublicDerivedType")
.namespace("Test.Accessibility")
.flags(TypeAttributes::CLASS | TypeAttributes::PUBLIC) .extends(CodedIndex::new(
TableId::TypeDef,
internal_base_token
.token()
.expect("TypeDef token should be resolved")
.row(),
CodedIndexType::TypeDefOrRef,
))
.build(assembly)?;
Ok(())
},
)
}
pub fn create_assembly_with_abstract_concrete_violation() -> Result<TestAssembly> {
create_test_assembly_with_error(get_testfile_mscorlib, "must be abstract", |assembly| {
TypeDefBuilder::new()
.name("IConcreteInterface")
.namespace("Test.Abstract")
.flags(TypeAttributes::INTERFACE | TypeAttributes::PUBLIC) .build(assembly)?;
Ok(())
})
}
pub fn create_assembly_with_method_inheritance_violation() -> Result<TestAssembly> {
create_test_assembly_with_error(get_testfile_mscorlib, "Concrete type", |assembly| {
let _concrete_type_token = TypeDefBuilder::new()
.name("ConcreteClassWithAbstractMethods")
.namespace("Test.Methods")
.flags(TypeAttributes::CLASS | TypeAttributes::PUBLIC) .build(assembly)?;
let void_signature = vec![0x00, 0x00, 0x01];
MethodDefBuilder::new()
.name("AbstractMethodInConcreteClass")
.flags(0x0446)
.impl_flags(0x0000)
.signature(&void_signature)
.rva(0)
.build(assembly)?;
Ok(())
})
}