Skip to content

Commit

Permalink
add cc_build_error_test (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyawk authored Nov 27, 2024
1 parent 742d586 commit 33c940b
Show file tree
Hide file tree
Showing 20 changed files with 214 additions and 88 deletions.
21 changes: 0 additions & 21 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Look up cache if it's not a scheduled job
if: ${{ github.event_name != 'schedule' }}
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.cache
key: ${{ github.repository }}-${{ github.job }}-${{ matrix.bazel-version }}-${{ runner.os }}-${{ hashFiles('.bazelrc', 'WORKSPACE', 'MODULE.bazel') }}
restore-keys: ${{ github.repository }}-${{ github.job }}-${{ matrix.bazel-version }}-${{ runner.os }}-
- name: Set up
uses: ./.github/actions/setup
with:
Expand Down Expand Up @@ -72,13 +65,6 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Look up cache if it's not a scheduled job
if: ${{ github.event_name != 'schedule' }}
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/examples/.cache
key: ${{ github.repository }}-${{ github.job }}-${{ matrix.bazel-version }}-${{ runner.os }}-${{ hashFiles('.bazelrc', 'WORKSPACE', 'MODULE.bazel', 'examples/.bazelrc', 'examples/WORKSPACE', 'examples/MODULE.bazel') }}
restore-keys: ${{ github.repository }}-${{ github.job }}-${{ matrix.bazel-version }}-${{ runner.os }}-
- name: Set up
uses: ./.github/actions/setup
with:
Expand All @@ -96,13 +82,6 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Look up cache if it's not a scheduled job
if: ${{ github.event_name != 'schedule' }}
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/.cache
key: ${{ github.repository }}-${{ github.job }}-${{ env.bazel-version }}-${{ runner.os }}-${{ hashFiles('.bazelrc', 'WORKSPACE', 'MODULE.bazel') }}
restore-keys: ${{ github.repository }}-${{ github.job }}-${{ env.bazel-version }}-${{ runner.os }}-
- name: Set up
uses: ./.github/actions/setup
with:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ Load this module from the [Bazel Central Registry](https://registry.bazel.build/
### C/C++ example

```bazel
load("@rules_build_error//lang/cc:defs.bzl", "cc_build_error")
load("@rules_build_error//lang/cc:defs.bzl", "cc_build_error_test")
load("@rules_build_error//matcher:defs.bzl", "matcher")

cc_build_error(
cc_build_error_test(
name = "cause_compile_error",
src = "cause_compile_error.cpp",
deps = [":library_to_successfully_link"], # `:library_to_successfully_link` must provide `CcInfo`, like `cc_library`
Expand Down
9 changes: 9 additions & 0 deletions development/cli/execute_tests.bash
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,20 @@ echo "Executing the test cases which should succeed in straightforward 'bazel te

echo "Executing the test cases which should fail at 'bazel build'"
check_bazel_build_error //tests/cc/cpp_successful_build:plain
check_bazel_build_error //tests/cc/cpp_successful_build:plain.test
check_bazel_build_error //tests/cc/cpp_successful_build:with_basic_regex_matcher
check_bazel_build_error //tests/cc/cpp_successful_build:with_basic_regex_matcher.test
check_bazel_build_error //tests/cc/cpp_successful_build:with_extended_regex_matcher
check_bazel_build_error //tests/cc/cpp_successful_build:with_extended_regex_matcher.test
check_bazel_build_error //tests/cc/cpp_successful_build:with_substr_matcher
check_bazel_build_error //tests/cc/cpp_successful_build:with_substr_matcher.test
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:plain
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:plain.test
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_basic_regex_matcher
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_basic_regex_matcher.test
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_extended_regex_matcher
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_extended_regex_matcher.test
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_substr_matcher
check_bazel_build_error //tests/cc/cpp_successful_build_with_deps:with_substr_matcher.test
check_bazel_build_error //tests/cc/cpp_compile_error:incorrect_matcher
check_bazel_build_error //tests/cc/cpp_compile_error:incorrect_matcher.test
25 changes: 24 additions & 1 deletion examples/cc/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@rules_build_error//lang/cc:defs.bzl", "cc_build_error")
load(
"@rules_build_error//lang/cc:defs.bzl",
"cc_build_error",
"cc_build_error_test",
)
load("@rules_build_error//matcher:defs.bzl", "matcher")

# `cc_build_error` targets are designed to build successfully
# only when the expected compilation or linking error occurs.

cc_build_error(
name = "compile_error",
src = "compile_error.cpp",
Expand All @@ -21,3 +28,19 @@ build_test(
":link_error",
],
)

# `cc_build_error_test` is a test rule for `cc_build_error` that succeeds
# only when `cc_build_error` builds successfully,
# meaning the expected compilation or linking error occurs.

cc_build_error_test(
name = "compile_error_test",
src = "compile_error.cpp",
compile_stderr = matcher.has_substr("Example compile error"),
)

cc_build_error_test(
name = "link_error_test",
src = "link_error.cpp",
link_stderr = matcher.contains_basic_regex("Declared.*Undefined"),
)
8 changes: 6 additions & 2 deletions lang/cc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Defines some implementations to check build error in C/C++.

## `cc_build_error`

`cc_build_error` is a wrapper macro for rules, providing [`CcBuildErrorInfo`](#ccbuilderrorinfo).
`cc_build_error` is a rule providing [`CcBuildErrorInfo`](#ccbuilderrorinfo).

In addition to the common rule attributes listed [here](https://bazel.build/reference/be/common-definitions#common-attributes), it can receive the following attributes (regarding the specific matcher, please refer to [its readme](../../matcher/README.md)):

Expand All @@ -22,6 +22,10 @@ In addition to the common rule attributes listed [here](https://bazel.build/refe
| link_stderr | Matcher for the stderr message while linking | specific matcher | No (defaults to no-op) | |
| link_stdout | Matcher for the stdout message while linking | specific matcher | No (defaults to no-op) | |

## `CcBuildErrorInfo`
### `CcBuildErrorInfo`

`CcBuildErrorInfo` is a provider describing the build error in C/C++. See its definition in [its bzl file](./build_error.bzl) for its details.

## `cc_build_error_test`

`cc_build_error_test` is a test rule used to verify that `cc_build_error` builds successfully. It accepts the same set of arguments as `cc_build_error`.
88 changes: 87 additions & 1 deletion lang/cc/build_error.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@ def cc_build_error(
}
kwargs.clear()

try_build_target = name + "__tb"
try_build_target = name + "__0"
_try_build(
name = try_build_target,
tags = ["manual"] + tags,
Expand Down Expand Up @@ -627,3 +627,89 @@ def cc_build_error(
testonly = testonly,
**kwargs_check_messages
)

def _create_test_impl(ctx):
"""Implementation of `_create_test`.
Args:
ctx(ctx): The rule's context.
Returns:
A list of providers.
"""
cc_build_error_info = ctx.attr.cc_build_error[CcBuildErrorInfo]
extension = ".bat" if ctx.attr.is_windows else ".sh"
content = "exit 0" if ctx.attr.is_windows else "#!/usr/bin/env bash\nexit 0"
executable_template = ctx.actions.declare_file(ctx.label.name + "/exe_tpl")
executable = ctx.actions.declare_file(ctx.label.name + extension)
ctx.actions.write(
output = executable_template,
is_executable = True,
content = content,
)
ctx.actions.run_shell(
outputs = [executable],
inputs = cc_build_error_info.markers + [executable_template],
command = "cp $1 $2",
arguments = [
executable_template.path,
executable.path,
],
)
return [
DefaultInfo(
files = depset([executable]),
executable = executable,
),
]

_create_test = rule(
implementation = _create_test_impl,
attrs = {
"cc_build_error": attr.label(
doc = "Target for `CcBuildErrorInfo`",
mandatory = True,
providers = [CcBuildErrorInfo],
),
"is_windows": attr.bool(
doc = "Whether the runtime environment is windows or not. " +
"This attribute is not user-facing.",
mandatory = True,
),
},
test = True,
)

def cc_build_error_test(*, name, **kwargs):
"""Test rule checking `cc_build_error` builds.
Args:
name(str): Name of the test target.
**kwargs(dict): Receives the same keyword arguments as `cc_build_error`.
"""
build_target_name = name + "__0"

# `testonly` is always true.
kwargs["testonly"] = True

# Arguments passed to the test target.
tags = kwargs.pop("tags", [])
visibility = kwargs.pop("visibility", None)

cc_build_error(
name = build_target_name,
tags = tags + ["manual"],
visibility = ["//visibility:private"],
**kwargs
)

_create_test(
name = name,
cc_build_error = ":" + build_target_name,
is_windows = select({
"@bazel_tools//src/conditions:host_windows": True,
"//conditions:default": False,
}),
tags = tags,
visibility = visibility,
)
2 changes: 2 additions & 0 deletions lang/cc/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ load(
":build_error.bzl",
_CcBuildErrorInfo = "CcBuildErrorInfo",
_cc_build_error = "cc_build_error",
_cc_build_error_test = "cc_build_error_test",
)

visibility("public")

cc_build_error = _cc_build_error
cc_build_error_test = _cc_build_error_test
CcBuildErrorInfo = _CcBuildErrorInfo
10 changes: 5 additions & 5 deletions tests/cc/c_compile_error/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("//lang/cc:defs.bzl", "cc_build_error")
load("//matcher:defs.bzl", "matcher")
load("//tests/cc:utils.bzl", "check_build_and_test")

cc_build_error(
check_build_and_test(
name = "plain",
src = "c_compile_error.c",
)

cc_build_error(
check_build_and_test(
name = "with_substr_matcher",
src = "c_compile_error.c",
compile_stderr = matcher.has_substr("for c_compile_error.c"),
)

cc_build_error(
check_build_and_test(
name = "with_basic_regex_matcher",
src = "c_compile_error.c",
compile_stderr = matcher.contains_basic_regex(r"for[[:space:]]c_compile_error\.\(c\|C\)"),
)

cc_build_error(
check_build_and_test(
name = "with_extended_regex_matcher",
src = "c_compile_error.c",
compile_stderr = matcher.contains_extended_regex(r"for[[:space:]]c_compile_error\.(c|C)"),
Expand Down
10 changes: 5 additions & 5 deletions tests/cc/c_compile_error_with_deps/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("//lang/cc:defs.bzl", "cc_build_error")
load("//matcher:defs.bzl", "matcher")
load("//tests/cc:utils.bzl", "check_build_and_test")

cc_library(
name = "library",
srcs = ["library.c"],
hdrs = ["library.h"],
)

cc_build_error(
check_build_and_test(
name = "plain",
src = "c_compile_error.c",
deps = [":library"],
)

cc_build_error(
check_build_and_test(
name = "with_substr_matcher",
src = "c_compile_error.c",
compile_stderr = matcher.has_substr("too many arguments"),
deps = [":library"],
)

cc_build_error(
check_build_and_test(
name = "with_basic_regex_matcher",
src = "c_compile_error.c",
compile_stderr = matcher.contains_basic_regex("too many arguments.*argument"),
deps = [":library"],
)

cc_build_error(
check_build_and_test(
name = "with_extended_regex_matcher",
src = "c_compile_error.c",
compile_stderr = matcher.contains_extended_regex("too many arguments.*argument"),
Expand Down
10 changes: 5 additions & 5 deletions tests/cc/c_link_error/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("//lang/cc:defs.bzl", "cc_build_error")
load("//matcher:defs.bzl", "matcher")
load("//tests/cc:utils.bzl", "check_build_and_test")

cc_build_error(
check_build_and_test(
name = "plain",
src = "c_link_error.c",
)

cc_build_error(
check_build_and_test(
name = "with_substr_matcher",
src = "c_link_error.c",
link_stderr = matcher.has_substr("GetReturnValue"),
)

cc_build_error(
check_build_and_test(
name = "with_basic_regex_matcher",
src = "c_link_error.c",
link_stderr = matcher.contains_basic_regex(r"undefined.*GetReturnValue"),
)

cc_build_error(
check_build_and_test(
name = "with_extended_regex_matcher",
src = "c_link_error.c",
link_stderr = matcher.contains_extended_regex(r"undefined.*GetReturnValue"),
Expand Down
10 changes: 5 additions & 5 deletions tests/cc/c_link_error_with_deps/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("//lang/cc:defs.bzl", "cc_build_error")
load("//matcher:defs.bzl", "matcher")
load("//tests/cc:utils.bzl", "check_build_and_test")

cc_library(
name = "library",
srcs = ["library.c"],
hdrs = ["library.h"],
)

cc_build_error(
check_build_and_test(
name = "plain",
src = "c_link_error.c",
deps = [":library"],
)

cc_build_error(
check_build_and_test(
name = "with_substr_matcher",
src = "c_link_error.c",
link_stderr = matcher.has_substr("FunctionWithoutDefinition"),
deps = [":library"],
)

cc_build_error(
check_build_and_test(
name = "with_basic_regex_matcher",
src = "c_link_error.c",
link_stderr = matcher.contains_basic_regex(r"undefined.*FunctionWithoutDefinition"),
deps = [":library"],
)

cc_build_error(
check_build_and_test(
name = "with_extended_regex_matcher",
src = "c_link_error.c",
link_stderr = matcher.contains_extended_regex(r"undefined.*FunctionWithoutDefinition"),
Expand Down
Loading

0 comments on commit 33c940b

Please sign in to comment.