1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
# SPDX-FileCopyrightText: 2024-present Hinrich Mahler <chango@mahlerhome.de>
#
# SPDX-License-Identifier: MIT
import pytest
import shortuuid
from chango.concrete.sections import (
GitHubSectionChangeNote,
PullRequest,
Section,
SectionChangeNote,
)
from chango.constants import MarkupLanguage
from chango.error import ValidationError
class DummyChangNote(
GitHubSectionChangeNote.with_sections(
[
Section(uid="req_section", title="Required Section", is_required=True),
Section(uid="opt_section", title="Optional Section"),
]
)
):
OWNER = "my-username"
REPOSITORY = "my-repo"
@pytest.fixture
def section_change_note():
return DummyChangNote(
slug="slug",
req_section="req 𝛙𝌢𑁍",
opt_section="opt 𝛙𝌢𑁍",
pull_requests=(
PullRequest(uid="uid1", closes_threads=("thread1",), author_uids=("author1",)),
PullRequest(uid="uid2", closes_threads=("thread2",), author_uids=("author2",)),
),
)
class TestSectionChangeNote:
"""Since TestSectionChangeNote is an abstract base class, we are testing with
GitHubTestSectionChangeNote as a simple implementation.
Note that we do *not* test abstract methods, as that is the responsibility of the concrete
implementations.
"""
sections = (
Section(uid="req_section", title="Required Section", is_required=True),
Section(uid="opt_section", title="Optional Section"),
)
def test_manual_subclass(self):
class SubClass(SectionChangeNote):
@classmethod
def get_pull_request_url(cls, pr_uid: str) -> str:
pass
@classmethod
def get_thread_url(cls, thread_uid: str) -> str:
pass
@classmethod
def get_author_url(cls, author_uid: str) -> str:
pass
with pytest.raises(TypeError, match="SectionChangeNote must not be subclassed manually"):
SubClass(slug="slug")
@pytest.mark.parametrize("name", [None, "CustomName"])
def test_with_sections(self, name):
cls = SectionChangeNote.with_sections(self.sections, name=name)
assert cls.SECTIONS["req_section"] is self.sections[0]
assert cls.SECTIONS["opt_section"] is self.sections[1]
assert cls.__name__ == (name or "DynamicSectionChangeNote")
def test_with_sections_empty_sequence(self):
with pytest.raises(ValueError, match="Class must have at least one section"):
SectionChangeNote.with_sections([])
def test_empty_init(self):
cls = GitHubSectionChangeNote.with_sections(
[Section(uid=f"opt_{i}", title=f"Optional {i}") for i in range(10)]
)
with pytest.raises(ValidationError, match="At least one section must be specified"):
cls(slug="slug", opt_0="", opt_1=None)
def test_constants(self, section_change_note):
assert section_change_note.file_extension == "toml"
assert section_change_note.MARKUP == MarkupLanguage.RESTRUCTUREDTEXT
@pytest.mark.parametrize("has_prs", [True, False])
def test_from_string(self, section_change_note, has_prs):
string = """
req_section = '''Required section.
With multiple lines.'''
opt_section = "Optional Section."
"""
if has_prs:
string += """
[[pull_requests]]
uid = "uid1"
closes_threads = ["thread1", "thread2"]
author_uids = ["author1"]
[[pull_requests]]
uid = "uid2"
closes_threads = ["thread3"]
author_uid = ["author2"]
"""
change_note = section_change_note.from_string("slug", "uid", string)
assert change_note.slug == "slug"
assert change_note.uid == "uid"
assert change_note.req_section == "Required section.\nWith multiple lines."
assert change_note.opt_section == "Optional Section."
if has_prs:
assert len(change_note.pull_requests) == 2 # noqa: PLR2004
assert change_note.pull_requests[0].uid == "uid1"
assert change_note.pull_requests[0].closes_threads == ("thread1", "thread2")
assert change_note.pull_requests[0].author_uids == ("author1",)
assert change_note.pull_requests[1].uid == "uid2"
assert change_note.pull_requests[1].closes_threads == ("thread3",)
assert change_note.pull_requests[1].author_uids == ("author2",)
else:
assert change_note.pull_requests == ()
def test_from_string_invalid(self, section_change_note):
with pytest.raises(ValidationError, match="Invalid TOML data"):
section_change_note.from_string("slug", "uid", "invalid toml")
@pytest.mark.parametrize("encoding", ["utf-8", "utf-16"])
def test_to_string(self, section_change_note, encoding):
string = section_change_note.to_string(encoding=encoding)
assert (
string
== """req_section = "req 𝛙𝌢𑁍"
opt_section = "opt 𝛙𝌢𑁍"
[[pull_requests]]
uid = "uid1"
author_uids = ["author1"]
closes_threads = ["thread1"]
[[pull_requests]]
uid = "uid2"
author_uids = ["author2"]
closes_threads = ["thread2"]
"""
)
@pytest.mark.parametrize("uid", ["uid1", None])
def test_build_template(self, uid):
change_note = DummyChangNote.build_template("slug", uid)
assert change_note.req_section == "Required Section Content"
assert change_note.opt_section == "Optional Section Content"
assert change_note.pull_requests == (
PullRequest(
uid="pr-number-1", closes_threads=("thread1", "thread2"), author_uids=("author1",)
),
PullRequest(uid="pr-number-2", closes_threads=("thread3",), author_uids=("author2",)),
)
assert change_note.slug == "slug"
if uid:
assert change_note.uid == "uid1"
else:
assert isinstance(change_note.uid, str)
assert len(change_note.uid) == len(shortuuid.ShortUUID().uuid())
|