xref: /aosp_15_r20/external/pigweed/pw_build/load_phase_test.bzl (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2024 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Test helpers for glob_dirs()."""
15
16load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
17load("//pw_build:compatibility.bzl", "incompatible_with_mcu")
18
19def return_error(err):
20    """Testing helper to return an error string rather than fail().
21
22    To use this, the starlark function your testing must support injection
23    of an alternative `fail()` handler.
24    """
25    return err
26
27# This provider allows the test logic implementation to see the information
28# captured by the build rule.
29_TestExpectationInfo = provider(
30    "A pair of expected and actual values for testing",
31    fields = ["actual", "expected"],
32)
33
34def _comparison_case_rule_impl(ctx):
35    return [
36        _TestExpectationInfo(
37            expected = ctx.attr.expected,
38            actual = ctx.attr.actual,
39        ),
40    ]
41
42# `rule()` calls have to be at the top of the file, so we can't just make this
43# a lambda of some kind. The best we can do is make it super easy to stamp out
44# more.
45def build_comparison_case_rule(attr_type):
46    return {
47        "attrs": {
48            "actual": attr_type,
49            "expected": attr_type,
50        },
51        "implementation": _comparison_case_rule_impl,
52        "provides": [_TestExpectationInfo],
53    }
54
55string_comparison = rule(
56    **build_comparison_case_rule(attr.string())
57)
58
59string_list_comparison = rule(
60    **build_comparison_case_rule(attr.string_list())
61)
62
63# Collect into a single struct to make it easier to load in a BUILD file.
64PW_LOAD_PHASE_TEST_TYPES = struct(
65    STRING = string_comparison,
66    STRING_LIST = string_list_comparison,
67)
68
69# Implement the actual test logic. In this case, it's pretty trivial: just
70# assert that the `expected` and `actual` attributes of the rule match.
71def _load_phase_test_impl(ctx):
72    env = analysistest.begin(ctx)
73    target_under_test = analysistest.target_under_test(env)
74    asserts.equals(
75        env,
76        target_under_test[_TestExpectationInfo].expected,
77        target_under_test[_TestExpectationInfo].actual,
78    )
79
80    return analysistest.end(env)
81
82_load_phase_test = analysistest.make(_load_phase_test_impl)
83
84# This is the macro for decaring an individual test case.
85def pw_load_phase_test(comparison_type):
86    def comparison_test(name, expected, actual, tags = [], **rule_kwargs):
87        comparison_type(
88            name = name + ".case",
89            expected = expected,
90            actual = actual,
91            tags = tags + ["manual"],
92            target_compatible_with = incompatible_with_mcu(),
93            testonly = True,
94            **rule_kwargs
95        )
96
97        _load_phase_test(
98            name = name,
99            target_under_test = name + ".case",
100            tags = tags,
101            target_compatible_with = incompatible_with_mcu(),
102            **rule_kwargs
103        )
104
105    return comparison_test
106
107# Actual test rule types.
108pw_string_comparison_test = pw_load_phase_test(PW_LOAD_PHASE_TEST_TYPES.STRING)
109pw_string_list_comparison_test = pw_load_phase_test(PW_LOAD_PHASE_TEST_TYPES.STRING_LIST)
110