GCC Code Coverage Report


Directory: ../
File: test/unittest/UnitBlockAllocator.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 59 60 98.3%
Functions: 18 20 90.0%
Branches: 118 332 35.5%

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 0 (3→4) taken 2 times.
✗ Branch 1 (3→11) not taken.
✓ Branch 2 (4→5) taken 2 times.
✗ Branch 3 (4→9) not taken.
7 MOCK_METHOD(byte *, allocate, (size_t size), (const override));
37
2/4
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→11) not taken.
✓ Branch 2 (4→5) taken 1 times.
✗ Branch 3 (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 0 (2→3) taken 1 times.
✗ Branch 1 (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 0 (57→4) taken 100000 times.
✓ Branch 1 (57→58) taken 1 times.
100001 for (size_t i = 0; i < NODE_COUNT; i++) {
52
2/4
✓ Branch 0 (4→5) taken 100000 times.
✗ Branch 1 (4→116) not taken.
✓ Branch 2 (5→6) taken 100000 times.
✗ Branch 3 (5→116) not taken.
100000 auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1));
53
3/12
✓ Branch 0 (6→7) taken 100000 times.
✗ Branch 1 (6→117) not taken.
✗ Branch 2 (8→9) not taken.
✓ Branch 3 (8→16) taken 100000 times.
✗ Branch 4 (9→10) not taken.
✗ Branch 5 (9→123) not taken.
✗ Branch 6 (11→12) not taken.
✗ Branch 7 (11→120) not taken.
✗ Branch 8 (12→13) not taken.
✗ Branch 9 (12→118) not taken.
✓ Branch 10 (18→19) taken 100000 times.
✗ Branch 11 (18→21) not taken.
100000 ASSERT_NE(nullptr, node);
54
1/2
✓ Branch 0 (20→22) taken 100000 times.
✗ Branch 1 (20→127) not taken.
100000 nodes.push_back(node);
55
4/14
✓ Branch 0 (22→23) taken 100000 times.
✗ Branch 1 (22→136) not taken.
✓ Branch 2 (23→24) taken 100000 times.
✗ Branch 3 (23→136) not taken.
✗ Branch 4 (25→26) not taken.
✓ Branch 5 (25→33) taken 100000 times.
✗ Branch 6 (26→27) not taken.
✗ Branch 7 (26→133) not taken.
✗ Branch 8 (28→29) not taken.
✗ Branch 9 (28→130) not taken.
✗ Branch 10 (29→30) not taken.
✗ Branch 11 (29→128) not taken.
✓ Branch 12 (35→36) taken 100000 times.
✗ Branch 13 (35→38) not taken.
100000 ASSERT_EQ(i, nodes.at(i)->codeLoc.line);
56
4/14
✓ Branch 0 (37→39) taken 100000 times.
✗ Branch 1 (37→146) not taken.
✓ Branch 2 (39→40) taken 100000 times.
✗ Branch 3 (39→137) not taken.
✗ Branch 4 (41→42) not taken.
✓ Branch 5 (41→49) taken 100000 times.
✗ Branch 6 (42→43) not taken.
✗ Branch 7 (42→143) not taken.
✗ Branch 8 (44→45) not taken.
✗ Branch 9 (44→140) not taken.
✗ Branch 10 (45→46) not taken.
✗ Branch 11 (45→138) not taken.
✓ Branch 12 (51→52) taken 100000 times.
✗ Branch 13 (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 0 (59→60) taken 1 times.
✗ Branch 1 (59→149) not taken.
✗ Branch 2 (61→62) not taken.
✓ Branch 3 (61→69) taken 1 times.
✗ Branch 4 (62→63) not taken.
✗ Branch 5 (62→155) not taken.
✗ Branch 6 (64→65) not taken.
✗ Branch 7 (64→152) not taken.
✗ Branch 8 (65→66) not taken.
✗ Branch 9 (65→150) not taken.
✓ Branch 10 (71→72) taken 1 times.
✗ Branch 11 (71→75) not taken.
1 ASSERT_EQ(NODE_COUNT, alloc.getAllocationCount());
61
3/12
✓ Branch 0 (74→76) taken 1 times.
✗ Branch 1 (74→159) not taken.
✗ Branch 2 (77→78) not taken.
✓ Branch 3 (77→85) taken 1 times.
✗ Branch 4 (78→79) not taken.
✗ Branch 5 (78→166) not taken.
✗ Branch 6 (80→81) not taken.
✗ Branch 7 (80→163) not taken.
✗ Branch 8 (81→82) not taken.
✗ Branch 9 (81→161) not taken.
✓ Branch 10 (87→88) taken 1 times.
✗ Branch 11 (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 0 (92→93) taken 1 times.
✗ Branch 1 (92→94) not taken.
✓ Branch 2 (96→97) taken 1 times.
✗ Branch 3 (96→99) not taken.
1 }
65
66
3/12
✓ Branch 0 (98→100) taken 1 times.
✗ Branch 1 (98→183) not taken.
✗ Branch 2 (101→102) not taken.
✓ Branch 3 (101→109) taken 1 times.
✗ Branch 4 (102→103) not taken.
✗ Branch 5 (102→180) not taken.
✗ Branch 6 (104→105) not taken.
✗ Branch 7 (104→177) not taken.
✗ Branch 8 (105→106) not taken.
✗ Branch 9 (105→175) not taken.
✓ Branch 10 (111→112) taken 1 times.
✗ Branch 11 (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 0 (2→3) taken 1 times.
✗ Branch 1 (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 0 (57→4) taken 1000 times.
✓ Branch 1 (57→58) taken 1 times.
1001 for (size_t i = 0; i < NODE_COUNT; i++) {
81
2/4
✓ Branch 0 (4→5) taken 1000 times.
✗ Branch 1 (4→116) not taken.
✓ Branch 2 (5→6) taken 1000 times.
✗ Branch 3 (5→116) not taken.
1000 auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1));
82
3/12
✓ Branch 0 (6→7) taken 1000 times.
✗ Branch 1 (6→117) not taken.
✗ Branch 2 (8→9) not taken.
✓ Branch 3 (8→16) taken 1000 times.
✗ Branch 4 (9→10) not taken.
✗ Branch 5 (9→123) not taken.
✗ Branch 6 (11→12) not taken.
✗ Branch 7 (11→120) not taken.
✗ Branch 8 (12→13) not taken.
✗ Branch 9 (12→118) not taken.
✓ Branch 10 (18→19) taken 1000 times.
✗ Branch 11 (18→21) not taken.
1000 ASSERT_NE(nullptr, node);
83
1/2
✓ Branch 0 (20→22) taken 1000 times.
✗ Branch 1 (20→127) not taken.
1000 nodes.push_back(node);
84
4/14
✓ Branch 0 (22→23) taken 1000 times.
✗ Branch 1 (22→136) not taken.
✓ Branch 2 (23→24) taken 1000 times.
✗ Branch 3 (23→136) not taken.
✗ Branch 4 (25→26) not taken.
✓ Branch 5 (25→33) taken 1000 times.
✗ Branch 6 (26→27) not taken.
✗ Branch 7 (26→133) not taken.
✗ Branch 8 (28→29) not taken.
✗ Branch 9 (28→130) not taken.
✗ Branch 10 (29→30) not taken.
✗ Branch 11 (29→128) not taken.
✓ Branch 12 (35→36) taken 1000 times.
✗ Branch 13 (35→38) not taken.
1000 ASSERT_EQ(i, nodes.at(i)->codeLoc.line);
85
4/14
✓ Branch 0 (37→39) taken 1000 times.
✗ Branch 1 (37→146) not taken.
✓ Branch 2 (39→40) taken 1000 times.
✗ Branch 3 (39→137) not taken.
✗ Branch 4 (41→42) not taken.
✓ Branch 5 (41→49) taken 1000 times.
✗ Branch 6 (42→43) not taken.
✗ Branch 7 (42→143) not taken.
✗ Branch 8 (44→45) not taken.
✗ Branch 9 (44→140) not taken.
✗ Branch 10 (45→46) not taken.
✗ Branch 11 (45→138) not taken.
✓ Branch 12 (51→52) taken 1000 times.
✗ Branch 13 (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 0 (59→60) taken 1 times.
✗ Branch 1 (59→149) not taken.
✗ Branch 2 (61→62) not taken.
✓ Branch 3 (61→69) taken 1 times.
✗ Branch 4 (62→63) not taken.
✗ Branch 5 (62→155) not taken.
✗ Branch 6 (64→65) not taken.
✗ Branch 7 (64→152) not taken.
✗ Branch 8 (65→66) not taken.
✗ Branch 9 (65→150) not taken.
✓ Branch 10 (71→72) taken 1 times.
✗ Branch 11 (71→75) not taken.
1 ASSERT_EQ(NODE_COUNT, alloc.getAllocationCount());
90
3/12
✓ Branch 0 (74→76) taken 1 times.
✗ Branch 1 (74→159) not taken.
✗ Branch 2 (77→78) not taken.
✓ Branch 3 (77→85) taken 1 times.
✗ Branch 4 (78→79) not taken.
✗ Branch 5 (78→166) not taken.
✗ Branch 6 (80→81) not taken.
✗ Branch 7 (80→163) not taken.
✗ Branch 8 (81→82) not taken.
✗ Branch 9 (81→161) not taken.
✓ Branch 10 (87→88) taken 1 times.
✗ Branch 11 (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 0 (92→93) taken 1 times.
✗ Branch 1 (92→94) not taken.
✓ Branch 2 (96→97) taken 1 times.
✗ Branch 3 (96→99) not taken.
1 }
94
95
3/12
✓ Branch 0 (98→100) taken 1 times.
✗ Branch 1 (98→183) not taken.
✗ Branch 2 (101→102) not taken.
✓ Branch 3 (101→109) taken 1 times.
✗ Branch 4 (102→103) not taken.
✗ Branch 5 (102→180) not taken.
✗ Branch 6 (104→105) not taken.
✗ Branch 7 (104→177) not taken.
✗ Branch 8 (105→106) not taken.
✗ Branch 9 (105→175) not taken.
✓ Branch 10 (111→112) taken 1 times.
✗ Branch 11 (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 0 (2→3) taken 1 times.
✗ Branch 1 (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 0 (3→4) taken 1 times.
✗ Branch 1 (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 0 (4→5) taken 1 times.
✗ Branch 1 (4→142) not taken.
✓ Branch 2 (5→6) taken 1 times.
✗ Branch 3 (5→140) not taken.
✓ Branch 4 (6→7) taken 1 times.
✗ Branch 5 (6→137) not taken.
✓ Branch 6 (8→9) taken 1 times.
✗ Branch 7 (8→137) not taken.
✓ Branch 8 (9→10) taken 1 times.
✗ Branch 9 (9→137) not taken.
✓ Branch 10 (10→11) taken 1 times.
✗ Branch 11 (10→136) not taken.
✓ Branch 12 (11→12) taken 1 times.
✗ Branch 13 (11→134) not taken.
1 EXPECT_CALL(mockMemoryManager, allocate(::testing::_)).Times(4).WillRepeatedly(mallocCallback);
109
8/16
✓ Branch 0 (15→16) taken 1 times.
✗ Branch 1 (15→153) not taken.
✓ Branch 2 (16→17) taken 1 times.
✗ Branch 3 (16→151) not taken.
✓ Branch 4 (17→18) taken 1 times.
✗ Branch 5 (17→148) not taken.
✓ Branch 6 (19→20) taken 1 times.
✗ Branch 7 (19→148) not taken.
✓ Branch 8 (20→21) taken 1 times.
✗ Branch 9 (20→148) not taken.
✓ Branch 10 (21→22) taken 1 times.
✗ Branch 11 (21→146) not taken.
✓ Branch 12 (22→23) taken 1 times.
✗ Branch 13 (22→146) not taken.
✓ Branch 14 (23→24) taken 1 times.
✗ Branch 15 (23→144) not taken.
1 EXPECT_CALL(mockMemoryManager, allocate(::testing::_)).Times(1).WillOnce(::testing::Return(nullptr));
110
7/14
✓ Branch 0 (27→28) taken 1 times.
✗ Branch 1 (27→164) not taken.
✓ Branch 2 (28→29) taken 1 times.
✗ Branch 3 (28→162) not taken.
✓ Branch 4 (29→30) taken 1 times.
✗ Branch 5 (29→159) not taken.
✓ Branch 6 (31→32) taken 1 times.
✗ Branch 7 (31→159) not taken.
✓ Branch 8 (32→33) taken 1 times.
✗ Branch 9 (32→159) not taken.
✓ Branch 10 (34→35) taken 1 times.
✗ Branch 11 (34→157) not taken.
✓ Branch 12 (35→36) taken 1 times.
✗ Branch 13 (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 0 (39→40) taken 1 times.
✗ Branch 1 (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 0 (94→41) taken 9 times.
✗ Branch 1 (94→95) not taken.
9 for (size_t i = 0; i < NODE_COUNT; i++) {
120
3/4
✓ Branch 0 (41→42) taken 9 times.
✗ Branch 1 (41→166) not taken.
✓ Branch 2 (42→43) taken 8 times.
✓ Branch 3 (42→166) taken 1 times.
9 auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1));
121
3/12
✓ Branch 0 (43→44) taken 8 times.
✗ Branch 1 (43→167) not taken.
✗ Branch 2 (45→46) not taken.
✓ Branch 3 (45→53) taken 8 times.
✗ Branch 4 (46→47) not taken.
✗ Branch 5 (46→173) not taken.
✗ Branch 6 (48→49) not taken.
✗ Branch 7 (48→170) not taken.
✗ Branch 8 (49→50) not taken.
✗ Branch 9 (49→168) not taken.
✓ Branch 10 (55→56) taken 8 times.
✗ Branch 11 (55→58) not taken.
8 ASSERT_NE(nullptr, node);
122
1/2
✓ Branch 0 (57→59) taken 8 times.
✗ Branch 1 (57→177) not taken.
8 nodes.push_back(node);
123
4/14
✓ Branch 0 (59→60) taken 8 times.
✗ Branch 1 (59→186) not taken.
✓ Branch 2 (60→61) taken 8 times.
✗ Branch 3 (60→186) not taken.
✗ Branch 4 (62→63) not taken.
✓ Branch 5 (62→70) taken 8 times.
✗ Branch 6 (63→64) not taken.
✗ Branch 7 (63→183) not taken.
✗ Branch 8 (65→66) not taken.
✗ Branch 9 (65→180) not taken.
✗ Branch 10 (66→67) not taken.
✗ Branch 11 (66→178) not taken.
✓ Branch 12 (72→73) taken 8 times.
✗ Branch 13 (72→75) not taken.
8 ASSERT_EQ(i, nodes.at(i)->codeLoc.line);
124
4/14
✓ Branch 0 (74→76) taken 8 times.
✗ Branch 1 (74→196) not taken.
✓ Branch 2 (76→77) taken 8 times.
✗ Branch 3 (76→187) not taken.
✗ Branch 4 (78→79) not taken.
✓ Branch 5 (78→86) taken 8 times.
✗ Branch 6 (79→80) not taken.
✗ Branch 7 (79→193) not taken.
✗ Branch 8 (81→82) not taken.
✗ Branch 9 (81→190) not taken.
✗ Branch 10 (82→83) not taken.
✗ Branch 11 (82→188) not taken.
✓ Branch 12 (88→89) taken 8 times.
✗ Branch 13 (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 0 (208→209) not taken.
✓ Branch 1 (208→210) taken 1 times.
2 } catch (CompilerError &ce) {
128
1/2
✓ Branch 0 (211→212) taken 1 times.
✗ Branch 1 (211→258) not taken.
1 std::stringstream ss;
129
1/2
✓ Branch 0 (212→213) taken 1 times.
✗ Branch 1 (212→256) not taken.
1 ss << "[Error|Compiler]:\n";
130
1/2
✓ Branch 0 (213→214) taken 1 times.
✗ Branch 1 (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 0 (215→216) taken 1 times.
✗ Branch 1 (215→245) not taken.
✓ Branch 2 (216→217) taken 1 times.
✗ Branch 3 (216→243) not taken.
✗ Branch 4 (219→220) not taken.
✓ Branch 5 (219→227) taken 1 times.
✗ Branch 6 (220→221) not taken.
✗ Branch 7 (220→252) not taken.
✗ Branch 8 (222→223) not taken.
✗ Branch 9 (222→249) not taken.
✗ Branch 10 (223→224) not taken.
✗ Branch 11 (223→247) not taken.
✓ Branch 12 (229→230) taken 1 times.
✗ Branch 13 (229→232) not taken.
1 ASSERT_EQ(ss.str(), ce.what());
132
2/4
✓ Branch 0 (234→235) taken 1 times.
✗ Branch 1 (234→237) not taken.
✓ Branch 2 (239→240) taken 1 times.
✗ Branch 3 (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 0 (104→105) taken 1 times.
✗ Branch 1 (104→107) not taken.
1 }
136
137
3/12
✓ Branch 0 (106→108) taken 1 times.
✗ Branch 1 (106→264) not taken.
✗ Branch 2 (109→110) not taken.
✓ Branch 3 (109→117) taken 1 times.
✗ Branch 4 (110→111) not taken.
✗ Branch 5 (110→270) not taken.
✗ Branch 6 (112→113) not taken.
✗ Branch 7 (112→267) not taken.
✗ Branch 8 (113→114) not taken.
✗ Branch 9 (113→265) not taken.
✓ Branch 10 (119→120) taken 1 times.
✗ Branch 11 (119→122) not taken.
1 ASSERT_EQ(8, destructedDummyNodes); // Only 8 blocks were constructed until the OOM error occurred
138
1/2
✓ Branch 0 (121→123) taken 1 times.
✗ Branch 1 (121→274) not taken.
1 ::testing::Mock::VerifyAndClearExpectations(&mockMemoryManager);
139
2/4
✓ Branch 0 (125→126) taken 1 times.
✗ Branch 1 (125→127) not taken.
✓ Branch 2 (129→130) taken 1 times.
✗ Branch 3 (129→132) not taken.
1 }
140
141 } // namespace spice::testing
142