10 KiB
Ticket #032 — Factoriser le chargement et l’installation d’une enquête
Contexte
Après le ticket #031.1, l’application sait :
- créer une enquête ;
- ouvrir une enquête existante ;
- remplacer la session active ;
- fermer proprement l’application.
Cependant, les flux « Nouvelle enquête » et « Ouvrir une enquête » dupliquent encore une partie importante de la logique :
investigation_session_open()
→ récupération du projet
→ récupération du chemin racine
→ investigation_tree_builder_build()
→ application_install_session()
→ nettoyage en cas d’échec
Cette duplication augmentera avec les futures fonctions :
- enquêtes récentes ;
- ouverture depuis la ligne de commande ;
- restauration de session ;
- ouverture depuis un rapport ou une archive.
Objectif
Créer dans src/core/application.c une fonction interne unique qui ouvre et installe une enquête à partir de son dossier racine.
Contrat attendu :
static gboolean application_open_and_install_investigation(
Application *application,
const char *root_path,
GError **error
);
Cette fonction doit garantir :
succès :
Application devient propriétaire de la nouvelle session
Application devient propriétaire du nouvel arbre
ancienne session libérée
ancien arbre libéré
fenêtre mise à jour
échec :
ancienne session conservée
ancien arbre conservé
nouvelle session libérée
nouvel arbre libéré
erreur transmise à l’appelant
Travail à réaliser
1. Ajouter un domaine d’erreur privé
Dans src/core/application.c, ajouter un domaine d’erreur uniquement utilisé par le contrôleur.
Exemple :
typedef enum
{
APPLICATION_OPEN_ERROR_INVALID_ARGUMENT,
APPLICATION_OPEN_ERROR_INVALID_PROJECT,
APPLICATION_OPEN_ERROR_TREE_BUILD,
APPLICATION_OPEN_ERROR_INSTALL
} ApplicationOpenError;
Ajouter :
#define APPLICATION_OPEN_ERROR \
application_open_error_quark()
Puis :
static GQuark application_open_error_quark(void)
{
return g_quark_from_static_string(
"labfy-investigation-application-open-error"
);
}
Le domaine reste privé à application.c.
2. Créer la fonction factorisée
Ajouter :
static gboolean application_open_and_install_investigation(
Application *application,
const char *root_path,
GError **error
);
La fonction doit :
- valider
application; - valider
application->main_window; - valider
root_path; - ouvrir une nouvelle
InvestigationSession; - récupérer son
InvestigationProject; - récupérer le chemin racine canonique ;
- construire un nouvel
InvestigationTreeModel; - appeler
application_install_session(); - transférer la propriété uniquement en cas de succès.
Règle de propriété
Avant application_install_session() :
la fonction possède new_session
la fonction possède new_tree_model
Après succès :
Application possède new_session
Application possède new_tree_model
Après échec :
la fonction doit libérer les objets qu’elle possède encore
Validation de GError
La fonction doit respecter la convention GLib :
g_return_val_if_fail(
error == NULL || *error == NULL,
FALSE
);
L’utilisation de g_return_val_if_fail() est acceptable ici pour vérifier le contrat du développeur.
Les erreurs utilisateur doivent être produites avec :
g_set_error()
g_set_error_literal()
g_propagate_prefixed_error()
3. Propager l’erreur de InvestigationSession
Si :
investigation_session_open()
échoue, la fonction doit conserver l’erreur métier d’origine et lui ajouter du contexte.
Exemple conceptuel :
Impossible d’ouvrir l’enquête : la base SQLite est absente
Ne pas remplacer l’erreur précise par un simple :
Erreur inconnue
lorsqu’un GError est disponible.
4. Refactoriser l’ouverture d’une enquête existante
application_on_folder_selected() ne doit plus contenir directement :
investigation_session_open()
investigation_tree_builder_build()
application_install_session()
Elle doit seulement :
- accepter l’annulation ;
- appeler
application_open_and_install_investigation(); - journaliser l’erreur ;
- libérer le
GError.
Structure attendue :
static void application_on_folder_selected(
const char *folder_path,
gpointer user_data
)
{
Application *application = user_data;
GError *error = NULL;
if (application == NULL ||
folder_path == NULL)
{
return;
}
if (!application_open_and_install_investigation(
application,
folder_path,
&error
))
{
g_warning(
"Impossible d'ouvrir l'enquête '%s' : %s",
folder_path,
error != NULL
? error->message
: "erreur inconnue"
);
g_clear_error(&error);
}
}
L’annulation ne doit pas produire de warning.
5. Refactoriser la création d’une enquête
application_on_create_investigation() doit conserver uniquement :
- la création physique du projet ;
- l’appel à la fonction factorisée ;
- le message spécifique indiquant que le projet existe sur le disque si son ouverture échoue.
Le flux devient :
investigation_project_create()
→ application_open_and_install_investigation()
La fonction ne doit plus reconstruire elle-même :
session
projet
chemin canonique
arbre
installation
En cas d’échec après création, le dossier créé reste volontairement sur le disque.
Le message doit être explicite :
L’enquête a été créée dans « ... », mais son ouverture a échoué : ...
6. Ne pas modifier application_install_session()
Cette fonction conserve sa responsabilité actuelle :
- valider les objets prêts à installer ;
- libérer l’ancien état ;
- transférer la propriété ;
- mettre à jour
MainWindow.
Le nouveau helper prépare les objets.
application_install_session() réalise le remplacement final.
Pseudo-code de la fonction factorisée
static gboolean application_open_and_install_investigation(
Application *application,
const char *root_path,
GError **error
)
{
InvestigationSession *new_session = NULL;
InvestigationTreeModel *new_tree_model = NULL;
const InvestigationProject *project = NULL;
const char *canonical_root_path = NULL;
GError *session_error = NULL;
valider les arguments;
new_session = investigation_session_open(
root_path,
&session_error
);
si échec :
propager session_error avec contexte;
return FALSE;
project = investigation_session_get_project(
new_session
);
valider project;
canonical_root_path =
investigation_project_get_root_path(project);
valider canonical_root_path;
new_tree_model =
investigation_tree_builder_build(
canonical_root_path
);
si échec :
produire GError;
fermer new_session;
return FALSE;
si application_install_session() échoue :
produire GError;
libérer new_tree_model;
fermer new_session;
return FALSE;
return TRUE;
}
Tests manuels
Création valide
- lancer l’application ;
- créer une enquête ;
- vérifier le titre ;
- vérifier la barre d’état ;
- vérifier l’arborescence.
Ouverture valide
- fermer et relancer ;
- ouvrir l’enquête créée ;
- vérifier le même résultat.
Remplacement valide
- ouvrir une enquête A ;
- ouvrir une enquête B ;
- vérifier que B remplace A.
Échec d’ouverture
- ouvrir une enquête valide A ;
- tenter d’ouvrir un dossier invalide ;
- vérifier que A reste active ;
- vérifier que l’erreur est journalisée.
Échec après création
Provoquer si possible un échec d’ouverture après création.
Vérifier :
- le dossier créé reste présent ;
- l’ancienne session reste active ;
- aucun double
free; - aucun crash.
Annulation
Annuler le sélecteur de dossier.
Vérifier :
- aucun warning ;
- aucun changement d’état ;
- aucun crash.
Critères d’acceptation
- Une seule fonction ouvre une session et construit son arbre.
- La création utilise cette fonction.
- L’ouverture utilise cette fonction.
application_install_session()n’est pas dupliquée.- L’ancienne session reste active en cas d’échec.
- L’ancien arbre reste actif en cas d’échec.
- Les nouveaux objets sont libérés en cas d’échec.
- Les erreurs de
InvestigationSessionsont propagées. - L’annulation ne produit pas d’erreur.
- Aucun code SQLite direct n’est ajouté.
- Aucun comportement GTK visible n’est cassé.
makeréussit.make testréussit.git diff --checkne retourne aucune erreur.
Audit attendu
La logique d’ouverture ne doit apparaître qu’une seule fois :
rg -n \
'investigation_session_open|investigation_tree_builder_build' \
src/core/application.c
Résultat attendu :
une occurrence de investigation_session_open
une occurrence de investigation_tree_builder_build
La création et l’ouverture doivent appeler le helper :
rg -n \
'application_open_and_install_investigation' \
src/core/application.c
Vérifier l’absence de SQLite direct :
rg -n \
'sqlite3_|#include <sqlite3.h>' \
src/core/application.c
Résultat attendu :
aucune sortie
Vérifier le format :
git diff --check
Fichiers concernés
src/core/application.c
Aucune modification publique n’est normalement nécessaire dans :
include/core/application.h
Commit attendu
make clean
make
make test
git diff --check
git status --short
git add src/core/application.c
git diff --cached --stat
git diff --cached
git commit -m "refactor(core): centralize investigation loading"
git push
Résultat attendu
Après ce ticket, tous les futurs points d’entrée utiliseront le même flux :
Création
Ouverture manuelle
Enquêtes récentes
Ligne de commande
Restauration de session
↓
application_open_and_install_investigation()
Le ticket #033 pourra ensuite afficher graphiquement les GError déjà correctement produits par ce flux.