Skip to content

Commit

Permalink
Add default reporter for Bazel integration
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lukokr-aarch64 committed Mar 24, 2022
1 parent 0e176c3 commit b404700
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 10 deletions.
36 changes: 26 additions & 10 deletions BUILD.bazel
@@ -1,13 +1,13 @@
# Load the cc_library rule.
load("@rules_cc//cc:defs.bzl", "cc_library")

load("@bazel_skylib//rules:expand_template.bzl", "expand_template")

expand_template(
name = "catch_user_config.hpp",
name = "catch_user_config",
out = "catch2/catch_user_config.hpp",
substitutions = {
"#cmakedefine CATCH_CONFIG_ANDROID_LOGWRITE": "",
"#cmakedefine CATCH_CONFIG_BAZEL_SUPPORT": " #define CATCH_CONFIG_BAZEL_SUPPORT",
"#cmakedefine CATCH_CONFIG_COLOUR_ANSI": "",
"#cmakedefine CATCH_CONFIG_COLOUR_NONE": "",
"#cmakedefine CATCH_CONFIG_COLOUR_WINDOWS": "",
Expand Down Expand Up @@ -57,23 +57,39 @@ expand_template(
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"],
copts = ["-std=c++14"],
include_prefix = ".", # to manipulate -I of dependenices
visibility = ["//visibility:public"],
)

# Static library, without main.
cc_library(
name = "catch2",
hdrs = glob(["src/catch2/**/*.hpp"]) + ["catch_user_config.hpp"],
srcs = glob(["src/catch2/**/*.cpp"],
exclude=[ "src/catch2/internal/catch_main.cpp"]),
visibility = ["//visibility:public"],
linkstatic = True,
srcs = glob(
["src/catch2/**/*.cpp"],
exclude = ["src/catch2/internal/catch_main.cpp"],
),
hdrs = glob(["src/catch2/**/*.hpp"]),
copts = ["-std=c++14"],
includes = ["src/"],
linkstatic = True,
visibility = ["//visibility:public"],
deps = [":catch2_generated"],
)

# Static library, with main.
cc_library(
name = "catch2_main",
srcs = ["src/catch2/internal/catch_main.cpp"],
deps = [":catch2"],
visibility = ["//visibility:public"],
linkstatic = True,
copts = ["-std=c++14"],
includes = ["src/"],
linkstatic = True,
visibility = ["//visibility:public"],
deps = [":catch2"],
)
4 changes: 4 additions & 0 deletions docs/configuration.md
Expand Up @@ -97,6 +97,10 @@ This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"`
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.

## C++11 toggles

CATCH_CONFIG_CPP11_TO_STRING // Use `std::to_string`
Expand Down
21 changes: 21 additions & 0 deletions src/catch2/catch_config.cpp
Expand Up @@ -8,6 +8,7 @@
#include <catch2/catch_config.hpp>
#include <catch2/catch_user_config.hpp>
#include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_platform.hpp>
#include <catch2/internal/catch_stream.hpp>
#include <catch2/internal/catch_stringref.hpp>
#include <catch2/internal/catch_string_manip.hpp>
Expand Down Expand Up @@ -80,6 +81,26 @@ namespace Catch {
} );
}

#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
// Register a JUnit reporter for Bazel. Bazel sets an enviorment
// 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( CATCH_PLATFORM_WINDOWS )
// 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(suppress: 4996)
auto const bazelOutputFile = std::getenv( "XML_OUTPUT_FILE" );
#else
auto const bazelOutputFile = std::getenv( "XML_OUTPUT_FILE" );
#endif
if ( bazelOutputFile != nullptr ) {
m_data.reporterSpecifications.push_back(
{ "junit", { bazelOutputFile } } );
}
#endif

bool defaultOutputUsed = false;
m_reporterStreams.reserve( m_data.reporterSpecifications.size() );
for ( auto const& reporterAndFile : m_data.reporterSpecifications ) {
Expand Down
1 change: 1 addition & 0 deletions src/catch2/catch_user_config.hpp.in
Expand Up @@ -159,6 +159,7 @@
// ------


#cmakedefine CATCH_CONFIG_BAZEL_SUPPORT
#cmakedefine CATCH_CONFIG_COLOUR_ANSI
#cmakedefine CATCH_CONFIG_COLOUR_NONE
#cmakedefine CATCH_CONFIG_COLOUR_WINDOWS
Expand Down
4 changes: 4 additions & 0 deletions tests/CMakeLists.txt
Expand Up @@ -473,6 +473,10 @@ set_tests_properties("Reporters::DashAsLocationInReporterSpecSendsOutputToStdout
)

if (CATCH_ENABLE_CONFIGURE_TESTS)
add_test(NAME "CMakeConfig::ConfigureBazelReporter"
COMMAND
"${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_LIST_DIR}/TestScripts/testConfigureBazelReporter.py" "${CATCH_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
)
add_test(NAME "CMakeConfig::DefaultReporter"
COMMAND
"${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_LIST_DIR}/TestScripts/testConfigureDefaultReporter.py" "${CATCH_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
Expand Down
90 changes: 90 additions & 0 deletions tests/TestScripts/testConfigureBazelReporter.py
@@ -0,0 +1,90 @@
#!/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

from ConfigureTestsCommon import configure_and_build, run_and_return_output

import os
import re
import sys
import xml.etree.ElementTree as ET

"""
Tests the CMake configure option for CATCH_CONFIG_DEFAULT_REPORTER
Requires 2 arguments, path folder where the Catch2's main CMakeLists.txt
exists, and path to where the output files should be stored.
"""
if len(sys.argv) != 3:
print("Wrong number of arguments: {}".format(len(sys.argv)))
print("Usage: {} catch2-top-level-dir base-build-output-dir".format(sys.argv[0]))
exit(1)

catch2_source_path = os.path.abspath(sys.argv[1])
build_dir_path = os.path.join(
os.path.abspath(sys.argv[2]), "CMakeConfigTests", "ConfigureBazelReporter"
)

configure_and_build(
catch2_source_path, build_dir_path, [("CATCH_CONFIG_BAZEL_SUPPORT", "ON")]
)

xml_out_path = os.path.join(
build_dir_path,
"test.xml",
)

# Ensure no file exists from previous test runs
if os.path.isfile(xml_out_path):
os.remove(xml_out_path)


os.environ["XML_OUTPUT_FILE"] = xml_out_path
stdout, _ = run_and_return_output(
os.path.join(build_dir_path, "tests"),
"SelfTest",
["-s", "[approx][custom]"],
)

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

testcases = tree.findall(".//testcase")
if len(testcases) != 1:
print(
"Unexpected number of testcases '{}' in '{}'".format(
len(testcases), xml_out_path
)
)
exit(2)

expected = {
"classname": "SelfTest.global",
"name": "Use a custom approx",
"status": "run",
}
testcase = testcases[0]

actual = testcase.attrib
for expect_key, expect_val in expected.items():
if expect_key not in actual:
print("Key not found in testcase tags: '{}'".format(expect_key))
exit(2)
if expect_val != actual[expect_key]:
print(
"Value mismatch in testcase tags '{}' != '{}' for key '{}'".format(
expect_val, actual[expect_key], expect_key
)
)
exit(2)

0 comments on commit b404700

Please sign in to comment.