Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ option (BUILD_TEST_APPS "Build test applications" OFF)
option (DIST_INSTALLER "Generate installer for distributing vapor binaries. Will generate standard make install if off" OFF)
option (USE_OMP "Use OpenMP on some calculations" OFF)
option (CONDA_BUILD "Use Conda to build" OFF)
option( BUILD_GOOGLE_TEST "Build unit tests using GoogleTest" OFF )
if (UNIX AND NOT APPLE)
include (CMakeDependentOption)
cmake_dependent_option (DIST_APPIMAGE "Generate an AppImage for VAPOR's installation across multiple Linux platforms" OFF "DIST_INSTALLER" ON)
Expand All @@ -116,6 +117,32 @@ if( USE_OMP )
endif()
endif()

#
# Build Google Test
#
if( BUILD_GOOGLE_TEST )
# Control internal options of GoogleTest
#
set( INSTALL_GTEST OFF CACHE INTERNAL "Not install GoogleTest")
set( BUILD_GMOCK ON CACHE INTERNAL "Build gmock")

# Let's use the new mechanism to incorporate GoogleTest
#
include(FetchContent)
FetchContent_Declare( googletest
URL https://github.com/google/googletest/archive/refs/heads/main.zip
DOWNLOAD_EXTRACT_TIMESTAMP NEW )

# Prevent overriding the parent project's compiler/linker settings on Windows
#
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

enable_testing() # calling this function before adding subdirectory to enable
# invoking ctest from the top-level build directory.
add_subdirectory( googletest_scripts )
endif()

set (GENERATE_FULL_INSTALLER ON)
if (BUILD_GUI)
set (BUILD_VDC ON)
Expand Down
10 changes: 10 additions & 0 deletions googletest_scripts/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Add an executable that tests a specific part of VAPOR.
add_executable( ptr_cache_test ptr_cache_test.cpp )
target_include_directories( ptr_cache_test PRIVATE ${PROJECT_SOURCE_DIR}/include/vapor/ )
target_link_libraries( ptr_cache_test PUBLIC GTest::gtest_main )


include(GoogleTest)

# Enable this executable to be tested using `ctest .`
gtest_discover_tests( ptr_cache_test )
112 changes: 112 additions & 0 deletions googletest_scripts/ptr_cache_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include "gtest/gtest.h"

#include "ptr_cache.hpp" // Only include the module that's tested

namespace {

struct MyObj {
int i = 0, j = 1;
};

// Besides correct insertion/query/eviction behaviors the `ptr_cache` has to be
// deleting objects correctly upon eviction. However, memory errors are not
// something GoogleTest can detect. As a result, one needs to run this
// executable in valgrind to make sure that there are no memory errors:
// valgrind ./googletest_scripts/ptr_cache_test

// Test the cache when queries don't count as a use.
// It needs to insert and evict correctly.
TEST(ptr_cache_query_false, insert_eviction)
{
VAPoR::ptr_cache<int, MyObj, 3, false> cache;
const auto* p = cache.query(1);
EXPECT_EQ(p, nullptr); // nothing in the cache yet, should get nullptr

cache.insert(1, new MyObj{1, 100});
cache.insert(2, new MyObj{2, 200});
cache.insert(3, new MyObj{3, 300});

// Make sure that we have all 3 objects
p = cache.query(1);
EXPECT_NE(p, nullptr); // not nullptr
EXPECT_EQ(p->j, 100);
p = cache.query(2);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 200);
p = cache.query(3);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 300);
p = cache.query(4);
EXPECT_EQ(p, nullptr);

// Insert a new object; make sure that "1" is evicted.
cache.insert(4, new MyObj{4, 400});
p = cache.query(4);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 400);
p = cache.query(1);
EXPECT_EQ(p, nullptr);

// Do a query on "2", but queries don't count as a use.
p = cache.query(2);

// Insert another object; make sure that "2" is evicted.
cache.insert(5, new MyObj{5, 500});
p = cache.query(5);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 500);
p = cache.query(2);
EXPECT_EQ(p, nullptr);
}


// Test the cache when queries count as a use.
TEST(ptr_cache_query_true, insert_eviction)
{
VAPoR::ptr_cache<int, MyObj, 3, true> cache;

cache.insert(1, new MyObj{1, 100});
cache.insert(2, new MyObj{2, 200});
cache.insert(3, new MyObj{3, 300});

// Make sure that we have all 3 objects
const auto* p = cache.query(1);
EXPECT_NE(p, nullptr); // not nullptr
EXPECT_EQ(p->j, 100);
p = cache.query(2);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 200);
p = cache.query(3);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 300);
p = cache.query(4);
EXPECT_EQ(p, nullptr);

// Insert a new object; make sure that "1" is evicted.
cache.insert(4, new MyObj{4, 400});
p = cache.query(4);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 400);
p = cache.query(1);
EXPECT_EQ(p, nullptr);

// Do a query on "2", then insert, it should be "3" that's evicted.
p = cache.query(2);
cache.insert(5, new MyObj{5, 500});
p = cache.query(5);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 500);
p = cache.query(3);
EXPECT_EQ(p, nullptr);

// Do another query on "2", then insert, it should be "4" that's evicted.
p = cache.query(2);
cache.insert(6, new MyObj{6, 600});
p = cache.query(6);
EXPECT_NE(p, nullptr);
EXPECT_EQ(p->j, 600);
p = cache.query(4);
EXPECT_EQ(p, nullptr);
}

} // End of namespace