feat(core): create investigation node

This commit is contained in:
grayTerminal-sh 2026-07-13 00:38:11 +02:00
parent b1f931d8f2
commit 1686194c1a
6 changed files with 443 additions and 0 deletions

View file

@ -0,0 +1,184 @@
# Ticket #007
## Titre
Créer le module `InvestigationNode`.
---
## Objectif
Créer une structure métier représentant un élément de l'arborescence d'une enquête.
Un nœud peut représenter :
- un dossier ;
- un fichier.
Ce module servira de base au futur modèle d'arborescence.
---
## Responsabilités
Le module `InvestigationNode` doit :
- mémoriser le nom d'un élément ;
- mémoriser son type ;
- gérer sa propre mémoire ;
- exposer ses informations en lecture seule.
---
## Hors périmètre
Ce ticket ne doit pas :
- parcourir le système de fichiers ;
- construire une arborescence complète ;
- stocker des enfants ;
- afficher quoi que ce soit avec GTK ;
- communiquer avec SQLite ;
- ouvrir une enquête.
---
## Architecture
```text
InvestigationTreeModel
└── InvestigationNode
```
Le module appartient à la couche `core`.
Il ne doit contenir aucune dépendance vers GTK.
---
## Fichiers concernés
```text
include/core/investigation_node.h
src/core/investigation_node.c
```
---
## Type attendu
```c
typedef enum
{
INVESTIGATION_NODE_DIRECTORY,
INVESTIGATION_NODE_FILE
} InvestigationNodeType;
```
---
## Interface publique attendue
```c
InvestigationNode *investigation_node_new(
const char *name,
InvestigationNodeType type
);
void investigation_node_free(
InvestigationNode *node
);
const char *investigation_node_get_name(
const InvestigationNode *node
);
InvestigationNodeType investigation_node_get_type(
const InvestigationNode *node
);
```
---
## Comportement attendu
Exemple d'utilisation :
```c
InvestigationNode *node = NULL;
node = investigation_node_new(
"01_Preuves_Originales",
INVESTIGATION_NODE_DIRECTORY
);
if (node == NULL)
{
/* Gestion de l'erreur */
}
const char *name = investigation_node_get_name(node);
InvestigationNodeType type = investigation_node_get_type(node);
investigation_node_free(node);
```
---
## Cas à gérer
- nom valide ;
- nom vide ;
- pointeur `NULL` ;
- type dossier ;
- type fichier ;
- libération avec `NULL`.
---
## Contraintes techniques
- C17 ;
- structure opaque ;
- aucun état global ;
- aucune dépendance GTK ;
- documentation Doxygen ;
- compilation sans warning ;
- noms conformes à `DEVELOPMENT.md`.
---
## Critères d'acceptation
- [ ] Le projet compile sans warning.
- [ ] La structure `InvestigationNode` est opaque.
- [ ] Un nœud peut représenter un fichier.
- [ ] Un nœud peut représenter un dossier.
- [ ] Le nom est copié et possédé par le nœud.
- [ ] Les getters retournent des données en lecture seule.
- [ ] `investigation_node_free(NULL)` est accepté.
- [ ] Aucun code GTK.
- [ ] Aucun code SQLite.
- [ ] Les fonctions publiques sont documentées avec Doxygen.
---
## Tests
- créer un nœud dossier ;
- créer un nœud fichier ;
- lire le nom ;
- lire le type ;
- tester un nom vide ;
- tester un nom `NULL` ;
- libérer un nœud valide ;
- appeler `investigation_node_free(NULL)`.
---
## Commit attendu
```text
feat(core): create investigation node
```

View file

@ -0,0 +1,80 @@
/******************************************************************************
* @file investigation_node.h
* @brief Interface publique d'un nœud de l'arborescence d'une enquête.
******************************************************************************/
#ifndef LABFY_INVESTIGATION_INVESTIGATION_NODE_H
#define LABFY_INVESTIGATION_INVESTIGATION_NODE_H
/**
* @brief Représentation opaque d'un nœud d'enquête.
*
* La structure réelle est définie dans investigation_node.c.
* Les autres modules manipulent uniquement un pointeur vers
* InvestigationNode.
*/
typedef struct InvestigationNode InvestigationNode;
/**
* @brief Type d'un nœud de l'arborescence.
*/
typedef enum
{
INVESTIGATION_NODE_DIRECTORY,
INVESTIGATION_NODE_FILE
} InvestigationNodeType;
/**
* @brief Crée un nouveau nœud d'enquête.
*
* Le nom fourni est copié. Le code appelant peut donc modifier ou libérer
* sa chaîne après l'appel sans affecter le nœud.
*
* @param name Nom du fichier ou du dossier.
* @param type Type du nœud.
*
* @return Un nouveau nœud, ou NULL si le nom est invalide ou si la création
* échoue.
*/
InvestigationNode *investigation_node_new(
const char *name,
InvestigationNodeType type
);
/**
* @brief Libère les ressources associées à un nœud.
*
* Cette fonction accepte NULL.
*
* @param node Nœud à libérer.
*/
void investigation_node_free(
InvestigationNode *node
);
/**
* @brief Retourne le nom du nœud.
*
* La chaîne retournée appartient au nœud et ne doit pas être modifiée
* ni libérée par le code appelant.
*
* @param node Nœud à consulter.
*
* @return Le nom en lecture seule, ou NULL si node vaut NULL.
*/
const char *investigation_node_get_name(
const InvestigationNode *node
);
/**
* @brief Retourne le type du nœud.
*
* @param node Nœud à consulter.
*
* @return Le type du nœud.
*/
InvestigationNodeType investigation_node_get_type(
const InvestigationNode *node
);
#endif

View file

@ -0,0 +1,91 @@
/******************************************************************************
* @file investigation_node.c
* @brief Implémentation d'un nœud d'enquête.
******************************************************************************/
#include "core/investigation_node.h"
#include <glib.h>
/**
* @struct InvestigationNode
* @brief Représentation interne d'un nœud.
*/
struct InvestigationNode
{
char *name;
InvestigationNodeType type;
};
InvestigationNode *investigation_node_new(
const char *name,
InvestigationNodeType type
)
{
InvestigationNode *node = NULL;
if (name == NULL || name[0] == '\0')
{
return NULL;
}
node = g_new0(
InvestigationNode,
1
);
if (node == NULL)
{
return NULL;
}
node->name = g_strdup(name);
if (node->name == NULL)
{
investigation_node_free(node);
return NULL;
}
node->type = type;
return node;
}
void investigation_node_free(
InvestigationNode *node
)
{
if (node == NULL)
{
return;
}
g_free(node->name);
g_free(node);
}
const char *investigation_node_get_name(
const InvestigationNode *node
)
{
if (node == NULL)
{
return NULL;
}
return node->name;
}
InvestigationNodeType investigation_node_get_type(
const InvestigationNode *node
)
{
if (node == NULL)
{
return INVESTIGATION_NODE_FILE;
}
return node->type;
}

Binary file not shown.

View file

@ -0,0 +1,88 @@
/******************************************************************************
* @file test_investigation_node.c
* @brief Tests du module InvestigationNode.
******************************************************************************/
#include "core/investigation_node.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
static void test_directory_node(void)
{
InvestigationNode *node = NULL;
node = investigation_node_new(
"01_Preuves_Originales",
INVESTIGATION_NODE_DIRECTORY
);
assert(node != NULL);
assert(strcmp(
investigation_node_get_name(node),
"01_Preuves_Originales"
) == 0);
assert(
investigation_node_get_type(node) ==
INVESTIGATION_NODE_DIRECTORY
);
investigation_node_free(node);
}
static void test_file_node(void)
{
InvestigationNode *node = NULL;
node = investigation_node_new(
"Chronologie.md",
INVESTIGATION_NODE_FILE
);
assert(node != NULL);
assert(strcmp(
investigation_node_get_name(node),
"Chronologie.md"
) == 0);
assert(
investigation_node_get_type(node) ==
INVESTIGATION_NODE_FILE
);
investigation_node_free(node);
}
static void test_invalid_names(void)
{
assert(
investigation_node_new(
NULL,
INVESTIGATION_NODE_FILE
) == NULL
);
assert(
investigation_node_new(
"",
INVESTIGATION_NODE_FILE
) == NULL
);
}
static void test_null_free(void)
{
investigation_node_free(NULL);
}
int main(void)
{
test_directory_node();
test_file_node();
test_invalid_names();
test_null_free();
printf("InvestigationNode : tous les tests sont valides.\n");
return 0;
}