"""Tests for ``muse path annotate`` — six-level and hub-scoped seven-level paths. Hub scoping (musehub#221) inserted a ``hub'`` segment between ``role'`` and ``index'``; this command must decode both shapes. """ from __future__ import annotations import json import pytest from muse.cli.commands.path_cmd import _annotate from muse.core.hdkeys import DOMAIN_IDENTITY, hub_index, muse_path from tests.cli_test_helper import CliRunner runner = CliRunner() class TestAnnotateSixLevel: def test_decodes_pre_hub_scoping_path(self) -> None: result = _annotate(muse_path(DOMAIN_IDENTITY)) assert result["purpose"] == "muse" assert result["domain"] == "muse/identity" assert result["entity_type"] == "human" assert result["role"] == "sign" assert result["hub_idx"] is None assert result["hub_scoped"] is False assert result["index"] == 0 class TestAnnotateSevenLevel: def test_decodes_hub_scoped_path(self) -> None: hub = hub_index("musehub.ai") result = _annotate(muse_path(DOMAIN_IDENTITY, hub=hub)) assert result["hub_idx"] == hub assert result["hub_scoped"] is True assert result["index"] == 0 def test_preserves_other_fields_when_hub_scoped(self) -> None: from muse.core.hdkeys import ENTITY_AGENT, ROLE_ATTEST hub = hub_index("staging.musehub.ai") result = _annotate(muse_path(DOMAIN_IDENTITY, ENTITY_AGENT, 3, ROLE_ATTEST, 2, hub=hub)) assert result["entity_type"] == "agent" assert result["entity_id"] == 3 assert result["role"] == "attest" assert result["hub_idx"] == hub assert result["index"] == 2 class TestAnnotateMalformed: def test_five_segments_raises(self) -> None: with pytest.raises(ValueError, match="Cannot parse path"): _annotate("m/1075233755'/0'/0'/0'/0'") def test_eight_segments_raises(self) -> None: with pytest.raises(ValueError, match="Cannot parse path"): _annotate("m/1075233755'/0'/0'/0'/0'/0'/0'/0'") def test_garbage_raises(self) -> None: with pytest.raises(ValueError, match="Cannot parse path"): _annotate("not-a-path") def test_empty_raises(self) -> None: with pytest.raises(ValueError, match="Cannot parse path"): _annotate("") class TestAnnotateCli: def test_cli_json_six_level(self) -> None: result = runner.invoke( None, ["path", "annotate", muse_path(DOMAIN_IDENTITY), "--json"] ) assert result.exit_code == 0, result.output data = json.loads(result.output) assert data["hub_scoped"] is False assert data["hub_idx"] is None def test_cli_json_seven_level(self) -> None: hub = hub_index("musehub.ai") path = muse_path(DOMAIN_IDENTITY, hub=hub) result = runner.invoke(None, ["path", "annotate", path, "--json"]) assert result.exit_code == 0, result.output data = json.loads(result.output) assert data["hub_scoped"] is True assert data["hub_idx"] == hub def test_cli_text_output_includes_hub_line_when_scoped(self) -> None: hub = hub_index("musehub.ai") path = muse_path(DOMAIN_IDENTITY, hub=hub) result = runner.invoke(None, ["path", "annotate", path]) assert result.exit_code == 0, result.output assert f"hub: {hub}" in result.output def test_cli_text_output_omits_hub_line_when_not_scoped(self) -> None: result = runner.invoke(None, ["path", "annotate", muse_path(DOMAIN_IDENTITY)]) assert result.exit_code == 0, result.output assert "hub:" not in result.output def test_cli_malformed_path_exits_nonzero(self) -> None: result = runner.invoke(None, ["path", "annotate", "garbage"]) assert result.exit_code != 0