Guide des tests¶
Documentation de la suite de tests unitaires Lua VEAF et du pipeline CI/CD.
Table des matières¶
- Vue d'ensemble
- Exécuter les tests
- Couverture
- Infrastructure
- Suite de tests
- Écrire des tests
- Pipeline CI/CD
Vue d'ensemble¶
Le projet couvre les modules runtime par une suite de tests Lua par module — la section « Suite de tests » les énumère toutes, et liste à sa fin ce qui n'est délibérément pas couvert. Les tests s'exécutent en Lua 5.1 standard avec le framework luaunit. Aucune installation de DCS n'est requise — l'API DCS est simulée par dcs_mocks.lua.
Exécuter les tests¶
Tous les tests¶
poetry run test-lua
Code de sortie 0 si toutes les suites passent, 1 si un test échoue.
Exécution filtrée¶
poetry run test-lua --filter spawn
poetry run test-lua --filter combat
Fichier unique¶
lua test/lua/test_veafSpawn.lua
Prérequis¶
poetry installdoit avoir été exécuté une fois- Lua 5.1 dans le PATH (
lua5.1,lua51oulua, ouC:\Program Files (x86)\Lua\5.1\lua.exesous Windows) - ou, à défaut, DCS installé : sous Windows,
test-lualit son dossier d'installation dans le registre (HKCU\Software\Eagle Dynamics\DCS World, puisDCS World OpenBeta) et prend le Lua 5.1.5 qu'il livre,bin\luae.exe. La couverture (--coverage) demande en plus que luacov soit trouvable par cet interpréteur (LUA_PATH). - Aucune autre dépendance (luaunit est embarqué dans
test/lua/luaunit.lua)
La version 5.1 est vérifiée : chaque candidat est interrogé avec lua -v, et un interpréteur
5.2+ est refusé au lieu d'être utilisé. C'est délibéré — Lua 5.2 a supprimé unpack et rendu
string.format('%d', ...) intolérant aux nombres fractionnaires, donc une exécution sous 5.4
produit des dizaines d'échecs qui ressemblent à des régressions et n'en sont pas.
Sous Windows, scoop install lua51 fournit Lua 5.1.5. Attention : son shim lua remplace celui
d'une autre version de Lua déjà installée par scoop ; le shim lua51 permet de garder les deux.
Couverture¶
Générez un rapport de couverture par fichier avec luacov :
poetry run test-lua --coverage
# ou forme courte :
poetry run test-lua -c
Après l'exécution, un tableau est affiché avec le nombre de lignes couvertes, manquées et le pourcentage de couverture par module. Le rapport est également écrit dans luacov.report.out à la racine du dépôt.
Prérequis (couverture)¶
luacov doit être installé via luarocks :
# Linux / DevContainer (luarocks est pré-installé)
luarocks install luacov
# Windows (peut nécessiter un shell élevé)
luarocks install luacov
Dans le DevContainer, luacov est installé automatiquement — aucune étape supplémentaire requise.
Configuration¶
La couverture est collectée uniquement pour les modules sous src/scripts/veaf/ (les helpers de test et luaunit sont exclus). Le fichier .luacov à la racine du dépôt contrôle ce comportement.
Infrastructure¶
Organisation des fichiers¶
test/lua/
├── luaunit.lua # Framework de test (embarqué)
├── dcs_mocks.lua # Stubs de l'API DCS
├── veaf_loader.lua # Chargeur de modules pour src/scripts/veaf/
└── test_*.lua # Un fichier par module
dcs_mocks.lua¶
Fournit des stubs minimaux pour l'API globale DCS afin que les modules puissent être chargés via require sans instance DCS active. Espaces de noms simulés :
env,timer,worldUnit,Group,StaticObject,Airbasecoalition,country,radiotrigger(incluanttrigger.smokeColor,trigger.action.*)- Helpers mathématiques (
math.isnan,math.inf)
Si un nouveau module ne se charge pas à cause d'un appel API DCS manquant, ajoutez le stub dans dcs_mocks.lua.
veaf_loader.lua¶
Modifie package.path pour que require("veaf"), require("veafSpawn"), etc. pointent vers src/scripts/veaf/. Chaque fichier de test commence par :
dofile("test/lua/dcs_mocks.lua")
dofile("test/lua/veaf_loader.lua")
local luaunit = require("luaunit")
-- charger le module à tester :
require("veafSpawn")
luaunit¶
L'API standard luaunit s'applique. Attention : assertNoError n'existe pas dans cette version ; utilisez pcall à la place :
local ok, err = pcall(function() veafSpawn.someFunction() end)
luaunit.assertIsTrue(ok, err)
Suite de tests¶
| Suite | Ce qu'elle couvre |
|---|---|
test_veaf.lua |
Utilitaires de base, helpers string/table/vecteur, logging |
test_veafCacheManager.lua |
Cache get/set/invalidate |
test_veafScheduler.lua |
Planificateur sur le timer natif : répétition, heure d'arrêt, tâche en échec |
test_skynetIadsUtils.lua |
Planificateur interne du Skynet vendorisé : une première exécution déjà passée est armée pour le tick suivant, répétition, heure d'arrêt et annulation inchangées |
test_veafMath.lua |
Conversions d'unités, vecteurs, formes de coordonnées, copie profonde |
test_veafGeo.lua |
Rendu texte des coordonnées, zones, positions moyennes, polygones |
test_veafGeo_ported.lua |
Géométrie portée depuis MiST : tirage dans un cercle, unités en zone circulaire, cap, dessin de zone |
test_veafMissionDb.lua |
Instantané de la mission, liste des joueurs, registre des noms, identifiants |
test_veafMissionDb_scenery.lua |
Registre des objets de décor détruits : enregistrement, recherche par zone, abonnement à l'événement |
test_veafDcsSpawner.lua |
Création de statiques à l'exécution : pays, identifiants, formes, cap aléatoire |
test_csar_init.lua |
Initialisation de CSAR, dans l'ordre de chargement d'une vraie mission (CSAR avant VEAF) : un seul gestionnaire d'événements quoi qu'il arrive |
test_community_scripts_load.lua |
Chaque script communautaire vendorisé se charge sans lever, avec les seuls mocks DCS — la porte qui manquait quand CTLD rc8 a livré un fichier qui ne se chargeait pas (#957). TUM en est exclu et le dit : il s'auto-initialise et exige des zones de territoire |
test_aienGroupSA.lua |
AIEN lit la conscience de situation d'un groupe par groupSA, construite à la demande : une artillerie touchée dès le début n'en a pas, et la contre-batterie plantait dessus (29/10/2026) |
test_stts.lua |
La synthèse vocale SRS valide ses paramètres avant la commande système |
test_veafInterpreter.lua |
Tokeniseur de texte marqueur |
test_veafTime.lua |
Parsing de temps, formatage, helpers temps DCS |
test_veafSecurity.lua |
Niveaux de sécurité, gestion des admins |
test_veafServerHook.lua |
Hook serveur : parsing et dispatch des commandes chat |
test_veafNamedPoints.lua |
Enregistrement de points, recherche, helpers ATC |
test_veafOpposition.lua |
Niveau d'opposition : compté sur les joueurs connectés ou en vol, hystérésis (hausse immédiate, baisse après un délai), marqueur _opposition et son niveau de sécurité |
test_veafShortcuts.lua |
Enregistrement et résolution des raccourcis |
test_veafShortcuts_bypass.lua |
Ce qu'un joueur peut taper après un raccourci qui contourne la sécurité |
test_veafWeather.lua |
Parsing météo, calculs QNH/vent |
test_dcsDataExport.lua |
Utilitaires d'export de données unités |
test_veafCombatMission.lua |
Cycle de vie d'une mission de combat |
test_veafCombatLog.lua |
Journal de combat : une ligne JSON par tir, coup au but, destruction et rafale (obus comptés), un tireur disparu ne casse rien, sans io rien n'est écrit |
test_veafCombatMission_menu.lua |
Menu radio MISSIONS : missions déclarées après initialize(), reconstruction différée |
test_veafAirbases.lua |
Recherche de données aérodromes |
test_veafCombatZone.lua |
Activation de zone, scoring, machine à états |
test_veafCombatZone_displacement.lua |
Ancrage du spawn d'un groupe très étalé : il garde sa forme |
test_veafDiagnostics.lua |
Interrupteur veaf.Diagnostics et lignes de diagnostic des zones de combat |
test_veafUnits.lua |
Recherche de templates d'unités, filtrage par catégorie |
test_veafAssets.lua |
Enregistrement d'assets, suivi d'état |
test_veafAssist.lua |
Assistance pilote : checklists, progression, menus |
test_veafRemote.lua |
Parsing de commandes distantes |
test_veafMarkers.lua |
Gestion des événements marqueur |
test_veafEventHandler.lua |
Dispatch d'événements, enregistrement de handlers |
test_veafSkynetIadsHelper.lua |
Helpers d'intégration Skynet IADS |
test_veafSkynetIadsHelper_spotter.lua |
Réseau de guetteurs : détection, graphe radio, propagation, passage de relais à Skynet |
test_veafSkynetIadsMonitor.lua |
État du moniteur Skynet |
test_veafGroundAI.lua |
Flags de comportement IA sol |
test_veafGroundAI_convoy.lua |
Convoi sous le feu : veille, scission, combat ou repli, appel à l'aide, ordres _gc |
test_veafRadio.lua |
Construction de l'arbre de menus radio |
test_veafRadio_pilots.lua |
Menu F10 en multijoueur : commandes liées aux pilotes présents, menus réservés à des groupes, menus par pilote |
test_veafQraManager.lua |
Machine à états QRA, gestion de zones |
test_veafAirWaves.lua |
Planification de waves, assignation de groupes |
test_veafReactiveZone.lua |
Base commune QRA / AirWaves : zone, zone mobile, spawn, liens, spawns différés |
test_veafAircraftSpawn.lua |
Avion lancé avec un rôle : contrat -cap, lecture de route, défense de zone (zone_defense) |
test_veafAwacsEscort.lua |
-awacs (hippodrome, Skynet, liaison de données) et -escort (tâche Escort, avion le plus proche du marqueur, entrée F10 « Escorte-moi ») |
test_veafSanctuary.lua |
Détection de zone sanctuaire |
test_veafMissileGuardian.lua |
Logique d'interception de missiles |
test_veafCampaign.lua |
Campagne multi-missions : tirage, enregistrement et pertes des garnisons |
test_veafCasMission.lua |
Génération de packages de menaces CAS |
test_veafTransportMission.lua |
Setup de mission de transport |
test_veafCarrierOperations.lua |
Séquence de recovery porte-avions |
test_veafMove.lua |
Parsing de commandes de déplacement/téléportation |
test_veafMove_escort.lua |
Récupération de la tâche Escort après recréation du groupe escorté |
test_veafGrass.lua |
Initialisation de pistes en herbe |
test_veafHelicopterSpawn.lua |
Hélicoptère créé par marqueur : posé par le chemin sol, catégorie HELICOPTER, armement de l'alias, tâches orbit et transport |
test_veafSpawn.lua |
Commandes spawn, analyse de texte marqueur, conversion fréquence laser |
test_veafSpawnParser.lua |
Parsing déterministe du texte marqueur de spawn (markTextAnalysis) |
test_veafCommands.lua |
Registre de commandes : ordonnancement par priorité et dispatch |
test_veafI18n.lua |
Couche i18n runtime Lua (veaf.t, catalogue veafI18n) |
Module non couvert :
| Module | Raison |
|---|---|
dcsUnits.lua |
Fichier de données pur ; exercé indirectement via test_veafUnits.lua |
Écrire des tests¶
Template minimal¶
-- test_veafMyModule.lua
package.path = package.path .. ";test/lua/?.lua;src/scripts/veaf/?.lua"
dofile("test/lua/dcs_mocks.lua")
dofile("test/lua/veaf_loader.lua")
local luaunit = require("luaunit")
require("veafMyModule")
TestVeafMyModuleConstants = {}
function TestVeafMyModuleConstants:test_Id()
luaunit.assertEquals(veafMyModule.Id, "MYMODULE")
end
TestVeafMyModuleLogic = {}
function TestVeafMyModuleLogic:test_someFunction()
local result = veafMyModule.someFunction("input")
luaunit.assertEquals(result, "expected")
end
-- Point d'entrée
os.exit(luaunit.LuaUnit.run())
Conventions¶
- Un fichier par module :
test_veaf<NomModule>.lua - Grouper les tests en classes :
TestVeaf<NomModule>Constants,TestVeaf<NomModule>Logic, etc. - Toujours terminer par
os.exit(luaunit.LuaUnit.run()) - Utiliser
pcallau lieu deassertNoError(indisponible dans cette version de luaunit) - Ne pas tester les fonctions internes/privées — uniquement ce que le module Lua exporte sur sa table globale
Ajouter des stubs d'API DCS¶
Si votre test échoue avec "nil value" ou "attempt to call a nil value" sur une fonction DCS, ajoutez le stub dans dcs_mocks.lua :
-- Dans dcs_mocks.lua :
trigger.action.myNewFunction = function(...) end
trigger.myNewConstant = 42
Pipeline CI/CD¶
Le workflow GitHub Actions (.github/workflows/lua-ci.yml) s'exécute à chaque push et pull request :
Jobs¶
lua-unit-tests — Ubuntu latest
1. Checkout du dépôt
2. Installation de lua5.1 via apt
3. Exécution de tous les fichiers test/lua/test_*.lua
4. Échec du job si une suite retourne un code non-zéro
luacheck — Ubuntu latest
1. Checkout du dépôt
2. Installation de lua5.1 + luacheck via LuaRocks
3. Analyse statique de src/scripts/veaf/ avec luacheck --config .luacheckrc (globaux non définis, variables inutilisées, shadowing)
4. Échec si une violation est détectée
stylua-check — Ubuntu latest
1. Checkout du dépôt
2. Exécution de JohnnyMorganz/stylua-action@v5 avec la version 2.4.0
3. Vérification de src/scripts/veaf/ et test/lua/ contre .stylua.toml
4. Échec si un fichier n'est pas formaté
lua-coverage — Ubuntu latest
1. Checkout du dépôt
2. Installation de lua5.1 + luacov via LuaRocks, puis de Poetry et des dépendances
3. Exécution de poetry run test-lua --cov-fail-under 83.0 (couverture ligne via luacov)
4. Échec si la couverture passe sous le plancher à cliquet (le nombre ne fait que monter)
Exécuter StyLua localement¶
# Vérification seule (pas d'écriture)
stylua --check src/scripts/veaf/ test/lua/
# Auto-formatage
stylua src/scripts/veaf/ test/lua/
Exécuter Luacheck localement¶
luacheck --config .luacheckrc src/scripts/veaf/
Configuration StyLua (.stylua.toml) :
column_width = 140
line_endings = "Windows"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferDouble"
call_parentheses = "Always"
collapse_simple_statement = "Never"