use crate::{
cilassembly::{ChangeRefRc, CilAssembly},
metadata::{
tables::{PropertyPtrRaw, TableDataOwned, TableId},
token::Token,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct PropertyPtrBuilder {
property: Option<u32>,
}
impl PropertyPtrBuilder {
#[must_use]
pub fn new() -> Self {
Self { property: None }
}
#[must_use]
pub fn property(mut self, property: u32) -> Self {
self.property = Some(property);
self
}
pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc> {
let property = self.property.ok_or_else(|| {
Error::ModificationInvalid("Property RID is required for PropertyPtr".to_string())
})?;
let property_ptr = PropertyPtrRaw {
rid: 0,
token: Token::new(0),
offset: 0,
property,
};
assembly.table_row_add(
TableId::PropertyPtr,
TableDataOwned::PropertyPtr(property_ptr),
)
}
}
impl Default for PropertyPtrBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test::factories::table::assemblyref::get_test_assembly;
use std::sync::Arc;
#[test]
fn test_propertyptr_builder_new() {
let builder = PropertyPtrBuilder::new();
assert!(builder.property.is_none());
}
#[test]
fn test_propertyptr_builder_default() {
let builder = PropertyPtrBuilder::default();
assert!(builder.property.is_none());
}
#[test]
fn test_propertyptr_builder_basic() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = PropertyPtrBuilder::new()
.property(1)
.build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_propertyptr_builder_reordering() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = PropertyPtrBuilder::new()
.property(15) .build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_propertyptr_builder_missing_property() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = PropertyPtrBuilder::new().build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("Property RID is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_propertyptr_builder_clone() {
let builder = PropertyPtrBuilder::new().property(6);
let cloned = builder.clone();
assert_eq!(builder.property, cloned.property);
}
#[test]
fn test_propertyptr_builder_debug() {
let builder = PropertyPtrBuilder::new().property(11);
let debug_str = format!("{builder:?}");
assert!(debug_str.contains("PropertyPtrBuilder"));
assert!(debug_str.contains("property"));
}
#[test]
fn test_propertyptr_builder_fluent_interface() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = PropertyPtrBuilder::new()
.property(25)
.build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_propertyptr_builder_multiple_builds() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = PropertyPtrBuilder::new()
.property(9)
.build(&mut assembly)
.expect("Should build first pointer");
let ref2 = PropertyPtrBuilder::new()
.property(4)
.build(&mut assembly)
.expect("Should build second pointer");
let ref3 = PropertyPtrBuilder::new()
.property(18)
.build(&mut assembly)
.expect("Should build third pointer");
assert!(!Arc::ptr_eq(&ref1, &ref2));
assert!(!Arc::ptr_eq(&ref2, &ref3));
Ok(())
}
#[test]
fn test_propertyptr_builder_large_property_rid() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = PropertyPtrBuilder::new()
.property(0xFFFF) .build(&mut assembly)
.expect("Should handle large property RID");
Ok(())
}
#[test]
fn test_propertyptr_builder_property_ordering_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let logical_to_physical = [(1, 12), (2, 6), (3, 15)];
for (_logical_idx, physical_property) in logical_to_physical {
let _change_ref = PropertyPtrBuilder::new()
.property(physical_property)
.build(&mut assembly)
.expect("Should build property pointer");
}
Ok(())
}
#[test]
fn test_propertyptr_builder_zero_property() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = PropertyPtrBuilder::new().property(0).build(&mut assembly);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_propertyptr_builder_type_property_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let type_properties = [7, 14, 3, 21, 9];
for &property_rid in &type_properties {
let _change_ref = PropertyPtrBuilder::new()
.property(property_rid)
.build(&mut assembly)
.expect("Should build property pointer");
}
Ok(())
}
#[test]
fn test_propertyptr_builder_compressed_metadata_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let compressed_order = [25, 10, 30, 5, 40, 15];
let mut pointer_refs = Vec::new();
for &property_order in &compressed_order {
let change_ref = PropertyPtrBuilder::new()
.property(property_order)
.build(&mut assembly)
.expect("Should build pointer for compressed metadata");
pointer_refs.push(change_ref);
}
assert_eq!(pointer_refs.len(), 6);
Ok(())
}
#[test]
fn test_propertyptr_builder_optimization_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let optimized_access_order = [100, 50, 200, 25, 150, 75, 300];
let mut optimization_refs = Vec::new();
for &optimized_property in &optimized_access_order {
let change_ref = PropertyPtrBuilder::new()
.property(optimized_property)
.build(&mut assembly)
.expect("Should build optimization pointer");
optimization_refs.push(change_ref);
}
assert_eq!(optimization_refs.len(), 7);
Ok(())
}
#[test]
fn test_propertyptr_builder_interface_property_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let interface_properties = [1, 5, 3, 8, 2];
for &prop_rid in &interface_properties {
let _change_ref = PropertyPtrBuilder::new()
.property(prop_rid)
.build(&mut assembly)
.expect("Should build interface property pointer");
}
Ok(())
}
#[test]
fn test_propertyptr_builder_edit_continue_property_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let original_properties = [10, 20, 30];
for &property_rid in &original_properties {
let _change_ref = PropertyPtrBuilder::new()
.property(property_rid)
.build(&mut assembly)
.expect("Should build property pointer for edit-continue");
}
let _new_property_ref = PropertyPtrBuilder::new()
.property(500) .build(&mut assembly)
.expect("Should build new property pointer");
Ok(())
}
}