GCC Code Coverage Report


Directory: ../
File: test/unittest/UnitBlockAllocator.cpp
Date: 2025-10-09 06:28:01
Coverage Exec Excl Total
Lines: 97.2% 70 3 75
Functions: 93.8% 15 2 18
Branches: 35.5% 118 6 338

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include <gmock/gmock.h>
4 #include <gtest/gtest.h>
5
6 #include <ast/ASTNodes.h>
7 #include <util/BlockAllocator.h>
8 #include <util/CodeLoc.h>
9 #include <util/Memory.h>
10
11 namespace spice::testing {
12
13 using namespace spice::compiler;
14
15 static size_t destructedDummyNodes = 0;
16
17 class DummyNode final : public ASTNode {
18 // Constructors
19 using ASTNode::ASTNode;
20
21 // Destructors
22 101008 ~DummyNode() override { destructedDummyNodes++; }
23
24 // Visitor methods
25 std::any accept(AbstractASTVisitor *visitor) override { return {}; } // LCOV_EXCL_LINE
26 std::any accept(ParallelizableASTVisitor *visitor) const override { return {}; } // LCOV_EXCL_LINE
27
28 // Other methods
29 GET_CHILDREN();
30 };
31 static constexpr size_t DUMMY_NODE_SIZE = sizeof(DummyNode);
32 static_assert(DUMMY_NODE_SIZE == 48, "DummyNode size has changed. Update test accordingly.");
33
34 class MockMemoryManager final : public MemoryManager {
35 public:
36
2/4
✓ Branch 3 → 4 taken 2 times.
✗ Branch 3 → 11 not taken.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 9 not taken.
7 MOCK_METHOD(byte *, allocate, (size_t size), (const override));
37
2/4
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 11 not taken.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 9 not taken.
5 MOCK_METHOD(void, deallocate, (byte * ptr), (const override));
38 };
39
40 4 TEST(BlockAllocatorTest, TestBlockAllocatorLarge) {
41 1 destructedDummyNodes = 0; // Reset destruction counter
42 static constexpr size_t NODE_COUNT = 100'000; // 100.000 * 48 bytes = 4.8 MB
43
44 {
45 // Create allocator, that can hold 5 nodes per block
46 1 constexpr DefaultMemoryManager memoryManager;
47
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 174 not taken.
1 BlockAllocator<ASTNode> alloc(memoryManager, DUMMY_NODE_SIZE * 5);
48
49 // Allocate nodes
50 1 std::vector<ASTNode *> nodes;
51
2/2
✓ Branch 57 → 4 taken 100000 times.
✓ Branch 57 → 58 taken 1 time.
100001 for (size_t i = 0; i < NODE_COUNT; i++) {
52
2/4
✓ Branch 4 → 5 taken 100000 times.
✗ Branch 4 → 116 not taken.
✓ Branch 5 → 6 taken 100000 times.
✗ Branch 5 → 116 not taken.
100000 auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1));
53
3/12
✓ Branch 6 → 7 taken 100000 times.
✗ Branch 6 → 117 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 16 taken 100000 times.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 123 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 120 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 118 not taken.
✓ Branch 18 → 19 taken 100000 times.
✗ Branch 18 → 21 not taken.
100000 ASSERT_NE(nullptr, node);
54
1/2
✓ Branch 20 → 22 taken 100000 times.
✗ Branch 20 → 127 not taken.
100000 nodes.push_back(node);
55
4/14
✓ Branch 22 → 23 taken 100000 times.
✗ Branch 22 → 136 not taken.
✓ Branch 23 → 24 taken 100000 times.
✗ Branch 23 → 136 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 33 taken 100000 times.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 133 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 130 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 128 not taken.
✓ Branch 35 → 36 taken 100000 times.
✗ Branch 35 → 38 not taken.
100000 ASSERT_EQ(i, nodes.at(i)->codeLoc.line);
56
4/14
✓ Branch 37 → 39 taken 100000 times.
✗ Branch 37 → 146 not taken.
✓ Branch 39 → 40 taken 100000 times.
✗ Branch 39 → 137 not taken.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 49 taken 100000 times.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 143 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 140 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 138 not taken.
✓ Branch 51 → 52 taken 100000 times.
✗ Branch 51 → 54 not taken.
100000 ASSERT_EQ(1, nodes.at(i)->codeLoc.col);
57 }
58
59 // Check if stats are correct
60
3/12
✓ Branch 59 → 60 taken 1 time.
✗ Branch 59 → 149 not taken.
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 69 taken 1 time.
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 155 not taken.
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 152 not taken.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 150 not taken.
✓ Branch 71 → 72 taken 1 time.
✗ Branch 71 → 75 not taken.
1 ASSERT_EQ(NODE_COUNT, alloc.getAllocationCount());
61
3/12
✓ Branch 74 → 76 taken 1 time.
✗ Branch 74 → 159 not taken.
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 85 taken 1 time.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 166 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 163 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 81 → 161 not taken.
✓ Branch 87 → 88 taken 1 time.
✗ Branch 87 → 90 not taken.
1 ASSERT_EQ(6'000'000, alloc.getTotalAllocatedSize());
62
63 // Block Allocator gets destructed here and with that, all allocated nodes should be destructed
64
2/4
✓ Branch 92 → 93 taken 1 time.
✗ Branch 92 → 94 not taken.
✓ Branch 96 → 97 taken 1 time.
✗ Branch 96 → 99 not taken.
1 }
65
66
3/12
✓ Branch 98 → 100 taken 1 time.
✗ Branch 98 → 183 not taken.
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 109 taken 1 time.
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 180 not taken.
✗ Branch 104 → 105 not taken.
✗ Branch 104 → 177 not taken.
✗ Branch 105 → 106 not taken.
✗ Branch 105 → 175 not taken.
✓ Branch 111 → 112 taken 1 time.
✗ Branch 111 → 114 not taken.
1 ASSERT_EQ(NODE_COUNT, destructedDummyNodes);
67 }
68
69 4 TEST(BlockAllocatorTest, TestBlockAllocatorUnevenBlockSize) {
70 1 destructedDummyNodes = 0; // Reset destruction counter
71 static constexpr size_t NODE_COUNT = 1'000; // 1.000 * 48 bytes = 48 KB
72
73 {
74 // Create allocator, that can hold 4.5 nodes per block
75 1 constexpr DefaultMemoryManager memoryManager;
76
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 174 not taken.
1 BlockAllocator<ASTNode> alloc(memoryManager, DUMMY_NODE_SIZE * 4.5);
77
78 // Allocate nodes
79 1 std::vector<ASTNode *> nodes;
80
2/2
✓ Branch 57 → 4 taken 1000 times.
✓ Branch 57 → 58 taken 1 time.
1001 for (size_t i = 0; i < NODE_COUNT; i++) {
81
2/4
✓ Branch 4 → 5 taken 1000 times.
✗ Branch 4 → 116 not taken.
✓ Branch 5 → 6 taken 1000 times.
✗ Branch 5 → 116 not taken.
1000 auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1));
82
3/12
✓ Branch 6 → 7 taken 1000 times.
✗ Branch 6 → 117 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 16 taken 1000 times.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 123 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 120 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 118 not taken.
✓ Branch 18 → 19 taken 1000 times.
✗ Branch 18 → 21 not taken.
1000 ASSERT_NE(nullptr, node);
83
1/2
✓ Branch 20 → 22 taken 1000 times.
✗ Branch 20 → 127 not taken.
1000 nodes.push_back(node);
84
4/14
✓ Branch 22 → 23 taken 1000 times.
✗ Branch 22 → 136 not taken.
✓ Branch 23 → 24 taken 1000 times.
✗ Branch 23 → 136 not taken.
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 33 taken 1000 times.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 133 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 130 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 128 not taken.
✓ Branch 35 → 36 taken 1000 times.
✗ Branch 35 → 38 not taken.
1000 ASSERT_EQ(i, nodes.at(i)->codeLoc.line);
85
4/14
✓ Branch 37 → 39 taken 1000 times.
✗ Branch 37 → 146 not taken.
✓ Branch 39 → 40 taken 1000 times.
✗ Branch 39 → 137 not taken.
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 49 taken 1000 times.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 143 not taken.
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 140 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 138 not taken.
✓ Branch 51 → 52 taken 1000 times.
✗ Branch 51 → 54 not taken.
1000 ASSERT_EQ(1, nodes.at(i)->codeLoc.col);
86 }
87
88 // Check if stats are correct
89
3/12
✓ Branch 59 → 60 taken 1 time.
✗ Branch 59 → 149 not taken.
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 69 taken 1 time.
✗ Branch 62 → 63 not taken.
✗ Branch 62 → 155 not taken.
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 152 not taken.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 150 not taken.
✓ Branch 71 → 72 taken 1 time.
✗ Branch 71 → 75 not taken.
1 ASSERT_EQ(NODE_COUNT, alloc.getAllocationCount());
90
3/12
✓ Branch 74 → 76 taken 1 time.
✗ Branch 74 → 159 not taken.
✗ Branch 77 → 78 not taken.
✓ Branch 77 → 85 taken 1 time.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 166 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 163 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 81 → 161 not taken.
✓ Branch 87 → 88 taken 1 time.
✗ Branch 87 → 90 not taken.
1 ASSERT_EQ(54'000, alloc.getTotalAllocatedSize());
91
92 // Block Allocator gets destructed here and with that, all allocated nodes should be destructed
93
2/4
✓ Branch 92 → 93 taken 1 time.
✗ Branch 92 → 94 not taken.
✓ Branch 96 → 97 taken 1 time.
✗ Branch 96 → 99 not taken.
1 }
94
95
3/12
✓ Branch 98 → 100 taken 1 time.
✗ Branch 98 → 183 not taken.
✗ Branch 101 → 102 not taken.
✓ Branch 101 → 109 taken 1 time.
✗ Branch 102 → 103 not taken.
✗ Branch 102 → 180 not taken.
✗ Branch 104 → 105 not taken.
✗ Branch 104 → 177 not taken.
✗ Branch 105 → 106 not taken.
✗ Branch 105 → 175 not taken.
✓ Branch 111 → 112 taken 1 time.
✗ Branch 111 → 114 not taken.
1 ASSERT_EQ(NODE_COUNT, destructedDummyNodes);
96 }
97
98 4 TEST(BlockAllocatorTest, TestBlockAllocatorOOM) {
99 1 destructedDummyNodes = 0; // Reset destruction counter
100 static constexpr size_t NODE_COUNT = 10; // 10 * 48 bytes = 0.48 KB
101
102 // Prepare mock methods
103
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 278 not taken.
1 MockMemoryManager mockMemoryManager;
104
105 // Make sure, that the memory manager returns nullptr when trying to allocate the fifth block
106
1/2
✓ Branch 3 → 4 taken 1 time.
✗ Branch 3 → 276 not taken.
1 ::testing::InSequence s;
107 4 auto mallocCallback = [](size_t size) { return static_cast<byte *>(malloc(size)); };
108
7/14
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 142 not taken.
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 140 not taken.
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 137 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 137 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 9 → 137 not taken.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 136 not taken.
✓ Branch 11 → 12 taken 1 time.
✗ Branch 11 → 134 not taken.
1 EXPECT_CALL(mockMemoryManager, allocate(::testing::_)).Times(4).WillRepeatedly(mallocCallback);
109
8/16
✓ Branch 15 → 16 taken 1 time.
✗ Branch 15 → 153 not taken.
✓ Branch 16 → 17 taken 1 time.
✗ Branch 16 → 151 not taken.
✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 148 not taken.
✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 148 not taken.
✓ Branch 20 → 21 taken 1 time.
✗ Branch 20 → 148 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 146 not taken.
✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 146 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 144 not taken.
1 EXPECT_CALL(mockMemoryManager, allocate(::testing::_)).Times(1).WillOnce(::testing::Return(nullptr));
110
7/14
✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 164 not taken.
✓ Branch 28 → 29 taken 1 time.
✗ Branch 28 → 162 not taken.
✓ Branch 29 → 30 taken 1 time.
✗ Branch 29 → 159 not taken.
✓ Branch 31 → 32 taken 1 time.
✗ Branch 31 → 159 not taken.
✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 159 not taken.
✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 157 not taken.
✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 155 not taken.
1 EXPECT_CALL(mockMemoryManager, deallocate(::testing::_)).Times(4).WillRepeatedly(::testing::Invoke(free));
111
112 {
113 // Create allocator, that can hold 2 nodes per block
114
1/2
✓ Branch 39 → 40 taken 1 time.
✗ Branch 39 → 263 not taken.
1 BlockAllocator<ASTNode> alloc(mockMemoryManager, DUMMY_NODE_SIZE * 2.25);
115
116 try {
117 // Allocate nodes
118 1 std::vector<ASTNode *> nodes;
119
1/2
✓ Branch 94 → 41 taken 9 times.
✗ Branch 94 → 95 not taken.
9 for (size_t i = 0; i < NODE_COUNT; i++) {
120
3/4
✓ Branch 41 → 42 taken 9 times.
✗ Branch 41 → 166 not taken.
✓ Branch 42 → 43 taken 8 times.
✓ Branch 42 → 166 taken 1 time.
9 auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1));
121
3/12
✓ Branch 43 → 44 taken 8 times.
✗ Branch 43 → 167 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 53 taken 8 times.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 173 not taken.
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 170 not taken.
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 168 not taken.
✓ Branch 55 → 56 taken 8 times.
✗ Branch 55 → 58 not taken.
8 ASSERT_NE(nullptr, node);
122
1/2
✓ Branch 57 → 59 taken 8 times.
✗ Branch 57 → 177 not taken.
8 nodes.push_back(node);
123
4/14
✓ Branch 59 → 60 taken 8 times.
✗ Branch 59 → 186 not taken.
✓ Branch 60 → 61 taken 8 times.
✗ Branch 60 → 186 not taken.
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 70 taken 8 times.
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 183 not taken.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 180 not taken.
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 178 not taken.
✓ Branch 72 → 73 taken 8 times.
✗ Branch 72 → 75 not taken.
8 ASSERT_EQ(i, nodes.at(i)->codeLoc.line);
124
4/14
✓ Branch 74 → 76 taken 8 times.
✗ Branch 74 → 196 not taken.
✓ Branch 76 → 77 taken 8 times.
✗ Branch 76 → 187 not taken.
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 86 taken 8 times.
✗ Branch 79 → 80 not taken.
✗ Branch 79 → 193 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 81 → 190 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 188 not taken.
✓ Branch 88 → 89 taken 8 times.
✗ Branch 88 → 91 not taken.
8 ASSERT_EQ(1, nodes.at(i)->codeLoc.col);
125 }
126 FAIL(); // LCOV_EXCL_LINE - Should not reach this point
127
1/2
✗ Branch 208 → 209 not taken.
✓ Branch 208 → 210 taken 1 time.
2 } catch (CompilerError &ce) {
128
1/2
✓ Branch 211 → 212 taken 1 time.
✗ Branch 211 → 258 not taken.
1 std::stringstream ss;
129
1/2
✓ Branch 212 → 213 taken 1 time.
✗ Branch 212 → 256 not taken.
1 ss << "[Error|Compiler]:\n";
130
1/2
✓ Branch 213 → 214 taken 1 time.
✗ Branch 213 → 256 not taken.
1 ss << "An out of memory error occurred: Could not allocate memory for BlockAllocator. Already allocated 4 blocks.";
131
4/14
✓ Branch 215 → 216 taken 1 time.
✗ Branch 215 → 245 not taken.
✓ Branch 216 → 217 taken 1 time.
✗ Branch 216 → 243 not taken.
✗ Branch 219 → 220 not taken.
✓ Branch 219 → 227 taken 1 time.
✗ Branch 220 → 221 not taken.
✗ Branch 220 → 252 not taken.
✗ Branch 222 → 223 not taken.
✗ Branch 222 → 249 not taken.
✗ Branch 223 → 224 not taken.
✗ Branch 223 → 247 not taken.
✓ Branch 229 → 230 taken 1 time.
✗ Branch 229 → 232 not taken.
1 ASSERT_EQ(ss.str(), ce.what());
132
2/4
✓ Branch 234 → 235 taken 1 time.
✗ Branch 234 → 237 not taken.
✓ Branch 239 → 240 taken 1 time.
✗ Branch 239 → 241 not taken.
2 }
133
134 // Block Allocator gets destructed here and with that, all allocated nodes should be destructed
135
1/2
✓ Branch 104 → 105 taken 1 time.
✗ Branch 104 → 107 not taken.
1 }
136
137
3/12
✓ Branch 106 → 108 taken 1 time.
✗ Branch 106 → 264 not taken.
✗ Branch 109 → 110 not taken.
✓ Branch 109 → 117 taken 1 time.
✗ Branch 110 → 111 not taken.
✗ Branch 110 → 270 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 267 not taken.
✗ Branch 113 → 114 not taken.
✗ Branch 113 → 265 not taken.
✓ Branch 119 → 120 taken 1 time.
✗ Branch 119 → 122 not taken.
1 ASSERT_EQ(8, destructedDummyNodes); // Only 8 blocks were constructed until the OOM error occurred
138
1/2
✓ Branch 121 → 123 taken 1 time.
✗ Branch 121 → 274 not taken.
1 ::testing::Mock::VerifyAndClearExpectations(&mockMemoryManager);
139
2/4
✓ Branch 125 → 126 taken 1 time.
✗ Branch 125 → 127 not taken.
✓ Branch 129 → 130 taken 1 time.
✗ Branch 129 → 132 not taken.
1 }
140
141 } // namespace spice::testing
142