diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 03cb235..bdd92c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build SeBa +name: Build and test SeBa on: push: @@ -19,3 +19,7 @@ jobs: run: | cd dstar make + - name: Build and run unit tests + run: | + git submodule update --init --recursive + make test \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..58750c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +Makefile.inc +dstar/Makefile.inc +**/*.o +**/*.a +starev +dstar/Normalisation +dstar/SeBa +**/*.data +build/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5a4e85a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "third_party/googletest"] + path = third_party/googletest + url = https://github.com/google/googletest.git diff --git a/Makefile b/Makefile index 290352b..8e76218 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ DIRS = node std sstar dstar rdc all: lib $(EXE) -test: +test-compiler: echo $(CXX) echo `which $(CXX)` @@ -22,3 +22,53 @@ lib: Makefile.inc clean: Makefile.inc @for d in $(DIRS) ; do echo '\nmake' $@ in $$d; make -C $$d $@ ; done /bin/rm -f *~ $(EXE) Makefile.inc + +# --- Test support --- +TEST_CXXFLAGS = $(CXXFLAGS) -std=c++23 +TESTDIR = tests +BUILDDIR = build +TESTBIN = $(BUILDDIR)/run_tests +TESTSRC = $(wildcard $(TESTDIR)/*.cpp) +TESTOBJ = $(patsubst $(TESTDIR)/%.cpp,$(BUILDDIR)/%.o,$(TESTSRC)) + +GTEST_DIR = third_party/googletest/googletest +GTEST_SRC = $(GTEST_DIR)/src/gtest-all.cc +GTEST_OBJ = $(BUILDDIR)/gtest-all.o +GTEST_INC = -I$(GTEST_DIR)/include -I$(GTEST_DIR) +GTEST_MAIN_SRC = $(GTEST_DIR)/src/gtest_main.cc +GTEST_MAIN_OBJ = $(BUILDDIR)/gtest_main.o + +# Create build directory +$(BUILDDIR): + mkdir -p $(BUILDDIR) + +# Compile Google Test source +$(GTEST_OBJ): $(GTEST_SRC) | $(BUILDDIR) + $(CXX) $(TEST_CXXFLAGS) $(GTEST_INC) -c $< -o $@ + +# Compile test sources +$(BUILDDIR)/%.o: $(TESTDIR)/%.cpp | $(BUILDDIR) + $(CXX) $(TEST_CXXFLAGS) $(GTEST_INC) -I./include -c $< -o $@ + +# Compile Google Test main +$(GTEST_MAIN_OBJ): $(GTEST_MAIN_SRC) | $(BUILDDIR) + $(CXX) $(TEST_CXXFLAGS) $(GTEST_INC) -c $< -o $@ + +# Link final test binary +$(TESTBIN): $(TESTOBJ) $(GTEST_OBJ) $(GTEST_MAIN_OBJ) + $(CXX) $(TEST_CXXFLAGS) $(GTEST_INC) -I./include $^ \ + $(LDLIBS) -lpthread -o $@ + +# Run tests +test: $(TESTBIN) + @echo "Running unit tests..." + @./$(TESTBIN) + +# Run specific tests matching a pattern +test_%: $(TESTBIN) + @echo "Running tests matching '$*'..." + @./$(TESTBIN) --gtest_filter=*${*}* + +# Optional cleanup +clean-tests: + /bin/rm -rf $(BUILDDIR) diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..63b0e36 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,78 @@ +# Tests + +## Overview + +Unit tests live in the `tests/` directory. +They use **GoogleTest (gtest)**, a lightweight C++ testing framework. +Tests are built and executed by running: + +``` sh +make test +``` + + +This compiles all test files (`tests/*.cpp`), links them against project libraries and gtest, and runs them automatically. +Passing tests will print `[ PASSED ]` lines in the terminal. + +## Getting GoogleTest Source + +This project vendors GoogleTest to make the test build self-contained. +Ensure the submodules are cloned so that the GoogleTest code is included: + +```sh +git submodule update --init --recursive +``` + +This will populate `third_party/googletest/`, which contains the GoogleTest source built automatically when running `make test`. + +## Cleaning Up + +To remove test binaries: + +``` sh +make clean-tests +``` + +## Writing a Test + +Each test file is a small C++ program that includes both gtest and your project +headers. + +You want to define test cases using the `TEST` macro provided by gtest, and +ensure that your functions behave as expected using assertions like `EXPECT_EQ`, `ASSERT_TRUE`, etc. + +Example: + +``` cpp +#include "util_math.h +#include + +TEST(Basic, Add) { EXPECT_EQ(add(2, 2), 4); } +``` + +## Running Tests + +Run all tests: + +``` sh +make test +``` + +Run a specific test suite or test case: + +``` sh +make test_[pattern] +``` + +E.g., run all tests marked `UtilMath`, run: + +``` sh +make test_UtilMath + +``` + +Run a specific test case within a suite: + +``` sh +make test_UtilMath.Twiddles +``` diff --git a/tests/test_basic.cpp b/tests/test_basic.cpp new file mode 100644 index 0000000..f753908 --- /dev/null +++ b/tests/test_basic.cpp @@ -0,0 +1,5 @@ +#include + +int add(int a, int b) { return a + b; } + +TEST(Basic, Add) { EXPECT_EQ(add(2, 2), 4); } diff --git a/tests/test_util_math.cpp b/tests/test_util_math.cpp new file mode 100644 index 0000000..f640961 --- /dev/null +++ b/tests/test_util_math.cpp @@ -0,0 +1,30 @@ +#include "util_math.h" +#include + +// basic numerical tolerance for comparisons +static constexpr real EPS = 1e-12; + +TEST(UtilMath, Twiddles) { + EXPECT_TRUE(twiddles(1.0, 1.0 + 1e-13, EPS)); + EXPECT_FALSE(twiddles(1.0, 1.1, EPS)); +} + +TEST(UtilMath, Sign) { + EXPECT_EQ(sign(3.5), 1); + EXPECT_EQ(sign(-2.1), -1); + EXPECT_EQ(sign(0.0), 0); +} + +TEST(UtilMath, AdjustNumberToPower) { + // result should not exceed max_step_size + real result = adjust_number_to_power(5.5, 4.0); + EXPECT_LE(result, 4.0); +} + +TEST(UtilMath, AsinhAcoshConsistency) { + real x = 1.5; + real s = sinh(x); + real c = cosh(x); + EXPECT_NEAR(asinh(s), x, 1e-12); + EXPECT_NEAR(acosh(c), x, 1e-12); +} diff --git a/third_party/googletest b/third_party/googletest new file mode 160000 index 0000000..b2b9072 --- /dev/null +++ b/third_party/googletest @@ -0,0 +1 @@ +Subproject commit b2b9072ecbe874f5937054653ef8f2731eb0f010