Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 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 | 202016 | ~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 | static constexpr size_t DUMMY_NODE_SIZE = sizeof(DummyNode); | ||
29 | static_assert(DUMMY_NODE_SIZE == 104, "DummyNode size has changed. Update test accordingly."); | ||
30 | |||
31 | class MockMemoryManager final : public MemoryManager { | ||
32 | public: | ||
33 |
2/4✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
14 | MOCK_METHOD(byte *, allocate, (size_t size), (const override)); |
34 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
10 | MOCK_METHOD(void, deallocate, (byte * ptr), (const override)); |
35 | }; | ||
36 | |||
37 | 8 | TEST(BlockAllocatorTest, TestBlockAllocatorLarge) { | |
38 | 2 | destructedDummyNodes = 0; // Reset destruction counter | |
39 | static constexpr size_t NODE_COUNT = 100'000; // 100.000 * 104 bytes = 10.4 MB | ||
40 | |||
41 | { | ||
42 | // Create allocator, that can hold 5 nodes per block | ||
43 | 2 | constexpr DefaultMemoryManager memoryManager; | |
44 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | BlockAllocator<ASTNode> alloc(memoryManager, DUMMY_NODE_SIZE * 5); |
45 | |||
46 | // Allocate nodes | ||
47 | 2 | std::vector<ASTNode *> nodes; | |
48 |
2/2✓ Branch 0 taken 100000 times.
✓ Branch 1 taken 1 times.
|
200002 | for (size_t i = 0; i < NODE_COUNT; i++) { |
49 |
2/4✓ Branch 1 taken 100000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 100000 times.
✗ Branch 5 not taken.
|
200000 | auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1)); |
50 |
3/12✓ Branch 1 taken 100000 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 100000 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 19 taken 100000 times.
✗ Branch 20 not taken.
|
200000 | ASSERT_NE(nullptr, node); |
51 |
1/2✓ Branch 1 taken 100000 times.
✗ Branch 2 not taken.
|
200000 | nodes.push_back(node); |
52 |
4/14✓ Branch 1 taken 100000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 100000 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 100000 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 22 taken 100000 times.
✗ Branch 23 not taken.
|
200000 | ASSERT_EQ(i, nodes.at(i)->codeLoc.line); |
53 |
4/14✓ Branch 1 taken 100000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 100000 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 100000 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 22 taken 100000 times.
✗ Branch 23 not taken.
|
200000 | ASSERT_EQ(1, nodes.at(i)->codeLoc.col); |
54 | } | ||
55 | |||
56 | // Check if stats are correct | ||
57 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
|
2 | ASSERT_EQ(NODE_COUNT, alloc.getAllocationCount()); |
58 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
|
2 | ASSERT_EQ(13'000'000, alloc.getTotalAllocatedSize()); |
59 | |||
60 | // Block Allocator gets destructed here and with that, all allocated nodes should be destructed | ||
61 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | } |
62 | |||
63 |
3/12✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
|
2 | ASSERT_EQ(NODE_COUNT, destructedDummyNodes); |
64 | } | ||
65 | |||
66 | 8 | TEST(BlockAllocatorTest, TestBlockAllocatorUnevenBlockSize) { | |
67 | 2 | destructedDummyNodes = 0; // Reset destruction counter | |
68 | static constexpr size_t NODE_COUNT = 1'000; // 1.000 * 104 bytes = 104 KB | ||
69 | |||
70 | { | ||
71 | // Create allocator, that can hold 4.5 nodes per block | ||
72 | 2 | constexpr DefaultMemoryManager memoryManager; | |
73 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | BlockAllocator<ASTNode> alloc(memoryManager, DUMMY_NODE_SIZE * 4.5); |
74 | |||
75 | // Allocate nodes | ||
76 | 2 | std::vector<ASTNode *> nodes; | |
77 |
2/2✓ Branch 0 taken 1000 times.
✓ Branch 1 taken 1 times.
|
2002 | for (size_t i = 0; i < NODE_COUNT; i++) { |
78 |
2/4✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1000 times.
✗ Branch 5 not taken.
|
2000 | auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1)); |
79 |
3/12✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1000 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 19 taken 1000 times.
✗ Branch 20 not taken.
|
2000 | ASSERT_NE(nullptr, node); |
80 |
1/2✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
|
2000 | nodes.push_back(node); |
81 |
4/14✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1000 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1000 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 22 taken 1000 times.
✗ Branch 23 not taken.
|
2000 | ASSERT_EQ(i, nodes.at(i)->codeLoc.line); |
82 |
4/14✓ Branch 1 taken 1000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1000 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1000 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 22 taken 1000 times.
✗ Branch 23 not taken.
|
2000 | ASSERT_EQ(1, nodes.at(i)->codeLoc.col); |
83 | } | ||
84 | |||
85 | // Check if stats are correct | ||
86 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
|
2 | ASSERT_EQ(NODE_COUNT, alloc.getAllocationCount()); |
87 |
3/12✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
|
2 | ASSERT_EQ(117'000, alloc.getTotalAllocatedSize()); |
88 | |||
89 | // Block Allocator gets destructed here and with that, all allocated nodes should be destructed | ||
90 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | } |
91 | |||
92 |
3/12✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
|
2 | ASSERT_EQ(NODE_COUNT, destructedDummyNodes); |
93 | } | ||
94 | |||
95 | 8 | TEST(BlockAllocatorTest, TestBlockAllocatorOOM) { | |
96 | 2 | destructedDummyNodes = 0; // Reset destruction counter | |
97 | static constexpr size_t NODE_COUNT = 10; // 10 * 104 bytes = 1.04 KB | ||
98 | |||
99 | // Prepare mock methods | ||
100 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | MockMemoryManager mockMemoryManager; |
101 | |||
102 | // Make sure, that the memory manager returns nullptr when trying to allocate the fifth block | ||
103 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | ::testing::InSequence s; |
104 | 4 | auto mallocCallback = [](size_t size) { return static_cast<byte *>(malloc(size)); }; | |
105 |
7/14✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
|
2 | EXPECT_CALL(mockMemoryManager, allocate(::testing::_)).Times(4).WillRepeatedly(mallocCallback); |
106 |
8/16✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
|
2 | EXPECT_CALL(mockMemoryManager, allocate(::testing::_)).Times(1).WillOnce(::testing::Return(nullptr)); |
107 |
7/14✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
|
2 | EXPECT_CALL(mockMemoryManager, deallocate(::testing::_)).Times(4).WillRepeatedly(::testing::Invoke(free)); |
108 | |||
109 | { | ||
110 | // Create allocator, that can hold 2 nodes per block | ||
111 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | BlockAllocator<ASTNode> alloc(mockMemoryManager, DUMMY_NODE_SIZE * 2.25); |
112 | |||
113 | try { | ||
114 | // Allocate nodes | ||
115 | 2 | std::vector<ASTNode *> nodes; | |
116 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
18 | for (size_t i = 0; i < NODE_COUNT; i++) { |
117 |
3/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1 times.
|
18 | auto node = alloc.allocate<DummyNode>(CodeLoc(i, 1)); |
118 |
3/12✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 19 taken 8 times.
✗ Branch 20 not taken.
|
16 | ASSERT_NE(nullptr, node); |
119 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
16 | nodes.push_back(node); |
120 |
4/14✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 22 taken 8 times.
✗ Branch 23 not taken.
|
16 | ASSERT_EQ(i, nodes.at(i)->codeLoc.line); |
121 |
4/14✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✓ Branch 22 taken 8 times.
✗ Branch 23 not taken.
|
16 | ASSERT_EQ(1, nodes.at(i)->codeLoc.col); |
122 | } | ||
123 | − | FAIL(); // LCOV_EXCL_LINE - Should not reach this point | |
124 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
4 | } catch (CompilerError &ce) { |
125 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | std::stringstream ss; |
126 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | ss << "[Error|Compiler]:\n"; |
127 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | ss << "An out of memory error occurred: Could not allocate memory for BlockAllocator. Already allocated 4 blocks."; |
128 |
4/14✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 24 taken 1 times.
✗ Branch 25 not taken.
|
2 | ASSERT_EQ(ss.str(), ce.what()); |
129 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
4 | } |
130 | |||
131 | // Block Allocator gets destructed here and with that, all allocated nodes should be destructed | ||
132 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | } |
133 | |||
134 |
3/12✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
|
2 | ASSERT_EQ(8, destructedDummyNodes); // Only 8 blocks were constructed until the OOM error occurred |
135 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | ::testing::Mock::VerifyAndClearExpectations(&mockMemoryManager); |
136 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | } |
137 | |||
138 | } // namespace spice::testing | ||
139 |