Skip to content

Commit

Permalink
Enable C++ unit testing (#113)
Browse files Browse the repository at this point in the history
* Enable C++ unit testing

* Have separate CMake project for C++ unit tests

* Move include

* Prefer GTest over Catch2
  • Loading branch information
thbeu authored Mar 14, 2024
1 parent ab47cd2 commit ce0528a
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 23 deletions.
25 changes: 11 additions & 14 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,25 @@ jobs:
steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Configure (${{ matrix.configuration }})
run: |
if [ "${{ matrix.toolchain }}" == "windows-msvc-shared" ]; then
cmake -S . -Bbuild -DCMAKE_UNITY_BUILD=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DBUILD_SHARED_LIBS=ON
cmake -S . -Bbuild -DCMAKE_UNITY_BUILD=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON
elif [ "${{ matrix.toolchain }}" == "windows-msvc-static" ]; then
cmake -S . -Bbuild -DCMAKE_UNITY_BUILD=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DBUILD_TESTING=ON -DBASH_EXECUTABLE="C:/Program Files/Git/bin/bash.exe" -DBUILD_SHARED_LIBS=OFF
else
cmake -S . -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.configuration }} -DCMAKE_UNITY_BUILD=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DBUILD_TESTING=ON
fi
- name: Build with ${{ matrix.compiler }}
run: |
if [ "${{ matrix.compiler }}" == "msvc" ]; then
cmake --build build --config ${{ matrix.configuration }}
else
cmake --build build
fi
- name: Test
run: ctest --test-dir build --build-config ${{ matrix.configuration }} --verbose

Expand All @@ -100,36 +100,33 @@ jobs:
steps:
- name: Set git to use LF
run: git config --global core.autocrlf input

- name: Checkout Code
uses: actions/checkout@v4

- name: Setup cygwin
uses: cygwin/cygwin-install-action@master
with:
packages: >-
cmake
gcc-core
gcc-g++
make
ninja
- name: Configure (Release)
run: |
export PATH=/usr/bin:$PATH
cmake -S . -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_UNITY_BUILD=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DBUILD_TESTING=ON -G Ninja
shell: C:\cygwin\bin\bash.exe -eo pipefail -o igncr '{0}'
env:
CYGWIN_NOWINPATH: 1


- name: Build with gcc
run: |
export PATH=/usr/bin:$PATH
cmake --build build
cmake --build build --target install
shell: C:\cygwin\bin\bash.exe -eo pipefail -o igncr '{0}'

- name: Test
run: |
export PATH=/usr/bin:$PATH
export PATH=/usr/bin:/usr/local/bin:$PATH
ctest --test-dir build --build-config Release --verbose
shell: C:\cygwin\bin\bash.exe -eo pipefail -o igncr '{0}'
17 changes: 8 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#
# See README.CMake

# Version 3.7 or above of cmake is currently required for all platforms.
cmake_minimum_required(VERSION 3.7)
# Version 3.11 or above of cmake is currently required for all platforms.
cmake_minimum_required(VERSION 3.11)
project(shapelib C CXX)

message(STATUS "CMake version = ${CMAKE_VERSION}")
Expand Down Expand Up @@ -184,11 +184,6 @@ if(BUILD_APPS)
)
endif()

if(MSVC)
# TODO(schwehr): How to test on Windows?
set(BUILD_TESTING OFF CACHE BOOL "")
endif()

find_program(BASH_EXECUTABLE bash)
if(BASH_EXECUTABLE)
set(BUILD_TESTING ON CACHE BOOL "")
Expand Down Expand Up @@ -235,8 +230,8 @@ if(BUILD_TESTING)
# Other executables to be built to facilitate tests.
foreach(executable shptest shputils)
add_executable(${executable} ${executable}.c)
target_link_libraries(${executable} ${PACKAGE})
endforeach(executable shptest shputils)
target_link_libraries(${executable} PRIVATE ${PACKAGE})
endforeach()

# Set environment variables defining path to executables being used
function(declare_test_executable TEST TARGETS)
Expand Down Expand Up @@ -270,6 +265,10 @@ if(BUILD_TESTING)
${BASH_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tests/test3.sh ${PROJECT_SOURCE_DIR}/tests/expect3.out
)
declare_test_executable(test3 "dbfadd;dbfcreate;dbfdump;shpadd;shpcreate;shpdump")

include(CTest)

add_subdirectory(tests)
endif()

include(cmake/contrib.cmake)
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ EXTRA_DIST = makefile.vc CMakeLists.txt autogen.sh \
cmake/contrib.cmake \
cmake/project-config-version.cmake.in \
cmake/project-config.cmake.in \
tests/CMakeLists.txt \
tests/dbf_test.cc \
tests/test1.sh tests/test2.sh tests/test3.sh \
tests/expect1.out tests/expect2.out tests/expect3.out \
tests/shape_eg_data/3dpoints.dbf \
Expand Down
31 changes: 31 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# CMake configuration for SHP C++ unit tests

project(${CMAKE_PROJECT_NAME}Tests CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Set up GoogleTest
include(FetchContent)

FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)

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

FetchContent_MakeAvailable(googletest)

foreach(executable dbf_test)
add_executable(${executable} ${PROJECT_SOURCE_DIR}/${executable}.cc)
target_link_libraries(${executable} PRIVATE ${PACKAGE} gtest)
add_test(
NAME ${executable}
COMMAND ${executable}
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
)
set_target_properties(${executable} PROPERTIES FOLDER "tests")
endforeach()
90 changes: 90 additions & 0 deletions tests/dbf_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <string_view>

#include <gtest/gtest.h>
#include "shapefil.h"

namespace fs = std::filesystem;

namespace
{

static const auto kTestData = fs::path{"shape_eg_data"};

static bool SetContents(const fs::path &file_name, std::string_view content)
{
std::ofstream file(file_name);
if (!file.is_open())
return false;
file << content;
file.close();
return true;
}

TEST(DBFOpenTest, OpenDoesNotExist_rb)
{
const auto handle = DBFOpen("/does/not/exist.dbf", "rb");
EXPECT_EQ(nullptr, handle);
}

TEST(DBFOpenTest, OpenDoesNotExist_rb_plus)
{
const auto handle = DBFOpen("/does/not/exist2.dbf", "rb+");
EXPECT_EQ(nullptr, handle);
}

TEST(DBFOpenTest, OpenUnexpectedFormat)
{
const auto filename = kTestData / "README.md";
const auto handle = DBFOpen(filename.string().c_str(), "rb");
EXPECT_EQ(nullptr, handle);
}

TEST(DBFOpenTest, OpenExisting)
{
const auto filename = kTestData / "anno.dbf";
const auto handle = DBFOpen(filename.string().c_str(), "rb");
EXPECT_NE(nullptr, handle);
DBFClose(handle);
}

TEST(DBFCreateTest, CreateDoesNotExist)
{
const auto handle = DBFCreate("/does/not/exist");
EXPECT_EQ(nullptr, handle);
}

TEST(DBFCreateTest, CreateAlreadyExisting)
{
const auto filename = kTestData / "in-the-way.dbf";
fs::copy(kTestData / "anno.dbf", filename);
EXPECT_TRUE(SetContents(filename, "some content"));
const auto handle = DBFCreate(filename.string().c_str());
// TODO(schwehr): Seems like a bug to overwrite an existing.
EXPECT_NE(nullptr, handle);
DBFClose(handle);
const auto size = fs::file_size(filename);
EXPECT_EQ(34, size);
fs::remove(filename);
}

TEST(DBFCreateTest, CreateAndClose)
{
const auto filename = kTestData / "empty.dbf";
const auto handle = DBFCreate(filename.string().c_str());
DBFClose(handle);
const auto size = fs::file_size(filename);
EXPECT_EQ(34, size);
fs::remove(filename);
}

} // namespace

int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

0 comments on commit ce0528a

Please sign in to comment.