Skip to content
Draft
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
11 changes: 8 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
pull_request:
branches:
- main
- candidate-v2.0.0
concurrency:
group: ${ {github.event_name }}-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{github.event_name == 'pull_request'}}
Expand All @@ -21,18 +22,22 @@ jobs:

runs-on: ubuntu-latest
container:
image: docker.io/openfoam/openfoam10-paraview510
image: microfluidica/openfoam:13
options: --user root
steps:
- name: Checkout AdditiveFOAM
uses: actions/checkout@v2
- name: Build AdditiveFOAM
run: |
. /opt/openfoam10/etc/bashrc
./Allwmake
- name: Build native tests
run: |
./tests/Allwmake
- name: Run native tests
run: |
./tests/run
- name: Test AdditiveFOAM
run: |
. /opt/openfoam10/etc/bashrc
cp -r tutorials/AMB2018-02-B userCase
cd userCase
# FIXME: use built-in "additiveFoam" smaller case when created
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ maintainers.

Your pull request must work with all current AdditiveFOAM tutorial examples
and be reviewed by at least one AdditiveFOAM developer.

For local verification, build the code with `./Allwmake`, build the native
test harness with `./tests/Allwmake`, and run it with `./tests/run`. The test
workflow and instructions for adding new native tests are documented in
[TESTING.md](TESTING.md).
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

The documentation for `AdditiveFOAM` is hosted on [GitHub Pages](https://ornl.github.io/AdditiveFOAM/).

For local test commands and guidance on adding native C++ tests, see [TESTING.md](TESTING.md).

### Repository Features
| Link | Description |
|-----------------------------------------------------------|------------------------------------------|
Expand Down
41 changes: 41 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Testing

AdditiveFOAM has two test layers:

- Native C++ unit-style tests under [`tests/`](tests), built with `wmake` and linked against the existing AdditiveFOAM/OpenFOAM libraries.
- The tutorial smoke run in GitHub Actions, which checks end-to-end integration.

## Prerequisites

- An OpenFOAM-13 environment must be sourced before building or running tests.
- AdditiveFOAM must be built first so the native tests can link against `libmovingBeamModels`.

## Build And Run

From the repository root:

```bash
. /path/to/openfoam/etc/bashrc
./Allwmake
./tests/Allwmake
./tests/run
```

`./tests/Allwmake` builds the native test executables without changing the default production build path. `./tests/run` executes the complete native suite.

## Current Coverage

The first native executable is `additiveFoamSegmentTests`. It validates `Foam::segment` from `libmovingBeamModels` by checking:

- default construction yields the documented zeroed point-source state
- construction from a space-delimited string populates mode, position, power, and parameter

## Adding A New Native Test

1. Create a new subdirectory under `tests/`.
2. Add a `Make/files` that includes `../shared/testMain.C`, your test source, and an `EXE` target name.
3. Add a `Make/options` file with the required include paths and linked AdditiveFOAM/OpenFOAM libraries.
4. Add the new directory to [`tests/Allwmake`](tests/Allwmake).
5. Add the produced executable to [`tests/run`](tests/run).

The vendored header at [`tests/vendor/doctest/doctest.h`](tests/vendor/doctest/doctest.h) keeps the harness self-contained and avoids extra package dependencies.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ License
#include "heatSourceModel.H"
#include "labelVector.H"
#include "hexMatcher.H"
#include "treeBoundBox.H"

// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //

Expand Down
11 changes: 11 additions & 0 deletions tests/Allwmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh
cd "${0%/*}" || exit 1

if [ -z "${WM_PROJECT_DIR:-}" ]; then
echo "Source the OpenFOAM environment before running ./tests/Allwmake" >&2
exit 1
fi

. "$WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments"

wmake $targetType segment
24 changes: 24 additions & 0 deletions tests/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/sh
cd "${0%/*}" || exit 1

set -eu

if [ -z "${FOAM_USER_APPBIN:-}" ]; then
echo "Source the OpenFOAM environment before running ./tests/run" >&2
exit 1
fi

test_binaries="
$FOAM_USER_APPBIN/additiveFoamSegmentTests
"

for test_binary in $test_binaries
do
if [ ! -x "$test_binary" ]; then
echo "Missing test binary: $test_binary" >&2
echo "Build the test suite first with ./tests/Allwmake" >&2
exit 1
fi

"$test_binary"
done
4 changes: 4 additions & 0 deletions tests/segment/Make/files
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
../shared/testMain.C
segmentTests.C

EXE = $(FOAM_USER_APPBIN)/additiveFoamSegmentTests
11 changes: 11 additions & 0 deletions tests/segment/Make/options
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
EXE_INC = \
-I../vendor/doctest \
-I../../applications/solvers/additiveFoam/movingHeatSource/segment \
-I$(LIB_SRC)/OpenFOAM/lnInclude

EXE_LIBS = \
-L$(FOAM_USER_LIBBIN) \
-lmovingBeamModels \
-lOpenFOAM \
-lfiniteVolume \
-lmeshTools
29 changes: 29 additions & 0 deletions tests/segment/segmentTests.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <string>

#include "doctest.h"
#include "segment.H"

TEST_CASE("Foam::segment default construction yields a zeroed point source")
{
Foam::segment seg;

CHECK_EQ(seg.mode(), Foam::scalar(1));
CHECK_EQ(seg.position().x(), Foam::scalar(0));
CHECK_EQ(seg.position().y(), Foam::scalar(0));
CHECK_EQ(seg.position().z(), Foam::scalar(0));
CHECK_EQ(seg.power(), Foam::scalar(0));
CHECK_EQ(seg.parameter(), Foam::scalar(0));
CHECK_EQ(seg.time(), Foam::scalar(0));
}

TEST_CASE("Foam::segment parses a space-delimited segment definition")
{
Foam::segment seg(std::string("0 1 2 3 400 5"));

CHECK_EQ(seg.mode(), Foam::scalar(0));
CHECK_EQ(seg.position().x(), Foam::scalar(1));
CHECK_EQ(seg.position().y(), Foam::scalar(2));
CHECK_EQ(seg.position().z(), Foam::scalar(3));
CHECK_EQ(seg.power(), Foam::scalar(400));
CHECK_EQ(seg.parameter(), Foam::scalar(5));
}
6 changes: 6 additions & 0 deletions tests/shared/testMain.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "doctest.h"

int main()
{
return doctest::runTests();
}
21 changes: 21 additions & 0 deletions tests/vendor/doctest/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016-2023 Viktor Kirilov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
174 changes: 174 additions & 0 deletions tests/vendor/doctest/doctest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@

// =================================================================================================
//
// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD
//
// Copyright (c) 2016-2017 Viktor Kirilov
//
// Distributed under the MIT Software License
// See accompanying LICENSE.txt file or copy at
// https://opensource.org/licenses/MIT
//
// The documentation can be found at the library's page:
// https://github.com/doctest/doctest
//
// =================================================================================================

#ifndef TESTS_VENDOR_DOCTEST_DOCTEST_H
#define TESTS_VENDOR_DOCTEST_DOCTEST_H

#include <exception>
#include <functional>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

namespace doctest
{

struct TestCase
{
const char* name;
void (*func)();
};

inline std::vector<TestCase>& registry()
{
static std::vector<TestCase> tests;
return tests;
}

struct Registrar
{
Registrar(const char* name, void (*func)())
{
registry().push_back({name, func});
}
};

class AssertionFailure : public std::runtime_error
{
public:
explicit AssertionFailure(const std::string& message)
:
std::runtime_error(message)
{}
};

template<class Left, class Right>
[[noreturn]] inline void failEquality
(
const char* file,
int line,
const char* lhsExpr,
const char* rhsExpr,
const Left& lhs,
const Right& rhs
)
{
std::ostringstream os;
os << file << ":" << line << ": CHECK_EQ(" << lhsExpr << ", " << rhsExpr
<< ") failed with lhs=" << lhs << " rhs=" << rhs;
throw AssertionFailure(os.str());
}

[[noreturn]] inline void failCheck
(
const char* file,
int line,
const char* expression
)
{
std::ostringstream os;
os << file << ":" << line << ": CHECK(" << expression << ") failed";
throw AssertionFailure(os.str());
}

template<class Left, class Right>
inline void checkEqual
(
const Left& lhs,
const Right& rhs,
const char* lhsExpr,
const char* rhsExpr,
const char* file,
int line
)
{
if (!(lhs == rhs))
{
failEquality(file, line, lhsExpr, rhsExpr, lhs, rhs);
}
}

inline void check
(
bool condition,
const char* expression,
const char* file,
int line
)
{
if (!condition)
{
failCheck(file, line, expression);
}
}

inline int runTests()
{
int failed = 0;
int passed = 0;

for (const auto& test : registry())
{
try
{
test.func();
++passed;
std::cout << "[pass] " << test.name << '\n';
}
catch (const std::exception& err)
{
++failed;
std::cerr << "[fail] " << test.name << '\n'
<< err.what() << '\n';
}
catch (...)
{
++failed;
std::cerr << "[fail] " << test.name << '\n'
<< "Unknown exception\n";
}
}

std::cout << "Executed " << (passed + failed) << " test case(s): "
<< passed << " passed, " << failed << " failed\n";

return failed == 0 ? 0 : 1;
}

} // namespace doctest

#define DOCTEST_DETAIL_CONCAT_IMPL(lhs, rhs) lhs##rhs
#define DOCTEST_DETAIL_CONCAT(lhs, rhs) DOCTEST_DETAIL_CONCAT_IMPL(lhs, rhs)

#define TEST_CASE(name) \
static void DOCTEST_DETAIL_CONCAT(doctest_case_, __LINE__)(); \
static doctest::Registrar DOCTEST_DETAIL_CONCAT \
( \
doctest_registrar_, \
__LINE__ \
)(name, &DOCTEST_DETAIL_CONCAT(doctest_case_, __LINE__)); \
static void DOCTEST_DETAIL_CONCAT(doctest_case_, __LINE__)()

#define CHECK(expression) \
doctest::check(static_cast<bool>(expression), #expression, __FILE__, __LINE__)

#define CHECK_EQ(lhs, rhs) \
doctest::checkEqual((lhs), (rhs), #lhs, #rhs, __FILE__, __LINE__)

#endif
Loading