"""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"