Skip to content

Commit 67b93de

Browse files
authored
Adding tests (#11)
* Adding tests * python version for tests * fixing github actions for tests * Need to figure out how to mock codebase
1 parent b434664 commit 67b93de

5 files changed

Lines changed: 152 additions & 213 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Run Pytest
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main # or the name of your default branch
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v2
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v2
18+
with:
19+
python-version: 3.10.4 # or any other version you prefer
20+
21+
- name: Install dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install -r backend/requirements.txt
25+
26+
- name: Run pytest
27+
run: cd backend && python -m pytest
28+
env:
29+
PROJECT_DIRECTORY: ${{ github.workspace }}

backend/.env.sample

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ CODEAPP_DB_PW=PW_FROM_SETUP_STEP4
44
CODEAPP_DB_HOST=localhost
55
IGNORE_DIRS=[node_modules,.nextm,.venv,__pycache__,.git]
66
PROJECT_DIRECTORY='/Users/josephblazick/Documents/GPT-CodeApp'
7-
FILE_EXTENSIONS=[.js,.py,.md]
7+
FILE_EXTENSIONS=[.js,.py,.md]
8+
OPENAI_API_KEY=...

backend/tests/test_agent_functions.py

Lines changed: 0 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,14 @@
11
import shutil
2-
import re
32
import json
43
import os
5-
import openai
64
from agent.agent_functions.changes import Changes
75
from dotenv import load_dotenv
86

97
load_dotenv()
108
DIRECTORY = os.getenv("PROJECT_DIRECTORY")
119

1210
temp_file = "backend/tests/test_files/agent_function_test1.py"
13-
TEST_FILE = "backend/tests/test_files/app_setup_test.py"
14-
FULL_PATH = os.path.join(DIRECTORY, TEST_FILE)
1511
temp_file_full = os.path.join(DIRECTORY, temp_file)
16-
with open(FULL_PATH, "r") as f:
17-
CONTENT = f.read()
18-
19-
system_prompt = f""""
20-
You are an AI Pair Programmer and a world class python developer helping the Human work on a project.
21-
22-
The project directory is setup as follows:
23-
+--GPT-CodeApp
24-
+--frontend
25-
+--tailwind.config.js
26-
+--next.config.js
27-
+--postcss.config.js
28-
+--store
29-
+--sidebar
30-
+--sidebarSlice.js
31-
+--index.js
32-
+--messages
33-
+--messagesSlice.js
34-
+--modal_bar_modals
35-
+--messageHistorySlice.js
36-
+--systemPromptSlice.js
37-
+--functionsSlice.js
38-
+--styles
39-
+--globals.css
40-
+--components
41-
+--ModelSelector.js
42-
+--RightSidebar.js
43-
+--ChatInput.js
44-
+--EditFilesModal.js
45-
+--LeftSidebar.js
46-
+--SearchBar.js
47-
+--modal_bar_modals
48-
+--MessageHistoryModal.js
49-
+--SystemPromptModal.js
50-
+--FunctionsModal.js
51-
+--ChatBox.js
52-
+--ModalBar.js
53-
+--pages
54-
+--index.js
55-
+--README.md
56-
+--CONTRIBUTING.md
57-
+--backend
58-
+--agent
59-
+--openai_function_call.py
60-
+--agent_functions
61-
+--changes.py
62-
+--shell_commands.py
63-
+--new_file.py
64-
+--agent_functions.py
65-
+--memory_manager.py
66-
+--agent.py
67-
+--database
68-
+--my_codebase.py
69-
+--UpdateHandler.py
70-
+--tests
71-
+--test_codebase.py
72-
+--test_files
73-
+--app_setup_test.py
74-
+--agent_function_test1.py
75-
+--conftest.py
76-
+--test_agent_functions.py
77-
+--test_memory_manager.py
78-
+--main.py
79-
+--app_setup.py
80-
+--CODE_OF_CONDUCT.md
81-
+--.pytest_cache
82-
+--README.md
83-
84-
Related File Contents:
85-
File: backend/tests/test_files/agent_function_test1.py
86-
Content:
87-
{CONTENT}
88-
"""
89-
90-
91-
def preprocess_response(response_str):
92-
# Find all occurrences of triple-quoted strings
93-
triple_quoted_strings = re.findall(r"\"\"\"(.*?)\"\"\"", response_str, re.DOTALL)
94-
95-
# For each occurrence, replace newlines and triple quotes
96-
for tqs in triple_quoted_strings:
97-
fixed_string = tqs.replace("\n", "\\n").replace('"', '\\"')
98-
response_str = response_str.replace(tqs, fixed_string)
99-
100-
# Now replace the triple quotes with single quotes
101-
response_str = response_str.replace('"""', '"')
102-
103-
return response_str
104-
105-
106-
def test_FileChange_real_world_example2():
107-
# Create a temporary file
108-
message_history = [
109-
{
110-
"role": "system",
111-
"content": system_prompt,
112-
},
113-
{
114-
"role": "user",
115-
"content": f"For file the file {temp_file}, re-write the Exception message to be informative. Respond with proper json",
116-
},
117-
]
118-
119-
keyword_args = {
120-
"model": "gpt-4-0613",
121-
"messages": message_history,
122-
"max_tokens": 1000,
123-
"temperature": 0.1,
124-
"functions": [Changes.openai_schema],
125-
"function_call": {"name": Changes.openai_schema["name"]},
126-
}
127-
128-
# Create a FileChange instance
129-
response = openai.ChatCompletion.create(**keyword_args)
130-
processed_response = preprocess_response(
131-
response["choices"][0].message.function_call.arguments
132-
)
133-
print(repr(processed_response))
134-
135-
args = json.loads(processed_response)
136-
print("File Name: ", temp_file)
137-
print("File Name: ", args.get("file_name"))
138-
print(f"Args: {args}")
139-
assert args.get("file_name") == temp_file
14012

14113

14214
def test_FileChange_real_world_example3():

backend/tests/test_codebase.py

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,38 @@
1-
import unittest
2-
import os
3-
from database.my_codebase import MyCodebase
4-
from app_setup import DB_CONNECTION
1+
# import unittest
2+
# import os
3+
# from unittest.mock import Mock
4+
# from database.my_codebase import MyCodebase
55

66

7-
class MyCodebaseTests(unittest.TestCase):
8-
def setUp(self):
9-
self.codebase = MyCodebase(directory="../", db_connection=DB_CONNECTION)
7+
# class MyCodebaseTests(unittest.TestCase):
8+
# def setUp(self):
9+
# # Create a mock connection object
10+
# conn = Mock()
1011

11-
def test_set_directory(self):
12-
new_directory = os.path.abspath("../")
13-
self.codebase.set_directory(new_directory)
14-
self.assertEqual(self.codebase.directory, os.path.abspath(new_directory))
12+
# # Create a mock cursor object
13+
# cursor = Mock()
1514

16-
def test_is_valid_file(self):
17-
self.assertTrue(self.codebase._is_valid_file("valid_file.py"))
18-
self.assertFalse(self.codebase._is_valid_file(".invalid_file.py"))
15+
# # Configure the mock connection to return the mock cursor when cursor() is called
16+
# conn.cursor.return_value = cursor
17+
# self.codebase = MyCodebase(os.path.abspath("./"), db_connection=conn)
1918

20-
def test_search(self):
21-
search_results = self.codebase.search("search_term")
22-
self.assertIsInstance(search_results, str)
19+
# def test_set_directory(self):
20+
# new_directory = os.path.abspath("../")
21+
# self.codebase.set_directory(new_directory)
22+
# self.assertEqual(self.codebase.directory, os.path.abspath(new_directory))
2323

24-
def test_get_summaries(self):
25-
summaries = self.codebase.get_summaries()
26-
self.assertIsInstance(summaries, dict)
24+
# def test_is_valid_file(self):
25+
# self.assertTrue(self.codebase._is_valid_file("valid_file.py"))
26+
# self.assertFalse(self.codebase._is_valid_file(".invalid_file.py"))
2727

28-
def test_tree(self):
29-
tree = self.codebase.tree()
30-
self.assertIsInstance(tree, str)
28+
# def test_search(self):
29+
# search_results = self.codebase.search("search_term")
30+
# self.assertIsInstance(search_results, str)
31+
32+
# def test_get_summaries(self):
33+
# summaries = self.codebase.get_summaries()
34+
# self.assertIsInstance(summaries, dict)
35+
36+
# def test_tree(self):
37+
# tree = self.codebase.tree()
38+
# self.assertIsInstance(tree, str)
Lines changed: 90 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,90 @@
1-
# import pytest
2-
# from unittest.mock import Mock
3-
# from agent.memory_manager import MemoryManager
4-
# from app_setup import DB_CONNECTION
5-
6-
7-
# @pytest.fixture
8-
# def setup(mocker):
9-
# mocker.patch(
10-
# "openai.ChatCompletion.create",
11-
# return_value={"choices": [{"message": {"content": "summary"}}]},
12-
# )
13-
# memory_manager = MemoryManager(
14-
# model="gpt-3.5-turbo-0613",
15-
# table_name="test",
16-
# db_connection=DB_CONNECTION,
17-
# )
18-
# return memory_manager
19-
20-
21-
# class TestMemoryManager:
22-
# @pytest.fixture(autouse=True)
23-
# def setup_method(self, setup):
24-
# self.memory_manager = setup
25-
26-
# def test_get_total_tokens_in_message(self):
27-
# message = "This is a test message."
28-
# tokens = self.memory_manager.get_total_tokens_in_message(message)
29-
# print(f"TOKENS: {tokens}")
30-
# assert isinstance(tokens, int)
31-
32-
# # def test_add_message(self):
33-
# # role = "user"
34-
# # content = "What's the weather like in Boston?"
35-
# # self.memory_manager.add_message(role, content)
36-
# # messages = self.memory_manager.get_messages()
37-
# # assert messages[0]["role"] == role
38-
# # assert messages[0]["content"] == content
39-
40-
# def test_get_total_tokens(self):
41-
# tokens = self.memory_manager.get_total_tokens()
42-
# assert isinstance(tokens, int)
43-
44-
# def test_get_messages(self):
45-
# messages = self.memory_manager.get_messages()
46-
# assert isinstance(messages, list)
47-
48-
# # def test_summarize(self):
49-
# # message = "This is a test message."
50-
# # summary, tokens = self.memory_manager.summarize(message)
51-
# # assert isinstance(summary, str)
52-
# # assert isinstance(tokens, int)
53-
54-
# # def test_set_system(self):
55-
# # input = {
56-
# # "system": "You are an AI Pair Programmer and a world class python developer helping the Human work on a project."
57-
# # }
58-
# # self.memory_manager.set_system(input)
59-
# # messages = self.memory_manager.get_messages()
60-
# # assert messages[0]["role"] == "system"
61-
# # assert messages[0]["content"] == input["system"]
1+
import pytest
2+
from unittest.mock import Mock
3+
from agent.memory_manager import MemoryManager
4+
5+
6+
@pytest.fixture
7+
def setup():
8+
# Create a mock connection object
9+
conn = Mock()
10+
11+
# Create a mock cursor object
12+
cursor = Mock()
13+
14+
# Configure the mock connection to return the mock cursor when cursor() is called
15+
conn.cursor.return_value = cursor
16+
17+
# Create an instance of MemoryManager with the mock connection
18+
memory_manager = MemoryManager(
19+
model="gpt-3.5-turbo-0613",
20+
table_name="test",
21+
db_connection=conn,
22+
)
23+
return memory_manager
24+
25+
26+
class TestMemoryManager:
27+
@pytest.fixture(autouse=True)
28+
def setup_method(self, setup):
29+
self.memory_manager = setup
30+
31+
def test_get_total_tokens_in_message(self):
32+
message = "This is a test message."
33+
tokens = self.memory_manager.get_total_tokens_in_message(message)
34+
print(f"TOKENS: {tokens}")
35+
assert isinstance(tokens, int)
36+
37+
def test_get_total_tokens(self):
38+
tokens = self.memory_manager.get_total_tokens()
39+
assert (
40+
tokens >= 0
41+
), f"Expected tokens to be greater than or equal to 0, but got {tokens}"
42+
assert isinstance(tokens, int)
43+
44+
def test_get_messages(self):
45+
# Configure the mock cursor's fetchall method to return a list
46+
cursor = self.memory_manager.cur
47+
cursor.fetchall.side_effect = [
48+
[("role1", "system_prompt")], # First call to fetchall
49+
[ # Second call to fetchall
50+
("user", "full_user_message", "user_message", 10),
51+
("assistant", "full_assistant_message", "assistant_message", 20),
52+
],
53+
]
54+
55+
assert self.memory_manager.get_messages() == [
56+
{"role": "role1", "content": "system_prompt"},
57+
{
58+
"role": "assistant",
59+
"content": "assistant_message",
60+
"full_content": "full_assistant_message",
61+
},
62+
{
63+
"role": "user",
64+
"content": "user_message",
65+
"full_content": "full_user_message",
66+
},
67+
]
68+
69+
def test_set_system(self):
70+
input = {
71+
"system": "You are an AI Pair Programmer and a world class python developer helping the Human work on a project."
72+
}
73+
self.memory_manager.set_system(input)
74+
self.memory_manager.cur.execute.assert_called() # Check if execute was called on cursor
75+
76+
def test_add_message(self):
77+
self.memory_manager.add_message("test_role", "test_content")
78+
self.memory_manager.cur.execute.assert_called()
79+
self.memory_manager.conn.commit.assert_called()
80+
call_args = self.memory_manager.cur.execute.call_args
81+
sql_query, params = call_args[0]
82+
assert type(params[0]) == str
83+
assert params[1] == "test_role"
84+
assert params[2] == "test_content"
85+
assert (
86+
params[3] > 0
87+
), f"Expected tokens to be greater than 0, but got {params[3]}"
88+
assert params[4] is None
89+
assert params[5] is None
90+
assert params[6] is not None

0 commit comments

Comments
 (0)