mirror of
https://github.com/Aider-AI/aider.git
synced 2025-05-31 09:44:59 +00:00
Merge branch 'main' into glob-add
This commit is contained in:
commit
cb2b2c5ce3
22 changed files with 465 additions and 94 deletions
|
@ -1,5 +1,7 @@
|
|||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import openai
|
||||
|
@ -7,6 +9,8 @@ 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):
|
||||
|
@ -177,6 +181,132 @@ class TestCoder(unittest.TestCase):
|
|||
# Assert that print was called once
|
||||
mock_print.assert_called_once()
|
||||
|
||||
def test_run_with_file_deletion(self):
|
||||
# Create a few temporary files
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
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)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import codecs
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from io import StringIO
|
||||
from unittest import TestCase
|
||||
|
||||
from aider import models
|
||||
from aider.coders import Coder
|
||||
from aider.commands import Commands
|
||||
from aider.dump import dump # noqa: F401
|
||||
from aider.io import InputOutput
|
||||
|
||||
|
||||
|
@ -18,6 +23,21 @@ class TestCommands(TestCase):
|
|||
os.chdir(self.original_cwd)
|
||||
shutil.rmtree(self.tempdir)
|
||||
|
||||
def test_cmd_add(self):
|
||||
# Initialize the Commands and InputOutput objects
|
||||
io = InputOutput(pretty=False, yes=True)
|
||||
from aider.coders import Coder
|
||||
|
||||
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
|
||||
commands = Commands(io, coder)
|
||||
|
||||
# Call the cmd_add method with 'foo.txt' and 'bar.txt' as a single string
|
||||
commands.cmd_add("foo.txt bar.txt")
|
||||
|
||||
# Check if both files have been created in the temporary directory
|
||||
self.assertTrue(os.path.exists("foo.txt"))
|
||||
self.assertTrue(os.path.exists("bar.txt"))
|
||||
|
||||
def test_cmd_add_with_glob_patterns(self):
|
||||
# Initialize the Commands and InputOutput objects
|
||||
io = InputOutput(pretty=False, yes=True)
|
||||
|
@ -80,3 +100,43 @@ class TestCommands(TestCase):
|
|||
# Check if the Python files have been removed from the chat session
|
||||
self.assertIn(os.path.abspath("test1.py"), coder.abs_fnames)
|
||||
self.assertNotIn(os.path.abspath("test2.py"), coder.abs_fnames)
|
||||
|
||||
def test_cmd_add_bad_encoding(self):
|
||||
# Initialize the Commands and InputOutput objects
|
||||
io = InputOutput(pretty=False, yes=True)
|
||||
from aider.coders import Coder
|
||||
|
||||
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
|
||||
commands = Commands(io, coder)
|
||||
|
||||
# Create a new file foo.bad which will fail to decode as utf-8
|
||||
with codecs.open("foo.bad", "w", encoding="iso-8859-15") as f:
|
||||
f.write("ÆØÅ") # Characters not present in utf-8
|
||||
|
||||
commands.cmd_add("foo.bad")
|
||||
|
||||
self.assertEqual(coder.abs_fnames, set())
|
||||
|
||||
def test_cmd_tokens(self):
|
||||
# Initialize the Commands and InputOutput objects
|
||||
io = InputOutput(pretty=False, yes=True)
|
||||
|
||||
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
|
||||
commands = Commands(io, coder)
|
||||
|
||||
commands.cmd_add("foo.txt bar.txt")
|
||||
|
||||
# Redirect the standard output to an instance of io.StringIO
|
||||
stdout = StringIO()
|
||||
sys.stdout = stdout
|
||||
|
||||
commands.cmd_tokens("")
|
||||
|
||||
# Reset the standard output
|
||||
sys.stdout = sys.__stdout__
|
||||
|
||||
# Get the console output
|
||||
console_output = stdout.getvalue()
|
||||
|
||||
self.assertIn("foo.txt", console_output)
|
||||
self.assertIn("bar.txt", console_output)
|
||||
|
|
|
@ -1,11 +1,26 @@
|
|||
# flake8: noqa: E501
|
||||
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from aider import models
|
||||
from aider.coders import Coder
|
||||
from aider.coders import editblock_coder as eb
|
||||
from aider.dump import dump # noqa: F401
|
||||
from aider.io import InputOutput
|
||||
|
||||
|
||||
class TestUtils(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_replace_most_similar_chunk(self):
|
||||
whole = "This is a sample text.\nAnother line of text.\nYet another line.\n"
|
||||
part = "This is a sample text"
|
||||
|
@ -223,6 +238,85 @@ These changes replace the `subprocess.run` patches with `subprocess.check_output
|
|||
result = eb.replace_part_with_missing_leading_whitespace(whole, part, replace)
|
||||
self.assertEqual(result, expected_output)
|
||||
|
||||
def test_full_edit(self):
|
||||
# Create a few temporary files
|
||||
_, file1 = tempfile.mkstemp()
|
||||
|
||||
with open(file1, "w", encoding="utf-8") as f:
|
||||
f.write("one\ntwo\nthree\n")
|
||||
|
||||
files = [file1]
|
||||
|
||||
# Initialize the Coder object with the mocked IO and mocked repo
|
||||
coder = Coder.create(
|
||||
models.GPT4, "diff", io=InputOutput(), openai_api_key="fake_key", fnames=files
|
||||
)
|
||||
|
||||
def mock_send(*args, **kwargs):
|
||||
coder.partial_response_content = f"""
|
||||
Do this:
|
||||
|
||||
{Path(file1).name}
|
||||
<<<<<<< ORIGINAL
|
||||
two
|
||||
=======
|
||||
new
|
||||
>>>>>>> UPDATED
|
||||
|
||||
"""
|
||||
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")
|
||||
|
||||
content = Path(file1).read_text(encoding="utf-8")
|
||||
self.assertEqual(content, "one\nnew\nthree\n")
|
||||
|
||||
def test_full_edit_dry_run(self):
|
||||
# Create a few temporary files
|
||||
_, file1 = tempfile.mkstemp()
|
||||
|
||||
orig_content = "one\ntwo\nthree\n"
|
||||
|
||||
with open(file1, "w", encoding="utf-8") as f:
|
||||
f.write(orig_content)
|
||||
|
||||
files = [file1]
|
||||
|
||||
# Initialize the Coder object with the mocked IO and mocked repo
|
||||
coder = Coder.create(
|
||||
models.GPT4,
|
||||
"diff",
|
||||
io=InputOutput(dry_run=True),
|
||||
openai_api_key="fake_key",
|
||||
fnames=files,
|
||||
dry_run=True,
|
||||
)
|
||||
|
||||
def mock_send(*args, **kwargs):
|
||||
coder.partial_response_content = f"""
|
||||
Do this:
|
||||
|
||||
{Path(file1).name}
|
||||
<<<<<<< ORIGINAL
|
||||
two
|
||||
=======
|
||||
new
|
||||
>>>>>>> UPDATED
|
||||
|
||||
"""
|
||||
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")
|
||||
|
||||
content = Path(file1).read_text(encoding="utf-8")
|
||||
self.assertEqual(content, orig_content)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -3,6 +3,7 @@ import tempfile
|
|||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from aider.io import InputOutput
|
||||
from aider.repomap import RepoMap
|
||||
|
||||
|
||||
|
@ -21,7 +22,8 @@ class TestRepoMap(unittest.TestCase):
|
|||
with open(os.path.join(temp_dir, file), "w") as f:
|
||||
f.write("")
|
||||
|
||||
repo_map = RepoMap(root=temp_dir)
|
||||
io = InputOutput()
|
||||
repo_map = RepoMap(root=temp_dir, io=io)
|
||||
other_files = [os.path.join(temp_dir, file) for file in test_files]
|
||||
result = repo_map.get_repo_map([], other_files)
|
||||
|
||||
|
@ -65,7 +67,8 @@ print(my_function(3, 4))
|
|||
with open(os.path.join(temp_dir, test_file3), "w") as f:
|
||||
f.write(file_content3)
|
||||
|
||||
repo_map = RepoMap(root=temp_dir)
|
||||
io = InputOutput()
|
||||
repo_map = RepoMap(root=temp_dir, io=io)
|
||||
other_files = [
|
||||
os.path.join(temp_dir, test_file1),
|
||||
os.path.join(temp_dir, test_file2),
|
||||
|
@ -83,7 +86,7 @@ print(my_function(3, 4))
|
|||
def test_check_for_ctags_failure(self):
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.side_effect = Exception("ctags not found")
|
||||
repo_map = RepoMap()
|
||||
repo_map = RepoMap(io=InputOutput())
|
||||
self.assertFalse(repo_map.has_ctags)
|
||||
|
||||
def test_check_for_ctags_success(self):
|
||||
|
@ -100,7 +103,7 @@ print(my_function(3, 4))
|
|||
b' status = main()$/", "kind": "variable"}'
|
||||
),
|
||||
]
|
||||
repo_map = RepoMap()
|
||||
repo_map = RepoMap(io=InputOutput())
|
||||
self.assertTrue(repo_map.has_ctags)
|
||||
|
||||
def test_get_repo_map_without_ctags(self):
|
||||
|
@ -120,7 +123,7 @@ print(my_function(3, 4))
|
|||
with open(os.path.join(temp_dir, file), "w") as f:
|
||||
f.write("")
|
||||
|
||||
repo_map = RepoMap(root=temp_dir)
|
||||
repo_map = RepoMap(root=temp_dir, io=InputOutput())
|
||||
repo_map.has_ctags = False # force it off
|
||||
|
||||
other_files = [os.path.join(temp_dir, file) for file in test_files]
|
||||
|
|
|
@ -3,8 +3,10 @@ import shutil
|
|||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from aider import models
|
||||
from aider.coders import Coder
|
||||
from aider.coders.wholefile_coder import WholeFileCoder
|
||||
from aider.io import InputOutput
|
||||
|
||||
|
@ -15,10 +17,16 @@ class TestWholeFileCoder(unittest.TestCase):
|
|||
self.tempdir = tempfile.mkdtemp()
|
||||
os.chdir(self.tempdir)
|
||||
|
||||
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):
|
||||
os.chdir(self.original_cwd)
|
||||
shutil.rmtree(self.tempdir, ignore_errors=True)
|
||||
|
||||
self.patcher.stop()
|
||||
|
||||
def test_update_files(self):
|
||||
# Create a sample file in the temporary directory
|
||||
sample_file = "sample.txt"
|
||||
|
@ -198,6 +206,45 @@ after b
|
|||
self.assertEqual(fname_a.read_text(), "after a\n")
|
||||
self.assertEqual(fname_b.read_text(), "after b\n")
|
||||
|
||||
def test_full_edit(self):
|
||||
# Create a few temporary files
|
||||
_, file1 = tempfile.mkstemp()
|
||||
|
||||
with open(file1, "w", encoding="utf-8") as f:
|
||||
f.write("one\ntwo\nthree\n")
|
||||
|
||||
files = [file1]
|
||||
|
||||
# Initialize the Coder object with the mocked IO and mocked repo
|
||||
coder = Coder.create(
|
||||
models.GPT4, "whole", io=InputOutput(), openai_api_key="fake_key", fnames=files
|
||||
)
|
||||
|
||||
# no trailing newline so the response content below doesn't add ANOTHER newline
|
||||
new_content = "new\ntwo\nthree"
|
||||
|
||||
def mock_send(*args, **kwargs):
|
||||
coder.partial_response_content = f"""
|
||||
Do this:
|
||||
|
||||
{Path(file1).name}
|
||||
```
|
||||
{new_content}
|
||||
```
|
||||
|
||||
"""
|
||||
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")
|
||||
|
||||
content = Path(file1).read_text(encoding="utf-8")
|
||||
|
||||
# check for one trailing newline
|
||||
self.assertEqual(content, new_content + "\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue