ara-cli 0.1.9.69__py3-none-any.whl → 0.1.9.71__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/ara_command_action.py +16 -12
- ara_cli/ara_config.py +24 -10
- ara_cli/artefact_autofix.py +278 -23
- ara_cli/artefact_creator.py +3 -3
- ara_cli/artefact_fuzzy_search.py +9 -4
- ara_cli/artefact_link_updater.py +4 -4
- ara_cli/artefact_models/artefact_model.py +14 -7
- ara_cli/artefact_models/artefact_templates.py +1 -1
- ara_cli/artefact_models/feature_artefact_model.py +72 -18
- ara_cli/artefact_models/serialize_helper.py +1 -1
- ara_cli/artefact_reader.py +16 -38
- ara_cli/artefact_renamer.py +2 -2
- ara_cli/artefact_scan.py +28 -3
- ara_cli/chat.py +1 -1
- ara_cli/file_classifier.py +3 -3
- ara_cli/file_lister.py +1 -1
- ara_cli/list_filter.py +1 -1
- ara_cli/output_suppressor.py +1 -1
- ara_cli/prompt_extractor.py +3 -3
- ara_cli/prompt_handler.py +9 -10
- ara_cli/prompt_rag.py +2 -2
- ara_cli/template_manager.py +2 -2
- ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md +1 -1
- ara_cli/update_config_prompt.py +2 -2
- ara_cli/version.py +1 -1
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.9.71.dist-info}/METADATA +1 -1
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.9.71.dist-info}/RECORD +39 -39
- tests/test_ara_command_action.py +7 -7
- tests/{test_ara_autofix.py → test_artefact_autofix.py} +163 -29
- tests/test_artefact_link_updater.py +3 -3
- tests/test_artefact_renamer.py +2 -2
- tests/test_artefact_scan.py +52 -19
- tests/test_file_classifier.py +1 -1
- tests/test_file_lister.py +1 -1
- tests/test_list_filter.py +2 -2
- tests/test_update_config_prompt.py +2 -2
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.9.71.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.9.71.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.69.dist-info → ara_cli-0.1.9.71.dist-info}/top_level.txt +0 -0
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
ara_cli/__init__.py,sha256=0zl7IegxTid26EBGLav_fXZ4CCIV3H5TfAoFQiOHjvg,148
|
|
2
2
|
ara_cli/__main__.py,sha256=Z6XYWRLceIoZPvfC-X9EXouSZdtFOOe84kKVWJGA4r4,1861
|
|
3
|
-
ara_cli/ara_command_action.py,sha256=
|
|
3
|
+
ara_cli/ara_command_action.py,sha256=dmv2xAUw3UXB1dMfeJ3ibFYJhGjBDbQdXrHRtx_whaM,21981
|
|
4
4
|
ara_cli/ara_command_parser.py,sha256=v8LUdkBSI2771gI53PdrxtD8YVjhk-7E8vgTEsTGnRM,17952
|
|
5
|
-
ara_cli/ara_config.py,sha256=
|
|
6
|
-
ara_cli/artefact_autofix.py,sha256
|
|
7
|
-
ara_cli/artefact_creator.py,sha256=
|
|
5
|
+
ara_cli/ara_config.py,sha256=xynwnCrlpBj20ozL7ra8siniNlfM4eh4OlOHi7fkDY8,4237
|
|
6
|
+
ara_cli/artefact_autofix.py,sha256=_xCAZFNZHJnIS95QCNxGPezrCBb9v8gIMn9_Ixjcj74,14876
|
|
7
|
+
ara_cli/artefact_creator.py,sha256=ysWtlYDbZf_k8ya7ZBXILP_PWZKIssAAJK8kak5mW-E,6056
|
|
8
8
|
ara_cli/artefact_deleter.py,sha256=Co4wwCH3yW8H9NrOq7_2p5571EeHr0TsfE-H8KqoOfY,1900
|
|
9
|
-
ara_cli/artefact_fuzzy_search.py,sha256=
|
|
10
|
-
ara_cli/artefact_link_updater.py,sha256=
|
|
9
|
+
ara_cli/artefact_fuzzy_search.py,sha256=iBlDqjZf-_D3VUjFf7ZwkiQbpQDcwRndIU7aG_sRTgE,2668
|
|
10
|
+
ara_cli/artefact_link_updater.py,sha256=nKdxTpDKqWTOAMD8viKmUaklSFGWzJZ8S8E8xW_ADuM,3775
|
|
11
11
|
ara_cli/artefact_lister.py,sha256=jhk4n4eqp7hDIq07q43QzS7-36BM3OfZ4EABxCeOGcw,4764
|
|
12
|
-
ara_cli/artefact_reader.py,sha256=
|
|
13
|
-
ara_cli/artefact_renamer.py,sha256=
|
|
14
|
-
ara_cli/artefact_scan.py,sha256=
|
|
15
|
-
ara_cli/chat.py,sha256=
|
|
12
|
+
ara_cli/artefact_reader.py,sha256=E6DMBvbOYf1OoLf-OyLaiB6K2-gd7iHmjoQZU9Rsy6g,6965
|
|
13
|
+
ara_cli/artefact_renamer.py,sha256=Hnz_3zD9xxnBa1FHyUE6mIktLk_9ttP2rFRvQIkmz-o,4061
|
|
14
|
+
ara_cli/artefact_scan.py,sha256=yg1ozwavWmqsrO9lx4bY3ggCooiPJ_DYQuZuJlFJdqc,3617
|
|
15
|
+
ara_cli/chat.py,sha256=Vv4tfzP203hCISd2Q0W0ZZ7ua7dk0jJ1qdl9NiHI5gM,28635
|
|
16
16
|
ara_cli/classifier.py,sha256=zWskj7rBYdqYBGjksBm46iTgVU5IIf2PZsJr4qeiwVU,1878
|
|
17
17
|
ara_cli/codefusionretriever.py,sha256=fCHgXdIBRzkVAnapX-KI2NQ44XbrrF4tEQmn5J6clUI,1980
|
|
18
18
|
ara_cli/codehierachieretriever.py,sha256=Xd3EgEWWhkSf1TmTWtf8X5_YvyE_4B66nRrqarwSiTU,1182
|
|
19
19
|
ara_cli/commandline_completer.py,sha256=b00Dqb5n7SecpxYIDLxAfYhp8X6e3c8a5qYz6ko0i3E,1192
|
|
20
20
|
ara_cli/directory_navigator.py,sha256=6QbSAjJrJ5a6Lutol9J4HFgVDMiAQ672ny9TATrh04U,3318
|
|
21
|
-
ara_cli/file_classifier.py,sha256=
|
|
22
|
-
ara_cli/file_lister.py,sha256=
|
|
21
|
+
ara_cli/file_classifier.py,sha256=A7wilPtIFm81iMgvqD0PjkOVL_QMUc9TB2w2Z9UcPcM,4001
|
|
22
|
+
ara_cli/file_lister.py,sha256=0C-j8IzajXo5qlvnuy5WFfe43ALwJ-0JFh2K6Xx2ccw,2332
|
|
23
23
|
ara_cli/filename_validator.py,sha256=Aw9PL8d5-Ymhp3EY6lDrUBk3cudaNqo1Uw5RzPpI1jA,118
|
|
24
|
-
ara_cli/list_filter.py,sha256=
|
|
25
|
-
ara_cli/output_suppressor.py,sha256=
|
|
24
|
+
ara_cli/list_filter.py,sha256=qKGwwQsrWe7L5FbdxEbBYD1bbbi8c-RMypjXqXvLbgs,5291
|
|
25
|
+
ara_cli/output_suppressor.py,sha256=nwiHaQLwabOjMoJOeUESBnZszGMxrQZfJ3N2OvahX7Y,389
|
|
26
26
|
ara_cli/prompt_chat.py,sha256=kd_OINDQFit6jN04bb7mzgY259JBbRaTaNp9F-webkc,1346
|
|
27
|
-
ara_cli/prompt_extractor.py,sha256=
|
|
28
|
-
ara_cli/prompt_handler.py,sha256=
|
|
29
|
-
ara_cli/prompt_rag.py,sha256=
|
|
27
|
+
ara_cli/prompt_extractor.py,sha256=6l1Or7wuFNUDqbMg-NDXpFX-WMi2XV7YGH6hGDvow2o,7557
|
|
28
|
+
ara_cli/prompt_handler.py,sha256=ukYWR_AMDd8nfGkeUKyYQ8PO_-PfO8x9tV1kNcNWOT4,17672
|
|
29
|
+
ara_cli/prompt_rag.py,sha256=ydlhe4CUqz0jdzlY7jBbpKaf_5fjMrAZKnriKea3ZAg,7485
|
|
30
30
|
ara_cli/run_file_lister.py,sha256=XbrrDTJXp1LFGx9Lv91SNsEHZPP-PyEMBF_P4btjbDA,2360
|
|
31
31
|
ara_cli/tag_extractor.py,sha256=4krQyvmLR2ffhe7N7lWC7QjaxXcb90HaQdmjnBiD8ak,2523
|
|
32
|
-
ara_cli/template_manager.py,sha256=
|
|
33
|
-
ara_cli/update_config_prompt.py,sha256=
|
|
34
|
-
ara_cli/version.py,sha256=
|
|
32
|
+
ara_cli/template_manager.py,sha256=flMO3yXMUIgBxCgLdRtIhxezPDs5kfh3IASySSa1IKI,6669
|
|
33
|
+
ara_cli/update_config_prompt.py,sha256=Oy9vNTw6UhDohyTEfSKkqE5ifEMPlmWNYkKHgUrK_pY,4607
|
|
34
|
+
ara_cli/version.py,sha256=EyUSNmWg71ZqSwLCGsMkHZC9sx8se2ACVTOoCek_sn0,146
|
|
35
35
|
ara_cli/artefact_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
36
|
ara_cli/artefact_models/artefact_load.py,sha256=dNcwZDW2Dk0bts9YnPZ0ESmWD2NbsLIvl4Z-qQeGmTQ,401
|
|
37
37
|
ara_cli/artefact_models/artefact_mapping.py,sha256=8aD0spBjkJ8toMAmFawc6UTUxB6-tEEViZXv2I-r88Q,1874
|
|
38
|
-
ara_cli/artefact_models/artefact_model.py,sha256=
|
|
39
|
-
ara_cli/artefact_models/artefact_templates.py,sha256=
|
|
38
|
+
ara_cli/artefact_models/artefact_model.py,sha256=FSn_DBaqvcCpybsq0jzaQOinkGPqTVJ6MOSHY6lZtTg,14979
|
|
39
|
+
ara_cli/artefact_models/artefact_templates.py,sha256=kEBmxFfySgO8ISgMRLDKhBl-n8o1mi7p49-Pf686YU0,8345
|
|
40
40
|
ara_cli/artefact_models/businessgoal_artefact_model.py,sha256=jqYFMXjWle0YW9RvcFLDBAwy61bdT5VuDT_6lTOFzMw,4853
|
|
41
41
|
ara_cli/artefact_models/capability_artefact_model.py,sha256=SZqHx4O2mj4urn77Stnj4_Jxtlq3-LgBBU9SMkByppI,3079
|
|
42
42
|
ara_cli/artefact_models/epic_artefact_model.py,sha256=IadQWs6SWNcLgwvtOQWmYDyV9xLr3WwAsx-YMFan5fA,5765
|
|
43
43
|
ara_cli/artefact_models/example_artefact_model.py,sha256=UXrKbaPotg1jwcrVSdCeo-XH4tTD_-U1e3giaBn5_xg,1384
|
|
44
|
-
ara_cli/artefact_models/feature_artefact_model.py,sha256=
|
|
44
|
+
ara_cli/artefact_models/feature_artefact_model.py,sha256=JvgBKsiI1Y5Cs_0Ygn6lttJIjCpEC9XyZieDExUnsvg,18386
|
|
45
45
|
ara_cli/artefact_models/issue_artefact_model.py,sha256=v6CpKnkqiUh6Wch2kkEmyyW49c8ysdy1qz8l1Ft9uJA,2552
|
|
46
46
|
ara_cli/artefact_models/keyfeature_artefact_model.py,sha256=a3MyAiePN9n_GTN6QkTvamdsaorwVUff6w-9CdRZSlo,4243
|
|
47
|
-
ara_cli/artefact_models/serialize_helper.py,sha256=
|
|
47
|
+
ara_cli/artefact_models/serialize_helper.py,sha256=Wks30wy-UrwJURetydKykLgJkdGRgXFHkDT24vHe5tU,595
|
|
48
48
|
ara_cli/artefact_models/task_artefact_model.py,sha256=kHMw_Tr-Ud3EeHWpRWy4jI0xFnPzGZ-FT52c5rSrT1k,3558
|
|
49
49
|
ara_cli/artefact_models/userstory_artefact_model.py,sha256=u6G8wdeE2EpOsg1OPR-s8uShB4A77GfqN0vkSSuthFI,6582
|
|
50
50
|
ara_cli/artefact_models/vision_artefact_model.py,sha256=KcNE3QQjyT29ZMMhCQo4pOcXKTkI6pXLvyfqoN2kuUQ,5920
|
|
@@ -70,7 +70,7 @@ ara_cli/templates/template.userstory,sha256=x6fouctaYl6I9gAyR8KXLVXec7oUT4uFm4Ec
|
|
|
70
70
|
ara_cli/templates/template.userstory.prompt_log.md,sha256=Yp62iF7zDy2XNIwwJN35jKKSmezinK_JKbSvVuagtmA,205
|
|
71
71
|
ara_cli/templates/template.vision,sha256=FZYcXUZtFOLvk0H1UEMhrJrDWZnS2CSmDv9feMkyYjU,594
|
|
72
72
|
ara_cli/templates/template.vision.prompt_log.md,sha256=CAzBzj3O23CzrPIUq3xzpXGKn3_nAvyBLRUi-5Bnq_0,196
|
|
73
|
-
ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md,sha256=
|
|
73
|
+
ara_cli/templates/prompt-modules/blueprints/complete_pytest_unittest.blueprint.md,sha256=DtZsdfVDNy9_cGE_Nn_TE2T3oRwr27kecZchOp5uIG0,672
|
|
74
74
|
ara_cli/templates/prompt-modules/blueprints/empty.blueprint.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
75
75
|
ara_cli/templates/prompt-modules/blueprints/task_todo_list_C4_architecture_analysis.blueprint.md,sha256=jEZrZaVK_pkRhLp1SpTX3xR6BGXkox6NafXEjX_GDvM,3099
|
|
76
76
|
ara_cli/templates/prompt-modules/blueprints/task_todo_list_implement_feature_BDD_way.blueprint.md,sha256=EimfgzjhFIsZnJ0qMNbVlUQEU0vC9Sv1VupesLz7A1E,2088
|
|
@@ -132,27 +132,27 @@ ara_cli/templates/specification_breakdown_files/template.step.md,sha256=nzDRl9Xo
|
|
|
132
132
|
ara_cli/templates/specification_breakdown_files/template.technology.exploration.md,sha256=zQyiJcmbUfXdte-5uZwZUpT6ey0zwfZ00P4VwI97jQk,2274
|
|
133
133
|
ara_cli/templates/specification_breakdown_files/template.technology.md,sha256=bySiksz-8xtq0Nnj4svqe2MgUftWrVkbK9AcrDUE3KY,952
|
|
134
134
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
135
|
-
tests/
|
|
136
|
-
tests/test_ara_command_action.py,sha256=Y5MrG6VjXgebliKfdFaCaS8i3GoZCGSLpj3AWCbL5Lk,25695
|
|
135
|
+
tests/test_ara_command_action.py,sha256=JTLqXM9BSMlU33OQgrk_sZnoowFJZKZAx8q-st-wa34,25821
|
|
137
136
|
tests/test_ara_config.py,sha256=1LWby_iSestTIIqK-1clggL8kmbGGbtlYfsxAHaMMF8,2232
|
|
137
|
+
tests/test_artefact_autofix.py,sha256=0Y6z5EXTEDUbZb-xxWNhaVUKnhxVVS3w2YZWTvyvoZs,12103
|
|
138
138
|
tests/test_artefact_fuzzy_search.py,sha256=5Sh3_l9QK8-WHn6JpGPU1b6h4QEnl2JoMq1Tdp2cj1U,1261
|
|
139
|
-
tests/test_artefact_link_updater.py,sha256=
|
|
139
|
+
tests/test_artefact_link_updater.py,sha256=biqbEp2jCOz8giv72hu2P2hDfeJfJ9OrVGdAv5d9cK4,2191
|
|
140
140
|
tests/test_artefact_lister.py,sha256=VCEOCgDgnAOeUUgIoGAbWgz60hf9UT-tdHg18LGfB34,22656
|
|
141
141
|
tests/test_artefact_reader.py,sha256=660K-d8ed-j8hulsUB_7baPD2-hhbg9TffUR5yVc4Uo,927
|
|
142
|
-
tests/test_artefact_renamer.py,sha256=
|
|
143
|
-
tests/test_artefact_scan.py,sha256=
|
|
142
|
+
tests/test_artefact_renamer.py,sha256=lSnKCCfoFGgKhTdDZrEaeBq1xJAak1QoqH5aSeOe9Ro,3494
|
|
143
|
+
tests/test_artefact_scan.py,sha256=m1dws5d5m-dMnCn43BVhnNHHLU75zgVWaKIEK9y76fk,7512
|
|
144
144
|
tests/test_chat.py,sha256=-00mni6Kik_RO8BGUpWqaL4S0wt2MbUBi5jD06dSHJM,47538
|
|
145
145
|
tests/test_classifier.py,sha256=grYGPksydNdPsaEBQxYHZTuTdcJWz7VQtikCKA6BNaQ,1920
|
|
146
146
|
tests/test_directory_navigator.py,sha256=7G0MVrBbtBvbrFUpL0zb_9EkEWi1dulWuHsrQxMJxDY,140
|
|
147
|
-
tests/test_file_classifier.py,sha256=
|
|
147
|
+
tests/test_file_classifier.py,sha256=kLWPiePu3F5mkVuI_lK_2QlLh2kXD_Mt2K8KZZ1fAnA,10940
|
|
148
148
|
tests/test_file_creator.py,sha256=D3G7MbgE0m8JmZihxnTryxLco6iZdbV--2CGc0L20FM,2109
|
|
149
|
-
tests/test_file_lister.py,sha256=
|
|
150
|
-
tests/test_list_filter.py,sha256=
|
|
149
|
+
tests/test_file_lister.py,sha256=Q9HwhKKx540EPzTmfzOCnvtAgON0aMmpJE2eOe1J3EA,4324
|
|
150
|
+
tests/test_list_filter.py,sha256=fJA3d_SdaOAUkE7jn68MOVS0THXGghy1fye_64Zvo1U,7964
|
|
151
151
|
tests/test_tag_extractor.py,sha256=nSiAYlTKZ7TLAOtcJpwK5zTWHhFYU0tI5xKnivLc1dU,2712
|
|
152
152
|
tests/test_template_manager.py,sha256=q-LMHRG4rHkD6ON6YW4cpZxUx9hul6Or8wVVRC2kb-8,4099
|
|
153
|
-
tests/test_update_config_prompt.py,sha256=
|
|
154
|
-
ara_cli-0.1.9.
|
|
155
|
-
ara_cli-0.1.9.
|
|
156
|
-
ara_cli-0.1.9.
|
|
157
|
-
ara_cli-0.1.9.
|
|
158
|
-
ara_cli-0.1.9.
|
|
153
|
+
tests/test_update_config_prompt.py,sha256=xsqj1WTn4BsG5Q2t-sNPfu7EoMURFcS-hfb5VSXUnJc,6765
|
|
154
|
+
ara_cli-0.1.9.71.dist-info/METADATA,sha256=EloNN_cqYAUedL2f6JFADIE1mBXJSXD8nknW5Ggc9Y8,415
|
|
155
|
+
ara_cli-0.1.9.71.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
156
|
+
ara_cli-0.1.9.71.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
|
|
157
|
+
ara_cli-0.1.9.71.dist-info/top_level.txt,sha256=WM4cLHT5DYUaWzLtRj-gu3yVNFpGQ6lLRI3FMmC-38I,14
|
|
158
|
+
ara_cli-0.1.9.71.dist-info/RECORD,,
|
tests/test_ara_command_action.py
CHANGED
|
@@ -439,7 +439,7 @@ def read_user_action(args):
|
|
|
439
439
|
lambda x: x["title"] == artefact_name, artefact_info_dicts
|
|
440
440
|
))
|
|
441
441
|
|
|
442
|
-
with open(artefact_info["file_path"], 'r') as file:
|
|
442
|
+
with open(artefact_info["file_path"], 'r', encoding='utf-8') as file:
|
|
443
443
|
content = file.read()
|
|
444
444
|
artefact = artefact_from_content(content)
|
|
445
445
|
|
|
@@ -514,8 +514,8 @@ def test_set_status_action(classifier, artefact_name, artefact_names, new_status
|
|
|
514
514
|
|
|
515
515
|
# Verify the file was opened for reading and writing
|
|
516
516
|
expected_file_path = next(info["file_path"] for info in artefact_info_dicts if info["title"] == artefact_name)
|
|
517
|
-
mock_open.assert_any_call(expected_file_path, 'r')
|
|
518
|
-
mock_open.assert_any_call(expected_file_path, 'w')
|
|
517
|
+
mock_open.assert_any_call(expected_file_path, 'r', encoding='utf-8')
|
|
518
|
+
mock_open.assert_any_call(expected_file_path, 'w', encoding='utf-8')
|
|
519
519
|
|
|
520
520
|
# Verify the serialized content was written
|
|
521
521
|
mock_file_handle.__enter__.return_value.write.assert_called_once_with("serialized_content")
|
|
@@ -593,14 +593,14 @@ def test_set_user_action(
|
|
|
593
593
|
else:
|
|
594
594
|
# Should open the file and read content
|
|
595
595
|
expected_file_path = next(info["file_path"] for info in artefact_info_dicts if info["title"] == artefact_name)
|
|
596
|
-
mock_open.assert_any_call(expected_file_path, 'r')
|
|
596
|
+
mock_open.assert_any_call(expected_file_path, 'r', encoding='utf-8')
|
|
597
597
|
mock_artefact_from_content.assert_called_once_with(mock_file_content)
|
|
598
598
|
|
|
599
599
|
# Should set the users attribute on the artefact
|
|
600
600
|
assert mock_artefact.users == [new_user.lstrip('@') if new_user.startswith('@') else new_user]
|
|
601
601
|
|
|
602
602
|
# Should write the serialized content back to the file
|
|
603
|
-
mock_open.assert_any_call(expected_file_path, 'w')
|
|
603
|
+
mock_open.assert_any_call(expected_file_path, 'w', encoding='utf-8')
|
|
604
604
|
mock_file_handle.__enter__.return_value.write.assert_called_once_with("serialized_content")
|
|
605
605
|
|
|
606
606
|
# Should print a success message
|
|
@@ -655,7 +655,7 @@ def test_scan_action_with_issues(capsys):
|
|
|
655
655
|
"\t\treason1\n"
|
|
656
656
|
)
|
|
657
657
|
assert captured.out == expected_output
|
|
658
|
-
m.assert_called_once_with("incompatible_artefacts_report.md", "w")
|
|
658
|
+
m.assert_called_once_with("incompatible_artefacts_report.md", "w", encoding="utf-8")
|
|
659
659
|
handle = m()
|
|
660
660
|
expected_writes = [
|
|
661
661
|
call("# Artefact Check Report\n\n"),
|
|
@@ -684,7 +684,7 @@ def test_scan_action_all_good(capsys):
|
|
|
684
684
|
|
|
685
685
|
captured = capsys.readouterr()
|
|
686
686
|
assert captured.out == "All files are good!\n"
|
|
687
|
-
m.assert_called_once_with("incompatible_artefacts_report.md", "w")
|
|
687
|
+
m.assert_called_once_with("incompatible_artefacts_report.md", "w", encoding="utf-8")
|
|
688
688
|
handle = m()
|
|
689
689
|
handle.write.assert_has_calls([
|
|
690
690
|
call("# Artefact Check Report\n\n"),
|
|
@@ -9,10 +9,11 @@ from ara_cli.artefact_autofix import (
|
|
|
9
9
|
run_agent,
|
|
10
10
|
write_corrected_artefact,
|
|
11
11
|
construct_prompt,
|
|
12
|
-
fix_title_mismatch
|
|
12
|
+
fix_title_mismatch,
|
|
13
13
|
)
|
|
14
14
|
from ara_cli.artefact_models.artefact_model import ArtefactType
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
@pytest.fixture
|
|
17
18
|
def mock_artefact_type():
|
|
18
19
|
"""Provides a mock for the ArtefactType enum member."""
|
|
@@ -20,6 +21,7 @@ def mock_artefact_type():
|
|
|
20
21
|
mock_type.value = "feature"
|
|
21
22
|
return mock_type
|
|
22
23
|
|
|
24
|
+
|
|
23
25
|
@pytest.fixture
|
|
24
26
|
def mock_artefact_class():
|
|
25
27
|
"""Provides a mock for the Artefact class."""
|
|
@@ -30,13 +32,22 @@ def mock_artefact_class():
|
|
|
30
32
|
return mock_class
|
|
31
33
|
|
|
32
34
|
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def mock_classified_artefact_info():
|
|
37
|
+
"""Provides a mock for the classified artefact info dictionary."""
|
|
38
|
+
return MagicMock()
|
|
39
|
+
|
|
40
|
+
|
|
33
41
|
def test_read_report_file_success():
|
|
34
42
|
"""Tests successful reading of the report file."""
|
|
35
43
|
mock_content = "# Artefact Check Report\n- `file.feature`: reason"
|
|
36
44
|
with patch("builtins.open", mock_open(read_data=mock_content)) as m:
|
|
37
45
|
content = read_report_file()
|
|
38
46
|
assert content == mock_content
|
|
39
|
-
m.assert_called_once_with(
|
|
47
|
+
m.assert_called_once_with(
|
|
48
|
+
"incompatible_artefacts_report.md", "r", encoding="utf-8"
|
|
49
|
+
)
|
|
50
|
+
|
|
40
51
|
|
|
41
52
|
def test_read_report_file_not_found(capsys):
|
|
42
53
|
with patch("builtins.open", side_effect=OSError("File not found")):
|
|
@@ -44,28 +55,36 @@ def test_read_report_file_not_found(capsys):
|
|
|
44
55
|
assert content is None
|
|
45
56
|
assert "Artefact scan results file not found" in capsys.readouterr().out
|
|
46
57
|
|
|
58
|
+
|
|
47
59
|
def test_parse_report_with_issues():
|
|
48
|
-
content =
|
|
60
|
+
content = (
|
|
61
|
+
"# Artefact Check Report\n\n## feature\n- `path/to/file.feature`: A reason\n"
|
|
62
|
+
)
|
|
49
63
|
expected = {"feature": [("path/to/file.feature", "A reason")]}
|
|
50
64
|
assert parse_report(content) == expected
|
|
51
65
|
|
|
66
|
+
|
|
52
67
|
def test_parse_report_no_issues():
|
|
53
68
|
content = "# Artefact Check Report\n\nNo problems found.\n"
|
|
54
69
|
assert parse_report(content) == {}
|
|
55
70
|
|
|
71
|
+
|
|
56
72
|
def test_parse_report_invalid_format():
|
|
57
73
|
assert parse_report("This is not a valid report") == {}
|
|
58
74
|
|
|
75
|
+
|
|
59
76
|
def test_parse_report_invalid_line_format():
|
|
60
77
|
content = "# Artefact Check Report\n\n## feature\n- an invalid line\n"
|
|
61
78
|
assert parse_report(content) == {"feature": []}
|
|
62
79
|
|
|
80
|
+
|
|
63
81
|
def test_read_artefact_success():
|
|
64
82
|
mock_content = "Feature: My Feature"
|
|
65
83
|
with patch("builtins.open", mock_open(read_data=mock_content)) as m:
|
|
66
84
|
content = read_artefact("file.feature")
|
|
67
85
|
assert content == mock_content
|
|
68
|
-
m.assert_called_once_with("file.feature",
|
|
86
|
+
m.assert_called_once_with("file.feature", "r", encoding="utf-8")
|
|
87
|
+
|
|
69
88
|
|
|
70
89
|
def test_read_artefact_file_not_found(capsys):
|
|
71
90
|
with patch("builtins.open", side_effect=FileNotFoundError):
|
|
@@ -73,6 +92,7 @@ def test_read_artefact_file_not_found(capsys):
|
|
|
73
92
|
assert result is None
|
|
74
93
|
assert "File not found: nonexistent.feature" in capsys.readouterr().out
|
|
75
94
|
|
|
95
|
+
|
|
76
96
|
@patch("ara_cli.artefact_models.artefact_mapping.artefact_type_mapping")
|
|
77
97
|
def test_determine_artefact_type_and_class_no_class_found(mock_mapping, capsys):
|
|
78
98
|
mock_mapping.get.return_value = None
|
|
@@ -83,134 +103,248 @@ def test_determine_artefact_type_and_class_no_class_found(mock_mapping, capsys):
|
|
|
83
103
|
# The print statement inside the function is called before returning, so this check is valid.
|
|
84
104
|
assert "No artefact class found for" in capsys.readouterr().out
|
|
85
105
|
|
|
106
|
+
|
|
86
107
|
@patch("ara_cli.artefact_models.artefact_model.ArtefactType", side_effect=ValueError)
|
|
87
108
|
def test_determine_artefact_type_and_class_invalid(mock_artefact_type_enum, capsys):
|
|
88
|
-
artefact_type, artefact_class = determine_artefact_type_and_class(
|
|
109
|
+
artefact_type, artefact_class = determine_artefact_type_and_class(
|
|
110
|
+
"invalid_classifier"
|
|
111
|
+
)
|
|
89
112
|
assert artefact_type is None
|
|
90
113
|
assert artefact_class is None
|
|
91
114
|
assert "Invalid classifier: invalid_classifier" in capsys.readouterr().out
|
|
92
115
|
|
|
116
|
+
|
|
93
117
|
def test_write_corrected_artefact():
|
|
94
118
|
with patch("builtins.open", mock_open()) as m:
|
|
95
119
|
write_corrected_artefact("file.feature", "corrected content")
|
|
96
|
-
m.assert_called_once_with("file.feature",
|
|
120
|
+
m.assert_called_once_with("file.feature", "w", encoding="utf-8")
|
|
97
121
|
m().write.assert_called_once_with("corrected content")
|
|
98
122
|
|
|
123
|
+
|
|
99
124
|
def test_construct_prompt_for_task():
|
|
100
125
|
prompt = construct_prompt(ArtefactType.task, "some reason", "file.task", "text")
|
|
101
|
-
assert
|
|
126
|
+
assert (
|
|
127
|
+
"For task artefacts, if the action items looks like template or empty" in prompt
|
|
128
|
+
)
|
|
129
|
+
|
|
102
130
|
|
|
103
131
|
@patch("ara_cli.artefact_autofix.run_agent")
|
|
104
|
-
@patch(
|
|
132
|
+
@patch(
|
|
133
|
+
"ara_cli.artefact_autofix.determine_artefact_type_and_class",
|
|
134
|
+
return_value=(None, None),
|
|
135
|
+
)
|
|
105
136
|
@patch("ara_cli.artefact_autofix.read_artefact", return_value="original text")
|
|
106
|
-
def test_apply_autofix_exits_when_classifier_is_invalid(
|
|
137
|
+
def test_apply_autofix_exits_when_classifier_is_invalid(
|
|
138
|
+
mock_read, mock_determine, mock_run_agent, mock_classified_artefact_info
|
|
139
|
+
):
|
|
107
140
|
"""Tests that apply_autofix exits early if the classifier is invalid."""
|
|
108
|
-
result = apply_autofix(
|
|
141
|
+
result = apply_autofix(
|
|
142
|
+
"file.feature",
|
|
143
|
+
"invalid",
|
|
144
|
+
"reason",
|
|
145
|
+
deterministic=True,
|
|
146
|
+
non_deterministic=True,
|
|
147
|
+
classified_artefact_info=mock_classified_artefact_info,
|
|
148
|
+
)
|
|
109
149
|
assert result is False
|
|
110
150
|
mock_read.assert_called_once_with("file.feature")
|
|
111
151
|
mock_determine.assert_called_once_with("invalid")
|
|
112
152
|
mock_run_agent.assert_not_called()
|
|
113
153
|
|
|
154
|
+
|
|
114
155
|
@patch("ara_cli.artefact_autofix.run_agent")
|
|
115
156
|
@patch("ara_cli.artefact_autofix.write_corrected_artefact")
|
|
116
157
|
@patch("ara_cli.artefact_autofix.fix_title_mismatch", return_value="fixed text")
|
|
117
158
|
@patch("ara_cli.artefact_autofix.determine_artefact_type_and_class")
|
|
118
159
|
@patch("ara_cli.artefact_autofix.read_artefact", return_value="original text")
|
|
119
|
-
def test_apply_autofix_for_title_mismatch_with_deterministic_flag(
|
|
160
|
+
def test_apply_autofix_for_title_mismatch_with_deterministic_flag(
|
|
161
|
+
mock_read,
|
|
162
|
+
mock_determine,
|
|
163
|
+
mock_fix_title,
|
|
164
|
+
mock_write,
|
|
165
|
+
mock_run_agent,
|
|
166
|
+
mock_artefact_type,
|
|
167
|
+
mock_artefact_class,
|
|
168
|
+
mock_classified_artefact_info,
|
|
169
|
+
):
|
|
120
170
|
"""Tests that a deterministic fix is applied when the flag is True."""
|
|
121
171
|
mock_determine.return_value = (mock_artefact_type, mock_artefact_class)
|
|
122
172
|
reason = "Filename-Title Mismatch: some details"
|
|
123
|
-
|
|
124
|
-
result = apply_autofix(
|
|
173
|
+
|
|
174
|
+
result = apply_autofix(
|
|
175
|
+
"file.feature",
|
|
176
|
+
"feature",
|
|
177
|
+
reason,
|
|
178
|
+
deterministic=True,
|
|
179
|
+
non_deterministic=False,
|
|
180
|
+
classified_artefact_info=mock_classified_artefact_info,
|
|
181
|
+
)
|
|
125
182
|
|
|
126
183
|
assert result is True
|
|
127
|
-
mock_fix_title.assert_called_once_with(
|
|
184
|
+
mock_fix_title.assert_called_once_with(
|
|
185
|
+
file_path="file.feature",
|
|
186
|
+
artefact_text="original text",
|
|
187
|
+
artefact_class=mock_artefact_class,
|
|
188
|
+
classified_artefact_info=mock_classified_artefact_info,
|
|
189
|
+
)
|
|
128
190
|
mock_write.assert_called_once_with("file.feature", "fixed text")
|
|
129
191
|
mock_run_agent.assert_not_called()
|
|
130
192
|
|
|
193
|
+
|
|
131
194
|
@patch("ara_cli.artefact_autofix.run_agent")
|
|
132
195
|
@patch("ara_cli.artefact_autofix.write_corrected_artefact")
|
|
133
196
|
@patch("ara_cli.artefact_autofix.fix_title_mismatch")
|
|
134
197
|
@patch("ara_cli.artefact_autofix.determine_artefact_type_and_class")
|
|
135
198
|
@patch("ara_cli.artefact_autofix.read_artefact", return_value="original text")
|
|
136
|
-
def test_apply_autofix_skips_title_mismatch_without_deterministic_flag(
|
|
199
|
+
def test_apply_autofix_skips_title_mismatch_without_deterministic_flag(
|
|
200
|
+
mock_read,
|
|
201
|
+
mock_determine,
|
|
202
|
+
mock_fix_title,
|
|
203
|
+
mock_write,
|
|
204
|
+
mock_run_agent,
|
|
205
|
+
mock_artefact_type,
|
|
206
|
+
mock_artefact_class,
|
|
207
|
+
mock_classified_artefact_info,
|
|
208
|
+
):
|
|
137
209
|
"""Tests that a deterministic fix is skipped when the flag is False."""
|
|
138
210
|
mock_determine.return_value = (mock_artefact_type, mock_artefact_class)
|
|
139
211
|
reason = "Filename-Title Mismatch: some details"
|
|
140
|
-
|
|
141
|
-
result = apply_autofix(
|
|
212
|
+
|
|
213
|
+
result = apply_autofix(
|
|
214
|
+
"file.feature",
|
|
215
|
+
"feature",
|
|
216
|
+
reason,
|
|
217
|
+
deterministic=False,
|
|
218
|
+
non_deterministic=True,
|
|
219
|
+
classified_artefact_info=mock_classified_artefact_info,
|
|
220
|
+
)
|
|
142
221
|
|
|
143
222
|
assert result is False
|
|
144
223
|
mock_fix_title.assert_not_called()
|
|
145
224
|
mock_write.assert_not_called()
|
|
146
225
|
mock_run_agent.assert_not_called()
|
|
147
226
|
|
|
227
|
+
|
|
148
228
|
@patch("ara_cli.artefact_autofix.write_corrected_artefact")
|
|
149
229
|
@patch("ara_cli.artefact_autofix.run_agent")
|
|
150
230
|
@patch("ara_cli.artefact_autofix.determine_artefact_type_and_class")
|
|
151
231
|
@patch("ara_cli.artefact_autofix.read_artefact", return_value="original text")
|
|
152
|
-
def test_apply_autofix_for_llm_fix_with_non_deterministic_flag(
|
|
232
|
+
def test_apply_autofix_for_llm_fix_with_non_deterministic_flag(
|
|
233
|
+
mock_read,
|
|
234
|
+
mock_determine,
|
|
235
|
+
mock_run_agent,
|
|
236
|
+
mock_write,
|
|
237
|
+
mock_artefact_type,
|
|
238
|
+
mock_artefact_class,
|
|
239
|
+
mock_classified_artefact_info,
|
|
240
|
+
):
|
|
153
241
|
"""Tests that an LLM fix is applied when the non-deterministic flag is True."""
|
|
154
242
|
mock_determine.return_value = (mock_artefact_type, mock_artefact_class)
|
|
155
243
|
mock_run_agent.return_value = mock_artefact_class
|
|
156
244
|
reason = "Pydantic validation error"
|
|
157
245
|
|
|
158
|
-
result = apply_autofix(
|
|
246
|
+
result = apply_autofix(
|
|
247
|
+
"file.feature",
|
|
248
|
+
"feature",
|
|
249
|
+
reason,
|
|
250
|
+
deterministic=False,
|
|
251
|
+
non_deterministic=True,
|
|
252
|
+
classified_artefact_info=mock_classified_artefact_info,
|
|
253
|
+
)
|
|
159
254
|
|
|
160
255
|
assert result is True
|
|
161
256
|
mock_run_agent.assert_called_once()
|
|
162
257
|
mock_write.assert_called_once_with("file.feature", "llm corrected content")
|
|
163
258
|
|
|
259
|
+
|
|
164
260
|
@patch("ara_cli.artefact_autofix.write_corrected_artefact")
|
|
165
261
|
@patch("ara_cli.artefact_autofix.run_agent")
|
|
166
262
|
@patch("ara_cli.artefact_autofix.determine_artefact_type_and_class")
|
|
167
263
|
@patch("ara_cli.artefact_autofix.read_artefact", return_value="original text")
|
|
168
|
-
def test_apply_autofix_skips_llm_fix_without_non_deterministic_flag(
|
|
264
|
+
def test_apply_autofix_skips_llm_fix_without_non_deterministic_flag(
|
|
265
|
+
mock_read,
|
|
266
|
+
mock_determine,
|
|
267
|
+
mock_run_agent,
|
|
268
|
+
mock_write,
|
|
269
|
+
mock_artefact_type,
|
|
270
|
+
mock_artefact_class,
|
|
271
|
+
mock_classified_artefact_info,
|
|
272
|
+
):
|
|
169
273
|
"""Tests that an LLM fix is skipped when the non-deterministic flag is False."""
|
|
170
274
|
mock_determine.return_value = (mock_artefact_type, mock_artefact_class)
|
|
171
275
|
reason = "Pydantic validation error"
|
|
172
276
|
|
|
173
|
-
result = apply_autofix(
|
|
277
|
+
result = apply_autofix(
|
|
278
|
+
"file.feature",
|
|
279
|
+
"feature",
|
|
280
|
+
reason,
|
|
281
|
+
deterministic=True,
|
|
282
|
+
non_deterministic=False,
|
|
283
|
+
classified_artefact_info=mock_classified_artefact_info,
|
|
284
|
+
)
|
|
174
285
|
|
|
175
286
|
assert result is False
|
|
176
287
|
mock_run_agent.assert_not_called()
|
|
177
288
|
mock_write.assert_not_called()
|
|
178
289
|
|
|
290
|
+
|
|
179
291
|
@patch("ara_cli.artefact_autofix.run_agent", side_effect=Exception("LLM failed"))
|
|
180
292
|
@patch("ara_cli.artefact_autofix.determine_artefact_type_and_class")
|
|
181
293
|
@patch("ara_cli.artefact_autofix.read_artefact", return_value="original text")
|
|
182
|
-
def test_apply_autofix_llm_exception(
|
|
294
|
+
def test_apply_autofix_llm_exception(
|
|
295
|
+
mock_read,
|
|
296
|
+
mock_determine,
|
|
297
|
+
mock_run_agent,
|
|
298
|
+
capsys,
|
|
299
|
+
mock_artefact_type,
|
|
300
|
+
mock_artefact_class,
|
|
301
|
+
mock_classified_artefact_info,
|
|
302
|
+
):
|
|
183
303
|
"""Tests that an exception during an LLM fix is handled gracefully."""
|
|
184
304
|
mock_determine.return_value = (mock_artefact_type, mock_artefact_class)
|
|
185
305
|
reason = "Pydantic validation error"
|
|
186
306
|
|
|
187
|
-
result = apply_autofix(
|
|
307
|
+
result = apply_autofix(
|
|
308
|
+
"file.feature",
|
|
309
|
+
"feature",
|
|
310
|
+
reason,
|
|
311
|
+
deterministic=False,
|
|
312
|
+
non_deterministic=True,
|
|
313
|
+
classified_artefact_info=mock_classified_artefact_info,
|
|
314
|
+
)
|
|
188
315
|
|
|
189
316
|
assert result is False
|
|
190
|
-
assert
|
|
317
|
+
assert (
|
|
318
|
+
"LLM agent failed to fix artefact at file.feature: LLM failed"
|
|
319
|
+
in capsys.readouterr().out
|
|
320
|
+
)
|
|
321
|
+
|
|
191
322
|
|
|
192
323
|
# === Other Tests ===
|
|
193
324
|
|
|
325
|
+
|
|
194
326
|
def test_fix_title_mismatch_success(mock_artefact_class):
|
|
195
327
|
artefact_text = "Feature: wrong title\nSome other content"
|
|
196
328
|
file_path = "path/to/correct_title.feature"
|
|
197
|
-
|
|
329
|
+
|
|
198
330
|
expected_text = "Feature: correct title\nSome other content"
|
|
199
|
-
|
|
331
|
+
|
|
200
332
|
result = fix_title_mismatch(file_path, artefact_text, mock_artefact_class)
|
|
201
|
-
|
|
333
|
+
|
|
202
334
|
assert result == expected_text
|
|
203
335
|
mock_artefact_class._title_prefix.assert_called_once()
|
|
204
336
|
|
|
337
|
+
|
|
205
338
|
def test_fix_title_mismatch_prefix_not_found(capsys, mock_artefact_class):
|
|
206
339
|
artefact_text = "No title prefix here"
|
|
207
340
|
file_path = "path/to/correct_title.feature"
|
|
208
341
|
|
|
209
342
|
result = fix_title_mismatch(file_path, artefact_text, mock_artefact_class)
|
|
210
|
-
|
|
211
|
-
assert result == artefact_text
|
|
343
|
+
|
|
344
|
+
assert result == artefact_text # Should return original text
|
|
212
345
|
assert "Warning: Title prefix 'Feature:' not found" in capsys.readouterr().out
|
|
213
346
|
|
|
347
|
+
|
|
214
348
|
@patch("pydantic_ai.Agent")
|
|
215
349
|
def test_run_agent_exception_handling(mock_agent_class):
|
|
216
350
|
mock_agent_instance = mock_agent_class.return_value
|
|
@@ -25,7 +25,7 @@ def test_update_links_in_related_artefacts(mock_isfile, mock_listdir):
|
|
|
25
25
|
mock_file_handles = {filename: mock_open(read_data=content).return_value
|
|
26
26
|
for filename, content in file_contents.items()}
|
|
27
27
|
mock_open_function = mock_open()
|
|
28
|
-
mock_open_function.side_effect = lambda file_path, mode='r': mock_file_handles[os.path.basename(file_path)]
|
|
28
|
+
mock_open_function.side_effect = lambda file_path, mode='r', encoding='utf-8': mock_file_handles[os.path.basename(file_path)]
|
|
29
29
|
|
|
30
30
|
with patch("builtins.open", mock_open_function):
|
|
31
31
|
# Instantiate the ArtefactLinkUpdater with the mocked file system
|
|
@@ -38,8 +38,8 @@ def test_update_links_in_related_artefacts(mock_isfile, mock_listdir):
|
|
|
38
38
|
# Verify that the open function was called correctly for each file
|
|
39
39
|
for filename in file_contents.keys():
|
|
40
40
|
expected_file_path = os.path.join(dir_path, filename)
|
|
41
|
-
mock_open_function.assert_any_call(expected_file_path, 'r')
|
|
42
|
-
mock_open_function.assert_any_call(expected_file_path, 'w')
|
|
41
|
+
mock_open_function.assert_any_call(expected_file_path, 'r', encoding='utf-8')
|
|
42
|
+
mock_open_function.assert_any_call(expected_file_path, 'w', encoding='utf-8')
|
|
43
43
|
|
|
44
44
|
# Verify the content of the files was updated correctly
|
|
45
45
|
for filename, content in file_contents.items():
|
tests/test_artefact_renamer.py
CHANGED
|
@@ -53,9 +53,9 @@ def test_update_title_in_artefact(mock_file, classifier, artefact_name, read_dat
|
|
|
53
53
|
ar._update_title_in_artefact(artefact_path, new_title, classifier)
|
|
54
54
|
|
|
55
55
|
# Check that the file was opened for reading
|
|
56
|
-
mock_file.assert_any_call(artefact_path, 'r')
|
|
56
|
+
mock_file.assert_any_call(artefact_path, 'r', encoding='utf-8')
|
|
57
57
|
# Check that the file was opened for writing
|
|
58
|
-
mock_file.assert_any_call(artefact_path, 'w')
|
|
58
|
+
mock_file.assert_any_call(artefact_path, 'w', encoding='utf-8')
|
|
59
59
|
# Check that the file write was called with the correct new content
|
|
60
60
|
expected_content = read_data.replace(f"{read_data_prefix}{old_title}", f"{read_data_prefix}{new_title}")
|
|
61
61
|
mock_file().write.assert_called_with(expected_content)
|