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-refcnt)
|
||||
add_subdirectory(xo-subsys)
|
||||
add_subdirectory(xo-testutil) # unit test aux functions
|
||||
add_subdirectory(xo-flatstring)
|
||||
add_subdirectory(xo-pyutil)
|
||||
add_subdirectory(xo-reflect)
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ using `xo-build`.
|
|||
Finally, can also individual XO packages:
|
||||
```
|
||||
$ 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-refcnt = self.callPackage pkgs/xo-refcnt.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-pyutil = self.callPackage pkgs/xo-pyutil.nix { stdenv = jitStdenv; };
|
||||
xo-reflect = self.callPackage pkgs/xo-reflect.nix { stdenv = jitStdenv; };
|
||||
|
|
@ -526,6 +527,7 @@ in
|
|||
allocutil = pkgs.xo-allocutil;
|
||||
refcnt = pkgs.xo-refcnt;
|
||||
subsys = pkgs.xo-subsys;
|
||||
testutil = pkgs.xo-testutil;
|
||||
flatstring = pkgs.xo-flatstring;
|
||||
pyutil = pkgs.xo-pyutil;
|
||||
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