Initial commit
This commit is contained in:
15
skills/git-pr/tests/.gitignore
vendored
Normal file
15
skills/git-pr/tests/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
|
||||
# Cache test local
|
||||
.claude/
|
||||
|
||||
# Éditeurs
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
18
skills/git-pr/tests/run_tests.sh
Executable file
18
skills/git-pr/tests/run_tests.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Lance tous les tests unitaires du skill git-pr
|
||||
|
||||
set -e
|
||||
|
||||
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$TEST_DIR"
|
||||
|
||||
echo "🧪 Lancement tests git-pr..."
|
||||
echo ""
|
||||
|
||||
python3 test_milestone_cache.py -v
|
||||
echo ""
|
||||
|
||||
python3 test_project_cache.py -v
|
||||
echo ""
|
||||
|
||||
echo "✅ Tous les tests passés"
|
||||
210
skills/git-pr/tests/test_milestone_cache.py
Normal file
210
skills/git-pr/tests/test_milestone_cache.py
Normal file
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Tests unitaires pour milestone_cache"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
|
||||
from milestone_cache import MilestoneCache, CACHE_DIR, CACHE_FILE
|
||||
|
||||
|
||||
class TestNormalizeSemver(unittest.TestCase):
|
||||
"""Test normalisation semver"""
|
||||
|
||||
def test_normalise_un_chiffre_ajoute_zero_zero(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.normalize_semver("26"), "26.0.0")
|
||||
|
||||
def test_normalise_deux_chiffres_ajoute_zero(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.normalize_semver("26.1"), "26.1.0")
|
||||
|
||||
def test_normalise_trois_chiffres_reste_identique(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.normalize_semver("26.1.1"), "26.1.1")
|
||||
|
||||
def test_normalise_conserve_suffixe(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.normalize_semver("26.0.0 (Avenant)"), "26.0.0 (Avenant)")
|
||||
|
||||
|
||||
class TestGenerateAliases(unittest.TestCase):
|
||||
"""Test génération aliases stricte"""
|
||||
|
||||
def test_genere_alias_pour_titre_avec_parentheses(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.generate_aliases("26.1.1 (Hotfix)"), ["26.1.1"])
|
||||
|
||||
def test_genere_alias_pour_titre_avec_avenant(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.generate_aliases("26.0.0 (Avenant)"), ["26.0.0"])
|
||||
|
||||
def test_genere_pas_alias_pour_titre_sans_parentheses(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.generate_aliases("26.1.0"), [])
|
||||
|
||||
def test_genere_pas_alias_pour_titre_non_semver(self):
|
||||
cache = MilestoneCache()
|
||||
self.assertEqual(cache.generate_aliases("Release Candidate"), [])
|
||||
|
||||
|
||||
class TestFindExactMatch(unittest.TestCase):
|
||||
"""Test recherche exacte"""
|
||||
|
||||
def test_trouve_par_titre_exact(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 42, "title": "26.0.0 (Avenant)", "aliases": ["26.0.0"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("26.0.0 (Avenant)")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["number"], 42)
|
||||
|
||||
def test_ne_trouve_pas_si_titre_different(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 42, "title": "26.0.0 (Avenant)", "aliases": ["26.0.0"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("27.0.0")
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestFindByAlias(unittest.TestCase):
|
||||
"""Test recherche par alias"""
|
||||
|
||||
def test_query_trouve_via_alias(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 43, "title": "26.1.1 (Hotfix)", "aliases": ["26.1.1"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("26.1.1")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["title"], "26.1.1 (Hotfix)")
|
||||
|
||||
def test_query_trouve_milestone_sans_parentheses(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 44, "title": "26.1.0", "aliases": []}
|
||||
]
|
||||
}
|
||||
result = cache.find("26.1.0")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["number"], 44)
|
||||
|
||||
|
||||
class TestNoCollisionMatch(unittest.TestCase):
|
||||
"""Test pas de collision entre versions"""
|
||||
|
||||
def test_query_partielle_ne_trouve_pas_version_complete(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 43, "title": "26.1.1 (Hotfix)", "aliases": ["26.1.1"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("26.1")
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_query_majeure_ne_trouve_pas_version_mineure(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 42, "title": "26.0.0 (Avenant)", "aliases": ["26.0.0"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("26")
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestFindWithNormalization(unittest.TestCase):
|
||||
"""Test recherche avec normalisation"""
|
||||
|
||||
def test_query_normalisee_trouve_milestone(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 44, "title": "26.1.0", "aliases": []}
|
||||
]
|
||||
}
|
||||
normalized = cache.normalize_semver("26.1")
|
||||
result = cache.find(normalized)
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["title"], "26.1.0")
|
||||
|
||||
def test_query_majeure_normalisee_trouve_avenant(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {
|
||||
"milestones": [
|
||||
{"number": 42, "title": "26.0.0 (Avenant)", "aliases": ["26.0.0"]}
|
||||
]
|
||||
}
|
||||
normalized = cache.normalize_semver("26")
|
||||
result = cache.find(normalized)
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["title"], "26.0.0 (Avenant)")
|
||||
|
||||
|
||||
class TestCachePersistence(unittest.TestCase):
|
||||
"""Test sauvegarde/chargement"""
|
||||
|
||||
def test_charge_cache_vide_si_fichier_inexistant(self):
|
||||
cache = MilestoneCache()
|
||||
cache.cache = {"milestones": []}
|
||||
self.assertEqual(cache.cache["milestones"], [])
|
||||
|
||||
|
||||
class TestCreateMilestone(unittest.TestCase):
|
||||
"""Test création milestone inexistant"""
|
||||
|
||||
@patch('milestone_cache.subprocess.run')
|
||||
def test_cree_milestone_via_api(self, mock_run):
|
||||
mock_run.side_effect = [
|
||||
MagicMock(stdout="git@github.com:owner/repo.git\n"),
|
||||
MagicMock(stdout='{"number": 50, "title": "99.0.0"}')
|
||||
]
|
||||
cache = MilestoneCache()
|
||||
result = cache.create("99.0.0")
|
||||
self.assertEqual(result["number"], 50)
|
||||
self.assertEqual(result["title"], "99.0.0")
|
||||
|
||||
|
||||
class TestCreateWithNormalization(unittest.TestCase):
|
||||
"""Test création avec normalisation semver"""
|
||||
|
||||
@patch('milestone_cache.subprocess.run')
|
||||
def test_cree_milestone_normalise_depuis_majeure(self, mock_run):
|
||||
mock_run.side_effect = [
|
||||
MagicMock(stdout="git@github.com:owner/repo.git\n"),
|
||||
MagicMock(stdout='{"number": 51, "title": "26.0.0"}')
|
||||
]
|
||||
cache = MilestoneCache()
|
||||
normalized = cache.normalize_semver("26")
|
||||
result = cache.create(normalized)
|
||||
self.assertEqual(result["title"], "26.0.0")
|
||||
|
||||
@patch('milestone_cache.subprocess.run')
|
||||
def test_cree_milestone_normalise_depuis_mineure(self, mock_run):
|
||||
mock_run.side_effect = [
|
||||
MagicMock(stdout="git@github.com:owner/repo.git\n"),
|
||||
MagicMock(stdout='{"number": 52, "title": "26.1.0"}')
|
||||
]
|
||||
cache = MilestoneCache()
|
||||
normalized = cache.normalize_semver("26.1")
|
||||
result = cache.create(normalized)
|
||||
self.assertEqual(result["title"], "26.1.0")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
153
skills/git-pr/tests/test_project_cache.py
Normal file
153
skills/git-pr/tests/test_project_cache.py
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Tests unitaires pour project_cache"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
|
||||
from project_cache import ProjectCache, CACHE_DIR, CACHE_FILE
|
||||
|
||||
|
||||
class TestGenerateAliases(unittest.TestCase):
|
||||
"""Test génération aliases"""
|
||||
|
||||
def test_genere_alias_pour_titre_simple(self):
|
||||
cache = ProjectCache()
|
||||
aliases = cache.generate_aliases("Project Alpha")
|
||||
self.assertIn("project", aliases)
|
||||
self.assertIn("alpha", aliases)
|
||||
|
||||
def test_genere_alias_pour_titre_avec_tirets(self):
|
||||
cache = ProjectCache()
|
||||
aliases = cache.generate_aliases("Bug Tracking")
|
||||
self.assertIn("bug", aliases)
|
||||
self.assertIn("tracking", aliases)
|
||||
|
||||
def test_genere_alias_pour_titre_avec_chiffres(self):
|
||||
cache = ProjectCache()
|
||||
aliases = cache.generate_aliases("Sprint 2024-Q1")
|
||||
self.assertIn("sprint", aliases)
|
||||
self.assertIn("2024", aliases)
|
||||
self.assertIn("q1", aliases)
|
||||
|
||||
def test_genere_pas_alias_pour_mots_courts(self):
|
||||
cache = ProjectCache()
|
||||
aliases = cache.generate_aliases("The Big Project")
|
||||
self.assertNotIn("the", aliases)
|
||||
self.assertIn("big", aliases)
|
||||
self.assertIn("project", aliases)
|
||||
|
||||
|
||||
class TestFindExactMatch(unittest.TestCase):
|
||||
"""Test recherche exacte"""
|
||||
|
||||
def test_trouve_par_titre_exact(self):
|
||||
cache = ProjectCache()
|
||||
cache.cache = {
|
||||
"projects": [
|
||||
{"id": "PVT_123", "title": "Project Alpha", "number": 1, "aliases": ["project", "alpha"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("Project Alpha")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["id"], "PVT_123")
|
||||
|
||||
def test_trouve_par_titre_exact_case_insensitive(self):
|
||||
cache = ProjectCache()
|
||||
cache.cache = {
|
||||
"projects": [
|
||||
{"id": "PVT_123", "title": "Project Alpha", "number": 1, "aliases": ["project", "alpha"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("project alpha")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["id"], "PVT_123")
|
||||
|
||||
def test_ne_trouve_pas_si_titre_different(self):
|
||||
cache = ProjectCache()
|
||||
cache.cache = {
|
||||
"projects": [
|
||||
{"id": "PVT_123", "title": "Project Alpha", "number": 1, "aliases": ["project", "alpha"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("Project Beta")
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestFindByAlias(unittest.TestCase):
|
||||
"""Test recherche par alias"""
|
||||
|
||||
def test_query_trouve_via_alias(self):
|
||||
cache = ProjectCache()
|
||||
cache.cache = {
|
||||
"projects": [
|
||||
{"id": "PVT_456", "title": "Bug Tracking", "number": 2, "aliases": ["bug", "tracking"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("bug")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["title"], "Bug Tracking")
|
||||
|
||||
def test_query_trouve_via_alias_case_insensitive(self):
|
||||
cache = ProjectCache()
|
||||
cache.cache = {
|
||||
"projects": [
|
||||
{"id": "PVT_456", "title": "Bug Tracking", "number": 2, "aliases": ["bug", "tracking"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("BUG")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["title"], "Bug Tracking")
|
||||
|
||||
def test_query_trouve_projet_sans_alias(self):
|
||||
cache = ProjectCache()
|
||||
cache.cache = {
|
||||
"projects": [
|
||||
{"id": "PVT_789", "title": "Main", "number": 3, "aliases": ["main"]}
|
||||
]
|
||||
}
|
||||
result = cache.find("Main")
|
||||
self.assertIsNotNone(result)
|
||||
self.assertEqual(result["number"], 3)
|
||||
|
||||
|
||||
class TestCachePersistence(unittest.TestCase):
|
||||
"""Test sauvegarde/chargement"""
|
||||
|
||||
def test_charge_cache_vide_si_fichier_inexistant(self):
|
||||
cache = ProjectCache()
|
||||
cache.cache = {"projects": []}
|
||||
self.assertEqual(cache.cache["projects"], [])
|
||||
|
||||
|
||||
class TestRefreshFromApi(unittest.TestCase):
|
||||
"""Test refresh depuis API"""
|
||||
|
||||
def test_refresh_remplace_cache_complet(self):
|
||||
cache = ProjectCache()
|
||||
projects = [
|
||||
{"id": "PVT_111", "title": "Project A", "number": 1},
|
||||
{"id": "PVT_222", "title": "Project B", "number": 2}
|
||||
]
|
||||
cache.refresh_from_api(projects)
|
||||
self.assertEqual(len(cache.cache["projects"]), 2)
|
||||
self.assertEqual(cache.cache["projects"][0]["id"], "PVT_111")
|
||||
self.assertEqual(cache.cache["projects"][1]["id"], "PVT_222")
|
||||
|
||||
def test_refresh_genere_aliases(self):
|
||||
cache = ProjectCache()
|
||||
projects = [
|
||||
{"id": "PVT_333", "title": "Sprint Planning", "number": 3}
|
||||
]
|
||||
cache.refresh_from_api(projects)
|
||||
self.assertIn("sprint", cache.cache["projects"][0]["aliases"])
|
||||
self.assertIn("planning", cache.cache["projects"][0]["aliases"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user