package spanpool import "base:runtime" import "core:c/libc" import "core:log" import "core:slice" import "core:testing" expect_assert :: proc( t: ^testing.T, data: $T, client_proc: proc(_: ^testing.T, data: T), expr := #caller_expression, loc := #caller_location, ) { @(thread_local) jmp: libc.jmp_buf context.assertion_failure_proc = proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { log.infof("expected assertion %s: %s ", prefix, message, location = loc) libc.longjmp(&jmp, 1) } jmp_res := libc.setjmp(&jmp) if jmp_res == 0 { client_proc(t, data) libc.longjmp(&jmp, 2) } if jmp_res != 1 { log.errorf("%v DID NOT assert", expr, location = loc) } } @(test) test_basic_alloc :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) handle := allocate_elems(&pool, 1, 2, 3, 4) testing.expect_value(t, handle.first, 0) testing.expect_value(t, handle.len, 4) testing.expect_value(t, handle.gen, 1) } @(test) test_basic_free :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) handle := allocate_elems(&pool, 1, 2, 3, 4) free(&pool, handle) testing.expect_value(t, len(pool.free_spans), 1) testing.expect_value(t, pool.free_spans[0], Span{first = 0, len = 4}) } @(test) test_double_free :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) expect_assert(t, &pool, proc(t: ^testing.T, pool: ^Span_Pool(u32)) { handle := allocate_elems(pool, 1, 2, 3, 4) free(pool, handle) free(pool, handle) }) } @(test) test_resolve :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) handle := allocate_elems(&pool, 1, 2, 3, 4) handle2 := allocate_elems(&pool, 4, 3, 2, 1) testing.expect(t, slice.equal(resolve_slice(&pool, handle), []u32{1, 2, 3, 4})) testing.expect(t, slice.equal(resolve_slice(&pool, handle2), []u32{4, 3, 2, 1})) } @(test) test_multiple_spans :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) handle := allocate_elems(&pool, 1, 2, 3, 4) handle2 := allocate_elems(&pool, 4, 3, 2, 1) free(&pool, handle) free(&pool, handle2) testing.expect_value(t, len(pool.free_spans), 2) testing.expect_value(t, pool.free_spans[0], Span{first = 0, len = 4}) testing.expect_value(t, pool.free_spans[1], Span{first = 4, len = 4}) } @(test) test_reconcile :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) handle := allocate_elems(&pool, 1, 2, 3, 4) handle2 := allocate_elems(&pool, 4, 3, 2, 1) free(&pool, handle) free(&pool, handle2) reconcile(&pool) testing.expect_value(t, len(pool.free_spans), 1) testing.expect_value(t, pool.free_spans[0], Span{first = 0, len = 8}) } @(test) test_reconcile_with_gaps :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) handle := allocate_elems(&pool, 1, 2, 3, 4) handle2 := allocate_elems(&pool, 1, 2, 3, 4) handle3 := allocate_elems(&pool, 1, 2, 3, 4) handle4 := allocate_elems(&pool, 1, 2, 3, 4) handle5 := allocate_elems(&pool, 1, 2, 3, 4) handle6 := allocate_elems(&pool, 1, 2, 3, 4) handle7 := allocate_elems(&pool, 1, 2, 3, 4) free(&pool, handle) free(&pool, handle3) free(&pool, handle4) free(&pool, handle6) free(&pool, handle7) _, _ = handle2, handle5 reconcile(&pool) testing.expect_value(t, len(pool.free_spans), 3) testing.expect_value(t, pool.free_spans[0], Span{first = 0, len = 4}) testing.expect_value(t, pool.free_spans[1], Span{first = 8, len = 8}) testing.expect_value(t, pool.free_spans[2], Span{first = 20, len = 8}) } @(test) test_free_span_reuse :: proc(t: ^testing.T) { pool := Span_Pool(u32){} defer destroy_spanpool(&pool) handle := allocate_elems(&pool, 1, 2, 3, 4) _ = allocate_elems(&pool, 1, 2, 3, 4) free(&pool, handle) handle3 := allocate_elems(&pool, 5, 6) handle4 := allocate_elems(&pool, 7, 8) handle5 := allocate_elems(&pool, 9, 10) testing.expect_value(t, handle3, Handle{first = 0, len = 2, gen = 3}) testing.expect_value(t, handle4, Handle{first = 2, len = 2, gen = 3}) testing.expect_value(t, handle5, Handle{first = 8, len = 2, gen = 1}) testing.expect(t, slice.equal(resolve_slice(&pool, handle3), []u32{5, 6})) testing.expect(t, slice.equal(resolve_slice(&pool, handle4), []u32{7, 8})) testing.expect(t, slice.equal(resolve_slice(&pool, handle5), []u32{9, 10})) }