xo-testutil: unit test support library
This commit is contained in:
parent
338a9f685e
commit
198a7a9060
15 changed files with 404 additions and 0 deletions
|
|
@ -87,6 +87,7 @@ add_subdirectory(xo-facet) # sep iface,data
|
||||||
add_subdirectory(xo-allocutil)
|
add_subdirectory(xo-allocutil)
|
||||||
add_subdirectory(xo-refcnt)
|
add_subdirectory(xo-refcnt)
|
||||||
add_subdirectory(xo-subsys)
|
add_subdirectory(xo-subsys)
|
||||||
|
add_subdirectory(xo-testutil) # unit test aux functions
|
||||||
add_subdirectory(xo-flatstring)
|
add_subdirectory(xo-flatstring)
|
||||||
add_subdirectory(xo-pyutil)
|
add_subdirectory(xo-pyutil)
|
||||||
add_subdirectory(xo-reflect)
|
add_subdirectory(xo-reflect)
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,7 @@ using `xo-build`.
|
||||||
Finally, can also individual XO packages:
|
Finally, can also individual XO packages:
|
||||||
```
|
```
|
||||||
$ nix-build -A xo.cmake
|
$ nix-build -A xo.cmake
|
||||||
|
$ nix-build -A xo.indentlog
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@ let
|
||||||
xo-allocutil = self.callPackage pkgs/xo-allocutil.nix { stdenv = jitStdenv; };
|
xo-allocutil = self.callPackage pkgs/xo-allocutil.nix { stdenv = jitStdenv; };
|
||||||
xo-refcnt = self.callPackage pkgs/xo-refcnt.nix { stdenv = jitStdenv; };
|
xo-refcnt = self.callPackage pkgs/xo-refcnt.nix { stdenv = jitStdenv; };
|
||||||
xo-subsys = self.callPackage pkgs/xo-subsys.nix { stdenv = jitStdenv; };
|
xo-subsys = self.callPackage pkgs/xo-subsys.nix { stdenv = jitStdenv; };
|
||||||
|
xo-testutil = self.callPackage pkgs/xo-testutil.nix { stdenv = jitStdenv; };
|
||||||
xo-flatstring = self.callPackage pkgs/xo-flatstring.nix { stdenv = jitStdenv; buildDocs = true; buildExamples = true; };
|
xo-flatstring = self.callPackage pkgs/xo-flatstring.nix { stdenv = jitStdenv; buildDocs = true; buildExamples = true; };
|
||||||
xo-pyutil = self.callPackage pkgs/xo-pyutil.nix { stdenv = jitStdenv; };
|
xo-pyutil = self.callPackage pkgs/xo-pyutil.nix { stdenv = jitStdenv; };
|
||||||
xo-reflect = self.callPackage pkgs/xo-reflect.nix { stdenv = jitStdenv; };
|
xo-reflect = self.callPackage pkgs/xo-reflect.nix { stdenv = jitStdenv; };
|
||||||
|
|
@ -526,6 +527,7 @@ in
|
||||||
allocutil = pkgs.xo-allocutil;
|
allocutil = pkgs.xo-allocutil;
|
||||||
refcnt = pkgs.xo-refcnt;
|
refcnt = pkgs.xo-refcnt;
|
||||||
subsys = pkgs.xo-subsys;
|
subsys = pkgs.xo-subsys;
|
||||||
|
testutil = pkgs.xo-testutil;
|
||||||
flatstring = pkgs.xo-flatstring;
|
flatstring = pkgs.xo-flatstring;
|
||||||
pyutil = pkgs.xo-pyutil;
|
pyutil = pkgs.xo-pyutil;
|
||||||
reflect = pkgs.xo-reflect;
|
reflect = pkgs.xo-reflect;
|
||||||
|
|
|
||||||
55
pkgs/xo-testutil.nix
Normal file
55
pkgs/xo-testutil.nix
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
# nixpkgs dependencies
|
||||||
|
lib, stdenv, cmake, catch2,
|
||||||
|
doxygen, cli11,
|
||||||
|
|
||||||
|
python3Packages,
|
||||||
|
|
||||||
|
sphinx, graphviz,
|
||||||
|
|
||||||
|
# xo dependencies
|
||||||
|
xo-subsys,
|
||||||
|
xo-indentlog,
|
||||||
|
xo-cmake,
|
||||||
|
|
||||||
|
buildDocs ? false,
|
||||||
|
doCheck ? true,
|
||||||
|
} :
|
||||||
|
|
||||||
|
stdenv.mkDerivation (finalattrs:
|
||||||
|
{
|
||||||
|
name = "xo-testutil";
|
||||||
|
|
||||||
|
src = ../xo-testutil;
|
||||||
|
|
||||||
|
cmakeFlags = ["-DCMAKE_MODULE_PATH=${xo-cmake}/share/cmake"]
|
||||||
|
++ lib.optionals buildDocs ["-DXO_ENABLE_DOCS=on"]
|
||||||
|
++ lib.optionals doCheck ["-DENABLE_TESTING=1"];
|
||||||
|
|
||||||
|
inherit buildDocs;
|
||||||
|
inherit doCheck;
|
||||||
|
|
||||||
|
postBuild = lib.optionalString buildDocs ''
|
||||||
|
cmake --build . -- docs
|
||||||
|
'';
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
cmake
|
||||||
|
catch2
|
||||||
|
cli11
|
||||||
|
xo-cmake
|
||||||
|
] ++ lib.optionals buildDocs [
|
||||||
|
doxygen
|
||||||
|
sphinx
|
||||||
|
graphviz
|
||||||
|
python3Packages.sphinx-rtd-theme
|
||||||
|
python3Packages.breathe
|
||||||
|
python3Packages.sphinxcontrib-ditaa
|
||||||
|
python3Packages.sphinxcontrib-plantuml
|
||||||
|
python3Packages.pillow
|
||||||
|
];
|
||||||
|
propagatedBuildInputs = [
|
||||||
|
xo-subsys
|
||||||
|
xo-indentlog
|
||||||
|
];
|
||||||
|
})
|
||||||
30
xo-testutil/CMakeLists.txt
Normal file
30
xo-testutil/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# xo-testutil/CMakeLists.txt
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(xo_testutil VERSION 1.0)
|
||||||
|
enable_language(CXX)
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(cmake/xo-bootstrap-macros.cmake)
|
||||||
|
|
||||||
|
xo_cxx_toplevel_options3()
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# c++ settings
|
||||||
|
|
||||||
|
# one-time project-specific c++ flags. usually empty
|
||||||
|
set(PROJECT_CXX_FLAGS "")
|
||||||
|
add_definitions(${PROJECT_CXX_FLAGS})
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# output targets
|
||||||
|
|
||||||
|
add_subdirectory(src/testutil)
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# cmake export
|
||||||
|
|
||||||
|
xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets)
|
||||||
|
|
||||||
|
# end CMakeLists.txt
|
||||||
33
xo-testutil/cmake/xo-bootstrap-macros.cmake
Normal file
33
xo-testutil/cmake/xo-bootstrap-macros.cmake
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# for example:
|
||||||
|
# $ PREFIX=/usr/local # for example
|
||||||
|
# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build
|
||||||
|
#
|
||||||
|
# will get
|
||||||
|
# CMAKE_MODULE_PATH
|
||||||
|
# from xo-cmake-config --cmake-module-path
|
||||||
|
#
|
||||||
|
# and expect .cmake macros in
|
||||||
|
# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
|
||||||
|
find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED)
|
||||||
|
|
||||||
|
if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix"))
|
||||||
|
message(FATAL "could not find xo-cmake-config executable")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT XO_SUBMODULE_BUILD)
|
||||||
|
if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix))
|
||||||
|
# default to typical install location for xo-project-macros
|
||||||
|
execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH)
|
||||||
|
message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# needs to have been installed somewhere on CMAKE_MODULE_PATH,
|
||||||
|
# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX)
|
||||||
|
#
|
||||||
|
include(xo_macros/xo_cxx)
|
||||||
|
|
||||||
|
xo_cxx_bootstrap_message()
|
||||||
14
xo-testutil/cmake/xo_testutilConfig.cmake.in
Normal file
14
xo-testutil/cmake/xo_testutilConfig.cmake.in
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include(CMakeFindDependencyMacro)
|
||||||
|
|
||||||
|
# note: changes to find_dependency() calls here
|
||||||
|
# must coordinate with xo_dependency() calls
|
||||||
|
# in CMakeLists.txt
|
||||||
|
#
|
||||||
|
find_dependency(subsys)
|
||||||
|
find_dependency(indentlog)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake")
|
||||||
|
check_required_components("@PROJECT_NAME@")
|
||||||
35
xo-testutil/include/xo/testutil/Utest.hpp
Normal file
35
xo-testutil/include/xo/testutil/Utest.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/** @file Utest.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, May 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xo/indentlog/scope.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
|
||||||
|
/** RAII logging for catch2 unit tests
|
||||||
|
*
|
||||||
|
* Use:
|
||||||
|
* TEST_CASE(name, tags, ..)
|
||||||
|
* {
|
||||||
|
* scope log = Utest::ut_scope();
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
* log && log(xtag("foo", ...));
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Honors:
|
||||||
|
* UtestConfig::instance()->debug_flag_
|
||||||
|
**/
|
||||||
|
struct Utest {
|
||||||
|
/** Toplevel logging scope for unit tests.
|
||||||
|
* Integrates with UtestConfig
|
||||||
|
**/
|
||||||
|
static scope ut_scope();
|
||||||
|
};
|
||||||
|
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end Utest.hpp */
|
||||||
30
xo-testutil/include/xo/testutil/UtestAppStart.hpp
Normal file
30
xo-testutil/include/xo/testutil/UtestAppStart.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
/** @file UtestAppStart.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, May 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
|
||||||
|
/** @brief Startup sequence for a unit test
|
||||||
|
*
|
||||||
|
* Standard unit test startup sequence
|
||||||
|
**/
|
||||||
|
class UtestAppStart {
|
||||||
|
public:
|
||||||
|
explicit UtestAppStart(const char * app_name) : app_name_{app_name} {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse program arguments; recognize XO test arguments,
|
||||||
|
* sending remainder to catch2; do subsystem initialization
|
||||||
|
**/
|
||||||
|
int run(int argc, char * argv[]);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char * app_name_ = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end UtestAppStart.hpp */
|
||||||
25
xo-testutil/include/xo/testutil/UtestConfig.hpp
Normal file
25
xo-testutil/include/xo/testutil/UtestConfig.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
/** @file UtestConfig.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, May 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
|
||||||
|
/** unit-test configuration here
|
||||||
|
*
|
||||||
|
* TODO: promote to its own library, along with UtestListener
|
||||||
|
**/
|
||||||
|
struct UtestConfig {
|
||||||
|
bool debug_flag() const { return debug_flag_; }
|
||||||
|
|
||||||
|
/** announce each test using catch2's listener api **/
|
||||||
|
bool announce_flag_ = false;
|
||||||
|
/** enable debug output for all (!) tests **/
|
||||||
|
bool debug_flag_ = false;
|
||||||
|
|
||||||
|
static UtestConfig * instance();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end UtestConfig.hpp */
|
||||||
52
xo-testutil/include/xo/testutil/UtestListener.hpp
Normal file
52
xo-testutil/include/xo/testutil/UtestListener.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
/** @file UtestListener.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, May 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "UtestConfig.hpp"
|
||||||
|
|
||||||
|
// caller must define CATCH_CONFIG_RUNNER
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
|
||||||
|
/** @brief listener for catch2 unit tests.
|
||||||
|
* catch2 invokes this at the beginning of each unit test
|
||||||
|
*
|
||||||
|
* Enable with:
|
||||||
|
* @begin_code
|
||||||
|
* #include <catch2/catch.hpp>
|
||||||
|
* CATCH_REGISTER_LISTENER(UtestListener);
|
||||||
|
* @end_code
|
||||||
|
**/
|
||||||
|
struct UtestListener : Catch::TestEventListenerBase {
|
||||||
|
using TestEventListenerBase::TestEventListenerBase;
|
||||||
|
|
||||||
|
// TestCasweInfo members: .name, .className, .description, .tags, lineInfo {.file, .line}
|
||||||
|
virtual void testCaseStarting(const Catch::TestCaseInfo & info) override {
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
|
// preamble
|
||||||
|
|
||||||
|
if (UtestConfig::instance()->announce_flag_) {
|
||||||
|
cerr << "Starting unit test: "
|
||||||
|
<< "[" << info.name << "]"
|
||||||
|
<< " at "
|
||||||
|
<< "[" << info.lineInfo.file << ":" << info.lineInfo.line << "]"
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void testCaseEnded(const Catch::TestCaseStats & stats) override {
|
||||||
|
// postamble
|
||||||
|
}
|
||||||
|
|
||||||
|
// also sectionStarting / sectionEnded
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end UtestListener.hpp */
|
||||||
15
xo-testutil/src/testutil/CMakeLists.txt
Normal file
15
xo-testutil/src/testutil/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# testutil/CMakeLists.txt
|
||||||
|
|
||||||
|
set(SELF_LIB xo_testutil)
|
||||||
|
set(SELF_SRCS
|
||||||
|
UtestAppStart.cpp
|
||||||
|
UtestConfig.cpp
|
||||||
|
Utest.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||||
|
xo_install_include_tree3(include/xo/testutil)
|
||||||
|
# note: deps here must also appear in cmake/xo_testutilConfig.cmake.in
|
||||||
|
xo_dependency(${SELF_LIB} subsys)
|
||||||
|
xo_dependency(${SELF_LIB} indentlog)
|
||||||
|
xo_external_target_dependency(${SELF_LIB} Catch2 Catch2::Catch2)
|
||||||
18
xo-testutil/src/testutil/Utest.cpp
Normal file
18
xo-testutil/src/testutil/Utest.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
/** @file Utest.cpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, May 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "Utest.hpp"
|
||||||
|
#include "UtestConfig.hpp"
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
scope
|
||||||
|
Utest::ut_scope() {
|
||||||
|
return scope(XO_DEBUG(UtestConfig::instance()->debug_flag()),
|
||||||
|
xtag("name", Catch::getResultCapture().getCurrentTestName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end Utest.cpp */
|
||||||
75
xo-testutil/src/testutil/UtestAppStart.cpp
Normal file
75
xo-testutil/src/testutil/UtestAppStart.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
/** @file UtestAppStart.cpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, May 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "UtestAppStart.hpp"
|
||||||
|
#include "UtestConfig.hpp"
|
||||||
|
#include <xo/subsys/Subsystem.hpp>
|
||||||
|
#include <xo/indentlog/scope.hpp>
|
||||||
|
#include <CLI/CLI.hpp>
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_RUNNER
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::UtestConfig;
|
||||||
|
using xo::scope;
|
||||||
|
using xo::xtag;
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
|
int
|
||||||
|
UtestAppStart::run(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
CLI::App app{app_name_};
|
||||||
|
|
||||||
|
app.set_help_flag(); // disable default help impl, see below
|
||||||
|
{
|
||||||
|
app.add_flag("--debug",
|
||||||
|
UtestConfig::instance()->debug_flag_,
|
||||||
|
"enable debug logging (for all tests)");
|
||||||
|
|
||||||
|
app.add_flag("--announce",
|
||||||
|
UtestConfig::instance()->announce_flag_,
|
||||||
|
"announce each test via UtestListener");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool help_flag = false;
|
||||||
|
{
|
||||||
|
app.add_flag("--help,-h,-?", help_flag, "print this help message and exit");
|
||||||
|
}
|
||||||
|
|
||||||
|
app.allow_extras();
|
||||||
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
|
||||||
|
std::vector<const char *> argv2 = {argv[0]};
|
||||||
|
|
||||||
|
if (help_flag) {
|
||||||
|
// actual help impl, falls through to Session below
|
||||||
|
|
||||||
|
cout << app_name_ << " options" << endl;
|
||||||
|
cout << app.help() << endl;
|
||||||
|
cout << "catch2 options" << endl;
|
||||||
|
|
||||||
|
argv2.push_back("--help");
|
||||||
|
} else {
|
||||||
|
// keep program name
|
||||||
|
for (auto & x : app.remaining())
|
||||||
|
argv2.push_back(x.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
using xo::Subsystem;
|
||||||
|
Subsystem::initialize_all();
|
||||||
|
|
||||||
|
scope log(XO_DEBUG(UtestConfig::instance()->debug_flag()),
|
||||||
|
"start catch2 session");
|
||||||
|
|
||||||
|
// run catch2's test session / help
|
||||||
|
return Catch::Session().run(argv2.size(), argv2.data());
|
||||||
|
}
|
||||||
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
/* end UtestAppStart.cpp */
|
||||||
18
xo-testutil/src/testutil/UtestConfig.cpp
Normal file
18
xo-testutil/src/testutil/UtestConfig.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
/** @file UtestConfig.cpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, May 2026
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "UtestConfig.hpp"
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
UtestConfig *
|
||||||
|
UtestConfig::instance() {
|
||||||
|
static UtestConfig s_instance;
|
||||||
|
|
||||||
|
return &s_instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end UtestConfig.cpp */
|
||||||
Loading…
Add table
Add a link
Reference in a new issue