use crate::{
cilassembly::{ChangeRefRc, CilAssembly},
metadata::{
tables::{AssemblyRefOsRaw, TableDataOwned, TableId},
token::Token,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct AssemblyRefOSBuilder {
os_platform_id: Option<u32>,
os_major_version: Option<u32>,
os_minor_version: Option<u32>,
assembly_ref: Option<u32>,
}
impl AssemblyRefOSBuilder {
#[must_use]
pub fn new() -> Self {
Self {
os_platform_id: None,
os_major_version: None,
os_minor_version: None,
assembly_ref: None,
}
}
#[must_use]
pub fn os_platform_id(mut self, os_platform_id: u32) -> Self {
self.os_platform_id = Some(os_platform_id);
self
}
#[must_use]
pub fn os_major_version(mut self, os_major_version: u32) -> Self {
self.os_major_version = Some(os_major_version);
self
}
#[must_use]
pub fn os_minor_version(mut self, os_minor_version: u32) -> Self {
self.os_minor_version = Some(os_minor_version);
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 os_platform_id = self.os_platform_id.ok_or_else(|| {
Error::ModificationInvalid(
"OS platform identifier is required for AssemblyRefOS".to_string(),
)
})?;
let os_major_version = self.os_major_version.ok_or_else(|| {
Error::ModificationInvalid("OS major version is required for AssemblyRefOS".to_string())
})?;
let os_minor_version = self.os_minor_version.ok_or_else(|| {
Error::ModificationInvalid("OS minor version is required for AssemblyRefOS".to_string())
})?;
let assembly_ref = self.assembly_ref.ok_or_else(|| {
Error::ModificationInvalid("AssemblyRef RID is required for AssemblyRefOS".to_string())
})?;
let assembly_ref_os = AssemblyRefOsRaw {
rid: 0,
token: Token::new(0),
offset: 0,
os_platform_id,
os_major_version,
os_minor_version,
assembly_ref,
};
assembly.table_row_add(
TableId::AssemblyRefOS,
TableDataOwned::AssemblyRefOS(assembly_ref_os),
)
}
}
impl Default for AssemblyRefOSBuilder {
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_assemblyrefos_builder_new() {
let builder = AssemblyRefOSBuilder::new();
assert!(builder.os_platform_id.is_none());
assert!(builder.os_major_version.is_none());
assert!(builder.os_minor_version.is_none());
assert!(builder.assembly_ref.is_none());
}
#[test]
fn test_assemblyrefos_builder_default() {
let builder = AssemblyRefOSBuilder::default();
assert!(builder.os_platform_id.is_none());
assert!(builder.os_major_version.is_none());
assert!(builder.os_minor_version.is_none());
assert!(builder.assembly_ref.is_none());
}
#[test]
fn test_assemblyrefos_builder_windows10() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefOSBuilder::new()
.os_platform_id(1) .os_major_version(10) .os_minor_version(0) .assembly_ref(1)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
Ok(())
}
#[test]
fn test_assemblyrefos_builder_windows7() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefOSBuilder::new()
.os_platform_id(1) .os_major_version(6) .os_minor_version(1) .assembly_ref(2)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
Ok(())
}
#[test]
fn test_assemblyrefos_builder_custom_os() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefOSBuilder::new()
.os_platform_id(99) .os_major_version(2) .os_minor_version(5) .assembly_ref(3)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
Ok(())
}
#[test]
fn test_assemblyrefos_builder_missing_platform_id() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = AssemblyRefOSBuilder::new()
.os_major_version(10)
.os_minor_version(0)
.assembly_ref(1)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("OS platform identifier is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_assemblyrefos_builder_missing_major_version() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = AssemblyRefOSBuilder::new()
.os_platform_id(1)
.os_minor_version(0)
.assembly_ref(1)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("OS major version is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_assemblyrefos_builder_missing_minor_version() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = AssemblyRefOSBuilder::new()
.os_platform_id(1)
.os_major_version(10)
.assembly_ref(1)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("OS minor version is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_assemblyrefos_builder_missing_assembly_ref() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = AssemblyRefOSBuilder::new()
.os_platform_id(1)
.os_major_version(10)
.os_minor_version(0)
.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_assemblyrefos_builder_clone() {
let builder = AssemblyRefOSBuilder::new()
.os_platform_id(1)
.os_major_version(10)
.os_minor_version(0)
.assembly_ref(1);
let cloned = builder.clone();
assert_eq!(builder.os_platform_id, cloned.os_platform_id);
assert_eq!(builder.os_major_version, cloned.os_major_version);
assert_eq!(builder.os_minor_version, cloned.os_minor_version);
assert_eq!(builder.assembly_ref, cloned.assembly_ref);
}
#[test]
fn test_assemblyrefos_builder_debug() {
let builder = AssemblyRefOSBuilder::new()
.os_platform_id(2)
.os_major_version(5)
.os_minor_version(4)
.assembly_ref(2);
let debug_str = format!("{builder:?}");
assert!(debug_str.contains("AssemblyRefOSBuilder"));
assert!(debug_str.contains("os_platform_id"));
assert!(debug_str.contains("os_major_version"));
assert!(debug_str.contains("os_minor_version"));
assert!(debug_str.contains("assembly_ref"));
}
#[test]
fn test_assemblyrefos_builder_fluent_interface() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefOSBuilder::new()
.os_platform_id(2)
.os_major_version(12)
.os_minor_version(5)
.assembly_ref(4)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
Ok(())
}
#[test]
fn test_assemblyrefos_builder_multiple_builds() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = AssemblyRefOSBuilder::new()
.os_platform_id(1) .os_major_version(10)
.os_minor_version(0)
.assembly_ref(1)
.build(&mut assembly)
.expect("Should build first OS entry");
let ref2 = AssemblyRefOSBuilder::new()
.os_platform_id(2) .os_major_version(5)
.os_minor_version(4)
.assembly_ref(2)
.build(&mut assembly)
.expect("Should build second OS entry");
assert_eq!(ref1.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
assert_eq!(ref2.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
assert!(!std::sync::Arc::ptr_eq(&ref1, &ref2));
Ok(())
}
#[test]
fn test_assemblyrefos_builder_zero_values() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefOSBuilder::new()
.os_platform_id(0) .os_major_version(0) .os_minor_version(0) .assembly_ref(1)
.build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
Ok(())
}
#[test]
fn test_assemblyrefos_builder_large_assembly_ref() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = AssemblyRefOSBuilder::new()
.os_platform_id(1)
.os_major_version(10)
.os_minor_version(0)
.assembly_ref(0xFFFF) .build(&mut assembly)
.expect("Should handle large assembly ref RID");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::AssemblyRefOS));
Ok(())
}
}