feat(core): add investigation session loader
This commit is contained in:
parent
137e75722d
commit
4efdfe4865
12 changed files with 2382 additions and 24 deletions
21
Makefile
21
Makefile
|
|
@ -39,6 +39,7 @@ TEST_TRANSACTION = tests/test_transaction
|
||||||
TEST_ERROR = tests/test_error
|
TEST_ERROR = tests/test_error
|
||||||
TEST_INVESTIGATION_RECORD = tests/test_investigation_record
|
TEST_INVESTIGATION_RECORD = tests/test_investigation_record
|
||||||
TEST_INVESTIGATION_DAO := tests/test_investigation_dao
|
TEST_INVESTIGATION_DAO := tests/test_investigation_dao
|
||||||
|
TEST_INVESTIGATION_SESSION := tests/test_investigation_session
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -123,6 +124,19 @@ $(TEST_INVESTIGATION_DAO): \
|
||||||
src/database/error.c
|
src/database/error.c
|
||||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
|
$(TEST_INVESTIGATION_SESSION): \
|
||||||
|
tests/test_investigation_session.c \
|
||||||
|
src/core/investigation_session.c \
|
||||||
|
src/core/investigation_project.c \
|
||||||
|
src/dao/investigation_dao.c \
|
||||||
|
src/models/investigation_record.c \
|
||||||
|
src/database/database.c \
|
||||||
|
src/database/schema.c \
|
||||||
|
src/database/statement.c \
|
||||||
|
src/database/transaction.c \
|
||||||
|
src/database/error.c
|
||||||
|
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
test: \
|
test: \
|
||||||
$(TEST_NODE) \
|
$(TEST_NODE) \
|
||||||
$(TEST_TREE_MODEL) \
|
$(TEST_TREE_MODEL) \
|
||||||
|
|
@ -133,7 +147,8 @@ test: \
|
||||||
$(TEST_TRANSACTION) \
|
$(TEST_TRANSACTION) \
|
||||||
$(TEST_ERROR) \
|
$(TEST_ERROR) \
|
||||||
$(TEST_INVESTIGATION_RECORD) \
|
$(TEST_INVESTIGATION_RECORD) \
|
||||||
$(TEST_INVESTIGATION_DAO)
|
$(TEST_INVESTIGATION_DAO) \
|
||||||
|
$(TEST_INVESTIGATION_SESSION)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -145,6 +160,7 @@ test: \
|
||||||
@$(TEST_ERROR)
|
@$(TEST_ERROR)
|
||||||
@$(TEST_INVESTIGATION_RECORD)
|
@$(TEST_INVESTIGATION_RECORD)
|
||||||
@$(TEST_INVESTIGATION_DAO)
|
@$(TEST_INVESTIGATION_DAO)
|
||||||
|
@$(TEST_INVESTIGATION_SESSION)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -164,6 +180,7 @@ clean:
|
||||||
$(TEST_TRANSACTION) \
|
$(TEST_TRANSACTION) \
|
||||||
$(TEST_ERROR) \
|
$(TEST_ERROR) \
|
||||||
$(TEST_INVESTIGATION_RECORD) \
|
$(TEST_INVESTIGATION_RECORD) \
|
||||||
$(TEST_INVESTIGATION_DAO)
|
$(TEST_INVESTIGATION_DAO) \
|
||||||
|
$(TEST_INVESTIGATION_SESSION)
|
||||||
|
|
||||||
.PHONY: clean run test
|
.PHONY: clean run test
|
||||||
|
|
|
||||||
776
docs/tickets/open/TICKET-028.md
Normal file
776
docs/tickets/open/TICKET-028.md
Normal file
|
|
@ -0,0 +1,776 @@
|
||||||
|
# Ticket #028 — Ajouter l’ouverture d’une enquête existante
|
||||||
|
|
||||||
|
## Contexte
|
||||||
|
|
||||||
|
Les tickets précédents ont permis de mettre en place :
|
||||||
|
|
||||||
|
- la création transactionnelle d’une base d’enquête ;
|
||||||
|
- la couche `Database` ;
|
||||||
|
- les requêtes préparées `DatabaseStatement` ;
|
||||||
|
- la gestion des transactions et des erreurs ;
|
||||||
|
- le modèle `InvestigationRecord` ;
|
||||||
|
- le DAO `InvestigationDao` permettant de charger l’unique ligne de la table `investigation`.
|
||||||
|
|
||||||
|
Le projet possède également un type `InvestigationProject` chargé de représenter les chemins du projet sur le système de fichiers, notamment :
|
||||||
|
|
||||||
|
- le dossier racine de l’enquête ;
|
||||||
|
- le chemin du fichier `Enquete.sqlite`.
|
||||||
|
|
||||||
|
Cependant, l’application ne possède pas encore d’objet représentant une enquête réellement ouverte pendant son exécution.
|
||||||
|
|
||||||
|
Les différentes ressources sont encore séparées :
|
||||||
|
|
||||||
|
```text
|
||||||
|
InvestigationProject
|
||||||
|
Database
|
||||||
|
InvestigationRecord
|
||||||
|
```
|
||||||
|
|
||||||
|
Il faut désormais les regrouper dans un contexte cohérent dont la durée de vie correspond à celle d’une enquête ouverte.
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Créer un type opaque `InvestigationSession` chargé d’ouvrir une enquête existante et de conserver :
|
||||||
|
|
||||||
|
- son contexte de fichiers `InvestigationProject` ;
|
||||||
|
- sa connexion `Database` ;
|
||||||
|
- ses informations persistées `InvestigationRecord`.
|
||||||
|
|
||||||
|
L’ouverture doit vérifier que le dossier sélectionné correspond bien aux informations enregistrées dans la base SQLite.
|
||||||
|
|
||||||
|
La connexion SQLite doit rester ouverte pendant toute la durée de vie de la session afin de permettre les futurs appels aux DAO.
|
||||||
|
|
||||||
|
## Architecture attendue
|
||||||
|
|
||||||
|
```text
|
||||||
|
Application
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
InvestigationSession
|
||||||
|
├── InvestigationProject
|
||||||
|
├── Database
|
||||||
|
└── InvestigationRecord
|
||||||
|
▲
|
||||||
|
│
|
||||||
|
InvestigationDao
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
DatabaseStatement
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
SQLite
|
||||||
|
```
|
||||||
|
|
||||||
|
## Travail à réaliser
|
||||||
|
|
||||||
|
### 1. Créer le type `InvestigationSession`
|
||||||
|
|
||||||
|
Créer les fichiers :
|
||||||
|
|
||||||
|
```text
|
||||||
|
include/core/investigation_session.h
|
||||||
|
src/core/investigation_session.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Le type doit être opaque :
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct InvestigationSession InvestigationSession;
|
||||||
|
```
|
||||||
|
|
||||||
|
Sa représentation privée doit contenir au minimum :
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct InvestigationSession
|
||||||
|
{
|
||||||
|
InvestigationProject *project;
|
||||||
|
Database *database;
|
||||||
|
InvestigationRecord *record;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Le header public ne doit pas exposer cette structure.
|
||||||
|
|
||||||
|
### 2. Définir les erreurs d’ouverture
|
||||||
|
|
||||||
|
Créer une énumération dédiée :
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND,
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND,
|
||||||
|
INVESTIGATION_SESSION_ERROR_PROJECT,
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE,
|
||||||
|
INVESTIGATION_SESSION_ERROR_RECORD,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH,
|
||||||
|
INVESTIGATION_SESSION_ERROR_MEMORY
|
||||||
|
} InvestigationSessionError;
|
||||||
|
```
|
||||||
|
|
||||||
|
Définir un domaine d’erreur GLib :
|
||||||
|
|
||||||
|
```c
|
||||||
|
#define INVESTIGATION_SESSION_ERROR \
|
||||||
|
investigation_session_error_quark()
|
||||||
|
|
||||||
|
GQuark investigation_session_error_quark(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
Les erreurs doivent être transmises avec un paramètre :
|
||||||
|
|
||||||
|
```c
|
||||||
|
GError **error
|
||||||
|
```
|
||||||
|
|
||||||
|
Lorsqu’une erreur provenant de `Database` doit être propagée, son message doit être copié dans le `GError` avant la fermeture de la connexion.
|
||||||
|
|
||||||
|
### 3. Ajouter la fonction d’ouverture
|
||||||
|
|
||||||
|
Déclarer :
|
||||||
|
|
||||||
|
```c
|
||||||
|
InvestigationSession *investigation_session_open(
|
||||||
|
const char *investigation_root_path,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
La fonction doit ouvrir une enquête déjà existante à partir de son dossier racine.
|
||||||
|
|
||||||
|
Elle ne doit pas créer une nouvelle enquête.
|
||||||
|
|
||||||
|
### 4. Valider les paramètres
|
||||||
|
|
||||||
|
La fonction doit refuser :
|
||||||
|
|
||||||
|
```text
|
||||||
|
investigation_root_path == NULL
|
||||||
|
investigation_root_path vide
|
||||||
|
```
|
||||||
|
|
||||||
|
Le code d’erreur attendu est :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT
|
||||||
|
```
|
||||||
|
|
||||||
|
Le paramètre `error` peut être `NULL`.
|
||||||
|
|
||||||
|
Si `error` n’est pas `NULL`, il doit respecter les conventions GLib :
|
||||||
|
|
||||||
|
```c
|
||||||
|
*error == NULL
|
||||||
|
```
|
||||||
|
|
||||||
|
au moment de l’appel.
|
||||||
|
|
||||||
|
### 5. Vérifier le dossier racine
|
||||||
|
|
||||||
|
Le chemin fourni doit correspondre à un dossier existant.
|
||||||
|
|
||||||
|
La fonction doit vérifier :
|
||||||
|
|
||||||
|
```c
|
||||||
|
G_FILE_TEST_IS_DIR
|
||||||
|
```
|
||||||
|
|
||||||
|
Un chemin inexistant ou qui ne représente pas un dossier doit produire :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND
|
||||||
|
```
|
||||||
|
|
||||||
|
Le chemin doit être normalisé avec :
|
||||||
|
|
||||||
|
```c
|
||||||
|
g_canonicalize_filename()
|
||||||
|
```
|
||||||
|
|
||||||
|
La session doit travailler à partir de ce chemin canonique.
|
||||||
|
|
||||||
|
### 6. Construire `InvestigationProject`
|
||||||
|
|
||||||
|
Réutiliser l’API existante de `InvestigationProject`.
|
||||||
|
|
||||||
|
La logique de construction du chemin de la base ne doit pas être dupliquée dans `InvestigationSession`.
|
||||||
|
|
||||||
|
Le chemin attendu reste géré par `InvestigationProject` :
|
||||||
|
|
||||||
|
```text
|
||||||
|
<racine>/00_BaseDeDonnees/Enquete.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
Si l’API actuelle de `InvestigationProject` ne permet pas de représenter un projet existant, elle peut être étendue de manière minimale.
|
||||||
|
|
||||||
|
Aucune logique SQLite ne doit être ajoutée dans `InvestigationProject`.
|
||||||
|
|
||||||
|
### 7. Vérifier le fichier SQLite
|
||||||
|
|
||||||
|
Avant l’ouverture de la connexion, vérifier que le chemin retourné par `InvestigationProject` correspond à un fichier régulier :
|
||||||
|
|
||||||
|
```c
|
||||||
|
G_FILE_TEST_IS_REGULAR
|
||||||
|
```
|
||||||
|
|
||||||
|
Si le fichier n’existe pas, retourner :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND
|
||||||
|
```
|
||||||
|
|
||||||
|
L’ouverture d’une enquête existante ne doit jamais créer silencieusement une nouvelle base vide.
|
||||||
|
|
||||||
|
### 8. Ouvrir la connexion Database
|
||||||
|
|
||||||
|
Utiliser :
|
||||||
|
|
||||||
|
```c
|
||||||
|
database_open()
|
||||||
|
```
|
||||||
|
|
||||||
|
La fonction `investigation_session_open()` ne doit pas appeler directement :
|
||||||
|
|
||||||
|
```c
|
||||||
|
sqlite3_open()
|
||||||
|
sqlite3_open_v2()
|
||||||
|
sqlite3_close()
|
||||||
|
```
|
||||||
|
|
||||||
|
Si `database_open()` échoue, retourner :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE
|
||||||
|
```
|
||||||
|
|
||||||
|
La connexion doit rester ouverte si la session est créée avec succès.
|
||||||
|
|
||||||
|
### 9. Charger l’enquête persistée
|
||||||
|
|
||||||
|
Utiliser :
|
||||||
|
|
||||||
|
```c
|
||||||
|
investigation_dao_load()
|
||||||
|
```
|
||||||
|
|
||||||
|
Le DAO doit retourner un `InvestigationRecord`.
|
||||||
|
|
||||||
|
Si le chargement échoue :
|
||||||
|
|
||||||
|
- récupérer le code et le message de la dernière erreur `Database` ;
|
||||||
|
- copier le message dans un `GError` ;
|
||||||
|
- retourner `NULL` ;
|
||||||
|
- fermer proprement la connexion ;
|
||||||
|
- libérer le projet ;
|
||||||
|
- ne laisser aucune ressource allouée.
|
||||||
|
|
||||||
|
Le code d’erreur de session attendu est :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_RECORD
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10. Vérifier la cohérence du chemin racine
|
||||||
|
|
||||||
|
Le chemin sélectionné doit correspondre au champ persistant :
|
||||||
|
|
||||||
|
```text
|
||||||
|
investigation.root_path
|
||||||
|
```
|
||||||
|
|
||||||
|
Comparer les versions canoniques de :
|
||||||
|
|
||||||
|
```text
|
||||||
|
chemin racine sélectionné
|
||||||
|
chemin racine enregistré dans InvestigationRecord
|
||||||
|
```
|
||||||
|
|
||||||
|
La comparaison doit être faite après normalisation avec :
|
||||||
|
|
||||||
|
```c
|
||||||
|
g_canonicalize_filename()
|
||||||
|
```
|
||||||
|
|
||||||
|
Si les chemins ne correspondent pas, l’ouverture doit échouer avec :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette vérification évite d’ouvrir une base copiée ou déplacée sans détecter l’incohérence.
|
||||||
|
|
||||||
|
Le déplacement volontaire d’une enquête sera traité dans un ticket distinct.
|
||||||
|
|
||||||
|
### 11. Construire la session
|
||||||
|
|
||||||
|
La session ne doit être créée qu’après validation complète :
|
||||||
|
|
||||||
|
```text
|
||||||
|
dossier racine valide
|
||||||
|
↓
|
||||||
|
InvestigationProject valide
|
||||||
|
↓
|
||||||
|
fichier SQLite présent
|
||||||
|
↓
|
||||||
|
Database ouverte
|
||||||
|
↓
|
||||||
|
InvestigationRecord chargé
|
||||||
|
↓
|
||||||
|
chemin racine cohérent
|
||||||
|
↓
|
||||||
|
InvestigationSession créée
|
||||||
|
```
|
||||||
|
|
||||||
|
En cas d’échec d’allocation, retourner :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_MEMORY
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12. Ajouter la fonction de fermeture
|
||||||
|
|
||||||
|
Déclarer :
|
||||||
|
|
||||||
|
```c
|
||||||
|
void investigation_session_close(
|
||||||
|
InvestigationSession *session
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette fonction doit accepter `NULL`.
|
||||||
|
|
||||||
|
Elle doit libérer toutes les ressources possédées par la session :
|
||||||
|
|
||||||
|
```text
|
||||||
|
InvestigationRecord
|
||||||
|
Database
|
||||||
|
InvestigationProject
|
||||||
|
InvestigationSession
|
||||||
|
```
|
||||||
|
|
||||||
|
La session devient propriétaire de ces trois objets dès que son ouverture réussit.
|
||||||
|
|
||||||
|
### 13. Ajouter les accesseurs
|
||||||
|
|
||||||
|
Ajouter :
|
||||||
|
|
||||||
|
```c
|
||||||
|
const InvestigationProject *investigation_session_get_project(
|
||||||
|
const InvestigationSession *session
|
||||||
|
);
|
||||||
|
|
||||||
|
const InvestigationRecord *investigation_session_get_record(
|
||||||
|
const InvestigationSession *session
|
||||||
|
);
|
||||||
|
|
||||||
|
Database *investigation_session_get_database(
|
||||||
|
InvestigationSession *session
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Les pointeurs retournés appartiennent à la session et ne doivent pas être libérés par l’appelant.
|
||||||
|
|
||||||
|
Les accesseurs doivent retourner `NULL` si la session reçue est `NULL`.
|
||||||
|
|
||||||
|
`Database` reste non constante car les futurs DAO auront besoin d’une connexion modifiable.
|
||||||
|
|
||||||
|
### 14. Interdire les dépendances SQLite et GTK
|
||||||
|
|
||||||
|
Le module `InvestigationSession` ne doit pas inclure :
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
```
|
||||||
|
|
||||||
|
Il doit exclusivement utiliser les abstractions existantes :
|
||||||
|
|
||||||
|
```text
|
||||||
|
InvestigationProject
|
||||||
|
Database
|
||||||
|
InvestigationDao
|
||||||
|
InvestigationRecord
|
||||||
|
GLib
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tests à ajouter
|
||||||
|
|
||||||
|
Créer :
|
||||||
|
|
||||||
|
```text
|
||||||
|
tests/test_investigation_session.c
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test d’ouverture valide
|
||||||
|
|
||||||
|
Créer un dossier temporaire.
|
||||||
|
|
||||||
|
Initialiser une base avec :
|
||||||
|
|
||||||
|
```c
|
||||||
|
database_initialize()
|
||||||
|
```
|
||||||
|
|
||||||
|
Ouvrir ensuite l’enquête avec :
|
||||||
|
|
||||||
|
```c
|
||||||
|
investigation_session_open()
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
- la session n’est pas `NULL` ;
|
||||||
|
- aucune erreur n’est produite ;
|
||||||
|
- le projet est disponible ;
|
||||||
|
- la connexion Database est disponible ;
|
||||||
|
- le record est disponible ;
|
||||||
|
- le nom de l’enquête est correct ;
|
||||||
|
- le chemin racine est correct ;
|
||||||
|
- l’UUID est valide ;
|
||||||
|
- `created_at` n’est pas vide ;
|
||||||
|
- `updated_at` n’est pas vide ;
|
||||||
|
- la connexion peut encore être utilisée par un DAO ;
|
||||||
|
- la fermeture libère correctement les ressources.
|
||||||
|
|
||||||
|
### Test des paramètres invalides
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
```c
|
||||||
|
investigation_session_open(NULL, &error) == NULL
|
||||||
|
investigation_session_open("", &error) == NULL
|
||||||
|
```
|
||||||
|
|
||||||
|
Le code attendu est :
|
||||||
|
|
||||||
|
```c
|
||||||
|
INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier également le comportement avec :
|
||||||
|
|
||||||
|
```c
|
||||||
|
error == NULL
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test d’un dossier inexistant
|
||||||
|
|
||||||
|
Utiliser un chemin inexistant.
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
```text
|
||||||
|
résultat == NULL
|
||||||
|
erreur == INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND
|
||||||
|
message non vide
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test d’un chemin qui n’est pas un dossier
|
||||||
|
|
||||||
|
Créer un fichier temporaire et utiliser son chemin comme racine.
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
```text
|
||||||
|
résultat == NULL
|
||||||
|
erreur == INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test d’une base absente
|
||||||
|
|
||||||
|
Créer une structure de projet valide sans fichier :
|
||||||
|
|
||||||
|
```text
|
||||||
|
00_BaseDeDonnees/Enquete.sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
```text
|
||||||
|
résultat == NULL
|
||||||
|
erreur == INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND
|
||||||
|
```
|
||||||
|
|
||||||
|
La fonction ne doit pas créer de nouveau fichier SQLite.
|
||||||
|
|
||||||
|
### Test d’une base invalide
|
||||||
|
|
||||||
|
Créer un fichier SQLite vide ou une base ne contenant pas la table :
|
||||||
|
|
||||||
|
```text
|
||||||
|
investigation
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
```text
|
||||||
|
résultat == NULL
|
||||||
|
erreur == INVESTIGATION_SESSION_ERROR_RECORD
|
||||||
|
message non vide
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test d’un chemin racine incohérent
|
||||||
|
|
||||||
|
Créer une base avec un chemin racine enregistré différent du dossier utilisé pour l’ouverture.
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
```text
|
||||||
|
résultat == NULL
|
||||||
|
erreur == INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH
|
||||||
|
message non vide
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test des accesseurs avec NULL
|
||||||
|
|
||||||
|
Vérifier :
|
||||||
|
|
||||||
|
```c
|
||||||
|
investigation_session_get_project(NULL) == NULL
|
||||||
|
investigation_session_get_record(NULL) == NULL
|
||||||
|
investigation_session_get_database(NULL) == NULL
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier également :
|
||||||
|
|
||||||
|
```c
|
||||||
|
investigation_session_close(NULL);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test de réutilisation du DAO
|
||||||
|
|
||||||
|
Après l’ouverture valide d’une session, appeler de nouveau :
|
||||||
|
|
||||||
|
```c
|
||||||
|
investigation_dao_load(
|
||||||
|
investigation_session_get_database(session)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier que la connexion reste fonctionnelle pendant toute la durée de vie de la session.
|
||||||
|
|
||||||
|
## Gestion de la mémoire
|
||||||
|
|
||||||
|
Toutes les sorties d’échec de `investigation_session_open()` doivent libérer les ressources déjà créées.
|
||||||
|
|
||||||
|
Le nettoyage doit couvrir les cas suivants :
|
||||||
|
|
||||||
|
```text
|
||||||
|
échec avant création du projet
|
||||||
|
échec après création du projet
|
||||||
|
échec après ouverture de Database
|
||||||
|
échec après chargement du record
|
||||||
|
échec lors de la comparaison des chemins
|
||||||
|
échec lors de l’allocation de la session
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucun objet ne doit être libéré deux fois.
|
||||||
|
|
||||||
|
Aucune ressource temporaire ne doit rester allouée :
|
||||||
|
|
||||||
|
```text
|
||||||
|
chemins canoniques
|
||||||
|
messages copiés
|
||||||
|
GError temporaires
|
||||||
|
InvestigationProject
|
||||||
|
Database
|
||||||
|
InvestigationRecord
|
||||||
|
```
|
||||||
|
|
||||||
|
## Makefile
|
||||||
|
|
||||||
|
Ajouter :
|
||||||
|
|
||||||
|
```make
|
||||||
|
TEST_INVESTIGATION_SESSION := tests/test_investigation_session
|
||||||
|
```
|
||||||
|
|
||||||
|
Ajouter une règle compilant au minimum :
|
||||||
|
|
||||||
|
```text
|
||||||
|
tests/test_investigation_session.c
|
||||||
|
|
||||||
|
src/core/investigation_session.c
|
||||||
|
src/core/investigation_project.c
|
||||||
|
|
||||||
|
src/dao/investigation_dao.c
|
||||||
|
src/models/investigation_record.c
|
||||||
|
|
||||||
|
src/database/database.c
|
||||||
|
src/database/schema.c
|
||||||
|
src/database/statement.c
|
||||||
|
src/database/transaction.c
|
||||||
|
src/database/error.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Lier avec :
|
||||||
|
|
||||||
|
```text
|
||||||
|
GLib
|
||||||
|
SQLite
|
||||||
|
```
|
||||||
|
|
||||||
|
Ajouter le test aux cibles :
|
||||||
|
|
||||||
|
```text
|
||||||
|
test
|
||||||
|
clean
|
||||||
|
```
|
||||||
|
|
||||||
|
La nouvelle sortie attendue est :
|
||||||
|
|
||||||
|
```text
|
||||||
|
InvestigationSession : tous les tests sont valides.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Critères d’acceptation
|
||||||
|
|
||||||
|
- [ ] Le type `InvestigationSession` est opaque.
|
||||||
|
- [ ] Une session possède un `InvestigationProject`.
|
||||||
|
- [ ] Une session possède une connexion `Database`.
|
||||||
|
- [ ] Une session possède un `InvestigationRecord`.
|
||||||
|
- [ ] Le dossier racine est validé avant l’ouverture.
|
||||||
|
- [ ] Le chemin racine est normalisé.
|
||||||
|
- [ ] Le chemin de la base provient de `InvestigationProject`.
|
||||||
|
- [ ] Le fichier SQLite doit exister avant l’appel à `database_open()`.
|
||||||
|
- [ ] L’ouverture ne crée jamais silencieusement une nouvelle base.
|
||||||
|
- [ ] Le record est chargé avec `InvestigationDao`.
|
||||||
|
- [ ] Le chemin enregistré est comparé au chemin sélectionné.
|
||||||
|
- [ ] Une incohérence de chemin empêche l’ouverture.
|
||||||
|
- [ ] La connexion reste ouverte pendant la durée de vie de la session.
|
||||||
|
- [ ] La fermeture libère toutes les ressources.
|
||||||
|
- [ ] Les accesseurs acceptent une session `NULL`.
|
||||||
|
- [ ] Les erreurs sont propagées avec `GError`.
|
||||||
|
- [ ] Aucun type SQLite n’apparaît dans l’API de la session.
|
||||||
|
- [ ] Aucune dépendance GTK n’est ajoutée.
|
||||||
|
- [ ] Les tests d’ouverture valide sont présents.
|
||||||
|
- [ ] Les tests de paramètres invalides sont présents.
|
||||||
|
- [ ] Les tests de dossier absent sont présents.
|
||||||
|
- [ ] Les tests de base absente sont présents.
|
||||||
|
- [ ] Les tests de base invalide sont présents.
|
||||||
|
- [ ] Les tests de chemin incohérent sont présents.
|
||||||
|
- [ ] Les anciens tests restent valides.
|
||||||
|
- [ ] `make` réussit sans erreur.
|
||||||
|
- [ ] `make test` réussit.
|
||||||
|
- [ ] `git diff --check` ne retourne aucune erreur.
|
||||||
|
|
||||||
|
## Audit attendu
|
||||||
|
|
||||||
|
Les commandes suivantes ne doivent rien afficher :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rg -n 'sqlite3_|#include <sqlite3.h>|#include <gtk' \
|
||||||
|
include/core/investigation_session.h \
|
||||||
|
src/core/investigation_session.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Vérifier également que la logique du chemin SQLite n’est pas dupliquée :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rg -n '00_BaseDeDonnees|Enquete.sqlite' \
|
||||||
|
src/core/investigation_session.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Le résultat attendu est aucune occurrence, sauf éventuellement dans un commentaire de documentation justifié.
|
||||||
|
|
||||||
|
## Hors périmètre
|
||||||
|
|
||||||
|
Ce ticket ne doit pas ajouter :
|
||||||
|
|
||||||
|
- la création d’une nouvelle enquête ;
|
||||||
|
- le déplacement d’une enquête ;
|
||||||
|
- la réparation automatique d’un chemin racine incohérent ;
|
||||||
|
- la modification de `investigation.root_path` ;
|
||||||
|
- l’intégration dans la fenêtre GTK ;
|
||||||
|
- une boîte de dialogue de sélection ;
|
||||||
|
- l’affichage du nom de l’enquête ;
|
||||||
|
- les DAO des preuves, sources ou entités ;
|
||||||
|
- la fermeture demandée par l’interface utilisateur ;
|
||||||
|
- la sauvegarde automatique ;
|
||||||
|
- une migration de schéma ;
|
||||||
|
- un verrouillage multi-instance de la base.
|
||||||
|
|
||||||
|
## Fichiers principalement concernés
|
||||||
|
|
||||||
|
```text
|
||||||
|
include/core/investigation_session.h
|
||||||
|
|
||||||
|
src/core/investigation_session.c
|
||||||
|
|
||||||
|
tests/test_investigation_session.c
|
||||||
|
|
||||||
|
Makefile
|
||||||
|
```
|
||||||
|
|
||||||
|
Une adaptation limitée de ces fichiers est autorisée si nécessaire :
|
||||||
|
|
||||||
|
```text
|
||||||
|
include/core/investigation_project.h
|
||||||
|
src/core/investigation_project.c
|
||||||
|
```
|
||||||
|
|
||||||
|
## Résultat attendu
|
||||||
|
|
||||||
|
À la fin du ticket, le programme doit pouvoir ouvrir une enquête existante à partir de son dossier racine.
|
||||||
|
|
||||||
|
Une session valide doit conserver ensemble :
|
||||||
|
|
||||||
|
```text
|
||||||
|
le projet de fichiers
|
||||||
|
la connexion SQLite
|
||||||
|
les informations persistées de l’enquête
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette session deviendra le contexte principal utilisé ultérieurement par l’interface et les futurs DAO.
|
||||||
|
|
||||||
|
## Commit attendu
|
||||||
|
|
||||||
|
Une fois tous les critères d’acceptation validés :
|
||||||
|
|
||||||
|
```text
|
||||||
|
feat(core): add investigation session loader
|
||||||
|
```
|
||||||
|
|
||||||
|
Avant le commit :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make clean
|
||||||
|
make
|
||||||
|
make test
|
||||||
|
git diff --check
|
||||||
|
git status --short
|
||||||
|
```
|
||||||
|
|
||||||
|
Préparer les fichiers :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add \
|
||||||
|
Makefile \
|
||||||
|
include/core/investigation_session.h \
|
||||||
|
src/core/investigation_session.c \
|
||||||
|
tests/test_investigation_session.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Ajouter également les fichiers `InvestigationProject` uniquement s’ils ont réellement été modifiés :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add \
|
||||||
|
include/core/investigation_project.h \
|
||||||
|
src/core/investigation_project.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Contrôler le contenu préparé :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git diff --cached --stat
|
||||||
|
git diff --cached
|
||||||
|
```
|
||||||
|
|
||||||
|
Créer le commit :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git commit -m "feat(core): add investigation session loader"
|
||||||
|
```
|
||||||
|
|
||||||
|
Le push ne doit être effectué qu’après validation complète de la compilation, des tests et du contenu du commit.
|
||||||
|
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contexte opaque représentant les chemins d'un projet d'enquête.
|
||||||
|
*/
|
||||||
|
typedef struct InvestigationProject InvestigationProject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Crée une nouvelle enquête dans un dossier parent.
|
* @brief Crée une nouvelle enquête dans un dossier parent.
|
||||||
*
|
*
|
||||||
|
|
@ -15,7 +20,7 @@
|
||||||
*
|
*
|
||||||
* - le dossier racine de l'enquête ;
|
* - le dossier racine de l'enquête ;
|
||||||
* - l'arborescence standard ;
|
* - l'arborescence standard ;
|
||||||
* - le fichier vide 00_BaseDeDonnees/Enquete.sqlite.
|
* - le fichier 00_BaseDeDonnees/Enquete.sqlite.
|
||||||
*
|
*
|
||||||
* Le dossier parent doit déjà exister.
|
* Le dossier parent doit déjà exister.
|
||||||
*
|
*
|
||||||
|
|
@ -38,7 +43,7 @@ char *investigation_project_create(
|
||||||
const char *investigation_name
|
const char *investigation_name
|
||||||
);
|
);
|
||||||
|
|
||||||
/******************************************************************************
|
/**
|
||||||
* @brief Vérifie qu'un dossier est une enquête valide.
|
* @brief Vérifie qu'un dossier est une enquête valide.
|
||||||
*
|
*
|
||||||
* La fonction contrôle que tous les éléments obligatoires de la structure
|
* La fonction contrôle que tous les éléments obligatoires de la structure
|
||||||
|
|
@ -49,9 +54,62 @@ char *investigation_project_create(
|
||||||
* @param investigation_path Chemin de l'enquête à vérifier.
|
* @param investigation_path Chemin de l'enquête à vérifier.
|
||||||
*
|
*
|
||||||
* @return true si l'enquête est valide, sinon false.
|
* @return true si l'enquête est valide, sinon false.
|
||||||
******************************************************************************/
|
*/
|
||||||
bool investigation_project_validate(
|
bool investigation_project_validate(
|
||||||
const char *investigation_path
|
const char *investigation_path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée un contexte de chemins pour une enquête existante.
|
||||||
|
*
|
||||||
|
* Le chemin racine est converti en chemin canonique.
|
||||||
|
*
|
||||||
|
* Cette fonction ne crée aucun fichier et ne modifie pas le projet.
|
||||||
|
* Elle construit uniquement les chemins nécessaires à son utilisation.
|
||||||
|
*
|
||||||
|
* @param investigation_root_path Chemin racine de l'enquête.
|
||||||
|
*
|
||||||
|
* @return Un nouveau contexte InvestigationProject, ou NULL en cas d'échec.
|
||||||
|
*/
|
||||||
|
InvestigationProject *investigation_project_open(
|
||||||
|
const char *investigation_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère un contexte InvestigationProject.
|
||||||
|
*
|
||||||
|
* Cette fonction accepte NULL.
|
||||||
|
*
|
||||||
|
* @param project Contexte à libérer.
|
||||||
|
*/
|
||||||
|
void investigation_project_free(
|
||||||
|
InvestigationProject *project
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le chemin racine canonique de l'enquête.
|
||||||
|
*
|
||||||
|
* Le pointeur retourné appartient au contexte et ne doit pas être libéré.
|
||||||
|
*
|
||||||
|
* @param project Contexte du projet.
|
||||||
|
*
|
||||||
|
* @return Chemin racine, ou NULL si project vaut NULL.
|
||||||
|
*/
|
||||||
|
const char *investigation_project_get_root_path(
|
||||||
|
const InvestigationProject *project
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le chemin du fichier SQLite de l'enquête.
|
||||||
|
*
|
||||||
|
* Le pointeur retourné appartient au contexte et ne doit pas être libéré.
|
||||||
|
*
|
||||||
|
* @param project Contexte du projet.
|
||||||
|
*
|
||||||
|
* @return Chemin du fichier Enquete.sqlite, ou NULL si project vaut NULL.
|
||||||
|
*/
|
||||||
|
const char *investigation_project_get_database_path(
|
||||||
|
const InvestigationProject *project
|
||||||
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
143
include/core/investigation_session.h
Normal file
143
include/core/investigation_session.h
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file investigation_session.h
|
||||||
|
* @brief Interface publique d'une session d'enquête ouverte.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_INVESTIGATION_SESSION_H
|
||||||
|
#define LABFY_INVESTIGATION_INVESTIGATION_SESSION_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "core/investigation_project.h"
|
||||||
|
#include "database/database.h"
|
||||||
|
#include "models/investigation_record.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Session opaque représentant une enquête ouverte.
|
||||||
|
*
|
||||||
|
* Une session possède :
|
||||||
|
*
|
||||||
|
* - le contexte de fichiers InvestigationProject ;
|
||||||
|
* - la connexion Database ;
|
||||||
|
* - les informations persistées InvestigationRecord.
|
||||||
|
*/
|
||||||
|
typedef struct InvestigationSession InvestigationSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Codes d'erreur produits lors de l'ouverture d'une session.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND,
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND,
|
||||||
|
INVESTIGATION_SESSION_ERROR_PROJECT,
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE,
|
||||||
|
INVESTIGATION_SESSION_ERROR_RECORD,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH,
|
||||||
|
INVESTIGATION_SESSION_ERROR_MEMORY
|
||||||
|
} InvestigationSessionError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Domaine d'erreur GLib du module InvestigationSession.
|
||||||
|
*/
|
||||||
|
#define INVESTIGATION_SESSION_ERROR \
|
||||||
|
investigation_session_error_quark()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le domaine d'erreur du module.
|
||||||
|
*
|
||||||
|
* @return Le GQuark associé aux erreurs InvestigationSession.
|
||||||
|
*/
|
||||||
|
GQuark investigation_session_error_quark(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ouvre une enquête existante.
|
||||||
|
*
|
||||||
|
* La fonction :
|
||||||
|
*
|
||||||
|
* - vérifie que le chemin racine représente un dossier ;
|
||||||
|
* - construit un InvestigationProject ;
|
||||||
|
* - vérifie la présence du fichier SQLite ;
|
||||||
|
* - ouvre la connexion Database ;
|
||||||
|
* - charge le record persistant ;
|
||||||
|
* - vérifie la cohérence du chemin racine.
|
||||||
|
*
|
||||||
|
* Cette fonction ne crée aucune enquête et ne modifie pas la base.
|
||||||
|
*
|
||||||
|
* En cas de succès, la session devient propriétaire du projet,
|
||||||
|
* de la connexion Database et du record.
|
||||||
|
*
|
||||||
|
* Le paramètre error peut être NULL.
|
||||||
|
*
|
||||||
|
* @param investigation_root_path Chemin racine de l'enquête.
|
||||||
|
* @param error Adresse recevant une éventuelle erreur GLib.
|
||||||
|
*
|
||||||
|
* @return Une nouvelle session, ou NULL en cas d'échec.
|
||||||
|
*/
|
||||||
|
InvestigationSession *investigation_session_open(
|
||||||
|
const char *investigation_root_path,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ferme une session d'enquête.
|
||||||
|
*
|
||||||
|
* Cette fonction libère :
|
||||||
|
*
|
||||||
|
* - le record ;
|
||||||
|
* - la connexion Database ;
|
||||||
|
* - le contexte InvestigationProject ;
|
||||||
|
* - la session.
|
||||||
|
*
|
||||||
|
* Cette fonction accepte NULL.
|
||||||
|
*
|
||||||
|
* @param session Session à fermer.
|
||||||
|
*/
|
||||||
|
void investigation_session_close(
|
||||||
|
InvestigationSession *session
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le contexte de fichiers de la session.
|
||||||
|
*
|
||||||
|
* Le pointeur retourné appartient à la session et ne doit pas être libéré.
|
||||||
|
*
|
||||||
|
* @param session Session d'enquête.
|
||||||
|
*
|
||||||
|
* @return Le projet associé, ou NULL si session vaut NULL.
|
||||||
|
*/
|
||||||
|
const InvestigationProject *investigation_session_get_project(
|
||||||
|
const InvestigationSession *session
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne les informations persistées de l'enquête.
|
||||||
|
*
|
||||||
|
* Le pointeur retourné appartient à la session et ne doit pas être libéré.
|
||||||
|
*
|
||||||
|
* @param session Session d'enquête.
|
||||||
|
*
|
||||||
|
* @return Le record associé, ou NULL si session vaut NULL.
|
||||||
|
*/
|
||||||
|
const InvestigationRecord *investigation_session_get_record(
|
||||||
|
const InvestigationSession *session
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne la connexion Database de la session.
|
||||||
|
*
|
||||||
|
* Le pointeur retourné appartient à la session et ne doit pas être fermé
|
||||||
|
* par le code appelant.
|
||||||
|
*
|
||||||
|
* La connexion reste modifiable afin d'être utilisée par les futurs DAO.
|
||||||
|
*
|
||||||
|
* @param session Session d'enquête.
|
||||||
|
*
|
||||||
|
* @return La connexion associée, ou NULL si session vaut NULL.
|
||||||
|
*/
|
||||||
|
Database *investigation_session_get_database(
|
||||||
|
InvestigationSession *session
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
Binary file not shown.
|
|
@ -12,6 +12,27 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Nom du dossier contenant la base de données.
|
||||||
|
*/
|
||||||
|
#define INVESTIGATION_PROJECT_DATABASE_DIRECTORY \
|
||||||
|
"00_BaseDeDonnees"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Nom du fichier SQLite d'une enquête.
|
||||||
|
*/
|
||||||
|
#define INVESTIGATION_PROJECT_DATABASE_FILENAME \
|
||||||
|
"Enquete.sqlite"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Représentation privée des chemins d'un projet d'enquête.
|
||||||
|
*/
|
||||||
|
struct InvestigationProject
|
||||||
|
{
|
||||||
|
char *root_path;
|
||||||
|
char *database_path;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type d'un élément de la structure d'une enquête.
|
* @brief Type d'un élément de la structure d'une enquête.
|
||||||
*/
|
*/
|
||||||
|
|
@ -436,11 +457,10 @@ char *investigation_project_create(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
database_path = g_build_filename(
|
database_path = g_build_filename(
|
||||||
investigation_path,
|
investigation_path,
|
||||||
"00_BaseDeDonnees",
|
INVESTIGATION_PROJECT_DATABASE_DIRECTORY,
|
||||||
"Enquete.sqlite",
|
INVESTIGATION_PROJECT_DATABASE_FILENAME,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -460,14 +480,25 @@ char *investigation_project_create(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le chemin est enregistré avant l'initialisation.
|
||||||
|
*
|
||||||
|
* Ainsi, si database_initialize() crée le fichier puis échoue,
|
||||||
|
* le nettoyage pourra supprimer ce fichier avant ses dossiers parents.
|
||||||
|
*
|
||||||
|
* Le tableau devient propriétaire de database_path.
|
||||||
|
*/
|
||||||
|
g_ptr_array_add(
|
||||||
|
created_paths,
|
||||||
|
database_path
|
||||||
|
);
|
||||||
|
|
||||||
if (!database_initialize(
|
if (!database_initialize(
|
||||||
database_path,
|
database_path,
|
||||||
investigation_name,
|
investigation_name,
|
||||||
investigation_path
|
investigation_path
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
g_free(database_path);
|
|
||||||
|
|
||||||
investigation_project_cleanup_created_paths(
|
investigation_project_cleanup_created_paths(
|
||||||
created_paths
|
created_paths
|
||||||
);
|
);
|
||||||
|
|
@ -482,22 +513,11 @@ char *investigation_project_create(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Le fichier doit également être supprimé avant ses dossiers
|
|
||||||
* si une évolution future ajoute une étape pouvant encore échouer.
|
|
||||||
*
|
|
||||||
* Le tableau devient propriétaire de database_path.
|
|
||||||
*/
|
|
||||||
g_ptr_array_add(
|
|
||||||
created_paths,
|
|
||||||
database_path
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tout est créé avec succès.
|
* Tout est créé avec succès.
|
||||||
*
|
*
|
||||||
* On libère seulement le tableau et ses copies de chemins.
|
* On libère uniquement le tableau et ses chaînes.
|
||||||
* Les fichiers et dossiers restent sur le disque.
|
* Les fichiers et dossiers restent présents sur le disque.
|
||||||
*/
|
*/
|
||||||
g_ptr_array_free(
|
g_ptr_array_free(
|
||||||
created_paths,
|
created_paths,
|
||||||
|
|
@ -553,3 +573,109 @@ bool investigation_project_validate(
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InvestigationProject *investigation_project_open(
|
||||||
|
const char *investigation_root_path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
InvestigationProject *project = NULL;
|
||||||
|
char *canonical_root_path = NULL;
|
||||||
|
|
||||||
|
if (investigation_root_path == NULL ||
|
||||||
|
investigation_root_path[0] == '\0')
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
canonical_root_path = g_canonicalize_filename(
|
||||||
|
investigation_root_path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (canonical_root_path == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le contexte représente une enquête existante.
|
||||||
|
*
|
||||||
|
* On vérifie seulement ici que sa racine est un dossier.
|
||||||
|
* La présence de la base SQLite sera contrôlée séparément par
|
||||||
|
* InvestigationSession afin de produire une erreur précise.
|
||||||
|
*/
|
||||||
|
if (!g_file_test(
|
||||||
|
canonical_root_path,
|
||||||
|
G_FILE_TEST_IS_DIR
|
||||||
|
))
|
||||||
|
{
|
||||||
|
g_free(canonical_root_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
project = g_try_new0(
|
||||||
|
InvestigationProject,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (project == NULL)
|
||||||
|
{
|
||||||
|
g_free(canonical_root_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
project->root_path = canonical_root_path;
|
||||||
|
|
||||||
|
project->database_path = g_build_filename(
|
||||||
|
project->root_path,
|
||||||
|
INVESTIGATION_PROJECT_DATABASE_DIRECTORY,
|
||||||
|
INVESTIGATION_PROJECT_DATABASE_FILENAME,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (project->database_path == NULL)
|
||||||
|
{
|
||||||
|
investigation_project_free(project);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
void investigation_project_free(
|
||||||
|
InvestigationProject *project
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (project == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(project->database_path);
|
||||||
|
g_free(project->root_path);
|
||||||
|
g_free(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *investigation_project_get_root_path(
|
||||||
|
const InvestigationProject *project
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (project == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return project->root_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *investigation_project_get_database_path(
|
||||||
|
const InvestigationProject *project
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (project == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return project->database_path;
|
||||||
|
}
|
||||||
|
|
|
||||||
374
src/core/investigation_session.c
Normal file
374
src/core/investigation_session.c
Normal file
|
|
@ -0,0 +1,374 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file investigation_session.c
|
||||||
|
* @brief Gestion d'une session d'enquête ouverte.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "core/investigation_session.h"
|
||||||
|
|
||||||
|
#include "dao/investigation_dao.h"
|
||||||
|
#include "database/error.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Représentation privée d'une session d'enquête.
|
||||||
|
*/
|
||||||
|
struct InvestigationSession
|
||||||
|
{
|
||||||
|
InvestigationProject *project;
|
||||||
|
Database *database;
|
||||||
|
InvestigationRecord *record;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enregistre une erreur littérale si un GError est demandé.
|
||||||
|
*
|
||||||
|
* @param error Adresse recevant l'erreur.
|
||||||
|
* @param error_code Code d'erreur du module.
|
||||||
|
* @param error_message Message associé.
|
||||||
|
*/
|
||||||
|
static void investigation_session_set_error_literal(
|
||||||
|
GError **error,
|
||||||
|
InvestigationSessionError error_code,
|
||||||
|
const char *error_message
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (error == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR,
|
||||||
|
error_code,
|
||||||
|
error_message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark investigation_session_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string(
|
||||||
|
"investigation-session-error-quark"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
InvestigationSession *investigation_session_open(
|
||||||
|
const char *investigation_root_path,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
InvestigationProject *project = NULL;
|
||||||
|
InvestigationRecord *record = NULL;
|
||||||
|
Database *database = NULL;
|
||||||
|
|
||||||
|
char *canonical_root_path = NULL;
|
||||||
|
char *canonical_record_root_path = NULL;
|
||||||
|
|
||||||
|
const char *database_path = NULL;
|
||||||
|
const char *record_root_path = NULL;
|
||||||
|
const char *database_error_message = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convention GLib :
|
||||||
|
*
|
||||||
|
* un GError existant ne doit pas être remplacé.
|
||||||
|
*/
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (investigation_root_path == NULL ||
|
||||||
|
investigation_root_path[0] == '\0')
|
||||||
|
{
|
||||||
|
investigation_session_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Le chemin racine de l'enquête est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
canonical_root_path = g_canonicalize_filename(
|
||||||
|
investigation_root_path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (canonical_root_path == NULL)
|
||||||
|
{
|
||||||
|
investigation_session_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_MEMORY,
|
||||||
|
"Impossible d'allouer le chemin canonique de l'enquête."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_file_test(
|
||||||
|
canonical_root_path,
|
||||||
|
G_FILE_TEST_IS_DIR
|
||||||
|
))
|
||||||
|
{
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND,
|
||||||
|
"Le chemin racine '%s' n'est pas un dossier existant.",
|
||||||
|
canonical_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
project = investigation_project_open(
|
||||||
|
canonical_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
if (project == NULL)
|
||||||
|
{
|
||||||
|
investigation_session_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_PROJECT,
|
||||||
|
"Impossible de construire le contexte du projet d'enquête."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
database_path = investigation_project_get_database_path(
|
||||||
|
project
|
||||||
|
);
|
||||||
|
|
||||||
|
if (database_path == NULL)
|
||||||
|
{
|
||||||
|
investigation_session_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_PROJECT,
|
||||||
|
"Le projet ne fournit aucun chemin vers la base de données."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cette vérification doit précéder database_open().
|
||||||
|
*
|
||||||
|
* SQLite peut créer automatiquement une base absente lors de
|
||||||
|
* l'ouverture. Une session ne doit jamais créer silencieusement
|
||||||
|
* une nouvelle base.
|
||||||
|
*/
|
||||||
|
if (!g_file_test(
|
||||||
|
database_path,
|
||||||
|
G_FILE_TEST_IS_REGULAR
|
||||||
|
))
|
||||||
|
{
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR,
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND,
|
||||||
|
"Le fichier SQLite de l'enquête est absent : '%s'.",
|
||||||
|
database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
database = database_open(
|
||||||
|
database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
if (database == NULL)
|
||||||
|
{
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR,
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE,
|
||||||
|
"Impossible d'ouvrir la base de données '%s'.",
|
||||||
|
database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
record = investigation_dao_load(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
if (record == NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Le message doit être copié dans le GError avant la fermeture
|
||||||
|
* de Database, car il appartient à l'objet Database.
|
||||||
|
*/
|
||||||
|
database_error_message = database_error_get_message(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
if (database_error_message == NULL ||
|
||||||
|
database_error_message[0] == '\0')
|
||||||
|
{
|
||||||
|
database_error_message =
|
||||||
|
"Impossible de charger les informations de l'enquête.";
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR,
|
||||||
|
INVESTIGATION_SESSION_ERROR_RECORD,
|
||||||
|
"%s",
|
||||||
|
database_error_message
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
record_root_path = investigation_record_get_root_path(
|
||||||
|
record
|
||||||
|
);
|
||||||
|
|
||||||
|
if (record_root_path == NULL ||
|
||||||
|
record_root_path[0] == '\0')
|
||||||
|
{
|
||||||
|
investigation_session_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_RECORD,
|
||||||
|
"Le chemin racine enregistré dans la base est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
canonical_record_root_path = g_canonicalize_filename(
|
||||||
|
record_root_path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (canonical_record_root_path == NULL)
|
||||||
|
{
|
||||||
|
investigation_session_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_MEMORY,
|
||||||
|
"Impossible d'allouer le chemin canonique enregistré."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0(
|
||||||
|
canonical_root_path,
|
||||||
|
canonical_record_root_path
|
||||||
|
) != 0)
|
||||||
|
{
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH,
|
||||||
|
"Le chemin sélectionné '%s' ne correspond pas au chemin "
|
||||||
|
"enregistré '%s'.",
|
||||||
|
canonical_root_path,
|
||||||
|
canonical_record_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
session = g_try_new0(
|
||||||
|
InvestigationSession,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (session == NULL)
|
||||||
|
{
|
||||||
|
investigation_session_set_error_literal(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_MEMORY,
|
||||||
|
"Impossible d'allouer la session d'enquête."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* La session devient propriétaire des trois objets.
|
||||||
|
*/
|
||||||
|
session->project = project;
|
||||||
|
session->database = database;
|
||||||
|
session->record = record;
|
||||||
|
|
||||||
|
project = NULL;
|
||||||
|
database = NULL;
|
||||||
|
record = NULL;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
g_free(canonical_record_root_path);
|
||||||
|
g_free(canonical_root_path);
|
||||||
|
|
||||||
|
investigation_record_free(record);
|
||||||
|
database_close(database);
|
||||||
|
investigation_project_free(project);
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
void investigation_session_close(
|
||||||
|
InvestigationSession *session
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (session == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
investigation_record_free(
|
||||||
|
session->record
|
||||||
|
);
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
session->database
|
||||||
|
);
|
||||||
|
|
||||||
|
investigation_project_free(
|
||||||
|
session->project
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
const InvestigationProject *investigation_session_get_project(
|
||||||
|
const InvestigationSession *session
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (session == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session->project;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InvestigationRecord *investigation_session_get_record(
|
||||||
|
const InvestigationSession *session
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (session == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session->record;
|
||||||
|
}
|
||||||
|
|
||||||
|
Database *investigation_session_get_database(
|
||||||
|
InvestigationSession *session
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (session == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session->database;
|
||||||
|
}
|
||||||
Binary file not shown.
|
|
@ -735,6 +735,181 @@ static void test_validate_directory_replaced_by_file(void)
|
||||||
g_free(temporary_parent);
|
g_free(temporary_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie l'ouverture d'un projet existant et ses accesseurs.
|
||||||
|
*/
|
||||||
|
static void test_open_existing_project(void)
|
||||||
|
{
|
||||||
|
char *temporary_parent = NULL;
|
||||||
|
char *investigation_path = NULL;
|
||||||
|
char *path_with_dot = NULL;
|
||||||
|
char *expected_root_path = NULL;
|
||||||
|
char *expected_database_path = NULL;
|
||||||
|
|
||||||
|
InvestigationProject *project = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
temporary_parent = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-project-open-test-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(temporary_parent != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
investigation_path = investigation_project_create(
|
||||||
|
temporary_parent,
|
||||||
|
"Enquete_Ouverte"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(investigation_path != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le segment "." permet de vérifier la canonicalisation du chemin.
|
||||||
|
*/
|
||||||
|
path_with_dot = g_build_filename(
|
||||||
|
investigation_path,
|
||||||
|
".",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(path_with_dot != NULL);
|
||||||
|
|
||||||
|
expected_root_path = g_canonicalize_filename(
|
||||||
|
investigation_path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(expected_root_path != NULL);
|
||||||
|
|
||||||
|
expected_database_path = g_build_filename(
|
||||||
|
expected_root_path,
|
||||||
|
"00_BaseDeDonnees",
|
||||||
|
"Enquete.sqlite",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(expected_database_path != NULL);
|
||||||
|
|
||||||
|
project = investigation_project_open(
|
||||||
|
path_with_dot
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(project != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
strcmp(
|
||||||
|
investigation_project_get_root_path(project),
|
||||||
|
expected_root_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
strcmp(
|
||||||
|
investigation_project_get_database_path(project),
|
||||||
|
expected_database_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
investigation_project_free(project);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
temporary_parent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(expected_database_path);
|
||||||
|
g_free(expected_root_path);
|
||||||
|
g_free(path_with_dot);
|
||||||
|
g_free(investigation_path);
|
||||||
|
g_free(temporary_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le refus des chemins invalides lors de l'ouverture.
|
||||||
|
*/
|
||||||
|
static void test_open_invalid_project_paths(void)
|
||||||
|
{
|
||||||
|
char *temporary_directory = NULL;
|
||||||
|
char *temporary_file = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_project_open(NULL) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_project_open("") == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_project_open(
|
||||||
|
"/tmp/labfy-investigation-project-does-not-exist"
|
||||||
|
) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
temporary_directory = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-project-open-file-test-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(temporary_directory != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
temporary_file = g_build_filename(
|
||||||
|
temporary_directory,
|
||||||
|
"not-a-directory.txt",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(temporary_file != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_file_set_contents(
|
||||||
|
temporary_file,
|
||||||
|
"test\n",
|
||||||
|
-1,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_project_open(
|
||||||
|
temporary_file
|
||||||
|
) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
temporary_directory
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(temporary_file);
|
||||||
|
g_free(temporary_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie les fonctions acceptant un projet NULL.
|
||||||
|
*/
|
||||||
|
static void test_open_project_null_instance(void)
|
||||||
|
{
|
||||||
|
assert(
|
||||||
|
investigation_project_get_root_path(NULL) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_project_get_database_path(NULL) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
investigation_project_free(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
test_create_valid_investigation();
|
test_create_valid_investigation();
|
||||||
|
|
@ -749,6 +924,11 @@ int main(void)
|
||||||
test_validate_missing_directory();
|
test_validate_missing_directory();
|
||||||
test_validate_directory_replaced_by_file();
|
test_validate_directory_replaced_by_file();
|
||||||
|
|
||||||
|
|
||||||
|
test_open_existing_project();
|
||||||
|
test_open_invalid_project_paths();
|
||||||
|
test_open_project_null_instance();
|
||||||
|
|
||||||
printf(
|
printf(
|
||||||
"InvestigationProject : tous les tests sont valides.\n"
|
"InvestigationProject : tous les tests sont valides.\n"
|
||||||
);
|
);
|
||||||
|
|
|
||||||
BIN
tests/test_investigation_session
Executable file
BIN
tests/test_investigation_session
Executable file
Binary file not shown.
684
tests/test_investigation_session.c
Normal file
684
tests/test_investigation_session.c
Normal file
|
|
@ -0,0 +1,684 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file test_investigation_session.c
|
||||||
|
* @brief Tests du contexte représentant une enquête ouverte.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "core/investigation_session.h"
|
||||||
|
|
||||||
|
#include "core/investigation_project.h"
|
||||||
|
#include "dao/investigation_dao.h"
|
||||||
|
#include "database/database.h"
|
||||||
|
#include "models/investigation_record.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
static gboolean test_remove_path_recursively(
|
||||||
|
const char *path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GDir *directory = NULL;
|
||||||
|
const char *entry_name = NULL;
|
||||||
|
|
||||||
|
if (path == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_file_test(
|
||||||
|
path,
|
||||||
|
G_FILE_TEST_EXISTS
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_file_test(
|
||||||
|
path,
|
||||||
|
G_FILE_TEST_IS_DIR
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return g_remove(path) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
directory = g_dir_open(
|
||||||
|
path,
|
||||||
|
0,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (directory == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((entry_name = g_dir_read_name(directory)) != NULL)
|
||||||
|
{
|
||||||
|
char *entry_path = NULL;
|
||||||
|
gboolean removed = FALSE;
|
||||||
|
|
||||||
|
entry_path = g_build_filename(
|
||||||
|
path,
|
||||||
|
entry_name,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entry_path == NULL)
|
||||||
|
{
|
||||||
|
g_dir_close(directory);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
removed = test_remove_path_recursively(
|
||||||
|
entry_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(entry_path);
|
||||||
|
|
||||||
|
if (!removed)
|
||||||
|
{
|
||||||
|
g_dir_close(directory);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dir_close(directory);
|
||||||
|
|
||||||
|
return g_rmdir(path) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_assert_session_error(
|
||||||
|
const GError *error,
|
||||||
|
InvestigationSessionError expected_code
|
||||||
|
)
|
||||||
|
{
|
||||||
|
assert(error != NULL);
|
||||||
|
assert(error->domain == INVESTIGATION_SESSION_ERROR);
|
||||||
|
assert(error->code == (gint) expected_code);
|
||||||
|
assert(error->message != NULL);
|
||||||
|
assert(error->message[0] != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_open_valid_session(void)
|
||||||
|
{
|
||||||
|
char *temporary_parent = NULL;
|
||||||
|
char *investigation_path = NULL;
|
||||||
|
char *canonical_root_path = NULL;
|
||||||
|
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
const InvestigationProject *project = NULL;
|
||||||
|
const InvestigationRecord *record = NULL;
|
||||||
|
InvestigationRecord *reloaded_record = NULL;
|
||||||
|
Database *database = NULL;
|
||||||
|
|
||||||
|
const char *record_id = NULL;
|
||||||
|
const char *reloaded_record_id = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
temporary_parent = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-session-valid-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(temporary_parent != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
investigation_path = investigation_project_create(
|
||||||
|
temporary_parent,
|
||||||
|
"Enquete_Session"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(investigation_path != NULL);
|
||||||
|
|
||||||
|
canonical_root_path = g_canonicalize_filename(
|
||||||
|
investigation_path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(canonical_root_path != NULL);
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
investigation_path,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
project = investigation_session_get_project(
|
||||||
|
session
|
||||||
|
);
|
||||||
|
|
||||||
|
database = investigation_session_get_database(
|
||||||
|
session
|
||||||
|
);
|
||||||
|
|
||||||
|
record = investigation_session_get_record(
|
||||||
|
session
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(project != NULL);
|
||||||
|
assert(database != NULL);
|
||||||
|
assert(record != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
strcmp(
|
||||||
|
investigation_project_get_root_path(project),
|
||||||
|
canonical_root_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
strcmp(
|
||||||
|
investigation_record_get_name(record),
|
||||||
|
"Enquete_Session"
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
strcmp(
|
||||||
|
investigation_record_get_root_path(record),
|
||||||
|
canonical_root_path
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
record_id = investigation_record_get_id(
|
||||||
|
record
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(record_id != NULL);
|
||||||
|
assert(g_uuid_string_is_valid(record_id));
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_record_get_created_at(record) != NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_record_get_created_at(record)[0] != '\0'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_record_get_updated_at(record) != NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_record_get_updated_at(record)[0] != '\0'
|
||||||
|
);
|
||||||
|
|
||||||
|
reloaded_record = investigation_dao_load(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(reloaded_record != NULL);
|
||||||
|
|
||||||
|
reloaded_record_id = investigation_record_get_id(
|
||||||
|
reloaded_record
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(reloaded_record_id != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
strcmp(
|
||||||
|
record_id,
|
||||||
|
reloaded_record_id
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
investigation_record_free(reloaded_record);
|
||||||
|
investigation_session_close(session);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
temporary_parent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(canonical_root_path);
|
||||||
|
g_free(investigation_path);
|
||||||
|
g_free(temporary_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_open_invalid_parameters(void)
|
||||||
|
{
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
NULL,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session == NULL);
|
||||||
|
|
||||||
|
test_assert_session_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
"",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session == NULL);
|
||||||
|
|
||||||
|
test_assert_session_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_session_open(
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_session_open(
|
||||||
|
"",
|
||||||
|
NULL
|
||||||
|
) == NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_open_missing_root(void)
|
||||||
|
{
|
||||||
|
char *temporary_parent = NULL;
|
||||||
|
char *missing_root_path = NULL;
|
||||||
|
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
temporary_parent = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-session-missing-root-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(temporary_parent != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
missing_root_path = g_build_filename(
|
||||||
|
temporary_parent,
|
||||||
|
"does-not-exist",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(missing_root_path != NULL);
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
missing_root_path,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session == NULL);
|
||||||
|
|
||||||
|
test_assert_session_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!g_file_test(
|
||||||
|
missing_root_path,
|
||||||
|
G_FILE_TEST_EXISTS
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
temporary_parent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(missing_root_path);
|
||||||
|
g_free(temporary_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_open_root_is_file(void)
|
||||||
|
{
|
||||||
|
char *temporary_parent = NULL;
|
||||||
|
char *file_path = NULL;
|
||||||
|
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
temporary_parent = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-session-root-file-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(temporary_parent != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
file_path = g_build_filename(
|
||||||
|
temporary_parent,
|
||||||
|
"not-a-directory.txt",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(file_path != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_file_set_contents(
|
||||||
|
file_path,
|
||||||
|
"test\n",
|
||||||
|
-1,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
file_path,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session == NULL);
|
||||||
|
|
||||||
|
test_assert_session_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_NOT_FOUND
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
temporary_parent
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(file_path);
|
||||||
|
g_free(temporary_parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_open_missing_database(void)
|
||||||
|
{
|
||||||
|
char *investigation_root = NULL;
|
||||||
|
char *database_directory = NULL;
|
||||||
|
char *database_path = NULL;
|
||||||
|
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
investigation_root = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-session-missing-database-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(investigation_root != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
database_directory = g_build_filename(
|
||||||
|
investigation_root,
|
||||||
|
"00_BaseDeDonnees",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database_directory != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_mkdir(
|
||||||
|
database_directory,
|
||||||
|
0700
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
database_path = g_build_filename(
|
||||||
|
database_directory,
|
||||||
|
"Enquete.sqlite",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database_path != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!g_file_test(
|
||||||
|
database_path,
|
||||||
|
G_FILE_TEST_EXISTS
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
investigation_root,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session == NULL);
|
||||||
|
|
||||||
|
test_assert_session_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_DATABASE_NOT_FOUND
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!g_file_test(
|
||||||
|
database_path,
|
||||||
|
G_FILE_TEST_EXISTS
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
investigation_root
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(database_path);
|
||||||
|
g_free(database_directory);
|
||||||
|
g_free(investigation_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_open_invalid_database(void)
|
||||||
|
{
|
||||||
|
char *investigation_root = NULL;
|
||||||
|
char *database_directory = NULL;
|
||||||
|
char *database_path = NULL;
|
||||||
|
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
investigation_root = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-session-invalid-database-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(investigation_root != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
database_directory = g_build_filename(
|
||||||
|
investigation_root,
|
||||||
|
"00_BaseDeDonnees",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database_directory != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_mkdir(
|
||||||
|
database_directory,
|
||||||
|
0700
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
database_path = g_build_filename(
|
||||||
|
database_directory,
|
||||||
|
"Enquete.sqlite",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database_path != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_file_set_contents(
|
||||||
|
database_path,
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
investigation_root,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session == NULL);
|
||||||
|
|
||||||
|
test_assert_session_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_RECORD
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
investigation_root
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(database_path);
|
||||||
|
g_free(database_directory);
|
||||||
|
g_free(investigation_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_open_root_mismatch(void)
|
||||||
|
{
|
||||||
|
char *investigation_root = NULL;
|
||||||
|
char *database_directory = NULL;
|
||||||
|
char *database_path = NULL;
|
||||||
|
char *different_root_path = NULL;
|
||||||
|
|
||||||
|
InvestigationSession *session = NULL;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
investigation_root = g_dir_make_tmp(
|
||||||
|
"labfy-investigation-session-root-mismatch-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(investigation_root != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
database_directory = g_build_filename(
|
||||||
|
investigation_root,
|
||||||
|
"00_BaseDeDonnees",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database_directory != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
g_mkdir(
|
||||||
|
database_directory,
|
||||||
|
0700
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
|
||||||
|
database_path = g_build_filename(
|
||||||
|
database_directory,
|
||||||
|
"Enquete.sqlite",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(database_path != NULL);
|
||||||
|
|
||||||
|
different_root_path = g_build_filename(
|
||||||
|
investigation_root,
|
||||||
|
"autre-emplacement",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(different_root_path != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
database_initialize(
|
||||||
|
database_path,
|
||||||
|
"Enquete_Incoherente",
|
||||||
|
different_root_path
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
session = investigation_session_open(
|
||||||
|
investigation_root,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(session == NULL);
|
||||||
|
|
||||||
|
test_assert_session_error(
|
||||||
|
error,
|
||||||
|
INVESTIGATION_SESSION_ERROR_ROOT_MISMATCH
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(&error);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
test_remove_path_recursively(
|
||||||
|
investigation_root
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(different_root_path);
|
||||||
|
g_free(database_path);
|
||||||
|
g_free(database_directory);
|
||||||
|
g_free(investigation_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_null_session_accessors(void)
|
||||||
|
{
|
||||||
|
assert(
|
||||||
|
investigation_session_get_project(NULL) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_session_get_record(NULL) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
investigation_session_get_database(NULL) == NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
investigation_session_close(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
test_open_valid_session();
|
||||||
|
test_open_invalid_parameters();
|
||||||
|
test_open_missing_root();
|
||||||
|
test_open_root_is_file();
|
||||||
|
test_open_missing_database();
|
||||||
|
test_open_invalid_database();
|
||||||
|
test_open_root_mismatch();
|
||||||
|
test_null_session_accessors();
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"InvestigationSession : tous les tests sont valides.\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue