"""Phase 8: CALL / SEARCH ALL 系测试。 测试覆盖: - CALL 参数传递逻辑(by reference / by value / by content) - SEARCH ALL 二分查找逻辑(找到 / 未找到 / 重复键 / 空表) """ from __future__ import annotations from typing import Any # ── CALL 模拟 - def _call_by_reference(param: list) -> list: """模拟 COBOL CALL BY REFERENCE: 修改外部变量。""" param[0] = param[0] * 2 return param def _call_by_value(param: int) -> int: """模拟 COBOL CALL BY VALUE: 传入副本。""" return param * 2 def _call_by_content(param: list) -> list: """模拟 COBOL CALL BY CONTENT: 传入副本,不修改原始值。""" copy = param.copy() copy[0] = copy[0] * 2 return copy def _call_with_multiple( a: int, b: int, c: str = "", ) -> dict[str, Any]: """模拟多参数 CALL。""" return {"sum": a + b, "concat": c * 2} # ── SEARCH ALL 模拟 ── def _search_all(table: list[dict], key_field: str, target: Any) -> int | None: """模拟 COBOL SEARCH ALL(二分查找)。 要求 table 已按 key_field 升序排列。 参数 ---------- table : list[dict] 已排序的表。 key_field : str 待查找的键字段名。 target : Any 目标值。 返回 ------- int | None 找到时返回下标;未找到返回 None。 """ lo, hi = 0, len(table) - 1 while lo <= hi: mid = (lo + hi) // 2 val = table[mid][key_field] if val == target: return mid elif val < target: lo = mid + 1 else: hi = mid - 1 return None def _search_all_duplicate_keys( table: list[dict], key_field: str, target: Any, ) -> list[int]: """查找所有匹配的记录下标(处理重复键)。""" indices: list[int] = [] first = _search_all(table, key_field, target) if first is None: return [] # 向前扫描 i = first while i >= 0 and table[i][key_field] == target: indices.append(i) i -= 1 indices.reverse() # 向后扫描 i = first + 1 while i < len(table) and table[i][key_field] == target: indices.append(i) i += 1 return indices # ── 测试: CALL ── class TestCallByReference: """CALL BY REFERENCE 参数传递""" def test_by_reference_modifies_original(self): data = [5] result = _call_by_reference(data) assert data[0] == 10, "BY REFERENCE 应修改原始值" assert result == [10] def test_by_reference_string(self): data = ["hello"] _call_by_reference(data) assert data[0] == "hellohello" class TestCallByValue: """CALL BY VALUE 参数传递""" def test_by_value_no_side_effect(self): x = 5 result = _call_by_value(x) assert x == 5, "BY VALUE 不应修改原始值" assert result == 10 def test_by_value_zero(self): assert _call_by_value(0) == 0 def test_by_value_negative(self): assert _call_by_value(-3) == -6 class TestCallByContent: """CALL BY CONTENT 参数传递""" def test_by_content_preserves_original(self): data = [5] result = _call_by_content(data) assert data[0] == 5, "BY CONTENT 不应修改原始值" assert result == [10] class TestCallMultipleParameters: """多参数 CALL""" def test_multiple_params(self): result = _call_with_multiple(3, 4) assert result["sum"] == 7 def test_multiple_params_with_string(self): result = _call_with_multiple(1, 2, c="ab") assert result["sum"] == 3 assert result["concat"] == "abab" def test_multiple_params_default(self): result = _call_with_multiple(10, 20) assert result["concat"] == "" # ── 测试: SEARCH ALL ── class TestSearchAllFound: """SEARCH ALL — 找到""" def test_search_found_first(self): table = [{"K": 1}, {"K": 3}, {"K": 5}, {"K": 7}] idx = _search_all(table, "K", 1) assert idx == 0 def test_search_found_last(self): table = [{"K": 1}, {"K": 3}, {"K": 5}, {"K": 7}] idx = _search_all(table, "K", 7) assert idx == 3 def test_search_found_middle(self): table = [{"K": 1}, {"K": 3}, {"K": 5}, {"K": 7}] idx = _search_all(table, "K", 5) assert idx == 2 def test_search_string_keys(self): table = [{"K": "a"}, {"K": "b"}, {"K": "c"}, {"K": "d"}] idx = _search_all(table, "K", "c") assert idx == 2 class TestSearchAllNotFound: """SEARCH ALL — 未找到""" def test_search_not_found(self): table = [{"K": 1}, {"K": 3}, {"K": 5}] idx = _search_all(table, "K", 4) assert idx is None def test_search_below_all(self): table = [{"K": 10}, {"K": 20}] idx = _search_all(table, "K", 5) assert idx is None def test_search_above_all(self): table = [{"K": 10}, {"K": 20}] idx = _search_all(table, "K", 25) assert idx is None class TestSearchAllDuplicateKeys: """SEARCH ALL — 重复键""" def test_search_duplicate_keys(self): table = [{"K": 1}, {"K": 2}, {"K": 2}, {"K": 2}, {"K": 3}] indices = _search_all_duplicate_keys(table, "K", 2) assert indices == [1, 2, 3] def test_search_no_duplicate(self): table = [{"K": 1}, {"K": 2}, {"K": 3}] indices = _search_all_duplicate_keys(table, "K", 2) assert indices == [1] class TestSearchAllEdgeCases: """SEARCH ALL — 边界""" def test_search_empty_table(self): idx = _search_all([], "K", 1) assert idx is None def test_search_single_element_found(self): table = [{"K": 42}] idx = _search_all(table, "K", 42) assert idx == 0 def test_search_single_element_not_found(self): table = [{"K": 42}] idx = _search_all(table, "K", 99) assert idx is None