blob: c4c437ae03c6473cb42c1776fb52ad01c988c75b [file] [log] [blame] [edit]
# Copyright 2024 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Test helpers for glob_dirs()."""
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("//pw_build:compatibility.bzl", "incompatible_with_mcu")
def return_error(err):
"""Testing helper to return an error string rather than fail().
To use this, the starlark function your testing must support injection
of an alternative `fail()` handler.
"""
return err
# This provider allows the test logic implementation to see the information
# captured by the build rule.
_TestExpectationInfo = provider(
"A pair of expected and actual values for testing",
fields = ["actual", "expected"],
)
def _comparison_case_rule_impl(ctx):
return [
_TestExpectationInfo(
expected = ctx.attr.expected,
actual = ctx.attr.actual,
),
]
# `rule()` calls have to be at the top of the file, so we can't just make this
# a lambda of some kind. The best we can do is make it super easy to stamp out
# more.
def build_comparison_case_rule(attr_type):
return {
"attrs": {
"actual": attr_type,
"expected": attr_type,
},
"implementation": _comparison_case_rule_impl,
"provides": [_TestExpectationInfo],
}
string_comparison = rule(
**build_comparison_case_rule(attr.string())
)
string_list_comparison = rule(
**build_comparison_case_rule(attr.string_list())
)
# Collect into a single struct to make it easier to load in a BUILD file.
PW_LOAD_PHASE_TEST_TYPES = struct(
STRING = string_comparison,
STRING_LIST = string_list_comparison,
)
# Implement the actual test logic. In this case, it's pretty trivial: just
# assert that the `expected` and `actual` attributes of the rule match.
def _load_phase_test_impl(ctx):
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)
asserts.equals(
env,
target_under_test[_TestExpectationInfo].expected,
target_under_test[_TestExpectationInfo].actual,
)
return analysistest.end(env)
_load_phase_test = analysistest.make(_load_phase_test_impl)
# This is the macro for decaring an individual test case.
def pw_load_phase_test(comparison_type):
def comparison_test(name, expected, actual, tags = [], **rule_kwargs):
comparison_type(
name = name + ".case",
expected = expected,
actual = actual,
tags = tags + ["manual"],
target_compatible_with = incompatible_with_mcu(),
testonly = True,
**rule_kwargs
)
_load_phase_test(
name = name,
target_under_test = name + ".case",
tags = tags,
target_compatible_with = incompatible_with_mcu(),
**rule_kwargs
)
return comparison_test
# Actual test rule types.
pw_string_comparison_test = pw_load_phase_test(PW_LOAD_PHASE_TEST_TYPES.STRING)
pw_string_list_comparison_test = pw_load_phase_test(PW_LOAD_PHASE_TEST_TYPES.STRING_LIST)