mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-03 21:49:32 +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:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						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
 | 
			
		||||
							
								
								
									
										34
									
								
								BUILD.bazel
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								BUILD.bazel
									
									
									
									
									
								
							@@ -1,13 +1,14 @@
 | 
			
		||||
# 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_NO_COLOUR_WIN32": "",
 | 
			
		||||
        "#cmakedefine CATCH_CONFIG_COLOUR_WIN32": "",
 | 
			
		||||
        "#cmakedefine CATCH_CONFIG_COUNTER": "",
 | 
			
		||||
        "#cmakedefine CATCH_CONFIG_CPP11_TO_STRING": "",
 | 
			
		||||
@@ -55,23 +56,36 @@ 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"],
 | 
			
		||||
    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"]),
 | 
			
		||||
    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,
 | 
			
		||||
    includes = ["src/"],
 | 
			
		||||
    linkstatic = True,
 | 
			
		||||
    visibility = ["//visibility:public"],
 | 
			
		||||
    deps = [":catch2"],
 | 
			
		||||
)
 | 
			
		||||
@@ -26,6 +26,7 @@ endmacro()
 | 
			
		||||
 | 
			
		||||
set(_OverridableOptions
 | 
			
		||||
  "ANDROID_LOGWRITE"
 | 
			
		||||
  "BAZEL_SUPPORT"
 | 
			
		||||
  "COLOUR_WIN32"
 | 
			
		||||
  "COUNTER"
 | 
			
		||||
  "CPP11_TO_STRING"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
 | 
			
		||||
 | 
			
		||||
http_archive(
 | 
			
		||||
    name = "bazel_skylib",
 | 
			
		||||
    strip_prefix = "bazel-skylib-2a87d4a62af886fb320883aba102255aba87275e",
 | 
			
		||||
    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 = "e57f3ff541c65678f3c2b344c73945531838e86ea0be71c63eea862ab43e792b",
 | 
			
		||||
    sha256 = "d847b08d6702d2779e9eb399b54ff8920fa7521dc45e3e53572d1d8907767de7",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
 | 
			
		||||
 | 
			
		||||
bazel_skylib_workspace()
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
[stdout](#stdout)<br>
 | 
			
		||||
[Fallback stringifier](#fallback-stringifier)<br>
 | 
			
		||||
[Default reporter](#default-reporter)<br>
 | 
			
		||||
[Bazel support](#bazel-support)<br>
 | 
			
		||||
[C++11 toggles](#c11-toggles)<br>
 | 
			
		||||
[C++17 toggles](#c17-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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
        m_reporterStreams.reserve( m_data.reporterSpecifications.size() );
 | 
			
		||||
        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_CUSTOM_HANDLER
 | 
			
		||||
#cmakedefine CATCH_CONFIG_DISABLE
 | 
			
		||||
 
 | 
			
		||||
@@ -121,6 +121,14 @@ set_tests_properties(
 | 
			
		||||
    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,
 | 
			
		||||
# 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)
 | 
			
		||||
		Reference in New Issue
	
	Block a user