/ tests / hermes_cli / test_memory_reset.py
test_memory_reset.py
  1  """Tests for the `hermes memory reset` CLI command.
  2  
  3  Covers:
  4  - Reset both stores (MEMORY.md + USER.md)
  5  - Reset individual stores (--target memory / --target user)
  6  - Skip confirmation with --yes
  7  - Graceful handling when no memory files exist
  8  - Profile-scoped reset (uses HERMES_HOME)
  9  """
 10  
 11  import os
 12  import pytest
 13  from argparse import Namespace
 14  from pathlib import Path
 15  
 16  
 17  @pytest.fixture
 18  def memory_env(tmp_path, monkeypatch):
 19      """Set up a fake HERMES_HOME with memory files."""
 20      hermes_home = tmp_path / ".hermes"
 21      memories = hermes_home / "memories"
 22      memories.mkdir(parents=True)
 23      monkeypatch.setenv("HERMES_HOME", str(hermes_home))
 24  
 25      # Create sample memory files
 26      (memories / "MEMORY.md").write_text(
 27          "§\nHermes repo is at ~/.hermes/hermes-agent\n§\nUser prefers dark themes",
 28          encoding="utf-8",
 29      )
 30      (memories / "USER.md").write_text(
 31          "§\nUser is Teknium\n§\nTimezone: US Pacific",
 32          encoding="utf-8",
 33      )
 34      return hermes_home, memories
 35  
 36  
 37  def _run_memory_reset(target="all", yes=False, monkeypatch=None, confirm_input="no"):
 38      """Invoke the memory reset logic from cmd_memory in main.py.
 39  
 40      Simulates what happens when `hermes memory reset` is run.
 41      """
 42      from hermes_constants import get_hermes_home, display_hermes_home
 43  
 44      mem_dir = get_hermes_home() / "memories"
 45      files_to_reset = []
 46      if target in ("all", "memory"):
 47          files_to_reset.append(("MEMORY.md", "agent notes"))
 48      if target in ("all", "user"):
 49          files_to_reset.append(("USER.md", "user profile"))
 50  
 51      existing = [(f, desc) for f, desc in files_to_reset if (mem_dir / f).exists()]
 52      if not existing:
 53          return "nothing"
 54  
 55      if not yes:
 56          if confirm_input != "yes":
 57              return "cancelled"
 58  
 59      for f, desc in existing:
 60          (mem_dir / f).unlink()
 61  
 62      return "deleted"
 63  
 64  
 65  class TestMemoryReset:
 66      """Tests for `hermes memory reset` subcommand."""
 67  
 68      def test_reset_all_with_yes_flag(self, memory_env):
 69          """--yes flag should skip confirmation and delete both files."""
 70          hermes_home, memories = memory_env
 71          assert (memories / "MEMORY.md").exists()
 72          assert (memories / "USER.md").exists()
 73  
 74          result = _run_memory_reset(target="all", yes=True)
 75          assert result == "deleted"
 76          assert not (memories / "MEMORY.md").exists()
 77          assert not (memories / "USER.md").exists()
 78  
 79      def test_reset_memory_only(self, memory_env):
 80          """--target memory should only delete MEMORY.md."""
 81          hermes_home, memories = memory_env
 82  
 83          result = _run_memory_reset(target="memory", yes=True)
 84          assert result == "deleted"
 85          assert not (memories / "MEMORY.md").exists()
 86          assert (memories / "USER.md").exists()
 87  
 88      def test_reset_user_only(self, memory_env):
 89          """--target user should only delete USER.md."""
 90          hermes_home, memories = memory_env
 91  
 92          result = _run_memory_reset(target="user", yes=True)
 93          assert result == "deleted"
 94          assert (memories / "MEMORY.md").exists()
 95          assert not (memories / "USER.md").exists()
 96  
 97      def test_reset_no_files_exist(self, tmp_path, monkeypatch):
 98          """Should return 'nothing' when no memory files exist."""
 99          hermes_home = tmp_path / ".hermes"
100          (hermes_home / "memories").mkdir(parents=True)
101          monkeypatch.setenv("HERMES_HOME", str(hermes_home))
102  
103          result = _run_memory_reset(target="all", yes=True)
104          assert result == "nothing"
105  
106      def test_reset_confirmation_denied(self, memory_env):
107          """Without --yes and without typing 'yes', should be cancelled."""
108          hermes_home, memories = memory_env
109  
110          result = _run_memory_reset(target="all", yes=False, confirm_input="no")
111          assert result == "cancelled"
112          # Files should still exist
113          assert (memories / "MEMORY.md").exists()
114          assert (memories / "USER.md").exists()
115  
116      def test_reset_confirmation_accepted(self, memory_env):
117          """Typing 'yes' should proceed with deletion."""
118          hermes_home, memories = memory_env
119  
120          result = _run_memory_reset(target="all", yes=False, confirm_input="yes")
121          assert result == "deleted"
122          assert not (memories / "MEMORY.md").exists()
123          assert not (memories / "USER.md").exists()
124  
125      def test_reset_profile_scoped(self, tmp_path, monkeypatch):
126          """Reset should work on the active profile's HERMES_HOME."""
127          profile_home = tmp_path / "profiles" / "myprofile"
128          memories = profile_home / "memories"
129          memories.mkdir(parents=True)
130          (memories / "MEMORY.md").write_text("profile memory", encoding="utf-8")
131          (memories / "USER.md").write_text("profile user", encoding="utf-8")
132          monkeypatch.setenv("HERMES_HOME", str(profile_home))
133  
134          result = _run_memory_reset(target="all", yes=True)
135          assert result == "deleted"
136          assert not (memories / "MEMORY.md").exists()
137          assert not (memories / "USER.md").exists()
138  
139      def test_reset_partial_files(self, memory_env):
140          """Reset should work when only one memory file exists."""
141          hermes_home, memories = memory_env
142          (memories / "USER.md").unlink()
143  
144          result = _run_memory_reset(target="all", yes=True)
145          assert result == "deleted"
146          assert not (memories / "MEMORY.md").exists()
147  
148      def test_reset_empty_memories_dir(self, tmp_path, monkeypatch):
149          """No memories dir at all should report nothing."""
150          hermes_home = tmp_path / ".hermes"
151          hermes_home.mkdir(parents=True)
152          # No memories dir
153          monkeypatch.setenv("HERMES_HOME", str(hermes_home))
154  
155          # The memories dir won't exist; get_hermes_home() / "memories" won't have files
156          result = _run_memory_reset(target="all", yes=True)
157          assert result == "nothing"