diff --git a/tests/basic/test_commands.py b/tests/basic/test_commands.py index 7ded4ca3a..2d15e02f5 100644 --- a/tests/basic/test_commands.py +++ b/tests/basic/test_commands.py @@ -2105,3 +2105,87 @@ class TestCommands(TestCase): mock_tool_error.assert_any_call( "Command '/model gpt-4' is only supported in interactive mode, skipping." ) + + def test_reset_after_coder_clone_preserves_original_read_only_files(self): + with GitTemporaryDirectory() as repo_dir_path: + repo_dir = str(repo_dir_path) + io = InputOutput(pretty=False, fancy_input=False, yes=True) + + orig_ro_path = Path(repo_dir) / "orig_ro.txt" + orig_ro_path.write_text("original read only") + + editable_path = Path(repo_dir) / "editable.txt" + editable_path.write_text("editable content") + + other_ro_path = Path(repo_dir) / "other_ro.txt" + other_ro_path.write_text("other read only") + + original_read_only_fnames_set = {str(orig_ro_path)} + + # Create the initial Coder + orig_coder = Coder.create(main_model=self.GPT35, io=io, fnames=[], repo=None) + orig_coder.root = repo_dir # Set root for path operations + + # Replace its commands object with one that has the original_read_only_fnames + orig_coder.commands = Commands( + io, orig_coder, original_read_only_fnames=list(original_read_only_fnames_set) + ) + orig_coder.commands.coder = orig_coder + + # Populate coder's file sets + orig_coder.abs_read_only_fnames.add(str(orig_ro_path)) + orig_coder.abs_fnames.add(str(editable_path)) + orig_coder.abs_read_only_fnames.add(str(other_ro_path)) + + # Simulate SwitchCoder by creating a new coder from the original one + new_coder = Coder.create(from_coder=orig_coder) + new_commands = new_coder.commands + + # Perform /reset + new_commands.cmd_reset("") + + # Assertions for /reset + self.assertEqual(len(new_coder.abs_fnames), 0) + self.assertEqual(len(new_coder.abs_read_only_fnames), 1) + self.assertIn(str(orig_ro_path), new_coder.abs_read_only_fnames) + self.assertEqual(len(new_coder.done_messages), 0) + self.assertEqual(len(new_coder.cur_messages), 0) + + def test_drop_bare_after_coder_clone_preserves_original_read_only_files(self): + with GitTemporaryDirectory() as repo_dir_path: + repo_dir = str(repo_dir_path) + io = InputOutput(pretty=False, fancy_input=False, yes=True) + + orig_ro_path = Path(repo_dir) / "orig_ro.txt" + orig_ro_path.write_text("original read only") + + editable_path = Path(repo_dir) / "editable.txt" + editable_path.write_text("editable content") + + other_ro_path = Path(repo_dir) / "other_ro.txt" + other_ro_path.write_text("other read only") + + original_read_only_fnames_set = {str(orig_ro_path)} + + orig_coder = Coder.create(main_model=self.GPT35, io=io, fnames=[], repo=None) + orig_coder.root = repo_dir + orig_coder.commands = Commands( + io, orig_coder, original_read_only_fnames=list(original_read_only_fnames_set) + ) + orig_coder.commands.coder = orig_coder + + orig_coder.abs_read_only_fnames.add(str(orig_ro_path)) + orig_coder.abs_fnames.add(str(editable_path)) + orig_coder.abs_read_only_fnames.add(str(other_ro_path)) + orig_coder.done_messages = [{"role": "user", "content": "d1"}] + orig_coder.cur_messages = [{"role": "user", "content": "c1"}] + + new_coder = Coder.create(from_coder=orig_coder) + new_commands = new_coder.commands + new_commands.cmd_drop("") + + self.assertEqual(len(new_coder.abs_fnames), 0) + self.assertEqual(len(new_coder.abs_read_only_fnames), 1) + self.assertIn(str(orig_ro_path), new_coder.abs_read_only_fnames) + self.assertEqual(new_coder.done_messages, [{"role": "user", "content": "d1"}]) + self.assertEqual(new_coder.cur_messages, [{"role": "user", "content": "c1"}])