| # Copyright 2022 Google LLC. All rights reserved. |
| # |
| # 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 |
| # |
| # http://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. |
| |
| """kt_asserts""" |
| |
| load("//:visibility.bzl", "RULES_KOTLIN") |
| load("@bazel_skylib//lib:unittest.bzl", "asserts") |
| |
| visibility(RULES_KOTLIN) |
| |
| def _equals(a, b): |
| return a == b |
| |
| def _list_matching(left, right, matcher = None): |
| """Find the overlap between two lists. |
| |
| Args: |
| left: [list[A]] |
| right: [list[B]] |
| matcher: [function(A,B):bool] A matcher on the two list types |
| |
| Returns: |
| [(list[A], list[(A, B)], list[B])] The left-only, matching-pair, and right-only lists |
| """ |
| |
| matcher = matcher or _equals |
| |
| left_only = [] |
| matches = [] |
| right_only = list(right) |
| |
| def _process_left_ele(left_ele): |
| for index, right_ele in enumerate(right_only): |
| if matcher(left_ele, right_ele): |
| right_only.pop(index) |
| matches.append((left_ele, right_ele)) |
| return |
| |
| left_only.append(left_ele) |
| |
| for left_ele in left: |
| _process_left_ele(left_ele) |
| |
| return (left_only, matches, right_only) |
| |
| def _assert_list_matches(env, expected, actual, matcher = None, items_name = "items"): |
| """Assert two lists have an exact matching. |
| |
| Args: |
| env: [unittest.env] |
| expected: [list[A]] |
| actual: [list[B]] |
| matcher: [function(A,B):bool] |
| items_name: [string] The plural noun describing the list items in an error message |
| |
| Returns: |
| [None] Fails if assertion violated |
| """ |
| |
| extra_expected, _, extra_actual = _list_matching(expected, actual, matcher = matcher) |
| asserts.true( |
| env, |
| len(extra_actual) == 0 and len(extra_expected) == 0, |
| "Unmatched expected {name} {expected}\nUnmatched actual {name} {actual}".format( |
| name = items_name, |
| expected = extra_expected, |
| actual = extra_actual, |
| ), |
| ) |
| |
| def _assert_required_mnemonic_counts(env, required_mnemonic_counts, actual_actions): |
| """Assert that some set of menemonics is present/absent within a set of Actions. |
| |
| Args: |
| env: [unittest.env] |
| required_mnemonic_counts: [dict[string,string]] The menemonics to check -> expected count |
| actual_actions: [list[Action]] |
| |
| Returns: |
| [None] Fails if assertion violated |
| """ |
| |
| considered_actual_mnemonics = [ |
| x.mnemonic |
| for x in actual_actions |
| # Ignore any mnemonics not mentioned by the user |
| if (x.mnemonic in required_mnemonic_counts) |
| ] |
| |
| required_mnemonics = [] |
| for m, c in required_mnemonic_counts.items(): |
| for _ in range(0, int(c)): |
| required_mnemonics.append(m) |
| |
| _assert_list_matches( |
| env, |
| required_mnemonics, |
| considered_actual_mnemonics, |
| items_name = "mnemonics", |
| ) |
| |
| kt_asserts = struct( |
| list_matches = _assert_list_matches, |
| required_mnemonic_counts = _assert_required_mnemonic_counts, |
| ) |