mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-10-17 00:58:57 +08:00
188 lines
5.1 KiB
Python
188 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2026, RT-Thread Development Team
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
import unittest
|
|
|
|
import issue_labeler
|
|
|
|
|
|
def make_event(body, labels=(), action="opened"):
|
|
return {
|
|
"action": action,
|
|
"repository": {"full_name": "RT-Thread/rt-thread"},
|
|
"issue": {
|
|
"number": 42,
|
|
"body": body,
|
|
"labels": [{"name": label} for label in labels],
|
|
},
|
|
}
|
|
|
|
|
|
class FakeClient:
|
|
def __init__(self, available_labels, current_issue=None):
|
|
self.available_labels = [{"name": label} for label in available_labels]
|
|
self.current_issue = current_issue
|
|
self.calls = []
|
|
|
|
def list_labels(self, repository):
|
|
self.calls.append(("list_labels", repository))
|
|
return self.available_labels
|
|
|
|
def add_labels(self, repository, issue_number, labels):
|
|
self.calls.append(("add_labels", repository, issue_number, tuple(labels)))
|
|
|
|
def get_issue(self, repository, issue_number):
|
|
self.calls.append(("get_issue", repository, issue_number))
|
|
return self.current_issue
|
|
|
|
def remove_label(self, repository, issue_number, label):
|
|
self.calls.append(("remove_label", repository, issue_number, label))
|
|
|
|
|
|
class FormParsingTests(unittest.TestCase):
|
|
def test_maps_only_structured_allowlisted_values(self):
|
|
body = """### Affected area
|
|
|
|
Device drivers
|
|
|
|
### Hardware/BSP vendor
|
|
|
|
STM32
|
|
|
|
### Architecture
|
|
|
|
ARM / AArch64
|
|
|
|
### Describe the bug
|
|
|
|
Mentions GD32 and RISC-V here, but free text must not add labels.
|
|
"""
|
|
self.assertEqual(
|
|
issue_labeler.desired_labels(body),
|
|
(
|
|
"Component",
|
|
"component: drivers",
|
|
"BSP",
|
|
"BSP: STM32",
|
|
"Arch: ARM/AArch64",
|
|
),
|
|
)
|
|
|
|
def test_unknown_and_no_response_values_are_ignored(self):
|
|
body = """### Affected area
|
|
|
|
Other / Not sure
|
|
|
|
### Hardware/BSP vendor
|
|
|
|
_No response_
|
|
|
|
### Architecture
|
|
|
|
x86
|
|
"""
|
|
self.assertEqual(issue_labeler.desired_labels(body), ())
|
|
|
|
def test_headings_and_values_are_case_insensitive(self):
|
|
body = "### AFFECTED AREA\n\nnetworking\n\n### Architecture\n\nrisc-v\n"
|
|
self.assertEqual(
|
|
issue_labeler.desired_labels(body),
|
|
("Component", "component: net", "Arch: RISC-V"),
|
|
)
|
|
|
|
|
|
class EventTests(unittest.TestCase):
|
|
def test_accepts_supported_issue_actions(self):
|
|
context = issue_labeler.event_context(make_event("", action="edited"))
|
|
self.assertEqual(context.issue_number, 42)
|
|
|
|
def test_rejects_pull_requests_and_other_actions(self):
|
|
pull_request = make_event("")
|
|
pull_request["issue"]["pull_request"] = {"url": "https://example.test"}
|
|
self.assertIsNone(issue_labeler.event_context(pull_request))
|
|
self.assertIsNone(
|
|
issue_labeler.event_context(make_event("", action="closed"))
|
|
)
|
|
|
|
|
|
class LabelApplicationTests(unittest.TestCase):
|
|
def test_adds_only_existing_labels_and_preserves_current_labels(self):
|
|
body = """### Affected area
|
|
|
|
Kernel
|
|
|
|
### Hardware/BSP vendor
|
|
|
|
GD32
|
|
"""
|
|
context = issue_labeler.event_context(
|
|
make_event(body, labels=("Kernel", "bug"))
|
|
)
|
|
client = FakeClient(("Kernel", "BSP", "bug"))
|
|
|
|
result = issue_labeler.apply_labels(client, context)
|
|
|
|
self.assertEqual(result["added"], ["BSP"])
|
|
self.assertEqual(result["missing"], ["BSP: GD32"])
|
|
self.assertIn(
|
|
("add_labels", "RT-Thread/rt-thread", 42, ("BSP",)), client.calls
|
|
)
|
|
|
|
def test_replaces_stale_vendor_and_architecture_labels(self):
|
|
body = """### Hardware/BSP vendor
|
|
|
|
NXP
|
|
|
|
### Architecture
|
|
|
|
RISC-V
|
|
"""
|
|
context = issue_labeler.event_context(
|
|
make_event(
|
|
body,
|
|
labels=("bug", "BSP", "BSP: STM32", "Arch: ARM/AArch64"),
|
|
)
|
|
)
|
|
client = FakeClient(
|
|
(
|
|
"bug",
|
|
"BSP",
|
|
"BSP: STM32",
|
|
"BSP: NXP",
|
|
"Arch: ARM/AArch64",
|
|
"Arch: RISC-V",
|
|
),
|
|
current_issue=context.issue,
|
|
)
|
|
|
|
result = issue_labeler.apply_labels(client, context)
|
|
|
|
self.assertEqual(result["added"], ["BSP: NXP", "Arch: RISC-V"])
|
|
self.assertEqual(result["removed"], ["BSP: STM32", "Arch: ARM/AArch64"])
|
|
self.assertIn(
|
|
("remove_label", "RT-Thread/rt-thread", 42, "BSP: STM32"),
|
|
client.calls,
|
|
)
|
|
self.assertIn(
|
|
("remove_label", "RT-Thread/rt-thread", 42, "Arch: ARM/AArch64"),
|
|
client.calls,
|
|
)
|
|
|
|
def test_dry_run_reports_without_mutating(self):
|
|
body = "### Affected area\n\nDocumentation\n"
|
|
context = issue_labeler.event_context(make_event(body))
|
|
client = FakeClient(("Doc",))
|
|
|
|
result = issue_labeler.apply_labels(client, context, dry_run=True)
|
|
|
|
self.assertEqual(result["added"], ["Doc"])
|
|
self.assertFalse(any(call[0] == "add_labels" for call in client.calls))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|