Skip to content

Commit ed81b20

Browse files
castlerCopilot
andcommitted
[rules score] add unit tests for AoU forwarding tool
Test the aou_forwarding_to_lobster filter logic: - Filtering by AoU ID from forwarding YAML - Error on non-existent AoU ID - Versioned tag matching (req Pkg.Name@1 matches aou_id Pkg.Name) - Full versioned ID matching Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 325566b commit ed81b20

2 files changed

Lines changed: 184 additions & 0 deletions

File tree

bazel/rules/rules_score/test/BUILD

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,13 @@ py_test(
751751
deps = ["//bazel/rules/rules_score:safety_analysis_tools"],
752752
)
753753

754+
py_test(
755+
name = "test_aou_forwarding_to_lobster",
756+
size = "small",
757+
srcs = ["test_aou_forwarding_to_lobster.py"],
758+
deps = ["//bazel/rules/rules_score:aou_forwarding_to_lobster"],
759+
)
760+
754761
py_test(
755762
name = "test_rst_to_trlc",
756763
size = "small",
@@ -779,6 +786,7 @@ test_suite(
779786
":requirements_rst_tests",
780787
":seooc_tests",
781788
":sphinx_module_tests",
789+
":test_aou_forwarding_to_lobster",
782790
":test_rst_to_trlc",
783791
":test_safety_analysis_tools",
784792
":test_trlc_rst_image_rendering",
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# *******************************************************************************
2+
# Copyright (c) 2026 Contributors to the Eclipse Foundation
3+
#
4+
# See the NOTICE file(s) distributed with this work for additional
5+
# information regarding copyright ownership.
6+
#
7+
# This program and the accompanying materials are made available under the
8+
# terms of the Apache License Version 2.0 which is available at
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# SPDX-License-Identifier: Apache-2.0
12+
# *******************************************************************************
13+
"""Tests for aou_forwarding_to_lobster."""
14+
15+
import json
16+
import tempfile
17+
import unittest
18+
from pathlib import Path
19+
20+
import yaml
21+
22+
from aou_forwarding_to_lobster import (
23+
create_lobster_output,
24+
filter_forwarded_aous,
25+
load_lobster_items,
26+
parse_forwarding_yaml,
27+
)
28+
29+
30+
class TestParseForwardingYaml(unittest.TestCase):
31+
"""Tests for parse_forwarding_yaml."""
32+
33+
def _write_yaml(self, data: dict) -> str:
34+
f = tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False)
35+
yaml.dump(data, f)
36+
f.close()
37+
return f.name
38+
39+
def test_valid_yaml(self) -> None:
40+
path = self._write_yaml({
41+
"forwarded_aous": [
42+
{"aou_id": "Pkg.AoU1", "justification": "reason"},
43+
]
44+
})
45+
result = parse_forwarding_yaml(path)
46+
self.assertEqual(len(result), 1)
47+
self.assertEqual(result[0]["aou_id"], "Pkg.AoU1")
48+
self.assertEqual(result[0]["justification"], "reason")
49+
50+
def test_missing_forwarded_aous_key(self) -> None:
51+
path = self._write_yaml({"wrong_key": []})
52+
with self.assertRaises(SystemExit):
53+
parse_forwarding_yaml(path)
54+
55+
def test_missing_aou_id(self) -> None:
56+
path = self._write_yaml({"forwarded_aous": [{"justification": "r"}]})
57+
with self.assertRaises(SystemExit):
58+
parse_forwarding_yaml(path)
59+
60+
def test_missing_justification(self) -> None:
61+
path = self._write_yaml({"forwarded_aous": [{"aou_id": "Foo.Bar"}]})
62+
with self.assertRaises(SystemExit):
63+
parse_forwarding_yaml(path)
64+
65+
def test_multiple_entries(self) -> None:
66+
path = self._write_yaml({
67+
"forwarded_aous": [
68+
{"aou_id": "A.B", "justification": "r1"},
69+
{"aou_id": "C.D", "justification": "r2"},
70+
]
71+
})
72+
result = parse_forwarding_yaml(path)
73+
self.assertEqual(len(result), 2)
74+
75+
76+
class TestLoadLobsterItems(unittest.TestCase):
77+
"""Tests for load_lobster_items."""
78+
79+
def _write_lobster(self, items: list) -> str:
80+
data = {"schema": "lobster-req-trace", "version": 3, "generator": "test", "data": items}
81+
f = tempfile.NamedTemporaryFile(mode="w", suffix=".lobster", delete=False)
82+
json.dump(data, f)
83+
f.close()
84+
return f.name
85+
86+
def test_loads_items(self) -> None:
87+
items = [
88+
{"tag": "req Pkg.AoU1", "name": "AoU1"},
89+
{"tag": "req Pkg.AoU2", "name": "AoU2"},
90+
]
91+
path = self._write_lobster(items)
92+
loaded = load_lobster_items([path])
93+
self.assertEqual(len(loaded), 2)
94+
self.assertEqual(loaded[0]["tag"], "req Pkg.AoU1")
95+
96+
def test_multiple_files(self) -> None:
97+
path1 = self._write_lobster([{"tag": "req A.B", "name": "B"}])
98+
path2 = self._write_lobster([{"tag": "req C.D", "name": "D"}])
99+
loaded = load_lobster_items([path1, path2])
100+
self.assertEqual(len(loaded), 2)
101+
102+
def test_empty_data(self) -> None:
103+
path = self._write_lobster([])
104+
loaded = load_lobster_items([path])
105+
self.assertEqual(loaded, [])
106+
107+
108+
class TestFilterForwardedAous(unittest.TestCase):
109+
"""Tests for filter_forwarded_aous."""
110+
111+
def test_filters_correctly(self) -> None:
112+
items = [
113+
{"tag": "req Pkg.AoU1", "name": "AoU1"},
114+
{"tag": "req Pkg.AoU2", "name": "AoU2"},
115+
]
116+
entries = [{"aou_id": "Pkg.AoU1", "justification": "reason"}]
117+
filtered = filter_forwarded_aous(entries, items)
118+
self.assertEqual(len(filtered), 1)
119+
self.assertEqual(filtered[0]["tag"], "req Pkg.AoU1")
120+
121+
def test_multiple_filters(self) -> None:
122+
items = [
123+
{"tag": "req A.B", "name": "B"},
124+
{"tag": "req C.D", "name": "D"},
125+
{"tag": "req E.F", "name": "F"},
126+
]
127+
entries = [
128+
{"aou_id": "A.B", "justification": "r1"},
129+
{"aou_id": "E.F", "justification": "r2"},
130+
]
131+
filtered = filter_forwarded_aous(entries, items)
132+
self.assertEqual(len(filtered), 2)
133+
134+
def test_nonexistent_aou_id_raises(self) -> None:
135+
items = [{"tag": "req Pkg.AoU1", "name": "AoU1"}]
136+
entries = [{"aou_id": "NonExistent.Foo", "justification": "reason"}]
137+
with self.assertRaises(SystemExit):
138+
filter_forwarded_aous(entries, items)
139+
140+
def test_versioned_tag_matches_base_id(self) -> None:
141+
"""lobster-trlc generates versioned tags like 'req Pkg.Name@1'."""
142+
items = [
143+
{"tag": "req Pkg.AoU1@1", "name": "AoU1"},
144+
{"tag": "req Pkg.AoU2@3", "name": "AoU2"},
145+
]
146+
entries = [{"aou_id": "Pkg.AoU1", "justification": "reason"}]
147+
filtered = filter_forwarded_aous(entries, items)
148+
self.assertEqual(len(filtered), 1)
149+
self.assertEqual(filtered[0]["tag"], "req Pkg.AoU1@1")
150+
151+
def test_versioned_tag_matches_full_id(self) -> None:
152+
"""Full versioned ID should also work."""
153+
items = [{"tag": "req Pkg.AoU1@2", "name": "AoU1"}]
154+
entries = [{"aou_id": "Pkg.AoU1@2", "justification": "reason"}]
155+
filtered = filter_forwarded_aous(entries, items)
156+
self.assertEqual(len(filtered), 1)
157+
158+
159+
class TestCreateLobsterOutput(unittest.TestCase):
160+
"""Tests for create_lobster_output."""
161+
162+
def test_wraps_items(self) -> None:
163+
items = [{"tag": "req Foo.Bar", "name": "Bar"}]
164+
output = create_lobster_output(items)
165+
self.assertEqual(output["schema"], "lobster-req-trace")
166+
self.assertEqual(output["version"], 3)
167+
self.assertEqual(output["generator"], "aou_forwarding_to_lobster")
168+
self.assertEqual(output["data"], items)
169+
170+
def test_empty_items(self) -> None:
171+
output = create_lobster_output([])
172+
self.assertEqual(output["data"], [])
173+
174+
175+
if __name__ == "__main__":
176+
unittest.main()

0 commit comments

Comments
 (0)