1+ """Tests for database CLI commands."""
2+
3+ from pathlib import Path
4+ from unittest .mock import patch , AsyncMock , MagicMock
5+
6+ from typer .testing import CliRunner
7+
8+ from basic_memory .cli .main import app as cli_app
9+
10+
11+ def test_reset_command_clears_project_configuration (config_manager , app_config ):
12+ """Test that the reset command clears project configuration to defaults."""
13+ runner = CliRunner ()
14+
15+ # Set up initial configuration with multiple projects
16+ config_manager .config .projects = {
17+ "project1" : "/path/to/project1" ,
18+ "project2" : "/path/to/project2" ,
19+ "test-project" : "/path/to/test"
20+ }
21+ config_manager .config .default_project = "project1"
22+
23+ # Mock the confirmation to return True (user confirms reset)
24+ with patch ("basic_memory.cli.commands.db.typer.confirm" , return_value = True ):
25+ # Mock the database file existence check and deletion
26+ with patch ("pathlib.Path.exists" , return_value = True ):
27+ with patch ("pathlib.Path.unlink" ) as mock_unlink :
28+ # Mock the async db.run_migrations function
29+ with patch ("basic_memory.cli.commands.db.asyncio.run" ) as mock_run :
30+ mock_run .return_value = None
31+
32+ # Run the reset command
33+ result = runner .invoke (cli_app , ["db" , "reset" ])
34+
35+ # Should exit successfully
36+ assert result .exit_code == 0
37+
38+ # Database file should be deleted
39+ mock_unlink .assert_called_once ()
40+
41+ # Async migrations should be called
42+ mock_run .assert_called_once ()
43+
44+ # Configuration should be reset to defaults
45+ expected_projects = {"main" : str (Path .home () / "basic-memory" )}
46+ assert config_manager .config .projects == expected_projects
47+ assert config_manager .config .default_project == "main"
48+
49+
50+ def test_reset_command_user_cancels (config_manager ):
51+ """Test that the reset command does nothing when user cancels."""
52+ runner = CliRunner ()
53+
54+ # Set up initial configuration
55+ original_projects = {
56+ "project1" : "/path/to/project1" ,
57+ "project2" : "/path/to/project2"
58+ }
59+ config_manager .config .projects = original_projects .copy ()
60+ config_manager .config .default_project = "project1"
61+
62+ # Mock the confirmation to return False (user cancels)
63+ with patch ("basic_memory.cli.commands.db.typer.confirm" , return_value = False ):
64+ with patch ("pathlib.Path.unlink" ) as mock_unlink :
65+ with patch ("basic_memory.cli.commands.db.asyncio.run" ) as mock_run :
66+ # Run the reset command
67+ result = runner .invoke (cli_app , ["db" , "reset" ])
68+
69+ # Should exit successfully
70+ assert result .exit_code == 0
71+
72+ # No database operations should occur
73+ mock_unlink .assert_not_called ()
74+ mock_run .assert_not_called ()
75+
76+ # Configuration should remain unchanged
77+ assert config_manager .config .projects == original_projects
78+ assert config_manager .config .default_project == "project1"
79+
80+
81+ def test_reset_command_with_reindex (config_manager ):
82+ """Test that the reset command with --reindex flag calls sync."""
83+ runner = CliRunner ()
84+
85+ # Mock the confirmation to return True
86+ with patch ("basic_memory.cli.commands.db.typer.confirm" , return_value = True ):
87+ # Mock database operations
88+ with patch ("pathlib.Path.exists" , return_value = True ):
89+ with patch ("pathlib.Path.unlink" ):
90+ with patch ("basic_memory.cli.commands.db.asyncio.run" ):
91+ # Mock the sync command that gets imported and called
92+ with patch ("basic_memory.cli.commands.db.sync" ) as mock_sync :
93+ # Run the reset command with reindex flag
94+ result = runner .invoke (cli_app , ["db" , "reset" , "--reindex" ])
95+
96+ # Should exit successfully
97+ assert result .exit_code == 0
98+
99+ # Sync should be called with watch=False
100+ mock_sync .assert_called_once_with (watch = False )
101+
102+
103+ def test_reset_command_nonexistent_database (config_manager ):
104+ """Test reset command when database file doesn't exist."""
105+ runner = CliRunner ()
106+
107+ # Mock the confirmation to return True
108+ with patch ("basic_memory.cli.commands.db.typer.confirm" , return_value = True ):
109+ # Mock database file doesn't exist
110+ with patch ("pathlib.Path.exists" , return_value = False ):
111+ with patch ("pathlib.Path.unlink" ) as mock_unlink :
112+ with patch ("basic_memory.cli.commands.db.asyncio.run" ) as mock_run :
113+ # Run the reset command
114+ result = runner .invoke (cli_app , ["db" , "reset" ])
115+
116+ # Should exit successfully
117+ assert result .exit_code == 0
118+
119+ # Database file deletion should not be attempted
120+ mock_unlink .assert_not_called ()
121+
122+ # But migrations should still run
123+ mock_run .assert_called_once ()
124+
125+ # Configuration should still be reset
126+ expected_projects = {"main" : str (Path .home () / "basic-memory" )}
127+ assert config_manager .config .projects == expected_projects
128+ assert config_manager .config .default_project == "main"
0 commit comments