use crate::{
cilassembly::{ChangeRefRc, CilAssembly},
metadata::{
tables::{EncLogRaw, TableDataOwned, TableId},
token::Token,
},
Error, Result,
};
#[derive(Debug, Clone)]
pub struct EncLogBuilder {
token_value: Option<u32>,
func_code: Option<u32>,
}
impl EncLogBuilder {
#[must_use]
pub fn new() -> Self {
Self {
token_value: None,
func_code: None,
}
}
#[must_use]
pub fn token_value(mut self, token_value: u32) -> Self {
self.token_value = Some(token_value);
self
}
#[must_use]
pub fn func_code(mut self, func_code: u32) -> Self {
self.func_code = Some(func_code);
self
}
#[must_use]
pub fn create(mut self) -> Self {
self.func_code = Some(0);
self
}
#[must_use]
pub fn update(mut self) -> Self {
self.func_code = Some(1);
self
}
#[must_use]
pub fn delete(mut self) -> Self {
self.func_code = Some(2);
self
}
pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc> {
let token_value = self.token_value.ok_or_else(|| {
Error::ModificationInvalid("Token value is required for EncLog".to_string())
})?;
let func_code = self.func_code.ok_or_else(|| {
Error::ModificationInvalid("Function code is required for EncLog".to_string())
})?;
let enc_log = EncLogRaw {
rid: 0,
token: Token::new(0),
offset: 0,
token_value,
func_code,
};
assembly.table_row_add(TableId::EncLog, TableDataOwned::EncLog(enc_log))
}
}
impl Default for EncLogBuilder {
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_enclog_builder_new() {
let builder = EncLogBuilder::new();
assert!(builder.token_value.is_none());
assert!(builder.func_code.is_none());
}
#[test]
fn test_enclog_builder_default() {
let builder = EncLogBuilder::default();
assert!(builder.token_value.is_none());
assert!(builder.func_code.is_none());
}
#[test]
fn test_enclog_builder_create_method() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EncLogBuilder::new()
.token_value(0x06000001) .func_code(0) .build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EncLog));
Ok(())
}
#[test]
fn test_enclog_builder_update_type() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EncLogBuilder::new()
.token_value(0x02000010) .func_code(1) .build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EncLog));
Ok(())
}
#[test]
fn test_enclog_builder_delete_field() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EncLogBuilder::new()
.token_value(0x04000025) .func_code(2) .build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EncLog));
Ok(())
}
#[test]
fn test_enclog_builder_convenience_methods() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = EncLogBuilder::new()
.token_value(0x06000001)
.create()
.build(&mut assembly)
.expect("Should build create operation");
let ref2 = EncLogBuilder::new()
.token_value(0x02000001)
.update()
.build(&mut assembly)
.expect("Should build update operation");
let ref3 = EncLogBuilder::new()
.token_value(0x04000001)
.delete()
.build(&mut assembly)
.expect("Should build delete operation");
assert_eq!(ref1.kind(), ChangeRefKind::TableRow(TableId::EncLog));
assert_eq!(ref2.kind(), ChangeRefKind::TableRow(TableId::EncLog));
assert_eq!(ref3.kind(), ChangeRefKind::TableRow(TableId::EncLog));
Ok(())
}
#[test]
fn test_enclog_builder_missing_token_value() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = EncLogBuilder::new().func_code(0).build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("Token value is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_enclog_builder_missing_func_code() -> Result<()> {
let mut assembly = get_test_assembly()?;
let result = EncLogBuilder::new()
.token_value(0x06000001)
.build(&mut assembly);
assert!(result.is_err());
match result.unwrap_err() {
Error::ModificationInvalid(details) => {
assert!(details.contains("Function code is required"));
}
_ => panic!("Expected ModificationInvalid error"),
}
Ok(())
}
#[test]
fn test_enclog_builder_clone() {
let builder = EncLogBuilder::new().token_value(0x06000001).func_code(1);
let cloned = builder.clone();
assert_eq!(builder.token_value, cloned.token_value);
assert_eq!(builder.func_code, cloned.func_code);
}
#[test]
fn test_enclog_builder_debug() {
let builder = EncLogBuilder::new().token_value(0x02000005).func_code(2);
let debug_str = format!("{builder:?}");
assert!(debug_str.contains("EncLogBuilder"));
assert!(debug_str.contains("token_value"));
assert!(debug_str.contains("func_code"));
}
#[test]
fn test_enclog_builder_fluent_interface() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref_ = EncLogBuilder::new()
.token_value(0x08000001) .func_code(1) .build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EncLog));
Ok(())
}
#[test]
fn test_enclog_builder_multiple_builds() -> Result<()> {
let mut assembly = get_test_assembly()?;
let ref1 = EncLogBuilder::new()
.token_value(0x06000001) .create()
.build(&mut assembly)
.expect("Should build first log entry");
let ref2 = EncLogBuilder::new()
.token_value(0x02000001) .update()
.build(&mut assembly)
.expect("Should build second log entry");
assert_eq!(ref1.kind(), ChangeRefKind::TableRow(TableId::EncLog));
assert_eq!(ref2.kind(), ChangeRefKind::TableRow(TableId::EncLog));
assert!(!std::sync::Arc::ptr_eq(&ref1, &ref2));
Ok(())
}
#[test]
fn test_enclog_builder_various_tokens() -> Result<()> {
let mut assembly = get_test_assembly()?;
let tokens = [
0x02000001, 0x06000001, 0x04000001, 0x08000001, 0x14000001, 0x17000001, ];
for (i, &token_val) in tokens.iter().enumerate() {
let ref_ = EncLogBuilder::new()
.token_value(token_val)
.func_code(i as u32 % 3) .build(&mut assembly)
.expect("Should build successfully");
assert_eq!(ref_.kind(), ChangeRefKind::TableRow(TableId::EncLog));
}
Ok(())
}
}