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