mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 13:26:10 +01:00
Add default reporter for Bazel integration (#2399)
When the added Bazel configuration flag is enabled, a default JUnit reporter will be added if the XML envrioment variable is defined. Fix include paths for generated config header. Enable Bazel config by default when building with Bazel. Co-authored-by: Martin Hořeňovský <martin.horenovsky@gmail.com>
This commit is contained in:
parent
4b78157981
commit
cb551b4f6d
4
.bazelrc
Normal file
4
.bazelrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
build:gcc9 --cxxopt=-std=c++2a
|
||||||
|
build:clang13 --cxxopt=-std=c++17
|
||||||
|
build:vs2019 --cxxopt=/std:c++17
|
||||||
|
build:vs2022 --cxxopt=/std:c++17
|
36
BUILD.bazel
36
BUILD.bazel
@ -1,13 +1,14 @@
|
|||||||
# Load the cc_library rule.
|
# Load the cc_library rule.
|
||||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||||
|
|
||||||
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
|
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
|
||||||
|
|
||||||
expand_template(
|
expand_template(
|
||||||
name = "catch_user_config.hpp",
|
name = "catch_user_config",
|
||||||
out = "catch2/catch_user_config.hpp",
|
out = "catch2/catch_user_config.hpp",
|
||||||
substitutions = {
|
substitutions = {
|
||||||
"#cmakedefine CATCH_CONFIG_ANDROID_LOGWRITE": "",
|
"#cmakedefine CATCH_CONFIG_ANDROID_LOGWRITE": "",
|
||||||
|
"#cmakedefine CATCH_CONFIG_BAZEL_SUPPORT": "#define CATCH_CONFIG_BAZEL_SUPPORT",
|
||||||
|
"#cmakedefine CATCH_CONFIG_NO_COLOUR_WIN32": "",
|
||||||
"#cmakedefine CATCH_CONFIG_COLOUR_WIN32": "",
|
"#cmakedefine CATCH_CONFIG_COLOUR_WIN32": "",
|
||||||
"#cmakedefine CATCH_CONFIG_COUNTER": "",
|
"#cmakedefine CATCH_CONFIG_COUNTER": "",
|
||||||
"#cmakedefine CATCH_CONFIG_CPP11_TO_STRING": "",
|
"#cmakedefine CATCH_CONFIG_CPP11_TO_STRING": "",
|
||||||
@ -55,23 +56,36 @@ expand_template(
|
|||||||
template = "src/catch2/catch_user_config.hpp.in",
|
template = "src/catch2/catch_user_config.hpp.in",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Generated header library, modifies the include prefix to account for
|
||||||
|
# generation path so that we can include <catch2/catch_user_config.hpp>
|
||||||
|
# correctly.
|
||||||
|
cc_library(
|
||||||
|
name = "catch2_generated",
|
||||||
|
hdrs = ["catch2/catch_user_config.hpp"],
|
||||||
|
include_prefix = ".", # to manipulate -I of dependenices
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
|
||||||
# Static library, without main.
|
# Static library, without main.
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "catch2",
|
name = "catch2",
|
||||||
hdrs = glob(["src/catch2/**/*.hpp"]) + ["catch_user_config.hpp"],
|
srcs = glob(
|
||||||
srcs = glob(["src/catch2/**/*.cpp"],
|
["src/catch2/**/*.cpp"],
|
||||||
exclude=[ "src/catch2/internal/catch_main.cpp"]),
|
exclude = ["src/catch2/internal/catch_main.cpp"],
|
||||||
visibility = ["//visibility:public"],
|
),
|
||||||
linkstatic = True,
|
hdrs = glob(["src/catch2/**/*.hpp"]),
|
||||||
includes = ["src/"],
|
includes = ["src/"],
|
||||||
|
linkstatic = True,
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [":catch2_generated"],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Static library, with main.
|
# Static library, with main.
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "catch2_main",
|
name = "catch2_main",
|
||||||
srcs = ["src/catch2/internal/catch_main.cpp"],
|
srcs = ["src/catch2/internal/catch_main.cpp"],
|
||||||
deps = [":catch2"],
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
linkstatic = True,
|
|
||||||
includes = ["src/"],
|
includes = ["src/"],
|
||||||
)
|
linkstatic = True,
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [":catch2"],
|
||||||
|
)
|
@ -26,6 +26,7 @@ endmacro()
|
|||||||
|
|
||||||
set(_OverridableOptions
|
set(_OverridableOptions
|
||||||
"ANDROID_LOGWRITE"
|
"ANDROID_LOGWRITE"
|
||||||
|
"BAZEL_SUPPORT"
|
||||||
"COLOUR_WIN32"
|
"COLOUR_WIN32"
|
||||||
"COUNTER"
|
"COUNTER"
|
||||||
"CPP11_TO_STRING"
|
"CPP11_TO_STRING"
|
||||||
|
11
WORKSPACE
11
WORKSPACE
@ -1,11 +1,14 @@
|
|||||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "bazel_skylib",
|
name = "bazel_skylib",
|
||||||
|
strip_prefix = "bazel-skylib-2a87d4a62af886fb320883aba102255aba87275e",
|
||||||
urls = [
|
urls = [
|
||||||
"https://github.com/Vertexwahn/bazel-skylib/archive/b0cd4bbd4bf4af76c380e1f8fafdbe3964161aff.tar.gz",
|
"https://github.com/bazelbuild/bazel-skylib/archive/2a87d4a62af886fb320883aba102255aba87275e.tar.gz",
|
||||||
],
|
],
|
||||||
strip_prefix = "bazel-skylib-b0cd4bbd4bf4af76c380e1f8fafdbe3964161aff",
|
sha256 = "d847b08d6702d2779e9eb399b54ff8920fa7521dc45e3e53572d1d8907767de7",
|
||||||
sha256 = "e57f3ff541c65678f3c2b344c73945531838e86ea0be71c63eea862ab43e792b",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||||
bazel_skylib_workspace()
|
|
||||||
|
bazel_skylib_workspace()
|
@ -8,6 +8,7 @@
|
|||||||
[stdout](#stdout)<br>
|
[stdout](#stdout)<br>
|
||||||
[Fallback stringifier](#fallback-stringifier)<br>
|
[Fallback stringifier](#fallback-stringifier)<br>
|
||||||
[Default reporter](#default-reporter)<br>
|
[Default reporter](#default-reporter)<br>
|
||||||
|
[Bazel support](#bazel-support)<br>
|
||||||
[C++11 toggles](#c11-toggles)<br>
|
[C++11 toggles](#c11-toggles)<br>
|
||||||
[C++17 toggles](#c17-toggles)<br>
|
[C++17 toggles](#c17-toggles)<br>
|
||||||
[Other toggles](#other-toggles)<br>
|
[Other toggles](#other-toggles)<br>
|
||||||
@ -96,6 +97,12 @@ This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"`
|
|||||||
is equivalent with the out-of-the-box experience.
|
is equivalent with the out-of-the-box experience.
|
||||||
|
|
||||||
|
|
||||||
|
## Bazel support
|
||||||
|
When `CATCH_CONFIG_BAZEL_SUPPORT` is defined, Catch2 will register a `JUnit`
|
||||||
|
reporter writing to a path pointed by `XML_OUTPUT_FILE` provided by Bazel.
|
||||||
|
|
||||||
|
> `CATCH_CONFIG_BAZEL_SUPPORT` was [introduced](https://github.com/catchorg/Catch2/pull/2399) in Catch2 X.Y.Z.
|
||||||
|
|
||||||
## C++11 toggles
|
## C++11 toggles
|
||||||
|
|
||||||
CATCH_CONFIG_CPP11_TO_STRING // Use `std::to_string`
|
CATCH_CONFIG_CPP11_TO_STRING // Use `std::to_string`
|
||||||
|
@ -69,6 +69,28 @@ namespace Catch {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
|
||||||
|
// Register a JUnit reporter for Bazel. Bazel sets an environment
|
||||||
|
// variable with the path to XML output. If this file is written to
|
||||||
|
// during test, Bazel will not generate a default XML output.
|
||||||
|
// This allows the XML output file to contain higher level of detail
|
||||||
|
// than what is possible otherwise.
|
||||||
|
# if defined( _MSC_VER )
|
||||||
|
// On Windows getenv throws a warning as there is no input validation,
|
||||||
|
// since the key is hardcoded, this should not be an issue.
|
||||||
|
# pragma warning( push )
|
||||||
|
# pragma warning( disable : 4996 )
|
||||||
|
# endif
|
||||||
|
const auto bazelOutputFilePtr = std::getenv( "XML_OUTPUT_FILE" );
|
||||||
|
# if defined( _MSC_VER )
|
||||||
|
# pragma warning( pop )
|
||||||
|
# endif
|
||||||
|
if ( bazelOutputFilePtr != nullptr ) {
|
||||||
|
m_data.reporterSpecifications.push_back(
|
||||||
|
{ "junit", std::string( bazelOutputFilePtr ), {}, {} } );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool defaultOutputUsed = false;
|
bool defaultOutputUsed = false;
|
||||||
m_reporterStreams.reserve( m_data.reporterSpecifications.size() );
|
m_reporterStreams.reserve( m_data.reporterSpecifications.size() );
|
||||||
for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
|
for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
|
||||||
|
@ -165,6 +165,7 @@
|
|||||||
// ------
|
// ------
|
||||||
|
|
||||||
|
|
||||||
|
#cmakedefine CATCH_CONFIG_BAZEL_SUPPORT
|
||||||
#cmakedefine CATCH_CONFIG_DISABLE_EXCEPTIONS
|
#cmakedefine CATCH_CONFIG_DISABLE_EXCEPTIONS
|
||||||
#cmakedefine CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
|
#cmakedefine CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
|
||||||
#cmakedefine CATCH_CONFIG_DISABLE
|
#cmakedefine CATCH_CONFIG_DISABLE
|
||||||
|
@ -121,6 +121,14 @@ set_tests_properties(
|
|||||||
FAIL_REGULAR_EXPRESSION "abort;terminate;fatal"
|
FAIL_REGULAR_EXPRESSION "abort;terminate;fatal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_executable( BazelReporter ${TESTS_DIR}/X30-BazelReporter.cpp )
|
||||||
|
target_compile_definitions( BazelReporter PRIVATE CATCH_CONFIG_BAZEL_SUPPORT )
|
||||||
|
target_link_libraries(BazelReporter Catch2_buildall_interface)
|
||||||
|
add_test(NAME CATCH_CONFIG_BAZEL_REPORTER-1
|
||||||
|
COMMAND
|
||||||
|
"${PYTHON_EXECUTABLE}" "${CATCH_DIR}/tests/TestScripts/testBazelReporter.py" $<TARGET_FILE:BazelReporter> "${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# The default handler on Windows leads to the just-in-time debugger firing,
|
# The default handler on Windows leads to the just-in-time debugger firing,
|
||||||
# which makes this test unsuitable for CI and headless runs, as it opens
|
# which makes this test unsuitable for CI and headless runs, as it opens
|
||||||
|
17
tests/ExtraTests/X30-BazelReporter.cpp
Normal file
17
tests/ExtraTests/X30-BazelReporter.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
// Copyright Catch2 Authors
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
/**\file
|
||||||
|
* Test the Bazel report functionality with a simple set
|
||||||
|
* of dummy test cases.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
TEST_CASE( "Passing test case" ) { REQUIRE( 1 == 1 ); }
|
||||||
|
TEST_CASE( "Failing test case" ) { REQUIRE( 2 == 1 ); }
|
104
tests/TestScripts/testBazelReporter.py
Normal file
104
tests/TestScripts/testBazelReporter.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright Catch2 Authors
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# https://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
"""
|
||||||
|
Test that Catch2 recognizes `XML_OUTPUT_FILE` env variable and creates
|
||||||
|
a junit reporter that writes to the provided path.
|
||||||
|
|
||||||
|
Requires 2 arguments, path to Catch2 binary configured with
|
||||||
|
`CATCH_CONFIG_BAZEL_SUPPORT`, and the output directory for the output file.
|
||||||
|
"""
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Wrong number of arguments: {}".format(len(sys.argv)))
|
||||||
|
print("Usage: {} test-bin-path output-dir".format(sys.argv[0]))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
bin_path = os.path.abspath(sys.argv[1])
|
||||||
|
output_dir = os.path.abspath(sys.argv[2])
|
||||||
|
xml_out_path = os.path.join(output_dir, "bazel-out.xml")
|
||||||
|
|
||||||
|
# Ensure no file exists from previous test runs
|
||||||
|
if os.path.isfile(xml_out_path):
|
||||||
|
os.remove(xml_out_path)
|
||||||
|
|
||||||
|
print('bin path:', bin_path)
|
||||||
|
print('xml out path:', xml_out_path)
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["XML_OUTPUT_FILE"] = xml_out_path
|
||||||
|
test_passing = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
ret = subprocess.run(
|
||||||
|
bin_path,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
check=True,
|
||||||
|
universal_newlines=True,
|
||||||
|
env=env
|
||||||
|
)
|
||||||
|
stdout = ret.stdout
|
||||||
|
except subprocess.SubprocessError as ex:
|
||||||
|
if ex.returncode == 1:
|
||||||
|
# The test cases are allowed to fail.
|
||||||
|
test_passing = False
|
||||||
|
stdout = ex.stdout
|
||||||
|
else:
|
||||||
|
print('Could not run "{}"'.format(args))
|
||||||
|
print("Return code: {}".format(ex.returncode))
|
||||||
|
print("stdout: {}".format(ex.stdout))
|
||||||
|
print("stderr: {}".format(ex.stdout))
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Check for valid XML output
|
||||||
|
try:
|
||||||
|
tree = ET.parse(xml_out_path)
|
||||||
|
except ET.ParseError as ex:
|
||||||
|
print("Invalid XML: '{}'".format(ex))
|
||||||
|
raise
|
||||||
|
except FileNotFoundError as ex:
|
||||||
|
print("Could not find '{}'".format(xml_out_path))
|
||||||
|
raise
|
||||||
|
|
||||||
|
bin_name = os.path.basename(bin_path)
|
||||||
|
# Check for matching testsuite
|
||||||
|
if not tree.find('.//testsuite[@name="{}"]'.format(bin_name)):
|
||||||
|
print("Could not find '{}' testsuite".format(bin_name))
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
# Check that we haven't disabled the default reporter
|
||||||
|
summary_test_cases = re.findall(r'test cases: \d* \| \d* passed \| \d* failed', stdout)
|
||||||
|
if len(summary_test_cases) == 0:
|
||||||
|
print("Could not find test summary in {}".format(stdout))
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
total, passed, failed = [int(s) for s in summary_test_cases[0].split() if s.isdigit()]
|
||||||
|
|
||||||
|
if failed == 0 and not test_passing:
|
||||||
|
print("Expected at least 1 test failure!")
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
if len(tree.findall('.//testcase')) != total:
|
||||||
|
print("Unexpected number of test cases!")
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
if len(tree.findall('.//failure')) != failed:
|
||||||
|
print("Unexpected number of test failures!")
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
if (passed + failed) != total:
|
||||||
|
print("Something has gone very wrong, ({} + {}) != {}".format(passed, failed, total))
|
||||||
|
exit(2)
|
Loading…
Reference in New Issue
Block a user