use std::{path::PathBuf, sync::Arc};
use crate::{
cilassembly::CilAssembly,
metadata::{
method::MethodRc,
tables::{AssemblyRefRc, FileRc, ModuleRefRc},
token::Token,
typesystem::{CilTypeRc, CilTypeReference},
},
CilObject, Error, Result,
};
use super::{
builders::{AssemblyRefBuilder, CilTypeBuilder, FileBuilder, MethodBuilder, ModuleRefBuilder},
validator::TestAssembly,
};
pub mod dependencies;
pub fn create_module_ref(rid: u32, name: &str) -> ModuleRefRc {
ModuleRefBuilder::new()
.with_rid(rid)
.with_name(name)
.build()
}
pub fn create_assembly_ref(rid: u32, name: &str) -> AssemblyRefRc {
AssemblyRefBuilder::new()
.with_rid(rid)
.with_name(name)
.build()
}
pub fn create_file(rid: u32, name: &str) -> FileRc {
FileBuilder::new().with_rid(rid).with_name(name).build()
}
pub fn create_method(name: &str) -> MethodRc {
MethodBuilder::simple_void_method(name).build()
}
pub fn create_cil_type(
token: Token,
namespace: &str,
name: &str,
external: Option<CilTypeReference>,
) -> CilTypeRc {
CilTypeBuilder::new()
.with_token(token)
.with_namespace(namespace)
.with_name(name)
.with_external(external.unwrap_or_else(|| CilTypeReference::File(create_file(1, "test"))))
.build()
}
pub fn load_test_assembly(testfile_fn: fn() -> Option<PathBuf>) -> Result<CilAssembly> {
let testfile =
testfile_fn().ok_or_else(|| Error::Other("Test file not available".to_string()))?;
CilAssembly::from_path(&testfile)
}
pub fn create_test_assembly<F>(testfile_fn: fn() -> Option<PathBuf>, f: F) -> Result<TestAssembly>
where
F: FnOnce(&mut CilAssembly) -> Result<()>,
{
let mut assembly = load_test_assembly(testfile_fn)?;
f(&mut assembly)?;
let bytes = assembly.to_memory()?;
Ok(TestAssembly::from_bytes(bytes, false))
}
pub fn create_passing_test_assembly<F>(
testfile_fn: fn() -> Option<PathBuf>,
f: F,
) -> Result<TestAssembly>
where
F: FnOnce(&mut CilAssembly) -> Result<()>,
{
let mut assembly = load_test_assembly(testfile_fn)?;
f(&mut assembly)?;
let bytes = assembly.to_memory()?;
Ok(TestAssembly::from_bytes(bytes, true))
}
pub fn create_test_assembly_with_error<F>(
testfile_fn: fn() -> Option<PathBuf>,
error_pattern: &str,
f: F,
) -> Result<TestAssembly>
where
F: FnOnce(&mut CilAssembly) -> Result<()>,
{
let mut assembly = load_test_assembly(testfile_fn)?;
f(&mut assembly)?;
let bytes = assembly.to_memory()?;
Ok(TestAssembly::from_bytes_with_error(bytes, error_pattern))
}
pub fn test_assembly_arc() -> Arc<CilObject> {
use std::sync::LazyLock;
static TEST_ASSEMBLY: LazyLock<Arc<CilObject>> = LazyLock::new(|| {
Arc::new(
CilObject::from_path(
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests/samples/crafted_2.exe"),
)
.expect("Failed to load test assembly"),
)
});
Arc::clone(&TEST_ASSEMBLY)
}