ara-cli 0.1.10.5__py3-none-any.whl → 0.1.14.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.
Files changed (151) hide show
  1. ara_cli/__init__.py +51 -6
  2. ara_cli/__main__.py +87 -75
  3. ara_cli/ara_command_action.py +189 -101
  4. ara_cli/ara_config.py +187 -128
  5. ara_cli/ara_subcommands/common.py +2 -2
  6. ara_cli/ara_subcommands/config.py +221 -0
  7. ara_cli/ara_subcommands/convert.py +107 -0
  8. ara_cli/ara_subcommands/fetch.py +41 -0
  9. ara_cli/ara_subcommands/fetch_agents.py +22 -0
  10. ara_cli/ara_subcommands/fetch_scripts.py +19 -0
  11. ara_cli/ara_subcommands/fetch_templates.py +15 -10
  12. ara_cli/ara_subcommands/list.py +97 -23
  13. ara_cli/ara_subcommands/prompt.py +266 -106
  14. ara_cli/artefact_autofix.py +117 -64
  15. ara_cli/artefact_converter.py +355 -0
  16. ara_cli/artefact_creator.py +41 -17
  17. ara_cli/artefact_lister.py +3 -3
  18. ara_cli/artefact_models/artefact_model.py +1 -1
  19. ara_cli/artefact_models/artefact_templates.py +0 -9
  20. ara_cli/artefact_models/feature_artefact_model.py +8 -8
  21. ara_cli/artefact_reader.py +62 -43
  22. ara_cli/artefact_scan.py +39 -17
  23. ara_cli/chat.py +300 -71
  24. ara_cli/chat_agent/__init__.py +0 -0
  25. ara_cli/chat_agent/agent_process_manager.py +155 -0
  26. ara_cli/chat_script_runner/__init__.py +0 -0
  27. ara_cli/chat_script_runner/script_completer.py +23 -0
  28. ara_cli/chat_script_runner/script_finder.py +41 -0
  29. ara_cli/chat_script_runner/script_lister.py +36 -0
  30. ara_cli/chat_script_runner/script_runner.py +36 -0
  31. ara_cli/chat_web_search/__init__.py +0 -0
  32. ara_cli/chat_web_search/web_search.py +263 -0
  33. ara_cli/children_contribution_updater.py +737 -0
  34. ara_cli/classifier.py +34 -0
  35. ara_cli/commands/agent_run_command.py +98 -0
  36. ara_cli/commands/fetch_agents_command.py +106 -0
  37. ara_cli/commands/fetch_scripts_command.py +43 -0
  38. ara_cli/commands/fetch_templates_command.py +39 -0
  39. ara_cli/commands/fetch_templates_commands.py +39 -0
  40. ara_cli/commands/list_agents_command.py +39 -0
  41. ara_cli/commands/load_command.py +4 -3
  42. ara_cli/commands/load_image_command.py +1 -1
  43. ara_cli/commands/read_command.py +23 -27
  44. ara_cli/completers.py +95 -35
  45. ara_cli/constants.py +2 -0
  46. ara_cli/directory_navigator.py +37 -4
  47. ara_cli/error_handler.py +26 -11
  48. ara_cli/file_loaders/document_reader.py +0 -178
  49. ara_cli/file_loaders/factories/__init__.py +0 -0
  50. ara_cli/file_loaders/factories/document_reader_factory.py +32 -0
  51. ara_cli/file_loaders/factories/file_loader_factory.py +27 -0
  52. ara_cli/file_loaders/file_loader.py +1 -30
  53. ara_cli/file_loaders/loaders/__init__.py +0 -0
  54. ara_cli/file_loaders/{document_file_loader.py → loaders/document_file_loader.py} +1 -1
  55. ara_cli/file_loaders/loaders/text_file_loader.py +47 -0
  56. ara_cli/file_loaders/readers/__init__.py +0 -0
  57. ara_cli/file_loaders/readers/docx_reader.py +49 -0
  58. ara_cli/file_loaders/readers/excel_reader.py +27 -0
  59. ara_cli/file_loaders/{markdown_reader.py → readers/markdown_reader.py} +1 -1
  60. ara_cli/file_loaders/readers/odt_reader.py +59 -0
  61. ara_cli/file_loaders/readers/pdf_reader.py +54 -0
  62. ara_cli/file_loaders/readers/pptx_reader.py +104 -0
  63. ara_cli/file_loaders/tools/__init__.py +0 -0
  64. ara_cli/llm_utils.py +58 -0
  65. ara_cli/output_suppressor.py +53 -0
  66. ara_cli/prompt_chat.py +20 -4
  67. ara_cli/prompt_extractor.py +47 -32
  68. ara_cli/prompt_handler.py +123 -17
  69. ara_cli/tag_extractor.py +8 -7
  70. ara_cli/template_loader.py +2 -1
  71. ara_cli/template_manager.py +52 -21
  72. ara_cli/templates/global-scripts/hello_global.py +1 -0
  73. ara_cli/templates/prompt-modules/commands/add_scenarios_for_new_behaviour.feature_creation_agent.commands.md +1 -0
  74. ara_cli/templates/prompt-modules/commands/align_feature_with_implementation_changes.interview_agent.commands.md +1 -0
  75. ara_cli/templates/prompt-modules/commands/analyze_codebase_and_plan_tasks.interview_agent.commands.md +1 -0
  76. ara_cli/templates/prompt-modules/commands/choose_best_parent_artefact.interview_agent.commands.md +1 -0
  77. ara_cli/templates/prompt-modules/commands/create_tasks_from_artefact_content.interview_agent.commands.md +1 -0
  78. ara_cli/templates/prompt-modules/commands/create_tests_for_uncovered_modules.test_generation_agent.commands.md +1 -0
  79. ara_cli/templates/prompt-modules/commands/derive_features_from_video_description.feature_creation_agent.commands.md +1 -0
  80. ara_cli/templates/prompt-modules/commands/describe_agent_capabilities.agent.commands.md +1 -0
  81. ara_cli/templates/prompt-modules/commands/empty.commands.md +2 -12
  82. ara_cli/templates/prompt-modules/commands/execute_scoped_todos_in_task.interview_agent.commands.md +1 -0
  83. ara_cli/templates/prompt-modules/commands/explain_single_file_purpose.interview_agent.commands.md +1 -0
  84. ara_cli/templates/prompt-modules/commands/extract_file_information_bullets.interview_agent.commands.md +1 -0
  85. ara_cli/templates/prompt-modules/commands/extract_general.commands.md +12 -0
  86. ara_cli/templates/prompt-modules/commands/extract_markdown.commands.md +11 -0
  87. ara_cli/templates/prompt-modules/commands/extract_python.commands.md +13 -0
  88. ara_cli/templates/prompt-modules/commands/feature_add_or_modifiy_specified_behavior.commands.md +36 -0
  89. ara_cli/templates/prompt-modules/commands/feature_generate_initial_specified_bevahior.commands.md +53 -0
  90. ara_cli/templates/prompt-modules/commands/fix_failing_behave_step_definitions.interview_agent.commands.md +1 -0
  91. ara_cli/templates/prompt-modules/commands/fix_failing_pytest_tests.interview_agent.commands.md +1 -0
  92. ara_cli/templates/prompt-modules/commands/general_instruction_policy.commands.md +47 -0
  93. ara_cli/templates/prompt-modules/commands/generate_and_fix_pytest_tests.test_generation_agent.commands.md +1 -0
  94. ara_cli/templates/prompt-modules/commands/prompt_template_tech_stack_transformer.commands.md +95 -0
  95. ara_cli/templates/prompt-modules/commands/python_bug_fixing_code.commands.md +34 -0
  96. ara_cli/templates/prompt-modules/commands/python_generate_code.commands.md +27 -0
  97. ara_cli/templates/prompt-modules/commands/python_refactoring_code.commands.md +39 -0
  98. ara_cli/templates/prompt-modules/commands/python_step_definitions_generation_and_fixing.commands.md +40 -0
  99. ara_cli/templates/prompt-modules/commands/python_unittest_generation_and_fixing.commands.md +48 -0
  100. ara_cli/templates/prompt-modules/commands/suggest_next_story_child_tasks.interview_agent.commands.md +1 -0
  101. ara_cli/templates/prompt-modules/commands/summarize_or_transcribe_media.interview_agent.commands.md +1 -0
  102. ara_cli/templates/prompt-modules/commands/update_feature_to_match_implementation.feature_creation_agent.commands.md +1 -0
  103. ara_cli/templates/prompt-modules/commands/update_user_story_with_requirements.interview_agent.commands.md +1 -0
  104. ara_cli/version.py +1 -1
  105. {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/METADATA +49 -11
  106. ara_cli-0.1.14.0.dist-info/RECORD +253 -0
  107. {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/WHEEL +1 -1
  108. tests/test_ara_command_action.py +31 -19
  109. tests/test_ara_config.py +177 -90
  110. tests/test_artefact_autofix.py +170 -97
  111. tests/test_artefact_autofix_integration.py +495 -0
  112. tests/test_artefact_converter.py +312 -0
  113. tests/test_artefact_extraction.py +564 -0
  114. tests/test_artefact_lister.py +11 -8
  115. tests/test_chat.py +166 -130
  116. tests/test_chat_givens_images.py +603 -0
  117. tests/test_chat_script_runner.py +454 -0
  118. tests/test_children_contribution_updater.py +98 -0
  119. tests/test_document_loader_office.py +267 -0
  120. tests/test_llm_utils.py +164 -0
  121. tests/test_prompt_chat.py +343 -0
  122. tests/test_prompt_extractor.py +683 -0
  123. tests/test_prompt_handler.py +416 -214
  124. tests/test_setup_default_chat_prompt_mode.py +198 -0
  125. tests/test_tag_extractor.py +95 -49
  126. tests/test_web_search.py +467 -0
  127. ara_cli/file_loaders/document_readers.py +0 -233
  128. ara_cli/file_loaders/file_loaders.py +0 -123
  129. ara_cli/file_loaders/text_file_loader.py +0 -187
  130. ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +0 -27
  131. ara_cli/templates/prompt-modules/blueprints/pytest_unittest_prompt.blueprint.md +0 -32
  132. ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md +0 -30
  133. ara_cli/templates/prompt-modules/commands/artefact_classification.commands.md +0 -9
  134. ara_cli/templates/prompt-modules/commands/artefact_extension.commands.md +0 -17
  135. ara_cli/templates/prompt-modules/commands/artefact_formulation.commands.md +0 -14
  136. ara_cli/templates/prompt-modules/commands/behave_step_generation.commands.md +0 -102
  137. ara_cli/templates/prompt-modules/commands/code_generation_complex.commands.md +0 -20
  138. ara_cli/templates/prompt-modules/commands/code_generation_simple.commands.md +0 -13
  139. ara_cli/templates/prompt-modules/commands/error_fixing.commands.md +0 -20
  140. ara_cli/templates/prompt-modules/commands/feature_file_update.commands.md +0 -18
  141. ara_cli/templates/prompt-modules/commands/feature_formulation.commands.md +0 -43
  142. ara_cli/templates/prompt-modules/commands/js_code_generation_simple.commands.md +0 -13
  143. ara_cli/templates/prompt-modules/commands/refactoring.commands.md +0 -15
  144. ara_cli/templates/prompt-modules/commands/refactoring_analysis.commands.md +0 -9
  145. ara_cli/templates/prompt-modules/commands/reverse_engineer_feature_file.commands.md +0 -15
  146. ara_cli/templates/prompt-modules/commands/reverse_engineer_program_flow.commands.md +0 -19
  147. ara_cli-0.1.10.5.dist-info/RECORD +0 -194
  148. /ara_cli/file_loaders/{binary_file_loader.py → loaders/binary_file_loader.py} +0 -0
  149. /ara_cli/file_loaders/{image_processor.py → tools/image_processor.py} +0 -0
  150. {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/entry_points.txt +0 -0
  151. {ara_cli-0.1.10.5.dist-info → ara_cli-0.1.14.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,198 @@
1
+ import os
2
+ import tempfile
3
+ from unittest.mock import patch, MagicMock
4
+ import pytest
5
+ from ara_cli.prompt_chat import initialize_prompt_chat_mode
6
+ from ara_cli.classifier import Classifier
7
+
8
+
9
+ class TestSetupDefaultCombinedChatPromptMode:
10
+ """
11
+ Tests mirroring the scenarios in Setup_Default_Combined_Chat_Prompt_Mode.feature.
12
+ """
13
+
14
+ @pytest.fixture
15
+ def setup_ara_environment(self):
16
+ """Sets up a temporary directory structure mimicking the ara project."""
17
+ with tempfile.TemporaryDirectory() as tmpdir:
18
+ # Change to tmpdir to ensure relative paths work if used
19
+ cwd = os.getcwd()
20
+ os.chdir(tmpdir)
21
+
22
+ # Setup base directories
23
+ os.makedirs(os.path.join(tmpdir, "ara", "tasks"), exist_ok=True)
24
+
25
+ yield tmpdir
26
+
27
+ os.chdir(cwd)
28
+
29
+ @patch("ara_cli.prompt_chat.update_artefact_config_prompt_files")
30
+ @patch("ara_cli.chat.Chat.start", autospec=True)
31
+ @patch("ara_cli.chat.Chat.start_non_interactive", autospec=True)
32
+ @patch("ara_cli.prompt_handler.ConfigManager.get_config")
33
+ def test_scenario_1_start_prompt_chat_no_existing_file(
34
+ self,
35
+ mock_get_config,
36
+ mock_start_non_interactive,
37
+ mock_start,
38
+ mock_update_config,
39
+ setup_ara_environment,
40
+ ):
41
+ """
42
+ Scenario: Start prompt-chat mode with existing prompt.data directory and no existing default chat file.
43
+ Expectation: task_chat.md is created.
44
+ """
45
+ root_dir = setup_ara_environment
46
+ task_name = "123_chat_test"
47
+ classifier = "task"
48
+
49
+ # Mock config to avoid loading real config
50
+ mock_config = MagicMock()
51
+ mock_config.llm_config = [{"provider": "openai", "model": "gpt-4"}]
52
+ mock_get_config.return_value = mock_config
53
+
54
+ # Simulate directory creation normally handled by update_artefact_config_prompt_files
55
+ data_dir = os.path.join(root_dir, "ara", "tasks", f"{task_name}.data")
56
+ os.makedirs(data_dir, exist_ok=True)
57
+
58
+ # Execute
59
+ initialize_prompt_chat_mode(
60
+ classifier=classifier,
61
+ param=task_name,
62
+ chat_name=None, # Default to classifier name 'task' -> 'task_chat.md'
63
+ reset=None,
64
+ )
65
+
66
+ # check paths
67
+ # Classifier.get_sub_directory('task') -> 'tasks'
68
+ # Path: ara/tasks/123_chat_test.data/task_chat.md (Chat adds _chat.md suffix if missing)
69
+ expected_chat_path = os.path.join(
70
+ root_dir, "ara", "tasks", f"{task_name}.data", "task_chat.md"
71
+ )
72
+
73
+ assert os.path.exists(
74
+ expected_chat_path
75
+ ), f"Chat file not created at {expected_chat_path}"
76
+
77
+ with open(expected_chat_path, "r") as f:
78
+ content = f.read()
79
+ assert "# ara prompt:" in content
80
+
81
+ # Verify update config called
82
+ mock_update_config.assert_called_once()
83
+
84
+ @patch("ara_cli.prompt_chat.update_artefact_config_prompt_files")
85
+ @patch("ara_cli.chat.Chat.start", autospec=True)
86
+ @patch("ara_cli.chat.Chat.start_non_interactive", autospec=True)
87
+ @patch("ara_cli.prompt_handler.ConfigManager.get_config")
88
+ @patch("sys.stdin.readline", return_value="y\n") # Simulate user typing 'y'
89
+ @patch("sys.stdout.write") # Capture stdout to check prompt
90
+ def test_scenario_2_reset_existing_chat(
91
+ self,
92
+ mock_stdout,
93
+ mock_stdin,
94
+ mock_get_config,
95
+ mock_start_non_interactive,
96
+ mock_start,
97
+ mock_update_config,
98
+ setup_ara_environment,
99
+ ):
100
+ """
101
+ Scenario: Start prompt-chat mode with existing chat file, choose to reset.
102
+ Expectation: User prompted, file content reset.
103
+ """
104
+ root_dir = setup_ara_environment
105
+ task_name = "123_chat_test"
106
+ classifier = "task"
107
+
108
+ # Setup existing file
109
+ data_dir = os.path.join(root_dir, "ara", "tasks", f"{task_name}.data")
110
+ os.makedirs(data_dir, exist_ok=True)
111
+ chat_path = os.path.join(data_dir, "task_chat.md")
112
+
113
+ with open(chat_path, "w") as f:
114
+ f.write("# ara prompt:\nOld Content")
115
+
116
+ # Mock config
117
+ mock_config = MagicMock()
118
+ mock_config.llm_config = [{"provider": "openai", "model": "gpt-4"}]
119
+ mock_get_config.return_value = mock_config
120
+
121
+ # Execute
122
+ initialize_prompt_chat_mode(
123
+ classifier=classifier,
124
+ param=task_name,
125
+ chat_name=None,
126
+ reset=None, # Should trigger interactive prompt
127
+ )
128
+
129
+ # Verify prompt was printed
130
+ # Note: sys.stdout.write is called by print()
131
+ # We check if any call args contained the prompt string
132
+ prompt_found = False
133
+ for call in mock_stdout.call_args_list:
134
+ if (
135
+ call.args
136
+ and "already exists. Do you want to reset the chat?" in call.args[0]
137
+ ):
138
+ prompt_found = True
139
+ break
140
+ # Alternatively, 'print' might use the buffer directly, but patching sys.stdout should catch it if flush=True/end="" usage in chat.py matches.
141
+ # chat.py: print(f"{chat_file_short} already exists. Do you want to reset the chat? (y/N): ", end="", flush=True)
142
+
143
+ # Since 'print' with end="" calls stdout.write, this should work.
144
+ # However, verifying strict output in mock might be tricky if not captured perfectly.
145
+ # Focusing on the RESULT (file reset) is most important for Scenario logic.
146
+
147
+ with open(chat_path, "r") as f:
148
+ content = f.read()
149
+
150
+ assert content == "# ara prompt:\n", "Chat file should have been reset"
151
+ assert "Old Content" not in content
152
+
153
+ @patch("ara_cli.prompt_chat.update_artefact_config_prompt_files")
154
+ @patch("ara_cli.chat.Chat.start", autospec=True)
155
+ @patch("ara_cli.chat.Chat.start_non_interactive", autospec=True)
156
+ @patch("ara_cli.prompt_handler.ConfigManager.get_config")
157
+ @patch("sys.stdin.readline", return_value="n\n") # Simulate user typing 'n'
158
+ def test_scenario_3_append_existing_chat(
159
+ self,
160
+ mock_stdin,
161
+ mock_get_config,
162
+ mock_start_non_interactive,
163
+ mock_start,
164
+ mock_update_config,
165
+ setup_ara_environment,
166
+ ):
167
+ """
168
+ Scenario: Start prompt-chat mode with existing chat file, choose to append.
169
+ Expectation: File content preserved.
170
+ """
171
+ root_dir = setup_ara_environment
172
+ task_name = "123_chat_test"
173
+ classifier = "task"
174
+
175
+ # Setup existing file
176
+ data_dir = os.path.join(root_dir, "ara", "tasks", f"{task_name}.data")
177
+ os.makedirs(data_dir, exist_ok=True)
178
+ chat_path = os.path.join(data_dir, "task_chat.md")
179
+
180
+ original_content = "# ara prompt:\nOld Content"
181
+ with open(chat_path, "w") as f:
182
+ f.write(original_content)
183
+
184
+ # Mock config
185
+ mock_config = MagicMock()
186
+ mock_config.llm_config = [{"provider": "openai", "model": "gpt-4"}]
187
+ mock_get_config.return_value = mock_config
188
+
189
+ # Execute
190
+ initialize_prompt_chat_mode(
191
+ classifier=classifier, param=task_name, chat_name=None, reset=None
192
+ )
193
+
194
+ # Verify content preserved
195
+ with open(chat_path, "r") as f:
196
+ content = f.read()
197
+
198
+ assert content == original_content, "Chat file content should be preserved"
@@ -7,61 +7,107 @@ from ara_cli.list_filter import ListFilter
7
7
  @pytest.fixture
8
8
  def artefact():
9
9
  """Fixture to create a mock artefact object."""
10
+
10
11
  class Artefact:
11
- def __init__(self, tags, status, users, author="creator_unknown", path="dummy.md", content=""):
12
+ def __init__(
13
+ self,
14
+ tags,
15
+ status,
16
+ users,
17
+ author="creator_unknown",
18
+ path="dummy.md",
19
+ content="",
20
+ ):
12
21
  self.tags = tags
13
22
  self.status = status
14
23
  self.users = users
15
24
  self.author = author
16
25
  self.path = path
17
26
  self.content = content
27
+
18
28
  return Artefact
19
29
 
20
30
 
21
- @pytest.mark.parametrize("navigate_to_target, filtered_extra_column, list_filter, artefact_data, expected_tags", [
22
- (
23
- False, False, None,
24
- {'artefacts': [
25
- (['tag1', 'tag2'], 'in-progress', ['user1'], "creator_unknown"),
26
- (['tag3'], 'done', ['user2'], "creator_unknown")
27
- ]},
28
- ['creator_unknown', 'done', 'in-progress', 'tag1', 'tag2', 'tag3', 'user_user1', 'user_user2']
29
- ),
30
- (
31
- False, True, None,
32
- {'artefacts': [
33
- (['project_a', 'priority_high'], None, ['user1'], "creator_unknown"),
34
- (['feature_x'], 'done', ['user2'], "creator_unknown")
35
- ]},
36
- ['project_a']
37
- ),
38
- (
39
- False, False, ListFilter(include_tags=['kritik']),
40
- {'artefacts': [
41
- (['release', 'kritik'], 'review', ['dev1'], "creator_unknown"),
42
- (['bugfix'], 'to-do', ['dev2'], "creator_unknown")
43
- ]},
44
- ['creator_unknown', 'kritik', 'release', 'review', 'user_dev1']
45
- ),
46
- (
47
- True, False, None,
48
- {'artefacts': [
49
- (['tag3'], 'status2', ['user3'], "creator_unknown")
50
- ]},
51
- ['creator_unknown', 'status2', 'tag3', 'user_user3']
52
- ),
53
- (
54
- False, False, None,
55
- {'artefacts': []},
56
- []
57
- ),
58
- ])
59
- @patch('ara_cli.artefact_reader.ArtefactReader')
60
- @patch('ara_cli.template_manager.DirectoryNavigator')
61
- def test_extract_tags(mock_directory_navigator, mock_artefact_reader, artefact, navigate_to_target, filtered_extra_column, list_filter, artefact_data, expected_tags):
62
- mock_artefacts = {key: [artefact(
63
- *data) for data in artefact_list] for key, artefact_list in artefact_data.items()}
64
- mock_artefact_reader.read_artefacts.return_value = mock_artefacts
31
+ @pytest.mark.parametrize(
32
+ "navigate_to_target, filtered_extra_column, list_filter, artefact_data, expected_tags",
33
+ [
34
+ (
35
+ False,
36
+ False,
37
+ None,
38
+ {
39
+ "artefacts": [
40
+ (["tag1", "tag2"], "in-progress", ["user1"], "creator_unknown"),
41
+ (["tag3"], "done", ["user2"], "creator_unknown"),
42
+ ]
43
+ },
44
+ [
45
+ "creator_unknown",
46
+ "done",
47
+ "in-progress",
48
+ "tag1",
49
+ "tag2",
50
+ "tag3",
51
+ "user_user1",
52
+ "user_user2",
53
+ ],
54
+ ),
55
+ (
56
+ False,
57
+ True,
58
+ None,
59
+ {
60
+ "artefacts": [
61
+ (
62
+ ["project_a", "priority_high"],
63
+ None,
64
+ ["user1"],
65
+ "creator_unknown",
66
+ ),
67
+ (["feature_x"], "done", ["user2"], "creator_unknown"),
68
+ ]
69
+ },
70
+ ["project_a"],
71
+ ),
72
+ (
73
+ False,
74
+ False,
75
+ ListFilter(include_tags=["kritik"]),
76
+ {
77
+ "artefacts": [
78
+ (["release", "kritik"], "review", ["dev1"], "creator_unknown"),
79
+ (["bugfix"], "to-do", ["dev2"], "creator_unknown"),
80
+ ]
81
+ },
82
+ ["creator_unknown", "kritik", "release", "review", "user_dev1"],
83
+ ),
84
+ (
85
+ True,
86
+ False,
87
+ None,
88
+ {"artefacts": [(["tag3"], "status2", ["user3"], "creator_unknown")]},
89
+ ["creator_unknown", "status2", "tag3", "user_user3"],
90
+ ),
91
+ (False, False, None, {"artefacts": []}, []),
92
+ ],
93
+ )
94
+ @patch("ara_cli.artefact_reader.ArtefactReader")
95
+ @patch("ara_cli.template_manager.DirectoryNavigator")
96
+ def test_extract_tags(
97
+ mock_directory_navigator,
98
+ mock_artefact_reader,
99
+ artefact,
100
+ navigate_to_target,
101
+ filtered_extra_column,
102
+ list_filter,
103
+ artefact_data,
104
+ expected_tags,
105
+ ):
106
+ mock_artefacts = {
107
+ key: [artefact(*data) for data in artefact_list]
108
+ for key, artefact_list in artefact_data.items()
109
+ }
110
+ mock_artefact_reader.return_value.read_artefacts.return_value = mock_artefacts
65
111
 
66
112
  mock_navigator_instance = mock_directory_navigator.return_value
67
113
  mock_navigator_instance.navigate_to_target = MagicMock()
@@ -71,7 +117,7 @@ def test_extract_tags(mock_directory_navigator, mock_artefact_reader, artefact,
71
117
  result = tag_extractor.extract_tags(
72
118
  navigate_to_target=navigate_to_target,
73
119
  filtered_extra_column=filtered_extra_column,
74
- list_filter=list_filter
120
+ list_filter=list_filter,
75
121
  )
76
122
 
77
123
  if navigate_to_target:
@@ -79,11 +125,11 @@ def test_extract_tags(mock_directory_navigator, mock_artefact_reader, artefact,
79
125
  else:
80
126
  mock_navigator_instance.navigate_to_target.assert_not_called()
81
127
 
82
- mock_artefact_reader.read_artefacts.assert_called_once()
128
+ mock_artefact_reader.return_value.read_artefacts.assert_called_once()
83
129
 
84
130
  # Convert dictionary result to flat list for comparison
85
131
  actual_tags = []
86
132
  for group in result.values():
87
133
  actual_tags.extend(group)
88
-
89
- assert sorted(actual_tags) == sorted(expected_tags)
134
+
135
+ assert sorted(actual_tags) == sorted(expected_tags)