Merge pull request #4043 from Kelimion/expect_leak_or_bad_free

Allow testing for intentional leaks in test runner
This commit is contained in:
Jeroen van Rijn
2024-08-08 21:40:17 +02:00
committed by GitHub
5 changed files with 150 additions and 79 deletions
+4 -6
View File
@@ -87,12 +87,10 @@ shoco_test :: proc(t: ^testing.T) {
}
for v in Shoco_Tests {
when ODIN_OS == .Windows {
v := v
// Compressed source files are not encoded with carriage returns but git replaces raw files lf with crlf on commit (on windows only)
// So replace crlf with lf on windows
v.raw, _ = bytes.replace_all(v.raw, { 0xD, 0xA }, { 0xA })
}
v := v
// Compressed source files are not encoded with carriage returns but git replaces raw files lf with crlf on commit (on windows only)
// So replace crlf with lf on windows
v.raw, _ = bytes.replace_all(v.raw, { 0xD, 0xA }, { 0xA }, context.temp_allocator)
expected_raw := len(v.raw)
expected_compressed := len(v.compressed)
+72 -51
View File
@@ -5,76 +5,97 @@ import "core:mem"
expect_pool_allocation :: proc(t: ^testing.T, expected_used_bytes, num_bytes, alignment: int) {
pool: mem.Dynamic_Pool
mem.dynamic_pool_init(pool = &pool, alignment = alignment)
pool_allocator := mem.dynamic_pool_allocator(&pool)
pool: mem.Dynamic_Pool
mem.dynamic_pool_init(pool = &pool, alignment = alignment)
pool_allocator := mem.dynamic_pool_allocator(&pool)
element, err := mem.alloc(num_bytes, alignment, pool_allocator)
testing.expect(t, err == .None)
testing.expect(t, element != nil)
element, err := mem.alloc(num_bytes, alignment, pool_allocator)
testing.expect(t, err == .None)
testing.expect(t, element != nil)
expected_bytes_left := pool.block_size - expected_used_bytes
testing.expectf(t, pool.bytes_left == expected_bytes_left,
`
Allocated data with size %v bytes, expected %v bytes left, got %v bytes left, off by %v bytes.
Pool:
block_size = %v
out_band_size = %v
alignment = %v
unused_blocks = %v
used_blocks = %v
out_band_allocations = %v
current_block = %v
current_pos = %v
bytes_left = %v
`,
num_bytes, expected_bytes_left, pool.bytes_left, expected_bytes_left - pool.bytes_left,
pool.block_size,
pool.out_band_size,
pool.alignment,
pool.unused_blocks,
pool.used_blocks,
pool.out_band_allocations,
pool.current_block,
pool.current_pos,
pool.bytes_left,
)
expected_bytes_left := pool.block_size - expected_used_bytes
testing.expectf(t, pool.bytes_left == expected_bytes_left,
`
Allocated data with size %v bytes, expected %v bytes left, got %v bytes left, off by %v bytes.
Pool:
block_size = %v
out_band_size = %v
alignment = %v
unused_blocks = %v
used_blocks = %v
out_band_allocations = %v
current_block = %v
current_pos = %v
bytes_left = %v
`,
num_bytes, expected_bytes_left, pool.bytes_left, expected_bytes_left - pool.bytes_left,
pool.block_size,
pool.out_band_size,
pool.alignment,
pool.unused_blocks,
pool.used_blocks,
pool.out_band_allocations,
pool.current_block,
pool.current_pos,
pool.bytes_left,
)
mem.dynamic_pool_destroy(&pool)
testing.expect(t, pool.used_blocks == nil)
mem.dynamic_pool_destroy(&pool)
testing.expect(t, pool.used_blocks == nil)
}
expect_pool_allocation_out_of_band :: proc(t: ^testing.T, num_bytes, out_band_size: int) {
testing.expect(t, num_bytes >= out_band_size, "Sanity check failed, your test call is flawed! Make sure that num_bytes >= out_band_size!")
testing.expect(t, num_bytes >= out_band_size, "Sanity check failed, your test call is flawed! Make sure that num_bytes >= out_band_size!")
pool: mem.Dynamic_Pool
mem.dynamic_pool_init(pool = &pool, out_band_size = out_band_size)
pool_allocator := mem.dynamic_pool_allocator(&pool)
pool: mem.Dynamic_Pool
mem.dynamic_pool_init(pool = &pool, out_band_size = out_band_size)
pool_allocator := mem.dynamic_pool_allocator(&pool)
element, err := mem.alloc(num_bytes, allocator = pool_allocator)
testing.expect(t, err == .None)
testing.expect(t, element != nil)
testing.expectf(t, pool.out_band_allocations != nil,
"Allocated data with size %v bytes, which is >= out_of_band_size and it should be in pool.out_band_allocations, but isn't!",
)
element, err := mem.alloc(num_bytes, allocator = pool_allocator)
testing.expect(t, err == .None)
testing.expect(t, element != nil)
testing.expectf(t, pool.out_band_allocations != nil,
"Allocated data with size %v bytes, which is >= out_of_band_size and it should be in pool.out_band_allocations, but isn't!",
)
mem.dynamic_pool_destroy(&pool)
testing.expect(t, pool.out_band_allocations == nil)
mem.dynamic_pool_destroy(&pool)
testing.expect(t, pool.out_band_allocations == nil)
}
@(test)
test_dynamic_pool_alloc_aligned :: proc(t: ^testing.T) {
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes = 16, alignment=8)
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes = 16, alignment=8)
}
@(test)
test_dynamic_pool_alloc_unaligned :: proc(t: ^testing.T) {
expect_pool_allocation(t, expected_used_bytes = 8, num_bytes=1, alignment=8)
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes=9, alignment=8)
expect_pool_allocation(t, expected_used_bytes = 8, num_bytes=1, alignment=8)
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes=9, alignment=8)
}
@(test)
test_dynamic_pool_alloc_out_of_band :: proc(t: ^testing.T) {
expect_pool_allocation_out_of_band(t, num_bytes = 128, out_band_size = 128)
expect_pool_allocation_out_of_band(t, num_bytes = 129, out_band_size = 128)
expect_pool_allocation_out_of_band(t, num_bytes = 128, out_band_size = 128)
expect_pool_allocation_out_of_band(t, num_bytes = 129, out_band_size = 128)
}
@(test)
test_intentional_leaks :: proc(t: ^testing.T) {
testing.expect_leaks(t, intentionally_leaky_test, leak_verifier)
}
// Not tagged with @(test) because it's run through `test_intentional_leaks`
intentionally_leaky_test :: proc(t: ^testing.T) {
a: [dynamic]int
// Intentional leak
append(&a, 42)
// Intentional bad free
b := uintptr(&a[0]) + 42
free(rawptr(b))
}
leak_verifier :: proc(t: ^testing.T, ta: ^mem.Tracking_Allocator) {
testing.expect_value(t, len(ta.allocation_map), 1)
testing.expect_value(t, len(ta.bad_free_array), 1)
}