use crate::{
cilassembly::{ChangeRefRc, CilAssembly},
metadata::{
tables::{ParamPtrRaw, TableDataOwned, TableId},
token::Token,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct ParamPtrBuilder {
param: Option<u32>,
}
impl ParamPtrBuilder {
#[must_use]
pub fn new() -> Self {
Self { param: None }
}
#[must_use]
pub fn param(mut self, param: u32) -> Self {
self.param = Some(param);
self
}
pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc> {
let param = self.param.ok_or_else(|| {
Error::ModificationInvalid("Param RID is required for ParamPtr".to_string())
})?;
let param_ptr = ParamPtrRaw {
rid: 0,
token: Token::new(0),
offset: 0,
param,
};
assembly.table_row_add(TableId::ParamPtr, TableDataOwned::ParamPtr(param_ptr))
}
}
impl Default for ParamPtrBuilder {
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_paramptr_builder_new() {
let builder = ParamPtrBuilder::new();
assert!(builder.param.is_none());
}
#[test]
fn test_paramptr_builder_default() {
let builder = ParamPtrBuilder::default();
assert!(builder.param.is_none());
}
#[test]
fn test_paramptr_builder_basic() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = ParamPtrBuilder::new()
.param(1)
.build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_paramptr_builder_reordering() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = ParamPtrBuilder::new()
.param(10) .build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_paramptr_builder_missing_param() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = ParamPtrBuilder::new().build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("Param RID is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_paramptr_builder_clone() {
let builder = ParamPtrBuilder::new().param(3);
let cloned = builder.clone();
assert_eq!(builder.param, cloned.param);
}
#[test]
fn test_paramptr_builder_debug() {
let builder = ParamPtrBuilder::new().param(7);
let debug_str = format!("{builder:?}");
assert!(debug_str.contains("ParamPtrBuilder"));
assert!(debug_str.contains("param"));
}
#[test]
fn test_paramptr_builder_fluent_interface() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = ParamPtrBuilder::new()
.param(15)
.build(&mut assembly)
.expect("Should build successfully");
Ok(())
}
#[test]
fn test_paramptr_builder_multiple_builds() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = ParamPtrBuilder::new()
.param(5)
.build(&mut assembly)
.expect("Should build first pointer");
let ref2 = ParamPtrBuilder::new()
.param(2)
.build(&mut assembly)
.expect("Should build second pointer");
let ref3 = ParamPtrBuilder::new()
.param(8)
.build(&mut assembly)
.expect("Should build third pointer");
assert!(!Arc::ptr_eq(&ref1, &ref2));
assert!(!Arc::ptr_eq(&ref2, &ref3));
Ok(())
}
#[test]
fn test_paramptr_builder_large_param_rid() -> Result<()> {
let mut assembly = get_test_assembly()?;
let _change_ref = ParamPtrBuilder::new()
.param(0xFFFF) .build(&mut assembly)
.expect("Should handle large param RID");
Ok(())
}
#[test]
fn test_paramptr_builder_param_ordering_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let logical_to_physical = [(1, 8), (2, 3), (3, 6)];
for (_logical_idx, physical_param) in logical_to_physical {
let _change_ref = ParamPtrBuilder::new()
.param(physical_param)
.build(&mut assembly)
.expect("Should build parameter pointer");
}
Ok(())
}
#[test]
fn test_paramptr_builder_zero_param() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = ParamPtrBuilder::new().param(0).build(&mut assembly);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_paramptr_builder_method_parameter_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let method_params = [4, 1, 7, 2];
for ¶m_rid in &method_params {
let _change_ref = ParamPtrBuilder::new()
.param(param_rid)
.build(&mut assembly)
.expect("Should build parameter pointer");
}
Ok(())
}
#[test]
fn test_paramptr_builder_compressed_metadata_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let compressed_order = [10, 5, 15, 1, 20];
let mut pointer_refs = Vec::new();
for ¶m_order in &compressed_order {
let change_ref = ParamPtrBuilder::new()
.param(param_order)
.build(&mut assembly)
.expect("Should build pointer for compressed metadata");
pointer_refs.push(change_ref);
}
assert_eq!(pointer_refs.len(), 5);
Ok(())
}
#[test]
fn test_paramptr_builder_edit_continue_parameter_scenario() -> Result<()> {
let mut assembly = get_test_assembly()?;
let original_params = [1, 2, 3];
for ¶m_rid in &original_params {
let _change_ref = ParamPtrBuilder::new()
.param(param_rid)
.build(&mut assembly)
.expect("Should build parameter pointer for edit-continue");
}
let _new_param_ref = ParamPtrBuilder::new()
.param(100) .build(&mut assembly)
.expect("Should build new parameter pointer");
Ok(())
}
}