GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
* The ManaPlus Client |
||
3 |
* Copyright (C) 2013-2019 The ManaPlus Developers |
||
4 |
* Copyright (C) 2019-2021 Andrei Karas |
||
5 |
* |
||
6 |
* This file is part of The ManaPlus Client. |
||
7 |
* |
||
8 |
* This program is free software; you can redistribute it and/or modify |
||
9 |
* it under the terms of the GNU General Public License as published by |
||
10 |
* the Free Software Foundation; either version 2 of the License, or |
||
11 |
* any later version. |
||
12 |
* |
||
13 |
* This program is distributed in the hope that it will be useful, |
||
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 |
* GNU General Public License for more details. |
||
17 |
* |
||
18 |
* You should have received a copy of the GNU General Public License |
||
19 |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
20 |
*/ |
||
21 |
|||
22 |
#include "unittests/unittests.h" |
||
23 |
|||
24 |
#include "configmanager.h" |
||
25 |
#include "configuration.h" |
||
26 |
#include "client.h" |
||
27 |
#include "dirs.h" |
||
28 |
#include "graphicsmanager.h" |
||
29 |
|||
30 |
#include "being/actorsprite.h" |
||
31 |
|||
32 |
#include "fs/files.h" |
||
33 |
|||
34 |
#include "fs/virtfs/fs.h" |
||
35 |
#include "fs/virtfs/rwops.h" |
||
36 |
|||
37 |
#include "gui/userpalette.h" |
||
38 |
#include "gui/theme.h" |
||
39 |
|||
40 |
#include "input/inputactionmap.h" |
||
41 |
|||
42 |
#include "resources/image/image.h" |
||
43 |
|||
44 |
#include "resources/loaders/imageloader.h" |
||
45 |
|||
46 |
#include "resources/sdlimagehelper.h" |
||
47 |
#ifdef USE_SDL2 |
||
48 |
#include "resources/surfaceimagehelper.h" |
||
49 |
#endif // USE_SDL2 |
||
50 |
|||
51 |
#include "resources/resourcemanager/resourcemanager.h" |
||
52 |
|||
53 |
#include "utils/env.h" |
||
54 |
#include "utils/delete2.h" |
||
55 |
#include "utils/foreach.h" |
||
56 |
|||
57 |
PRAGMA48(GCC diagnostic push) |
||
58 |
PRAGMA48(GCC diagnostic ignored "-Wshadow") |
||
59 |
#include <SDL_image.h> |
||
60 |
PRAGMA48(GCC diagnostic pop) |
||
61 |
|||
62 |
#ifndef UNITTESTS_CATCH |
||
63 |
#include <algorithm> |
||
64 |
#endif // UNITTESTS_CATCH |
||
65 |
|||
66 |
#include "debug.h" |
||
67 |
|||
68 |
namespace |
||
69 |
{ |
||
70 |
class InputActionSortFunctorTest final |
||
71 |
{ |
||
72 |
public: |
||
73 |
bool operator() (const InputActionT key1, |
||
74 |
const InputActionT key2) const |
||
75 |
{ |
||
76 |
REQUIRE(CAST_SIZE(key1) < CAST_SIZE(InputAction::TOTAL)); |
||
77 |
REQUIRE(CAST_SIZE(key2) < CAST_SIZE(InputAction::TOTAL)); |
||
78 |
REQUIRE(key1 < InputAction::TOTAL); |
||
79 |
REQUIRE(key2 < InputAction::TOTAL); |
||
80 |
return keys[CAST_SIZE(key1)].priority |
||
81 |
>= keys[CAST_SIZE(key2)].priority; |
||
82 |
} |
||
83 |
|||
84 |
const InputActionData *keys A_NONNULLPOINTER; |
||
85 |
}; |
||
86 |
InputActionSortFunctorTest inputActionDataSorterTest; |
||
87 |
} // namespace |
||
88 |
|||
89 |
2 |
static bool compareBuffers(const unsigned char *const buf2) |
|
90 |
{ |
||
91 |
2 |
bool isCorrect(true); |
|
92 |
2 |
int sz = 0; |
|
93 |
const unsigned char *buf1 = reinterpret_cast<const unsigned char*>( |
||
94 |
✓✗ | 8 |
VirtFs::loadFile("hide.png", sz)); |
95 |
✓✗✓✗ ✓✗✓✗ ✗✗✗✗ |
8 |
REQUIRE(buf1 != nullptr); |
96 |
✓✗✓✗ ✓✗✓✗ ✗✗✗✗ |
8 |
REQUIRE(sz == 368); |
97 |
✓✓ | 738 |
for (int f = 0; f < sz; f ++) |
98 |
{ |
||
99 |
✗✓ | 736 |
if (buf1[f] != buf2[f]) |
100 |
{ |
||
101 |
isCorrect = false; |
||
102 |
logger->log("Wrong buffer chars: 0x%x vs 0x%x", |
||
103 |
buf1[f], |
||
104 |
buf2[f]); |
||
105 |
} |
||
106 |
} |
||
107 |
✓✗ | 2 |
delete [] buf1; |
108 |
2 |
return isCorrect; |
|
109 |
} |
||
110 |
|||
111 |
✓✗ | 15 |
TEST_CASE("integrity tests", "integrity") |
112 |
{ |
||
113 |
13 |
setEnv("SDL_VIDEODRIVER", "dummy"); |
|
114 |
|||
115 |
✓✗ | 13 |
client = new Client; |
116 |
13 |
XML::initXML(); |
|
117 |
13 |
SDL_Init(SDL_INIT_VIDEO); |
|
118 |
52 |
std::string name("data/test/test.zip"); |
|
119 |
26 |
std::string prefix; |
|
120 |
✓✗✓✗ |
13 |
if (Files::existsLocal(name) == false) |
121 |
✓✗ | 26 |
prefix = "../" + prefix; |
122 |
|||
123 |
✓✗✓✗ |
52 |
VirtFs::mountDirSilent("data", Append_false); |
124 |
✓✗✓✗ |
52 |
VirtFs::mountDirSilent("../data", Append_false); |
125 |
|||
126 |
✓✗ | 13 |
Dirs::initRootDir(); |
127 |
✓✗ | 13 |
Dirs::initHomeDir(); |
128 |
|||
129 |
✓✗ | 13 |
setBrandingDefaults(branding); |
130 |
✓✗ | 13 |
ConfigManager::initConfiguration(); |
131 |
|||
132 |
#ifdef USE_SDL2 |
||
133 |
imageHelper = new SurfaceImageHelper; |
||
134 |
|||
135 |
SDLImageHelper::setRenderer(graphicsManager.createRenderer( |
||
136 |
GraphicsManager::createWindow(640, 480, 0, |
||
137 |
SDL_WINDOW_SHOWN | SDL_SWSURFACE), SDL_RENDERER_SOFTWARE)); |
||
138 |
#else // USE_SDL2 |
||
139 |
|||
140 |
✓✗ | 26 |
imageHelper = new SDLImageHelper(); |
141 |
|||
142 |
✓✗ | 13 |
GraphicsManager::createWindow(640, 480, 0, SDL_ANYFORMAT | SDL_SWSURFACE); |
143 |
#endif // USE_SDL2 |
||
144 |
|||
145 |
✓✗✓✗ |
13 |
userPalette = new UserPalette; |
146 |
|||
147 |
✓✗✓✗ |
52 |
config.setValue("fontSize", 16); |
148 |
✓✗✓✗ |
13 |
theme = new Theme; |
149 |
✓✗ | 13 |
Theme::selectSkin(); |
150 |
|||
151 |
✓✗ | 13 |
ActorSprite::load(); |
152 |
13 |
const char *const name1 = "dir/hide.png"; |
|
153 |
13 |
const int size1 = 368; |
|
154 |
|||
155 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity test 1") |
156 |
{ |
||
157 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(sizeof(inputActionData) / sizeof(InputActionData) == |
158 |
CAST_SIZE(InputAction::TOTAL)); |
||
159 |
} |
||
160 |
|||
161 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity test 2") |
162 |
{ |
||
163 |
2 |
KeyToActionMap actionMap; |
|
164 |
1 |
const size_t sz = CAST_SIZE(InputAction::TOTAL); |
|
165 |
✓✓ | 671 |
for (size_t i = 0; i < sz; i ++) |
166 |
{ |
||
167 |
670 |
InputActionT val = static_cast<InputActionT>(i); |
|
168 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(val < InputAction::TOTAL); |
169 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(val > InputAction::NO_VALUE); |
170 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(val > InputAction::UNDEFINED_VALUE); |
171 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(CAST_SIZE(val) < CAST_SIZE(InputAction::TOTAL)); |
172 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(CAST_SIZE(val) < CAST_SIZE(InputAction::NO_VALUE)); |
173 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(CAST_SIZE(val) < CAST_SIZE(InputAction::UNDEFINED_VALUE)); |
174 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(CAST_S32(val) < CAST_S32(InputAction::TOTAL)); |
175 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(CAST_S32(val) > CAST_S32(InputAction::NO_VALUE)); |
176 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(CAST_S32(val) > CAST_S32(InputAction::UNDEFINED_VALUE)); |
177 |
} |
||
178 |
} |
||
179 |
|||
180 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity test 3") |
181 |
{ |
||
182 |
2 |
KeyToActionMap actionMap; |
|
183 |
1 |
int cnt = 0; |
|
184 |
1 |
const size_t sz = CAST_SIZE(InputAction::TOTAL); |
|
185 |
✓✓ | 671 |
for (size_t i = 0; i < sz; i ++) |
186 |
{ |
||
187 |
✓✗ | 1340 |
actionMap[cnt++].push_back(static_cast<InputActionT>(i)); |
188 |
✓✓ | 670 |
if (cnt > 3) |
189 |
167 |
cnt = 0; |
|
190 |
} |
||
191 |
✓✓ | 2 |
FOR_EACH (KeyToActionMapIter, it, actionMap) |
192 |
{ |
||
193 |
4 |
KeysVector *const keys = &it->second; |
|
194 |
✓✓ | 682 |
FOR_EACHP (KeysVectorIter, itk, keys) |
195 |
{ |
||
196 |
670 |
const size_t val = CAST_SIZE(*itk); |
|
197 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
2680 |
REQUIRE(val < sz); |
198 |
} |
||
199 |
} |
||
200 |
} |
||
201 |
|||
202 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity test 4") |
203 |
{ |
||
204 |
2 |
KeyToActionMap actionMap; |
|
205 |
2 |
KeyTimeMap keyTimeMap; |
|
206 |
1 |
actionMap.clear(); |
|
207 |
1 |
keyTimeMap.clear(); |
|
208 |
|||
209 |
✓✓ | 671 |
for (size_t i = 0; i < CAST_SIZE(InputAction::TOTAL); i ++) |
210 |
{ |
||
211 |
✓✗ | 1340 |
actionMap[10].push_back( |
212 |
2010 |
static_cast<InputActionT>(i)); |
|
213 |
} |
||
214 |
|||
215 |
✓✗ | 1 |
KeysVector *const keys = &actionMap[0]; |
216 |
1 |
inputActionDataSorterTest.keys = &inputActionData[0]; |
|
217 |
3 |
std::sort(keys->begin(), keys->end(), inputActionDataSorterTest); |
|
218 |
} |
||
219 |
|||
220 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity test 5") |
221 |
{ |
||
222 |
2 |
KeyToActionMap mKeyToAction; |
|
223 |
2 |
KeyToIdMap mKeyToId; |
|
224 |
2 |
KeyTimeMap mKeyTimeMap; |
|
225 |
inputManager.updateKeyActionMap(mKeyToAction, mKeyToId, |
||
226 |
✓✗ | 1 |
mKeyTimeMap, InputType::KEYBOARD); |
227 |
} |
||
228 |
|||
229 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 1") |
230 |
{ |
||
231 |
✓✗✓✗ |
4 |
Image *const image = Loader::getImage( |
232 |
1 |
"graphics/images/login_wallpaper.png"); |
|
233 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(image != nullptr); |
234 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
5 |
REQUIRE(image->getSDLSurface() != nullptr); |
235 |
✓✗ | 1 |
image->decRef(); |
236 |
} |
||
237 |
|||
238 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 2") |
239 |
{ |
||
240 |
✓✗✓✗ |
2 |
VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); |
241 |
✓✗✓✗ |
4 |
Image *const image = Loader::getImage( |
242 |
1 |
"dir/hide.png"); |
|
243 |
✓✗✓✗ |
2 |
VirtFs::unmountZip(prefix + "data/test/test.zip"); |
244 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(image != nullptr); |
245 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
5 |
REQUIRE(image->getSDLSurface() != nullptr); |
246 |
✓✗ | 1 |
image->decRef(); |
247 |
} |
||
248 |
|||
249 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 3") |
250 |
{ |
||
251 |
✓✗✓✗ |
2 |
VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); |
252 |
✓✗✓✗ |
4 |
Image *const image = Loader::getImage( |
253 |
1 |
"dir/brimmedhat.png"); |
|
254 |
✓✗✓✗ |
2 |
VirtFs::unmountZip(prefix + "data/test/test.zip"); |
255 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(image != nullptr); |
256 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
5 |
REQUIRE(image->getSDLSurface() != nullptr); |
257 |
✓✗ | 1 |
image->decRef(); |
258 |
} |
||
259 |
|||
260 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 4") |
261 |
{ |
||
262 |
✓✗✓✗ |
2 |
VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); |
263 |
|||
264 |
✓✗✓✗ |
4 |
SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); |
265 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(rw != nullptr); |
266 |
unsigned char buf[size1]; |
||
267 |
✓✗ | 1 |
const size_t sz = SDL_RWread(rw, buf, 1, size1); |
268 |
✗✓ | 1 |
if (sz != size1) |
269 |
SDL_RWclose(rw); |
||
270 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(sz == size1); |
271 |
✓✗ | 1 |
SDL_RWclose(rw); |
272 |
✓✗✓✗ |
2 |
VirtFs::unmountZip(prefix + "data/test/test.zip"); |
273 |
✓✗✓✗ |
2 |
VirtFs::mountDirSilent(prefix + "data/test", Append_true); |
274 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✗✗✗ |
3 |
REQUIRE(compareBuffers(buf)); |
275 |
✓✗✓✗ |
2 |
VirtFs::unmountDirSilent(prefix + "data/test"); |
276 |
} |
||
277 |
|||
278 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 7") |
279 |
{ |
||
280 |
✓✗✓✗ |
2 |
VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); |
281 |
|||
282 |
✓✗✓✗ |
4 |
SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); |
283 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(rw != nullptr); |
284 |
✓✗ | 1 |
int64_t seek = SDL_RWseek(rw, 0, RW_SEEK_END); |
285 |
✗✓ | 1 |
if (seek == -1) |
286 |
SDL_RWclose(rw); |
||
287 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(seek != -1); |
288 |
✓✗ | 1 |
const int64_t pos = SDL_RWtell(rw); |
289 |
✗✓ | 1 |
if (pos != size1) |
290 |
SDL_RWclose(rw); |
||
291 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(pos == size1); |
292 |
|||
293 |
✓✗ | 1 |
seek = SDL_RWseek(rw, 0, RW_SEEK_SET); |
294 |
✗✓ | 1 |
if (seek == -1) |
295 |
SDL_RWclose(rw); |
||
296 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(seek != -1); |
297 |
|||
298 |
unsigned char buf[size1]; |
||
299 |
✓✗ | 1 |
const size_t sz = SDL_RWread(rw, buf, 1, pos); |
300 |
✗✓ | 1 |
if (sz != size1) |
301 |
SDL_RWclose(rw); |
||
302 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(sz == size1); |
303 |
|||
304 |
✓✗ | 1 |
SDL_RWclose(rw); |
305 |
✓✗✓✗ |
2 |
VirtFs::unmountZip(prefix + "data/test/test.zip"); |
306 |
✓✗✓✗ |
4 |
VirtFs::mountDirSilent("data/test", Append_true); |
307 |
✓✗✓✗ |
4 |
VirtFs::mountDirSilent("../data/test", Append_true); |
308 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✗✗✗ |
3 |
REQUIRE(compareBuffers(buf)); |
309 |
✓✗✓✗ |
4 |
VirtFs::unmountDirSilent("data/test"); |
310 |
✓✗✓✗ |
4 |
VirtFs::unmountDirSilent("../data/test"); |
311 |
} |
||
312 |
|||
313 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 8") |
314 |
{ |
||
315 |
✓✗✓✗ |
2 |
VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); |
316 |
|||
317 |
✓✗✓✗ |
4 |
SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); |
318 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(rw != nullptr); |
319 |
✓✗✗✓ |
1 |
if (IMG_isPNG(rw) == 0) |
320 |
{ |
||
321 |
SDL_RWclose(rw); |
||
322 |
REQUIRE(false); |
||
323 |
} |
||
324 |
✓✗ | 1 |
SDL_Surface *const tmpImage = IMG_LoadPNG_RW(rw); |
325 |
✓✗ | 1 |
SDL_RWclose(rw); |
326 |
✓✗✓✗ |
2 |
VirtFs::unmountZip(prefix + "data/test/test.zip"); |
327 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(tmpImage != nullptr); |
328 |
✓✗ | 1 |
SDL_FreeSurface(tmpImage); |
329 |
} |
||
330 |
|||
331 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 9") |
332 |
{ |
||
333 |
✓✗✓✗ |
2 |
VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); |
334 |
|||
335 |
✓✗✓✗ |
4 |
SDL_RWops *const rw = VirtFs::rwopsOpenRead(name1); |
336 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(rw != nullptr); |
337 |
✓✗ | 1 |
Resource *const res = imageHelper->load(rw); |
338 |
✓✗✓✗ |
2 |
VirtFs::unmountZip(prefix + "data/test/test.zip"); |
339 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(res != nullptr); |
340 |
✓✗ | 1 |
delete res; |
341 |
} |
||
342 |
|||
343 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✓ |
91 |
SECTION("integrity Loader::getImage test 10") |
344 |
{ |
||
345 |
✓✗✓✗ |
2 |
VirtFs::mountZip(prefix + "data/test/test.zip", Append_false); |
346 |
✓✗✓✗ |
4 |
Image *const image = Loader::getImage( |
347 |
1 |
name1); |
|
348 |
✓✗✓✗ |
2 |
VirtFs::unmountZip(prefix + "data/test/test.zip"); |
349 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
4 |
REQUIRE(image != nullptr); |
350 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✗ ✗✗ |
5 |
REQUIRE(image->getSDLSurface() != nullptr); |
351 |
✓✗ | 1 |
image->decRef(); |
352 |
} |
||
353 |
|||
354 |
✓✗ | 13 |
ResourceManager::cleanOrphans(true); |
355 |
|||
356 |
✓✗ | 13 |
delete2(userPalette) |
357 |
✓✗ | 13 |
delete2(client) |
358 |
|||
359 |
✓✗✓✗ |
52 |
VirtFs::unmountDirSilent("data"); |
360 |
✓✗✓✗ |
52 |
VirtFs::unmountDirSilent("../data"); |
361 |
✓✗✓✗ |
16 |
} |
Generated by: GCOVR (Version 3.3) |