From 95839efba6d02d33063a12cece521ec2db015cdf Mon Sep 17 00:00:00 2001 From: grayTerminal-sh Date: Mon, 20 Jul 2026 20:40:40 +0200 Subject: [PATCH] feat: add entity type DAO --- Makefile | 17 +- include/dao/entity_type_dao.h | 121 +++++++ src/dao/entity_type_dao.c | 518 ++++++++++++++++++++++++++++++ tests/test_entity_type_dao.c | 578 ++++++++++++++++++++++++++++++++++ 4 files changed, 1233 insertions(+), 1 deletion(-) create mode 100644 include/dao/entity_type_dao.h create mode 100644 src/dao/entity_type_dao.c create mode 100644 tests/test_entity_type_dao.c diff --git a/Makefile b/Makefile index ab99d6c..89bd421 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ EVIDENCE_INTEGRITY_VERIFIER_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") @@ -84,6 +85,7 @@ TEST_EVIDENCE_CATEGORY_ITEM := tests/test_evidence_category_item TEST_EVIDENCE_CATEGORY_MODEL := tests/test_evidence_category_model TEST_EVIDENCE_INTEGRITY_TASK := tests/test_evidence_integrity_task TEST_ENTITY_RECORD := tests/test_entity_record +TEST_ENTITY_TYPE_DAO := tests/test_entity_type_dao all: $(TARGET) @@ -375,6 +377,17 @@ $(TEST_ENTITY_RECORD): \ src/models/entity_record.c $(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_NODE) \ $(TEST_TREE_MODEL) \ @@ -410,7 +423,8 @@ test: \ $(TEST_EVIDENCE_IMPORT_TASK) \ $(TEST_EVIDENCE_IMPORT_DIALOG) \ $(TEST_EVIDENCE_INTEGRITY_TASK) \ - $(TEST_ENTITY_RECORD) + $(TEST_ENTITY_RECORD) \ + $(TEST_ENTITY_TYPE_DAO) @echo "Exécution des tests..." @./$(TEST_NODE) @./$(TEST_TREE_MODEL) @@ -447,6 +461,7 @@ test: \ @$(TEST_EVIDENCE_IMPORT_DIALOG) @$(TEST_EVIDENCE_INTEGRITY_TASK) @$(TEST_ENTITY_RECORD) + @$(TEST_ENTITY_TYPE_DAO) @echo "Tous les tests sont valides." %.o: %.c diff --git a/include/dao/entity_type_dao.h b/include/dao/entity_type_dao.h new file mode 100644 index 0000000..e1d1f99 --- /dev/null +++ b/include/dao/entity_type_dao.h @@ -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 + +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 diff --git a/src/dao/entity_type_dao.c b/src/dao/entity_type_dao.c new file mode 100644 index 0000000..82c1625 --- /dev/null +++ b/src/dao/entity_type_dao.c @@ -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 +#include + +/** + * @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; +} diff --git a/tests/test_entity_type_dao.c b/tests/test_entity_type_dao.c new file mode 100644 index 0000000..781e889 --- /dev/null +++ b/tests/test_entity_type_dao.c @@ -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 +#include + +/** + * @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(); +}