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
|
"""
The Files explorer in the Search view is not merged, and must not become so.
The Search view folds a file several groups share into one entry, so a film
shared by two groups is one poster instead of two. The Files tab is the one
place where that would be wrong: there each group is a top-level folder, the
two copies live in two different folders, and walking into one is how a member
browses *that group*. Merging would silently delete one of the two branches of
the tree.
This is the guarantee a later refactor is most likely to break — the four entry
lists in `search-page.js` are near-identical, and tidying them into one shared
builder is the obvious cleanup. It would also be the last thing anyone tests by
hand, because the Files tab looks unchanged until you notice a group's folder
has fewer files in it than the group does.
So: read the source, and refuse a build where `fileEntries` goes through the
merge. Weak evidence, and the only kind available for the SPA — but the failure
it guards against is a one-line edit, which is exactly what a source-reading
test catches well.
See docs/MESHBAY_DESIGN.md §9.11.
"""
import re
from pathlib import Path
import pytest
STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static"
SEARCH_PAGE = STATIC / "search-page.js"
pytestmark = pytest.mark.skipif(
not SEARCH_PAGE.exists(), reason="the SPA sources are not available")
MERGE_CALL = "mergeUnitEntries"
def _memo(name):
"""The body of `const <name> = useMemo(() => { ... }, [...]);`."""
src = SEARCH_PAGE.read_text()
m = re.search(
r"^ const " + re.escape(name) + r" = useMemo\(\(\) => \{.*?^ \}, \[.*?\]\);",
src, re.M | re.S)
assert m, (
f"{name} is no longer a useMemo where this test reads it — the Files "
"explorer's exemption from the merge is untested until this is fixed")
return m.group(0)
def test_the_files_list_is_not_merged():
body = _memo("fileEntries")
assert MERGE_CALL not in body, (
"fileEntries now goes through the source merge. The Files explorer "
"shows one folder per group and a member navigates into it; merging "
"two groups' copies of a file would remove it from one of those "
"folders. See docs/MESHBAY_DESIGN.md §9.11")
@pytest.mark.parametrize("name", ["videoEntries", "musicEntries", "photoEntries"])
def test_the_media_lists_are_merged(name):
"""
The other half of the check. Without it, deleting the merge outright would
leave the test above passing and saying nothing.
"""
assert MERGE_CALL in _memo(name), (
f"{name} no longer goes through the source merge — a file shared by "
"two groups is two entries again")
def test_the_files_list_still_carries_one_group_per_entry():
"""
What makes the explorer work: the path is prefixed with the group's name,
so the top level of the tree is the set of groups. A merged entry could not
be prefixed with anything, having several.
"""
body = _memo("fileEntries")
assert "data.groupName + (e.path ? '/' + e.path : '')" in body, (
"fileEntries no longer prefixes paths with the group name — the "
"explorer's per-group top level is what this whole exemption is for")
|