feat: Adds optional read-only response to confirm_ask

This commit is contained in:
Finn 2025-05-01 20:49:19 -04:00
parent e205629a94
commit 02accb9790
5 changed files with 118 additions and 10 deletions

View file

@ -135,6 +135,9 @@ class TestCoder(unittest.TestCase):
repo.git.add(str(fname2))
repo.git.commit("-m", "new")
# Make confirm_ask return "yes" by default
mock_io.confirm_ask.return_value = "yes"
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(self.GPT35, None, mock_io)
@ -238,8 +241,8 @@ class TestCoder(unittest.TestCase):
# Mock get_file_mentions to return two file names
coder.get_file_mentions = MagicMock(return_value=set(["file1.txt", "file2.txt"]))
# Mock confirm_ask to return False for the first call and True for the second
io.confirm_ask = MagicMock(side_effect=[False, True, True])
# Mock confirm_ask to return "no" for the first call and "yes" for the second
io.confirm_ask = MagicMock(side_effect=["no", "yes", "yes"])
# First call to check_for_file_mentions
coder.check_for_file_mentions("Please check file1.txt for the info")

View file

@ -1587,6 +1587,40 @@ class TestCommands(TestCase):
# Check if all files were removed from abs_read_only_fnames
self.assertEqual(len(coder.abs_read_only_fnames), 0)
def test_check_for_file_mentions_with_readonly_option(self):
with GitTemporaryDirectory():
io = InputOutput(pretty=False, fancy_input=False, yes=False)
coder = Coder.create(self.GPT35, None, io)
# Create a test file
test_file = Path("test_file.py")
test_file.write_text("print('Hello, world!')")
# Mock get_file_mentions to return our test file and confirm_ask to return "readonly"
with (
mock.patch.object(coder, "get_file_mentions", return_value={"test_file.py"}),
mock.patch.object(io, "confirm_ask", return_value="readonly"),
):
# Call check_for_file_mentions with content mentioning the file
result = coder.check_for_file_mentions("Let's look at test_file.py")
# Verify confirm_ask was called with show_readonly=True
io.confirm_ask.assert_called_with(
"Add file to the chat?",
subject="test_file.py",
group=mock.ANY,
allow_never=True,
show_readonly=True,
return_string=True,
)
# Verify the file was added as read-only
self.assertEqual(len(coder.abs_fnames), 0)
self.assertEqual(len(coder.abs_read_only_fnames), 1)
# Verify the return message includes "(read-only)"
self.assertIn("(read-only)", result)
def test_cmd_read_only_with_tilde_path(self):
with GitTemporaryDirectory():
io = InputOutput(pretty=False, fancy_input=False, yes=False)

View file

@ -246,6 +246,51 @@ class TestInputOutput(unittest.TestCase):
self.assertNotIn("(A)ll", mock_input.call_args[0][0])
mock_input.reset_mock()
@patch("builtins.input")
def test_confirm_ask_read_only_option(self, mock_input):
io = InputOutput(pretty=False, fancy_input=False)
# Test case 1: User selects 'Read-only' option
mock_input.return_value = "r"
result = io.confirm_ask(
"Add file to the chat?", subject="test_file.py", show_readonly=True, return_string=True
)
self.assertEqual(result, "readonly")
mock_input.assert_called_once()
mock_input.reset_mock()
# Test case 2: show_readonly=False should not offer read-only option
mock_input.side_effect = ["r", "n"] # First 'r' will be invalid, then 'n' to exit the loop
result = io.confirm_ask(
"Add file to the chat?", subject="test_file.py", show_readonly=False, return_string=True
)
self.assertEqual(result, "no")
self.assertEqual(mock_input.call_count, 2)
mock_input.reset_mock()
# Test case 3: Return boolean with show_readonly=True and 'r' response
mock_input.side_effect = None # Clear any side_effect
mock_input.return_value = "r"
result = io.confirm_ask(
"Add file to the chat?", subject="test_file.py", show_readonly=True, return_string=False
)
self.assertTrue(result) # Should return True for backward compatibility
mock_input.assert_called_once()
mock_input.reset_mock()
# Test case 4: Verify prompt includes read-only option
mock_input.return_value = "y"
io.confirm_ask("Add file to the chat?", subject="test_file.py", show_readonly=True)
call_args = mock_input.call_args[0][0]
self.assertIn("(R)ead-only", call_args)
mock_input.reset_mock()
# Test case 5: Verify prompt doesn't include read-only option when show_readonly=False
mock_input.return_value = "y"
io.confirm_ask("Add file to the chat?", subject="test_file.py", show_readonly=False)
call_args = mock_input.call_args[0][0]
self.assertNotIn("(R)ead-only", call_args)
@patch("builtins.input")
def test_confirm_ask_yes_no(self, mock_input):
io = InputOutput(pretty=False, fancy_input=False)
@ -451,8 +496,6 @@ class TestInputOutputMultilineMode(unittest.TestCase):
"""Test that tool_output correctly handles hex colors without # prefix"""
from unittest.mock import patch
from rich.text import Text
# Create IO with hex color without # for tool_output_color
io = InputOutput(tool_output_color="FFA500", pretty=True)