diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..05fb869 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,42 @@ +name: Coverage + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read # to fetch code (actions/checkout) + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + codecov: + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Install packages + run: sudo apt-get install -y lcov + + - name: Configure + run: cmake -DCMAKE_BUILD_TYPE=Coverage -S . -B build + - name: Build + run: cmake --build build + - name: Run Tests + working-directory: build + run: ctest + - name: Generating coverage report + run: cmake --build build --target coverage_html + + - name: Upload HTML coverage report + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: cov-html + path: build/coverage_report/** + diff --git a/.gitignore b/.gitignore index 259148f..c3b5630 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +build/ + # Prerequisites *.d diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..efb3f61 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.14) +project(xsf) + +# Scipy requ C++17 +# https://docs.scipy.org/doc/scipy/dev/toolchain.html#c-language-standards +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include_directories(${CMAKE_SOURCE_DIR}/include) + +# Tests +enable_testing() +add_subdirectory(tests) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..3018d1a --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,23 @@ +# Get googletest +# https://google.github.io/googletest/quickstart-cmake.html +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG b514bdc898e2951020cbdca1304b75f5950d1f59 # v1.15.2 +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +include(GoogleTest) +include(${CMAKE_SOURCE_DIR}/tests/Coverage.cmake) + +# Add Tests +function(add_gtest test_name) + add_executable(${test_name} ${test_name}.cpp) + target_link_libraries(${test_name} GTest::gtest_main) + gtest_discover_tests(${test_name}) +endfunction() + +add_gtest(airy) diff --git a/tests/Coverage.cmake b/tests/Coverage.cmake new file mode 100644 index 0000000..b12e021 --- /dev/null +++ b/tests/Coverage.cmake @@ -0,0 +1,30 @@ +if(CMAKE_BUILD_TYPE STREQUAL "Coverage") + +# Enable coverage compilation option +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") +endif() +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /coverage") +endif() + +# Add custom targets for generating coverage reports +add_custom_target(coverage + COMMAND lcov --capture --directory . --output-file coverage.info + COMMAND lcov --output-file coverage.info --extract coverage.info '*/include/xsf/*' + COMMAND lcov --list coverage.info + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Generating coverage report" +) + +# Generate coverage reports in HTML format +add_custom_target(coverage_html + COMMAND genhtml --demangle-cpp --legend coverage.info --output-directory coverage_report + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Generating HTML coverage report" +) +add_dependencies(coverage_html coverage) + +endif() # CMAKE_BUILD_TYPE=Coverage \ No newline at end of file diff --git a/tests/airy.cpp b/tests/airy.cpp new file mode 100644 index 0000000..143a0c2 --- /dev/null +++ b/tests/airy.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +TEST(Airy, BasicAssertions) { + const double nan64 = std::numeric_limits::quiet_NaN(); + const std::complex nan64c(std::nan(""), std::nan("")); + double x, ai, aip, bi, bip; + + x = 0.0; + xsf::airy(x, ai, aip, bi, bip); + EXPECT_NE(ai, nan64); + EXPECT_NE(aip, nan64); + EXPECT_NE(bi, nan64); + EXPECT_NE(bip, nan64); + + xsf::airye(x, ai, aip, bi, bip); + EXPECT_NE(ai, nan64); + EXPECT_NE(aip, nan64); + EXPECT_NE(bi, nan64); + EXPECT_NE(bip, nan64); + + double apt, bpt, ant, bnt; + x = 1.0; + xsf::itairy(x, apt, bpt, ant, bnt); + EXPECT_NE(apt, nan64); + EXPECT_NE(bpt, nan64); + EXPECT_NE(ant, nan64); + EXPECT_NE(bnt, nan64); + + // std::complex + std::complex z, cai, caip, cbi, cbip; + z = 0.0; + xsf::airy(z, cai, caip, cbi, cbip); + EXPECT_NE(cai, nan64c); + EXPECT_NE(caip, nan64c); + EXPECT_NE(cbi, nan64c); + EXPECT_NE(cbip, nan64c); + + xsf::airye(z, cai, caip, cbi, cbip); + EXPECT_NE(cai, nan64c); + EXPECT_NE(caip, nan64c); + EXPECT_NE(cbi, nan64c); + EXPECT_NE(cbip, nan64c); +}