use drcov::{BasicBlock, CoverageData, ModuleEntry, ModuleTableVersion};
#[test]
fn test_builder_sequential_module_ids() {
let valid = CoverageData::builder()
.add_module("/bin/test1", 0x400000, 0x500000)
.add_module("/bin/test2", 0x500000, 0x600000)
.add_module("/bin/test3", 0x600000, 0x700000)
.build();
assert!(valid.is_ok());
let invalid = CoverageData::builder()
.add_full_module(ModuleEntry {
id: 0,
base: 0x400000,
end: 0x500000,
path: "/bin/test1".to_string(),
..Default::default()
})
.add_full_module(ModuleEntry {
id: 2, base: 0x500000,
end: 0x600000,
path: "/bin/test2".to_string(),
..Default::default()
})
.build();
assert!(invalid.is_err());
let duplicate = CoverageData::builder()
.add_full_module(ModuleEntry {
id: 0,
base: 0x400000,
end: 0x500000,
path: "/bin/test1".to_string(),
..Default::default()
})
.add_full_module(ModuleEntry {
id: 0, base: 0x500000,
end: 0x600000,
path: "/bin/test2".to_string(),
..Default::default()
})
.build();
assert!(duplicate.is_err());
}
#[test]
fn test_builder_basic_block_validation() {
let valid = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.add_module("/lib/test", 0x500000, 0x600000)
.add_coverage(0, 0x1000, 32)
.add_coverage(1, 0x2000, 64)
.build();
assert!(valid.is_ok());
let invalid_ref = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.add_coverage(1, 0x1000, 32) .build();
assert!(invalid_ref.is_err());
let out_of_range = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.add_coverage(100, 0x1000, 32) .build();
assert!(out_of_range.is_err());
let empty_bb = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.build();
assert!(empty_bb.is_ok());
}
#[test]
fn test_builder_module_address_ranges() {
let non_overlapping = CoverageData::builder()
.add_module("/bin/test1", 0x400000, 0x500000)
.add_module("/bin/test2", 0x600000, 0x700000)
.build();
assert!(non_overlapping.is_ok());
let adjacent = CoverageData::builder()
.add_module("/bin/test1", 0x400000, 0x500000)
.add_module("/bin/test2", 0x500000, 0x600000)
.build();
assert!(adjacent.is_ok());
let overlapping = CoverageData::builder()
.add_module("/bin/test1", 0x400000, 0x500000)
.add_module("/bin/test2", 0x450000, 0x550000) .build();
assert!(overlapping.is_ok());
let zero_size = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x400000)
.build();
assert!(zero_size.is_ok());
let inverted = CoverageData::builder()
.add_module("/bin/test", 0x500000, 0x400000)
.build();
assert!(inverted.is_ok());
}
#[test]
fn test_builder_mixed_construction_methods() {
let mixed = CoverageData::builder()
.add_module("/bin/auto", 0x400000, 0x500000) .add_full_module(ModuleEntry {
id: 1, base: 0x500000,
end: 0x600000,
path: "/bin/manual".to_string(),
..Default::default()
})
.add_module("/bin/auto2", 0x600000, 0x700000) .build();
assert!(mixed.is_ok());
let invalid_mix = CoverageData::builder()
.add_module("/bin/auto", 0x400000, 0x500000) .add_full_module(ModuleEntry {
id: 5, base: 0x500000,
end: 0x600000,
path: "/bin/manual".to_string(),
..Default::default()
})
.build();
assert!(invalid_mix.is_err());
}
#[test]
fn test_builder_basic_block_construction_methods() {
let mixed_bb = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.add_coverage(0, 0x1000, 32)
.add_basic_block(BasicBlock {
module_id: 0,
start: 0x2000,
size: 64,
})
.build();
assert!(mixed_bb.is_ok());
let invalid_bb = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.add_basic_block(BasicBlock {
module_id: 1, start: 0x1000,
size: 32,
})
.build();
assert!(invalid_bb.is_err());
}
#[test]
fn test_builder_flavor_and_version_settings() {
let default_builder = CoverageData::builder().build().unwrap();
assert_eq!(default_builder.header.flavor, "drcov");
assert_eq!(default_builder.module_version, ModuleTableVersion::Legacy);
let custom = CoverageData::builder()
.flavor("custom_tool")
.module_version(ModuleTableVersion::V4)
.build()
.unwrap();
assert_eq!(custom.header.flavor, "custom_tool");
assert_eq!(custom.module_version, ModuleTableVersion::V4);
let overwritten = CoverageData::builder()
.flavor("first")
.flavor("second") .module_version(ModuleTableVersion::V2)
.module_version(ModuleTableVersion::V3) .build()
.unwrap();
assert_eq!(overwritten.header.flavor, "second");
assert_eq!(overwritten.module_version, ModuleTableVersion::V3);
}
#[test]
fn test_builder_empty_configurations() {
let empty = CoverageData::builder().build();
assert!(empty.is_ok());
let empty_data = empty.unwrap();
assert_eq!(empty_data.modules.len(), 0);
assert_eq!(empty_data.basic_blocks.len(), 0);
let modules_only = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.build();
assert!(modules_only.is_ok());
}
#[test]
fn test_builder_large_numbers() {
let max_addresses = CoverageData::builder()
.add_module("/bin/test", u64::MAX - 0x1000, u64::MAX)
.add_coverage(0, u32::MAX, u16::MAX)
.build();
assert!(max_addresses.is_ok());
let zero_addresses = CoverageData::builder()
.add_module("/bin/test", 0, 0)
.add_coverage(0, 0, 0)
.build();
assert!(zero_addresses.is_ok());
}
#[test]
fn test_builder_module_entry_fields() {
let full_module = CoverageData::builder()
.add_full_module(ModuleEntry {
id: 0,
base: 0x400000,
end: 0x500000,
entry: 0x401000,
path: "/bin/test".to_string(),
containing_id: Some(42),
offset: Some(0x1000),
checksum: Some(0x12345678),
timestamp: Some(0x87654321),
})
.build();
assert!(full_module.is_ok());
let negative_containing_id = CoverageData::builder()
.add_full_module(ModuleEntry {
id: 0,
base: 0x400000,
end: 0x500000,
entry: 0x401000,
path: "/bin/test".to_string(),
containing_id: Some(-1),
..Default::default()
})
.build();
assert!(negative_containing_id.is_ok());
let long_path = "a".repeat(1000);
let long_path_module = CoverageData::builder()
.add_module(&long_path, 0x400000, 0x500000)
.build();
assert!(long_path_module.is_ok());
}
#[test]
fn test_builder_chaining() {
let chained = CoverageData::builder()
.module_version(ModuleTableVersion::V4)
.add_module("/bin/test1", 0x400000, 0x500000)
.flavor("test_tool")
.add_coverage(0, 0x1000, 32)
.add_module("/bin/test2", 0x500000, 0x600000)
.add_coverage(1, 0x2000, 64)
.build();
assert!(chained.is_ok());
let data = chained.unwrap();
assert_eq!(data.header.flavor, "test_tool");
assert_eq!(data.module_version, ModuleTableVersion::V4);
assert_eq!(data.modules.len(), 2);
assert_eq!(data.basic_blocks.len(), 2);
}
#[test]
fn test_builder_validation_edge_cases() {
let many_modules_builder = CoverageData::builder();
let mut builder = many_modules_builder;
for i in 0..1000u32 {
let base = 0x400000 + i as u64 * 0x1000;
builder = builder.add_module(&format!("/module{i}"), base, base + 0x1000);
}
let many_modules = builder.build();
assert!(many_modules.is_ok());
let max_module_id = CoverageData::builder()
.add_module("/bin/test", 0x400000, 0x500000)
.add_basic_block(BasicBlock {
module_id: 0, start: 0x1000,
size: 32,
})
.build();
assert!(max_module_id.is_ok());
}