ara-cli 0.1.9.69__py3-none-any.whl → 0.1.10.8__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.
Potentially problematic release.
This version of ara-cli might be problematic. Click here for more details.
- ara_cli/__init__.py +18 -2
- ara_cli/__main__.py +248 -62
- ara_cli/ara_command_action.py +155 -86
- ara_cli/ara_config.py +226 -80
- ara_cli/ara_subcommands/__init__.py +0 -0
- ara_cli/ara_subcommands/autofix.py +26 -0
- ara_cli/ara_subcommands/chat.py +27 -0
- ara_cli/ara_subcommands/classifier_directory.py +16 -0
- ara_cli/ara_subcommands/common.py +100 -0
- ara_cli/ara_subcommands/create.py +75 -0
- ara_cli/ara_subcommands/delete.py +22 -0
- ara_cli/ara_subcommands/extract.py +22 -0
- ara_cli/ara_subcommands/fetch_templates.py +14 -0
- ara_cli/ara_subcommands/list.py +65 -0
- ara_cli/ara_subcommands/list_tags.py +25 -0
- ara_cli/ara_subcommands/load.py +48 -0
- ara_cli/ara_subcommands/prompt.py +136 -0
- ara_cli/ara_subcommands/read.py +47 -0
- ara_cli/ara_subcommands/read_status.py +20 -0
- ara_cli/ara_subcommands/read_user.py +20 -0
- ara_cli/ara_subcommands/reconnect.py +27 -0
- ara_cli/ara_subcommands/rename.py +22 -0
- ara_cli/ara_subcommands/scan.py +14 -0
- ara_cli/ara_subcommands/set_status.py +22 -0
- ara_cli/ara_subcommands/set_user.py +22 -0
- ara_cli/ara_subcommands/template.py +16 -0
- ara_cli/artefact_autofix.py +649 -68
- ara_cli/artefact_creator.py +8 -11
- ara_cli/artefact_deleter.py +2 -4
- ara_cli/artefact_fuzzy_search.py +22 -10
- ara_cli/artefact_link_updater.py +4 -4
- ara_cli/artefact_lister.py +29 -55
- ara_cli/artefact_models/artefact_data_retrieval.py +23 -0
- ara_cli/artefact_models/artefact_load.py +11 -3
- ara_cli/artefact_models/artefact_model.py +146 -39
- ara_cli/artefact_models/artefact_templates.py +70 -44
- ara_cli/artefact_models/businessgoal_artefact_model.py +23 -25
- ara_cli/artefact_models/epic_artefact_model.py +34 -26
- ara_cli/artefact_models/feature_artefact_model.py +203 -64
- ara_cli/artefact_models/keyfeature_artefact_model.py +21 -24
- ara_cli/artefact_models/serialize_helper.py +1 -1
- ara_cli/artefact_models/task_artefact_model.py +83 -15
- ara_cli/artefact_models/userstory_artefact_model.py +37 -27
- ara_cli/artefact_models/vision_artefact_model.py +23 -42
- ara_cli/artefact_reader.py +92 -91
- ara_cli/artefact_renamer.py +8 -4
- ara_cli/artefact_scan.py +66 -3
- ara_cli/chat.py +622 -162
- ara_cli/chat_agent/__init__.py +0 -0
- ara_cli/chat_agent/agent_communicator.py +62 -0
- ara_cli/chat_agent/agent_process_manager.py +211 -0
- ara_cli/chat_agent/agent_status_manager.py +73 -0
- ara_cli/chat_agent/agent_workspace_manager.py +76 -0
- ara_cli/commands/__init__.py +0 -0
- ara_cli/commands/command.py +7 -0
- ara_cli/commands/extract_command.py +15 -0
- ara_cli/commands/load_command.py +65 -0
- ara_cli/commands/load_image_command.py +34 -0
- ara_cli/commands/read_command.py +117 -0
- ara_cli/completers.py +144 -0
- ara_cli/directory_navigator.py +37 -4
- ara_cli/error_handler.py +134 -0
- ara_cli/file_classifier.py +6 -5
- ara_cli/file_lister.py +1 -1
- ara_cli/file_loaders/__init__.py +0 -0
- ara_cli/file_loaders/binary_file_loader.py +33 -0
- ara_cli/file_loaders/document_file_loader.py +34 -0
- ara_cli/file_loaders/document_reader.py +245 -0
- ara_cli/file_loaders/document_readers.py +233 -0
- ara_cli/file_loaders/file_loader.py +50 -0
- ara_cli/file_loaders/file_loaders.py +123 -0
- ara_cli/file_loaders/image_processor.py +89 -0
- ara_cli/file_loaders/markdown_reader.py +75 -0
- ara_cli/file_loaders/text_file_loader.py +187 -0
- ara_cli/global_file_lister.py +51 -0
- ara_cli/list_filter.py +1 -1
- ara_cli/output_suppressor.py +1 -1
- ara_cli/prompt_extractor.py +215 -88
- ara_cli/prompt_handler.py +521 -134
- ara_cli/prompt_rag.py +2 -2
- ara_cli/tag_extractor.py +83 -38
- ara_cli/template_loader.py +245 -0
- ara_cli/template_manager.py +18 -13
- ara_cli/templates/prompt-modules/commands/empty.commands.md +2 -12
- ara_cli/templates/prompt-modules/commands/extract_general.commands.md +12 -0
- ara_cli/templates/prompt-modules/commands/extract_markdown.commands.md +11 -0
- ara_cli/templates/prompt-modules/commands/extract_python.commands.md +13 -0
- ara_cli/templates/prompt-modules/commands/feature_add_or_modifiy_specified_behavior.commands.md +36 -0
- ara_cli/templates/prompt-modules/commands/feature_generate_initial_specified_bevahior.commands.md +53 -0
- ara_cli/templates/prompt-modules/commands/prompt_template_tech_stack_transformer.commands.md +95 -0
- ara_cli/templates/prompt-modules/commands/python_bug_fixing_code.commands.md +34 -0
- ara_cli/templates/prompt-modules/commands/python_generate_code.commands.md +27 -0
- ara_cli/templates/prompt-modules/commands/python_refactoring_code.commands.md +39 -0
- ara_cli/templates/prompt-modules/commands/python_step_definitions_generation_and_fixing.commands.md +40 -0
- ara_cli/templates/prompt-modules/commands/python_unittest_generation_and_fixing.commands.md +48 -0
- ara_cli/update_config_prompt.py +9 -3
- ara_cli/version.py +1 -1
- ara_cli-0.1.10.8.dist-info/METADATA +241 -0
- ara_cli-0.1.10.8.dist-info/RECORD +193 -0
- tests/test_ara_command_action.py +73 -59
- tests/test_ara_config.py +341 -36
- tests/test_artefact_autofix.py +1060 -0
- tests/test_artefact_link_updater.py +3 -3
- tests/test_artefact_lister.py +52 -132
- tests/test_artefact_renamer.py +2 -2
- tests/test_artefact_scan.py +327 -33
- tests/test_chat.py +2063 -498
- tests/test_file_classifier.py +24 -1
- tests/test_file_creator.py +3 -5
- tests/test_file_lister.py +1 -1
- tests/test_global_file_lister.py +131 -0
- tests/test_list_filter.py +2 -2
- tests/test_prompt_handler.py +746 -0
- tests/test_tag_extractor.py +19 -13
- tests/test_template_loader.py +192 -0
- tests/test_template_manager.py +5 -4
- tests/test_update_config_prompt.py +2 -2
- ara_cli/ara_command_parser.py +0 -327
- ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +0 -27
- ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -30
- ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -9
- ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -17
- ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -14
- ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -102
- ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -20
- ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -13
- ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -20
- ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -18
- ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -43
- ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -13
- ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -15
- ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -9
- ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -15
- ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -19
- ara_cli/templates/template.businessgoal +0 -10
- ara_cli/templates/template.capability +0 -10
- ara_cli/templates/template.epic +0 -15
- ara_cli/templates/template.example +0 -6
- ara_cli/templates/template.feature +0 -26
- ara_cli/templates/template.issue +0 -14
- ara_cli/templates/template.keyfeature +0 -15
- ara_cli/templates/template.task +0 -6
- ara_cli/templates/template.userstory +0 -17
- ara_cli/templates/template.vision +0 -14
- ara_cli-0.1.9.69.dist-info/METADATA +0 -16
- ara_cli-0.1.9.69.dist-info/RECORD +0 -158
- tests/test_ara_autofix.py +0 -219
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.10.8.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.10.8.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.10.8.dist-info}/top_level.txt +0 -0
tests/test_artefact_scan.py
CHANGED
|
@@ -1,22 +1,272 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from unittest.mock import patch, MagicMock, mock_open, call
|
|
3
|
-
from ara_cli.artefact_scan import
|
|
4
|
-
|
|
3
|
+
from ara_cli.artefact_scan import (
|
|
4
|
+
check_file,
|
|
5
|
+
find_invalid_files,
|
|
6
|
+
show_results,
|
|
7
|
+
is_contribution_valid,
|
|
8
|
+
is_rule_valid,
|
|
9
|
+
check_contribution,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.mark.parametrize("contribution", [None, False, 0, "", []])
|
|
14
|
+
def test_check_contribution_none_contribution(contribution):
|
|
15
|
+
# Should return (True, None) if contribution is falsey
|
|
16
|
+
result = check_contribution(
|
|
17
|
+
contribution, classified_artefact_info={}, file_path="irrelevant"
|
|
18
|
+
)
|
|
19
|
+
assert result == (True, None)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_check_contribution_invalid_contribution(monkeypatch):
|
|
23
|
+
# If is_contribution_valid returns False, should return (False, custom_reason)
|
|
24
|
+
contribution = MagicMock()
|
|
25
|
+
contribution.classifier = "some_cls"
|
|
26
|
+
contribution.artefact_name = "some_art"
|
|
27
|
+
with patch(
|
|
28
|
+
"ara_cli.artefact_scan.is_contribution_valid", return_value=False
|
|
29
|
+
) as mock_is_contrib, patch("ara_cli.artefact_scan.is_rule_valid") as mock_is_rule:
|
|
30
|
+
result = check_contribution(
|
|
31
|
+
contribution, classified_artefact_info={}, file_path="f"
|
|
32
|
+
)
|
|
33
|
+
assert result == (
|
|
34
|
+
False,
|
|
35
|
+
"Invalid Contribution Reference: The contribution references "
|
|
36
|
+
"'some_cls' artefact 'some_art' which does not exist.",
|
|
37
|
+
)
|
|
38
|
+
mock_is_contrib.assert_called_once_with(contribution, {})
|
|
39
|
+
mock_is_rule.assert_not_called()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_check_contribution_invalid_rule(monkeypatch):
|
|
43
|
+
# is_contribution_valid returns True, is_rule_valid returns False
|
|
44
|
+
contribution = MagicMock()
|
|
45
|
+
contribution.classifier = "c"
|
|
46
|
+
contribution.artefact_name = "a"
|
|
47
|
+
contribution.rule = "r"
|
|
48
|
+
with patch(
|
|
49
|
+
"ara_cli.artefact_scan.is_contribution_valid", return_value=True
|
|
50
|
+
) as mock_is_contrib, patch(
|
|
51
|
+
"ara_cli.artefact_scan.is_rule_valid", return_value=False
|
|
52
|
+
) as mock_is_rule:
|
|
53
|
+
result = check_contribution(
|
|
54
|
+
contribution, classified_artefact_info={"x": 1}, file_path="myfile"
|
|
55
|
+
)
|
|
56
|
+
assert result == (
|
|
57
|
+
False,
|
|
58
|
+
"Rule Mismatch: The contribution references rule 'r' which the parent c 'a' does not have.",
|
|
59
|
+
)
|
|
60
|
+
mock_is_contrib.assert_called_once_with(contribution, {"x": 1})
|
|
61
|
+
mock_is_rule.assert_called_once_with(contribution, {"x": 1})
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_check_contribution_all_valid(monkeypatch):
|
|
65
|
+
# Both is_contribution_valid and is_rule_valid return True
|
|
66
|
+
contribution = MagicMock()
|
|
67
|
+
contribution.classifier = "c"
|
|
68
|
+
contribution.artefact_name = "a"
|
|
69
|
+
contribution.rule = "r"
|
|
70
|
+
with patch(
|
|
71
|
+
"ara_cli.artefact_scan.is_contribution_valid", return_value=True
|
|
72
|
+
) as mock_is_contrib, patch(
|
|
73
|
+
"ara_cli.artefact_scan.is_rule_valid", return_value=True
|
|
74
|
+
) as mock_is_rule:
|
|
75
|
+
result = check_contribution(
|
|
76
|
+
contribution, classified_artefact_info={1: 2}, file_path="p"
|
|
77
|
+
)
|
|
78
|
+
assert result == (True, None)
|
|
79
|
+
mock_is_contrib.assert_called_once_with(contribution, {1: 2})
|
|
80
|
+
mock_is_rule.assert_called_once_with(contribution, {1: 2})
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@pytest.mark.parametrize(
|
|
84
|
+
"contribution_attrs,expected",
|
|
85
|
+
[
|
|
86
|
+
(None, True), # contribution is None
|
|
87
|
+
({"artefact_name": None, "classifier": "foo"}, True), # artefact_name is None
|
|
88
|
+
(
|
|
89
|
+
{"artefact_name": "", "classifier": "foo"},
|
|
90
|
+
True,
|
|
91
|
+
), # artefact_name is empty string
|
|
92
|
+
({"artefact_name": "bar", "classifier": None}, True), # classifier is None
|
|
93
|
+
(
|
|
94
|
+
{"artefact_name": "bar", "classifier": ""},
|
|
95
|
+
True,
|
|
96
|
+
), # classifier is empty string
|
|
97
|
+
],
|
|
98
|
+
)
|
|
99
|
+
def test_is_rule_valid_short_circuits(contribution_attrs, expected):
|
|
100
|
+
if contribution_attrs is None:
|
|
101
|
+
contribution = None
|
|
102
|
+
else:
|
|
103
|
+
contribution = MagicMock()
|
|
104
|
+
for k, v in contribution_attrs.items():
|
|
105
|
+
setattr(contribution, k, v)
|
|
106
|
+
with patch("ara_cli.artefact_reader.ArtefactReader.read_artefact") as mock_read:
|
|
107
|
+
result = is_rule_valid(contribution, classified_artefact_info={})
|
|
108
|
+
assert result is expected
|
|
109
|
+
mock_read.assert_not_called()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_is_rule_valid_rule_is_none():
|
|
113
|
+
"""Should return True if contribution.rule is None or falsey."""
|
|
114
|
+
contribution = MagicMock()
|
|
115
|
+
contribution.artefact_name = "foo"
|
|
116
|
+
contribution.classifier = "bar"
|
|
117
|
+
contribution.rule = None
|
|
118
|
+
with patch("ara_cli.artefact_reader.ArtefactReader.read_artefact") as mock_read:
|
|
119
|
+
result = is_rule_valid(contribution, classified_artefact_info={})
|
|
120
|
+
assert result is True
|
|
121
|
+
mock_read.assert_not_called()
|
|
122
|
+
|
|
123
|
+
# Also test rule as empty string
|
|
124
|
+
contribution.rule = ""
|
|
125
|
+
with patch("ara_cli.artefact_reader.ArtefactReader.read_artefact") as mock_read:
|
|
126
|
+
result = is_rule_valid(contribution, classified_artefact_info={})
|
|
127
|
+
assert result is True
|
|
128
|
+
mock_read.assert_not_called()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@pytest.mark.parametrize(
|
|
132
|
+
"parent,expected",
|
|
133
|
+
[
|
|
134
|
+
(None, True), # parent is None
|
|
135
|
+
(MagicMock(rules=None), False), # parent.rules is None
|
|
136
|
+
],
|
|
137
|
+
)
|
|
138
|
+
def test_is_rule_valid_parent_or_rules_none(parent, expected):
|
|
139
|
+
contribution = MagicMock()
|
|
140
|
+
contribution.artefact_name = "foo"
|
|
141
|
+
contribution.classifier = "bar"
|
|
142
|
+
contribution.rule = "r1"
|
|
143
|
+
with patch(
|
|
144
|
+
"ara_cli.artefact_reader.ArtefactReader.read_artefact", return_value=parent
|
|
145
|
+
) as mock_read:
|
|
146
|
+
result = is_rule_valid(contribution, classified_artefact_info={})
|
|
147
|
+
assert result is expected
|
|
148
|
+
mock_read.assert_called_once_with("foo", "bar")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_is_rule_valid_rule_not_in_parent_rules():
|
|
152
|
+
"""Should return False if rule is not in parent.rules."""
|
|
153
|
+
contribution = MagicMock()
|
|
154
|
+
contribution.artefact_name = "foo"
|
|
155
|
+
contribution.classifier = "bar"
|
|
156
|
+
contribution.rule = "missing_rule"
|
|
157
|
+
parent = MagicMock()
|
|
158
|
+
parent.rules = ["rule1", "rule2"]
|
|
159
|
+
with patch(
|
|
160
|
+
"ara_cli.artefact_reader.ArtefactReader.read_artefact", return_value=parent
|
|
161
|
+
) as mock_read:
|
|
162
|
+
result = is_rule_valid(contribution, classified_artefact_info={})
|
|
163
|
+
assert result is False
|
|
164
|
+
mock_read.assert_called_once_with("foo", "bar")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_is_rule_valid_rule_in_parent_rules():
|
|
168
|
+
"""Should return True if rule is in parent.rules."""
|
|
169
|
+
contribution = MagicMock()
|
|
170
|
+
contribution.artefact_name = "foo"
|
|
171
|
+
contribution.classifier = "bar"
|
|
172
|
+
contribution.rule = "my_rule"
|
|
173
|
+
parent = MagicMock()
|
|
174
|
+
parent.rules = ["my_rule", "other_rule"]
|
|
175
|
+
with patch(
|
|
176
|
+
"ara_cli.artefact_reader.ArtefactReader.read_artefact", return_value=parent
|
|
177
|
+
) as mock_read:
|
|
178
|
+
result = is_rule_valid(contribution, classified_artefact_info={})
|
|
179
|
+
assert result is True
|
|
180
|
+
mock_read.assert_called_once_with("foo", "bar")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@pytest.mark.parametrize(
|
|
184
|
+
"contribution_attrs,expected",
|
|
185
|
+
[
|
|
186
|
+
# contribution is None
|
|
187
|
+
(None, True),
|
|
188
|
+
# artefact_name missing/None/empty
|
|
189
|
+
({"artefact_name": None, "classifier": "foo"}, True),
|
|
190
|
+
({"artefact_name": "", "classifier": "foo"}, True),
|
|
191
|
+
# classifier missing/None/empty
|
|
192
|
+
({"artefact_name": "bar", "classifier": None}, True),
|
|
193
|
+
({"artefact_name": "bar", "classifier": ""}, True),
|
|
194
|
+
],
|
|
195
|
+
)
|
|
196
|
+
def test_is_contribution_valid_short_circuits(contribution_attrs, expected):
|
|
197
|
+
classified_artefact_info = {"dummy": []}
|
|
198
|
+
if contribution_attrs is None:
|
|
199
|
+
contribution = None
|
|
200
|
+
else:
|
|
201
|
+
contribution = MagicMock()
|
|
202
|
+
for k, v in contribution_attrs.items():
|
|
203
|
+
setattr(contribution, k, v)
|
|
204
|
+
with patch(
|
|
205
|
+
"ara_cli.artefact_fuzzy_search.extract_artefact_names_of_classifier"
|
|
206
|
+
) as mock_extract:
|
|
207
|
+
result = is_contribution_valid(contribution, classified_artefact_info)
|
|
208
|
+
assert result is expected
|
|
209
|
+
# The extract function should NOT be called in these cases
|
|
210
|
+
mock_extract.assert_not_called()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def test_is_contribution_valid_references_existing_artefact():
|
|
214
|
+
"""
|
|
215
|
+
contribution with valid artefact_name and classifier,
|
|
216
|
+
artefact_name IS in list returned by extract_artefact_names_of_classifier.
|
|
217
|
+
"""
|
|
218
|
+
contribution = MagicMock()
|
|
219
|
+
contribution.artefact_name = "valid_art"
|
|
220
|
+
contribution.classifier = "valid_clf"
|
|
221
|
+
classified_artefact_info = {"valid_clf": [{"name": "valid_art"}]}
|
|
222
|
+
with patch(
|
|
223
|
+
"ara_cli.artefact_fuzzy_search.extract_artefact_names_of_classifier",
|
|
224
|
+
return_value=["valid_art"],
|
|
225
|
+
) as mock_extract:
|
|
226
|
+
result = is_contribution_valid(contribution, classified_artefact_info)
|
|
227
|
+
assert result is True
|
|
228
|
+
mock_extract.assert_called_once_with(
|
|
229
|
+
classified_files=classified_artefact_info, classifier="valid_clf"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def test_is_contribution_valid_references_missing_artefact():
|
|
234
|
+
"""
|
|
235
|
+
contribution with valid artefact_name and classifier,
|
|
236
|
+
artefact_name is NOT in list returned by extract_artefact_names_of_classifier.
|
|
237
|
+
"""
|
|
238
|
+
contribution = MagicMock()
|
|
239
|
+
contribution.artefact_name = "missing_art"
|
|
240
|
+
contribution.classifier = "some_clf"
|
|
241
|
+
classified_artefact_info = {"some_clf": [{"name": "another"}]}
|
|
242
|
+
with patch(
|
|
243
|
+
"ara_cli.artefact_fuzzy_search.extract_artefact_names_of_classifier",
|
|
244
|
+
return_value=["another", "something_else"],
|
|
245
|
+
) as mock_extract:
|
|
246
|
+
result = is_contribution_valid(contribution, classified_artefact_info)
|
|
247
|
+
assert result is False
|
|
248
|
+
mock_extract.assert_called_once_with(
|
|
249
|
+
classified_files=classified_artefact_info, classifier="some_clf"
|
|
250
|
+
)
|
|
5
251
|
|
|
6
252
|
|
|
7
253
|
def test_check_file_valid():
|
|
8
254
|
"""Tests the happy path where the file is valid and the title matches."""
|
|
9
255
|
mock_artefact_instance = MagicMock()
|
|
10
256
|
mock_artefact_instance.title = "dummy_path"
|
|
257
|
+
# Mock contribution to be None to avoid contribution reference check
|
|
258
|
+
mock_artefact_instance.contribution = None
|
|
11
259
|
|
|
12
260
|
mock_artefact_class = MagicMock()
|
|
13
261
|
mock_artefact_class.deserialize.return_value = mock_artefact_instance
|
|
14
262
|
|
|
15
263
|
with patch("builtins.open", mock_open(read_data="valid content")):
|
|
16
264
|
is_valid, reason = check_file("dummy_path.feature", mock_artefact_class)
|
|
17
|
-
|
|
18
|
-
assert
|
|
19
|
-
|
|
265
|
+
|
|
266
|
+
assert (
|
|
267
|
+
reason is None
|
|
268
|
+
), f"Reason for invalid found, expected none to be found. The reason found: {reason}"
|
|
269
|
+
assert is_valid is True, "File detected as invalid, expected to be valid"
|
|
20
270
|
|
|
21
271
|
|
|
22
272
|
def test_check_file_title_mismatch():
|
|
@@ -49,8 +299,7 @@ def test_check_file_value_error():
|
|
|
49
299
|
|
|
50
300
|
def test_check_file_assertion_error():
|
|
51
301
|
mock_artefact_class = MagicMock()
|
|
52
|
-
mock_artefact_class.deserialize.side_effect = AssertionError(
|
|
53
|
-
"Assertion error")
|
|
302
|
+
mock_artefact_class.deserialize.side_effect = AssertionError("Assertion error")
|
|
54
303
|
|
|
55
304
|
with patch("builtins.open", mock_open(read_data="invalid content")):
|
|
56
305
|
is_valid, reason = check_file("dummy_path", mock_artefact_class)
|
|
@@ -76,36 +325,46 @@ def test_check_file_unexpected_error():
|
|
|
76
325
|
assert is_valid is False
|
|
77
326
|
assert "Unexpected error: Exception('Unexpected error')" in reason
|
|
78
327
|
|
|
328
|
+
|
|
79
329
|
# Tests for find_invalid_files
|
|
80
330
|
|
|
81
331
|
|
|
82
332
|
def test_find_invalid_files():
|
|
333
|
+
"""Tests finding invalid files with proper mocking of check_file."""
|
|
83
334
|
mock_artefact_class = MagicMock()
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
335
|
+
classified_info = {
|
|
336
|
+
"test_classifier": [
|
|
337
|
+
{"file_path": "file1.txt"}, # Should be checked
|
|
338
|
+
{"file_path": "file2.txt"}, # Should be checked
|
|
339
|
+
{"file_path": "templates/file3.txt"}, # Should be skipped
|
|
340
|
+
{"file_path": "some/path/file.data"}, # Should be skipped
|
|
341
|
+
]
|
|
342
|
+
}
|
|
93
343
|
|
|
344
|
+
with patch(
|
|
345
|
+
"ara_cli.artefact_models.artefact_mapping.artefact_type_mapping",
|
|
346
|
+
{"test_classifier": mock_artefact_class},
|
|
347
|
+
):
|
|
94
348
|
with patch("ara_cli.artefact_scan.check_file") as mock_check_file:
|
|
95
349
|
mock_check_file.side_effect = [
|
|
96
|
-
(True, None),
|
|
97
|
-
(False, "Invalid content")
|
|
350
|
+
(True, None), # for file1.txt
|
|
351
|
+
(False, "Invalid content"), # for file2.txt
|
|
98
352
|
]
|
|
99
353
|
|
|
100
|
-
invalid_files = find_invalid_files(
|
|
101
|
-
|
|
354
|
+
invalid_files = find_invalid_files(classified_info, "test_classifier")
|
|
355
|
+
|
|
102
356
|
assert len(invalid_files) == 1
|
|
103
357
|
assert invalid_files[0] == ("file2.txt", "Invalid content")
|
|
104
358
|
assert mock_check_file.call_count == 2
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
359
|
+
|
|
360
|
+
# Check that check_file was called with the correct parameters
|
|
361
|
+
mock_check_file.assert_has_calls(
|
|
362
|
+
[
|
|
363
|
+
call("file1.txt", mock_artefact_class, classified_info),
|
|
364
|
+
call("file2.txt", mock_artefact_class, classified_info),
|
|
365
|
+
],
|
|
366
|
+
any_order=False,
|
|
367
|
+
)
|
|
109
368
|
|
|
110
369
|
|
|
111
370
|
def test_show_results_no_issues(capsys):
|
|
@@ -114,18 +373,20 @@ def test_show_results_no_issues(capsys):
|
|
|
114
373
|
show_results(invalid_artefacts)
|
|
115
374
|
captured = capsys.readouterr()
|
|
116
375
|
assert captured.out == "All files are good!\n"
|
|
117
|
-
m.assert_called_once_with(
|
|
376
|
+
m.assert_called_once_with(
|
|
377
|
+
"incompatible_artefacts_report.md", "w", encoding="utf-8"
|
|
378
|
+
)
|
|
118
379
|
handle = m()
|
|
119
|
-
handle.write.assert_has_calls(
|
|
120
|
-
call("# Artefact Check Report\n\n"),
|
|
121
|
-
|
|
122
|
-
|
|
380
|
+
handle.write.assert_has_calls(
|
|
381
|
+
[call("# Artefact Check Report\n\n"), call("No problems found.\n")],
|
|
382
|
+
any_order=False,
|
|
383
|
+
)
|
|
123
384
|
|
|
124
385
|
|
|
125
386
|
def test_show_results_with_issues(capsys):
|
|
126
387
|
invalid_artefacts = {
|
|
127
388
|
"classifier1": [("file1.txt", "reason1"), ("file2.txt", "reason2")],
|
|
128
|
-
"classifier2": [("file3.txt", "reason3")]
|
|
389
|
+
"classifier2": [("file3.txt", "reason3")],
|
|
129
390
|
}
|
|
130
391
|
with patch("builtins.open", mock_open()) as m:
|
|
131
392
|
show_results(invalid_artefacts)
|
|
@@ -141,7 +402,9 @@ def test_show_results_with_issues(capsys):
|
|
|
141
402
|
"\t\treason3\n"
|
|
142
403
|
)
|
|
143
404
|
assert captured.out == expected_output
|
|
144
|
-
m.assert_called_once_with(
|
|
405
|
+
m.assert_called_once_with(
|
|
406
|
+
"incompatible_artefacts_report.md", "w", encoding="utf-8"
|
|
407
|
+
)
|
|
145
408
|
handle = m()
|
|
146
409
|
expected_writes = [
|
|
147
410
|
call("# Artefact Check Report\n\n"),
|
|
@@ -151,6 +414,37 @@ def test_show_results_with_issues(capsys):
|
|
|
151
414
|
call("\n"),
|
|
152
415
|
call("## classifier2\n"),
|
|
153
416
|
call("- `file3.txt`: reason3\n"),
|
|
154
|
-
call("\n")
|
|
417
|
+
call("\n"),
|
|
155
418
|
]
|
|
156
|
-
handle.write.assert_has_calls(expected_writes, any_order=False)
|
|
419
|
+
handle.write.assert_has_calls(expected_writes, any_order=False)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def test_check_file_with_invalid_contribution():
|
|
423
|
+
"""Tests file with invalid contribution reference."""
|
|
424
|
+
mock_artefact_instance = MagicMock()
|
|
425
|
+
mock_artefact_instance.title = "dummy_path"
|
|
426
|
+
|
|
427
|
+
# Set up invalid contribution
|
|
428
|
+
mock_contribution = MagicMock()
|
|
429
|
+
mock_contribution.classifier = "test_classifier"
|
|
430
|
+
mock_contribution.artefact_name = "non_existing_artefact"
|
|
431
|
+
mock_artefact_instance.contribution = mock_contribution
|
|
432
|
+
|
|
433
|
+
mock_artefact_class = MagicMock()
|
|
434
|
+
mock_artefact_class.deserialize.return_value = mock_artefact_instance
|
|
435
|
+
|
|
436
|
+
# Mock classified_artefact_info
|
|
437
|
+
classified_info = {"test_classifier": [{"name": "existing_artefact"}]}
|
|
438
|
+
|
|
439
|
+
# Mock extract_artefact_names_of_classifier to return a list without the referenced artefact
|
|
440
|
+
with patch("builtins.open", mock_open(read_data="valid content")):
|
|
441
|
+
with patch(
|
|
442
|
+
"ara_cli.artefact_fuzzy_search.extract_artefact_names_of_classifier",
|
|
443
|
+
return_value=["existing_artefact"],
|
|
444
|
+
):
|
|
445
|
+
is_valid, reason = check_file(
|
|
446
|
+
"dummy_path.feature", mock_artefact_class, classified_info
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
assert is_valid is False
|
|
450
|
+
assert "Invalid Contribution Reference" in reason
|