ara-cli 0.1.9.96__py3-none-any.whl → 0.1.10.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ara_cli/__init__.py +1 -1
- ara_cli/__main__.py +4 -2
- ara_cli/ara_command_action.py +54 -1
- ara_cli/ara_command_parser.py +42 -2
- ara_cli/ara_config.py +118 -94
- ara_cli/chat.py +203 -142
- ara_cli/prompt_handler.py +268 -127
- ara_cli/template_loader.py +245 -0
- ara_cli/version.py +1 -1
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.0.dist-info}/METADATA +2 -1
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.0.dist-info}/RECORD +17 -15
- tests/test_chat.py +1840 -574
- tests/test_prompt_handler.py +40 -4
- tests/test_template_loader.py +192 -0
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.0.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.0.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.96.dist-info → ara_cli-0.1.10.0.dist-info}/top_level.txt +0 -0
tests/test_chat.py
CHANGED
|
@@ -8,6 +8,7 @@ import ara_cli
|
|
|
8
8
|
from unittest.mock import patch, MagicMock, mock_open
|
|
9
9
|
from types import SimpleNamespace
|
|
10
10
|
from ara_cli.chat import Chat
|
|
11
|
+
from ara_cli.error_handler import AraError
|
|
11
12
|
from ara_cli.template_manager import TemplatePathManager
|
|
12
13
|
from ara_cli.ara_config import ConfigManager
|
|
13
14
|
from ara_cli.file_loaders.text_file_loader import TextFileLoader
|
|
@@ -49,7 +50,7 @@ def get_default_config():
|
|
|
49
50
|
@pytest.fixture
|
|
50
51
|
def temp_chat_file():
|
|
51
52
|
"""Fixture to create a temporary chat file."""
|
|
52
|
-
temp_file = tempfile.NamedTemporaryFile(delete=True, mode=
|
|
53
|
+
temp_file = tempfile.NamedTemporaryFile(delete=True, mode="w+", encoding="utf-8")
|
|
53
54
|
yield temp_file
|
|
54
55
|
temp_file.close()
|
|
55
56
|
|
|
@@ -57,7 +58,7 @@ def temp_chat_file():
|
|
|
57
58
|
@pytest.fixture
|
|
58
59
|
def temp_load_file():
|
|
59
60
|
"""Fixture to create a temporary file to load."""
|
|
60
|
-
temp_file = tempfile.NamedTemporaryFile(delete=True, mode=
|
|
61
|
+
temp_file = tempfile.NamedTemporaryFile(delete=True, mode="w+", encoding="utf-8")
|
|
61
62
|
temp_file.write("This is the content to load.")
|
|
62
63
|
temp_file.flush()
|
|
63
64
|
yield temp_file
|
|
@@ -65,19 +66,23 @@ def temp_load_file():
|
|
|
65
66
|
|
|
66
67
|
|
|
67
68
|
def test_handle_existing_chat_no_reset(temp_chat_file):
|
|
68
|
-
with patch(
|
|
69
|
+
with patch("builtins.input", return_value="n"):
|
|
69
70
|
mock_config = get_default_config()
|
|
70
|
-
with patch(
|
|
71
|
+
with patch(
|
|
72
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
73
|
+
):
|
|
71
74
|
chat = Chat(temp_chat_file.name, reset=None)
|
|
72
75
|
assert chat.chat_name == temp_chat_file.name
|
|
73
76
|
|
|
74
77
|
|
|
75
78
|
def test_handle_existing_chat_with_reset(temp_chat_file):
|
|
76
|
-
with patch(
|
|
79
|
+
with patch("builtins.input", return_value="y"):
|
|
77
80
|
mock_config = get_default_config()
|
|
78
|
-
with patch(
|
|
81
|
+
with patch(
|
|
82
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
83
|
+
):
|
|
79
84
|
chat = Chat(temp_chat_file.name, reset=None)
|
|
80
|
-
with open(temp_chat_file.name,
|
|
85
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
81
86
|
content = file.read()
|
|
82
87
|
assert content.strip() == "# ara prompt:"
|
|
83
88
|
|
|
@@ -85,33 +90,42 @@ def test_handle_existing_chat_with_reset(temp_chat_file):
|
|
|
85
90
|
def test_handle_existing_chat_reset_flag(temp_chat_file):
|
|
86
91
|
mock_config = get_default_config()
|
|
87
92
|
|
|
88
|
-
with patch(
|
|
93
|
+
with patch(
|
|
94
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
95
|
+
):
|
|
89
96
|
Chat(temp_chat_file.name, reset=True)
|
|
90
|
-
with open(temp_chat_file.name,
|
|
97
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
91
98
|
content = file.read()
|
|
92
99
|
assert content.strip() == "# ara prompt:"
|
|
93
100
|
|
|
94
101
|
|
|
95
|
-
@pytest.mark.parametrize(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
@pytest.mark.parametrize(
|
|
103
|
+
"chat_name, expected_file_name",
|
|
104
|
+
[
|
|
105
|
+
("test", "test_chat.md"),
|
|
106
|
+
("test.md", "test.md"),
|
|
107
|
+
("test_chat", "test_chat.md"),
|
|
108
|
+
("test_chat.md", "test_chat.md"),
|
|
109
|
+
("another_test", "another_test_chat.md"),
|
|
110
|
+
("another_test.md", "another_test.md"),
|
|
111
|
+
],
|
|
112
|
+
)
|
|
103
113
|
def test_initialize_new_chat(chat_name, expected_file_name):
|
|
104
114
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
105
115
|
temp_chat_file_path = os.path.join(temp_dir, "temp_chat_file.md")
|
|
106
116
|
mock_config = get_default_config()
|
|
107
|
-
with patch(
|
|
117
|
+
with patch(
|
|
118
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
119
|
+
):
|
|
108
120
|
chat_instance = Chat(temp_chat_file_path, reset=False)
|
|
109
|
-
created_chat_file = chat_instance.initialize_new_chat(
|
|
121
|
+
created_chat_file = chat_instance.initialize_new_chat(
|
|
122
|
+
os.path.join(temp_dir, chat_name)
|
|
123
|
+
)
|
|
110
124
|
|
|
111
125
|
assert created_chat_file.endswith(expected_file_name)
|
|
112
126
|
assert os.path.exists(created_chat_file)
|
|
113
127
|
|
|
114
|
-
with open(created_chat_file,
|
|
128
|
+
with open(created_chat_file, "r", encoding="utf-8") as file:
|
|
115
129
|
content = file.read()
|
|
116
130
|
|
|
117
131
|
assert content == chat_instance.default_chat_content
|
|
@@ -123,36 +137,49 @@ def test_init_with_limited_command_set():
|
|
|
123
137
|
temp_chat_file_path = os.path.join(temp_dir, "temp_chat_file.md")
|
|
124
138
|
|
|
125
139
|
mock_config = get_default_config()
|
|
126
|
-
with patch(
|
|
127
|
-
|
|
140
|
+
with patch(
|
|
141
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
142
|
+
):
|
|
143
|
+
chat_instance = Chat(
|
|
144
|
+
temp_chat_file_path, reset=False, enable_commands=enable_commands
|
|
145
|
+
)
|
|
128
146
|
|
|
129
|
-
assert
|
|
130
|
-
assert
|
|
131
|
-
assert
|
|
132
|
-
assert
|
|
133
|
-
assert
|
|
147
|
+
assert "r" in chat_instance.aliases
|
|
148
|
+
assert "s" in chat_instance.aliases
|
|
149
|
+
assert "QUIT" in chat_instance.aliases
|
|
150
|
+
assert "q" in chat_instance.aliases
|
|
151
|
+
assert "h" in chat_instance.aliases
|
|
134
152
|
|
|
135
153
|
assert "shell" in chat_instance.hidden_commands
|
|
136
154
|
assert getattr(chat_instance, "do_shell") == chat_instance.default
|
|
137
155
|
|
|
138
156
|
|
|
139
|
-
@pytest.mark.parametrize(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
])
|
|
157
|
+
@pytest.mark.parametrize(
|
|
158
|
+
"chat_name, existing_files, expected",
|
|
159
|
+
[
|
|
160
|
+
("test_chat", ["test_chat"], "test_chat"),
|
|
161
|
+
("test_chat", ["test_chat.md"], "test_chat.md"),
|
|
162
|
+
("test_chat", ["test_chat_chat.md"], "test_chat_chat.md"),
|
|
163
|
+
("new_chat", [], "new_chat_chat.md"),
|
|
164
|
+
],
|
|
165
|
+
)
|
|
145
166
|
def test_setup_chat(monkeypatch, chat_name, existing_files, expected):
|
|
146
167
|
def mock_exists(path):
|
|
147
168
|
return path in existing_files
|
|
148
169
|
|
|
149
|
-
monkeypatch.setattr(os.path,
|
|
150
|
-
monkeypatch.setattr(
|
|
151
|
-
|
|
170
|
+
monkeypatch.setattr(os.path, "exists", mock_exists)
|
|
171
|
+
monkeypatch.setattr(
|
|
172
|
+
Chat, "handle_existing_chat", lambda self, chat_file, reset=None: chat_file
|
|
173
|
+
)
|
|
174
|
+
monkeypatch.setattr(
|
|
175
|
+
Chat, "initialize_new_chat", lambda self, chat_name: f"{chat_name}_chat.md"
|
|
176
|
+
)
|
|
152
177
|
|
|
153
178
|
mock_config = get_default_config()
|
|
154
179
|
|
|
155
|
-
with patch(
|
|
180
|
+
with patch(
|
|
181
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
182
|
+
):
|
|
156
183
|
chat_instance = Chat(chat_name)
|
|
157
184
|
result = chat_instance.setup_chat(chat_name)
|
|
158
185
|
assert result == expected
|
|
@@ -161,7 +188,9 @@ def test_setup_chat(monkeypatch, chat_name, existing_files, expected):
|
|
|
161
188
|
def test_disable_commands(temp_chat_file):
|
|
162
189
|
mock_config = get_default_config()
|
|
163
190
|
|
|
164
|
-
with patch(
|
|
191
|
+
with patch(
|
|
192
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
193
|
+
):
|
|
165
194
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
166
195
|
|
|
167
196
|
chat.aliases["q"] = "quit"
|
|
@@ -174,7 +203,7 @@ def test_disable_commands(temp_chat_file):
|
|
|
174
203
|
chat.disable_commands(commands_to_disable)
|
|
175
204
|
|
|
176
205
|
for command in commands_to_disable:
|
|
177
|
-
assert getattr(chat, f
|
|
206
|
+
assert getattr(chat, f"do_{command}") == chat.default
|
|
178
207
|
assert command in chat.hidden_commands
|
|
179
208
|
|
|
180
209
|
assert "q" not in chat.aliases
|
|
@@ -184,15 +213,37 @@ def test_disable_commands(temp_chat_file):
|
|
|
184
213
|
assert "r" in chat.aliases
|
|
185
214
|
|
|
186
215
|
|
|
187
|
-
@pytest.mark.parametrize(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
216
|
+
@pytest.mark.parametrize(
|
|
217
|
+
"lines, expected",
|
|
218
|
+
[
|
|
219
|
+
(["This is a line.", "Another line here.", "Yet another line."], None),
|
|
220
|
+
(["This is a line.", "# ara prompt:", "Another line here."], "# ara prompt:"),
|
|
221
|
+
(
|
|
222
|
+
[
|
|
223
|
+
"This is a line.",
|
|
224
|
+
"# ara prompt:",
|
|
225
|
+
"Another line here.",
|
|
226
|
+
"# ara response:",
|
|
227
|
+
],
|
|
228
|
+
"# ara response:",
|
|
229
|
+
),
|
|
230
|
+
(
|
|
231
|
+
[
|
|
232
|
+
"This is a line.",
|
|
233
|
+
" # ara prompt: ",
|
|
234
|
+
"Another line here.",
|
|
235
|
+
" # ara response: ",
|
|
236
|
+
],
|
|
237
|
+
"# ara response:",
|
|
238
|
+
),
|
|
239
|
+
(["# ara prompt:", "# ara response:"], "# ara response:"),
|
|
240
|
+
(
|
|
241
|
+
["# ara response:", "# ara prompt:", "# ara prompt:", "# ara response:"],
|
|
242
|
+
"# ara response:",
|
|
243
|
+
),
|
|
244
|
+
([], None),
|
|
245
|
+
],
|
|
246
|
+
)
|
|
196
247
|
def test_get_last_role_marker(lines, expected):
|
|
197
248
|
assert Chat.get_last_role_marker(lines=lines) == expected
|
|
198
249
|
|
|
@@ -202,7 +253,9 @@ def test_start_non_interactive(temp_chat_file, capsys):
|
|
|
202
253
|
temp_chat_file.write(content)
|
|
203
254
|
temp_chat_file.flush()
|
|
204
255
|
mock_config = get_default_config()
|
|
205
|
-
with patch(
|
|
256
|
+
with patch(
|
|
257
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
258
|
+
):
|
|
206
259
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
207
260
|
chat.start_non_interactive()
|
|
208
261
|
|
|
@@ -214,10 +267,12 @@ def test_start_non_interactive(temp_chat_file, capsys):
|
|
|
214
267
|
def test_start(temp_chat_file):
|
|
215
268
|
initial_dir = os.getcwd()
|
|
216
269
|
mock_config = get_default_config()
|
|
217
|
-
with patch(
|
|
270
|
+
with patch(
|
|
271
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
272
|
+
):
|
|
218
273
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
219
274
|
|
|
220
|
-
with patch(
|
|
275
|
+
with patch("ara_cli.chat.Chat.cmdloop") as mock_cmdloop:
|
|
221
276
|
chat.start()
|
|
222
277
|
mock_cmdloop.assert_called_once()
|
|
223
278
|
|
|
@@ -226,103 +281,204 @@ def test_start(temp_chat_file):
|
|
|
226
281
|
os.chdir(initial_dir)
|
|
227
282
|
|
|
228
283
|
|
|
229
|
-
@pytest.mark.parametrize(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
284
|
+
@pytest.mark.parametrize(
|
|
285
|
+
"initial_content, expected_content",
|
|
286
|
+
[
|
|
287
|
+
(
|
|
288
|
+
["This is a line.\n", "Another line here.\n", "Yet another line.\n"],
|
|
289
|
+
[
|
|
290
|
+
"This is a line.\n",
|
|
291
|
+
"Another line here.\n",
|
|
292
|
+
"Yet another line.\n",
|
|
293
|
+
"\n",
|
|
294
|
+
"# ara prompt:",
|
|
295
|
+
],
|
|
296
|
+
),
|
|
297
|
+
(
|
|
298
|
+
["This is a line.\n", "# ara prompt:\n", "Another line here.\n"],
|
|
299
|
+
["This is a line.\n", "# ara prompt:\n", "Another line here.\n"],
|
|
300
|
+
),
|
|
301
|
+
(
|
|
302
|
+
[
|
|
303
|
+
"This is a line.\n",
|
|
304
|
+
"# ara prompt:\n",
|
|
305
|
+
"Another line here.\n",
|
|
306
|
+
"# ara response:\n",
|
|
307
|
+
],
|
|
308
|
+
[
|
|
309
|
+
"This is a line.\n",
|
|
310
|
+
"# ara prompt:\n",
|
|
311
|
+
"Another line here.\n",
|
|
312
|
+
"# ara response:\n",
|
|
313
|
+
"\n",
|
|
314
|
+
"# ara prompt:",
|
|
315
|
+
],
|
|
316
|
+
),
|
|
317
|
+
(
|
|
318
|
+
[
|
|
319
|
+
"This is a line.\n",
|
|
320
|
+
" # ara prompt: \n",
|
|
321
|
+
"Another line here.\n",
|
|
322
|
+
" # ara response: \n",
|
|
323
|
+
],
|
|
324
|
+
[
|
|
325
|
+
"This is a line.\n",
|
|
326
|
+
" # ara prompt: \n",
|
|
327
|
+
"Another line here.\n",
|
|
328
|
+
" # ara response: \n",
|
|
329
|
+
"\n",
|
|
330
|
+
"# ara prompt:",
|
|
331
|
+
],
|
|
332
|
+
),
|
|
333
|
+
(
|
|
334
|
+
["# ara prompt:\n", "# ara response:\n"],
|
|
335
|
+
["# ara prompt:\n", "# ara response:\n", "\n", "# ara prompt:"],
|
|
336
|
+
),
|
|
337
|
+
(
|
|
338
|
+
[
|
|
339
|
+
"# ara response:\n",
|
|
340
|
+
"# ara prompt:\n",
|
|
341
|
+
"# ara prompt:\n",
|
|
342
|
+
"# ara response:\n",
|
|
343
|
+
],
|
|
344
|
+
[
|
|
345
|
+
"# ara response:\n",
|
|
346
|
+
"# ara prompt:\n",
|
|
347
|
+
"# ara prompt:\n",
|
|
348
|
+
"# ara response:\n",
|
|
349
|
+
"\n",
|
|
350
|
+
"# ara prompt:",
|
|
351
|
+
],
|
|
352
|
+
),
|
|
353
|
+
],
|
|
354
|
+
)
|
|
248
355
|
def test_add_prompt_tag_if_needed(temp_chat_file, initial_content, expected_content):
|
|
249
356
|
temp_chat_file.writelines(initial_content)
|
|
250
357
|
temp_chat_file.flush()
|
|
251
358
|
|
|
252
359
|
mock_config = get_default_config()
|
|
253
|
-
with patch(
|
|
254
|
-
|
|
360
|
+
with patch(
|
|
361
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
362
|
+
):
|
|
363
|
+
Chat(temp_chat_file.name, reset=False).add_prompt_tag_if_needed(
|
|
364
|
+
temp_chat_file.name
|
|
365
|
+
)
|
|
255
366
|
|
|
256
|
-
with open(temp_chat_file.name,
|
|
367
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
257
368
|
lines = file.readlines()
|
|
258
369
|
|
|
259
370
|
assert lines == expected_content
|
|
260
371
|
|
|
261
372
|
|
|
262
|
-
@pytest.mark.parametrize(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
373
|
+
@pytest.mark.parametrize(
|
|
374
|
+
"lines, expected",
|
|
375
|
+
[
|
|
376
|
+
(
|
|
377
|
+
["\n", " ", "# ara prompt:", "Another line here.", " \n"],
|
|
378
|
+
"Another line here.",
|
|
379
|
+
),
|
|
380
|
+
(["This is a line.", "Another line here.", " \n", "\n"], "Another line here."),
|
|
381
|
+
(["\n", " \n", " \n"], ""),
|
|
382
|
+
(
|
|
383
|
+
["This is a line.", "Another line here.", "# ara response:", " \n"],
|
|
384
|
+
"# ara response:",
|
|
385
|
+
),
|
|
386
|
+
],
|
|
387
|
+
)
|
|
268
388
|
def test_get_last_non_empty_line(lines, expected, temp_chat_file):
|
|
269
|
-
temp_chat_file.writelines(line +
|
|
389
|
+
temp_chat_file.writelines(line + "\n" for line in lines)
|
|
270
390
|
temp_chat_file.flush()
|
|
271
391
|
|
|
272
|
-
with open(temp_chat_file.name,
|
|
392
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
273
393
|
assert Chat.get_last_non_empty_line(Chat, file) == expected
|
|
274
394
|
|
|
275
395
|
|
|
276
|
-
@pytest.mark.parametrize(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
])
|
|
396
|
+
@pytest.mark.parametrize(
|
|
397
|
+
"lines, expected",
|
|
398
|
+
[
|
|
399
|
+
(["\n", " ", "# ara prompt:", "Another line here.", " \n"], ""),
|
|
400
|
+
(["This is a line.", "Another line here."], "Another line here."),
|
|
401
|
+
(["\n", " \n", " \n"], ""),
|
|
402
|
+
(["This is a line.", "Another line here.", "# ara response:", " \n"], ""),
|
|
403
|
+
([], ""),
|
|
404
|
+
([""], ""),
|
|
405
|
+
],
|
|
406
|
+
)
|
|
284
407
|
def test_get_last_line(lines, expected, temp_chat_file):
|
|
285
|
-
temp_chat_file.writelines(line +
|
|
408
|
+
temp_chat_file.writelines(line + "\n" for line in lines)
|
|
286
409
|
temp_chat_file.flush()
|
|
287
410
|
|
|
288
|
-
with open(temp_chat_file.name,
|
|
411
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
289
412
|
assert Chat.get_last_line(Chat, file) == expected
|
|
290
413
|
|
|
291
414
|
|
|
292
|
-
@pytest.mark.parametrize(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
415
|
+
@pytest.mark.parametrize(
|
|
416
|
+
"chat_history, expected_text_content, expected_image_data_list",
|
|
417
|
+
[
|
|
418
|
+
(["Message 1", "Message 2"], "Message 1\nMessage 2", []),
|
|
419
|
+
(
|
|
420
|
+
["Text with image", "(data:image/png;base64,abc123)"],
|
|
421
|
+
"Text with image",
|
|
422
|
+
[
|
|
423
|
+
{
|
|
424
|
+
"type": "image_url",
|
|
425
|
+
"image_url": {"url": "data:image/png;base64,abc123"},
|
|
426
|
+
}
|
|
427
|
+
],
|
|
428
|
+
),
|
|
429
|
+
(
|
|
430
|
+
["Just text", "Another (data:image/png;base64,xyz789) image"],
|
|
431
|
+
"Just text",
|
|
432
|
+
[
|
|
433
|
+
{
|
|
434
|
+
"type": "image_url",
|
|
435
|
+
"image_url": {"url": "data:image/png;base64,xyz789"},
|
|
436
|
+
}
|
|
437
|
+
],
|
|
438
|
+
),
|
|
439
|
+
(["No images here at all"], "No images here at all", []),
|
|
440
|
+
],
|
|
441
|
+
)
|
|
442
|
+
def test_assemble_prompt(
|
|
443
|
+
temp_chat_file, chat_history, expected_text_content, expected_image_data_list
|
|
444
|
+
):
|
|
303
445
|
mock_config = get_default_config()
|
|
304
|
-
with patch(
|
|
446
|
+
with patch(
|
|
447
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
448
|
+
):
|
|
305
449
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
306
450
|
chat.chat_history = chat_history
|
|
307
451
|
|
|
308
|
-
with patch('ara_cli.prompt_handler.append_images_to_message', return_value="mocked combined content") as mock_append
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
assert combined_content == [{'content': 'You are a helpful assistant that can process both text and images.', 'role': 'system'}, 'mocked combined content']
|
|
452
|
+
with patch('ara_cli.prompt_handler.append_images_to_message', return_value="mocked combined content") as mock_append, \
|
|
453
|
+
patch('ara_cli.prompt_handler.prepend_system_prompt', return_value=[{'role': 'system', 'content': 'You are a helpful assistant that can process both text and images.'}]) as mock_prepend:
|
|
454
|
+
chat.assemble_prompt()
|
|
312
455
|
|
|
313
456
|
mock_append.assert_called_once_with(
|
|
314
|
-
{
|
|
315
|
-
|
|
457
|
+
{
|
|
458
|
+
"role": "user",
|
|
459
|
+
"content": [{"type": "text", "text": expected_text_content}],
|
|
460
|
+
},
|
|
461
|
+
expected_image_data_list,
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
mock_prepend.assert_called_once()
|
|
316
465
|
|
|
317
466
|
|
|
318
|
-
@pytest.mark.parametrize(
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
])
|
|
323
|
-
|
|
467
|
+
@pytest.mark.parametrize(
|
|
468
|
+
"chat_history, last_line_in_file, expected_written_content",
|
|
469
|
+
[
|
|
470
|
+
(["Message 1", "Message 2"], "Some other line", "\n# ara response:\n"),
|
|
471
|
+
(["Message 1", "Message 2"], "Some other line\n", "# ara response:\n"),
|
|
472
|
+
(["Message 1", "Message 2"], "# ara response:", ""),
|
|
473
|
+
],
|
|
474
|
+
)
|
|
475
|
+
def test_send_message(
|
|
476
|
+
temp_chat_file, chat_history, last_line_in_file, expected_written_content
|
|
477
|
+
):
|
|
324
478
|
mock_config = get_default_config()
|
|
325
|
-
with patch(
|
|
479
|
+
with patch(
|
|
480
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
481
|
+
):
|
|
326
482
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
327
483
|
chat.chat_history = chat_history
|
|
328
484
|
|
|
@@ -333,9 +489,9 @@ def test_send_message(temp_chat_file, chat_history, last_line_in_file, expected_
|
|
|
333
489
|
|
|
334
490
|
mock_chunks = [mock_chunk1, mock_chunk2]
|
|
335
491
|
|
|
336
|
-
with patch(
|
|
337
|
-
|
|
338
|
-
|
|
492
|
+
with patch("ara_cli.chat.send_prompt", return_value=mock_chunks), patch.object(
|
|
493
|
+
chat, "get_last_line", return_value=last_line_in_file
|
|
494
|
+
), patch.object(chat, "assemble_prompt", return_value="mocked prompt"):
|
|
339
495
|
|
|
340
496
|
m = mock_open(read_data=last_line_in_file)
|
|
341
497
|
with patch("builtins.open", m):
|
|
@@ -347,67 +503,138 @@ def test_send_message(temp_chat_file, chat_history, last_line_in_file, expected_
|
|
|
347
503
|
assert "response_part_2" in written_content
|
|
348
504
|
|
|
349
505
|
|
|
350
|
-
@pytest.mark.parametrize(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
506
|
+
@pytest.mark.parametrize(
|
|
507
|
+
"role, message, initial_content, expected_content",
|
|
508
|
+
[
|
|
509
|
+
(
|
|
510
|
+
"ara prompt",
|
|
511
|
+
"This is a new prompt message.",
|
|
512
|
+
["Existing content.\n"],
|
|
513
|
+
[
|
|
514
|
+
"Existing content.\n",
|
|
515
|
+
"\n",
|
|
516
|
+
"# ara prompt:\nThis is a new prompt message.\n",
|
|
517
|
+
],
|
|
518
|
+
),
|
|
519
|
+
(
|
|
520
|
+
"ara response",
|
|
521
|
+
"This is a new response message.",
|
|
522
|
+
["# ara prompt:\nThis is a prompt.\n"],
|
|
523
|
+
[
|
|
524
|
+
"# ara prompt:\nThis is a prompt.\n",
|
|
525
|
+
"\n",
|
|
526
|
+
"# ara response:\nThis is a new response message.\n",
|
|
527
|
+
],
|
|
528
|
+
),
|
|
529
|
+
(
|
|
530
|
+
"ara prompt",
|
|
531
|
+
"This is another prompt.",
|
|
532
|
+
["# ara response:\nThis is a response.\n"],
|
|
533
|
+
[
|
|
534
|
+
"# ara response:\nThis is a response.\n",
|
|
535
|
+
"\n",
|
|
536
|
+
"# ara prompt:\nThis is another prompt.\n",
|
|
537
|
+
],
|
|
538
|
+
),
|
|
539
|
+
(
|
|
540
|
+
"ara response",
|
|
541
|
+
"Another response here.",
|
|
542
|
+
["# ara prompt:\nPrompt here.\n", "# ara response:\nFirst response.\n"],
|
|
543
|
+
[
|
|
544
|
+
"# ara prompt:\nPrompt here.\n",
|
|
545
|
+
"# ara response:\nFirst response.\n",
|
|
546
|
+
"\n",
|
|
547
|
+
"# ara response:\nAnother response here.\n",
|
|
548
|
+
],
|
|
549
|
+
),
|
|
550
|
+
(
|
|
551
|
+
"ara prompt",
|
|
552
|
+
"Final prompt message.",
|
|
553
|
+
["# ara prompt:\nInitial prompt.\n", "# ara response:\nResponse here.\n"],
|
|
554
|
+
[
|
|
555
|
+
"# ara prompt:\nInitial prompt.\n",
|
|
556
|
+
"# ara response:\nResponse here.\n",
|
|
557
|
+
"\n",
|
|
558
|
+
"# ara prompt:\nFinal prompt message.\n",
|
|
559
|
+
],
|
|
560
|
+
),
|
|
561
|
+
],
|
|
562
|
+
)
|
|
371
563
|
def test_save_message(temp_chat_file, role, message, initial_content, expected_content):
|
|
372
564
|
temp_chat_file.writelines(initial_content)
|
|
373
565
|
temp_chat_file.flush()
|
|
374
566
|
|
|
375
567
|
mock_config = get_default_config()
|
|
376
|
-
with patch(
|
|
568
|
+
with patch(
|
|
569
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
570
|
+
):
|
|
377
571
|
chat_instance = Chat(temp_chat_file.name, reset=False)
|
|
378
572
|
chat_instance.save_message(role, message)
|
|
379
573
|
|
|
380
|
-
with open(temp_chat_file.name,
|
|
574
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
381
575
|
lines = file.readlines()
|
|
382
576
|
|
|
383
|
-
assert
|
|
577
|
+
assert "".join(lines) == "".join(expected_content)
|
|
384
578
|
|
|
385
579
|
|
|
386
|
-
@pytest.mark.parametrize(
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
580
|
+
@pytest.mark.parametrize(
|
|
581
|
+
"initial_content, expected_content",
|
|
582
|
+
[
|
|
583
|
+
(
|
|
584
|
+
[
|
|
585
|
+
"# ara prompt:\nPrompt message.\n",
|
|
586
|
+
"# ara response:\nResponse message.\n",
|
|
587
|
+
],
|
|
588
|
+
["# ara prompt:\nPrompt message.\n"],
|
|
589
|
+
),
|
|
590
|
+
(
|
|
591
|
+
[
|
|
592
|
+
"# ara prompt:\nPrompt message 1.\n",
|
|
593
|
+
"# ara response:\nResponse message 1.\n",
|
|
594
|
+
"# ara prompt:\nPrompt message 2.\n",
|
|
595
|
+
"# ara response:\nResponse message 2.\n",
|
|
596
|
+
],
|
|
597
|
+
[
|
|
598
|
+
"# ara prompt:\nPrompt message 1.\n",
|
|
599
|
+
"# ara response:\nResponse message 1.\n",
|
|
600
|
+
"# ara prompt:\nPrompt message 2.\n",
|
|
601
|
+
],
|
|
602
|
+
),
|
|
603
|
+
(
|
|
604
|
+
["# ara prompt:\nOnly prompt message.\n"],
|
|
605
|
+
["# ara prompt:\nOnly prompt message.\n"],
|
|
606
|
+
),
|
|
607
|
+
(
|
|
608
|
+
[
|
|
609
|
+
"# ara prompt:\nPrompt message.\n",
|
|
610
|
+
"# ara response:\nResponse message.\n",
|
|
611
|
+
"# ara prompt:\nAnother prompt message.\n",
|
|
612
|
+
],
|
|
613
|
+
[
|
|
614
|
+
"# ara prompt:\nPrompt message.\n",
|
|
615
|
+
"# ara response:\nResponse message.\n",
|
|
616
|
+
"# ara prompt:\nAnother prompt message.\n",
|
|
617
|
+
],
|
|
618
|
+
),
|
|
619
|
+
],
|
|
620
|
+
)
|
|
396
621
|
def test_resend_message(temp_chat_file, initial_content, expected_content):
|
|
397
622
|
temp_chat_file.writelines(initial_content)
|
|
398
623
|
temp_chat_file.flush()
|
|
399
624
|
|
|
400
625
|
mock_config = get_default_config()
|
|
401
|
-
with patch(
|
|
626
|
+
with patch(
|
|
627
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
628
|
+
):
|
|
402
629
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
403
630
|
|
|
404
|
-
with patch.object(chat,
|
|
631
|
+
with patch.object(chat, "send_message") as mock_send_message:
|
|
405
632
|
chat.resend_message()
|
|
406
633
|
|
|
407
|
-
with open(temp_chat_file.name,
|
|
634
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
408
635
|
lines = file.readlines()
|
|
409
636
|
|
|
410
|
-
assert
|
|
637
|
+
assert "".join(lines) == "".join(expected_content)
|
|
411
638
|
mock_send_message.assert_called_once()
|
|
412
639
|
|
|
413
640
|
|
|
@@ -416,76 +643,64 @@ def test_resend_message_empty(temp_chat_file):
|
|
|
416
643
|
temp_chat_file.flush()
|
|
417
644
|
|
|
418
645
|
mock_config = get_default_config()
|
|
419
|
-
with patch(
|
|
646
|
+
with patch(
|
|
647
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
648
|
+
):
|
|
420
649
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
421
650
|
|
|
422
|
-
with patch.object(chat,
|
|
651
|
+
with patch.object(chat, "send_message") as mock_send_message:
|
|
423
652
|
chat.resend_message()
|
|
424
653
|
|
|
425
|
-
with open(temp_chat_file.name,
|
|
654
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
426
655
|
lines = file.readlines()
|
|
427
656
|
|
|
428
|
-
assert
|
|
429
|
-
assert
|
|
657
|
+
assert "".join(lines) == ""
|
|
658
|
+
assert "".join(chat.chat_history) == ""
|
|
430
659
|
mock_send_message.assert_not_called()
|
|
431
660
|
|
|
432
661
|
|
|
433
|
-
@pytest.mark.parametrize(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
])
|
|
662
|
+
@pytest.mark.parametrize(
|
|
663
|
+
"strings, expected_content",
|
|
664
|
+
[
|
|
665
|
+
(["Line 1", "Line 2", "Line 3"], "Line 1\nLine 2\nLine 3\n"),
|
|
666
|
+
(["Single line"], "Single line\n"),
|
|
667
|
+
(["First line", "", "Third line"], "First line\n\nThird line\n"),
|
|
668
|
+
([], "\n"),
|
|
669
|
+
],
|
|
670
|
+
)
|
|
439
671
|
def test_append_strings(temp_chat_file, strings, expected_content):
|
|
440
672
|
mock_config = get_default_config()
|
|
441
|
-
with patch(
|
|
673
|
+
with patch(
|
|
674
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
675
|
+
):
|
|
442
676
|
chat_instance = Chat(temp_chat_file.name, reset=False)
|
|
443
677
|
chat_instance.append_strings(strings)
|
|
444
678
|
|
|
445
|
-
with open(temp_chat_file.name,
|
|
679
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
446
680
|
content = file.read()
|
|
447
681
|
|
|
448
682
|
assert content == expected_content
|
|
449
683
|
|
|
450
684
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
("existing_elsewhere.txt", False, True, "existing_elsewhere.txt"),
|
|
459
|
-
("non_existent.txt", False, False, None),
|
|
460
|
-
]
|
|
461
|
-
|
|
462
|
-
with patch('os.path.exists') as mock_exists, \
|
|
463
|
-
patch('os.path.dirname', return_value="current_directory") as mock_dirname:
|
|
464
|
-
|
|
465
|
-
for file_name, exists_in_current, exists_elsewhere, expected_path in test_cases:
|
|
466
|
-
mock_exists.side_effect = [exists_in_current, exists_elsewhere]
|
|
467
|
-
|
|
468
|
-
result = chat.determine_file_path(file_name)
|
|
469
|
-
|
|
470
|
-
assert result == expected_path
|
|
471
|
-
|
|
472
|
-
mock_exists.reset_mock()
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
@pytest.mark.parametrize("file_name, expected_content", [
|
|
476
|
-
("document.txt", "Hello World\n"),
|
|
477
|
-
("another_document.txt", "Another World\n"),
|
|
478
|
-
])
|
|
685
|
+
@pytest.mark.parametrize(
|
|
686
|
+
"file_name, expected_content",
|
|
687
|
+
[
|
|
688
|
+
("document.txt", "Hello World\n"),
|
|
689
|
+
("another_document.txt", "Another World\n"),
|
|
690
|
+
],
|
|
691
|
+
)
|
|
479
692
|
def test_load_text_file(temp_chat_file, file_name, expected_content):
|
|
480
693
|
# Create a mock config
|
|
481
694
|
mock_config = MagicMock()
|
|
482
695
|
|
|
483
696
|
# Patch the get_config method to return the mock config
|
|
484
|
-
with patch(
|
|
697
|
+
with patch(
|
|
698
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
699
|
+
):
|
|
485
700
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
486
701
|
|
|
487
702
|
# Mock the TextFileLoader
|
|
488
|
-
with patch.object(TextFileLoader,
|
|
703
|
+
with patch.object(TextFileLoader, "load", return_value=True) as mock_load:
|
|
489
704
|
# Call the load_text_file method
|
|
490
705
|
result = chat.load_text_file(file_name)
|
|
491
706
|
|
|
@@ -501,7 +716,7 @@ def test_load_text_file(temp_chat_file, file_name, expected_content):
|
|
|
501
716
|
[
|
|
502
717
|
True,
|
|
503
718
|
# False # TODO: @file_exists_check decorator should be fixed
|
|
504
|
-
]
|
|
719
|
+
],
|
|
505
720
|
)
|
|
506
721
|
def test_load_binary_file(temp_chat_file, path_exists):
|
|
507
722
|
"""
|
|
@@ -515,24 +730,30 @@ def test_load_binary_file(temp_chat_file, path_exists):
|
|
|
515
730
|
file_content = b"fake-binary-data"
|
|
516
731
|
|
|
517
732
|
mock_config = get_default_config()
|
|
518
|
-
with patch(
|
|
733
|
+
with patch(
|
|
734
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
735
|
+
):
|
|
519
736
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
520
737
|
|
|
521
738
|
# Path to the actual file to be loaded
|
|
522
739
|
path_to_load = file_name if path_exists else None
|
|
523
740
|
|
|
524
741
|
# We patch open within the loader's module
|
|
525
|
-
with patch(
|
|
526
|
-
|
|
742
|
+
with patch(
|
|
743
|
+
"ara_cli.file_loaders.binary_file_loader.open",
|
|
744
|
+
mock_open(read_data=file_content),
|
|
745
|
+
) as mock_loader_open:
|
|
527
746
|
|
|
528
|
-
result = chat.load_binary_file(
|
|
747
|
+
result = chat.load_binary_file(
|
|
748
|
+
file_name, mime_type=mime_type, prefix="PRE-", suffix="-POST"
|
|
749
|
+
)
|
|
529
750
|
|
|
530
751
|
if path_exists:
|
|
531
752
|
assert result is True
|
|
532
753
|
# Check read call for the image
|
|
533
|
-
mock_loader_open.assert_any_call(file_name,
|
|
754
|
+
mock_loader_open.assert_any_call(file_name, "rb")
|
|
534
755
|
# Check write call to the chat file
|
|
535
|
-
mock_loader_open.assert_any_call(chat.chat_name,
|
|
756
|
+
mock_loader_open.assert_any_call(chat.chat_name, "a", encoding="utf-8")
|
|
536
757
|
|
|
537
758
|
# Assuming the loader formats it as a base64 markdown image
|
|
538
759
|
base64_encoded = base64.b64encode(file_content).decode("utf-8")
|
|
@@ -548,88 +769,117 @@ def test_load_binary_file(temp_chat_file, path_exists):
|
|
|
548
769
|
mock_loader_open.assert_not_called()
|
|
549
770
|
|
|
550
771
|
|
|
551
|
-
@pytest.mark.parametrize(
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
772
|
+
@pytest.mark.parametrize(
|
|
773
|
+
"file_name, module_to_mock, mock_setup, expected_content",
|
|
774
|
+
[
|
|
775
|
+
(
|
|
776
|
+
"test.docx",
|
|
777
|
+
"docx",
|
|
778
|
+
lambda mock: setattr(
|
|
779
|
+
mock.Document.return_value,
|
|
780
|
+
"paragraphs",
|
|
781
|
+
[MagicMock(text="Docx content")],
|
|
782
|
+
),
|
|
783
|
+
"Docx content",
|
|
784
|
+
),
|
|
785
|
+
pytest.param(
|
|
786
|
+
"test.pdf",
|
|
787
|
+
"pymupdf4llm",
|
|
788
|
+
lambda mock: setattr(
|
|
789
|
+
mock, "to_markdown", MagicMock(return_value="PDF content")
|
|
790
|
+
),
|
|
791
|
+
"PDF content",
|
|
792
|
+
marks=pytest.mark.filterwarnings("ignore::DeprecationWarning"),
|
|
793
|
+
),
|
|
794
|
+
pytest.param(
|
|
795
|
+
"test.odt",
|
|
796
|
+
"pymupdf4llm",
|
|
797
|
+
lambda mock: setattr(
|
|
798
|
+
mock, "to_markdown", MagicMock(return_value="ODT content")
|
|
799
|
+
),
|
|
800
|
+
"ODT content",
|
|
801
|
+
marks=pytest.mark.filterwarnings("ignore::DeprecationWarning"),
|
|
802
|
+
),
|
|
803
|
+
],
|
|
804
|
+
)
|
|
805
|
+
def test_load_document_file(
|
|
806
|
+
temp_chat_file, file_name, module_to_mock, mock_setup, expected_content
|
|
807
|
+
):
|
|
574
808
|
mock_config = get_default_config()
|
|
575
|
-
with patch(
|
|
809
|
+
with patch(
|
|
810
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
811
|
+
):
|
|
576
812
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
577
813
|
|
|
578
814
|
# Patch the dependency in sys.modules before it's imported inside the method
|
|
579
|
-
with patch.dict(
|
|
815
|
+
with patch.dict("sys.modules", {module_to_mock: MagicMock()}) as mock_modules:
|
|
580
816
|
mock_setup(mock_modules[module_to_mock])
|
|
581
817
|
|
|
582
|
-
with patch(
|
|
583
|
-
|
|
818
|
+
with patch(
|
|
819
|
+
"ara_cli.file_loaders.document_file_loader.open", mock_open()
|
|
820
|
+
) as mock_chat_open:
|
|
584
821
|
# FIX: Call with a positional argument `file_name` as the decorator expects, not a keyword `file_path`.
|
|
585
822
|
result = chat.load_document_file(
|
|
586
|
-
file_name, prefix="Prefix-", suffix="-Suffix", block_delimiter="```"
|
|
823
|
+
file_name, prefix="Prefix-", suffix="-Suffix", block_delimiter="```"
|
|
824
|
+
)
|
|
587
825
|
|
|
588
826
|
assert result is True
|
|
589
827
|
expected_write = f"Prefix-```\n{expected_content}\n```-Suffix\n"
|
|
590
|
-
mock_chat_open.assert_called_with(
|
|
591
|
-
chat.chat_name, 'a', encoding='utf-8')
|
|
828
|
+
mock_chat_open.assert_called_with(chat.chat_name, "a", encoding="utf-8")
|
|
592
829
|
mock_chat_open().write.assert_called_once_with(expected_write)
|
|
593
830
|
|
|
594
831
|
|
|
595
832
|
def test_load_document_file_unsupported(temp_chat_file, capsys):
|
|
596
833
|
mock_config = get_default_config()
|
|
597
|
-
with patch(
|
|
834
|
+
with patch(
|
|
835
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
836
|
+
):
|
|
598
837
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
599
838
|
|
|
600
839
|
unsupported_file = "test.txt"
|
|
601
|
-
|
|
602
|
-
result = chat.load_document_file(unsupported_file)
|
|
840
|
+
result = chat.load_document_file(unsupported_file)
|
|
603
841
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
842
|
+
assert result is False
|
|
843
|
+
captured = capsys.readouterr()
|
|
844
|
+
assert "Unsupported document type." in captured.out
|
|
607
845
|
|
|
608
846
|
|
|
609
|
-
@pytest.mark.parametrize(
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
847
|
+
@pytest.mark.parametrize(
|
|
848
|
+
"file_name, file_type, mime_type",
|
|
849
|
+
[
|
|
850
|
+
("image.png", "binary", "image/png"),
|
|
851
|
+
("document.txt", "text", None),
|
|
852
|
+
("document.docx", "document", None),
|
|
853
|
+
("document.pdf", "document", None),
|
|
854
|
+
("archive.zip", "text", None),
|
|
855
|
+
],
|
|
856
|
+
)
|
|
616
857
|
def test_load_file(temp_chat_file, file_name, file_type, mime_type):
|
|
617
858
|
mock_config = get_default_config()
|
|
618
|
-
with patch(
|
|
859
|
+
with patch(
|
|
860
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
861
|
+
):
|
|
619
862
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
620
863
|
|
|
621
|
-
with patch.object(
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
864
|
+
with patch.object(
|
|
865
|
+
chat, "load_binary_file", return_value=True
|
|
866
|
+
) as mock_load_binary, patch.object(
|
|
867
|
+
chat, "load_text_file", return_value=True
|
|
868
|
+
) as mock_load_text, patch.object(
|
|
869
|
+
chat, "load_document_file", return_value=True
|
|
870
|
+
) as mock_load_document:
|
|
871
|
+
|
|
872
|
+
chat.load_file(
|
|
873
|
+
file_name=file_name,
|
|
874
|
+
prefix="p-",
|
|
875
|
+
suffix="-f",
|
|
876
|
+
block_delimiter="b",
|
|
877
|
+
extract_images=False,
|
|
878
|
+
)
|
|
626
879
|
|
|
627
880
|
if file_type == "binary":
|
|
628
881
|
mock_load_binary.assert_called_once_with(
|
|
629
|
-
file_path=file_name,
|
|
630
|
-
mime_type=mime_type,
|
|
631
|
-
prefix="p-",
|
|
632
|
-
suffix="-f"
|
|
882
|
+
file_path=file_name, mime_type=mime_type, prefix="p-", suffix="-f"
|
|
633
883
|
)
|
|
634
884
|
mock_load_text.assert_not_called()
|
|
635
885
|
mock_load_document.assert_not_called()
|
|
@@ -641,7 +891,7 @@ def test_load_file(temp_chat_file, file_name, file_type, mime_type):
|
|
|
641
891
|
prefix="p-",
|
|
642
892
|
suffix="-f",
|
|
643
893
|
block_delimiter="b",
|
|
644
|
-
extract_images=False
|
|
894
|
+
extract_images=False,
|
|
645
895
|
)
|
|
646
896
|
else:
|
|
647
897
|
mock_load_binary.assert_not_called()
|
|
@@ -650,30 +900,63 @@ def test_load_file(temp_chat_file, file_name, file_type, mime_type):
|
|
|
650
900
|
prefix="p-",
|
|
651
901
|
suffix="-f",
|
|
652
902
|
block_delimiter="b",
|
|
653
|
-
extract_images=False
|
|
903
|
+
extract_images=False,
|
|
654
904
|
)
|
|
655
905
|
mock_load_document.assert_not_called()
|
|
656
906
|
|
|
657
907
|
|
|
658
|
-
@pytest.mark.parametrize(
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
]
|
|
667
|
-
|
|
908
|
+
@pytest.mark.parametrize(
|
|
909
|
+
"files, pattern, user_input, expected_output, expected_file",
|
|
910
|
+
[
|
|
911
|
+
# Single file cases - should return directly without prompting
|
|
912
|
+
(["file1.md"], "*.md", "", None, "file1.md"),
|
|
913
|
+
(["single_file.txt"], "pattern", "", None, "single_file.txt"),
|
|
914
|
+
# Multiple files with normal pattern - should prompt user
|
|
915
|
+
(
|
|
916
|
+
["file1.md", "file2.md"],
|
|
917
|
+
"*.md",
|
|
918
|
+
"1",
|
|
919
|
+
"1: file1.md\n2: file2.md\n",
|
|
920
|
+
"file1.md",
|
|
921
|
+
),
|
|
922
|
+
(
|
|
923
|
+
["file1.md", "file2.md"],
|
|
924
|
+
"*.md",
|
|
925
|
+
"2",
|
|
926
|
+
"1: file1.md\n2: file2.md\n",
|
|
927
|
+
"file2.md",
|
|
928
|
+
),
|
|
929
|
+
# Special patterns that force prompting even with single file
|
|
930
|
+
(["single_file.md"], "*", "1", "1: single_file.md\n", "single_file.md"),
|
|
931
|
+
(["single_file.md"], "global/*", "1", "1: single_file.md\n", "single_file.md"),
|
|
932
|
+
# Multiple files with special patterns
|
|
933
|
+
(["file1.md", "file2.md"], "*", "1", "1: file1.md\n2: file2.md\n", "file1.md"),
|
|
934
|
+
(
|
|
935
|
+
["global_file1.md", "global_file2.md"],
|
|
936
|
+
"global/*",
|
|
937
|
+
"2",
|
|
938
|
+
"1: global_file1.md\n2: global_file2.md\n",
|
|
939
|
+
"global_file2.md",
|
|
940
|
+
),
|
|
941
|
+
],
|
|
942
|
+
)
|
|
943
|
+
def test_choose_file_to_load_valid_cases(
|
|
944
|
+
monkeypatch, capsys, files, pattern, user_input, expected_output, expected_file
|
|
945
|
+
):
|
|
946
|
+
"""Test choose_file_to_load with valid inputs and successful selections"""
|
|
947
|
+
|
|
668
948
|
def mock_input(prompt):
|
|
669
949
|
return user_input
|
|
670
950
|
|
|
671
|
-
monkeypatch.setattr(
|
|
951
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
672
952
|
|
|
673
953
|
mock_config = get_default_config()
|
|
674
|
-
with patch(
|
|
954
|
+
with patch(
|
|
955
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
956
|
+
):
|
|
675
957
|
with patch("builtins.open", mock_open()):
|
|
676
958
|
chat = Chat("dummy_chat_name", reset=False)
|
|
959
|
+
|
|
677
960
|
file_path = chat.choose_file_to_load(files, pattern)
|
|
678
961
|
|
|
679
962
|
captured = capsys.readouterr()
|
|
@@ -684,17 +967,340 @@ def test_choose_file_to_load(monkeypatch, capsys, files, pattern, user_input, ex
|
|
|
684
967
|
assert file_path == expected_file
|
|
685
968
|
|
|
686
969
|
|
|
687
|
-
@pytest.mark.parametrize(
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
970
|
+
@pytest.mark.parametrize(
|
|
971
|
+
"files, pattern, user_input, expected_error_message",
|
|
972
|
+
[
|
|
973
|
+
# Choice index out of range (too high)
|
|
974
|
+
(["file1.md", "file2.md"], "*.md", "3", "Invalid choice. Aborting load."),
|
|
975
|
+
(
|
|
976
|
+
["file1.md", "file2.md", "file3.md"],
|
|
977
|
+
"*.md",
|
|
978
|
+
"4",
|
|
979
|
+
"Invalid choice. Aborting load.",
|
|
980
|
+
),
|
|
981
|
+
# Choice index out of range (zero)
|
|
982
|
+
(["file1.md", "file2.md"], "*.md", "0", "Invalid choice. Aborting load."),
|
|
983
|
+
# Choice index out of range (negative)
|
|
984
|
+
(["file1.md", "file2.md"], "*.md", "-1", "Invalid choice. Aborting load."),
|
|
985
|
+
(["file1.md", "file2.md"], "*.md", "-5", "Invalid choice. Aborting load."),
|
|
986
|
+
# Special patterns with out of range choices
|
|
987
|
+
(["file1.md"], "*", "2", "Invalid choice. Aborting load."),
|
|
988
|
+
(["file1.md"], "global/*", "0", "Invalid choice. Aborting load."),
|
|
989
|
+
],
|
|
990
|
+
)
|
|
991
|
+
@patch("ara_cli.error_handler.report_error")
|
|
992
|
+
def test_choose_file_to_load_invalid_choice_index(
|
|
993
|
+
mock_report_error,
|
|
994
|
+
monkeypatch,
|
|
995
|
+
capsys,
|
|
996
|
+
files,
|
|
997
|
+
pattern,
|
|
998
|
+
user_input,
|
|
999
|
+
expected_error_message,
|
|
1000
|
+
):
|
|
1001
|
+
"""Test choose_file_to_load with invalid choice indices"""
|
|
1002
|
+
|
|
1003
|
+
def mock_input(prompt):
|
|
1004
|
+
return user_input
|
|
1005
|
+
|
|
1006
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1007
|
+
|
|
1008
|
+
mock_config = get_default_config()
|
|
1009
|
+
with patch(
|
|
1010
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1011
|
+
):
|
|
1012
|
+
with patch("builtins.open", mock_open()):
|
|
1013
|
+
chat = Chat("dummy_chat_name", reset=False)
|
|
1014
|
+
|
|
1015
|
+
file_path = chat.choose_file_to_load(files, pattern)
|
|
1016
|
+
|
|
1017
|
+
# Verify error was reported
|
|
1018
|
+
mock_report_error.assert_called_once()
|
|
1019
|
+
error_call = mock_report_error.call_args[0][0]
|
|
1020
|
+
assert isinstance(error_call, ValueError)
|
|
1021
|
+
assert str(error_call) == expected_error_message
|
|
1022
|
+
|
|
1023
|
+
# Verify None was returned
|
|
1024
|
+
assert file_path is None
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
@pytest.mark.parametrize(
|
|
1028
|
+
"files, pattern, user_input, expected_error_message",
|
|
1029
|
+
[
|
|
1030
|
+
# Non-numeric input
|
|
1031
|
+
(["file1.md", "file2.md"], "*.md", "invalid", "Invalid input. Aborting load."),
|
|
1032
|
+
(["file1.md", "file2.md"], "*.md", "abc", "Invalid input. Aborting load."),
|
|
1033
|
+
(["file1.md", "file2.md"], "*.md", "1.5", "Invalid input. Aborting load."),
|
|
1034
|
+
# Empty input
|
|
1035
|
+
(["file1.md", "file2.md"], "*.md", "", "Invalid input. Aborting load."),
|
|
1036
|
+
# Special characters
|
|
1037
|
+
(["file1.md", "file2.md"], "*.md", "!", "Invalid input. Aborting load."),
|
|
1038
|
+
(["file1.md", "file2.md"], "*.md", "@#$", "Invalid input. Aborting load."),
|
|
1039
|
+
# Special patterns with invalid input
|
|
1040
|
+
(
|
|
1041
|
+
["file1.md", "file2.md"],
|
|
1042
|
+
"*",
|
|
1043
|
+
"not_a_number",
|
|
1044
|
+
"Invalid input. Aborting load.",
|
|
1045
|
+
),
|
|
1046
|
+
(["file1.md", "file2.md"], "global/*", "xyz", "Invalid input. Aborting load."),
|
|
1047
|
+
],
|
|
1048
|
+
)
|
|
1049
|
+
@patch("ara_cli.error_handler.report_error")
|
|
1050
|
+
def test_choose_file_to_load_invalid_input_format(
|
|
1051
|
+
mock_report_error,
|
|
1052
|
+
monkeypatch,
|
|
1053
|
+
capsys,
|
|
1054
|
+
files,
|
|
1055
|
+
pattern,
|
|
1056
|
+
user_input,
|
|
1057
|
+
expected_error_message,
|
|
1058
|
+
):
|
|
1059
|
+
"""Test choose_file_to_load with non-numeric and invalid input formats"""
|
|
1060
|
+
|
|
1061
|
+
def mock_input(prompt):
|
|
1062
|
+
return user_input
|
|
1063
|
+
|
|
1064
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1065
|
+
|
|
1066
|
+
mock_config = get_default_config()
|
|
1067
|
+
with patch(
|
|
1068
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1069
|
+
):
|
|
1070
|
+
with patch("builtins.open", mock_open()):
|
|
1071
|
+
chat = Chat("dummy_chat_name", reset=False)
|
|
1072
|
+
|
|
1073
|
+
file_path = chat.choose_file_to_load(files, pattern)
|
|
1074
|
+
|
|
1075
|
+
# Verify error was reported
|
|
1076
|
+
mock_report_error.assert_called_once()
|
|
1077
|
+
error_call = mock_report_error.call_args[0][0]
|
|
1078
|
+
assert isinstance(error_call, ValueError)
|
|
1079
|
+
assert str(error_call) == expected_error_message
|
|
1080
|
+
|
|
1081
|
+
# Verify None was returned
|
|
1082
|
+
assert file_path is None
|
|
1083
|
+
|
|
1084
|
+
|
|
1085
|
+
def test_choose_file_to_load_files_are_sorted(monkeypatch, capsys):
|
|
1086
|
+
"""Test that files are sorted before displaying to user"""
|
|
1087
|
+
files = ["zebra.md", "alpha.md", "beta.md"]
|
|
1088
|
+
expected_order = ["alpha.md", "beta.md", "zebra.md"]
|
|
1089
|
+
|
|
1090
|
+
def mock_input(prompt):
|
|
1091
|
+
return "2" # Choose the second file (beta.md after sorting)
|
|
1092
|
+
|
|
1093
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1094
|
+
|
|
1095
|
+
mock_config = get_default_config()
|
|
1096
|
+
with patch(
|
|
1097
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1098
|
+
):
|
|
1099
|
+
with patch("builtins.open", mock_open()):
|
|
1100
|
+
chat = Chat("dummy_chat_name", reset=False)
|
|
1101
|
+
|
|
1102
|
+
file_path = chat.choose_file_to_load(files, "*.md")
|
|
1103
|
+
|
|
1104
|
+
captured = capsys.readouterr()
|
|
1105
|
+
|
|
1106
|
+
# Verify files are displayed in sorted order
|
|
1107
|
+
assert "1: alpha.md" in captured.out
|
|
1108
|
+
assert "2: beta.md" in captured.out
|
|
1109
|
+
assert "3: zebra.md" in captured.out
|
|
1110
|
+
|
|
1111
|
+
# Verify correct file was selected (beta.md, which is index 1 after sorting)
|
|
1112
|
+
assert file_path == "beta.md"
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
def test_choose_file_to_load_basename_displayed(monkeypatch, capsys):
|
|
1116
|
+
"""Test that only basenames are displayed to user, not full paths"""
|
|
1117
|
+
files = ["/long/path/to/file1.md", "/another/long/path/file2.md"]
|
|
1118
|
+
|
|
1119
|
+
def mock_input(prompt):
|
|
1120
|
+
return "1"
|
|
1121
|
+
|
|
1122
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1123
|
+
|
|
1124
|
+
mock_config = get_default_config()
|
|
1125
|
+
with patch(
|
|
1126
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1127
|
+
):
|
|
1128
|
+
with patch("builtins.open", mock_open()):
|
|
1129
|
+
chat = Chat("dummy_chat_name", reset=False)
|
|
1130
|
+
|
|
1131
|
+
file_path = chat.choose_file_to_load(files, "*.md")
|
|
1132
|
+
|
|
1133
|
+
captured = capsys.readouterr()
|
|
1134
|
+
|
|
1135
|
+
# Verify only basenames are shown, not full paths
|
|
1136
|
+
assert "1: file2.md" in captured.out
|
|
1137
|
+
assert "2: file1.md" in captured.out
|
|
1138
|
+
assert "/long/path/to/" not in captured.out
|
|
1139
|
+
assert "/another/long/path/" not in captured.out
|
|
1140
|
+
|
|
1141
|
+
# But full path should be returned
|
|
1142
|
+
assert file_path == "/another/long/path/file2.md"
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
def test_choose_file_to_load_empty_files_list(monkeypatch):
|
|
1146
|
+
"""Test choose_file_to_load with empty files list"""
|
|
1147
|
+
|
|
1148
|
+
def mock_input(prompt):
|
|
1149
|
+
return "1"
|
|
1150
|
+
|
|
1151
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1152
|
+
|
|
1153
|
+
mock_config = get_default_config()
|
|
1154
|
+
with patch(
|
|
1155
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1156
|
+
):
|
|
1157
|
+
with patch("builtins.open", mock_open()):
|
|
1158
|
+
chat = Chat("dummy_chat_name", reset=False)
|
|
1159
|
+
|
|
1160
|
+
# With empty list, should go to else branch and try to access files[0]
|
|
1161
|
+
# This will raise IndexError, but let's test the actual behavior
|
|
1162
|
+
with pytest.raises(IndexError):
|
|
1163
|
+
chat.choose_file_to_load([], "pattern")
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
def test_choose_file_to_load_input_prompt_message(monkeypatch, capsys):
|
|
1167
|
+
"""Test that the correct prompt message is displayed"""
|
|
1168
|
+
files = ["file1.md", "file2.md"]
|
|
1169
|
+
expected_prompt = "Please choose a file to load (enter number): "
|
|
1170
|
+
|
|
1171
|
+
def mock_input(prompt):
|
|
1172
|
+
assert prompt == expected_prompt
|
|
1173
|
+
return "1"
|
|
1174
|
+
|
|
1175
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1176
|
+
|
|
1177
|
+
mock_config = get_default_config()
|
|
1178
|
+
with patch(
|
|
1179
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1180
|
+
):
|
|
1181
|
+
with patch("builtins.open", mock_open()):
|
|
1182
|
+
chat = Chat("dummy_chat_name", reset=False)
|
|
1183
|
+
|
|
1184
|
+
chat.choose_file_to_load(files, "*.md")
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
@pytest.mark.parametrize(
|
|
1188
|
+
"directory, pattern, file_type, existing_files, exclude_pattern, excluded_files, user_input, expected_output, expected_loaded_file",
|
|
1189
|
+
[
|
|
1190
|
+
# Basic successful load - single file
|
|
1191
|
+
(
|
|
1192
|
+
"prompt.data",
|
|
1193
|
+
"*.rules.md",
|
|
1194
|
+
"rules",
|
|
1195
|
+
["rules1.md"],
|
|
1196
|
+
None,
|
|
1197
|
+
[],
|
|
1198
|
+
"",
|
|
1199
|
+
"Loaded rules from rules1.md",
|
|
1200
|
+
"rules1.md",
|
|
1201
|
+
),
|
|
1202
|
+
# Multiple files - user chooses first
|
|
1203
|
+
(
|
|
1204
|
+
"prompt.data",
|
|
1205
|
+
"*.rules.md",
|
|
1206
|
+
"rules",
|
|
1207
|
+
["rules1.md", "rules2.md"],
|
|
1208
|
+
None,
|
|
1209
|
+
[],
|
|
1210
|
+
"1",
|
|
1211
|
+
"Loaded rules from rules1.md",
|
|
1212
|
+
"rules1.md",
|
|
1213
|
+
),
|
|
1214
|
+
# Multiple files - user chooses second
|
|
1215
|
+
(
|
|
1216
|
+
"prompt.data",
|
|
1217
|
+
"*.rules.md",
|
|
1218
|
+
"rules",
|
|
1219
|
+
["rules1.md", "rules2.md"],
|
|
1220
|
+
None,
|
|
1221
|
+
[],
|
|
1222
|
+
"2",
|
|
1223
|
+
"Loaded rules from rules2.md",
|
|
1224
|
+
"rules2.md",
|
|
1225
|
+
),
|
|
1226
|
+
# Multiple files - invalid choice (out of range)
|
|
1227
|
+
(
|
|
1228
|
+
"prompt.data",
|
|
1229
|
+
"*.rules.md",
|
|
1230
|
+
"rules",
|
|
1231
|
+
["rules1.md", "rules2.md"],
|
|
1232
|
+
None,
|
|
1233
|
+
[],
|
|
1234
|
+
"3",
|
|
1235
|
+
"Invalid choice. Aborting load.",
|
|
1236
|
+
None,
|
|
1237
|
+
),
|
|
1238
|
+
# Multiple files - invalid input (non-numeric)
|
|
1239
|
+
(
|
|
1240
|
+
"prompt.data",
|
|
1241
|
+
"*.rules.md",
|
|
1242
|
+
"rules",
|
|
1243
|
+
["rules1.md", "rules2.md"],
|
|
1244
|
+
None,
|
|
1245
|
+
[],
|
|
1246
|
+
"invalid",
|
|
1247
|
+
"Invalid input. Aborting load.",
|
|
1248
|
+
None,
|
|
1249
|
+
),
|
|
1250
|
+
# No matching files
|
|
1251
|
+
(
|
|
1252
|
+
"prompt.data",
|
|
1253
|
+
"*.rules.md",
|
|
1254
|
+
"rules",
|
|
1255
|
+
[],
|
|
1256
|
+
None,
|
|
1257
|
+
[],
|
|
1258
|
+
"",
|
|
1259
|
+
"No rules file found.",
|
|
1260
|
+
None,
|
|
1261
|
+
),
|
|
1262
|
+
# Global pattern with multiple files
|
|
1263
|
+
(
|
|
1264
|
+
"prompt.data",
|
|
1265
|
+
"*",
|
|
1266
|
+
"rules",
|
|
1267
|
+
["rules1.md", "rules2.md"],
|
|
1268
|
+
None,
|
|
1269
|
+
[],
|
|
1270
|
+
"1",
|
|
1271
|
+
"Loaded rules from rules1.md",
|
|
1272
|
+
"rules1.md",
|
|
1273
|
+
),
|
|
1274
|
+
# Global/* pattern with multiple files
|
|
1275
|
+
(
|
|
1276
|
+
"prompt.data",
|
|
1277
|
+
"global/*",
|
|
1278
|
+
"rules",
|
|
1279
|
+
["global_rules1.md", "global_rules2.md"],
|
|
1280
|
+
None,
|
|
1281
|
+
[],
|
|
1282
|
+
"2",
|
|
1283
|
+
"Loaded rules from global_rules2.md",
|
|
1284
|
+
"global_rules2.md",
|
|
1285
|
+
),
|
|
1286
|
+
],
|
|
1287
|
+
)
|
|
1288
|
+
def test_load_helper_basic_scenarios(
|
|
1289
|
+
monkeypatch,
|
|
1290
|
+
capsys,
|
|
1291
|
+
temp_chat_file,
|
|
1292
|
+
directory,
|
|
1293
|
+
pattern,
|
|
1294
|
+
file_type,
|
|
1295
|
+
existing_files,
|
|
1296
|
+
exclude_pattern,
|
|
1297
|
+
excluded_files,
|
|
1298
|
+
user_input,
|
|
1299
|
+
expected_output,
|
|
1300
|
+
expected_loaded_file,
|
|
1301
|
+
):
|
|
1302
|
+
"""Test _load_helper basic scenarios without exclusions"""
|
|
1303
|
+
|
|
698
1304
|
def mock_glob(file_pattern):
|
|
699
1305
|
return existing_files
|
|
700
1306
|
|
|
@@ -704,30 +1310,84 @@ def test_load_helper(monkeypatch, capsys, temp_chat_file, directory, pattern, fi
|
|
|
704
1310
|
def mock_load_file(self, file_path):
|
|
705
1311
|
return True
|
|
706
1312
|
|
|
707
|
-
monkeypatch.setattr(glob,
|
|
708
|
-
monkeypatch.setattr(
|
|
709
|
-
monkeypatch.setattr(Chat,
|
|
710
|
-
monkeypatch.setattr(Chat,
|
|
1313
|
+
monkeypatch.setattr(glob, "glob", mock_glob)
|
|
1314
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1315
|
+
monkeypatch.setattr(Chat, "load_file", mock_load_file)
|
|
1316
|
+
monkeypatch.setattr(Chat, "add_prompt_tag_if_needed", lambda self, chat_file: None)
|
|
711
1317
|
|
|
712
1318
|
mock_config = get_default_config()
|
|
713
|
-
with patch(
|
|
1319
|
+
with patch(
|
|
1320
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1321
|
+
):
|
|
714
1322
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
715
|
-
chat._load_helper(directory, pattern, file_type)
|
|
716
1323
|
|
|
717
|
-
|
|
1324
|
+
chat._load_helper(directory, pattern, file_type, exclude_pattern)
|
|
718
1325
|
|
|
719
|
-
|
|
1326
|
+
captured = capsys.readouterr()
|
|
1327
|
+
# Check both stdout and stderr since error messages go to stderr
|
|
1328
|
+
output = captured.out + captured.err
|
|
1329
|
+
assert expected_output in output
|
|
720
1330
|
|
|
721
1331
|
if expected_loaded_file:
|
|
722
|
-
assert expected_loaded_file in
|
|
1332
|
+
assert expected_loaded_file in output
|
|
723
1333
|
|
|
724
1334
|
|
|
725
|
-
@pytest.mark.parametrize(
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
1335
|
+
@pytest.mark.parametrize(
|
|
1336
|
+
"directory, pattern, file_type, existing_files, exclude_pattern, excluded_files, user_input, expected_output, expected_loaded_file",
|
|
1337
|
+
[
|
|
1338
|
+
# Exclude some files - one remaining
|
|
1339
|
+
(
|
|
1340
|
+
"prompt.data",
|
|
1341
|
+
"*.rules.md",
|
|
1342
|
+
"rules",
|
|
1343
|
+
["rules1.md", "rules2.md"],
|
|
1344
|
+
"*.exclude.md",
|
|
1345
|
+
["rules2.md"],
|
|
1346
|
+
"",
|
|
1347
|
+
"Loaded rules from rules1.md",
|
|
1348
|
+
"rules1.md",
|
|
1349
|
+
),
|
|
1350
|
+
# Exclude some files - multiple remaining, user chooses
|
|
1351
|
+
(
|
|
1352
|
+
"prompt.data",
|
|
1353
|
+
"*.rules.md",
|
|
1354
|
+
"rules",
|
|
1355
|
+
["rules1.md", "rules2.md", "rules3.md"],
|
|
1356
|
+
"*.exclude.md",
|
|
1357
|
+
["rules2.md"],
|
|
1358
|
+
"2",
|
|
1359
|
+
"Loaded rules from rules3.md",
|
|
1360
|
+
"rules3.md",
|
|
1361
|
+
),
|
|
1362
|
+
# Exclude all files
|
|
1363
|
+
(
|
|
1364
|
+
"prompt.data",
|
|
1365
|
+
"*.rules.md",
|
|
1366
|
+
"rules",
|
|
1367
|
+
["rules1.md", "rules2.md"],
|
|
1368
|
+
"*.exclude.md",
|
|
1369
|
+
["rules1.md", "rules2.md"],
|
|
1370
|
+
"",
|
|
1371
|
+
"No rules file found.",
|
|
1372
|
+
None,
|
|
1373
|
+
),
|
|
1374
|
+
],
|
|
1375
|
+
)
|
|
1376
|
+
def test_load_helper_with_exclusions(
|
|
1377
|
+
monkeypatch,
|
|
1378
|
+
capsys,
|
|
1379
|
+
temp_chat_file,
|
|
1380
|
+
directory,
|
|
1381
|
+
pattern,
|
|
1382
|
+
file_type,
|
|
1383
|
+
existing_files,
|
|
1384
|
+
exclude_pattern,
|
|
1385
|
+
excluded_files,
|
|
1386
|
+
user_input,
|
|
1387
|
+
expected_output,
|
|
1388
|
+
expected_loaded_file,
|
|
1389
|
+
):
|
|
1390
|
+
"""Test _load_helper with file exclusions"""
|
|
731
1391
|
|
|
732
1392
|
def mock_glob(file_pattern):
|
|
733
1393
|
if file_pattern == exclude_pattern:
|
|
@@ -740,27 +1400,158 @@ def test_load_helper_with_exclude(monkeypatch, capsys, temp_chat_file, directory
|
|
|
740
1400
|
def mock_load_file(self, file_path):
|
|
741
1401
|
return True
|
|
742
1402
|
|
|
743
|
-
monkeypatch.setattr(glob,
|
|
744
|
-
monkeypatch.setattr(
|
|
745
|
-
monkeypatch.setattr(Chat,
|
|
746
|
-
monkeypatch.setattr(Chat,
|
|
1403
|
+
monkeypatch.setattr(glob, "glob", mock_glob)
|
|
1404
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1405
|
+
monkeypatch.setattr(Chat, "load_file", mock_load_file)
|
|
1406
|
+
monkeypatch.setattr(Chat, "add_prompt_tag_if_needed", lambda self, chat_file: None)
|
|
747
1407
|
|
|
748
1408
|
mock_config = get_default_config()
|
|
749
|
-
with patch(
|
|
1409
|
+
with patch(
|
|
1410
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1411
|
+
):
|
|
750
1412
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1413
|
+
|
|
751
1414
|
chat._load_helper(directory, pattern, file_type, exclude_pattern)
|
|
752
1415
|
|
|
753
1416
|
captured = capsys.readouterr()
|
|
754
|
-
|
|
755
|
-
|
|
1417
|
+
# Check both stdout and stderr since error messages go to stderr
|
|
1418
|
+
output = captured.out + captured.err
|
|
1419
|
+
assert expected_output in output
|
|
756
1420
|
|
|
757
1421
|
if expected_loaded_file:
|
|
758
|
-
assert expected_loaded_file in
|
|
1422
|
+
assert expected_loaded_file in output
|
|
1423
|
+
|
|
1424
|
+
|
|
1425
|
+
def test_load_helper_load_file_fails(monkeypatch, capsys, temp_chat_file):
|
|
1426
|
+
"""Test _load_helper when load_file returns False"""
|
|
1427
|
+
|
|
1428
|
+
def mock_glob(file_pattern):
|
|
1429
|
+
return ["rules1.md"]
|
|
1430
|
+
|
|
1431
|
+
def mock_load_file(self, file_path):
|
|
1432
|
+
return False # Simulate load failure
|
|
1433
|
+
|
|
1434
|
+
monkeypatch.setattr(glob, "glob", mock_glob)
|
|
1435
|
+
monkeypatch.setattr(Chat, "load_file", mock_load_file)
|
|
1436
|
+
monkeypatch.setattr(Chat, "add_prompt_tag_if_needed", lambda self, chat_file: None)
|
|
1437
|
+
|
|
1438
|
+
mock_config = get_default_config()
|
|
1439
|
+
with patch(
|
|
1440
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1441
|
+
):
|
|
1442
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1443
|
+
|
|
1444
|
+
chat._load_helper("prompt.data", "*.rules.md", "rules")
|
|
1445
|
+
|
|
1446
|
+
captured = capsys.readouterr()
|
|
1447
|
+
output = captured.out + captured.err
|
|
1448
|
+
# Should not print "Loaded" message when load_file returns False
|
|
1449
|
+
assert "Loaded rules from" not in output
|
|
1450
|
+
|
|
1451
|
+
|
|
1452
|
+
def test_load_helper_choose_file_returns_none(temp_chat_file):
|
|
1453
|
+
"""Test _load_helper when choose_file_to_load returns None"""
|
|
1454
|
+
mock_config = get_default_config()
|
|
1455
|
+
with patch(
|
|
1456
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1457
|
+
):
|
|
1458
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1459
|
+
|
|
1460
|
+
# Mock these to ensure they're not called when choose_file_to_load returns None
|
|
1461
|
+
with patch("glob.glob", return_value=["rules1.md", "rules2.md"]), patch.object(
|
|
1462
|
+
chat, "choose_file_to_load", return_value=None
|
|
1463
|
+
) as mock_choose, patch.object(
|
|
1464
|
+
chat, "add_prompt_tag_if_needed"
|
|
1465
|
+
) as mock_add_prompt_tag, patch.object(
|
|
1466
|
+
chat, "load_file"
|
|
1467
|
+
) as mock_load_file:
|
|
1468
|
+
|
|
1469
|
+
chat._load_helper("prompt.data", "*.rules.md", "rules")
|
|
1470
|
+
|
|
1471
|
+
# Verify that subsequent methods are not called when choose_file_to_load returns None
|
|
1472
|
+
mock_choose.assert_called_once()
|
|
1473
|
+
mock_add_prompt_tag.assert_not_called()
|
|
1474
|
+
mock_load_file.assert_not_called()
|
|
1475
|
+
|
|
1476
|
+
|
|
1477
|
+
def test_load_helper_directory_path_construction(temp_chat_file):
|
|
1478
|
+
"""Test that _load_helper constructs directory paths correctly"""
|
|
1479
|
+
expected_directory_path = os.path.join(
|
|
1480
|
+
os.path.dirname(temp_chat_file.name), "custom_dir"
|
|
1481
|
+
)
|
|
1482
|
+
expected_file_pattern = os.path.join(expected_directory_path, "*.custom.md")
|
|
1483
|
+
|
|
1484
|
+
def mock_glob(file_pattern):
|
|
1485
|
+
# Verify the correct path is being used
|
|
1486
|
+
assert file_pattern == expected_file_pattern
|
|
1487
|
+
return ["custom1.md"]
|
|
1488
|
+
|
|
1489
|
+
mock_config = get_default_config()
|
|
1490
|
+
with patch(
|
|
1491
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1492
|
+
):
|
|
1493
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1494
|
+
|
|
1495
|
+
with patch("glob.glob", side_effect=mock_glob), patch.object(
|
|
1496
|
+
chat, "load_file", return_value=True
|
|
1497
|
+
), patch.object(chat, "add_prompt_tag_if_needed"):
|
|
1498
|
+
|
|
1499
|
+
chat._load_helper("custom_dir", "*.custom.md", "custom")
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
def test_load_helper_calls_add_prompt_tag_before_load(temp_chat_file):
|
|
1503
|
+
"""Test that _load_helper calls add_prompt_tag_if_needed before loading file"""
|
|
1504
|
+
call_order = []
|
|
1505
|
+
|
|
1506
|
+
def mock_add_prompt_tag(chat_file):
|
|
1507
|
+
call_order.append("add_prompt_tag")
|
|
1508
|
+
|
|
1509
|
+
def mock_load_file(file_path):
|
|
1510
|
+
call_order.append("load_file")
|
|
1511
|
+
return True
|
|
1512
|
+
|
|
1513
|
+
mock_config = get_default_config()
|
|
1514
|
+
with patch(
|
|
1515
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1516
|
+
):
|
|
1517
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1518
|
+
|
|
1519
|
+
with patch("glob.glob", return_value=["rules1.md"]), patch.object(
|
|
1520
|
+
chat, "add_prompt_tag_if_needed", side_effect=mock_add_prompt_tag
|
|
1521
|
+
), patch.object(chat, "load_file", side_effect=mock_load_file):
|
|
1522
|
+
|
|
1523
|
+
chat._load_helper("prompt.data", "*.rules.md", "rules")
|
|
1524
|
+
|
|
1525
|
+
# Verify correct call order
|
|
1526
|
+
assert call_order == ["add_prompt_tag", "load_file"]
|
|
1527
|
+
|
|
1528
|
+
|
|
1529
|
+
@patch("ara_cli.error_handler.report_error")
|
|
1530
|
+
def test_load_helper_reports_error_when_no_files_found(
|
|
1531
|
+
mock_report_error, temp_chat_file
|
|
1532
|
+
):
|
|
1533
|
+
"""Test that _load_helper reports error when no matching files are found"""
|
|
1534
|
+
mock_config = get_default_config()
|
|
1535
|
+
with patch(
|
|
1536
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1537
|
+
):
|
|
1538
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1539
|
+
|
|
1540
|
+
with patch("glob.glob", return_value=[]): # No files found
|
|
1541
|
+
chat._load_helper("prompt.data", "*.rules.md", "rules")
|
|
1542
|
+
|
|
1543
|
+
# Verify error is reported with correct message
|
|
1544
|
+
mock_report_error.assert_called_once()
|
|
1545
|
+
error_call = mock_report_error.call_args[0]
|
|
1546
|
+
assert isinstance(error_call[0], AraError)
|
|
1547
|
+
assert "No rules file found." in str(error_call[0])
|
|
759
1548
|
|
|
760
1549
|
|
|
761
1550
|
def test_help_menu_with_aliases(temp_chat_file, capsys):
|
|
762
1551
|
mock_config = get_default_config()
|
|
763
|
-
with patch(
|
|
1552
|
+
with patch(
|
|
1553
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1554
|
+
):
|
|
764
1555
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
765
1556
|
|
|
766
1557
|
chat._help_menu(verbose=False)
|
|
@@ -774,7 +1565,9 @@ def test_help_menu_with_aliases(temp_chat_file, capsys):
|
|
|
774
1565
|
|
|
775
1566
|
def test_do_quit(temp_chat_file, capsys):
|
|
776
1567
|
mock_config = get_default_config()
|
|
777
|
-
with patch(
|
|
1568
|
+
with patch(
|
|
1569
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1570
|
+
):
|
|
778
1571
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
779
1572
|
|
|
780
1573
|
result = chat.do_quit("")
|
|
@@ -786,46 +1579,63 @@ def test_do_quit(temp_chat_file, capsys):
|
|
|
786
1579
|
|
|
787
1580
|
def test_onecmd_plus_hooks(temp_chat_file):
|
|
788
1581
|
mock_config = get_default_config()
|
|
789
|
-
with patch(
|
|
1582
|
+
with patch(
|
|
1583
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1584
|
+
):
|
|
790
1585
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
791
1586
|
|
|
792
1587
|
command = "dummy command"
|
|
793
1588
|
|
|
794
|
-
with patch.object(chat,
|
|
795
|
-
with patch.object(
|
|
1589
|
+
with patch.object(chat, "full_input", create=True):
|
|
1590
|
+
with patch.object(
|
|
1591
|
+
cmd2.Cmd, "onecmd_plus_hooks", return_value=True
|
|
1592
|
+
) as mock_super_onecmd_plus_hooks:
|
|
796
1593
|
result = chat.onecmd_plus_hooks(command, 20)
|
|
797
1594
|
|
|
798
|
-
mock_super_onecmd_plus_hooks.assert_called_once_with(
|
|
1595
|
+
mock_super_onecmd_plus_hooks.assert_called_once_with(
|
|
1596
|
+
command, orig_rl_history_length=20
|
|
1597
|
+
)
|
|
799
1598
|
assert result is True
|
|
800
1599
|
|
|
801
1600
|
|
|
802
1601
|
def test_default(temp_chat_file):
|
|
803
1602
|
mock_config = get_default_config()
|
|
804
|
-
with patch(
|
|
1603
|
+
with patch(
|
|
1604
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1605
|
+
):
|
|
805
1606
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
806
1607
|
chat.full_input = "sample input"
|
|
807
1608
|
chat.default(chat.full_input)
|
|
808
1609
|
assert chat.message_buffer == ["sample input"]
|
|
809
1610
|
|
|
810
|
-
|
|
811
|
-
@
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
])
|
|
817
|
-
|
|
1611
|
+
|
|
1612
|
+
@patch("ara_cli.commands.load_command.LoadCommand")
|
|
1613
|
+
@pytest.mark.parametrize(
|
|
1614
|
+
"file_name_arg, load_images_arg, matching_files",
|
|
1615
|
+
[
|
|
1616
|
+
("test.txt", "", ["/path/to/test.txt"]),
|
|
1617
|
+
("*.txt", "", ["/path/to/a.txt", "/path/to/b.txt"]),
|
|
1618
|
+
("doc.pdf", "--load-images", ["/path/to/doc.pdf"]),
|
|
1619
|
+
("nonexistent.txt", "", []),
|
|
1620
|
+
],
|
|
1621
|
+
)
|
|
1622
|
+
def test_do_LOAD(
|
|
1623
|
+
MockLoadCommand, temp_chat_file, file_name_arg, load_images_arg, matching_files
|
|
1624
|
+
):
|
|
818
1625
|
from ara_cli.chat import load_parser
|
|
1626
|
+
|
|
819
1627
|
args_str = f"{file_name_arg} {load_images_arg}".strip()
|
|
820
1628
|
args = load_parser.parse_args(args_str.split() if args_str else [])
|
|
821
1629
|
|
|
822
1630
|
mock_config = get_default_config()
|
|
823
|
-
with patch(
|
|
1631
|
+
with patch(
|
|
1632
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1633
|
+
):
|
|
824
1634
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
825
1635
|
# FIX: Mock add_prompt_tag_if_needed to prevent IndexError on the empty temp file.
|
|
826
1636
|
chat.add_prompt_tag_if_needed = MagicMock()
|
|
827
1637
|
|
|
828
|
-
with patch.object(chat,
|
|
1638
|
+
with patch.object(chat, "find_matching_files_to_load", return_value=matching_files):
|
|
829
1639
|
chat.onecmd_plus_hooks(f"LOAD {args_str}", orig_rl_history_length=0)
|
|
830
1640
|
|
|
831
1641
|
if not matching_files:
|
|
@@ -833,16 +1643,17 @@ def test_do_LOAD(MockLoadCommand, temp_chat_file, file_name_arg, load_images_arg
|
|
|
833
1643
|
else:
|
|
834
1644
|
# Check that the tag was prepared for each file loaded
|
|
835
1645
|
assert chat.add_prompt_tag_if_needed.call_count == len(matching_files)
|
|
836
|
-
|
|
1646
|
+
|
|
837
1647
|
# Check that the LoadCommand was instantiated and executed for each file
|
|
838
1648
|
assert MockLoadCommand.call_count == len(matching_files)
|
|
839
1649
|
for i, file_path in enumerate(matching_files):
|
|
840
1650
|
_, kwargs = MockLoadCommand.call_args_list[i]
|
|
841
|
-
assert kwargs[
|
|
842
|
-
assert kwargs[
|
|
843
|
-
assert kwargs[
|
|
1651
|
+
assert kwargs["chat_instance"] == chat
|
|
1652
|
+
assert kwargs["file_path"] == file_path
|
|
1653
|
+
assert kwargs["extract_images"] == args.load_images
|
|
844
1654
|
assert MockLoadCommand.return_value.execute.call_count == len(matching_files)
|
|
845
1655
|
|
|
1656
|
+
|
|
846
1657
|
def test_do_LOAD_interactive(monkeypatch, capsys, temp_chat_file, temp_load_file):
|
|
847
1658
|
def mock_glob(file_pattern):
|
|
848
1659
|
return [temp_load_file.name]
|
|
@@ -850,12 +1661,14 @@ def test_do_LOAD_interactive(monkeypatch, capsys, temp_chat_file, temp_load_file
|
|
|
850
1661
|
def mock_input(prompt):
|
|
851
1662
|
return temp_load_file.name
|
|
852
1663
|
|
|
853
|
-
monkeypatch.setattr(glob,
|
|
854
|
-
monkeypatch.setattr(
|
|
855
|
-
monkeypatch.setattr(Chat,
|
|
1664
|
+
monkeypatch.setattr(glob, "glob", mock_glob)
|
|
1665
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
1666
|
+
monkeypatch.setattr(Chat, "add_prompt_tag_if_needed", lambda self, chat_file: None)
|
|
856
1667
|
|
|
857
1668
|
mock_config = get_default_config()
|
|
858
|
-
with patch(
|
|
1669
|
+
with patch(
|
|
1670
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1671
|
+
):
|
|
859
1672
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
860
1673
|
chat.do_LOAD("")
|
|
861
1674
|
|
|
@@ -863,68 +1676,200 @@ def test_do_LOAD_interactive(monkeypatch, capsys, temp_chat_file, temp_load_file
|
|
|
863
1676
|
assert f"Loaded contents of file {temp_load_file.name}" in captured.out
|
|
864
1677
|
|
|
865
1678
|
|
|
866
|
-
@pytest.mark.parametrize(
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
1679
|
+
@pytest.mark.parametrize(
|
|
1680
|
+
"text, line, begidx, endidx, matching_files",
|
|
1681
|
+
[
|
|
1682
|
+
("file", "LOAD file", 5, 9, ["file1.md", "file2.txt"]),
|
|
1683
|
+
(
|
|
1684
|
+
"path/to/file",
|
|
1685
|
+
"LOAD path/to/file",
|
|
1686
|
+
5,
|
|
1687
|
+
18,
|
|
1688
|
+
["path/to/file1.md", "path/to/file2.txt"],
|
|
1689
|
+
),
|
|
1690
|
+
("nonexistent", "LOAD nonexistent", 5, 16, []),
|
|
1691
|
+
],
|
|
1692
|
+
)
|
|
1693
|
+
def test_complete_LOAD(
|
|
1694
|
+
monkeypatch, temp_chat_file, text, line, begidx, endidx, matching_files
|
|
1695
|
+
):
|
|
872
1696
|
def mock_glob(pattern):
|
|
873
1697
|
return matching_files
|
|
874
1698
|
|
|
875
|
-
monkeypatch.setattr(glob,
|
|
1699
|
+
monkeypatch.setattr(glob, "glob", mock_glob)
|
|
876
1700
|
|
|
877
1701
|
mock_config = get_default_config()
|
|
878
|
-
with patch(
|
|
1702
|
+
with patch(
|
|
1703
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1704
|
+
):
|
|
879
1705
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
880
1706
|
completions = chat.complete_LOAD(text, line, begidx, endidx)
|
|
881
1707
|
|
|
882
1708
|
assert completions == matching_files
|
|
883
1709
|
|
|
884
1710
|
|
|
885
|
-
@pytest.mark.parametrize(
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1711
|
+
@pytest.mark.parametrize(
|
|
1712
|
+
"file_name, expected_mime_type",
|
|
1713
|
+
[
|
|
1714
|
+
("test.png", "image/png"),
|
|
1715
|
+
("test.jpg", "image/jpeg"),
|
|
1716
|
+
("test.jpeg", "image/jpeg"),
|
|
1717
|
+
("TEST.PNG", "image/png"), # Test case insensitive
|
|
1718
|
+
("path/to/image.JPG", "image/jpeg"), # Test with path
|
|
1719
|
+
],
|
|
1720
|
+
)
|
|
1721
|
+
@patch("ara_cli.error_handler.report_error")
|
|
1722
|
+
def test_load_image_success(
|
|
1723
|
+
mock_report_error, temp_chat_file, file_name, expected_mime_type
|
|
1724
|
+
):
|
|
1725
|
+
"""Test load_image successfully loads supported image files"""
|
|
1726
|
+
mock_config = get_default_config()
|
|
1727
|
+
with patch(
|
|
1728
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1729
|
+
):
|
|
1730
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1731
|
+
|
|
1732
|
+
with patch.object(chat, "load_binary_file", return_value=True) as mock_load_binary:
|
|
1733
|
+
result = chat.load_image(
|
|
1734
|
+
file_name=file_name, prefix="prefix-", suffix="-suffix"
|
|
1735
|
+
)
|
|
1736
|
+
|
|
1737
|
+
mock_load_binary.assert_called_once_with(
|
|
1738
|
+
file_path=file_name,
|
|
1739
|
+
mime_type=expected_mime_type,
|
|
1740
|
+
prefix="prefix-",
|
|
1741
|
+
suffix="-suffix",
|
|
1742
|
+
)
|
|
1743
|
+
assert result is True
|
|
1744
|
+
mock_report_error.assert_not_called()
|
|
1745
|
+
|
|
1746
|
+
|
|
1747
|
+
@pytest.mark.parametrize(
|
|
1748
|
+
"file_name",
|
|
1749
|
+
[
|
|
1750
|
+
"document.txt",
|
|
1751
|
+
"archive.zip",
|
|
1752
|
+
"video.mp4",
|
|
1753
|
+
"audio.wav",
|
|
1754
|
+
"script.py",
|
|
1755
|
+
"image.gif", # Not in BINARY_TYPE_MAPPING
|
|
1756
|
+
"image.bmp", # Not in BINARY_TYPE_MAPPING
|
|
1757
|
+
"", # Empty filename
|
|
1758
|
+
"no_extension",
|
|
1759
|
+
],
|
|
1760
|
+
)
|
|
1761
|
+
@patch("ara_cli.error_handler.report_error")
|
|
1762
|
+
def test_load_image_unsupported_file_types(
|
|
1763
|
+
mock_report_error, temp_chat_file, file_name
|
|
1764
|
+
):
|
|
1765
|
+
"""Test load_image reports error for unsupported file types"""
|
|
1766
|
+
mock_config = get_default_config()
|
|
1767
|
+
with patch(
|
|
1768
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1769
|
+
):
|
|
1770
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1771
|
+
|
|
1772
|
+
with patch.object(chat, "load_binary_file") as mock_load_binary:
|
|
1773
|
+
result = chat.load_image(file_name=file_name)
|
|
1774
|
+
|
|
1775
|
+
mock_load_binary.assert_not_called()
|
|
1776
|
+
mock_report_error.assert_called_once()
|
|
1777
|
+
|
|
1778
|
+
# Verify the error message and type
|
|
1779
|
+
error_call = mock_report_error.call_args[0]
|
|
1780
|
+
assert isinstance(error_call[0], AraError)
|
|
1781
|
+
assert f"File {file_name} not recognized as image, could not load" in str(
|
|
1782
|
+
error_call[0]
|
|
1783
|
+
)
|
|
1784
|
+
assert result is None
|
|
1785
|
+
|
|
1786
|
+
|
|
1787
|
+
@patch("ara_cli.error_handler.report_error")
|
|
1788
|
+
def test_load_image_load_binary_file_fails(mock_report_error, temp_chat_file):
|
|
1789
|
+
"""Test load_image when load_binary_file returns False"""
|
|
1790
|
+
mock_config = get_default_config()
|
|
1791
|
+
with patch(
|
|
1792
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1793
|
+
):
|
|
1794
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1795
|
+
|
|
1796
|
+
with patch.object(chat, "load_binary_file", return_value=False) as mock_load_binary:
|
|
1797
|
+
result = chat.load_image(file_name="test.png", prefix="pre-", suffix="-post")
|
|
1798
|
+
|
|
1799
|
+
mock_load_binary.assert_called_once_with(
|
|
1800
|
+
file_path="test.png", mime_type="image/png", prefix="pre-", suffix="-post"
|
|
1801
|
+
)
|
|
1802
|
+
assert result is False
|
|
1803
|
+
mock_report_error.assert_not_called()
|
|
1804
|
+
|
|
1805
|
+
|
|
1806
|
+
@patch("ara_cli.error_handler.report_error")
|
|
1807
|
+
def test_load_image_default_parameters(mock_report_error, temp_chat_file):
|
|
1808
|
+
"""Test load_image with default prefix and suffix parameters"""
|
|
892
1809
|
mock_config = get_default_config()
|
|
893
|
-
with patch(
|
|
1810
|
+
with patch(
|
|
1811
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1812
|
+
):
|
|
894
1813
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
895
1814
|
|
|
896
|
-
with patch.object(chat,
|
|
897
|
-
chat.load_image(file_name=
|
|
1815
|
+
with patch.object(chat, "load_binary_file", return_value=True) as mock_load_binary:
|
|
1816
|
+
result = chat.load_image(file_name="image.jpeg")
|
|
1817
|
+
|
|
1818
|
+
mock_load_binary.assert_called_once_with(
|
|
1819
|
+
file_path="image.jpeg", mime_type="image/jpeg", prefix="", suffix=""
|
|
1820
|
+
)
|
|
1821
|
+
assert result is True
|
|
1822
|
+
mock_report_error.assert_not_called()
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
@patch("ara_cli.error_handler.report_error")
|
|
1826
|
+
def test_load_image_binary_type_mapping_usage(mock_report_error, temp_chat_file):
|
|
1827
|
+
"""Test that load_image correctly uses Chat.BINARY_TYPE_MAPPING"""
|
|
1828
|
+
mock_config = get_default_config()
|
|
1829
|
+
with patch(
|
|
1830
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1831
|
+
):
|
|
1832
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
1833
|
+
|
|
1834
|
+
# Verify the mapping is used correctly by testing each supported extension
|
|
1835
|
+
original_mapping = Chat.BINARY_TYPE_MAPPING.copy()
|
|
1836
|
+
|
|
1837
|
+
with patch.object(chat, "load_binary_file", return_value=True) as mock_load_binary:
|
|
1838
|
+
for extension, expected_mime in original_mapping.items():
|
|
1839
|
+
mock_load_binary.reset_mock()
|
|
1840
|
+
test_filename = f"test{extension}"
|
|
1841
|
+
|
|
1842
|
+
chat.load_image(file_name=test_filename)
|
|
898
1843
|
|
|
899
|
-
if is_image:
|
|
900
|
-
# FIX: The called method's parameter is `file_path`, not `file_name`.
|
|
901
1844
|
mock_load_binary.assert_called_once_with(
|
|
902
|
-
file_path=
|
|
903
|
-
mime_type=expected_mime,
|
|
904
|
-
prefix="p-",
|
|
905
|
-
suffix="-f"
|
|
1845
|
+
file_path=test_filename, mime_type=expected_mime, prefix="", suffix=""
|
|
906
1846
|
)
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
captured = capsys.readouterr()
|
|
910
|
-
assert f"File {file_name} not recognized as image, could not load" in captured.out
|
|
1847
|
+
|
|
1848
|
+
mock_report_error.assert_not_called()
|
|
911
1849
|
|
|
912
1850
|
|
|
913
|
-
@patch(
|
|
914
|
-
@pytest.mark.parametrize(
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1851
|
+
@patch("ara_cli.commands.load_image_command.LoadImageCommand")
|
|
1852
|
+
@pytest.mark.parametrize(
|
|
1853
|
+
"image_file, should_load, expected_mime",
|
|
1854
|
+
[
|
|
1855
|
+
("test.png", True, "image/png"),
|
|
1856
|
+
("test.jpg", True, "image/jpeg"),
|
|
1857
|
+
("test.txt", False, None),
|
|
1858
|
+
],
|
|
1859
|
+
)
|
|
1860
|
+
def test_do_LOAD_IMAGE(
|
|
1861
|
+
MockLoadImageCommand, capsys, temp_chat_file, image_file, should_load, expected_mime
|
|
1862
|
+
):
|
|
920
1863
|
matching_files = [f"/path/to/{image_file}"]
|
|
921
1864
|
|
|
922
1865
|
mock_config = get_default_config()
|
|
923
|
-
with patch(
|
|
1866
|
+
with patch(
|
|
1867
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1868
|
+
):
|
|
924
1869
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
925
1870
|
chat.add_prompt_tag_if_needed = MagicMock()
|
|
926
1871
|
|
|
927
|
-
with patch.object(chat,
|
|
1872
|
+
with patch.object(chat, "find_matching_files_to_load", return_value=matching_files):
|
|
928
1873
|
chat.do_LOAD_IMAGE(image_file)
|
|
929
1874
|
|
|
930
1875
|
if should_load:
|
|
@@ -934,7 +1879,7 @@ def test_do_LOAD_IMAGE(MockLoadImageCommand, capsys, temp_chat_file, image_file,
|
|
|
934
1879
|
file_path=matching_files[0],
|
|
935
1880
|
mime_type=expected_mime,
|
|
936
1881
|
prefix=f"\nFile: {matching_files[0]}\n",
|
|
937
|
-
output=chat.poutput
|
|
1882
|
+
output=chat.poutput,
|
|
938
1883
|
)
|
|
939
1884
|
MockLoadImageCommand.return_value.execute.assert_called_once()
|
|
940
1885
|
else:
|
|
@@ -943,45 +1888,59 @@ def test_do_LOAD_IMAGE(MockLoadImageCommand, capsys, temp_chat_file, image_file,
|
|
|
943
1888
|
chat.add_prompt_tag_if_needed.assert_called_once()
|
|
944
1889
|
MockLoadImageCommand.assert_not_called()
|
|
945
1890
|
captured = capsys.readouterr()
|
|
946
|
-
assert
|
|
1891
|
+
assert (
|
|
1892
|
+
f"File {matching_files[0]} not recognized as image, could not load"
|
|
1893
|
+
in captured.err
|
|
1894
|
+
)
|
|
947
1895
|
|
|
948
1896
|
|
|
949
|
-
@pytest.mark.parametrize(
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1897
|
+
@pytest.mark.parametrize(
|
|
1898
|
+
"input_chat_name, expected_chat_name",
|
|
1899
|
+
[
|
|
1900
|
+
("", "What should be the new chat name? "),
|
|
1901
|
+
("new_chat", "new_chat_chat.md"),
|
|
1902
|
+
("new_chat.md", "new_chat.md"),
|
|
1903
|
+
],
|
|
1904
|
+
)
|
|
954
1905
|
def test_do_new(monkeypatch, temp_chat_file, input_chat_name, expected_chat_name):
|
|
955
1906
|
def mock_input(prompt):
|
|
956
1907
|
return "input_chat_name"
|
|
957
1908
|
|
|
958
|
-
monkeypatch.setattr(
|
|
1909
|
+
monkeypatch.setattr("builtins.input", mock_input)
|
|
959
1910
|
|
|
960
1911
|
mock_config = get_default_config()
|
|
961
|
-
with patch(
|
|
1912
|
+
with patch(
|
|
1913
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1914
|
+
):
|
|
962
1915
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
963
1916
|
|
|
964
|
-
with patch.object(Chat,
|
|
1917
|
+
with patch.object(Chat, "__init__", return_value=None) as mock_init:
|
|
965
1918
|
chat.do_NEW(input_chat_name)
|
|
966
1919
|
if input_chat_name == "":
|
|
967
|
-
mock_init.assert_called_with(
|
|
1920
|
+
mock_init.assert_called_with(
|
|
1921
|
+
os.path.join(os.path.dirname(temp_chat_file.name), "input_chat_name")
|
|
1922
|
+
)
|
|
968
1923
|
else:
|
|
969
|
-
mock_init.assert_called_with(
|
|
1924
|
+
mock_init.assert_called_with(
|
|
1925
|
+
os.path.join(os.path.dirname(temp_chat_file.name), input_chat_name)
|
|
1926
|
+
)
|
|
970
1927
|
|
|
971
1928
|
|
|
972
1929
|
def test_do_RERUN(temp_chat_file):
|
|
973
1930
|
initial_content = [
|
|
974
1931
|
"# ara prompt:\nPrompt message.\n",
|
|
975
|
-
"# ara response:\nResponse message.\n"
|
|
1932
|
+
"# ara response:\nResponse message.\n",
|
|
976
1933
|
]
|
|
977
1934
|
temp_chat_file.writelines(initial_content)
|
|
978
1935
|
temp_chat_file.flush()
|
|
979
1936
|
|
|
980
1937
|
mock_config = get_default_config()
|
|
981
|
-
with patch(
|
|
1938
|
+
with patch(
|
|
1939
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1940
|
+
):
|
|
982
1941
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
983
1942
|
|
|
984
|
-
with patch.object(chat,
|
|
1943
|
+
with patch.object(chat, "resend_message") as mock_resend_message:
|
|
985
1944
|
chat.do_RERUN("")
|
|
986
1945
|
mock_resend_message.assert_called_once()
|
|
987
1946
|
|
|
@@ -992,15 +1951,17 @@ def test_do_CLEAR(temp_chat_file, capsys):
|
|
|
992
1951
|
temp_chat_file.flush()
|
|
993
1952
|
|
|
994
1953
|
mock_config = get_default_config()
|
|
995
|
-
with patch(
|
|
1954
|
+
with patch(
|
|
1955
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1956
|
+
):
|
|
996
1957
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
997
1958
|
|
|
998
|
-
with patch(
|
|
1959
|
+
with patch("builtins.input", return_value="y"):
|
|
999
1960
|
chat.do_CLEAR(None)
|
|
1000
1961
|
|
|
1001
1962
|
captured = capsys.readouterr()
|
|
1002
1963
|
|
|
1003
|
-
with open(temp_chat_file.name,
|
|
1964
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
1004
1965
|
content = file.read()
|
|
1005
1966
|
|
|
1006
1967
|
assert content.strip() == "# ara prompt:"
|
|
@@ -1013,118 +1974,204 @@ def test_do_CLEAR_abort(temp_chat_file, capsys):
|
|
|
1013
1974
|
temp_chat_file.flush()
|
|
1014
1975
|
|
|
1015
1976
|
mock_config = get_default_config()
|
|
1016
|
-
with patch(
|
|
1977
|
+
with patch(
|
|
1978
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
1979
|
+
):
|
|
1017
1980
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1018
1981
|
|
|
1019
|
-
with patch(
|
|
1982
|
+
with patch("builtins.input", return_value="n"):
|
|
1020
1983
|
chat.do_CLEAR(None)
|
|
1021
1984
|
|
|
1022
1985
|
captured = capsys.readouterr()
|
|
1023
1986
|
|
|
1024
|
-
with open(temp_chat_file.name,
|
|
1987
|
+
with open(temp_chat_file.name, "r", encoding="utf-8") as file:
|
|
1025
1988
|
content = file.read()
|
|
1026
1989
|
|
|
1027
1990
|
assert content.strip() == initial_content
|
|
1028
1991
|
assert "Cleared content of" not in captured.out
|
|
1029
1992
|
|
|
1030
1993
|
|
|
1031
|
-
@pytest.mark.parametrize(
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1994
|
+
@pytest.mark.parametrize(
|
|
1995
|
+
"rules_name",
|
|
1996
|
+
[
|
|
1997
|
+
"",
|
|
1998
|
+
"global/test_rule",
|
|
1999
|
+
"local_rule",
|
|
2000
|
+
],
|
|
2001
|
+
)
|
|
2002
|
+
def test_do_LOAD_RULES(temp_chat_file, rules_name):
|
|
1037
2003
|
mock_config = get_default_config()
|
|
1038
|
-
with patch(
|
|
2004
|
+
with patch(
|
|
2005
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2006
|
+
):
|
|
1039
2007
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1040
2008
|
|
|
1041
|
-
with patch.object(chat,
|
|
2009
|
+
with patch.object(chat.template_loader, "load_template") as mock_load_template:
|
|
1042
2010
|
chat.do_LOAD_RULES(rules_name)
|
|
1043
|
-
|
|
1044
|
-
rules_name, "rules", "*.rules.md"
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
2011
|
+
mock_load_template.assert_called_once_with(
|
|
2012
|
+
rules_name, "rules", chat.chat_name, "*.rules.md"
|
|
2013
|
+
)
|
|
2014
|
+
|
|
2015
|
+
|
|
2016
|
+
@pytest.mark.parametrize(
|
|
2017
|
+
"intention_name",
|
|
2018
|
+
[
|
|
2019
|
+
"",
|
|
2020
|
+
"global/test_intention",
|
|
2021
|
+
"local_intention",
|
|
2022
|
+
],
|
|
2023
|
+
)
|
|
2024
|
+
def test_do_LOAD_INTENTION(temp_chat_file, intention_name):
|
|
1055
2025
|
mock_config = get_default_config()
|
|
1056
|
-
with patch(
|
|
2026
|
+
with patch(
|
|
2027
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2028
|
+
):
|
|
1057
2029
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1058
2030
|
|
|
1059
|
-
with patch.object(chat,
|
|
2031
|
+
with patch.object(chat.template_loader, "load_template") as mock_load_template:
|
|
1060
2032
|
chat.do_LOAD_INTENTION(intention_name)
|
|
1061
|
-
|
|
1062
|
-
intention_name, "intention", "*.intention.md"
|
|
2033
|
+
mock_load_template.assert_called_once_with(
|
|
2034
|
+
intention_name, "intention", chat.chat_name, "*.intention.md"
|
|
2035
|
+
)
|
|
1063
2036
|
|
|
1064
2037
|
|
|
1065
|
-
@pytest.mark.parametrize(
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
]
|
|
1071
|
-
|
|
2038
|
+
@pytest.mark.parametrize(
|
|
2039
|
+
"blueprint_name",
|
|
2040
|
+
[
|
|
2041
|
+
"global/test_blueprint",
|
|
2042
|
+
"local_blueprint",
|
|
2043
|
+
],
|
|
2044
|
+
)
|
|
2045
|
+
def test_do_LOAD_BLUEPRINT(temp_chat_file, blueprint_name):
|
|
1072
2046
|
mock_config = get_default_config()
|
|
1073
|
-
with patch(
|
|
2047
|
+
with patch(
|
|
2048
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2049
|
+
):
|
|
1074
2050
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1075
2051
|
|
|
1076
|
-
with patch.object(chat,
|
|
2052
|
+
with patch.object(chat.template_loader, "load_template") as mock_load_template:
|
|
1077
2053
|
chat.do_LOAD_BLUEPRINT(blueprint_name)
|
|
1078
|
-
mock_load_template.assert_called_once_with(
|
|
2054
|
+
mock_load_template.assert_called_once_with(
|
|
2055
|
+
blueprint_name, "blueprint", chat.chat_name
|
|
2056
|
+
)
|
|
1079
2057
|
|
|
1080
2058
|
|
|
1081
|
-
@pytest.mark.parametrize(
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
2059
|
+
@pytest.mark.parametrize(
|
|
2060
|
+
"commands_name",
|
|
2061
|
+
[
|
|
2062
|
+
"",
|
|
2063
|
+
"global/test_command",
|
|
2064
|
+
"local_command",
|
|
2065
|
+
],
|
|
2066
|
+
)
|
|
2067
|
+
def test_do_LOAD_COMMANDS(temp_chat_file, commands_name):
|
|
1088
2068
|
mock_config = get_default_config()
|
|
1089
|
-
with patch(
|
|
2069
|
+
with patch(
|
|
2070
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2071
|
+
):
|
|
1090
2072
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1091
2073
|
|
|
1092
|
-
with patch.object(chat,
|
|
2074
|
+
with patch.object(chat.template_loader, "load_template") as mock_load_template:
|
|
1093
2075
|
chat.do_LOAD_COMMANDS(commands_name)
|
|
1094
|
-
|
|
1095
|
-
commands_name, "commands", "*.commands.md"
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
2076
|
+
mock_load_template.assert_called_once_with(
|
|
2077
|
+
commands_name, "commands", chat.chat_name, "*.commands.md"
|
|
2078
|
+
)
|
|
2079
|
+
|
|
2080
|
+
|
|
2081
|
+
@pytest.mark.parametrize(
|
|
2082
|
+
"template_name, template_type, default_pattern, custom_template_subdir, expected_directory, expected_pattern",
|
|
2083
|
+
[
|
|
2084
|
+
(
|
|
2085
|
+
"local_command",
|
|
2086
|
+
"commands",
|
|
2087
|
+
"*.commands.md",
|
|
2088
|
+
"custom-prompt-modules",
|
|
2089
|
+
"/mocked_local_templates_path/custom-prompt-modules/commands",
|
|
2090
|
+
"local_command",
|
|
2091
|
+
),
|
|
2092
|
+
(
|
|
2093
|
+
"local_command",
|
|
2094
|
+
"commands",
|
|
2095
|
+
"*.commands.md",
|
|
2096
|
+
"mocked_custom_modules_path",
|
|
2097
|
+
"/mocked_local_templates_path/mocked_custom_modules_path/commands",
|
|
2098
|
+
"local_command",
|
|
2099
|
+
),
|
|
2100
|
+
(
|
|
2101
|
+
"local_rule",
|
|
2102
|
+
"rules",
|
|
2103
|
+
"*.rules.md",
|
|
2104
|
+
"custom-prompt-modules",
|
|
2105
|
+
"/mocked_local_templates_path/custom-prompt-modules/rules",
|
|
2106
|
+
"local_rule",
|
|
2107
|
+
),
|
|
2108
|
+
(
|
|
2109
|
+
"local_rule",
|
|
2110
|
+
"rules",
|
|
2111
|
+
"*.rules.md",
|
|
2112
|
+
"mocked_custom_modules_path",
|
|
2113
|
+
"/mocked_local_templates_path/mocked_custom_modules_path/rules",
|
|
2114
|
+
"local_rule",
|
|
2115
|
+
),
|
|
2116
|
+
(
|
|
2117
|
+
"local_intention",
|
|
2118
|
+
"intention",
|
|
2119
|
+
"*.intentions.md",
|
|
2120
|
+
"custom-prompt-modules",
|
|
2121
|
+
"/mocked_local_templates_path/custom-prompt-modules/intentions",
|
|
2122
|
+
"local_intention",
|
|
2123
|
+
),
|
|
2124
|
+
(
|
|
2125
|
+
"local_intention",
|
|
2126
|
+
"intention",
|
|
2127
|
+
"*.intentions.md",
|
|
2128
|
+
"mocked_custom_modules_path",
|
|
2129
|
+
"/mocked_local_templates_path/mocked_custom_modules_path/intentions",
|
|
2130
|
+
"local_intention",
|
|
2131
|
+
),
|
|
2132
|
+
(
|
|
2133
|
+
"local_blueprint",
|
|
2134
|
+
"blueprint",
|
|
2135
|
+
"*.blueprints.md",
|
|
2136
|
+
"custom-prompt-modules",
|
|
2137
|
+
"/mocked_local_templates_path/custom-prompt-modules/blueprints",
|
|
2138
|
+
"local_blueprint",
|
|
2139
|
+
),
|
|
2140
|
+
(
|
|
2141
|
+
"local_blueprint",
|
|
2142
|
+
"blueprint",
|
|
2143
|
+
"*.blueprints.md",
|
|
2144
|
+
"mocked_custom_modules_path",
|
|
2145
|
+
"/mocked_local_templates_path/mocked_custom_modules_path/blueprints",
|
|
2146
|
+
"local_blueprint",
|
|
2147
|
+
),
|
|
2148
|
+
],
|
|
2149
|
+
)
|
|
2150
|
+
def test_load_template_local(
|
|
2151
|
+
monkeypatch,
|
|
2152
|
+
temp_chat_file,
|
|
2153
|
+
template_name,
|
|
2154
|
+
template_type,
|
|
2155
|
+
default_pattern,
|
|
2156
|
+
custom_template_subdir,
|
|
2157
|
+
expected_directory,
|
|
2158
|
+
expected_pattern,
|
|
2159
|
+
):
|
|
2160
|
+
expected_base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))
|
|
1119
2161
|
expected_directory_abs = expected_base_dir + expected_directory
|
|
1120
2162
|
mock_config = get_default_config()
|
|
1121
|
-
with patch(
|
|
2163
|
+
with patch(
|
|
2164
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2165
|
+
):
|
|
1122
2166
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1123
2167
|
|
|
1124
2168
|
mock_local_templates_path = "mocked_local_templates_path"
|
|
1125
2169
|
|
|
1126
|
-
monkeypatch.setattr(
|
|
1127
|
-
|
|
2170
|
+
monkeypatch.setattr(
|
|
2171
|
+
ConfigManager,
|
|
2172
|
+
"get_config",
|
|
2173
|
+
lambda: MagicMock(local_prompt_templates_dir=mock_local_templates_path),
|
|
2174
|
+
)
|
|
1128
2175
|
|
|
1129
2176
|
config = chat.config
|
|
1130
2177
|
config.local_prompt_templates_dir = mock_local_templates_path
|
|
@@ -1132,98 +2179,158 @@ def test_load_template_local(monkeypatch, temp_chat_file, template_name, templat
|
|
|
1132
2179
|
|
|
1133
2180
|
chat.config = config
|
|
1134
2181
|
|
|
1135
|
-
with patch.object(chat,
|
|
2182
|
+
with patch.object(chat, "_load_helper") as mock_load_helper:
|
|
1136
2183
|
chat._load_template_from_global_or_local(template_name, template_type)
|
|
1137
2184
|
mock_load_helper.assert_called_once_with(
|
|
1138
|
-
expected_directory_abs, expected_pattern, template_type
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
2185
|
+
expected_directory_abs, expected_pattern, template_type
|
|
2186
|
+
)
|
|
2187
|
+
|
|
2188
|
+
|
|
2189
|
+
@pytest.mark.parametrize(
|
|
2190
|
+
"template_name, template_type, default_pattern, expected_directory, expected_pattern",
|
|
2191
|
+
[
|
|
2192
|
+
(
|
|
2193
|
+
"global/test_command",
|
|
2194
|
+
"commands",
|
|
2195
|
+
"*.commands.md",
|
|
2196
|
+
"mocked_template_base_path/prompt-modules/commands/",
|
|
2197
|
+
"test_command",
|
|
2198
|
+
),
|
|
2199
|
+
(
|
|
2200
|
+
"global/test_rule",
|
|
2201
|
+
"rules",
|
|
2202
|
+
"*.rules.md",
|
|
2203
|
+
"mocked_template_base_path/prompt-modules/rules/",
|
|
2204
|
+
"test_rule",
|
|
2205
|
+
),
|
|
2206
|
+
(
|
|
2207
|
+
"global/test_intention",
|
|
2208
|
+
"intention",
|
|
2209
|
+
"*.intentions.md",
|
|
2210
|
+
"mocked_template_base_path/prompt-modules/intentions/",
|
|
2211
|
+
"test_intention",
|
|
2212
|
+
),
|
|
2213
|
+
(
|
|
2214
|
+
"global/test_blueprint",
|
|
2215
|
+
"blueprint",
|
|
2216
|
+
"*.blueprints.md",
|
|
2217
|
+
"mocked_template_base_path/prompt-modules/blueprints/",
|
|
2218
|
+
"test_blueprint",
|
|
2219
|
+
),
|
|
2220
|
+
],
|
|
2221
|
+
)
|
|
2222
|
+
def test_load_template_from_global(
|
|
2223
|
+
monkeypatch,
|
|
2224
|
+
temp_chat_file,
|
|
2225
|
+
template_name,
|
|
2226
|
+
template_type,
|
|
2227
|
+
default_pattern,
|
|
2228
|
+
expected_directory,
|
|
2229
|
+
expected_pattern,
|
|
2230
|
+
):
|
|
1152
2231
|
mock_config = get_default_config()
|
|
1153
|
-
with patch(
|
|
2232
|
+
with patch(
|
|
2233
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2234
|
+
):
|
|
1154
2235
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1155
2236
|
|
|
1156
2237
|
mock_template_base_path = "mocked_template_base_path"
|
|
1157
2238
|
|
|
1158
2239
|
monkeypatch.setattr(
|
|
1159
|
-
TemplatePathManager,
|
|
2240
|
+
TemplatePathManager, "get_template_base_path", lambda: mock_template_base_path
|
|
2241
|
+
)
|
|
1160
2242
|
|
|
1161
2243
|
config = chat.config
|
|
1162
2244
|
chat.config = config
|
|
1163
2245
|
|
|
1164
|
-
with patch.object(chat,
|
|
2246
|
+
with patch.object(chat, "_load_helper") as mock_load_helper:
|
|
1165
2247
|
chat._load_template_from_global_or_local(template_name, template_type)
|
|
1166
2248
|
mock_load_helper.assert_called_once_with(
|
|
1167
|
-
expected_directory, expected_pattern, template_type
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
@pytest.mark.parametrize("template_name, template_type, default_pattern", [
|
|
1171
|
-
("global/test_command", "commands", "*.commands.md"),
|
|
1172
|
-
("local_command", "commands", "*.commands.md"),
|
|
2249
|
+
expected_directory, expected_pattern, template_type
|
|
2250
|
+
)
|
|
1173
2251
|
|
|
1174
|
-
("global/test_rule", "rules", "*.rules.md"),
|
|
1175
|
-
("local_rule", "rules", "*.rules.md"),
|
|
1176
2252
|
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
2253
|
+
@pytest.mark.parametrize(
|
|
2254
|
+
"template_name, template_type, default_pattern",
|
|
2255
|
+
[
|
|
2256
|
+
("global/test_command", "commands", "*.commands.md"),
|
|
2257
|
+
("local_command", "commands", "*.commands.md"),
|
|
2258
|
+
("global/test_rule", "rules", "*.rules.md"),
|
|
2259
|
+
("local_rule", "rules", "*.rules.md"),
|
|
2260
|
+
("global/test_intention", "intention", "*.intentions.md"),
|
|
2261
|
+
("local_intention", "intention", "*.intentions.md"),
|
|
2262
|
+
],
|
|
2263
|
+
)
|
|
2264
|
+
def test_load_template_helper_load_from_template_dirs(
|
|
2265
|
+
monkeypatch, temp_chat_file, template_name, template_type, default_pattern
|
|
2266
|
+
):
|
|
1181
2267
|
mock_config = get_default_config()
|
|
1182
|
-
with patch(
|
|
2268
|
+
with patch(
|
|
2269
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2270
|
+
):
|
|
1183
2271
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1184
2272
|
|
|
1185
|
-
with patch.object(
|
|
1186
|
-
chat
|
|
1187
|
-
|
|
2273
|
+
with patch.object(
|
|
2274
|
+
chat, "_load_template_from_global_or_local"
|
|
2275
|
+
) as mock_load_template:
|
|
2276
|
+
chat._load_template_helper(template_name, template_type, default_pattern)
|
|
1188
2277
|
|
|
1189
2278
|
mock_load_template.assert_called_once_with(
|
|
1190
|
-
template_name=template_name, template_type=template_type
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
@pytest.mark.parametrize("template_name, template_type, default_pattern", [
|
|
1194
|
-
(None, "commands", "*.commands.md"),
|
|
1195
|
-
("", "commands", "*.commands.md"),
|
|
2279
|
+
template_name=template_name, template_type=template_type
|
|
2280
|
+
)
|
|
1196
2281
|
|
|
1197
|
-
(None, "rules", "*.rules.md"),
|
|
1198
|
-
("", "rules", "*.rules.md"),
|
|
1199
2282
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
2283
|
+
@pytest.mark.parametrize(
|
|
2284
|
+
"template_name, template_type, default_pattern",
|
|
2285
|
+
[
|
|
2286
|
+
(None, "commands", "*.commands.md"),
|
|
2287
|
+
("", "commands", "*.commands.md"),
|
|
2288
|
+
(None, "rules", "*.rules.md"),
|
|
2289
|
+
("", "rules", "*.rules.md"),
|
|
2290
|
+
(None, "intention", "*.intention.md"),
|
|
2291
|
+
("", "intention", "*.intention.md"),
|
|
2292
|
+
],
|
|
2293
|
+
)
|
|
2294
|
+
def test_load_template_helper_load_default_pattern(
|
|
2295
|
+
monkeypatch, temp_chat_file, template_name, template_type, default_pattern
|
|
2296
|
+
):
|
|
1204
2297
|
mock_config = get_default_config()
|
|
1205
|
-
with patch(
|
|
2298
|
+
with patch(
|
|
2299
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2300
|
+
):
|
|
1206
2301
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1207
2302
|
|
|
1208
2303
|
with patch.object(chat, "_load_helper") as mock_load_helper:
|
|
1209
|
-
chat._load_template_helper(
|
|
1210
|
-
template_name, template_type, default_pattern)
|
|
2304
|
+
chat._load_template_helper(template_name, template_type, default_pattern)
|
|
1211
2305
|
|
|
1212
2306
|
mock_load_helper.assert_called_once_with(
|
|
1213
|
-
"prompt.data", default_pattern, template_type
|
|
2307
|
+
"prompt.data", default_pattern, template_type
|
|
2308
|
+
)
|
|
1214
2309
|
|
|
1215
2310
|
|
|
1216
|
-
@pytest.mark.parametrize(
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
2311
|
+
@pytest.mark.parametrize(
|
|
2312
|
+
"force_flag, write_flag, expected_force, expected_write",
|
|
2313
|
+
[
|
|
2314
|
+
(False, False, False, False),
|
|
2315
|
+
(True, False, True, False),
|
|
2316
|
+
(False, True, False, True),
|
|
2317
|
+
(True, True, True, True),
|
|
2318
|
+
],
|
|
2319
|
+
)
|
|
2320
|
+
@patch("ara_cli.commands.extract_command.ExtractCommand")
|
|
2321
|
+
def test_do_EXTRACT_with_flags(
|
|
2322
|
+
MockExtractCommand,
|
|
2323
|
+
temp_chat_file,
|
|
2324
|
+
force_flag,
|
|
2325
|
+
write_flag,
|
|
2326
|
+
expected_force,
|
|
2327
|
+
expected_write,
|
|
2328
|
+
):
|
|
1224
2329
|
"""Test do_EXTRACT with different flag combinations"""
|
|
1225
2330
|
mock_config = get_default_config()
|
|
1226
|
-
with patch(
|
|
2331
|
+
with patch(
|
|
2332
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2333
|
+
):
|
|
1227
2334
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1228
2335
|
|
|
1229
2336
|
# Build command string with flags
|
|
@@ -1232,31 +2339,36 @@ def test_do_EXTRACT_with_flags(MockExtractCommand, temp_chat_file, force_flag, w
|
|
|
1232
2339
|
command_parts.append("-f")
|
|
1233
2340
|
if write_flag:
|
|
1234
2341
|
command_parts.append("-w")
|
|
1235
|
-
|
|
2342
|
+
|
|
1236
2343
|
command_string = " ".join(command_parts)
|
|
1237
|
-
|
|
2344
|
+
|
|
1238
2345
|
chat.onecmd_plus_hooks(command_string, orig_rl_history_length=0)
|
|
1239
2346
|
|
|
1240
2347
|
MockExtractCommand.assert_called_once_with(
|
|
1241
2348
|
file_name=chat.chat_name,
|
|
1242
2349
|
force=expected_force,
|
|
1243
2350
|
write=expected_write,
|
|
1244
|
-
output=chat.poutput
|
|
2351
|
+
output=chat.poutput,
|
|
1245
2352
|
)
|
|
1246
2353
|
MockExtractCommand.return_value.execute.assert_called_once()
|
|
1247
2354
|
|
|
1248
2355
|
|
|
1249
|
-
@pytest.mark.parametrize(
|
|
1250
|
-
"
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
2356
|
+
@pytest.mark.parametrize(
|
|
2357
|
+
"command_string",
|
|
2358
|
+
[
|
|
2359
|
+
"EXTRACT --force",
|
|
2360
|
+
"EXTRACT --write",
|
|
2361
|
+
"EXTRACT -f -w",
|
|
2362
|
+
"EXTRACT --force --write",
|
|
2363
|
+
],
|
|
2364
|
+
)
|
|
2365
|
+
@patch("ara_cli.commands.extract_command.ExtractCommand")
|
|
1256
2366
|
def test_do_EXTRACT_long_form_flags(MockExtractCommand, temp_chat_file, command_string):
|
|
1257
2367
|
"""Test do_EXTRACT with long-form flag variations"""
|
|
1258
2368
|
mock_config = get_default_config()
|
|
1259
|
-
with patch(
|
|
2369
|
+
with patch(
|
|
2370
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2371
|
+
):
|
|
1260
2372
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1261
2373
|
|
|
1262
2374
|
chat.onecmd_plus_hooks(command_string, orig_rl_history_length=0)
|
|
@@ -1265,50 +2377,53 @@ def test_do_EXTRACT_long_form_flags(MockExtractCommand, temp_chat_file, command_
|
|
|
1265
2377
|
MockExtractCommand.return_value.execute.assert_called_once()
|
|
1266
2378
|
|
|
1267
2379
|
|
|
1268
|
-
@patch(
|
|
2380
|
+
@patch("ara_cli.commands.extract_command.ExtractCommand")
|
|
1269
2381
|
def test_do_EXTRACT_no_flags(MockExtractCommand, temp_chat_file):
|
|
1270
2382
|
"""Test do_EXTRACT with no flags (default behavior)"""
|
|
1271
2383
|
mock_config = get_default_config()
|
|
1272
|
-
with patch(
|
|
2384
|
+
with patch(
|
|
2385
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2386
|
+
):
|
|
1273
2387
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1274
2388
|
|
|
1275
2389
|
chat.onecmd_plus_hooks("EXTRACT", orig_rl_history_length=0)
|
|
1276
2390
|
|
|
1277
2391
|
MockExtractCommand.assert_called_once_with(
|
|
1278
|
-
file_name=chat.chat_name,
|
|
1279
|
-
force=False,
|
|
1280
|
-
write=False,
|
|
1281
|
-
output=chat.poutput
|
|
2392
|
+
file_name=chat.chat_name, force=False, write=False, output=chat.poutput
|
|
1282
2393
|
)
|
|
1283
2394
|
MockExtractCommand.return_value.execute.assert_called_once()
|
|
1284
2395
|
|
|
1285
2396
|
|
|
1286
|
-
@patch(
|
|
2397
|
+
@patch("ara_cli.commands.extract_command.ExtractCommand")
|
|
1287
2398
|
def test_do_EXTRACT_command_instantiation(MockExtractCommand, temp_chat_file):
|
|
1288
2399
|
"""Test that ExtractCommand is properly instantiated with correct parameters"""
|
|
1289
2400
|
mock_config = get_default_config()
|
|
1290
|
-
with patch(
|
|
2401
|
+
with patch(
|
|
2402
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2403
|
+
):
|
|
1291
2404
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1292
2405
|
|
|
1293
2406
|
chat.onecmd_plus_hooks("EXTRACT -f", orig_rl_history_length=0)
|
|
1294
2407
|
|
|
1295
2408
|
# Verify the command was instantiated with the correct chat instance attributes
|
|
1296
2409
|
call_args = MockExtractCommand.call_args
|
|
1297
|
-
assert call_args[1][
|
|
1298
|
-
assert call_args[1][
|
|
1299
|
-
assert isinstance(call_args[1][
|
|
1300
|
-
assert isinstance(call_args[1][
|
|
2410
|
+
assert call_args[1]["file_name"] == chat.chat_name
|
|
2411
|
+
assert call_args[1]["output"] == chat.poutput
|
|
2412
|
+
assert isinstance(call_args[1]["force"], bool)
|
|
2413
|
+
assert isinstance(call_args[1]["write"], bool)
|
|
1301
2414
|
|
|
1302
2415
|
|
|
1303
|
-
@patch(
|
|
2416
|
+
@patch("ara_cli.commands.extract_command.ExtractCommand")
|
|
1304
2417
|
def test_do_EXTRACT_command_execution(MockExtractCommand, temp_chat_file):
|
|
1305
2418
|
"""Test that ExtractCommand.execute() is called"""
|
|
1306
2419
|
mock_config = get_default_config()
|
|
1307
|
-
with patch(
|
|
2420
|
+
with patch(
|
|
2421
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2422
|
+
):
|
|
1308
2423
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1309
2424
|
|
|
1310
2425
|
mock_command_instance = MockExtractCommand.return_value
|
|
1311
|
-
|
|
2426
|
+
|
|
1312
2427
|
chat.onecmd_plus_hooks("EXTRACT", orig_rl_history_length=0)
|
|
1313
2428
|
|
|
1314
2429
|
mock_command_instance.execute.assert_called_once_with()
|
|
@@ -1316,54 +2431,205 @@ def test_do_EXTRACT_command_execution(MockExtractCommand, temp_chat_file):
|
|
|
1316
2431
|
|
|
1317
2432
|
def test_do_SEND(temp_chat_file):
|
|
1318
2433
|
mock_config = get_default_config()
|
|
1319
|
-
with patch(
|
|
2434
|
+
with patch(
|
|
2435
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2436
|
+
):
|
|
1320
2437
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1321
2438
|
chat.message_buffer = ["Message part 1", "Message part 2"]
|
|
1322
2439
|
|
|
1323
|
-
with patch.object(chat,
|
|
1324
|
-
with patch.object(chat,
|
|
2440
|
+
with patch.object(chat, "save_message") as mock_save_message:
|
|
2441
|
+
with patch.object(chat, "send_message") as mock_send_message:
|
|
1325
2442
|
chat.do_SEND(None)
|
|
1326
2443
|
mock_save_message.assert_called_once_with(
|
|
1327
|
-
Chat.ROLE_PROMPT, "Message part 1\nMessage part 2"
|
|
2444
|
+
Chat.ROLE_PROMPT, "Message part 1\nMessage part 2"
|
|
2445
|
+
)
|
|
1328
2446
|
mock_send_message.assert_called_once()
|
|
1329
2447
|
|
|
1330
2448
|
|
|
1331
|
-
@pytest.mark.parametrize(
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
2449
|
+
@pytest.mark.parametrize(
|
|
2450
|
+
"template_name, artefact_obj, expected_write, expected_print",
|
|
2451
|
+
[
|
|
2452
|
+
(
|
|
2453
|
+
"TestTemplate",
|
|
2454
|
+
MagicMock(serialize=MagicMock(return_value="serialized_content")),
|
|
2455
|
+
"serialized_content",
|
|
2456
|
+
"Loaded TestTemplate artefact template\n",
|
|
2457
|
+
),
|
|
2458
|
+
(
|
|
2459
|
+
"AnotherTemplate",
|
|
2460
|
+
MagicMock(serialize=MagicMock(return_value="other_content")),
|
|
2461
|
+
"other_content",
|
|
2462
|
+
"Loaded AnotherTemplate artefact template\n",
|
|
2463
|
+
),
|
|
2464
|
+
(
|
|
2465
|
+
"",
|
|
2466
|
+
MagicMock(serialize=MagicMock(return_value="empty_content")),
|
|
2467
|
+
"empty_content",
|
|
2468
|
+
"Loaded artefact template\n",
|
|
2469
|
+
),
|
|
2470
|
+
],
|
|
2471
|
+
)
|
|
2472
|
+
def test_do_LOAD_TEMPLATE_success(
|
|
2473
|
+
temp_chat_file, template_name, artefact_obj, expected_write, expected_print, capsys
|
|
2474
|
+
):
|
|
1338
2475
|
mock_config = MagicMock()
|
|
1339
|
-
with patch(
|
|
2476
|
+
with patch(
|
|
2477
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2478
|
+
):
|
|
1340
2479
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
2480
|
+
|
|
2481
|
+
with patch(
|
|
2482
|
+
"ara_cli.artefact_models.artefact_templates.template_artefact_of_type",
|
|
2483
|
+
return_value=artefact_obj,
|
|
2484
|
+
) as mock_template_loader, patch.object(
|
|
2485
|
+
chat, "add_prompt_tag_if_needed"
|
|
2486
|
+
) as mock_add_prompt_tag, patch(
|
|
2487
|
+
"builtins.open", mock_open()
|
|
2488
|
+
) as mock_file:
|
|
2489
|
+
|
|
1344
2490
|
chat.do_LOAD_TEMPLATE(template_name)
|
|
2491
|
+
|
|
1345
2492
|
mock_template_loader.assert_called_once_with(template_name)
|
|
1346
2493
|
artefact_obj.serialize.assert_called_once_with()
|
|
1347
2494
|
mock_add_prompt_tag.assert_called_once_with(chat.chat_name)
|
|
1348
|
-
mock_file.assert_called_with(chat.chat_name,
|
|
2495
|
+
mock_file.assert_called_with(chat.chat_name, "a", encoding="utf-8")
|
|
1349
2496
|
mock_file().write.assert_called_once_with(expected_write)
|
|
2497
|
+
|
|
1350
2498
|
out = capsys.readouterr()
|
|
1351
2499
|
assert expected_print in out.out
|
|
1352
2500
|
|
|
1353
2501
|
|
|
1354
|
-
@pytest.mark.parametrize(
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
2502
|
+
@pytest.mark.parametrize(
|
|
2503
|
+
"template_name",
|
|
2504
|
+
[
|
|
2505
|
+
"MissingTemplate",
|
|
2506
|
+
"",
|
|
2507
|
+
"NonExistentTemplate",
|
|
2508
|
+
],
|
|
2509
|
+
)
|
|
2510
|
+
@patch("ara_cli.error_handler.report_error")
|
|
2511
|
+
def test_do_LOAD_TEMPLATE_missing_artefact(
|
|
2512
|
+
mock_report_error, temp_chat_file, template_name
|
|
2513
|
+
):
|
|
1359
2514
|
mock_config = MagicMock()
|
|
1360
|
-
with patch(
|
|
2515
|
+
with patch(
|
|
2516
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2517
|
+
):
|
|
1361
2518
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
2519
|
+
|
|
2520
|
+
with patch(
|
|
2521
|
+
"ara_cli.artefact_models.artefact_templates.template_artefact_of_type",
|
|
2522
|
+
return_value=None,
|
|
2523
|
+
) as mock_template_loader, patch.object(
|
|
2524
|
+
chat, "add_prompt_tag_if_needed"
|
|
2525
|
+
) as mock_add_prompt_tag, patch(
|
|
2526
|
+
"builtins.open", mock_open()
|
|
2527
|
+
) as mock_file:
|
|
2528
|
+
|
|
2529
|
+
chat.do_LOAD_TEMPLATE(template_name)
|
|
2530
|
+
|
|
1367
2531
|
mock_template_loader.assert_called_once_with(template_name)
|
|
2532
|
+
mock_report_error.assert_called_once()
|
|
2533
|
+
|
|
2534
|
+
# Verify the error details
|
|
2535
|
+
error_call = mock_report_error.call_args[0][0]
|
|
2536
|
+
assert isinstance(error_call, ValueError)
|
|
2537
|
+
assert str(error_call) == f"No template for '{template_name}' found."
|
|
2538
|
+
|
|
2539
|
+
# Verify subsequent operations are not called
|
|
1368
2540
|
mock_add_prompt_tag.assert_not_called()
|
|
1369
2541
|
mock_file.assert_not_called()
|
|
2542
|
+
|
|
2543
|
+
|
|
2544
|
+
def test_do_LOAD_TEMPLATE_string_join_behavior(temp_chat_file):
|
|
2545
|
+
"""Test that template_name is properly joined when passed as argument"""
|
|
2546
|
+
mock_config = MagicMock()
|
|
2547
|
+
with patch(
|
|
2548
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2549
|
+
):
|
|
2550
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
2551
|
+
|
|
2552
|
+
mock_artefact = MagicMock(serialize=MagicMock(return_value="test_content"))
|
|
2553
|
+
|
|
2554
|
+
with patch(
|
|
2555
|
+
"ara_cli.artefact_models.artefact_templates.template_artefact_of_type",
|
|
2556
|
+
return_value=mock_artefact,
|
|
2557
|
+
) as mock_template_loader, patch.object(chat, "add_prompt_tag_if_needed"), patch(
|
|
2558
|
+
"builtins.open", mock_open()
|
|
2559
|
+
):
|
|
2560
|
+
|
|
2561
|
+
# Test with string argument (normal case)
|
|
2562
|
+
chat.do_LOAD_TEMPLATE("TestTemplate")
|
|
2563
|
+
mock_template_loader.assert_called_with("TestTemplate")
|
|
2564
|
+
|
|
2565
|
+
# Reset mock for next test
|
|
2566
|
+
mock_template_loader.reset_mock()
|
|
2567
|
+
|
|
2568
|
+
# Test with list-like argument (edge case)
|
|
2569
|
+
chat.do_LOAD_TEMPLATE(["Test", "Template"])
|
|
2570
|
+
mock_template_loader.assert_called_with("TestTemplate")
|
|
2571
|
+
|
|
2572
|
+
|
|
2573
|
+
def test_do_LOAD_TEMPLATE_file_operations(temp_chat_file):
|
|
2574
|
+
"""Test file operations are performed in correct order"""
|
|
2575
|
+
mock_config = MagicMock()
|
|
2576
|
+
with patch(
|
|
2577
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2578
|
+
):
|
|
2579
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
2580
|
+
|
|
2581
|
+
mock_artefact = MagicMock(serialize=MagicMock(return_value="test_content"))
|
|
2582
|
+
call_order = []
|
|
2583
|
+
|
|
2584
|
+
def mock_add_prompt_tag(chat_name):
|
|
2585
|
+
call_order.append("add_prompt_tag")
|
|
2586
|
+
|
|
2587
|
+
def mock_write(content):
|
|
2588
|
+
call_order.append("write")
|
|
2589
|
+
|
|
2590
|
+
with patch(
|
|
2591
|
+
"ara_cli.artefact_models.artefact_templates.template_artefact_of_type",
|
|
2592
|
+
return_value=mock_artefact,
|
|
2593
|
+
), patch.object(
|
|
2594
|
+
chat, "add_prompt_tag_if_needed", side_effect=mock_add_prompt_tag
|
|
2595
|
+
), patch(
|
|
2596
|
+
"builtins.open", mock_open()
|
|
2597
|
+
) as mock_file:
|
|
2598
|
+
|
|
2599
|
+
mock_file().write.side_effect = mock_write
|
|
2600
|
+
|
|
2601
|
+
chat.do_LOAD_TEMPLATE("TestTemplate")
|
|
2602
|
+
|
|
2603
|
+
# Verify operations happen in correct order
|
|
2604
|
+
assert call_order == ["add_prompt_tag", "write"]
|
|
2605
|
+
|
|
2606
|
+
# Verify file is opened with correct parameters
|
|
2607
|
+
mock_file.assert_called_with(chat.chat_name, "a", encoding="utf-8")
|
|
2608
|
+
|
|
2609
|
+
|
|
2610
|
+
def test_do_LOAD_TEMPLATE_serialize_called_correctly(temp_chat_file):
|
|
2611
|
+
"""Test that artefact.serialize() is called and its result is used"""
|
|
2612
|
+
mock_config = MagicMock()
|
|
2613
|
+
with patch(
|
|
2614
|
+
"ara_cli.prompt_handler.ConfigManager.get_config", return_value=mock_config
|
|
2615
|
+
):
|
|
2616
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
2617
|
+
|
|
2618
|
+
expected_content = "unique_serialized_content_12345"
|
|
2619
|
+
mock_artefact = MagicMock()
|
|
2620
|
+
mock_artefact.serialize.return_value = expected_content
|
|
2621
|
+
|
|
2622
|
+
with patch(
|
|
2623
|
+
"ara_cli.artefact_models.artefact_templates.template_artefact_of_type",
|
|
2624
|
+
return_value=mock_artefact,
|
|
2625
|
+
), patch.object(chat, "add_prompt_tag_if_needed"), patch(
|
|
2626
|
+
"builtins.open", mock_open()
|
|
2627
|
+
) as mock_file:
|
|
2628
|
+
|
|
2629
|
+
chat.do_LOAD_TEMPLATE("TestTemplate")
|
|
2630
|
+
|
|
2631
|
+
# Verify serialize was called exactly once
|
|
2632
|
+
mock_artefact.serialize.assert_called_once_with()
|
|
2633
|
+
|
|
2634
|
+
# Verify the serialized content was written to file
|
|
2635
|
+
mock_file().write.assert_called_once_with(expected_content)
|