|
| 1 | +# Drakkar-Software OctoBot-Tentacles-Manager |
| 2 | +# Copyright (c) Drakkar-Software, All rights reserved. |
| 3 | +# |
| 4 | +# This library is free software; you can redistribute it and/or |
| 5 | +# modify it under the terms of the GNU Lesser General Public |
| 6 | +# License as published by the Free Software Foundation; either |
| 7 | +# version 3.0 of the License, or (at your option) any later version. |
| 8 | +# |
| 9 | +# This library is distributed in the hope that it will be useful, |
| 10 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | +# Lesser General Public License for more details. |
| 13 | +# |
| 14 | +# You should have received a copy of the GNU Lesser General Public |
| 15 | +# License along with this library. |
| 16 | +import os |
| 17 | + |
| 18 | +import octobot_tentacles_manager.constants as constants |
| 19 | +import octobot_tentacles_manager.util.tentacle_explorer as tentacle_explorer |
| 20 | + |
| 21 | + |
| 22 | +class _DummyTentacleClass: |
| 23 | + pass |
| 24 | + |
| 25 | + |
| 26 | +def _write_tentacle_metadata_file(directory: str) -> None: |
| 27 | + metadata_path = os.path.join(directory, constants.TENTACLE_METADATA) |
| 28 | + with open(metadata_path, "w", encoding="utf-8") as metadata_file: |
| 29 | + metadata_file.write("{}") |
| 30 | + |
| 31 | + |
| 32 | +def _ensure_tentacle_type_with_metadata_nested_under(root: str, type_folder_name: str) -> str: |
| 33 | + """ |
| 34 | + Make ``type_folder_name`` a discovered tentacle type: one direct child folder |
| 35 | + must contain ``metadata.json`` (see _has_tentacle_in_direct_sub_directories). |
| 36 | + """ |
| 37 | + type_dir = os.path.join(root, type_folder_name) |
| 38 | + marker = os.path.join(type_dir, "_type_marker_tentacle") |
| 39 | + os.makedirs(marker, exist_ok=True) |
| 40 | + _write_tentacle_metadata_file(marker) |
| 41 | + return type_dir |
| 42 | + |
| 43 | + |
| 44 | +def _add_tentacle_folders(tentacle_type_dir: str, *tentacle_folder_names: str) -> None: |
| 45 | + for entry_name in tentacle_folder_names: |
| 46 | + os.makedirs(os.path.join(tentacle_type_dir, entry_name), exist_ok=True) |
| 47 | + |
| 48 | + |
| 49 | +class TestParseAllTentacles: |
| 50 | + def test_tentacle_names_are_sorted_regardless_of_filesystem_entry_order( |
| 51 | + self, tmp_path, monkeypatch |
| 52 | + ): |
| 53 | + # Avoid interference from any tentacles registered elsewhere in the test session. |
| 54 | + monkeypatch.setattr( |
| 55 | + tentacle_explorer, "_extra_tentacle_data_by_name", {} |
| 56 | + ) |
| 57 | + services_dir = _ensure_tentacle_type_with_metadata_nested_under( |
| 58 | + str(tmp_path), "Services" |
| 59 | + ) |
| 60 | + # Intentional non-alphabetic creation order; result must be sorted by name. |
| 61 | + _add_tentacle_folders(services_dir, "zebra", "mike", "charlie") |
| 62 | + names = [tentacle.name for tentacle in tentacle_explorer._parse_all_tentacles(str(tmp_path))] |
| 63 | + expected_names = sorted(names) |
| 64 | + assert names == expected_names |
| 65 | + assert names == [ |
| 66 | + "_type_marker_tentacle", |
| 67 | + "charlie", |
| 68 | + "mike", |
| 69 | + "zebra", |
| 70 | + ] |
| 71 | + |
| 72 | + def test_merges_extra_registered_tentacles_and_sorts_by_name( |
| 73 | + self, tmp_path, monkeypatch |
| 74 | + ): |
| 75 | + extra = {} |
| 76 | + monkeypatch.setattr( |
| 77 | + tentacle_explorer, "_extra_tentacle_data_by_name", extra |
| 78 | + ) |
| 79 | + services_dir = _ensure_tentacle_type_with_metadata_nested_under( |
| 80 | + str(tmp_path), "Services" |
| 81 | + ) |
| 82 | + _add_tentacle_folders(services_dir, "mountain", "ant") |
| 83 | + # Register names that interleave with filesystem names when unsorted. |
| 84 | + tentacle_explorer.register_extra_tentacle_data("zebra", "Other", _DummyTentacleClass) |
| 85 | + tentacle_explorer.register_extra_tentacle_data("alpha", "Other", _DummyTentacleClass) |
| 86 | + try: |
| 87 | + names = [ |
| 88 | + t.name |
| 89 | + for t in tentacle_explorer._parse_all_tentacles(str(tmp_path)) |
| 90 | + ] |
| 91 | + assert names == sorted(names) |
| 92 | + assert names == [ |
| 93 | + "_type_marker_tentacle", |
| 94 | + "alpha", |
| 95 | + "ant", |
| 96 | + "mountain", |
| 97 | + "zebra", |
| 98 | + ] |
| 99 | + finally: |
| 100 | + extra.clear() |
0 commit comments