summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-cli/tests/test_remote_paths.py
blob: 5192e7b3a7e4966ac5f69b300575909cb4549064 (plain) (blame)
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
"""Remote paths and group handles — `docs/MESHBAY_DESIGN.md` §8.4, `group-link.js`."""

import pytest
from meshbay_cli.client.paths import encode_name, handle, parse, resolve_group
from meshbay_cli.errors import NOT_FOUND, USAGE, CliError

GROUPS = [
    {"id": "1", "name": "Family", "owner_username": "alice"},
    {"id": "2", "name": "Family", "owner_username": "bob"},
    {"id": "3", "name": "Some Saga/Box @Set", "owner_username": "alice"},
    {"id": "4", "name": "me@home", "owner_username": "carol"},
    {"id": "5", "name": "Work", "owner_username": "Dave"},
]


def test_nothing_or_a_slash_is_every_group():
    assert parse("") is None
    assert parse("/") is None


def test_a_typed_path_decodes_only_the_slash_and_the_percent():
    p = parse("Some Saga%2FBox @Set@alice/share/100% done.txt")
    assert p.group == "Some Saga/Box @Set@alice"
    assert p.parts == ["share", "100% done.txt"]
    assert parse("G/a%252Fb").parts == ["a%2Fb"]


def test_a_link_copied_from_the_application_is_decoded_in_full():
    p = parse("https://hub.example/#/Some%20Saga%2FBox%20@Set@alice/share/b%C3%A9b%C3%A9.jpg")
    assert p.from_link
    assert p.group == "Some Saga/Box @Set@alice"
    assert p.parts == ["share", "bébé.jpg"]


def test_dot_segments_are_refused():
    with pytest.raises(CliError) as e:
        parse("Family/share/../etc")
    assert e.value.code == USAGE


def test_names_are_nfc():
    decomposed = "été"
    assert parse(f"G/{decomposed}").parts == ["été"]


def test_the_owner_is_after_the_last_at():
    assert resolve_group(GROUPS, "Family@bob")["id"] == "2"
    assert resolve_group(GROUPS, "Some Saga/Box @Set@alice")["id"] == "3"
    assert resolve_group(GROUPS, "me@home@carol")["id"] == "4"


def test_a_name_with_an_at_of_its_own_still_resolves_without_owner():
    assert resolve_group(GROUPS, "me@home")["id"] == "4"


def test_names_and_owners_compare_without_case():
    assert resolve_group(GROUPS, "some saga/box @set")["id"] == "3"
    assert resolve_group(GROUPS, "work@dave")["id"] == "5"


def test_two_groups_of_one_name_ask_for_the_owner():
    with pytest.raises(CliError) as e:
        resolve_group(GROUPS, "Family")
    assert e.value.code == USAGE
    assert "Family@alice" in e.value.message and "Family@bob" in e.value.message


def test_an_unknown_group_is_not_found():
    with pytest.raises(CliError) as e:
        resolve_group(GROUPS, "Nope")
    assert e.value.code == NOT_FOUND


def test_a_handle_can_be_typed_back():
    for g in GROUPS:
        assert resolve_group(GROUPS, parse(handle(g)).group)["id"] == g["id"]
    assert encode_name("100%/x") == "100%25%2Fx"