2026-03-11 22:50:02 -04:00
|
|
|
#!/usr/bin/env python3
|
2026-03-11 23:15:07 -04:00
|
|
|
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
2026-03-11 22:50:02 -04:00
|
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import tempfile
|
|
|
|
|
import unittest
|
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
|
|
from script.addons.check_addons_exist import main
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMainModuleFound(unittest.TestCase):
|
|
|
|
|
"""Test main() when modules exist with valid __manifest__.py."""
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.tmpdir = tempfile.mkdtemp()
|
|
|
|
|
# Create a valid addon
|
|
|
|
|
addon_path = os.path.join(self.tmpdir, "my_addon")
|
|
|
|
|
os.makedirs(addon_path)
|
|
|
|
|
with open(os.path.join(addon_path, "__manifest__.py"), "w") as f:
|
|
|
|
|
f.write("{}")
|
|
|
|
|
# Create config.conf
|
|
|
|
|
self.config_path = os.path.join(self.tmpdir, "config.conf")
|
|
|
|
|
with open(self.config_path, "w") as f:
|
|
|
|
|
f.write(f"[options]\naddons_path = {self.tmpdir}\n")
|
|
|
|
|
|
|
|
|
|
def test_single_module_found(self):
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
["prog", "-m", "my_addon", "-c", self.config_path],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, 0)
|
|
|
|
|
|
|
|
|
|
def test_output_json_module_found(self):
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
[
|
|
|
|
|
"prog",
|
|
|
|
|
"-m",
|
|
|
|
|
"my_addon",
|
|
|
|
|
"-c",
|
|
|
|
|
self.config_path,
|
|
|
|
|
"--output_json",
|
|
|
|
|
],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, 0)
|
|
|
|
|
|
|
|
|
|
def test_format_json_output(self):
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
[
|
|
|
|
|
"prog",
|
|
|
|
|
"-m",
|
|
|
|
|
"my_addon",
|
|
|
|
|
"-c",
|
|
|
|
|
self.config_path,
|
|
|
|
|
"--output_json",
|
|
|
|
|
"--format_json",
|
|
|
|
|
],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, 0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMainModuleMissing(unittest.TestCase):
|
|
|
|
|
"""Test main() when modules do not exist."""
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.tmpdir = tempfile.mkdtemp()
|
|
|
|
|
self.config_path = os.path.join(self.tmpdir, "config.conf")
|
|
|
|
|
with open(self.config_path, "w") as f:
|
|
|
|
|
f.write(f"[options]\naddons_path = {self.tmpdir}\n")
|
|
|
|
|
|
|
|
|
|
def test_missing_module_returns_1(self):
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
["prog", "-m", "nonexistent", "-c", self.config_path],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, 1)
|
|
|
|
|
|
|
|
|
|
def test_missing_module_json(self):
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
[
|
|
|
|
|
"prog",
|
|
|
|
|
"-m",
|
|
|
|
|
"nonexistent",
|
|
|
|
|
"-c",
|
|
|
|
|
self.config_path,
|
|
|
|
|
"--output_json",
|
|
|
|
|
],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMainDuplicateModule(unittest.TestCase):
|
|
|
|
|
"""Test main() when same module exists in multiple addon paths."""
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.tmpdir = tempfile.mkdtemp()
|
|
|
|
|
path1 = os.path.join(self.tmpdir, "addons1", "dup_mod")
|
|
|
|
|
path2 = os.path.join(self.tmpdir, "addons2", "dup_mod")
|
|
|
|
|
os.makedirs(path1)
|
|
|
|
|
os.makedirs(path2)
|
|
|
|
|
with open(os.path.join(path1, "__manifest__.py"), "w") as f:
|
|
|
|
|
f.write("{}")
|
|
|
|
|
with open(os.path.join(path2, "__manifest__.py"), "w") as f:
|
|
|
|
|
f.write("{}")
|
|
|
|
|
addons = (
|
|
|
|
|
os.path.join(self.tmpdir, "addons1")
|
|
|
|
|
+ ","
|
|
|
|
|
+ os.path.join(self.tmpdir, "addons2")
|
|
|
|
|
)
|
|
|
|
|
self.config_path = os.path.join(self.tmpdir, "config.conf")
|
|
|
|
|
with open(self.config_path, "w") as f:
|
|
|
|
|
f.write(f"[options]\naddons_path = {addons}\n")
|
|
|
|
|
|
|
|
|
|
def test_duplicate_returns_2(self):
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
["prog", "-m", "dup_mod", "-c", self.config_path],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, 2)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMainMissingManifest(unittest.TestCase):
|
|
|
|
|
"""Test main() when directory exists but __manifest__.py is absent."""
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.tmpdir = tempfile.mkdtemp()
|
|
|
|
|
addon_path = os.path.join(self.tmpdir, "empty_addon")
|
|
|
|
|
os.makedirs(addon_path)
|
|
|
|
|
self.config_path = os.path.join(self.tmpdir, "config.conf")
|
|
|
|
|
with open(self.config_path, "w") as f:
|
|
|
|
|
f.write(f"[options]\naddons_path = {self.tmpdir}\n")
|
|
|
|
|
|
|
|
|
|
def test_dir_without_manifest_returns_1(self):
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
["prog", "-m", "empty_addon", "-c", self.config_path],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMainBadConfig(unittest.TestCase):
|
|
|
|
|
"""Test main() with invalid config files."""
|
|
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
|
self.tmpdir = tempfile.mkdtemp()
|
|
|
|
|
|
|
|
|
|
def test_missing_options_section(self):
|
|
|
|
|
config_path = os.path.join(self.tmpdir, "config.conf")
|
|
|
|
|
with open(config_path, "w") as f:
|
|
|
|
|
f.write("[other]\nkey = value\n")
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
["prog", "-m", "mod", "-c", config_path],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, -1)
|
|
|
|
|
|
|
|
|
|
def test_missing_addons_path_key(self):
|
|
|
|
|
config_path = os.path.join(self.tmpdir, "config.conf")
|
|
|
|
|
with open(config_path, "w") as f:
|
|
|
|
|
f.write("[options]\nother_key = value\n")
|
|
|
|
|
with patch(
|
|
|
|
|
"sys.argv",
|
|
|
|
|
["prog", "-m", "mod", "-c", config_path],
|
|
|
|
|
):
|
|
|
|
|
result = main()
|
|
|
|
|
self.assertEqual(result, -1)
|
[FIX] tests : balayer test/test_*.py et refuser un fichier muet
Le lanceur ne prenait que sept préfixes de noms, « le reste demandant une
base de données » : les 3703 tests du répertoire passent avec PostgreSQL
injoignable, et la suite n'en exécutait que 1131. Il balaie test/test_*.py.
Deux formes rendent un fichier muet sans erreur : unittest.main() posé en
plein milieu, qui sort avant que la seconde moitié soit définie (quatre
fichiers, 87 tests), et l'absence de bloc __main__, qui compte zéro (huit
fichiers, 174 tests). Une garde refuse ces deux formes et le retour d'une
liste de préfixes.
--- EN ---
The runner took seven filename prefixes only, "the rest needing a
database": all 3703 tests in the directory pass with PostgreSQL
unreachable, and the suite ran 1131 of them. It now globs test/test_*.py.
Two shapes make a file silent without error: unittest.main() placed
mid-file, which exits before the second half is defined (four files, 87
tests), and no __main__ block at all, which counts zero (eight files, 174
tests). A guard now refuses both shapes and the return of a prefix list.
Assisted-by: Claude Opus 5
(cherry picked from commit db71b333cc08ae0fce4ddaaf037357648b10236b)
2026-08-26 07:46:14 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
unittest.main()
|