A full unit test suite for the Project_zero C++ library: 260 tests, all passing. Verified on both g++ 13 / Ubuntu 24.04 / C++20 and MSVC / Visual Studio / C++20. The concurrent tests were additionally run under ThreadSanitizer with no data races detected.
| Test file | Module | Covers | Tests |
|---|---|---|---|
tests/allocator_test.cpp |
Allocator.h |
Pool, Monotonic, Stack, Segregated, Debug allocators | 31 |
tests/smart_ptr_test.cpp |
Smart_ptr.h |
Unique_ptr, Shared_ptr, Weak_ptr, make_unique/make_shared | 38 |
tests/algorithms_test.cpp |
My_algorithms.h |
Linear/Binary search, Selection/Bubble/Insertion/Quick sort | 35 |
tests/adt_sequence_test.cpp |
ADT.h |
Forward_list, List, Deque, Vector(+bool), Stack, Queue | 58 |
tests/adt_tree_map_set_test.cpp |
ADT.h |
Binary_tree, Map, Multimap, Set, Multiset | 44 |
tests/adt_hash_test.cpp |
ADT.h |
Hash_table, Unordered_map/multimap/set/multiset | 29 |
tests/adt_concurrent_test.cpp |
ADT.h |
Thread_safe, Concurrent_hash_table, Concurrent_unordered_map/set (+ real multi-thread stress tests) | 25 |
Total: 260 tests, 260 passed.
While writing the tests, two real defects were found and fixed directly in the source:
Both implementations extracted a node from other and passed the temporary Node_handle
straight into insert(). If insertion failed (duplicate key already in this), the
temporary handle was destroyed at the end of the expression — deleting the node's data
along with it, instead of leaving the element in other the way std::map::merge /
std::set::merge do.
Fix: capture the handle in a named variable; on failed insertion, insert it back into other.
operator== for Pool_allocator, Monotonic_allocator, Stack_allocator,
Segregated_allocator, and Debug_allocator is a friend function template that compared
two different template instantiations (e.g. Monotonic_allocator<int> vs
Monotonic_allocator<double>) by reading each other's private field directly. Per the
standard, friendship of a class does not transitively extend to that class's own friend
functions, so this access is only valid for the instantiation the function is declared
inside of. GCC accepted this leniently; MSVC correctly rejected it with C2248.
Fix: route the comparison of the "other" side through the type's existing public
accessor (resource() / stats()) instead of touching the private field directly. Added
a small public resource() accessor to Segregated_allocator, which didn't have one.
See ADT_bugfixes.diff and Allocator_bugfixes.diff for the exact patches.
My_algorithms.hrelies on the MSVC-specific_NODISCARDmacro (normally provided by<sal.h>on Visual Studio). On g++/Linux it isn't defined, so the test file defines it manually before the#include. Not needed on MSVC, since it comes from the platform headers.find()/sort()onLinear_search,Binary_search,Selection_sort,Bubble_sort,Insertion_sort, andQuick_sortareprotected. To test the algorithm logic directly (rather than only the console-driven methods that read fromstd::cin), small accessor subclasses are used (using Base::method;) with explicit constructors —Fields<T>is a virtual base for these mixins, so plain constructor inheritance (using Base::Base;) doesn't initialize it correctly.Auto_ptrinSmart_ptr.honly compiles under MSVC with_MSVC_LANG < 201703L. Since the project targets C++20, it never compiles at all and therefore isn't tested.- The
Concurrent_hash_table/Concurrent_unordered_mapstress tests intentionally limit insert counts (or pre-size the table) to avoid triggering arehashmid-run under ThreadSanitizer.rehashbriefly holds a lock on every old bucket at once — correct at runtime, but it exceeds ThreadSanitizer's internal cap on simultaneously tracked locks once the bucket count grows past ~64. That's a TSAN instrumentation limitation, not a real race in the code under test.
Requirements: g++/clang (C++20), cmake (≥3.14), libgtest-dev.
sudo apt-get install -y cmake libgtest-dev
mkdir build && cd build
cmake ..
make -j$(nproc)
ctest # or run individual binaries: ./allocator_tests, ./smart_ptr_tests, etc.Each module builds into its own executable: allocator_tests, smart_ptr_tests,
algorithms_tests, adt_sequence_tests, adt_tree_map_set_tests, adt_hash_tests,
adt_concurrent_tests.
- Install GoogleTest via vcpkg:
vcpkg install gtest:x64-windows vcpkg integrate install - In your existing
Project_zero.slnx, add a new Empty Project (C++) namedTests(Solution Explorer → right-click the solution → Add → New Project). - Add all files from
tests/*.cppto theTestsproject. - In
Tests→ Properties (All Configurations, x64):- C/C++ → General → Additional Include Directories:
$(SolutionDir)ADT;$(SolutionDir)Allocator;$(SolutionDir)Smart_ptr;$(SolutionDir)My_algorithms - C/C++ → Language → C++ Language Standard:
ISO C++20 Standard (/std:c++20) - Linker → Input → Additional Dependencies:
gtest.lib;gtest_main.lib;%(AdditionalDependencies)(usegtestd.lib;gtest_maind.libfor the Debug configuration if needed) - Linker → System → SubSystem:
Console (/SUBSYSTEM:CONSOLE) - Do not add project references to
ADT/Allocator/Smart_ptr/My_algorithms— they are header-only here, and vcpkg will otherwise try (and fail) to link non-existent.libfiles.
- C/C++ → General → Additional Include Directories:
- Set
Testsas the startup project and build (Build → Rebuild Solution). - Run with Ctrl+F5 (Start Without Debugging) to keep the console open after the run.
For a proper test tree instead of a raw console log, install the "Test Adapter for Google Test" component via the Visual Studio Installer (Individual Components tab — it's a VS installer component, not a Marketplace extension in current VS versions), then use Test → Test Explorer.
g++ -std=c++20 -fsanitize=thread -g -O1 \
-I Project_zero-main/Allocator -I Project_zero-main/Smart_ptr \
-I Project_zero-main/My_algorithms -I Project_zero-main/ADT \
tests/adt_concurrent_test.cpp -lgtest -lgtest_main -lpthread \
-o adt_concurrent_tsan
./adt_concurrent_tsan