xref: /aosp_15_r20/external/bazelbuild-kotlin-rules/kotlin/common/testing/asserts.bzl (revision 3a22c0a33dd99bcca39a024d43e6fbcc55c2806e)
1# Copyright 2022 Google LLC. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the License);
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://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,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""kt_asserts"""
16
17load("//:visibility.bzl", "RULES_KOTLIN")
18load("@bazel_skylib//lib:unittest.bzl", "asserts")
19
20visibility(RULES_KOTLIN)
21
22def _equals(a, b):
23    return a == b
24
25def _list_matching(left, right, matcher = None):
26    """Find the overlap between two lists.
27
28    Args:
29        left: [list[A]]
30        right: [list[B]]
31        matcher: [function(A,B):bool] A matcher on the two list types
32
33    Returns:
34        [(list[A], list[(A, B)], list[B])] The left-only, matching-pair, and right-only lists
35    """
36
37    matcher = matcher or _equals
38
39    left_only = []
40    matches = []
41    right_only = list(right)
42
43    def _process_left_ele(left_ele):
44        for index, right_ele in enumerate(right_only):
45            if matcher(left_ele, right_ele):
46                right_only.pop(index)
47                matches.append((left_ele, right_ele))
48                return
49
50        left_only.append(left_ele)
51
52    for left_ele in left:
53        _process_left_ele(left_ele)
54
55    return (left_only, matches, right_only)
56
57def _assert_list_matches(env, expected, actual, matcher = None, items_name = "items"):
58    """Assert two lists have an exact matching.
59
60    Args:
61        env: [unittest.env]
62        expected: [list[A]]
63        actual: [list[B]]
64        matcher: [function(A,B):bool]
65        items_name: [string] The plural noun describing the list items in an error message
66
67    Returns:
68        [None] Fails if assertion violated
69    """
70
71    extra_expected, _, extra_actual = _list_matching(expected, actual, matcher = matcher)
72    asserts.true(
73        env,
74        len(extra_actual) == 0 and len(extra_expected) == 0,
75        "Unmatched expected {name} {expected}\nUnmatched actual {name} {actual}".format(
76            name = items_name,
77            expected = extra_expected,
78            actual = extra_actual,
79        ),
80    )
81
82def _assert_required_mnemonic_counts(env, required_mnemonic_counts, actual_actions):
83    """Assert that some set of menemonics is present/absent within a set of Actions.
84
85    Args:
86        env: [unittest.env]
87        required_mnemonic_counts: [dict[string,string]] The menemonics to check -> expected count
88        actual_actions: [list[Action]]
89
90    Returns:
91        [None] Fails if assertion violated
92    """
93
94    considered_actual_mnemonics = [
95        x.mnemonic
96        for x in actual_actions
97        # Ignore any mnemonics not mentioned by the user
98        if (x.mnemonic in required_mnemonic_counts)
99    ]
100
101    required_mnemonics = []
102    for m, c in required_mnemonic_counts.items():
103        for _ in range(0, int(c)):
104            required_mnemonics.append(m)
105
106    _assert_list_matches(
107        env,
108        required_mnemonics,
109        considered_actual_mnemonics,
110        items_name = "mnemonics",
111    )
112
113kt_asserts = struct(
114    list_matches = _assert_list_matches,
115    required_mnemonic_counts = _assert_required_mnemonic_counts,
116)
117