mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-20 12:24:59 +00:00

# Aider chat conversation: USER: I ran this command: pytest -k test_get_tracked_files -s And got this output: ============================= test session starts ============================== platform darwin -- Python 3.11.3, pytest-7.3.1, pluggy-1.0.0 rootdir: /Users/gauthier/Projects/aider configfile: pytest.ini collected 61 items / 60 deselected / 1 selected tests/test_coder.py F =================================== FAILURES =================================== _______________________ TestCoder.test_get_tracked_files _______________________ self = <tests.test_coder.TestCoder testMethod=test_get_tracked_files> def test_get_tracked_files(self): # Create a temporary directory tempdir = Path(tempfile.mkdtemp()) # Initialize a git repository in the temporary directory repo = git.Repo.init(tempdir) # Create three empty files and add them to the git repository filenames = ["README.md", "doc/fänny_dirname/README.md", "doc/systemüberblick.md"] for filename in filenames: > (tempdir / filename).touch() tests/test_coder.py:374: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = PosixPath('/var/folders/49/kxrdwwbx0h9bchx99397477c0000gn/T/tmpoowegb9x/doc/fänny_dirname/README.md') mode = 438, exist_ok = True def touch(self, mode=0o666, exist_ok=True): """ Create this file with the given access mode, if it doesn't exist. """ if exist_ok: # First try to bump modification time # Implementation note: GNU touch uses the UTIME_NOW option of # the utimensat() / futimens() functions. try: os.utime(self, None) except OSError: # Avoid exception chaining pass else: return flags = os.O_CREAT | os.O_WRONLY if not exist_ok: flags |= os.O_EXCL > fd = os.open(self, flags, mode) E FileNotFoundError: [Errno 2] No such file or directory: '/var/folders/49/kxrdwwbx0h9bchx99397477c0000gn/T/tmpoowegb9x/doc/fänny_dirname/README.md' /usr/local/Cellar/python@3.11/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/pathlib.py:1108: FileNotFoundError =========================== short test summary info ============================ FAILED tests/test_coder.py::TestCoder::test_get_tracked_files - FileNotFoundE... ======================= 1 failed, 60 deselected in 1.53s ======================= ASSISTANT: The error message indicates that the directory `doc/fänny_dirname` does not exist when the test tries to create the file `README.md` inside it. We need to ensure that the directory exists before creating the file. We can use the `mkdir` method of `Path` with the `parents=True` argument to create the directory and all its missing parents. Here is the updated code: ```python tests/test_coder.py <<<<<<< ORIGINAL def test_get_tracked_files(self): # Create a temporary directory tempdir = Path(tempfile.mkdtemp()) # Initialize a git repository in the temporary directory repo = git.Repo.init(tempdir) # Create three empty files and add them to the git repository filenames = ["README.md", "doc/fänny_dirname/README.md", "doc/systemüberblick.md"] for filename in filenames: (tempdir / filename).touch() repo.git.add(filename) # Create a Coder object on the temporary directory coder = Coder.create( models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", root=tempdir ) # Assert that coder.get_tracked_files() returns the three filenames self.assertEqual(set(coder.get_tracked_files()), set(filenames)) ======= def test_get_tracked_files(self): # Create a temporary directory tempdir = Path(tempfile.mkdtemp()) # Initialize a git repository in the temporary directory repo = git.Repo.init(tempdir) # Create three empty files and add them to the git repository filenames = ["README.md", "doc/fänny_dirname/README.md", "doc/systemüberblick.md"] for filename in filenames: file_path = tempdir / filename file_path.parent.mkdir(parents=True, exist_ok=True) file_path.touch() repo.git.add(str(file_path)) # Create a Coder object on the temporary directory coder = Coder.create( models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", root=tempdir ) # Assert that coder.get_tracked_files() returns the three filenames self.assertEqual(set(coder.get_tracked_files()), set(filenames)) >>>>>>> UPDATED ``` This code creates the parent directory of each file before creating the file. It also converts the `Path` object to a string before passing it to `repo.git.add`, because the `git` library may not accept `Path` objects.
388 lines
13 KiB
Python
388 lines
13 KiB
Python
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import git
|
|
import openai
|
|
import requests
|
|
|
|
from aider import models
|
|
from aider.coders import Coder
|
|
from aider.dump import dump # noqa: F401
|
|
from aider.io import InputOutput
|
|
|
|
|
|
class TestCoder(unittest.TestCase):
|
|
def setUp(self):
|
|
self.patcher = patch("aider.coders.base_coder.check_model_availability")
|
|
self.mock_check = self.patcher.start()
|
|
self.mock_check.return_value = True
|
|
|
|
def tearDown(self):
|
|
self.patcher.stop()
|
|
|
|
def test_check_for_file_mentions(self):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Mock the git repo
|
|
mock_repo = MagicMock()
|
|
mock_repo.git.execute.return_value = "file1.txt\nfile2.py"
|
|
coder.repo = mock_repo
|
|
|
|
# Call the check_for_file_mentions method
|
|
coder.check_for_file_mentions("Please check file1.txt and file2.py")
|
|
|
|
# Check if coder.abs_fnames contains both files
|
|
expected_files = set(
|
|
map(
|
|
str,
|
|
[
|
|
Path(coder.root) / "file1.txt",
|
|
Path(coder.root) / "file2.py",
|
|
],
|
|
)
|
|
)
|
|
self.assertEqual(coder.abs_fnames, expected_files)
|
|
|
|
def test_get_files_content(self):
|
|
tempdir = Path(tempfile.mkdtemp())
|
|
|
|
file1 = tempdir / "file1.txt"
|
|
file2 = tempdir / "file2.txt"
|
|
|
|
file1.touch()
|
|
file2.touch()
|
|
|
|
files = [file1, file2]
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(
|
|
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", fnames=files
|
|
)
|
|
|
|
content = coder.get_files_content().splitlines()
|
|
self.assertIn("file1.txt", content)
|
|
self.assertIn("file2.txt", content)
|
|
|
|
def test_check_for_filename_mentions_of_longer_paths(self):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Mock the git repo
|
|
mock_repo = MagicMock()
|
|
mock_repo.git.execute.return_value = "file1.txt\nfile2.py"
|
|
coder.repo = mock_repo
|
|
|
|
# Call the check_for_file_mentions method
|
|
coder.check_for_file_mentions("Please check file1.txt and file2.py")
|
|
|
|
# Check if coder.abs_fnames contains both files
|
|
expected_files = set(
|
|
map(
|
|
str,
|
|
[
|
|
Path(coder.root) / "file1.txt",
|
|
Path(coder.root) / "file2.py",
|
|
],
|
|
)
|
|
)
|
|
self.assertEqual(coder.abs_fnames, expected_files)
|
|
|
|
def test_check_for_ambiguous_filename_mentions_of_longer_paths(self):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Mock the git repo
|
|
mock_repo = MagicMock()
|
|
mock_repo.git.execute.return_value = "file1.txt\nother/file1.txt"
|
|
coder.repo = mock_repo
|
|
|
|
# Call the check_for_file_mentions method
|
|
coder.check_for_file_mentions("Please check file1.txt!")
|
|
|
|
self.assertEqual(coder.abs_fnames, set())
|
|
|
|
def test_get_commit_message(self):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Mock the send method to set partial_response_content and return False
|
|
def mock_send(*args, **kwargs):
|
|
coder.partial_response_content = "a good commit message"
|
|
return False
|
|
|
|
coder.send = MagicMock(side_effect=mock_send)
|
|
|
|
# Call the get_commit_message method with dummy diff and context
|
|
result = coder.get_commit_message("dummy diff", "dummy context")
|
|
|
|
# Assert that the returned message is the expected one
|
|
self.assertEqual(result, "a good commit message")
|
|
|
|
def test_get_commit_message_strip_quotes(self):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Mock the send method to set partial_response_content and return False
|
|
def mock_send(*args, **kwargs):
|
|
coder.partial_response_content = "a good commit message"
|
|
return False
|
|
|
|
coder.send = MagicMock(side_effect=mock_send)
|
|
|
|
# Call the get_commit_message method with dummy diff and context
|
|
result = coder.get_commit_message("dummy diff", "dummy context")
|
|
|
|
# Assert that the returned message is the expected one
|
|
self.assertEqual(result, "a good commit message")
|
|
|
|
def test_get_commit_message_no_strip_unmatched_quotes(self):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Mock the send method to set partial_response_content and return False
|
|
def mock_send(*args, **kwargs):
|
|
coder.partial_response_content = 'a good "commit message"'
|
|
return False
|
|
|
|
coder.send = MagicMock(side_effect=mock_send)
|
|
|
|
# Call the get_commit_message method with dummy diff and context
|
|
result = coder.get_commit_message("dummy diff", "dummy context")
|
|
|
|
# Assert that the returned message is the expected one
|
|
self.assertEqual(result, 'a good "commit message"')
|
|
|
|
@patch("aider.coders.base_coder.openai.ChatCompletion.create")
|
|
@patch("builtins.print")
|
|
def test_send_with_retries_rate_limit_error(self, mock_print, mock_chat_completion_create):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Set up the mock to raise RateLimitError on
|
|
# the first call and return None on the second call
|
|
mock_chat_completion_create.side_effect = [
|
|
openai.error.RateLimitError("Rate limit exceeded"),
|
|
None,
|
|
]
|
|
|
|
# Call the send_with_retries method
|
|
coder.send_with_retries("model", ["message"], None)
|
|
|
|
# Assert that print was called once
|
|
mock_print.assert_called_once()
|
|
|
|
@patch("aider.coders.base_coder.openai.ChatCompletion.create")
|
|
@patch("builtins.print")
|
|
def test_send_with_retries_connection_error(self, mock_print, mock_chat_completion_create):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Set up the mock to raise ConnectionError on the first call
|
|
# and return None on the second call
|
|
mock_chat_completion_create.side_effect = [
|
|
requests.exceptions.ConnectionError("Connection error"),
|
|
None,
|
|
]
|
|
|
|
# Call the send_with_retries method
|
|
coder.send_with_retries("model", ["message"], None)
|
|
|
|
# Assert that print was called once
|
|
mock_print.assert_called_once()
|
|
|
|
def test_run_with_file_deletion(self):
|
|
# Create a few temporary files
|
|
|
|
tempdir = Path(tempfile.mkdtemp())
|
|
|
|
file1 = tempdir / "file1.txt"
|
|
file2 = tempdir / "file2.txt"
|
|
|
|
file1.touch()
|
|
file2.touch()
|
|
|
|
files = [file1, file2]
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(
|
|
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", fnames=files
|
|
)
|
|
|
|
def mock_send(*args, **kwargs):
|
|
coder.partial_response_content = "ok"
|
|
coder.partial_response_function_call = dict()
|
|
|
|
coder.send = MagicMock(side_effect=mock_send)
|
|
|
|
# Call the run method with a message
|
|
coder.run(with_message="hi")
|
|
self.assertEqual(len(coder.abs_fnames), 2)
|
|
|
|
file1.unlink()
|
|
|
|
# Call the run method again with a message
|
|
coder.run(with_message="hi")
|
|
self.assertEqual(len(coder.abs_fnames), 1)
|
|
|
|
def test_run_with_file_unicode_error(self):
|
|
# Create a few temporary files
|
|
_, file1 = tempfile.mkstemp()
|
|
_, file2 = tempfile.mkstemp()
|
|
|
|
files = [file1, file2]
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(
|
|
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", fnames=files
|
|
)
|
|
|
|
def mock_send(*args, **kwargs):
|
|
coder.partial_response_content = "ok"
|
|
coder.partial_response_function_call = dict()
|
|
|
|
coder.send = MagicMock(side_effect=mock_send)
|
|
|
|
# Call the run method with a message
|
|
coder.run(with_message="hi")
|
|
self.assertEqual(len(coder.abs_fnames), 2)
|
|
|
|
# Write some non-UTF8 text into the file
|
|
with open(file1, "wb") as f:
|
|
f.write(b"\x80abc")
|
|
|
|
# Call the run method again with a message
|
|
coder.run(with_message="hi")
|
|
self.assertEqual(len(coder.abs_fnames), 1)
|
|
|
|
def test_choose_fence(self):
|
|
# Create a few temporary files
|
|
_, file1 = tempfile.mkstemp()
|
|
|
|
with open(file1, "wb") as f:
|
|
f.write(b"this contains ``` backticks")
|
|
|
|
files = [file1]
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(
|
|
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", fnames=files
|
|
)
|
|
|
|
def mock_send(*args, **kwargs):
|
|
coder.partial_response_content = "ok"
|
|
coder.partial_response_function_call = dict()
|
|
|
|
coder.send = MagicMock(side_effect=mock_send)
|
|
|
|
# Call the run method with a message
|
|
coder.run(with_message="hi")
|
|
|
|
self.assertNotEqual(coder.fence[0], "```")
|
|
|
|
def test_run_with_file_utf_unicode_error(self):
|
|
"make sure that we honor InputOutput(encoding) and don't just assume utf-8"
|
|
# Create a few temporary files
|
|
_, file1 = tempfile.mkstemp()
|
|
_, file2 = tempfile.mkstemp()
|
|
|
|
files = [file1, file2]
|
|
|
|
encoding = "utf-16"
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(
|
|
models.GPT4,
|
|
None,
|
|
io=InputOutput(encoding=encoding),
|
|
openai_api_key="fake_key",
|
|
fnames=files,
|
|
)
|
|
|
|
def mock_send(*args, **kwargs):
|
|
coder.partial_response_content = "ok"
|
|
coder.partial_response_function_call = dict()
|
|
|
|
coder.send = MagicMock(side_effect=mock_send)
|
|
|
|
# Call the run method with a message
|
|
coder.run(with_message="hi")
|
|
self.assertEqual(len(coder.abs_fnames), 2)
|
|
|
|
some_content_which_will_error_if_read_with_encoding_utf8 = "ÅÍÎÏ".encode(encoding)
|
|
with open(file1, "wb") as f:
|
|
f.write(some_content_which_will_error_if_read_with_encoding_utf8)
|
|
|
|
coder.run(with_message="hi")
|
|
|
|
# both files should still be here
|
|
self.assertEqual(len(coder.abs_fnames), 2)
|
|
|
|
@patch("aider.coders.base_coder.openai.ChatCompletion.create")
|
|
def test_run_with_invalid_request_error(self, mock_chat_completion_create):
|
|
# Mock the IO object
|
|
mock_io = MagicMock()
|
|
|
|
# Initialize the Coder object with the mocked IO and mocked repo
|
|
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
|
|
|
|
# Set up the mock to raise InvalidRequestError
|
|
mock_chat_completion_create.side_effect = openai.error.InvalidRequestError(
|
|
"Invalid request", "param"
|
|
)
|
|
|
|
# Call the run method and assert that InvalidRequestError is raised
|
|
with self.assertRaises(openai.error.InvalidRequestError):
|
|
coder.run(with_message="hi")
|
|
|
|
def test_get_tracked_files(self):
|
|
# Create a temporary directory
|
|
tempdir = Path(tempfile.mkdtemp())
|
|
|
|
# Initialize a git repository in the temporary directory
|
|
repo = git.Repo.init(tempdir)
|
|
|
|
# Create three empty files and add them to the git repository
|
|
filenames = ["README.md", "doc/fänny_dirname/README.md", "doc/systemüberblick.md"]
|
|
for filename in filenames:
|
|
file_path = tempdir / filename
|
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
file_path.touch()
|
|
repo.git.add(str(file_path))
|
|
|
|
# Create a Coder object on the temporary directory
|
|
coder = Coder.create(
|
|
models.GPT4, None, io=InputOutput(), openai_api_key="fake_key", root=tempdir
|
|
)
|
|
|
|
# Assert that coder.get_tracked_files() returns the three filenames
|
|
self.assertEqual(set(coder.get_tracked_files()), set(filenames))
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|