diff --git a/.gitignore b/.gitignore index 6e5647983..69691db47 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,9 @@ exts/cesium.omniverse/certs/cacert.pem # Test output _testoutput +# Test utils header has components generated by CMake +tests/testUtils.h + # Packman user files *.user diff --git a/CMakeLists.txt b/CMakeLists.txt index aa975fd1b..268f948b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -425,6 +425,7 @@ find_package(cpr) find_package(doctest) find_package(stb) find_package(ZLIB) +find_package(yaml-cpp) # So that the installed libraries can find shared libraries in the same directory set(CMAKE_INSTALL_RPATH $ORIGIN) diff --git a/ThirdParty.extra.json b/ThirdParty.extra.json index c5d20267a..8b9a9d5ac 100644 --- a/ThirdParty.extra.json +++ b/ThirdParty.extra.json @@ -6,5 +6,14 @@ ], "version": "0.15.0", "url": "https://github.com/CesiumGS/cesium-native" + }, + { + "name": "glTF-Asset-Generator", + "license": [ + "MIT" + ], + "version": "0.6.1", + "url": "https://github.com/KhronosGroup/glTF-Asset-Generator", + "notes": "A selection of test models from this generator are used for testing." } ] diff --git a/ThirdParty.json b/ThirdParty.json index b3aed9a59..7b4d81d1f 100644 --- a/ThirdParty.json +++ b/ThirdParty.json @@ -15,6 +15,15 @@ "version": "1.9.0", "url": "https://docs.libcpr.org/" }, + { + "name": "glTF-Asset-Generator", + "license": [ + "MIT" + ], + "version": "0.6.1", + "url": "https://github.com/KhronosGroup/glTF-Asset-Generator", + "notes": "A selection of test models from this generator are used for testing." + }, { "name": "libcurl", "license": [ @@ -56,6 +65,14 @@ "version": "cci.20220909", "url": "https://github.com/nothings/stb" }, + { + "name": "yaml-cpp", + "license": [ + "MIT" + ], + "version": "0.7.0", + "url": "https://github.com/jbeder/yaml-cpp" + }, { "name": "zlib", "license": [ diff --git a/cmake/AddConanDependencies.cmake b/cmake/AddConanDependencies.cmake index 145aab8aa..915e735ee 100644 --- a/cmake/AddConanDependencies.cmake +++ b/cmake/AddConanDependencies.cmake @@ -10,6 +10,7 @@ set(REQUIRES "pybind11/2.10.1@#561736204506dad955276aaab438aab4" "stb/cci.20220909@#1c47474f095ef8cd9e4959558525b827" "zlib/1.2.13@#13c96f538b52e1600c40b88994de240f" + "yaml-cpp/0.7.0@#85b409c274a53d226b71f1bdb9cb4f8b" "libcurl/7.86.0@#88506b3234d553b90af1ceefc3dd1652" "nasm/2.15.05@#799d63b1672a337584b09635b0f22fc1") diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2d88cdf07..ee43eeb2f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -37,11 +37,11 @@ setup_lib( CesiumUsdSchemas CesiumIonClient Cesium3DTilesSelection - CesiumAsync CesiumGeospatial CesiumGeometry CesiumGltf CesiumGltfReader + CesiumAsync CesiumJsonReader CesiumUtility async++ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a88360d3f..ac54f4f91 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,10 @@ include(Macros) glob_files(SOURCES "${CMAKE_CURRENT_LIST_DIR}/*.cpp") +# replace a string in the utils header with the intended working dir for the test executable +set(TEST_WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}") +configure_file("${CMAKE_CURRENT_LIST_DIR}/testUtils.h.in" "${CMAKE_CURRENT_LIST_DIR}/testUtils.h") + # cmake-format: off setup_app( TARGET_NAME @@ -11,6 +15,7 @@ setup_app( LIBRARIES CesiumOmniverseCore doctest::doctest + yaml-cpp::yaml-cpp CXX_FLAGS ${CESIUM_OMNI_CXX_FLAGS} CXX_FLAGS_DEBUG diff --git a/tests/ExampleTests.cpp b/tests/ExampleTests.cpp index 848804325..01d6fd491 100644 --- a/tests/ExampleTests.cpp +++ b/tests/ExampleTests.cpp @@ -2,17 +2,27 @@ * A collection of simple tests to demonstrate Doctest */ -#include "doctestUtils.h" +#include "testUtils.h" #include +#include #include +#include #include #include +#include + +#include + +const std::string CONFIG_PATH = "tests/configs/exampleConfig.yaml"; // Test Suites are not required, but this sort of grouping makes it possible // to select which tests do/don't run via command line options TEST_SUITE("Example Tests") { + // ---------------------------------------------- + // Basic Tests + // ---------------------------------------------- TEST_CASE("The most basic test") { CHECK(1 + 1 == 2); @@ -65,6 +75,52 @@ TEST_SUITE("Example Tests") { CHECK(item > 0); } + // ---------------------------------------------- + // YAML Config Examples + // ---------------------------------------------- + + std::string transmogrifier(const std::string& s) { + // an example function with differing output for some scenarios + if (s == "scenario2") { + return "bar"; + } + return "foo"; + } + + void checkAgainstExpectedResults(const std::string& scenarioName, const YAML::Node& expectedResults) { + + // we have to specify the type of the desired data from the config via as() + CHECK(3.14159 == expectedResults["pi"].as()); + CHECK(2 == expectedResults["onlyEvenPrime"].as()); + + // as() does work for some non-scalar types, such as vectors, lists, and maps + // for adding custom types to the config, see: + // https://github.com/jbeder/yaml-cpp/wiki/Tutorial#converting-tofrom-native-data-types + const auto fib = expectedResults["fibonacciSeq"].as>(); + CHECK(fib[2] + fib[3] == fib[4]); + + // More complicated checks can be done with helper functions that take the scenario as input + CHECK(transmogrifier(scenarioName) == expectedResults["transmogrifierOutput"].as()); + } + + TEST_CASE("Use a config file to detail multiple scenarios") { + + YAML::Node configRoot = YAML::LoadFile(CONFIG_PATH); + + // The config file has default parameters and + // an override for one or more scenarios + std::vector scenarios = {"scenario1", "scenario2", "scenario3"}; + + for (const auto& s : scenarios) { + ConfigMap conf = getScenarioConfig(s, configRoot); + checkAgainstExpectedResults(s, conf); + } + } + + // ---------------------------------------------- + // Misc. + // ---------------------------------------------- + TEST_CASE("A few other useful macros") { // The most common test macro is CHECK, but others are available // Here are just a few diff --git a/tests/GltfTests.cpp b/tests/GltfTests.cpp new file mode 100644 index 000000000..88ce1c5c5 --- /dev/null +++ b/tests/GltfTests.cpp @@ -0,0 +1,149 @@ +#include "testUtils.h" + +#include "cesium/omniverse/GltfAccessors.h" +#include "cesium/omniverse/GltfUtil.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace cesium::omniverse; + +const std::string ASSET_DIR = "tests/testAssets/gltfs"; +const std::string CONFIG_PATH = "tests/configs/gltfConfig.yaml"; + +// simplifies casting when comparing some material queries to expected output from config +bool operator==(const pxr::GfVec3f& v3, const std::vector& v) { + return v.size() == 3 && v3[0] == v[0] && v3[1] == v[1] && v3[2] == v[2]; +} + +TEST_SUITE("Test GltfUtil") { + void checkGltfExpectedResults(const std::filesystem::path& gltfFileName, const YAML::Node& expectedResults) { + + // --- Load Gltf --- + std::ifstream gltfStream(gltfFileName, std::ifstream::binary); + gltfStream.seekg(0, std::ios::end); + auto gltfFileLength = gltfStream.tellg(); + gltfStream.seekg(0, std::ios::beg); + + std::vector gltfBuf(gltfFileLength); + gltfStream.read((char*)&gltfBuf[0], gltfFileLength); + + CesiumGltfReader::GltfReader reader; + auto gltf = reader.readGltf(gsl::span(reinterpret_cast(gltfBuf.data()), gltfFileLength)); + + if (!gltf.errors.empty()) { + for (const auto& err : gltf.errors) { + std::cerr << err; + } + throw std::runtime_error("failed to parse model"); + } + + // gltf.model is a std::optional, make sure it exists + if (!(gltf.model && gltf.model->meshes.size() > 0)) { + throw std::runtime_error("test model is empty"); + } + + // --- Begin checks --- + const auto& prim = gltf.model->meshes[0].primitives[0]; + const auto& model = *gltf.model; + + CHECK(GltfUtil::hasNormals(model, prim, false) == expectedResults["hasNormals"].as()); + CHECK(GltfUtil::hasTexcoords(model, prim, 0) == expectedResults["hasTexcoords"].as()); + CHECK(GltfUtil::hasImageryTexcoords(model, prim, 0) == expectedResults["hasImageryTexcoords"].as()); + CHECK(GltfUtil::hasVertexColors(model, prim, 0) == expectedResults["hasVertexColors"].as()); + CHECK(GltfUtil::hasMaterial(prim) == expectedResults["hasMaterial"].as()); + CHECK(GltfUtil::getDoubleSided(model, prim) == expectedResults["doubleSided"].as()); + + // material tests + if (GltfUtil::hasMaterial(prim)) { + const auto& mat = gltf.model->materials[0]; + CHECK(GltfUtil::getAlphaMode(mat) == expectedResults["alphaMode"].as()); + CHECK(GltfUtil::getAlphaCutoff(mat) == expectedResults["alphaCutoff"].as()); + CHECK(GltfUtil::getBaseAlpha(mat) == expectedResults["baseAlpha"].as()); + CHECK(GltfUtil::getMetallicFactor(mat) == expectedResults["metallicFactor"].as()); + CHECK(GltfUtil::getRoughnessFactor(mat) == expectedResults["roughnessFactor"].as()); + CHECK(GltfUtil::getBaseColorTextureWrapS(model, mat) == expectedResults["baseColorTextureWrapS"].as()); + CHECK(GltfUtil::getBaseColorTextureWrapT(model, mat) == expectedResults["baseColorTextureWrapT"].as()); + + CHECK(GltfUtil::getBaseColorFactor(mat) == expectedResults["baseColorFactor"].as>()); + CHECK(GltfUtil::getEmissiveFactor(mat) == expectedResults["emissiveFactor"].as>()); + } + + // Accessor smoke tests + PositionsAccessor positions; + IndicesAccessor indices; + positions = GltfUtil::getPositions(model, prim); + CHECK(positions.size() > 0); + indices = GltfUtil::getIndices(model, prim, positions); + CHECK(indices.size() > 0); + if (GltfUtil::hasNormals(model, prim, false)) { + CHECK(GltfUtil::getNormals(model, prim, positions, indices, false).size() > 0); + } + if (GltfUtil::hasVertexColors(model, prim, 0)) { + CHECK(GltfUtil::getVertexColors(model, prim, 0).size() > 0); + } + if (GltfUtil::hasTexcoords(model, prim, 0)) { + CHECK(GltfUtil::getTexcoords(model, prim, 0).size() > 0); + } + if (GltfUtil::hasImageryTexcoords(model, prim, 0)) { + CHECK(GltfUtil::getImageryTexcoords(model, prim, 0).size() > 0); + } + CHECK(GltfUtil::getExtent(model, prim) != std::nullopt); + } + + TEST_CASE("Default getter smoke tests") { + + CHECK_NOTHROW(GltfUtil::getDefaultBaseAlpha()); + CHECK_NOTHROW(GltfUtil::getDefaultBaseColorFactor()); + CHECK_NOTHROW(GltfUtil::getDefaultMetallicFactor()); + CHECK_NOTHROW(GltfUtil::getDefaultRoughnessFactor()); + CHECK_NOTHROW(GltfUtil::getDefaultEmissiveFactor()); + CHECK_NOTHROW(GltfUtil::getDefaultWrapS()); + CHECK_NOTHROW(GltfUtil::getDefaultWrapT()); + CHECK_NOTHROW(GltfUtil::getDefaultAlphaCutoff()); + CHECK_NOTHROW(GltfUtil::getDefaultAlphaMode()); + } + + TEST_CASE("Check helper functions on various models") { + + std::vector gltfFiles; + + // get list of gltf test files + for (auto const& i : std::filesystem::directory_iterator(ASSET_DIR)) { + std::filesystem::path fname = i.path().filename(); + if (fname.extension() == ".gltf" || fname.extension() == ".glb") { + gltfFiles.push_back(fname.string()); + } + } + + // parse test config yaml + const auto configRoot = YAML::LoadFile(CONFIG_PATH); + const auto basePath = std::filesystem::path(ASSET_DIR); + + for (auto const& fileName : gltfFiles) { + // attach filename to any failed checks + CAPTURE(fileName); + + const auto conf = getScenarioConfig(fileName, configRoot); + + // the / operator concatonates file paths + checkGltfExpectedResults(basePath / fileName, conf); + } + } +} diff --git a/tests/ObjectPoolTests.cpp b/tests/ObjectPoolTests.cpp index 76f23b400..4ee6f27ae 100644 --- a/tests/ObjectPoolTests.cpp +++ b/tests/ObjectPoolTests.cpp @@ -1,8 +1,7 @@ -#include "doctestUtils.h" +#include "testUtils.h" #include #include -#include #include #include diff --git a/tests/configs/exampleConfig.yaml b/tests/configs/exampleConfig.yaml new file mode 100644 index 000000000..7ea5e2ae5 --- /dev/null +++ b/tests/configs/exampleConfig.yaml @@ -0,0 +1,29 @@ +--- + + +# One way to use the config file is to generate multiple scenarios with +# variations on some known parameters. If most of the scenarios have a +# parameter at one particular value, it can make sense to establish that as +# the default, then we only need to list the changes from that default. +# See the gltf test config for a real use-case +scenarios: + default: + # currently supported data types for the testUtils methods: + # float + pi : 3.14159 + # int + onlyEvenPrime : 2 + # string + transmogrifierOutput : "foo" + # sequence + fibonacciSeq : + - 1 + - 1 + - 2 + - 3 + - 5 + + + # an example override for a given item + scenario2: + transmogrifierOutput : "bar" diff --git a/tests/configs/gltfConfig.yaml b/tests/configs/gltfConfig.yaml new file mode 100644 index 000000000..ac657e04b --- /dev/null +++ b/tests/configs/gltfConfig.yaml @@ -0,0 +1,119 @@ +--- +# + +scenarios: + default: + hasNormals : True + hasTexcoords : True + hasImageryTexcoords : False + hasVertexColors : False + doubleSided : False + # Material Attributes + hasMaterial : True + alphaMode : 0 + alphaCutoff : 0.5 + baseAlpha : 1.0 + metallicFactor : 1.0 + roughnessFactor : 1.0 + baseColorTextureWrapS : 10497 # opengl enum for "repeat" + baseColorTextureWrapT : 10497 + emissiveFactor: + - 0 + - 0 + - 0 + baseColorFactor: + - 1 + - 1 + - 1 + + # Note: all files should all be .glbs. Anything that uses or queries + # accessors requires (included in some tests) requires a call to + # CesiumGltfReader::resolveExternalData, which proved to be complicated to integrate. + Duck.glb: + hasTexcoords : True + metallicFactor : 0 + + Mesh_Primitives_00.glb: + hasNormals : False + hasTexcoords : False + baseColorFactor: + - 0 + - 1 + - 0 + + Mesh_PrimitivesUV_00.glb: + hasNormals : False + hasTexcoords : False + + Mesh_PrimitivesUV_06.glb: + hasVertexColors : True + + Mesh_PrimitivesUV_08.glb: + hasVertexColors : True + + Material_07.glb: + metallicFactor : 0.0 + emissiveFactor : + - 1 + - 1 + - 1 + baseColorFactor : + - 0.2 + - 0.2 + - 0.2 + + Material_AlphaBlend_05.glb: + hasNormals : False + hasTexcoords : True + alphaMode : 2 + baseAlpha : 0.7 + + Material_AlphaBlend_06.glb: + hasNormals : False + hasVertexColors : True + hasTexcoords : True + alphaMode : 2 + baseAlpha : 0.7 + + Material_AlphaMask_04.glb: + hasNormals : False + hasTexcoords : True + alphaMode : 1 + alphaCutoff : 0.0 + + Material_AlphaMask_06.glb: + hasNormals : False + hasTexcoords : True + alphaMode : 1 + alphaCutoff : 0.6 + baseAlpha : 0.7 + + Mesh_PrimitiveVertexColor_00.glb: + hasMaterial : False + hasTexcoords : False + hasVertexColors : True + + Mesh_PrimitiveVertexColor_01.glb: + hasMaterial : False + hasTexcoords : False + hasVertexColors : True + + Mesh_PrimitiveVertexColor_02.glb: + hasMaterial : False + hasTexcoords : False + hasVertexColors : True + + Mesh_PrimitiveVertexColor_03.glb: + hasMaterial : False + hasTexcoords : False + hasVertexColors : True + + Mesh_PrimitiveVertexColor_04.glb: + hasMaterial : False + hasTexcoords : False + hasVertexColors : True + + Mesh_PrimitiveVertexColor_05.glb: + hasMaterial : False + hasTexcoords : False + hasVertexColors : True diff --git a/tests/doctestMain.cpp b/tests/doctestMain.cpp index 59a528060..c0fb55723 100644 --- a/tests/doctestMain.cpp +++ b/tests/doctestMain.cpp @@ -1,9 +1,34 @@ #define DOCTEST_CONFIG_SUPER_FAST_ASSERTS #define DOCTEST_CONFIG_NO_EXCEPTIONS +#define DOCTEST_CONFIG_IMPLEMENT -// Defining this magic variable and importing doctest are all that's required -// Doctest will automatically find all the TEST_CASEs linked/defined elsewhere -// and include them in a main function it builds -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "testUtils.h" #include + +#include + +int main(int argc, char** argv) { + doctest::Context context; + + context.applyCommandLine(argc, argv); + + // Some tests contain relative paths rooted in the top level project dir + // so we set this as the working directory + std::filesystem::path oldWorkingDir = std::filesystem::current_path(); + std::filesystem::current_path(TEST_WORKING_DIRECTORY); + + int res = context.run(); // run + + // restore the previous working directory + std::filesystem::current_path(oldWorkingDir); + + if (context.shouldExit()) { // important - query flags (and --exit) rely on the user doing this + return res; // propagate the result of the tests + } + + int client_stuff_return_code = 0; + // your program - if the testing framework is integrated in your production code + + return res + client_stuff_return_code; // the result from doctest is propagated here as well +} diff --git a/tests/doctestUtils.cpp b/tests/doctestUtils.cpp deleted file mode 100644 index 1d99e8ba1..000000000 --- a/tests/doctestUtils.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "doctestUtils.h" - -void fillWithRandomInts(std::list& lst, int min, int max, int n) { - - for (int i = 0; i < n; i++) { - // The odd order here is to avoid issues with rollover - int x = (rand() % (max - min)) + min; - lst.push_back(x); - } -} diff --git a/tests/testAssets/gltfs/Duck.glb b/tests/testAssets/gltfs/Duck.glb new file mode 100644 index 000000000..217170d2b Binary files /dev/null and b/tests/testAssets/gltfs/Duck.glb differ diff --git a/tests/testAssets/gltfs/Material_07.glb b/tests/testAssets/gltfs/Material_07.glb new file mode 100644 index 000000000..a16be9e86 Binary files /dev/null and b/tests/testAssets/gltfs/Material_07.glb differ diff --git a/tests/testAssets/gltfs/Material_AlphaBlend_05.glb b/tests/testAssets/gltfs/Material_AlphaBlend_05.glb new file mode 100644 index 000000000..ff78181b7 Binary files /dev/null and b/tests/testAssets/gltfs/Material_AlphaBlend_05.glb differ diff --git a/tests/testAssets/gltfs/Material_AlphaBlend_06.glb b/tests/testAssets/gltfs/Material_AlphaBlend_06.glb new file mode 100644 index 000000000..e74d54036 Binary files /dev/null and b/tests/testAssets/gltfs/Material_AlphaBlend_06.glb differ diff --git a/tests/testAssets/gltfs/Material_AlphaMask_04.glb b/tests/testAssets/gltfs/Material_AlphaMask_04.glb new file mode 100644 index 000000000..2c7c72273 Binary files /dev/null and b/tests/testAssets/gltfs/Material_AlphaMask_04.glb differ diff --git a/tests/testAssets/gltfs/Material_AlphaMask_06.glb b/tests/testAssets/gltfs/Material_AlphaMask_06.glb new file mode 100644 index 000000000..f77eac450 Binary files /dev/null and b/tests/testAssets/gltfs/Material_AlphaMask_06.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_00.glb b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_00.glb new file mode 100644 index 000000000..b7f6406be Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_00.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_01.glb b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_01.glb new file mode 100644 index 000000000..49875c8f5 Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_01.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_02.glb b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_02.glb new file mode 100644 index 000000000..629fee3a3 Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_02.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_03.glb b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_03.glb new file mode 100644 index 000000000..7b36bf2f5 Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_03.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_04.glb b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_04.glb new file mode 100644 index 000000000..416c280da Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_04.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_05.glb b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_05.glb new file mode 100644 index 000000000..456d9cd25 Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitiveVertexColor_05.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitivesUV_00.glb b/tests/testAssets/gltfs/Mesh_PrimitivesUV_00.glb new file mode 100644 index 000000000..3f7373818 Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitivesUV_00.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitivesUV_06.glb b/tests/testAssets/gltfs/Mesh_PrimitivesUV_06.glb new file mode 100644 index 000000000..cd4b7f421 Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitivesUV_06.glb differ diff --git a/tests/testAssets/gltfs/Mesh_PrimitivesUV_08.glb b/tests/testAssets/gltfs/Mesh_PrimitivesUV_08.glb new file mode 100644 index 000000000..82541c127 Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_PrimitivesUV_08.glb differ diff --git a/tests/testAssets/gltfs/Mesh_Primitives_00.glb b/tests/testAssets/gltfs/Mesh_Primitives_00.glb new file mode 100644 index 000000000..2da6d04bc Binary files /dev/null and b/tests/testAssets/gltfs/Mesh_Primitives_00.glb differ diff --git a/tests/testUtils.cpp b/tests/testUtils.cpp new file mode 100644 index 000000000..cb7d386be --- /dev/null +++ b/tests/testUtils.cpp @@ -0,0 +1,37 @@ +#include "testUtils.h" + +#include +#include + +#include +#include +#include +#include +#include + +void fillWithRandomInts(std::list& lst, int min, int max, int n) { + + for (int i = 0; i < n; i++) { + // The odd order here is to avoid issues with rollover + int x = (rand() % (max - min)) + min; + lst.push_back(x); + } +} + +ConfigMap getScenarioConfig(const std::string& scenario, YAML::Node configRoot) { + ConfigMap sConfig = ConfigMap(); + + const auto& defaultConfig = configRoot["scenarios"]["default"]; + + for (YAML::const_iterator it = defaultConfig.begin(); it != defaultConfig.end(); it++) { + sConfig[it->first.as()] = it->second; + } + + const auto& overrides = configRoot["scenarios"][scenario]; + + for (auto it = overrides.begin(); it != overrides.end(); it++) { + sConfig[it->first.as()] = it->second; + } + + return sConfig; +} diff --git a/tests/doctestUtils.h b/tests/testUtils.h.in similarity index 66% rename from tests/doctestUtils.h rename to tests/testUtils.h.in index f55423ef8..474e6a315 100644 --- a/tests/doctestUtils.h +++ b/tests/testUtils.h.in @@ -1,11 +1,23 @@ #pragma once +// ************************************ +// ***** Before editing this file ***** +// ************************************ +// be sure you are editing testUtils.h.in and not directly editing testUtils.h +// cmake generates testUtils.h at build time by processing testUtils.h.in +// in order to perform some string replacement + #include #include #include #include +#include + #define NUM_TEST_REPETITIONS 100 +// Some tests contain relative paths rooted in the top level project dir +// cmake fills in this information via string replacement +#define TEST_WORKING_DIRECTORY "@TEST_WORKING_DIRECTORY@" // Macro for parameterizing test data using one currently recommended method. // See the doctest docs for more info: @@ -21,3 +33,6 @@ _doctest_subcase_idx = 0 void fillWithRandomInts(std::list& lst, int min, int max, int n); + +using ConfigMap = YAML::Node; +ConfigMap getScenarioConfig(const std::string& scenario, YAML::Node configRoot);