perf(campaign): share linear collision-safe attachment naming
Release v0.1.29. Coordinated integrity review: GovOPlaN/govoplan-core#298.
This commit is contained in:
Executable
+75
@@ -0,0 +1,75 @@
|
||||
from pathlib import Path
|
||||
import random
|
||||
import unittest
|
||||
|
||||
from govoplan_campaign.backend.services.filenames import FilenameAllocator
|
||||
from govoplan_campaign.backend.services.zip_service import _normalized_members
|
||||
|
||||
|
||||
def legacy_names(names):
|
||||
used = set()
|
||||
result = []
|
||||
for name in names:
|
||||
path = Path(name)
|
||||
candidate = name
|
||||
counter = 2
|
||||
while candidate.casefold() in used:
|
||||
candidate = f"{path.stem} ({counter}){path.suffix}"
|
||||
counter += 1
|
||||
used.add(candidate.casefold())
|
||||
result.append(candidate)
|
||||
return result
|
||||
|
||||
|
||||
class FilenameAllocatorTests(unittest.TestCase):
|
||||
def test_exact_equivalence_with_colliding_suffixes_case_unicode_and_multiple_dots(
|
||||
self,
|
||||
):
|
||||
choices = [
|
||||
"report.pdf",
|
||||
"REPORT.PDF",
|
||||
"report (2).pdf",
|
||||
"report (3).pdf",
|
||||
"report (2) (2).pdf",
|
||||
".hidden",
|
||||
"a.tar.gz",
|
||||
"A.TAR.GZ",
|
||||
"Straße.txt",
|
||||
"STRASSE.txt",
|
||||
"readme",
|
||||
]
|
||||
rng = random.Random(42)
|
||||
for _ in range(30):
|
||||
names = [rng.choice(choices) for _ in range(200)]
|
||||
allocator = FilenameAllocator()
|
||||
self.assertEqual(
|
||||
legacy_names(names), [allocator.allocate(name) for name in names]
|
||||
)
|
||||
|
||||
def test_zip_and_message_names_preserve_every_input_and_sequence(self):
|
||||
names = ["a.pdf", "A.pdf", "a (2).pdf", "a.pdf"]
|
||||
paths = [Path(f"/synthetic/{index}/source") for index in range(len(names))]
|
||||
members = _normalized_members(list(zip(paths, names)))
|
||||
self.assertEqual(paths, [path for path, _ in members])
|
||||
self.assertEqual(legacy_names(names), [name for _, name in members])
|
||||
self.assertEqual("a.pdf", FilenameAllocator().allocate("a.pdf"))
|
||||
|
||||
def test_many_collisions_have_linear_membership_work(self):
|
||||
class CountingSet(set):
|
||||
probes = 0
|
||||
|
||||
def __contains__(self, item):
|
||||
self.probes += 1
|
||||
return super().__contains__(item)
|
||||
|
||||
allocator = FilenameAllocator()
|
||||
allocator.used = CountingSet()
|
||||
for _ in range(10000):
|
||||
last = allocator.allocate("report.pdf")
|
||||
self.assertEqual("report (10000).pdf", last)
|
||||
self.assertEqual(10000, len(allocator.used))
|
||||
self.assertEqual(19999, allocator.used.probes)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user