| # 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) |