use crate::{
cilassembly::{ChangeRefRc, CilAssembly},
metadata::{
tables::{AssemblyRefProcessorRaw, TableDataOwned, TableId},
token::Token,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct AssemblyRefProcessorBuilder {
processor: Option<u32>,
assembly_ref: Option<u32>,
}
impl AssemblyRefProcessorBuilder {
#[must_use]
pub fn new() -> Self {
Self {
processor: None,
assembly_ref: None,
}
}
#[must_use]
pub fn processor(mut self, processor: u32) -> Self {
self.processor = Some(processor);
self
}
#[must_use]
pub fn assembly_ref(mut self, assembly_ref: u32) -> Self {
self.assembly_ref = Some(assembly_ref);
self
}
pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc> {
let processor = self.processor.ok_or_else(|| {
Error::ModificationInvalid(
"Processor architecture identifier is required for AssemblyRefProcessor"
.to_string(),
)
})?;
let assembly_ref = self.assembly_ref.ok_or_else(|| {
Error::ModificationInvalid(
"AssemblyRef RID is required for AssemblyRefProcessor".to_string(),
)
})?;
let assembly_ref_processor = AssemblyRefProcessorRaw {
rid: 0,
token: Token::new(0),
offset: 0,
processor,
assembly_ref,
};
assembly.table_row_add(
TableId::AssemblyRefProcessor,
TableDataOwned::AssemblyRefProcessor(assembly_ref_processor),
)
}
}
impl Default for AssemblyRefProcessorBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
cilassembly::ChangeRefKind, test::factories::table::assemblyref::get_test_assembly,
};
#[test]
fn test_assemblyrefprocessor_builder_new() {
let builder = AssemblyRefProcessorBuilder::new();
assert!(builder.processor.is_none());
assert!(builder.assembly_ref.is_none());
}
#[test]
fn test_assemblyrefprocessor_builder_default() {
let builder = AssemblyRefProcessorBuilder::default();
assert!(builder.processor.is_none());
assert!(builder.assembly_ref.is_none());
}
#[test]
fn test_assemblyrefprocessor_builder_x64() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefProcessorBuilder::new()
.processor(0x8664) .assembly_ref(1)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(
ref_.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_x86() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefProcessorBuilder::new()
.processor(0x014C) .assembly_ref(2)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(
ref_.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_arm64() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefProcessorBuilder::new()
.processor(0xAA64) .assembly_ref(3)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(
ref_.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_no_requirement() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefProcessorBuilder::new()
.processor(0x0000) .assembly_ref(1)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(
ref_.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_missing_processor() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = AssemblyRefProcessorBuilder::new()
.assembly_ref(1)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("Processor architecture identifier is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_missing_assembly_ref() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = AssemblyRefProcessorBuilder::new()
.processor(0x8664)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("AssemblyRef RID is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_clone() {
let builder = AssemblyRefProcessorBuilder::new()
.processor(0x8664)
.assembly_ref(1);
let cloned = builder.clone();
assert_eq!(builder.processor, cloned.processor);
assert_eq!(builder.assembly_ref, cloned.assembly_ref);
}
#[test]
fn test_assemblyrefprocessor_builder_debug() {
let builder = AssemblyRefProcessorBuilder::new()
.processor(0x014C)
.assembly_ref(2);
let debug_str = format!("{builder:?}");
assert!(debug_str.contains("AssemblyRefProcessorBuilder"));
assert!(debug_str.contains("processor"));
assert!(debug_str.contains("assembly_ref"));
}
#[test]
fn test_assemblyrefprocessor_builder_fluent_interface() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefProcessorBuilder::new()
.processor(0x01C0) .assembly_ref(5)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(
ref_.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_multiple_builds() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = AssemblyRefProcessorBuilder::new()
.processor(0x8664) .assembly_ref(1)
.build(&mut assembly)
.expect("Should build first processor entry");
let ref2 = AssemblyRefProcessorBuilder::new()
.processor(0x014C) .assembly_ref(2)
.build(&mut assembly)
.expect("Should build second processor entry");
assert!(!std::sync::Arc::ptr_eq(&ref1, &ref2));
assert_eq!(
ref1.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
assert_eq!(
ref2.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_large_assembly_ref() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefProcessorBuilder::new()
.processor(0x8664)
.assembly_ref(0xFFFF) .build(&mut assembly)
.expect("Should handle large assembly ref RID");
assert_eq!(
ref_.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
#[test]
fn test_assemblyrefprocessor_builder_custom_processor() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefProcessorBuilder::new()
.processor(0x1234) .assembly_ref(1)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(
ref_.kind(),
ChangeRefKind::TableRow(TableId::AssemblyRefProcessor)
);
Ok(())
}
}