summaryrefslogtreecommitdiff
path: root/src/unit/allocator_utils.h
blob: f0af88c352ed9ebc121bdd39d78a2f45a6619616 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#ifndef SAND_UNIT_ALLOCATOR_UTILS_H
#define SAND_UNIT_ALLOCATOR_UTILS_H

// This module defines some tests for running against allocators.

#include "../core/allocator.h"

#include "greatest.h"

inline TEST test_allocator_basic_usage(SandAllocator *a) {
	size_t count = 100;
	int *ptr = sand_allocate(a, sizeof(int) * count);
	ASSERT_NEQm("Small allocation should not fail", ptr, NULL);
	// Unit tests are run under address sanitizer, so this should catch when
	// returned memory isn't actually writable.
	for (size_t i = 0; i < count; ++i) {
		ptr[i] = 123;
	}
	// FIXME: I don't really know how to test this.
	sand_deallocate(a, ptr, sizeof(int) * count);
	PASS();
}

inline TEST test_allocator_reallocation(SandAllocator *a) {
	size_t count = 50;
	int *ptr = sand_allocate(a, sizeof(int) * count);
	ASSERT_NEQm("Small allocation should not fail", ptr, NULL);

	for (size_t i = 0; i < count; ++i) {
		ptr[i] = 123;
	}

	size_t new_count = 100;
	int *new_ptr = sand_reallocate(a, ptr, sizeof(int) * count, sizeof(int) * new_count);
	ASSERT_NEQm("Small reallocation should not fail", new_ptr, NULL);

	for (size_t i = 0; i < count; ++i) {
		ASSERT_EQm("Reallocated memory is copied over", new_ptr[i], 123);
	}

	// Just like `test_std_allocator_basic_usage` this should
	// ensure newly allocated memory is reallocated.
	for (size_t i = count; i < new_count; ++i) {
		new_ptr[i] = 456;
	}

	sand_deallocate(a, new_ptr, sizeof(int) * new_count);
	PASS();
}

inline TEST test_allocator_weird_alignments(SandAllocator *a) {
	size_t alignments[] = {2,4,8,16,32,64,128,256,1024};

	for (unsigned i = 0; i < sizeof(alignments)/sizeof((alignments)[0]); ++i) {
		int *allocation = sand_allocate_aligned(a, sizeof(*allocation), alignments[i]);
		*allocation = 123; // ASAN will crash us if invalid memory is returned.
		sand_deallocate(a, allocation, sizeof(*allocation));
	}

	PASS();
}

inline TEST test_allocator_unreasonably_large_allocation_fails_gracefully(SandAllocator *a) {
#if defined(__has_feature)
#  if __has_feature(address_sanitizer)
	SKIPm("Test does not work under address_sanitizer");
#  endif
#endif

	// Compute a request size which is very unlikely to be available.
	//                    kibi   mebi   gibi   tebi -byte
	size_t size = (size_t)1024 * 1024 * 1024 * 1024;

	void *result = sand_allocate(a, size);
	ASSERT_EQm("Allocation should fail", result, NULL);

	PASS();
}

#define RUN_ALLOCATOR_TESTS(DO)             \
	DO(test_allocator_basic_usage)      \
	DO(test_allocator_reallocation)     \
	DO(test_allocator_weird_alignments) \
	DO(test_allocator_unreasonably_large_allocation_fails_gracefully)

#endif