Skip to content

Latest commit

 

History

History
123 lines (99 loc) · 7.54 KB

File metadata and controls

123 lines (99 loc) · 7.54 KB

Project_zero — Unit Tests (GoogleTest)

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.

Coverage

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.

Bugs found and fixed in the library code (not worked around in the tests)

While writing the tests, two real defects were found and fixed directly in the source:

1. Map::merge() / Set::merge() silently dropped elements (ADT/ADT.h)

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.

2. Cross-instantiation private member access in allocator operator== (Allocator/Allocator.h)

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.

Notes on quirks handled in the tests

  • My_algorithms.h relies on the MSVC-specific _NODISCARD macro (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() on Linear_search, Binary_search, Selection_sort, Bubble_sort, Insertion_sort, and Quick_sort are protected. To test the algorithm logic directly (rather than only the console-driven methods that read from std::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_ptr in Smart_ptr.h only 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_map stress tests intentionally limit insert counts (or pre-size the table) to avoid triggering a rehash mid-run under ThreadSanitizer. rehash briefly 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.

Build & run — CMake (Linux/macOS or Windows with g++/clang)

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.

Build & run — Visual Studio (recommended for this project)

  1. Install GoogleTest via vcpkg:
    vcpkg install gtest:x64-windows
    vcpkg integrate install
  2. In your existing Project_zero.slnx, add a new Empty Project (C++) named Tests (Solution Explorer → right-click the solution → Add → New Project).
  3. Add all files from tests/*.cpp to the Tests project.
  4. 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) (use gtestd.lib;gtest_maind.lib for 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 .lib files.
  5. Set Tests as the startup project and build (Build → Rebuild Solution).
  6. 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.

Optional: ThreadSanitizer run for the concurrent tests

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