GCC Code Coverage Report


Directory: ./
File: tests/TestCommon.h
Date: 2023-01-04 16:32:12
Exec Total Coverage
Lines: 38 38 100.0%
Functions: 29 29 100.0%
Branches: 5 10 50.0%

Line Branch Exec Source
1 #pragma once
2
3 #include <gtest/gtest.h>
4 #include <gmock/gmock-matchers.h>
5
6 #include <CXXIter/CXXIter.h>
7
8 using ::testing::ElementsAre;
9 using ::testing::Pair;
10
11 // ################################################################################################
12 // CUSTOM MATCHERS
13 // ################################################################################################
14
15 template <size_t CNT, typename T>
16 class RawArrayElementsAreMatcher : public ::testing::MatcherInterface<const T*> {
17 public:
18 using is_gtest_matcher = void;
19
20 explicit RawArrayElementsAreMatcher(std::array<T, CNT> elements) : elements(elements) {}
21
22 bool MatchAndExplain(const T* value, ::testing::MatchResultListener* listener) const override {
23 for(size_t i = 0; i < CNT; ++i) {
24 if(elements[i] != value[i]) {
25 if(listener->IsInterested()) {
26 *listener->stream() << "Array element mismatch at index: " << i << ". Should have been: "
27 << elements[i] << " but was: " << value[i] << std::endl;
28 }
29 return false;
30 }
31 }
32 return true;
33 }
34
35 void DescribeTo(std::ostream* os) const override {
36 *os << "Expected array to have elements: [";
37 for(size_t i = 0; i < elements.size(); ++i) {
38 if(i > 0) { *os << ", "; }
39 *os << elements[i];
40 }
41 std::cout << "]" << std::endl;
42 }
43 private:
44 std::array<T, CNT> elements;
45 };
46
47 template<typename T, typename... TRest>
48 ::testing::Matcher<const T*> RawArrayElementsAre(T el0, TRest... els) {
49 static constexpr size_t ELEMENT_CNT = 1 + sizeof...(els);
50 return ::testing::MakeMatcher(new RawArrayElementsAreMatcher<ELEMENT_CNT, T>({el0, static_cast<T>(els)...}));
51 }
52
53
54 // ################################################################################################
55 // TEST STRUCTURES
56 // ################################################################################################
57
58 using TestPair = std::pair<std::string, int>;
59 // define hash for TestPair
60 namespace std {
61 template<>
62 struct hash<TestPair> {
63 20 inline std::size_t operator()(const TestPair& v) const {
64 std::hash<std::string> firstHash;
65 std::hash<int> secondHash;
66 20 return firstHash(v.first) ^ secondHash(v.second);
67 }
68 };
69 }
70
71 enum class LifecycleEventType {
72 CTOR,
73 DTOR,
74 MOVECTOR,
75 CPYCTOR
76 };
77 struct LifecycleEvent {
78 const void* ptr;
79 LifecycleEventType event;
80 /**
81 * @brief Optional pointer determining the memory area used as source for copy/move ctor or assignment.
82 */
83 const void* ptrFrom;
84 26 LifecycleEvent(const void* ptr, LifecycleEventType event, const void* ptrFrom = nullptr) : ptr(ptr), event(event), ptrFrom(ptrFrom) {}
85 };
86
87 using LifecycleEvents = std::vector<LifecycleEvent>;
88
89 struct LifecycleDebugger {
90 bool alive = true;
91 std::string heapTest;
92 LifecycleEvents& evtLog;
93
94 6 LifecycleDebugger(std::string heapTest, LifecycleEvents& evtLog) : heapTest(heapTest), evtLog(evtLog) {
95
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 evtLog.push_back(LifecycleEvent(this, LifecycleEventType::CTOR));
96 6 }
97 13 ~LifecycleDebugger() {
98 13 evtLog.push_back(LifecycleEvent(this, LifecycleEventType::DTOR));
99 13 }
100 3 LifecycleDebugger(const LifecycleDebugger& o) : heapTest(o.heapTest), evtLog(o.evtLog) {
101
1/2
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 evtLog.push_back(LifecycleEvent(this, LifecycleEventType::CPYCTOR, &o));
102 3 }
103 LifecycleDebugger& operator=(const LifecycleDebugger& o) = delete;
104 4 LifecycleDebugger(LifecycleDebugger&& o) : heapTest(std::move(o.heapTest)), evtLog(o.evtLog) {
105 4 o.alive = false;
106
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 evtLog.push_back(LifecycleEvent(this, LifecycleEventType::MOVECTOR, &o));
107 4 }
108 LifecycleDebugger& operator=(LifecycleDebugger&& o) = delete;
109 };
110
111
112 // ################################################################################################
113 // CUSTOM CONTAINER
114 // ################################################################################################
115
116 template<typename TItem> struct CustomContainer {
117 using CustomContainerItem = TItem;
118 std::vector<CustomContainerItem> input;
119 size_t cnt = 0;
120
121 8 CustomContainer() {}
122
1/2
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
7 CustomContainer(std::initializer_list<TItem>&& initialItems) : input(std::move(initialItems)) {}
123
124 24 size_t size() const { return input.size(); }
125 6 CustomContainerItem& get(size_t idx) { return input.at(idx); }
126 1 const CustomContainerItem& get(size_t idx) const { return input.at(idx); }
127 36 void append(CustomContainerItem&& item) {
128 36 input.push_back(std::forward<CustomContainerItem>(item));
129 36 }
130 };
131
132 namespace CXXIter {
133 // SourceTrait implementation for the CustomContainer
134 template<typename TItem> struct trait::Source<CustomContainer<TItem>> {
135 using Item = typename CustomContainer<TItem>::CustomContainerItem;
136 using ItemRef = typename CustomContainer<TItem>::CustomContainerItem&;
137 using ItemConstRef = const typename CustomContainer<TItem>::CustomContainerItem&;
138 using IteratorState = size_t;
139 using ConstIteratorState = size_t;
140
141 3 static constexpr inline SizeHint sizeHint(const CustomContainer<TItem>& container) { return SizeHint(container.size(), container.size()); }
142
143 2 static constexpr inline IteratorState initIterator(CustomContainer<TItem>&) { return 0; }
144 1 static constexpr inline ConstIteratorState initIterator(const CustomContainer<TItem>&) { return 0; }
145
146 4 static constexpr inline bool hasNext(CustomContainer<TItem>& container, IteratorState& iter) { return iter < container.size(); }
147 2 static constexpr inline bool hasNext(const CustomContainer<TItem>& container, ConstIteratorState& iter) { return iter < container.size(); }
148
149 2 static constexpr inline ItemRef next(CustomContainer<TItem>& container, IteratorState& iter) { return container.get(iter++); }
150 1 static constexpr inline ItemConstRef next(const CustomContainer<TItem>& container, ConstIteratorState& iter) { return container.get(iter++); }
151
152 static constexpr inline ItemRef peekNext(CustomContainer<TItem>& container, IteratorState& iter) { return container.get(iter); }
153 static constexpr inline ItemConstRef peekNext(const CustomContainer<TItem>& container, ConstIteratorState& iter) { return container.get(iter); }
154
155 static constexpr inline size_t skipN(CustomContainer<TItem>& container, IteratorState& iter, size_t n) {
156 size_t skipN = std::min(container.cnt - iter, n);
157 iter += skipN;
158 return skipN;
159 }
160 };
161
162 // IntoCollector implementation for the CustomContainer
163 template<typename TChainInput, typename TItem>
164 struct IntoCollector<TChainInput, CustomContainer<TItem>> {
165 using Item = typename TChainInput::Item;
166 using ItemOwned = typename TChainInput::ItemOwned;
167 8 static void collectInto(TChainInput& input, CustomContainer<TItem>& container) {
168 20 input.forEach([&container](Item&& item) { container.append(std::forward<ItemOwned>(item)); });
169 8 }
170 };
171
172 // Collector implementation for the CustomContainer
173 template<typename TChainInput>
174 struct Collector<TChainInput, CustomContainer> {
175 template<typename Item, typename ItemOwned>
176 4 static CustomContainer<ItemOwned> collect(TChainInput& input) {
177 4 CustomContainer<ItemOwned> container;
178
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
10 input.forEach([&container](Item&& item) { container.append(std::forward<ItemOwned>(item)); });
179 4 return container;
180 }
181 };
182 };
183