We now no longer call malloc/free/... directly, but use an allocator object that is passed around. This was mainly done as a preparation for a garbage collector: The collector will need to know, how much memory we're using, introducing the collector abstraction will allow the GC to hook into the memory allocation and observe the memory usage. This has other potential applications: - We could now be embedded into applications that can't use the libc allocator. - There could be an allocator that limits the total amount of used memory, e.g. for sandboxing purposes. - In our tests we could use this to simulate out of memory conditions (implement an allocator that fails at the n-th allocation, increase n by one and restart the test until there are no more faked OOM conditions). The function signature of the allocator is basically exactly the same as the one Lua uses.
329 lines
8.4 KiB
C
329 lines
8.4 KiB
C
#include <string.h>
|
|
|
|
#include "test.h"
|
|
|
|
#include "alloc.h"
|
|
#include "resizable.h"
|
|
|
|
struct splice_test_data {
|
|
const int *old;
|
|
size_t cut_start;
|
|
size_t cut_len;
|
|
const int *other;
|
|
const int *want;
|
|
};
|
|
|
|
static size_t
|
|
getlen(const int *data)
|
|
{
|
|
size_t len = 0;
|
|
for (; *data != 0; data++) {
|
|
len++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static void
|
|
run_splice_test(testctx t, struct splice_test_data st)
|
|
{
|
|
struct apfl_allocator allocator = test_allocator(t);
|
|
|
|
size_t len = getlen(st.old);
|
|
int *mem = ALLOC_LIST(allocator, int, len);
|
|
memcpy(mem, st.old, sizeof(int) * len);
|
|
size_t cap = len;
|
|
|
|
size_t other_len = getlen(st.other);
|
|
|
|
if (!apfl_resizable_splice(
|
|
allocator,
|
|
sizeof(int),
|
|
(void **)&mem,
|
|
&len,
|
|
&cap,
|
|
st.cut_start,
|
|
st.cut_len,
|
|
st.other,
|
|
other_len
|
|
)) {
|
|
test_fatalf(t, "splice failed!");
|
|
}
|
|
|
|
size_t want_len = getlen(st.want);
|
|
|
|
if (len != want_len) {
|
|
test_fatalf(t, "Expected len=%d, got %d", (int)want_len, (int)len);
|
|
}
|
|
if (cap < want_len) {
|
|
test_fatalf(t, "Expected cap>=%d, got %d", (int)want_len, (int)cap);
|
|
}
|
|
|
|
for (size_t i = 0; i < len; i++) {
|
|
int have = mem[i];
|
|
int want = st.want[i];
|
|
|
|
if (have != want) {
|
|
test_failf(t, "have(%d) != want(%d) at i=%d", have, want, (int)i);
|
|
}
|
|
}
|
|
|
|
FREE_LIST(allocator, mem, cap);
|
|
}
|
|
|
|
TEST(splice_empty, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {0},
|
|
.cut_start = 0,
|
|
.cut_len = 0,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_remove_single_begin, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 1,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {2, 3, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_remove_multiple_begin, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 2,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {3, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_remove_single_end, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 2,
|
|
.cut_len = 1,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {1, 2, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_remove_multiple_end, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 1,
|
|
.cut_len = 2,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {1, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_remove_single_mid, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 1,
|
|
.cut_len = 1,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {1, 3, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_same_size_single_mid, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 1,
|
|
.cut_len = 1,
|
|
.other = (int[]) {42, 0},
|
|
.want = (int[]) {1, 42, 3, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_larger_size_single_mid, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 1,
|
|
.cut_len = 1,
|
|
.other = (int[]) {10, 20, 30, 0},
|
|
.want = (int[]) {1, 10, 20, 30, 3, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_smaller_size_single_mid, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 1,
|
|
.cut_len = 2,
|
|
.other = (int[]) {10, 0},
|
|
.want = (int[]) {1, 10, 4, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_same_size_single_begin, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 1,
|
|
.other = (int[]) {42, 0},
|
|
.want = (int[]) {42, 2, 3, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_larger_size_single_begin, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 1,
|
|
.other = (int[]) {10, 20, 30, 0},
|
|
.want = (int[]) {10, 20, 30, 2, 3, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_smaller_size_single_begin, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 2,
|
|
.other = (int[]) {10, 0},
|
|
.want = (int[]) {10, 3, 4, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_same_size_single_end, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 2,
|
|
.cut_len = 1,
|
|
.other = (int[]) {42, 0},
|
|
.want = (int[]) {1, 2, 42, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_larger_size_single_end, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 0},
|
|
.cut_start = 2,
|
|
.cut_len = 1,
|
|
.other = (int[]) {10, 20, 30, 0},
|
|
.want = (int[]) {1, 2, 10, 20, 30, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_smaller_size_single_end, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 2,
|
|
.cut_len = 2,
|
|
.other = (int[]) {10, 0},
|
|
.want = (int[]) {1, 2, 10, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_remove_all, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 4,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_all_same_size, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 4,
|
|
.other = (int[]) {10, 20, 30, 40, 0},
|
|
.want = (int[]) {10, 20, 30, 40, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_all_smaller_size, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 4,
|
|
.other = (int[]) {10, 0},
|
|
.want = (int[]) {10, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_replace_all_larger_size, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 4,
|
|
.other = (int[]) {10, 20, 30, 40, 50, 60, 0},
|
|
.want = (int[]) {10, 20, 30, 40, 50, 60, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_noop, t) {
|
|
for (size_t i = 0; i < 4; i++) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = i,
|
|
.cut_len = 0,
|
|
.other = (int[]) {0},
|
|
.want = (int[]) {1, 2, 3, 4, 0},
|
|
});
|
|
}
|
|
}
|
|
|
|
TEST(splice_insert_begin, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 0,
|
|
.cut_len = 0,
|
|
.other = (int[]) {10, 20, 30, 0},
|
|
.want = (int[]) {10, 20, 30, 1, 2, 3, 4, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_insert_mid, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 1,
|
|
.cut_len = 0,
|
|
.other = (int[]) {10, 20, 30, 0},
|
|
.want = (int[]) {1, 10, 20, 30, 2, 3, 4, 0},
|
|
});
|
|
}
|
|
|
|
TEST(splice_insert_end, t) {
|
|
run_splice_test(t, (struct splice_test_data) {
|
|
.old = (int[]) {1, 2, 3, 4, 0},
|
|
.cut_start = 4,
|
|
.cut_len = 0,
|
|
.other = (int[]) {10, 20, 30, 0},
|
|
.want = (int[]) {1, 2, 3, 4, 10, 20, 30, 0},
|
|
});
|
|
}
|
|
|
|
TESTS_BEGIN
|
|
ADDTEST(splice_empty),
|
|
ADDTEST(splice_remove_single_begin),
|
|
ADDTEST(splice_remove_multiple_begin),
|
|
ADDTEST(splice_remove_single_end),
|
|
ADDTEST(splice_remove_multiple_end),
|
|
ADDTEST(splice_remove_single_mid),
|
|
ADDTEST(splice_replace_same_size_single_mid),
|
|
ADDTEST(splice_replace_larger_size_single_mid),
|
|
ADDTEST(splice_replace_smaller_size_single_mid),
|
|
ADDTEST(splice_replace_same_size_single_begin),
|
|
ADDTEST(splice_replace_larger_size_single_begin),
|
|
ADDTEST(splice_replace_smaller_size_single_begin),
|
|
ADDTEST(splice_replace_same_size_single_end),
|
|
ADDTEST(splice_replace_larger_size_single_end),
|
|
ADDTEST(splice_replace_smaller_size_single_end),
|
|
ADDTEST(splice_remove_all),
|
|
ADDTEST(splice_replace_all_same_size),
|
|
ADDTEST(splice_replace_all_smaller_size),
|
|
ADDTEST(splice_replace_all_larger_size),
|
|
ADDTEST(splice_noop),
|
|
ADDTEST(splice_insert_begin),
|
|
ADDTEST(splice_insert_mid),
|
|
ADDTEST(splice_insert_end),
|
|
TESTS_END
|