diff options
Diffstat (limited to 'packages/meshbay-cli/tests/test_remote_paths.py')
| -rw-r--r-- | packages/meshbay-cli/tests/test_remote_paths.py | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/packages/meshbay-cli/tests/test_remote_paths.py b/packages/meshbay-cli/tests/test_remote_paths.py new file mode 100644 index 0000000..5192e7b --- /dev/null +++ b/packages/meshbay-cli/tests/test_remote_paths.py @@ -0,0 +1,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" |