feat: add entity type DAO
This commit is contained in:
parent
59d05b6683
commit
95839efba6
4 changed files with 1233 additions and 1 deletions
17
Makefile
17
Makefile
|
|
@ -42,6 +42,7 @@ EVIDENCE_INTEGRITY_VERIFIER_TEST_CFLAGS := \
|
||||||
$(TEST_CFLAGS) \
|
$(TEST_CFLAGS) \
|
||||||
-Wpedantic
|
-Wpedantic
|
||||||
ENTITY_RECORD_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
|
ENTITY_RECORD_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
|
||||||
|
ENTITY_TYPE_DAO_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
|
||||||
|
|
||||||
SRC := $(shell find src -name "*.c")
|
SRC := $(shell find src -name "*.c")
|
||||||
|
|
||||||
|
|
@ -84,6 +85,7 @@ TEST_EVIDENCE_CATEGORY_ITEM := tests/test_evidence_category_item
|
||||||
TEST_EVIDENCE_CATEGORY_MODEL := tests/test_evidence_category_model
|
TEST_EVIDENCE_CATEGORY_MODEL := tests/test_evidence_category_model
|
||||||
TEST_EVIDENCE_INTEGRITY_TASK := tests/test_evidence_integrity_task
|
TEST_EVIDENCE_INTEGRITY_TASK := tests/test_evidence_integrity_task
|
||||||
TEST_ENTITY_RECORD := tests/test_entity_record
|
TEST_ENTITY_RECORD := tests/test_entity_record
|
||||||
|
TEST_ENTITY_TYPE_DAO := tests/test_entity_type_dao
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -375,6 +377,17 @@ $(TEST_ENTITY_RECORD): \
|
||||||
src/models/entity_record.c
|
src/models/entity_record.c
|
||||||
$(CC) $(ENTITY_RECORD_TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
$(CC) $(ENTITY_RECORD_TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
|
$(TEST_ENTITY_TYPE_DAO): \
|
||||||
|
tests/test_entity_type_dao.c \
|
||||||
|
src/dao/entity_type_dao.c \
|
||||||
|
src/models/entity_type.c \
|
||||||
|
src/database/database.c \
|
||||||
|
src/database/schema.c \
|
||||||
|
src/database/statement.c \
|
||||||
|
src/database/transaction.c \
|
||||||
|
src/database/error.c
|
||||||
|
$(CC) $(ENTITY_TYPE_DAO_TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS) -lsqlite3
|
||||||
|
|
||||||
test: \
|
test: \
|
||||||
$(TEST_NODE) \
|
$(TEST_NODE) \
|
||||||
$(TEST_TREE_MODEL) \
|
$(TEST_TREE_MODEL) \
|
||||||
|
|
@ -410,7 +423,8 @@ test: \
|
||||||
$(TEST_EVIDENCE_IMPORT_TASK) \
|
$(TEST_EVIDENCE_IMPORT_TASK) \
|
||||||
$(TEST_EVIDENCE_IMPORT_DIALOG) \
|
$(TEST_EVIDENCE_IMPORT_DIALOG) \
|
||||||
$(TEST_EVIDENCE_INTEGRITY_TASK) \
|
$(TEST_EVIDENCE_INTEGRITY_TASK) \
|
||||||
$(TEST_ENTITY_RECORD)
|
$(TEST_ENTITY_RECORD) \
|
||||||
|
$(TEST_ENTITY_TYPE_DAO)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -447,6 +461,7 @@ test: \
|
||||||
@$(TEST_EVIDENCE_IMPORT_DIALOG)
|
@$(TEST_EVIDENCE_IMPORT_DIALOG)
|
||||||
@$(TEST_EVIDENCE_INTEGRITY_TASK)
|
@$(TEST_EVIDENCE_INTEGRITY_TASK)
|
||||||
@$(TEST_ENTITY_RECORD)
|
@$(TEST_ENTITY_RECORD)
|
||||||
|
@$(TEST_ENTITY_TYPE_DAO)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
|
||||||
121
include/dao/entity_type_dao.h
Normal file
121
include/dao/entity_type_dao.h
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file entity_type_dao.h
|
||||||
|
* @brief Lecture des types d'entité depuis SQLite.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_ENTITY_TYPE_DAO_H
|
||||||
|
#define LABFY_INVESTIGATION_ENTITY_TYPE_DAO_H
|
||||||
|
|
||||||
|
#include "database/database.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DAO opaque donnant accès aux types d'entité.
|
||||||
|
*
|
||||||
|
* Le DAO emprunte la connexion Database reçue lors de sa création.
|
||||||
|
*/
|
||||||
|
typedef struct EntityTypeDao EntityTypeDao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Catégories d'erreurs produites par EntityTypeDao.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Un argument public est invalide.
|
||||||
|
*/
|
||||||
|
ENTITY_TYPE_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* L'allocation d'une ressource a échoué.
|
||||||
|
*/
|
||||||
|
ENTITY_TYPE_DAO_ERROR_MEMORY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La requête SQLite n'a pas pu être préparée.
|
||||||
|
*/
|
||||||
|
ENTITY_TYPE_DAO_ERROR_PREPARE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une ligne SQLite n'a pas pu être lue.
|
||||||
|
*/
|
||||||
|
ENTITY_TYPE_DAO_ERROR_READ,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Une ligne SQLite ne peut pas produire un EntityType valide.
|
||||||
|
*/
|
||||||
|
ENTITY_TYPE_DAO_ERROR_MODEL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La table ou le schéma attendu est absent ou invalide.
|
||||||
|
*/
|
||||||
|
ENTITY_TYPE_DAO_ERROR_SCHEMA
|
||||||
|
} EntityTypeDaoError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Domaine d'erreur du DAO des types d'entité.
|
||||||
|
*/
|
||||||
|
#define ENTITY_TYPE_DAO_ERROR \
|
||||||
|
entity_type_dao_error_quark()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le domaine d'erreur du DAO.
|
||||||
|
*
|
||||||
|
* @return Quark GLib associé à EntityTypeDao.
|
||||||
|
*/
|
||||||
|
GQuark entity_type_dao_error_quark(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée un DAO utilisant une connexion Database existante.
|
||||||
|
*
|
||||||
|
* La connexion est empruntée et doit rester valide pendant toute
|
||||||
|
* la durée de vie du DAO.
|
||||||
|
*
|
||||||
|
* @param database Connexion SQLite ouverte.
|
||||||
|
* @param error Emplacement facultatif recevant une erreur.
|
||||||
|
*
|
||||||
|
* @return Nouveau DAO, ou NULL en cas d'échec.
|
||||||
|
*/
|
||||||
|
EntityTypeDao *entity_type_dao_new(
|
||||||
|
Database *database,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère le DAO.
|
||||||
|
*
|
||||||
|
* La connexion Database empruntée n'est pas fermée.
|
||||||
|
* Cette fonction accepte NULL.
|
||||||
|
*
|
||||||
|
* @param entity_type_dao DAO à libérer.
|
||||||
|
*/
|
||||||
|
void entity_type_dao_free(
|
||||||
|
EntityTypeDao *entity_type_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Charge tous les types d'entité.
|
||||||
|
*
|
||||||
|
* Les types sont triés par identifiant numérique croissant.
|
||||||
|
*
|
||||||
|
* Le tableau retourné appartient à l'appelant et utilise
|
||||||
|
* entity_type_free() comme fonction de destruction.
|
||||||
|
*
|
||||||
|
* Une table vide produit un tableau vide, sans erreur.
|
||||||
|
*
|
||||||
|
* @param entity_type_dao DAO valide.
|
||||||
|
* @param error Emplacement facultatif recevant une erreur.
|
||||||
|
*
|
||||||
|
* @return Nouveau GPtrArray, ou NULL en cas d'échec.
|
||||||
|
*/
|
||||||
|
GPtrArray *entity_type_dao_list_all(
|
||||||
|
EntityTypeDao *entity_type_dao,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
518
src/dao/entity_type_dao.c
Normal file
518
src/dao/entity_type_dao.c
Normal file
|
|
@ -0,0 +1,518 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file entity_type_dao.c
|
||||||
|
* @brief Lecture des types d'entité depuis SQLite.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "dao/entity_type_dao.h"
|
||||||
|
|
||||||
|
#include "database/error.h"
|
||||||
|
#include "database/statement.h"
|
||||||
|
#include "models/entity_type.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Requête listant les types d'entité.
|
||||||
|
*/
|
||||||
|
static const char *const entity_type_dao_list_all_sql =
|
||||||
|
"SELECT "
|
||||||
|
" id, "
|
||||||
|
" code, "
|
||||||
|
" label, "
|
||||||
|
" description "
|
||||||
|
"FROM types_entite "
|
||||||
|
"ORDER BY id ASC;";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct EntityTypeDao
|
||||||
|
* @brief Représentation interne du DAO.
|
||||||
|
*/
|
||||||
|
struct EntityTypeDao
|
||||||
|
{
|
||||||
|
Database *database;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère un EntityType contenu dans un GPtrArray.
|
||||||
|
*/
|
||||||
|
static void entity_type_dao_destroy_type(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EntityType *entity_type =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
entity_type_free(
|
||||||
|
entity_type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Détermine si un message SQLite indique un schéma incompatible.
|
||||||
|
*/
|
||||||
|
static gboolean entity_type_dao_is_schema_error(
|
||||||
|
const char *database_message
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (database_message == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_strstr_len(
|
||||||
|
database_message,
|
||||||
|
-1,
|
||||||
|
"no such table"
|
||||||
|
) != NULL ||
|
||||||
|
g_strstr_len(
|
||||||
|
database_message,
|
||||||
|
-1,
|
||||||
|
"no such column"
|
||||||
|
) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enregistre une erreur de préparation SQL.
|
||||||
|
*/
|
||||||
|
static void entity_type_dao_set_prepare_error(
|
||||||
|
EntityTypeDao *entity_type_dao,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const char *database_message =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
EntityTypeDaoError error_code =
|
||||||
|
ENTITY_TYPE_DAO_ERROR_PREPARE;
|
||||||
|
|
||||||
|
if (error == NULL ||
|
||||||
|
*error != NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity_type_dao != NULL)
|
||||||
|
{
|
||||||
|
database_message =
|
||||||
|
database_error_get_message(
|
||||||
|
entity_type_dao->database
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity_type_dao_is_schema_error(
|
||||||
|
database_message
|
||||||
|
))
|
||||||
|
{
|
||||||
|
error_code =
|
||||||
|
ENTITY_TYPE_DAO_ERROR_SCHEMA;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
error_code,
|
||||||
|
"Impossible de préparer la lecture "
|
||||||
|
"des types d'entité : %s",
|
||||||
|
database_message != NULL
|
||||||
|
? database_message
|
||||||
|
: "erreur Database inconnue"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enregistre une erreur de lecture SQLite.
|
||||||
|
*/
|
||||||
|
static void entity_type_dao_set_read_error(
|
||||||
|
EntityTypeDao *entity_type_dao,
|
||||||
|
GError **error,
|
||||||
|
const char *context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const char *database_message =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (error == NULL ||
|
||||||
|
*error != NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity_type_dao != NULL)
|
||||||
|
{
|
||||||
|
database_message =
|
||||||
|
database_error_get_message(
|
||||||
|
entity_type_dao->database
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_READ,
|
||||||
|
"%s : %s",
|
||||||
|
context != NULL
|
||||||
|
? context
|
||||||
|
: "Impossible de lire un type d'entité",
|
||||||
|
database_message != NULL
|
||||||
|
? database_message
|
||||||
|
: "donnée SQLite invalide"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construit un EntityType depuis la ligne SQLite courante.
|
||||||
|
*/
|
||||||
|
static EntityType *entity_type_dao_read_current_row(
|
||||||
|
EntityTypeDao *entity_type_dao,
|
||||||
|
DatabaseStatement *statement,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EntityType *entity_type =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
int64_t identifier =
|
||||||
|
0;
|
||||||
|
|
||||||
|
char *code =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *label =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *description =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *model_error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (entity_type_dao == NULL ||
|
||||||
|
statement == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
"La ligne du type d'entité ne peut pas être lue."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_statement_column_int64(
|
||||||
|
statement,
|
||||||
|
0,
|
||||||
|
&identifier
|
||||||
|
))
|
||||||
|
{
|
||||||
|
entity_type_dao_set_read_error(
|
||||||
|
entity_type_dao,
|
||||||
|
error,
|
||||||
|
"Impossible de lire l'identifiant du type d'entité"
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_statement_column_text(
|
||||||
|
statement,
|
||||||
|
1,
|
||||||
|
&code
|
||||||
|
))
|
||||||
|
{
|
||||||
|
entity_type_dao_set_read_error(
|
||||||
|
entity_type_dao,
|
||||||
|
error,
|
||||||
|
"Impossible de lire le code du type d'entité"
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_statement_column_text(
|
||||||
|
statement,
|
||||||
|
2,
|
||||||
|
&label
|
||||||
|
))
|
||||||
|
{
|
||||||
|
entity_type_dao_set_read_error(
|
||||||
|
entity_type_dao,
|
||||||
|
error,
|
||||||
|
"Impossible de lire le libellé du type d'entité"
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_statement_column_text(
|
||||||
|
statement,
|
||||||
|
3,
|
||||||
|
&description
|
||||||
|
))
|
||||||
|
{
|
||||||
|
entity_type_dao_set_read_error(
|
||||||
|
entity_type_dao,
|
||||||
|
error,
|
||||||
|
"Impossible de lire la description du type d'entité"
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_type =
|
||||||
|
entity_type_new(
|
||||||
|
(gint64) identifier,
|
||||||
|
code,
|
||||||
|
label,
|
||||||
|
description,
|
||||||
|
&model_error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entity_type == NULL)
|
||||||
|
{
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_MODEL,
|
||||||
|
"Le type d'entité lu depuis SQLite est invalide : %s",
|
||||||
|
model_error != NULL
|
||||||
|
? model_error->message
|
||||||
|
: "erreur de modèle inconnue"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&model_error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
description
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
label
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
code
|
||||||
|
);
|
||||||
|
|
||||||
|
return entity_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark entity_type_dao_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string(
|
||||||
|
"entity-type-dao-error-quark"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityTypeDao *entity_type_dao_new(
|
||||||
|
Database *database,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EntityTypeDao *entity_type_dao =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (database == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
"La connexion Database est obligatoire."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_type_dao =
|
||||||
|
g_try_new0(
|
||||||
|
EntityTypeDao,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entity_type_dao == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_MEMORY,
|
||||||
|
"Impossible d'allouer le DAO des types d'entité."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* La connexion reste possédée par la session ou le code appelant.
|
||||||
|
*/
|
||||||
|
entity_type_dao->database =
|
||||||
|
database;
|
||||||
|
|
||||||
|
return entity_type_dao;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entity_type_dao_free(
|
||||||
|
EntityTypeDao *entity_type_dao
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (entity_type_dao == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Database est empruntée et ne doit pas être fermée ici.
|
||||||
|
*/
|
||||||
|
entity_type_dao->database =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
entity_type_dao
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GPtrArray *entity_type_dao_list_all(
|
||||||
|
EntityTypeDao *entity_type_dao,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DatabaseStatement *statement =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GPtrArray *entity_types =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
DatabaseStatementStepResult step_result =
|
||||||
|
DATABASE_STATEMENT_STEP_ERROR;
|
||||||
|
|
||||||
|
gboolean success =
|
||||||
|
FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entity_type_dao == NULL ||
|
||||||
|
entity_type_dao->database == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Le DAO des types d'entité est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_types =
|
||||||
|
g_ptr_array_new_with_free_func(
|
||||||
|
entity_type_dao_destroy_type
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entity_types == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_MEMORY,
|
||||||
|
"Impossible d'allouer la liste des types d'entité."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
statement =
|
||||||
|
database_statement_prepare(
|
||||||
|
entity_type_dao->database,
|
||||||
|
entity_type_dao_list_all_sql
|
||||||
|
);
|
||||||
|
|
||||||
|
if (statement == NULL)
|
||||||
|
{
|
||||||
|
entity_type_dao_set_prepare_error(
|
||||||
|
entity_type_dao,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
EntityType *entity_type =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
step_result =
|
||||||
|
database_statement_step(
|
||||||
|
statement
|
||||||
|
);
|
||||||
|
|
||||||
|
if (step_result ==
|
||||||
|
DATABASE_STATEMENT_STEP_DONE)
|
||||||
|
{
|
||||||
|
success =
|
||||||
|
TRUE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_result ==
|
||||||
|
DATABASE_STATEMENT_STEP_ERROR)
|
||||||
|
{
|
||||||
|
entity_type_dao_set_read_error(
|
||||||
|
entity_type_dao,
|
||||||
|
error,
|
||||||
|
"Impossible de parcourir les types d'entité"
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_type =
|
||||||
|
entity_type_dao_read_current_row(
|
||||||
|
entity_type_dao,
|
||||||
|
statement,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entity_type == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_add(
|
||||||
|
entity_types,
|
||||||
|
entity_type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
database_statement_finalize(
|
||||||
|
statement
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
g_ptr_array_unref(
|
||||||
|
entity_types
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity_types;
|
||||||
|
}
|
||||||
578
tests/test_entity_type_dao.c
Normal file
578
tests/test_entity_type_dao.c
Normal file
|
|
@ -0,0 +1,578 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file test_entity_type_dao.c
|
||||||
|
* @brief Tests du DAO des types d'entité.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "dao/entity_type_dao.h"
|
||||||
|
|
||||||
|
#include "database/database.h"
|
||||||
|
#include "database/statement.h"
|
||||||
|
#include "models/entity_type.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ressources utilisées par un test EntityTypeDao.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *temporary_directory;
|
||||||
|
char *database_path;
|
||||||
|
|
||||||
|
Database *database;
|
||||||
|
EntityTypeDao *entity_type_dao;
|
||||||
|
} TestEntityTypeDaoFixture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exécute une requête SQL ne retournant aucune ligne.
|
||||||
|
*/
|
||||||
|
static void test_entity_type_dao_execute_sql(
|
||||||
|
Database *database,
|
||||||
|
const char *sql
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DatabaseStatement *statement =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
sql
|
||||||
|
);
|
||||||
|
|
||||||
|
statement =
|
||||||
|
database_statement_prepare(
|
||||||
|
database,
|
||||||
|
sql
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
statement
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_cmpint(
|
||||||
|
database_statement_step(
|
||||||
|
statement
|
||||||
|
),
|
||||||
|
==,
|
||||||
|
DATABASE_STATEMENT_STEP_DONE
|
||||||
|
);
|
||||||
|
|
||||||
|
database_statement_finalize(
|
||||||
|
statement
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée une base temporaire contenant le schéma de l'application.
|
||||||
|
*/
|
||||||
|
static TestEntityTypeDaoFixture
|
||||||
|
test_entity_type_dao_fixture_create(void)
|
||||||
|
{
|
||||||
|
TestEntityTypeDaoFixture fixture =
|
||||||
|
{0};
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
fixture.temporary_directory =
|
||||||
|
g_dir_make_tmp(
|
||||||
|
"labfy-entity-type-dao-test-XXXXXX",
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_no_error(
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
fixture.temporary_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture.database_path =
|
||||||
|
g_build_filename(
|
||||||
|
fixture.temporary_directory,
|
||||||
|
"Enquete.sqlite",
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
fixture.database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_true(
|
||||||
|
database_initialize(
|
||||||
|
fixture.database_path,
|
||||||
|
"Enquete_EntityTypeDao",
|
||||||
|
fixture.temporary_directory
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture.database =
|
||||||
|
database_open(
|
||||||
|
fixture.database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
fixture.database
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture.entity_type_dao =
|
||||||
|
entity_type_dao_new(
|
||||||
|
fixture.database,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_no_error(
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
fixture.entity_type_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
return fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère la fixture et supprime la base temporaire.
|
||||||
|
*/
|
||||||
|
static void test_entity_type_dao_fixture_clear(
|
||||||
|
TestEntityTypeDaoFixture *fixture
|
||||||
|
)
|
||||||
|
{
|
||||||
|
g_assert_nonnull(
|
||||||
|
fixture
|
||||||
|
);
|
||||||
|
|
||||||
|
entity_type_dao_free(
|
||||||
|
fixture->entity_type_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
fixture->database
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_cmpint(
|
||||||
|
g_remove(
|
||||||
|
fixture->database_path
|
||||||
|
),
|
||||||
|
==,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_cmpint(
|
||||||
|
g_rmdir(
|
||||||
|
fixture->temporary_directory
|
||||||
|
),
|
||||||
|
==,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
fixture->database_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
fixture->temporary_directory
|
||||||
|
);
|
||||||
|
|
||||||
|
fixture->entity_type_dao =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
fixture->database =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
fixture->database_path =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
fixture->temporary_directory =
|
||||||
|
NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le refus d'une connexion absente.
|
||||||
|
*/
|
||||||
|
static void test_entity_type_dao_new_invalid_database(void)
|
||||||
|
{
|
||||||
|
EntityTypeDao *entity_type_dao =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
entity_type_dao =
|
||||||
|
entity_type_dao_new(
|
||||||
|
NULL,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_null(
|
||||||
|
entity_type_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_error(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le chargement du catalogue initial.
|
||||||
|
*/
|
||||||
|
static void test_entity_type_dao_list_all(void)
|
||||||
|
{
|
||||||
|
static const char *const expected_codes[] =
|
||||||
|
{
|
||||||
|
"email_address",
|
||||||
|
"bank_account",
|
||||||
|
"facebook_account",
|
||||||
|
"instagram_account",
|
||||||
|
"identity_document",
|
||||||
|
"iban",
|
||||||
|
"person",
|
||||||
|
"pseudonym",
|
||||||
|
"phone_number",
|
||||||
|
"website",
|
||||||
|
"domain_name",
|
||||||
|
"ip_address",
|
||||||
|
"organization",
|
||||||
|
"other"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const expected_labels[] =
|
||||||
|
{
|
||||||
|
"Adresse email",
|
||||||
|
"Compte bancaire",
|
||||||
|
"Compte Facebook",
|
||||||
|
"Compte Instagram",
|
||||||
|
"Document d'identité",
|
||||||
|
"IBAN",
|
||||||
|
"Personne",
|
||||||
|
"Pseudonyme",
|
||||||
|
"Numéro de téléphone",
|
||||||
|
"Site web",
|
||||||
|
"Nom de domaine",
|
||||||
|
"Adresse IP",
|
||||||
|
"Organisation",
|
||||||
|
"Autre"
|
||||||
|
};
|
||||||
|
|
||||||
|
TestEntityTypeDaoFixture fixture =
|
||||||
|
test_entity_type_dao_fixture_create();
|
||||||
|
|
||||||
|
GPtrArray *entity_types =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
guint index =
|
||||||
|
0;
|
||||||
|
|
||||||
|
entity_types =
|
||||||
|
entity_type_dao_list_all(
|
||||||
|
fixture.entity_type_dao,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_no_error(
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
entity_types
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_cmpuint(
|
||||||
|
entity_types->len,
|
||||||
|
==,
|
||||||
|
G_N_ELEMENTS(
|
||||||
|
expected_codes
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (index = 0;
|
||||||
|
index < entity_types->len;
|
||||||
|
index++)
|
||||||
|
{
|
||||||
|
const EntityType *entity_type =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
entity_type =
|
||||||
|
g_ptr_array_index(
|
||||||
|
entity_types,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
entity_type
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* La requête utilise ORDER BY id ASC.
|
||||||
|
*/
|
||||||
|
g_assert_cmpint(
|
||||||
|
entity_type_get_identifier(
|
||||||
|
entity_type
|
||||||
|
),
|
||||||
|
==,
|
||||||
|
(gint64) index + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_cmpstr(
|
||||||
|
entity_type_get_code(
|
||||||
|
entity_type
|
||||||
|
),
|
||||||
|
==,
|
||||||
|
expected_codes[index]
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_cmpstr(
|
||||||
|
entity_type_get_label(
|
||||||
|
entity_type
|
||||||
|
),
|
||||||
|
==,
|
||||||
|
expected_labels[index]
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le catalogue V1 ne renseigne aucune description.
|
||||||
|
*/
|
||||||
|
g_assert_null(
|
||||||
|
entity_type_get_description(
|
||||||
|
entity_type
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_unref(
|
||||||
|
entity_types
|
||||||
|
);
|
||||||
|
|
||||||
|
test_entity_type_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie qu'une table vide retourne un tableau vide.
|
||||||
|
*/
|
||||||
|
static void test_entity_type_dao_list_empty(void)
|
||||||
|
{
|
||||||
|
TestEntityTypeDaoFixture fixture =
|
||||||
|
test_entity_type_dao_fixture_create();
|
||||||
|
|
||||||
|
GPtrArray *entity_types =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
test_entity_type_dao_execute_sql(
|
||||||
|
fixture.database,
|
||||||
|
"DELETE FROM types_entite;"
|
||||||
|
);
|
||||||
|
|
||||||
|
entity_types =
|
||||||
|
entity_type_dao_list_all(
|
||||||
|
fixture.entity_type_dao,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_no_error(
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
entity_types
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_cmpuint(
|
||||||
|
entity_types->len,
|
||||||
|
==,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
g_ptr_array_unref(
|
||||||
|
entity_types
|
||||||
|
);
|
||||||
|
|
||||||
|
test_entity_type_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le signalement d'une table absente.
|
||||||
|
*/
|
||||||
|
static void test_entity_type_dao_missing_table(void)
|
||||||
|
{
|
||||||
|
Database *database =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
EntityTypeDao *entity_type_dao =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GPtrArray *entity_types =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
database =
|
||||||
|
database_open(
|
||||||
|
":memory:"
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
|
||||||
|
entity_type_dao =
|
||||||
|
entity_type_dao_new(
|
||||||
|
database,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_no_error(
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_nonnull(
|
||||||
|
entity_type_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
g_test_expect_message(
|
||||||
|
NULL,
|
||||||
|
G_LOG_LEVEL_WARNING,
|
||||||
|
"*Impossible de préparer la requête SQL*"
|
||||||
|
);
|
||||||
|
|
||||||
|
entity_types =
|
||||||
|
entity_type_dao_list_all(
|
||||||
|
entity_type_dao,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_test_assert_expected_messages();
|
||||||
|
|
||||||
|
g_assert_null(
|
||||||
|
entity_types
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_error(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_SCHEMA
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
entity_type_dao_free(
|
||||||
|
entity_type_dao
|
||||||
|
);
|
||||||
|
|
||||||
|
database_close(
|
||||||
|
database
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le refus d'une ligne produisant un modèle invalide.
|
||||||
|
*/
|
||||||
|
static void test_entity_type_dao_invalid_model(void)
|
||||||
|
{
|
||||||
|
TestEntityTypeDaoFixture fixture =
|
||||||
|
test_entity_type_dao_fixture_create();
|
||||||
|
|
||||||
|
GPtrArray *entity_types =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le schéma interdit NULL mais autorise actuellement
|
||||||
|
* une chaîne uniquement composée d'espaces.
|
||||||
|
*/
|
||||||
|
test_entity_type_dao_execute_sql(
|
||||||
|
fixture.database,
|
||||||
|
"UPDATE types_entite "
|
||||||
|
"SET code = ' ' "
|
||||||
|
"WHERE id = 1;"
|
||||||
|
);
|
||||||
|
|
||||||
|
entity_types =
|
||||||
|
entity_type_dao_list_all(
|
||||||
|
fixture.entity_type_dao,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_null(
|
||||||
|
entity_types
|
||||||
|
);
|
||||||
|
|
||||||
|
g_assert_error(
|
||||||
|
error,
|
||||||
|
ENTITY_TYPE_DAO_ERROR,
|
||||||
|
ENTITY_TYPE_DAO_ERROR_MODEL
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
test_entity_type_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(
|
||||||
|
int argc,
|
||||||
|
char **argv
|
||||||
|
)
|
||||||
|
{
|
||||||
|
g_test_init(
|
||||||
|
&argc,
|
||||||
|
&argv,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
g_test_add_func(
|
||||||
|
"/entity-type-dao/new-invalid-database",
|
||||||
|
test_entity_type_dao_new_invalid_database
|
||||||
|
);
|
||||||
|
|
||||||
|
g_test_add_func(
|
||||||
|
"/entity-type-dao/list-all",
|
||||||
|
test_entity_type_dao_list_all
|
||||||
|
);
|
||||||
|
|
||||||
|
g_test_add_func(
|
||||||
|
"/entity-type-dao/list-empty",
|
||||||
|
test_entity_type_dao_list_empty
|
||||||
|
);
|
||||||
|
|
||||||
|
g_test_add_func(
|
||||||
|
"/entity-type-dao/missing-table",
|
||||||
|
test_entity_type_dao_missing_table
|
||||||
|
);
|
||||||
|
|
||||||
|
g_test_add_func(
|
||||||
|
"/entity-type-dao/invalid-model",
|
||||||
|
test_entity_type_dao_invalid_model
|
||||||
|
);
|
||||||
|
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue