Code Coverage Report


Directory: targets/
File: om-tree-test-library/source/om/tree_test.cpp
Date: 2024-10-29 22:25:26
Exec Total Coverage
Lines: 0 0 100.0%
Functions: 0 0 -%
Branches: 0 0 -%

Line Branch Exec Source
1 // LCOV_EXCL_START
2
3 extern "C" {
4 #include <om/tree_test.h>
5 }
6
7 extern "C" {
8 #include <om/bit.h>
9 #include <om/memory.h>
10 #if Om_Tree_IsPrintEnabled
11 #include <om/print.h>
12 #endif
13 #include <om/require.h>
14 #include <om/time.h>
15 #include <om/tree.h>
16 #include <om/tree/iteration.h>
17 #include <om/tree/lookup.h>
18 }
19
20 #include <algorithm>
21 #include <cinttypes>
22 #include <climits>
23 #include <cstdio>
24 #include <cstring>
25 #include <iomanip>
26 #include <iostream>
27 #include <map>
28 #include <random>
29 #include <set>
30 #include <string>
31
32 namespace {
33
34 namespace AllocatedSizeLeafNodeInterface {
35
36 auto InitializeCopy(
37 Om_Tree_LeafNode * const theLeafNode,
38 Om_Tree_LeafNode const theLeafNodeToCopy
39 ) -> bool {
40 Om_Require(theLeafNode);
41 auto * const theMemory = static_cast<size_t *>(
42 Om_Memory_Allocate(sizeof(size_t))
43 );
44 if(theMemory != nullptr) {
45 // NOLINTNEXTLINE(performance-no-int-to-ptr)
46 *theMemory = *reinterpret_cast<size_t const *>(theLeafNodeToCopy);
47 }
48 *theLeafNode = reinterpret_cast<Om_Tree_LeafNode>(theMemory);
49 return (theMemory != nullptr);
50 }
51
52 #if Om_Tree_IsPrintEnabled
53 auto Print(
54 Om_Tree_LeafNode const theLeafNode,
55 FILE * const theStream
56 ) {
57 assert(theStream);
58
59 // NOLINTNEXTLINE(performance-no-int-to-ptr)
60 auto const * const theSize = reinterpret_cast<size_t const *>(
61 theLeafNode
62 );
63 assert(theSize);
64 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg)
65 return (fprintf(theStream, "%zu", *theSize) >= 0);
66 }
67 #endif
68
69 auto Match(
70 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
71 Om_Tree_LeafNode const theLHSLeafNode,
72 Om_Tree_LeafNode const theRHSLeafNode
73 ) -> bool {
74 // NOLINTBEGIN(performance-no-int-to-ptr)
75 auto const * const theLHSSize = reinterpret_cast<size_t const *>(
76 theLHSLeafNode
77 );
78 auto const * const theRHSSize = reinterpret_cast<size_t const *>(
79 theRHSLeafNode
80 );
81 // NOLINTEND(performance-no-int-to-ptr)
82 assert(theLHSSize && theRHSSize);
83 return (*theLHSSize == *theRHSSize);
84 }
85
86 void Deinitialize(
87 Om_Tree_LeafNode const theLeafNode
88 ) {
89 // NOLINTNEXTLINE(performance-no-int-to-ptr)
90 Om_Memory_Deallocate(reinterpret_cast<size_t *>(theLeafNode));
91 }
92
93 }
94
95 Om_Tree_LeafNode_Interface const theAllocatedSizeLeafNodeInterface = {
96 .InitializeCopy = AllocatedSizeLeafNodeInterface::InitializeCopy,
97 #if Om_Tree_IsPrintEnabled
98 .Print = AllocatedSizeLeafNodeInterface::Print,
99 #endif
100 .Match = AllocatedSizeLeafNodeInterface::Match,
101 .Deinitialize = AllocatedSizeLeafNodeInterface::Deinitialize
102 };
103
104 auto Insert(
105 Om_Tree & theTree,
106 std::string const & theString,
107 Om_Tree_LeafNode const theValue
108 ) -> int {
109 int theResult{};
110
111 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
112 std::cout << "Inserting " << std::quoted(theString);
113 std::cout << " (\"";
114 Om_Print_BinaryByteArray(theString.length(), theString.data(), stdout);
115 std::cout << "\")... ";
116 #endif
117 {
118 Om_Tree_LeafNode * theLeafNode{};
119 theResult = Om_Tree_Insert(
120 &theTree, theString.length(), theString.data(), &theLeafNode
121 );
122 Om_Require(theResult);
123 if(theResult > 0) {
124 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
125 std::cout << "Inserted." << std::endl;
126 #endif
127 Om_Require(theLeafNode != nullptr);
128 } else {
129 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
130 std::cout << "Found." << std::endl;
131 #endif
132 Om_Require(theLeafNode != nullptr);
133 }
134
135 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
136 std::cout << "Setting to " << theValue << "...";
137 #endif
138 Om_Require(theLeafNode);
139 assert(theLeafNode);
140 *theLeafNode = theValue;
141 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
142 std::cout << "Set." << std::endl;
143 #endif
144 }
145
146 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
147 std::cout << "Tree:" << std::endl;
148 Om_Require(Om_Tree_Print(&theTree, stdout));
149 #endif
150
151 {
152 auto * const theLeafNode = Om_Tree_Get(
153 &theTree, theString.length(), theString.data()
154 );
155 Om_Require(theLeafNode && (*theLeafNode == theValue));
156 }
157
158 {
159 Om_Tree theCopy;
160 Om_Require(Om_Tree_InitializeCopy(&theCopy, &theTree));
161 Om_Require(Om_Tree_Match(&theCopy, &theTree));
162 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
163 std::cout << "Copy:" << std::endl;
164 Om_Require(Om_Tree_Print(&theCopy, stdout));
165 std::cout << std::endl;
166 #endif
167 Om_Tree_Reinitialize(&theCopy);
168 Om_Require(Om_Tree_IsEmpty(&theCopy));
169 }
170
171 return theResult;
172 }
173
174 auto Remove(
175 Om_Tree & theTree,
176 std::string const & theString,
177 Om_Tree_LeafNode & theValue
178 ) -> int {
179 int theResult{};
180
181 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
182 std::cout << "Removing " << std::quoted(theString);
183 std::cout << " (\"";
184 Om_Print_BinaryByteArray(theString.length(), theString.data(), stdout);
185 std::cout << "\")... ";
186 #endif
187 theResult = Om_Tree_Remove(
188 &theTree, theString.length(), theString.data(), &theValue
189 );
190 Om_Require(theResult);
191 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
192 if(theResult > 0) {
193 std::cout << "Removed." << std::endl;
194 } else {
195 std::cout << "Not found." << std::endl;
196 }
197
198 std::cout << "Tree:" << std::endl;
199 Om_Tree_Print(&theTree, stdout);
200 std::cout << std::endl;
201 #endif
202 return theResult;
203 }
204
205 #if !defined(NDEBUG)
206 template<typename TheFunction>
207 void TestAllocationFailure(
208 TheFunction const & theFunction
209 ) {
210 // Allocation failures.
211 assert(!Om_Memory_FailAllocations);
212 assert(!Om_Memory_AllocationToFail);
213 Om_Memory_FailAllocations = true;
214 for(
215 size_t theAllocationToFail{};
216 theAllocationToFail < SIZE_MAX;
217 ++theAllocationToFail
218 ) {
219 Om_Memory_AllocationToFail = theAllocationToFail;
220 if(theFunction()) {
221 Om_Require(theAllocationToFail);
222 break;
223 }
224 }
225 Om_Memory_AllocationToFail = 0U;
226 Om_Memory_FailAllocations = false;
227 }
228 #endif
229
230 #if Om_Tree_IsPrintEnabled
231 auto Read(
232 FILE * const theFile
233 ) -> std::string {
234 assert(theFile);
235
236 {
237 [[maybe_unused]] auto const theResult = fseek(theFile, 0, SEEK_END);
238 assert(theResult == 0);
239 }
240 size_t theLength{};
241 {
242 auto const theResult = ftell(theFile);
243 assert(theResult >= 0);
244 theLength = static_cast<size_t>(theResult);
245 }
246 {
247 [[maybe_unused]] auto const theResult = fseek(theFile, 0, SEEK_SET);
248 assert(theResult == 0);
249 }
250 std::string theString(theLength, '\0');
251 {
252 [[maybe_unused]] auto const theResult = fread(
253 &theString.front(), 1U, theLength, theFile
254 );
255 assert(theResult == theLength);
256 }
257 return theString;
258 }
259 #endif
260
261 void Fuzz(
262 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
263 std::uint_fast32_t const theSeed,
264 size_t const theStringCount,
265 size_t const theMaximumStringLength,
266 size_t const theIterationCount,
267 bool const isBaseline = false
268 ) {
269 timespec theStart{};
270 timespec theEnd{};
271
272 double theInsertionTime{};
273 double theNegativeLookupTime{};
274 double thePositiveLookupTime{};
275 double theIterationTime{};
276 double theCopyMatchClearTime{};
277 double theRemovalTime{};
278
279 std::minstd_rand random{theSeed};
280
281 for(
282 size_t theIterationIndex{};
283 theIterationIndex < theIterationCount;
284 ++theIterationIndex
285 ) {
286 Om_Tree theTree;
287 Om_Tree_Initialize(&theTree, nullptr);
288 std::map<std::string, size_t> theMap{};
289
290 std::set<std::string> theStrings{};
291 for(
292 size_t theStringIndex{};
293 theStringIndex < theStringCount;
294 ++theStringIndex
295 ) {
296 std::string theString(random() % theMaximumStringLength, '\0');
297 std::generate(
298 theString.begin(), theString.end(), [&random]() {
299 return static_cast<char>((random() % UCHAR_MAX) + 1U);
300 }
301 );
302 theStrings.insert(theString);
303
304 Om_Require(timespec_get(&theStart, TIME_UTC));
305 bool wasFound{};
306 if(isBaseline) {
307 wasFound = theMap.contains(theString);
308 } else {
309 wasFound = (
310 Om_Tree_Get(&theTree, theString.length(), theString.data()) !=
311 nullptr
312 );
313 }
314 Om_Require(timespec_get(&theEnd, TIME_UTC));
315 if(!wasFound) {
316 theNegativeLookupTime += Om_Time_GetElapsedMilliseconds(
317 theStart, theEnd
318 );
319 }
320
321 Om_Require(timespec_get(&theStart, TIME_UTC));
322 if(isBaseline) {
323 theMap[theString] = theStringIndex;
324 } else {
325 Om_Tree_Set(
326 &theTree, theString.length(), theString.data(), theStringIndex
327 );
328 }
329 Om_Require(timespec_get(&theEnd, TIME_UTC));
330 theInsertionTime += Om_Time_GetElapsedMilliseconds(theStart, theEnd);
331
332 Om_Require(timespec_get(&theStart, TIME_UTC));
333 if(isBaseline) {
334 auto const theIterator = theMap.find(theString);
335 assert(theIterator != theMap.end());
336 Om_Require(theIterator->second == theStringIndex);
337 } else {
338 Om_Tree_Lookup theLookup;
339 Om_Tree_Lookup_Initialize(&theLookup, &theTree);
340 assert(Om_Tree_Lookup_CanAdvance(&theLookup));
341 Om_Tree_Lookup_Advance(
342 &theLookup, theString.length() + 1U, theString.data()
343 );
344 auto const * const theLeafNode = Om_Tree_Lookup_GetLeafNode(
345 &theLookup
346 );
347 Om_Require(theLeafNode && (*theLeafNode == theStringIndex));
348 }
349 Om_Require(timespec_get(&theEnd, TIME_UTC));
350 thePositiveLookupTime += Om_Time_GetElapsedMilliseconds(
351 theStart, theEnd
352 );
353 }
354
355 {
356 size_t theIndex = 0U;
357 Om_Require(timespec_get(&theStart, TIME_UTC));
358 if(isBaseline) {
359 for(auto theElement : theMap) {
360 assert(theIndex < SIZE_MAX);
361 ++theIndex;
362 }
363 } else {
364 Om_Tree_Iteration theIteration;
365 Om_Tree_Iteration_Initialize(&theIteration, &theTree);
366 Om_Require(Om_Tree_Iteration_GetLeafNode(&theIteration));
367 do {
368 assert(theIndex < SIZE_MAX);
369 ++theIndex;
370 } while(Om_Tree_Iteration_Advance(&theIteration));
371 Om_Tree_Iteration_Deinitialize(&theIteration);
372 }
373 Om_Require(timespec_get(&theEnd, TIME_UTC));
374 Om_Require(theIndex == theStrings.size());
375 }
376 theIterationTime += Om_Time_GetElapsedMilliseconds(theStart, theEnd);
377
378 Om_Require(timespec_get(&theStart, TIME_UTC));
379 if(isBaseline) {
380 std::map<std::string, size_t> theCopy{theMap};
381 Om_Require(theCopy == theMap);
382 theCopy.clear();
383 assert(theCopy.empty());
384 } else {
385 Om_Tree theCopy;
386 Om_Require(Om_Tree_InitializeCopy(&theCopy, &theTree));
387 Om_Require(Om_Tree_Match(&theCopy, &theTree));
388 Om_Tree_Reinitialize(&theCopy);
389 Om_Require(Om_Tree_IsEmpty(&theCopy));
390 }
391 Om_Require(timespec_get(&theEnd, TIME_UTC));
392 theCopyMatchClearTime += Om_Time_GetElapsedMilliseconds(theStart, theEnd);
393
394 for(auto const & theString : theStrings) {
395 int unsigned theStatus{};
396 Om_Require(timespec_get(&theStart, TIME_UTC));
397 if(isBaseline) {
398 theMap.erase(theString);
399 } else {
400 Om_Tree_Unset(&theTree, theString.length(), theString.data());
401 }
402 Om_Require(timespec_get(&theEnd, TIME_UTC));
403 theRemovalTime += Om_Time_GetElapsedMilliseconds(theStart, theEnd);
404 Om_Require(!theStatus);
405 }
406 Om_Require(Om_Tree_IsEmpty(&theTree));
407 }
408
409 theInsertionTime = theInsertionTime / static_cast<double>(
410 theIterationCount
411 );
412 theNegativeLookupTime = theNegativeLookupTime / static_cast<double>(
413 theIterationCount
414 );
415 thePositiveLookupTime = thePositiveLookupTime / static_cast<double>(
416 theIterationCount
417 );
418 theIterationTime = theIterationTime / static_cast<double>(
419 theIterationCount
420 );
421 theCopyMatchClearTime = theCopyMatchClearTime / static_cast<double>(
422 theIterationCount
423 );
424 theRemovalTime = theRemovalTime / static_cast<double>(
425 theIterationCount
426 );
427
428 std::cout << "Fuzz ";
429 if(isBaseline) {
430 std::cout << "(std::map) ";
431 } else {
432 std::cout << "(Om_Tree) ";
433 }
434 std::cout << "(";
435 std::cout << theSeed;
436 std::cout << ", ";
437 std::cout << theStringCount;
438 std::cout << ", ";
439 std::cout << theMaximumStringLength;
440 std::cout << ", ";
441 std::cout << theIterationCount;
442 std::cout << "):" << std::endl;
443 std::cout << " ";
444 std::cout << "Insertion (ms): ";
445 std::cout << std::fixed << theInsertionTime;
446 std::cout << "; ";
447 std::cout << "Lookup (negative) (ms): ";
448 std::cout << std::fixed << theNegativeLookupTime;
449 std::cout << "; ";
450 std::cout << "Lookup (positive) (ms): ";
451 std::cout << std::fixed << thePositiveLookupTime;
452 std::cout << "; ";
453 std::cout << "Iteration (ms): ";
454 std::cout << std::fixed << theIterationTime;
455 std::cout << "; ";
456 std::cout << "Copy+Match+Clear (ms): ";
457 std::cout << std::fixed << theCopyMatchClearTime;
458 std::cout << "; ";
459 std::cout << "Removal (ms): ";
460 std::cout << std::fixed << theRemovalTime;
461 std::cout << std::endl;
462 }
463
464 }
465
466 void Om_TreeTest() {
467 try {
468 // Basic insertion, removal and lookup tests.
469 {
470 Om_Tree theTree;
471 Om_Tree_Initialize(&theTree, nullptr);
472
473 std::vector<char const *> const theStrings{
474 "\xF0\x9F\x98\x82",
475 "abc",
476 "adc",
477 "ade",
478 "ad\x01",
479 "a",
480 "ad",
481 "bac",
482 "bab",
483 "ca",
484 "",
485 "\xF0\x9F\x98\x81"
486 };
487
488 for(size_t theIndex{}; theIndex < theStrings.size(); ++theIndex) {
489 auto const & theString = theStrings[theIndex];
490 Om_Require(Om_Tree_GetCount(&theTree) == theIndex);
491 Om_Require(
492 Insert(theTree, theString, theIndex + theStrings.size()) == 1
493 );
494 Om_Require(Insert(theTree, theString, theIndex) == -1);
495 }
496
497 for(size_t theIndex{}; theIndex < theStrings.size(); ++theIndex) {
498 auto const & theString = theStrings[theIndex];
499 Om_Tree_LeafNode theLeafNode = 0U;
500 Om_Require(Remove(theTree, theString, theLeafNode) == 1);
501 Om_Require(theLeafNode == theIndex);
502 Om_Require(Remove(theTree, theString, theLeafNode) == -1);
503 }
504
505 Om_Require(Om_Tree_IsEmpty(&theTree));
506 }
507
508 // Additional insertion tests.
509 {
510 #if !defined(NDEBUG)
511 TestAllocationFailure(
512 []() {
513 Om_Tree theTree;
514 Om_Tree_Initialize(&theTree, nullptr);
515 int theResult = Om_Tree_Set(&theTree, 1U, "0", 0U);
516 if(theResult != 0) {
517 theResult = Om_Tree_Set(&theTree, 1U, "1", 0U);
518 if(theResult != 0) {
519 theResult = Om_Tree_Set(&theTree, 0U, "", 0U);
520 }
521 }
522 Om_Tree_Deinitialize(&theTree);
523 return (theResult != 0);
524 }
525 );
526
527 // Split a branch on the last byte of the null terminator.
528 TestAllocationFailure(
529 []() {
530 Om_Tree theTree;
531 Om_Tree_Initialize(&theTree, nullptr);
532 int theResult = Om_Tree_Set(&theTree, 1U, "\1", 0U);
533 if(theResult != 0) {
534 theResult = Om_Tree_Set(&theTree, 0U, "", 0U);
535 }
536 Om_Tree_Deinitialize(&theTree);
537 return (theResult != 0);
538 }
539 );
540 #endif
541
542 // Set with leaf node interface.
543 {
544 Om_Tree theTree;
545 Om_Tree_Initialize(&theTree, &theAllocatedSizeLeafNodeInterface);
546 std::string const theString{"1"};
547
548 auto * theSize = static_cast<size_t *>(
549 Om_Memory_Allocate(sizeof(size_t))
550 );
551 Om_Require(theSize);
552 *theSize = 2U;
553
554 int theResult = Om_Tree_Set(
555 &theTree, theString.length(), theString.data(),
556 reinterpret_cast<Om_Tree_LeafNode>(theSize)
557 );
558 Om_Require(theResult == 1);
559
560 theSize = static_cast<size_t *>(Om_Memory_Allocate(sizeof(size_t)));
561 Om_Require(theSize);
562 *theSize = 1U;
563
564 theResult = Om_Tree_Set(
565 &theTree, theString.length(), theString.data(),
566 reinterpret_cast<Om_Tree_LeafNode>(theSize)
567 );
568 Om_Require(theResult == -1);
569
570 Om_Tree_Deinitialize(&theTree);
571 }
572
573 // Set without leaf node interface.
574 {
575 Om_Tree theTree;
576 Om_Tree_Initialize(&theTree, nullptr);
577 std::string const theString{"1"};
578
579 size_t theSize{2U};
580 int theResult = Om_Tree_Set(
581 &theTree, theString.length(), theString.data(), theSize
582 );
583 Om_Require(theResult == 1);
584
585 theSize = 1U;
586 theResult = Om_Tree_Set(
587 &theTree, theString.length(), theString.data(), theSize
588 );
589 Om_Require(theResult == -1);
590
591 Om_Tree_Deinitialize(&theTree);
592 }
593 }
594
595 // Additional removal tests.
596 {
597 {
598 Om_Tree theTree;
599 Om_Tree_Initialize(&theTree, nullptr);
600 Om_Require(Om_Tree_Set(&theTree, 2U, "02", 0U));
601 Om_Require(Om_Tree_Set(&theTree, 2U, "03", 0U));
602
603 // Branch byte mismatch.
604 Om_Require(Om_Tree_Unset(&theTree, 1U, "1") == -1);
605
606 // Deleting child sibling to leaf.
607 Om_Tree_Set(&theTree, 3U, "03\x1", 0U);
608 Om_Require(Om_Tree_Unset(&theTree, 3U, "03\x1") == 1);
609
610 // Deleting leaf with non-empty sibling.
611 Om_Tree_Set(&theTree, 3U, "02\x1", 0U);
612 Om_Require(Om_Tree_Unset(&theTree, 2U, "02") == 1);
613
614 Om_Tree_Deinitialize(&theTree);
615 }
616
617 // Unset with leaf node interface.
618 {
619 std::string const theString{"1"};
620
621 auto * const theSize = static_cast<size_t *>(
622 Om_Memory_Allocate(sizeof(size_t))
623 );
624 Om_Require(theSize);
625 assert(theSize);
626 *theSize = 1U;
627
628 Om_Tree theTree;
629 Om_Tree_Initialize(&theTree, &theAllocatedSizeLeafNodeInterface);
630 Om_Tree_Set(
631 &theTree, theString.length(), theString.data(),
632 reinterpret_cast<Om_Tree_LeafNode>(theSize)
633 );
634 Om_Require(
635 Om_Tree_Unset(&theTree, theString.length(), theString.data()) == 1
636 );
637 Om_Tree_Deinitialize(&theTree);
638 }
639
640 #if !defined(NDEBUG)
641 // Memory errors.
642 TestAllocationFailure(
643 []() {
644 Om_Tree theTree;
645 Om_Tree_Initialize(&theTree, nullptr);
646
647 Om_Memory_FailAllocations = false;
648 Om_Tree_Set(&theTree, 1U, "2", 1U);
649 Om_Tree_Set(&theTree, 2U, "2\1", 2U);
650 Om_Tree_Set(&theTree, 2U, "3\1", 3U);
651 Om_Tree_Set(&theTree, 2U, "3\3", 4U);
652 Om_Require(Om_Tree_GetCount(&theTree) == 4U);
653 Om_Memory_FailAllocations = true;
654
655 do {
656 int theResult = Om_Tree_Unset(&theTree, 1U, "2");
657 if(theResult != 1) {
658 Om_Require(theResult == 0);
659 Om_Require(Om_Tree_GetCount(&theTree) == 4U);
660 break;
661 }
662 Om_Require(Om_Tree_GetCount(&theTree) == 3U);
663
664 theResult = Om_Tree_Unset(&theTree, 2U, "2\1");
665 if(theResult != 1) {
666 Om_Require(theResult == 0);
667 Om_Require(Om_Tree_GetCount(&theTree) == 3U);
668 break;
669 }
670 Om_Require(Om_Tree_GetCount(&theTree) == 2U);
671
672 theResult = Om_Tree_Unset(&theTree, 2U, "3\1");
673 if(theResult != 1) {
674 Om_Require(theResult == 0);
675 Om_Require(Om_Tree_GetCount(&theTree) == 2U);
676 break;
677 }
678 Om_Require(Om_Tree_GetCount(&theTree) == 1U);
679
680 theResult = Om_Tree_Unset(&theTree, 2U, "3\3");
681 Om_Require(theResult == 1);
682 Om_Require(Om_Tree_GetCount(&theTree) == 0U);
683 Om_Require(Om_Tree_IsEmpty(&theTree));
684 return true;
685 } while(false);
686
687 Om_Tree_Deinitialize(&theTree);
688 return false;
689 }
690 );
691 #endif
692 }
693
694 // Additional find and lookup tests.
695 {
696 Om_Tree theTree;
697 Om_Tree_Initialize(&theTree, nullptr);
698
699 // False find in empty tree.
700 Om_Require(!Om_Tree_Get(&theTree, 1U, "0"));
701
702 // False find.
703 Om_Tree_Set(&theTree, 2U, "00", 2U);
704 Om_Tree_Set(&theTree, 2U, "01", 2U);
705 Om_Require(!Om_Tree_Get(&theTree, 2U, "02"));
706
707 // False substring find.
708 Om_Require(!Om_Tree_Get(&theTree, 0U, ""));
709
710 {
711 Om_Tree_Lookup theLookup;
712 Om_Tree_Lookup_Initialize(&theLookup, &theTree);
713 Om_Require(Om_Tree_Lookup_CanAdvance(&theLookup));
714 Om_Require(Om_Tree_Lookup_Advance(&theLookup, 1U, "0") == 1);
715 Om_Require(Om_Tree_Lookup_CanAdvance(&theLookup));
716 Om_Require(Om_Tree_Lookup_Advance(&theLookup, 1U, "0") == 1);
717 {
718 Om_Tree_Lookup theEmptyBranchLookup = theLookup;
719 Om_Require(Om_Tree_Lookup_CanAdvance(&theEmptyBranchLookup));
720 Om_Require(
721 Om_Tree_Lookup_Advance(&theEmptyBranchLookup, 1U, "\x1") == 0
722 );
723 Om_Require(!Om_Tree_Lookup_CanAdvance(&theEmptyBranchLookup));
724 }
725 {
726 Om_Tree_Lookup theLeafLookup = theLookup;
727 Om_Require(Om_Tree_Lookup_Advance(&theLeafLookup, 1U, "") == -1);
728 Om_Require(!Om_Tree_Lookup_CanAdvance(&theLeafLookup));
729 }
730 }
731 Om_Tree_Reinitialize(&theTree);
732
733 // Finding a node with a bit count of 0.
734 Om_Tree_Set(&theTree, 1U, "\xB5", 0U);
735 Om_Tree_Set(&theTree, 1U, "\xB7", 0U);
736 Om_Tree_Set(&theTree, 2U, "\xB7\xE1", 0U);
737 Om_Require(Om_Tree_Get(&theTree, 1U, "\xB7"));
738 {
739 Om_Tree_Lookup theLookup;
740 Om_Tree_Lookup_Initialize(&theLookup, &theTree);
741 Om_Require(Om_Tree_Lookup_Advance(&theLookup, 1U, "\xB7") == 1);
742 Om_Require(Om_Tree_Lookup_Advance(&theLookup, 1U, "") == -1);
743 }
744 Om_Tree_Deinitialize(&theTree);
745 }
746
747 // Additional comparison tests.
748 {
749 // Empty match.
750 {
751 Om_Tree theEmptyTree;
752 Om_Tree_Initialize(&theEmptyTree, nullptr);
753 Om_Require(Om_Tree_Match(&theEmptyTree, &theEmptyTree));
754 }
755
756 // Emptiness mismatch.
757 {
758 Om_Tree theEmptyTree;
759 Om_Tree_Initialize(&theEmptyTree, nullptr);
760
761 Om_Tree theTree;
762 Om_Tree_Initialize(&theTree, nullptr);
763 Om_Require(Insert(theTree, "", 0U) == 1);
764
765 Om_Require(!Om_Tree_Match(&theEmptyTree, &theTree));
766 Om_Require(!Om_Tree_Match(&theTree, &theEmptyTree));
767
768 // Hack the leaf count to exercise branch node checking.
769 theTree.thisLeafCount = 0U;
770 Om_Require(!Om_Tree_Match(&theEmptyTree, &theTree));
771 Om_Require(!Om_Tree_Match(&theTree, &theEmptyTree));
772
773 Om_Tree_Deinitialize(&theTree);
774 }
775
776 // Length mismatch.
777 {
778 Om_Tree theLHSTree;
779 Om_Tree_Initialize(&theLHSTree, nullptr);
780 Om_Require(Insert(theLHSTree, "0", 0U) == 1);
781
782 Om_Tree theRHSTree;
783 Om_Tree_Initialize(&theRHSTree, nullptr);
784 Om_Require(Insert(theRHSTree, "00", 0U) == 1);
785
786 Om_Require(!Om_Tree_Match(&theLHSTree, &theRHSTree));
787 Om_Require(!Om_Tree_Match(&theRHSTree, &theLHSTree));
788
789 Om_Tree_Deinitialize(&theLHSTree);
790 Om_Tree_Deinitialize(&theRHSTree);
791 }
792
793 // Leaf mismatch.
794 {
795 Om_Tree theLHSTree;
796 Om_Tree_Initialize(&theLHSTree, nullptr);
797 Om_Require(Insert(theLHSTree, "0", 0U) == 1);
798
799 Om_Tree theRHSTree;
800 Om_Tree_Initialize(&theRHSTree, nullptr);
801 Om_Require(Insert(theRHSTree, "0", 1U) == 1);
802
803 Om_Require(!Om_Tree_Match(&theLHSTree, &theRHSTree));
804 Om_Require(!Om_Tree_Match(&theRHSTree, &theLHSTree));
805
806 Om_Tree_Deinitialize(&theLHSTree);
807 Om_Tree_Deinitialize(&theRHSTree);
808 }
809
810 // Leaf mismatch with interface.
811 {
812 Om_Tree theLHSTree;
813 Om_Tree_Initialize(&theLHSTree, &theAllocatedSizeLeafNodeInterface);
814 {
815 auto * theValue = static_cast<size_t *>(
816 Om_Memory_Allocate(sizeof(size_t))
817 );
818 Om_Require(theValue);
819 *theValue = 1U;
820
821 Om_Tree_Set(
822 &theLHSTree, 0U, "", reinterpret_cast<Om_Tree_LeafNode>(theValue)
823 );
824 }
825
826 Om_Tree theRHSTree;
827 Om_Tree_Initialize(&theRHSTree, &theAllocatedSizeLeafNodeInterface);
828 {
829 auto * theValue = static_cast<size_t *>(
830 Om_Memory_Allocate(sizeof(size_t))
831 );
832 Om_Require(theValue);
833 *theValue = 2U;
834
835 Om_Tree_Set(
836 &theRHSTree, 0U, "", reinterpret_cast<Om_Tree_LeafNode>(theValue)
837 );
838 }
839
840 Om_Require(!Om_Tree_Match(&theLHSTree, &theRHSTree));
841 Om_Require(!Om_Tree_Match(&theRHSTree, &theLHSTree));
842
843 Om_Tree_Deinitialize(&theLHSTree);
844 Om_Tree_Deinitialize(&theRHSTree);
845 }
846
847 // Bit count mismatch.
848 {
849 Om_Tree theLHSTree;
850 Om_Tree_Initialize(&theLHSTree, nullptr);
851 Om_Require(Insert(theLHSTree, "0", 0U) == 1);
852 Om_Require(Insert(theLHSTree, "1", 0U) == 1);
853
854 Om_Tree theRHSTree;
855 Om_Tree_Initialize(&theRHSTree, nullptr);
856 Om_Require(Insert(theRHSTree, "0", 0U) == 1);
857 Om_Require(Insert(theRHSTree, "2", 0U) == 1);
858
859 Om_Require(!Om_Tree_Match(&theLHSTree, &theRHSTree));
860 Om_Require(!Om_Tree_Match(&theRHSTree, &theLHSTree));
861
862 Om_Tree_Deinitialize(&theLHSTree);
863 Om_Tree_Deinitialize(&theRHSTree);
864 }
865
866 // Low branch child mismatch.
867 {
868 Om_Tree theLHSTree;
869 Om_Tree_Initialize(&theLHSTree, nullptr);
870 Om_Require(Insert(theLHSTree, "2", 0U) == 1);
871 Om_Require(Insert(theLHSTree, "4", 0U) == 1);
872
873 Om_Tree theRHSTree;
874 Om_Tree_Initialize(&theRHSTree, nullptr);
875 Om_Require(Insert(theRHSTree, "3", 0U) == 1);
876 Om_Require(Insert(theRHSTree, "4", 0U) == 1);
877
878 Om_Require(!Om_Tree_Match(&theLHSTree, &theRHSTree));
879 Om_Require(!Om_Tree_Match(&theRHSTree, &theLHSTree));
880
881 Om_Tree_Deinitialize(&theLHSTree);
882 Om_Tree_Deinitialize(&theRHSTree);
883 }
884
885 // Leaf interface mismatch.
886 {
887 Om_Tree theLHSTree;
888 Om_Tree_Initialize(&theLHSTree, nullptr);
889 Om_Tree theRHSTree;
890 Om_Tree_Initialize(&theRHSTree, &theAllocatedSizeLeafNodeInterface);
891 Om_Require(!Om_Tree_Match(&theLHSTree, &theRHSTree));
892 Om_Require(!Om_Tree_Match(&theRHSTree, &theLHSTree));
893 }
894
895 // Matching leaf child but mismatching branch child nullness.
896 {
897 Om_Tree theLHSTree;
898 Om_Tree_Initialize(&theLHSTree, nullptr);
899 Om_Tree_Set(&theLHSTree, 1U, "\3", 3U);
900 Om_Tree_Set(&theLHSTree, 2U, "\3\1", 31U);
901 Om_Tree_Set(&theLHSTree, 1U, "\2", 2U);
902
903 Om_Tree theRHSTree;
904 Om_Tree_Initialize(&theRHSTree, nullptr);
905 Om_Tree_Set(&theRHSTree, 1U, "\3", 3U);
906 Om_Tree_Set(&theRHSTree, 1U, "\2", 2U);
907 Om_Tree_Set(&theRHSTree, 2U, "\2\1", 21U);
908
909 Om_Require(!Om_Tree_Match(&theLHSTree, &theRHSTree));
910 Om_Require(!Om_Tree_Match(&theRHSTree, &theLHSTree));
911 Om_Tree_Deinitialize(&theLHSTree);
912 Om_Tree_Deinitialize(&theRHSTree);
913 }
914
915 #if !defined(NDEBUG)
916 {
917 assert(!Om_Memory_FailAllocations);
918 assert(!Om_Memory_AllocationToFail);
919
920 Om_Tree theLHSTree;
921 Om_Tree_Initialize(&theLHSTree, nullptr);
922 Om_Tree_Set(&theLHSTree, 1U, "\3", 3U);
923 Om_Tree_Set(&theLHSTree, 1U, "\2", 2U);
924
925 Om_Tree theRHSTree;
926 Om_Tree_Initialize(&theRHSTree, nullptr);
927 Om_Tree_Set(&theRHSTree, 1U, "\3", 3U);
928 Om_Tree_Set(&theRHSTree, 2U, "\2\1", 21U);
929
930 Om_Memory_FailAllocations = true;
931 for(
932 size_t theAllocationToFail{};
933 theAllocationToFail < 2U; // The number of stack allocations
934 ++theAllocationToFail
935 ) {
936 Om_Memory_AllocationToFail = theAllocationToFail;
937 Om_Require(
938 !Om_Tree_Match(&theLHSTree, &theRHSTree) &&
939 !Om_Tree_Match(&theRHSTree, &theLHSTree)
940 );
941 }
942 Om_Memory_AllocationToFail = 0U;
943 Om_Memory_FailAllocations = false;
944
945 Om_Tree_Deinitialize(&theLHSTree);
946 Om_Tree_Deinitialize(&theRHSTree);
947 }
948 #endif
949 }
950
951 // Additional copy tests.
952 {
953 {
954 Om_Tree theTree;
955 Om_Tree_Initialize(&theTree, nullptr);
956 {
957 Om_Tree theCopy;
958 Om_Require(Om_Tree_InitializeCopy(&theCopy, &theTree));
959 }
960 Om_Require(Om_Tree_Set(&theTree, 1U, "2", 2U) == 1);
961 Om_Require(Om_Tree_Set(&theTree, 1U, "3", 3U) == 1);
962 Om_Require(Om_Tree_Set(&theTree, 2U, "3\1", 4U) == 1);
963 #if !defined(NDEBUG)
964 TestAllocationFailure(
965 [&theTree]() {
966 Om_Tree theCopy;
967 bool const wasCopied{Om_Tree_InitializeCopy(&theCopy, &theTree)};
968 if(wasCopied) {
969 Om_Require(!Om_Tree_IsEmpty(&theCopy));
970 Om_Tree_Reinitialize(&theCopy);
971 }
972 return wasCopied;
973 }
974 );
975 #endif
976 Om_Tree_Deinitialize(&theTree);
977 }
978
979 {
980 Om_Tree theTree;
981 Om_Tree_Initialize(&theTree, &theAllocatedSizeLeafNodeInterface);
982 {
983 auto * theValue = static_cast<size_t *>(
984 Om_Memory_Allocate(sizeof(size_t))
985 );
986 Om_Require(theValue);
987 *theValue = 2U;
988 Om_Tree_Set(
989 &theTree, 1U, "2", reinterpret_cast<Om_Tree_LeafNode>(theValue)
990 );
991
992 theValue = static_cast<size_t *>(Om_Memory_Allocate(sizeof(size_t)));
993 Om_Require(theValue);
994 *theValue = 3U;
995 Om_Tree_Set(
996 &theTree, 1U, "3", reinterpret_cast<Om_Tree_LeafNode>(theValue)
997 );
998 }
999 #if !defined(NDEBUG)
1000 TestAllocationFailure(
1001 [&theTree]() {
1002 Om_Tree theCopy;
1003 bool const wasCopied{Om_Tree_InitializeCopy(&theCopy, &theTree)};
1004 if(wasCopied) {
1005 Om_Require(Om_Tree_Match(&theCopy, &theTree));
1006 Om_Tree_Deinitialize(&theCopy);
1007 }
1008 return wasCopied;
1009 }
1010 );
1011 #endif
1012 Om_Tree_Deinitialize(&theTree);
1013 }
1014 }
1015
1016 #if Om_Tree_IsPrintEnabled
1017 // Additional print tests.
1018 {
1019 std::string theString(4095U, '*');
1020 Om_Tree_LeafNode theValue = 42U;
1021
1022 std::string theExpected{};
1023 theExpected += "- : \"";
1024 for(size_t theIndex{}; theIndex < theString.size(); ++theIndex) {
1025 if(theIndex != 0U) {
1026 theExpected += ' ';
1027 }
1028 theExpected += "00101010";
1029 }
1030 theExpected += " 00000001:7\"\n";
1031 theExpected += "\t0 . 42\n";
1032 theExpected += "\t1 : -\n";
1033
1034 // With leaf node interface.
1035 {
1036 auto * const theFile = tmpfile();
1037 try {
1038 {
1039 auto * const theSize = static_cast<size_t *>(
1040 Om_Memory_Allocate(sizeof(size_t))
1041 );
1042 Om_Require(theSize);
1043 assert(theSize);
1044 *theSize = theValue;
1045
1046 Om_Tree theTree;
1047 Om_Tree_Initialize(&theTree, &theAllocatedSizeLeafNodeInterface);
1048 Om_Require(
1049 Om_Tree_Set(
1050 &theTree, theString.length(), theString.data(),
1051 reinterpret_cast<Om_Tree_LeafNode>(theSize)
1052 )
1053 );
1054 Om_Require(Om_Tree_Print(&theTree, theFile));
1055 Om_Tree_Deinitialize(&theTree);
1056 }
1057
1058 auto const & theResult = Read(theFile);
1059 Om_Require(theResult == theExpected);
1060 Om_Require(0 == fclose(theFile));
1061 } catch(...) {
1062 Om_Require(0 == fclose(theFile));
1063 Om_Require(false);
1064 }
1065 }
1066
1067 // Without leaf node interface.
1068 {
1069 auto * const theFile = tmpfile();
1070 try {
1071 {
1072 Om_Tree theTree;
1073 Om_Tree_Initialize(&theTree, nullptr);
1074 Om_Require(
1075 Om_Tree_Set(
1076 &theTree, theString.length(), theString.data(), theValue
1077 )
1078 );
1079 Om_Require(Om_Tree_Print(&theTree, theFile));
1080 Om_Tree_Deinitialize(&theTree);
1081 }
1082
1083 auto const & theResult = Read(theFile);
1084 Om_Require(theResult == theExpected);
1085 Om_Require(0 == fclose(theFile));
1086 } catch(...) {
1087 Om_Require(0 == fclose(theFile));
1088 Om_Require(false);
1089 }
1090 }
1091 }
1092 #endif
1093
1094 // Iteration tests.
1095 {
1096 Om_Tree theTree;
1097 Om_Tree_Initialize(&theTree, nullptr);
1098
1099 #if !defined(NDEBUG)
1100 // Memory tests.
1101 TestAllocationFailure(
1102 [&theTree]() {
1103 Om_Tree_Iteration theIteration;
1104 if(Om_Tree_Iteration_Initialize(&theIteration, &theTree)) {
1105 Om_Tree_Iteration_Deinitialize(&theIteration);
1106 return true;
1107 }
1108 return false;
1109 }
1110 );
1111 #endif
1112
1113 // Empty tree.
1114 {
1115 Om_Tree_Iteration theIteration;
1116 Om_Require(Om_Tree_Iteration_Initialize(&theIteration, &theTree));
1117 Om_Require(!Om_Tree_Iteration_Advance(&theIteration));
1118 Om_Require(Om_Tree_Iteration_GetStringLength(&theIteration) == 0U);
1119 char const * const theString = Om_Tree_Iteration_GetString(
1120 &theIteration
1121 );
1122 Om_Require(theString && (0 == strcmp(theString, "")));
1123 Om_Require(Om_Tree_Iteration_GetLeafNode(&theIteration) == nullptr);
1124 Om_Tree_Iteration_Deinitialize(&theIteration);
1125 }
1126
1127 // Insert one leaf.
1128 {
1129 [[maybe_unused]] int const theResult = Om_Tree_Set(
1130 &theTree, 1U, "1", 1U
1131 );
1132 assert(theResult == 1);
1133
1134 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
1135 std::cout << "Iterating tree 1:" << std::endl;
1136 Om_Require(Om_Tree_Print(&theTree, stdout));
1137 #endif
1138
1139 Om_Tree_Iteration theIteration;
1140 Om_Require(Om_Tree_Iteration_Initialize(&theIteration, &theTree));
1141 char const * const theString = Om_Tree_Iteration_GetString(
1142 &theIteration
1143 );
1144 Om_Require(theString && (0 == strcmp(theString, "1")));
1145 Om_Tree_LeafNode const * const theLeafNode = (
1146 Om_Tree_Iteration_GetLeafNode(&theIteration)
1147 );
1148 Om_Require(theLeafNode && (*theLeafNode == 1U));
1149 Om_Require(!Om_Tree_Iteration_Advance(&theIteration));
1150 Om_Tree_Iteration_Deinitialize(&theIteration);
1151 }
1152
1153 // Insert another leaf whereby both have null branch siblings.
1154 {
1155 [[maybe_unused]] int const theResult = Om_Tree_Set(
1156 &theTree, 1U, "2", 2U
1157 );
1158 assert(theResult == 1);
1159
1160 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
1161 std::cout << "Iterating tree 2:" << std::endl;
1162 Om_Require(Om_Tree_Print(&theTree, stdout));
1163 #endif
1164
1165 Om_Tree_Iteration theIteration;
1166 Om_Require(Om_Tree_Iteration_Initialize(&theIteration, &theTree));
1167 char const * theString = Om_Tree_Iteration_GetString(&theIteration);
1168 Om_Require(theString && (0 == strcmp(theString, "1")));
1169 Om_Tree_LeafNode const * theLeafNode = (
1170 Om_Tree_Iteration_GetLeafNode(&theIteration)
1171 );
1172 Om_Require(theLeafNode && (*theLeafNode == 1U));
1173
1174 Om_Require(Om_Tree_Iteration_Advance(&theIteration));
1175 theString = Om_Tree_Iteration_GetString(&theIteration);
1176 Om_Require(theString && (0 == strcmp(theString, "2")));
1177 theLeafNode = Om_Tree_Iteration_GetLeafNode(&theIteration);
1178 Om_Require(theLeafNode && (*theLeafNode == 2U));
1179
1180 Om_Require(!Om_Tree_Iteration_Advance(&theIteration));
1181 Om_Tree_Iteration_Deinitialize(&theIteration);
1182 }
1183
1184 // Insert a leaf such that an existing leaf now has a non-null sibling.
1185 {
1186 [[maybe_unused]] int const theResult = Om_Tree_Set(
1187 &theTree, 2U, "1\x1", 3U
1188 );
1189 assert(theResult == 1);
1190
1191 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
1192 std::cout << "Iterating tree 3:" << std::endl;
1193 Om_Require(Om_Tree_Print(&theTree, stdout));
1194 #endif
1195
1196 Om_Tree_Iteration theIteration;
1197 Om_Require(Om_Tree_Iteration_Initialize(&theIteration, &theTree));
1198 char const * theString = Om_Tree_Iteration_GetString(&theIteration);
1199 Om_Require(theString && (0 == strcmp(theString, "1")));
1200 Om_Tree_LeafNode const * theLeafNode = (
1201 Om_Tree_Iteration_GetLeafNode(&theIteration)
1202 );
1203 Om_Require(theLeafNode && (*theLeafNode == 1U));
1204
1205 Om_Require(Om_Tree_Iteration_Advance(&theIteration));
1206 theString = Om_Tree_Iteration_GetString(&theIteration);
1207 Om_Require(theString && (0 == strcmp(theString, "1\x1")));
1208 theLeafNode = Om_Tree_Iteration_GetLeafNode(&theIteration);
1209 Om_Require(theLeafNode && (*theLeafNode == 3U));
1210
1211 Om_Require(Om_Tree_Iteration_Advance(&theIteration));
1212 theString = Om_Tree_Iteration_GetString(&theIteration);
1213 Om_Require(theString && (0 == strcmp(theString, "2")));
1214 theLeafNode = Om_Tree_Iteration_GetLeafNode(&theIteration);
1215 Om_Require(theLeafNode && (*theLeafNode == 2U));
1216
1217 Om_Require(!Om_Tree_Iteration_Advance(&theIteration));
1218 Om_Tree_Iteration_Deinitialize(&theIteration);
1219 }
1220
1221 // Cover the case of advancing and hitting parent with maximum bit count.
1222 {
1223 [[maybe_unused]] int const theResult = Om_Tree_Set(
1224 &theTree, 1U, "0", 4U
1225 );
1226 assert(theResult == 1);
1227
1228 #if Om_Tree_IsPrintEnabled && !defined(NDEBUG)
1229 std::cout << "Iterating tree 4:" << std::endl;
1230 Om_Require(Om_Tree_Print(&theTree, stdout));
1231 #endif
1232
1233 Om_Tree_Iteration theIteration;
1234 Om_Require(Om_Tree_Iteration_Initialize(&theIteration, &theTree));
1235 char const * theString = Om_Tree_Iteration_GetString(&theIteration);
1236 Om_Require(theString && (0 == strcmp(theString, "0")));
1237 Om_Tree_LeafNode const * theLeafNode = (
1238 Om_Tree_Iteration_GetLeafNode(&theIteration)
1239 );
1240 Om_Require(theLeafNode && (*theLeafNode == 4U));
1241
1242 Om_Require(Om_Tree_Iteration_Advance(&theIteration));
1243 theString = Om_Tree_Iteration_GetString(&theIteration);
1244 Om_Require(theString && (0 == strcmp(theString, "1")));
1245 theLeafNode = Om_Tree_Iteration_GetLeafNode(&theIteration);
1246 Om_Require(theLeafNode && (*theLeafNode == 1U));
1247
1248 Om_Require(Om_Tree_Iteration_Advance(&theIteration));
1249 theString = Om_Tree_Iteration_GetString(&theIteration);
1250 Om_Require(theString && (0 == strcmp(theString, "1\x1")));
1251 theLeafNode = Om_Tree_Iteration_GetLeafNode(&theIteration);
1252 Om_Require(theLeafNode && (*theLeafNode == 3U));
1253
1254 Om_Require(Om_Tree_Iteration_Advance(&theIteration));
1255 theString = Om_Tree_Iteration_GetString(&theIteration);
1256 Om_Require(theString && (0 == strcmp(theString, "2")));
1257 theLeafNode = Om_Tree_Iteration_GetLeafNode(&theIteration);
1258 Om_Require(theLeafNode && (*theLeafNode == 2U));
1259
1260 Om_Require(!Om_Tree_Iteration_Advance(&theIteration));
1261 Om_Tree_Iteration_Deinitialize(&theIteration);
1262 }
1263
1264 Om_Tree_Deinitialize(&theTree);
1265 }
1266
1267 // Fuzz tests.
1268 {
1269 std::uint_fast32_t const theSeed{1U};
1270 #if defined(NDEBUG)
1271 size_t const theStringCount{1000U};
1272 size_t const theIterationCount{100U};
1273
1274 std::cout << std::endl;
1275
1276 std::vector<size_t> const theMaximumStringLengthVector{64U, 127U, 1000U};
1277 for(auto const theMaximumStringLength : theMaximumStringLengthVector) {
1278 Fuzz(
1279 theSeed, theStringCount, theMaximumStringLength, theIterationCount,
1280 true
1281 );
1282 Fuzz(
1283 theSeed, theStringCount, theMaximumStringLength, theIterationCount
1284 );
1285 std::cout << std::endl;
1286 }
1287 #else
1288 Fuzz(theSeed, 100U, 100U, 1U);
1289 #endif
1290 }
1291
1292 #if !defined(NDEBUG)
1293 Om_Require(Om_Memory_GetAllocationCount() == 0U);
1294 #endif
1295 } catch(std::exception const & theException) {
1296 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg)
1297 [[maybe_unused]] auto const theResult = fprintf(
1298 stderr, "An error has occurred: %s\n", theException.what()
1299 );
1300 Om_Require(false);
1301 } catch(...) {
1302 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg, hicpp-vararg)
1303 [[maybe_unused]] auto const theResult = fputs(
1304 "An unknown error has occurred.\n", stderr
1305 );
1306 Om_Require(false);
1307 }
1308 }
1309
1310 // LCOV_EXCL_STOP
1311