diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index c5f76f9..7def7f6 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -639,6 +639,41 @@ Lorsque plusieurs solutions existent, la préférence est donnée à celle qui f --- +## Gestion de la mémoire + +Le projet applique une règle unique concernant la propriété des ressources. + +> Le propriétaire crée. +> Le propriétaire détruit. + +Lorsqu'une ressource est transmise à un objet qui en devient propriétaire, le code appelant ne doit plus la libérer. + +Chaque module est responsable uniquement des ressources qu'il possède. + +Cette règle s'applique à toutes les structures du projet. + +--- + +## Bibliothèques autorisées + +Le projet privilégie les bibliothèques éprouvées plutôt que des réimplémentations. + +### Couche Core + +Autorisé : + +- Langage C17 +- GLib +- SQLite + +Interdit : + +- GTK + +Les structures de données fournies par GLib (GPtrArray, GHashTable, GList, etc.) doivent être privilégiées lorsqu'elles répondent au besoin du projet. + +--- + # Branche principale La branche `main` est toujours stable. diff --git a/docs/tickets/closed/TICKET-008.md b/docs/tickets/closed/TICKET-008.md new file mode 100644 index 0000000..11cb581 --- /dev/null +++ b/docs/tickets/closed/TICKET-008.md @@ -0,0 +1,158 @@ +# Ticket #008 + +## Titre + +Créer le module `InvestigationTreeModel`. + +--- + +## Objectif + +Créer une structure métier représentant le modèle de l'arborescence d'une enquête. + +Le modèle sera propriétaire du nœud racine et servira de base au futur explorateur d'enquête. + +--- + +## Responsabilités + +Le module `InvestigationTreeModel` doit : + +- posséder un nœud racine ; +- gérer le cycle de vie du modèle ; +- exposer le nœud racine en lecture seule. + +--- + +## Hors périmètre + +Ce ticket ne doit pas : + +- parcourir le système de fichiers ; +- créer les enfants d'un nœud ; +- afficher une interface GTK ; +- communiquer avec SQLite ; +- charger une enquête. + +--- + +## Architecture + +```text +Investigation + │ + ▼ +InvestigationTreeModel + │ + ▼ +InvestigationNode +``` + +Le module appartient à la couche **Core**. + +Aucune dépendance vers GTK. + +--- + +## Principe de propriété + +Le module est **propriétaire** du nœud racine. + +À partir du moment où un `InvestigationNode` est transmis au constructeur : + +```c +investigation_tree_model_new(root_node); +``` + +le modèle devient responsable de sa destruction. + +Le code appelant ne doit plus appeler : + +```c +investigation_node_free(root_node); +``` + +La destruction du modèle doit automatiquement détruire son nœud racine. + +--- + +## Fichiers concernés + +```text +include/core/investigation_tree_model.h +src/core/investigation_tree_model.c +``` + +--- + +## Interface publique attendue + +```c +InvestigationTreeModel *investigation_tree_model_new( + InvestigationNode *root_node +); + +void investigation_tree_model_free( + InvestigationTreeModel *tree_model +); + +const InvestigationNode *investigation_tree_model_get_root( + const InvestigationTreeModel *tree_model +); +``` + +--- + +## Comportement attendu + +Le modèle contient uniquement un nœud racine. + +Exemple : + +```text +Template +``` + +Les enfants seront ajoutés dans un ticket ultérieur. + +--- + +## Contraintes techniques + +- C17 +- Structure opaque +- Aucun état global +- Aucune dépendance GTK +- Documentation Doxygen +- Compilation sans warning +- Respect des conventions du projet + +--- + +## Critères d'acceptation + +- [ ] Le projet compile sans warning. +- [ ] Le modèle est opaque. +- [ ] Le modèle possède un nœud racine. +- [ ] Le getter retourne le nœud racine. +- [ ] La destruction du modèle détruit également le nœud racine. +- [ ] Aucun code GTK. +- [ ] Aucun code SQLite. + +--- + +## Tests + +- création d'un modèle valide ; +- lecture du nœud racine ; +- destruction du modèle ; +- création avec un nœud NULL ; +- destruction avec NULL. + +--- + +## Commit attendu + +```text +feat(core): create investigation tree model +``` diff --git a/labfy-investigation/include/core/investigation_tree_model.h b/labfy-investigation/include/core/investigation_tree_model.h new file mode 100644 index 0000000..af5754e --- /dev/null +++ b/labfy-investigation/include/core/investigation_tree_model.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * @file investigation_tree_model.h + * @brief Interface publique du modèle d'arborescence d'une enquête. + ******************************************************************************/ + +#ifndef LABFY_INVESTIGATION_INVESTIGATION_TREE_MODEL_H +#define LABFY_INVESTIGATION_INVESTIGATION_TREE_MODEL_H + +#include "core/investigation_node.h" + +/** + * @brief Représentation opaque du modèle d'arborescence. + * + * La structure réelle est définie dans investigation_tree_model.c. + * Les autres modules manipulent uniquement un pointeur vers + * InvestigationTreeModel. + */ +typedef struct InvestigationTreeModel InvestigationTreeModel; + +/** + * @brief Crée un nouveau modèle d'arborescence. + * + * Le modèle devient propriétaire de root_node après cet appel. + * Le code appelant ne doit donc plus libérer root_node directement. + * + * @param root_node Nœud racine transféré au modèle. + * + * @return Un nouveau modèle, ou NULL si root_node vaut NULL + * ou si la création échoue. + */ +InvestigationTreeModel *investigation_tree_model_new( + InvestigationNode *root_node +); + +/** + * @brief Libère le modèle et le nœud racine qu'il possède. + * + * Cette fonction accepte NULL. + * + * @param tree_model Modèle à libérer. + */ +void investigation_tree_model_free( + InvestigationTreeModel *tree_model +); + +/** + * @brief Retourne le nœud racine du modèle. + * + * Le pointeur retourné appartient toujours au modèle. + * Il ne doit être ni modifié ni libéré par le code appelant. + * + * @param tree_model Modèle à consulter. + * + * @return Nœud racine en lecture seule, ou NULL si tree_model vaut NULL. + */ +const InvestigationNode *investigation_tree_model_get_root( + const InvestigationTreeModel *tree_model +); + +#endif diff --git a/labfy-investigation/src/core/investigation_tree_model.c b/labfy-investigation/src/core/investigation_tree_model.c new file mode 100644 index 0000000..d450cc6 --- /dev/null +++ b/labfy-investigation/src/core/investigation_tree_model.c @@ -0,0 +1,76 @@ +/****************************************************************************** + * @file investigation_tree_model.c + * @brief Implémentation du modèle d'arborescence d'une enquête. + ******************************************************************************/ + +#include "core/investigation_tree_model.h" + +#include + +/** + * @struct InvestigationTreeModel + * @brief Représentation interne du modèle. + */ +struct InvestigationTreeModel +{ + InvestigationNode *root_node; +}; + +InvestigationTreeModel *investigation_tree_model_new( + InvestigationNode *root_node +) +{ + InvestigationTreeModel *tree_model = NULL; + + if (root_node == NULL) + { + return NULL; + } + + tree_model = g_new0( + InvestigationTreeModel, + 1 + ); + + if (tree_model == NULL) + { + return NULL; + } + + /* + * Ownership transferred. + * + * Le modèle devient propriétaire du nœud racine. + */ + tree_model->root_node = root_node; + + return tree_model; +} + +void investigation_tree_model_free( + InvestigationTreeModel *tree_model +) +{ + if (tree_model == NULL) + { + return; + } + + investigation_node_free( + tree_model->root_node + ); + + g_free(tree_model); +} + +const InvestigationNode *investigation_tree_model_get_root( + const InvestigationTreeModel *tree_model +) +{ + if (tree_model == NULL) + { + return NULL; + } + + return tree_model->root_node; +} diff --git a/labfy-investigation/tests/test_investigation_tree_model b/labfy-investigation/tests/test_investigation_tree_model new file mode 100755 index 0000000..e88c7dc Binary files /dev/null and b/labfy-investigation/tests/test_investigation_tree_model differ diff --git a/labfy-investigation/tests/test_investigation_tree_model.c b/labfy-investigation/tests/test_investigation_tree_model.c new file mode 100644 index 0000000..5a295e4 --- /dev/null +++ b/labfy-investigation/tests/test_investigation_tree_model.c @@ -0,0 +1,90 @@ +/****************************************************************************** + * @file test_investigation_tree_model.c + * @brief Tests du module InvestigationTreeModel. + ******************************************************************************/ + +#include "core/investigation_node.h" +#include "core/investigation_tree_model.h" + +#include +#include +#include + +/** + * @brief Vérifie la création d'un modèle valide. + */ +static void test_tree_model_creation(void) +{ + InvestigationNode *root_node = NULL; + InvestigationTreeModel *tree_model = NULL; + const InvestigationNode *returned_node = NULL; + + root_node = investigation_node_new( + "Template", + INVESTIGATION_NODE_DIRECTORY + ); + + assert(root_node != NULL); + + tree_model = investigation_tree_model_new(root_node); + + assert(tree_model != NULL); + + returned_node = investigation_tree_model_get_root(tree_model); + + assert(returned_node != NULL); + + assert( + strcmp( + investigation_node_get_name(returned_node), + "Template" + ) == 0 + ); + + assert( + investigation_node_get_type(returned_node) == + INVESTIGATION_NODE_DIRECTORY + ); + + /* + * tree_model est propriétaire de root_node. + */ + investigation_tree_model_free(tree_model); +} + +/** + * @brief Vérifie les paramètres invalides. + */ +static void test_invalid_parameters(void) +{ + assert( + investigation_tree_model_new(NULL) == NULL + ); + + assert( + investigation_tree_model_get_root(NULL) == NULL + ); +} + +/** + * @brief Vérifie que free(NULL) est accepté. + */ +static void test_null_free(void) +{ + investigation_tree_model_free(NULL); +} + +int main(void) +{ + test_tree_model_creation(); + + test_invalid_parameters(); + + test_null_free(); + + printf( + "InvestigationTreeModel : tous les tests sont valides.\n" + ); + + return 0; +}