Skip to content

Commit 4de43f2

Browse files
castlerCopilot
authored 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 c2f67ee commit 4de43f2

2 files changed

Lines changed: 192 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: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
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+
19+
import yaml
20+
21+
from aou_forwarding_to_lobster import (
22+
create_lobster_output,
23+
filter_forwarded_aous,
24+
load_lobster_items,
25+
parse_forwarding_yaml,
26+
)
27+
28+
29+
class TestParseForwardingYaml(unittest.TestCase):
30+
"""Tests for parse_forwarding_yaml."""
31+
32+
def _write_yaml(self, data: dict) -> str:
33+
f = tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False)
34+
yaml.dump(data, f)
35+
f.close()
36+
return f.name
37+
38+
def test_valid_yaml(self) -> None:
39+
path = self._write_yaml(
40+
{
41+
"forwarded_aous": [
42+
{"aou_id": "Pkg.AoU1", "justification": "reason"},
43+
]
44+
}
45+
)
46+
result = parse_forwarding_yaml(path)
47+
self.assertEqual(len(result), 1)
48+
self.assertEqual(result[0]["aou_id"], "Pkg.AoU1")
49+
self.assertEqual(result[0]["justification"], "reason")
50+
51+
def test_missing_forwarded_aous_key(self) -> None:
52+
path = self._write_yaml({"wrong_key": []})
53+
with self.assertRaises(SystemExit):
54+
parse_forwarding_yaml(path)
55+
56+
def test_missing_aou_id(self) -> None:
57+
path = self._write_yaml({"forwarded_aous": [{"justification": "r"}]})
58+
with self.assertRaises(SystemExit):
59+
parse_forwarding_yaml(path)
60+
61+
def test_missing_justification(self) -> None:
62+
path = self._write_yaml({"forwarded_aous": [{"aou_id": "Foo.Bar"}]})
63+
with self.assertRaises(SystemExit):
64+
parse_forwarding_yaml(path)
65+
66+
def test_multiple_entries(self) -> None:
67+
path = self._write_yaml(
68+
{
69+
"forwarded_aous": [
70+
{"aou_id": "A.B", "justification": "r1"},
71+
{"aou_id": "C.D", "justification": "r2"},
72+
]
73+
}
74+
)
75+
result = parse_forwarding_yaml(path)
76+
self.assertEqual(len(result), 2)
77+
78+
79+
class TestLoadLobsterItems(unittest.TestCase):
80+
"""Tests for load_lobster_items."""
81+
82+
def _write_lobster(self, items: list) -> str:
83+
data = {
84+
"schema": "lobster-req-trace",
85+
"version": 3,
86+
"generator": "test",
87+
"data": items,
88+
}
89+
f = tempfile.NamedTemporaryFile(mode="w", suffix=".lobster", delete=False)
90+
json.dump(data, f)
91+
f.close()
92+
return f.name
93+
94+
def test_loads_items(self) -> None:
95+
items = [
96+
{"tag": "req Pkg.AoU1", "name": "AoU1"},
97+
{"tag": "req Pkg.AoU2", "name": "AoU2"},
98+
]
99+
path = self._write_lobster(items)
100+
loaded = load_lobster_items([path])
101+
self.assertEqual(len(loaded), 2)
102+
self.assertEqual(loaded[0]["tag"], "req Pkg.AoU1")
103+
104+
def test_multiple_files(self) -> None:
105+
path1 = self._write_lobster([{"tag": "req A.B", "name": "B"}])
106+
path2 = self._write_lobster([{"tag": "req C.D", "name": "D"}])
107+
loaded = load_lobster_items([path1, path2])
108+
self.assertEqual(len(loaded), 2)
109+
110+
def test_empty_data(self) -> None:
111+
path = self._write_lobster([])
112+
loaded = load_lobster_items([path])
113+
self.assertEqual(loaded, [])
114+
115+
116+
class TestFilterForwardedAous(unittest.TestCase):
117+
"""Tests for filter_forwarded_aous."""
118+
119+
def test_filters_correctly(self) -> None:
120+
items = [
121+
{"tag": "req Pkg.AoU1", "name": "AoU1"},
122+
{"tag": "req Pkg.AoU2", "name": "AoU2"},
123+
]
124+
entries = [{"aou_id": "Pkg.AoU1", "justification": "reason"}]
125+
filtered = filter_forwarded_aous(entries, items)
126+
self.assertEqual(len(filtered), 1)
127+
self.assertEqual(filtered[0]["tag"], "req Pkg.AoU1")
128+
129+
def test_multiple_filters(self) -> None:
130+
items = [
131+
{"tag": "req A.B", "name": "B"},
132+
{"tag": "req C.D", "name": "D"},
133+
{"tag": "req E.F", "name": "F"},
134+
]
135+
entries = [
136+
{"aou_id": "A.B", "justification": "r1"},
137+
{"aou_id": "E.F", "justification": "r2"},
138+
]
139+
filtered = filter_forwarded_aous(entries, items)
140+
self.assertEqual(len(filtered), 2)
141+
142+
def test_nonexistent_aou_id_raises(self) -> None:
143+
items = [{"tag": "req Pkg.AoU1", "name": "AoU1"}]
144+
entries = [{"aou_id": "NonExistent.Foo", "justification": "reason"}]
145+
with self.assertRaises(SystemExit):
146+
filter_forwarded_aous(entries, items)
147+
148+
def test_versioned_tag_matches_base_id(self) -> None:
149+
"""lobster-trlc generates versioned tags like 'req Pkg.Name@1'."""
150+
items = [
151+
{"tag": "req Pkg.AoU1@1", "name": "AoU1"},
152+
{"tag": "req Pkg.AoU2@3", "name": "AoU2"},
153+
]
154+
entries = [{"aou_id": "Pkg.AoU1", "justification": "reason"}]
155+
filtered = filter_forwarded_aous(entries, items)
156+
self.assertEqual(len(filtered), 1)
157+
self.assertEqual(filtered[0]["tag"], "req Pkg.AoU1@1")
158+
159+
def test_versioned_tag_matches_full_id(self) -> None:
160+
"""Full versioned ID should also work."""
161+
items = [{"tag": "req Pkg.AoU1@2", "name": "AoU1"}]
162+
entries = [{"aou_id": "Pkg.AoU1@2", "justification": "reason"}]
163+
filtered = filter_forwarded_aous(entries, items)
164+
self.assertEqual(len(filtered), 1)
165+
166+
167+
class TestCreateLobsterOutput(unittest.TestCase):
168+
"""Tests for create_lobster_output."""
169+
170+
def test_wraps_items(self) -> None:
171+
items = [{"tag": "req Foo.Bar", "name": "Bar"}]
172+
output = create_lobster_output(items)
173+
self.assertEqual(output["schema"], "lobster-req-trace")
174+
self.assertEqual(output["version"], 3)
175+
self.assertEqual(output["generator"], "aou_forwarding_to_lobster")
176+
self.assertEqual(output["data"], items)
177+
178+
def test_empty_items(self) -> None:
179+
output = create_lobster_output([])
180+
self.assertEqual(output["data"], [])
181+
182+
183+
if __name__ == "__main__":
184+
unittest.main()

0 commit comments

Comments
 (0)