labfy-investigation/tests/test_evidence_importer.c
2026-07-19 21:03:12 +02:00

2665 lines
50 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* @file test_evidence_importer.c
* @brief Tests de limport transactionnel des preuves.
******************************************************************************/
#include "core/evidence_importer.h"
#include "dao/evidence_dao.h"
#include "database/database.h"
#include "database/transaction.h"
#include "models/evidence_record.h"
#include "core/evidence_importer_test.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <glib/gstdio.h>
/**
* @brief Dossier relatif utilisé par les tests.
*/
#define TEST_EVIDENCE_RELATIVE_DIRECTORY \
"01_Preuves_Originales/Documents"
/**
* @brief Environnement temporaire dun test EvidenceImporter.
*/
typedef struct
{
char *root_directory;
char *database_path;
char *source_directory;
char *evidence_directory;
char *destination_directory;
Database *database;
EvidenceDao *evidence_dao;
EvidenceImporter *evidence_importer;
} TestEvidenceImporterFixture;
/**
* @brief Vérifie grossièrement le format UTC strict du modèle.
*/
static void test_evidence_importer_assert_utc_timestamp(
const char *timestamp
)
{
assert(timestamp != NULL);
assert(
strlen(
timestamp
) == 20
);
assert(timestamp[4] == '-');
assert(timestamp[7] == '-');
assert(timestamp[10] == 'T');
assert(timestamp[13] == ':');
assert(timestamp[16] == ':');
assert(timestamp[19] == 'Z');
}
/**
* @brief Crée une enquête temporaire complète.
*/
static TestEvidenceImporterFixture
test_evidence_importer_fixture_create(void)
{
TestEvidenceImporterFixture fixture = {0};
GError *error = NULL;
fixture.root_directory =
g_dir_make_tmp(
"labfy-evidence-importer-test-XXXXXX",
&error
);
assert(fixture.root_directory != NULL);
assert(error == NULL);
fixture.database_path =
g_build_filename(
fixture.root_directory,
"Enquete.sqlite",
NULL
);
fixture.source_directory =
g_build_filename(
fixture.root_directory,
"sources",
NULL
);
fixture.evidence_directory =
g_build_filename(
fixture.root_directory,
"01_Preuves_Originales",
NULL
);
fixture.destination_directory =
g_build_filename(
fixture.evidence_directory,
"Documents",
NULL
);
assert(fixture.database_path != NULL);
assert(fixture.source_directory != NULL);
assert(fixture.evidence_directory != NULL);
assert(fixture.destination_directory != NULL);
assert(
g_mkdir(
fixture.source_directory,
0700
) == 0
);
assert(
g_mkdir(
fixture.evidence_directory,
0700
) == 0
);
assert(
g_mkdir(
fixture.destination_directory,
0700
) == 0
);
assert(
database_initialize(
fixture.database_path,
"Enquete_EvidenceImporter",
fixture.root_directory
)
);
fixture.database =
database_open(
fixture.database_path
);
assert(fixture.database != NULL);
fixture.evidence_dao =
evidence_dao_new(
fixture.database,
&error
);
assert(fixture.evidence_dao != NULL);
assert(error == NULL);
fixture.evidence_importer =
evidence_importer_new(
fixture.database,
&error
);
assert(fixture.evidence_importer != NULL);
assert(error == NULL);
return fixture;
}
/**
* @brief Détruit une fixture dont les preuves ont déjà été supprimées.
*/
static void test_evidence_importer_fixture_clear(
TestEvidenceImporterFixture *fixture
)
{
assert(fixture != NULL);
evidence_importer_free(
fixture->evidence_importer
);
evidence_dao_free(
fixture->evidence_dao
);
database_close(
fixture->database
);
assert(
g_remove(
fixture->database_path
) == 0
);
assert(
g_rmdir(
fixture->destination_directory
) == 0
);
assert(
g_rmdir(
fixture->evidence_directory
) == 0
);
assert(
g_rmdir(
fixture->source_directory
) == 0
);
assert(
g_rmdir(
fixture->root_directory
) == 0
);
g_free(
fixture->destination_directory
);
g_free(
fixture->evidence_directory
);
g_free(
fixture->source_directory
);
g_free(
fixture->database_path
);
g_free(
fixture->root_directory
);
fixture->evidence_importer = NULL;
fixture->evidence_dao = NULL;
fixture->database = NULL;
fixture->destination_directory = NULL;
fixture->evidence_directory = NULL;
fixture->source_directory = NULL;
fixture->database_path = NULL;
fixture->root_directory = NULL;
}
/**
* @brief Vérifie le refus dune connexion absente.
*/
static void test_evidence_importer_new_null_database(void)
{
EvidenceImporter *evidence_importer = NULL;
GError *error = NULL;
evidence_importer =
evidence_importer_new(
NULL,
&error
);
assert(evidence_importer == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_INVALID_ARGUMENT
);
g_clear_error(
&error
);
evidence_importer_free(
NULL
);
}
/**
* @brief Vérifie la création et la libération dun importeur valide.
*/
static void test_evidence_importer_new_valid(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
/*
* La création de la fixture prouve que limporteur et le DAO
* peuvent emprunter simultanément la même connexion.
*/
assert(fixture.evidence_importer != NULL);
assert(fixture.evidence_dao != NULL);
assert(fixture.database != NULL);
assert(
!database_transaction_is_active(
fixture.database
)
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie un import complet : fichier, modèle et SQLite.
*/
static void test_evidence_importer_import_valid_text_file(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
EvidenceRecord *loaded_record = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *expected_relative_path = NULL;
char *source_contents = NULL;
char *destination_contents = NULL;
const char *identifier = NULL;
const char *internal_name = NULL;
gsize source_contents_size = 0;
gsize destination_contents_size = 0;
guint64 evidence_count = 0;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"Preuve Originale.TXT",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"abc",
3,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
request.collected_at =
"2026-07-18T20:30:00Z";
request.source =
"Fichier communiqué directement par la victime.";
request.description =
"Première preuve importée par le service transactionnel.";
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(error == NULL);
assert(evidence_record != NULL);
/*
* Le commit doit être terminé avant le retour.
*/
assert(
!database_transaction_is_active(
fixture.database
)
);
identifier =
evidence_record_get_identifier(
evidence_record
);
internal_name =
evidence_record_get_internal_name(
evidence_record
);
assert(identifier != NULL);
assert(internal_name != NULL);
assert(
g_uuid_string_is_valid(
identifier
)
);
assert(
strcmp(
evidence_record_get_original_name(
evidence_record
),
"Preuve Originale.TXT"
) == 0
);
/*
* Lextension est normalisée en minuscules.
*/
assert(
g_str_has_prefix(
internal_name,
identifier
)
);
assert(
g_str_has_suffix(
internal_name,
".txt"
)
);
destination_path =
g_build_filename(
fixture.destination_directory,
internal_name,
NULL
);
expected_relative_path =
g_build_filename(
TEST_EVIDENCE_RELATIVE_DIRECTORY,
internal_name,
NULL
);
assert(destination_path != NULL);
assert(expected_relative_path != NULL);
assert(
strcmp(
evidence_record_get_relative_path(
evidence_record
),
expected_relative_path
) == 0
);
assert(
strcmp(
evidence_record_get_type_identifier(
evidence_record
),
"document"
) == 0
);
assert(
evidence_record_get_size_bytes(
evidence_record
) == 3
);
assert(
strcmp(
evidence_record_get_sha256(
evidence_record
),
"ba7816bf8f01cfea414140de5dae2223"
"b00361a396177a9cb410ff61f20015ad"
) == 0
);
test_evidence_importer_assert_utc_timestamp(
evidence_record_get_imported_at(
evidence_record
)
);
assert(
strcmp(
evidence_record_get_collected_at(
evidence_record
),
request.collected_at
) == 0
);
assert(
strcmp(
evidence_record_get_source(
evidence_record
),
request.source
) == 0
);
assert(
strcmp(
evidence_record_get_description(
evidence_record
),
request.description
) == 0
);
assert(
evidence_record_get_integrity_status(
evidence_record
) ==
EVIDENCE_INTEGRITY_STATUS_VALID
);
/*
* La copie validée doit exister après le commit.
*/
assert(
g_file_test(
destination_path,
G_FILE_TEST_IS_REGULAR
)
);
assert(
g_file_get_contents(
source_path,
&source_contents,
&source_contents_size,
&error
)
);
assert(error == NULL);
assert(
g_file_get_contents(
destination_path,
&destination_contents,
&destination_contents_size,
&error
)
);
assert(error == NULL);
assert(source_contents_size == 3);
assert(destination_contents_size == 3);
assert(
memcmp(
source_contents,
"abc",
3
) == 0
);
assert(
memcmp(
destination_contents,
source_contents,
3
) == 0
);
/*
* La ligne SQLite doit exister exactement une fois.
*/
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
&error
)
);
assert(error == NULL);
assert(evidence_count == 1);
loaded_record =
evidence_dao_find_by_identifier(
fixture.evidence_dao,
identifier,
&error
);
assert(error == NULL);
assert(loaded_record != NULL);
assert(
strcmp(
evidence_record_get_identifier(
loaded_record
),
identifier
) == 0
);
assert(
strcmp(
evidence_record_get_original_name(
loaded_record
),
evidence_record_get_original_name(
evidence_record
)
) == 0
);
assert(
strcmp(
evidence_record_get_internal_name(
loaded_record
),
internal_name
) == 0
);
assert(
strcmp(
evidence_record_get_relative_path(
loaded_record
),
expected_relative_path
) == 0
);
assert(
evidence_record_get_size_bytes(
loaded_record
) ==
evidence_record_get_size_bytes(
evidence_record
)
);
assert(
strcmp(
evidence_record_get_sha256(
loaded_record
),
evidence_record_get_sha256(
evidence_record
)
) == 0
);
assert(
strcmp(
evidence_record_get_imported_at(
loaded_record
),
evidence_record_get_imported_at(
evidence_record
)
) == 0
);
assert(
evidence_record_get_integrity_status(
loaded_record
) ==
EVIDENCE_INTEGRITY_STATUS_VALID
);
evidence_record_free(
loaded_record
);
evidence_record_free(
evidence_record
);
g_free(
destination_contents
);
g_free(
source_contents
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
expected_relative_path
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie limport dun fichier vide sans métadonnées facultatives.
*/
static void test_evidence_importer_import_empty_optional_null(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
EvidenceRecord *loaded_record = NULL;
char *source_path = NULL;
char *destination_path = NULL;
const char *identifier = NULL;
const char *internal_name = NULL;
guint64 evidence_count = 0;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"preuve_vide",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"",
0,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
request.collected_at = NULL;
request.source = NULL;
request.description = NULL;
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(error == NULL);
assert(evidence_record != NULL);
identifier =
evidence_record_get_identifier(
evidence_record
);
internal_name =
evidence_record_get_internal_name(
evidence_record
);
assert(identifier != NULL);
assert(internal_name != NULL);
/*
* Le fichier original ne possède pas dextension :
* le nom interne doit être exactement lUUID.
*/
assert(
strcmp(
internal_name,
identifier
) == 0
);
assert(
evidence_record_get_size_bytes(
evidence_record
) == 0
);
assert(
strcmp(
evidence_record_get_sha256(
evidence_record
),
"e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855"
) == 0
);
assert(
evidence_record_get_collected_at(
evidence_record
) == NULL
);
assert(
evidence_record_get_source(
evidence_record
) == NULL
);
assert(
evidence_record_get_description(
evidence_record
) == NULL
);
destination_path =
g_build_filename(
fixture.destination_directory,
internal_name,
NULL
);
assert(destination_path != NULL);
assert(
g_file_test(
destination_path,
G_FILE_TEST_IS_REGULAR
)
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
&error
)
);
assert(error == NULL);
assert(evidence_count == 1);
loaded_record =
evidence_dao_find_by_identifier(
fixture.evidence_dao,
identifier,
&error
);
assert(error == NULL);
assert(loaded_record != NULL);
assert(
evidence_record_get_collected_at(
loaded_record
) == NULL
);
assert(
evidence_record_get_source(
loaded_record
) == NULL
);
assert(
evidence_record_get_description(
loaded_record
) == NULL
);
evidence_record_free(
loaded_record
);
evidence_record_free(
evidence_record
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie limport exact dun fichier binaire.
*/
static void test_evidence_importer_import_binary_file(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
static const guint8 binary_data[] =
{
0x00,
0xFF,
0x80,
0x41,
0x00,
0x7F,
0x10
};
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *destination_contents = NULL;
const char *internal_name = NULL;
gsize destination_contents_size = 0;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"donnees.BIN",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
(const char *) binary_data,
(gssize) sizeof(binary_data),
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(error == NULL);
assert(evidence_record != NULL);
internal_name =
evidence_record_get_internal_name(
evidence_record
);
assert(internal_name != NULL);
assert(
g_str_has_suffix(
internal_name,
".bin"
)
);
assert(
evidence_record_get_size_bytes(
evidence_record
) ==
sizeof(binary_data)
);
assert(
strcmp(
evidence_record_get_sha256(
evidence_record
),
"c90d3a7754f84abc867e780e5a0c0f8d"
"a5c663bd1766ad89e538536a3763f367"
) == 0
);
destination_path =
g_build_filename(
fixture.destination_directory,
internal_name,
NULL
);
assert(destination_path != NULL);
assert(
g_file_get_contents(
destination_path,
&destination_contents,
&destination_contents_size,
&error
)
);
assert(error == NULL);
assert(
destination_contents_size ==
sizeof(binary_data)
);
assert(
memcmp(
destination_contents,
binary_data,
sizeof(binary_data)
) == 0
);
assert(
!database_transaction_is_active(
fixture.database
)
);
evidence_record_free(
evidence_record
);
g_free(
destination_contents
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Compte les entrées présentes dans le dossier de destination.
*/
static guint test_evidence_importer_count_destination_entries(
const TestEvidenceImporterFixture *fixture
)
{
GDir *directory = NULL;
const char *entry_name = NULL;
guint entry_count = 0;
GError *error = NULL;
assert(fixture != NULL);
assert(fixture->destination_directory != NULL);
directory =
g_dir_open(
fixture->destination_directory,
0,
&error
);
assert(directory != NULL);
assert(error == NULL);
while ((entry_name = g_dir_read_name(directory)) != NULL)
{
assert(entry_name[0] != '\0');
entry_count++;
}
g_dir_close(
directory
);
return entry_count;
}
/**
* @brief Vérifie quune annulation préalable ne crée aucune preuve.
*/
static void test_evidence_importer_cancelled_before_copy(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
GCancellable *cancellable = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"preuve_annulee.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve annulee",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
cancellable =
g_cancellable_new();
assert(cancellable != NULL);
g_cancellable_cancel(
cancellable
);
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
cancellable,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_CANCELLED
);
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
assert(
!database_transaction_is_active(
fixture.database
)
);
g_clear_error(
&error
);
g_object_unref(
cancellable
);
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le rollback et le nettoyage pour un type inconnu.
*/
static void test_evidence_importer_unknown_type_cleanup(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"preuve_type_inconnu.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"contenu de preuve",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"type_totalement_inconnu";
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_DATABASE
);
assert(
strstr(
error->message,
"type de preuve"
) != NULL
);
/*
* La copie créée avant linsertion doit avoir été supprimée.
*/
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
assert(
!database_transaction_is_active(
fixture.database
)
);
/*
* Le fichier source ne doit jamais être supprimé ou modifié.
*/
assert(
g_file_test(
source_path,
G_FILE_TEST_IS_REGULAR
)
);
g_clear_error(
&error
);
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie que limporteur respecte une transaction appelante.
*/
static void test_evidence_importer_transaction_already_active(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"preuve_transaction.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"transaction externe",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
assert(
database_transaction_begin(
fixture.database
)
);
assert(
database_transaction_is_active(
fixture.database
)
);
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_DATABASE
);
/*
* Limporteur ne possède pas cette transaction :
* il ne doit donc pas lannuler.
*/
assert(
database_transaction_is_active(
fixture.database
)
);
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
g_clear_error(
&error
);
assert(
database_transaction_rollback(
fixture.database
)
);
assert(
!database_transaction_is_active(
fixture.database
)
);
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le nettoyage lorsque le modèle refuse les métadonnées.
*/
static void test_evidence_importer_invalid_collected_at_cleanup(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"preuve_date_invalide.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve avec date invalide",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
/*
* EvidenceRecord exige une date UTC stricte.
*/
request.collected_at =
"18/07/2026 20:30";
request.source =
"Fichier de test.";
request.description =
"La création du modèle doit échouer.";
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_MODEL
);
/*
* La copie a eu lieu avant la création du modèle,
* mais elle doit avoir été supprimée.
*/
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
assert(
!database_transaction_is_active(
fixture.database
)
);
/*
* Le fichier source reste intact.
*/
assert(
g_file_test(
source_path,
G_FILE_TEST_IS_REGULAR
)
);
g_clear_error(
&error
);
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie la conservation dun nom original complexe.
*/
static void test_evidence_importer_complex_original_name(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
char *destination_path = NULL;
const char *identifier = NULL;
const char *internal_name = NULL;
guint64 evidence_count = 0;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"Capture été.Version Finale.PDF",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"contenu du document",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(error == NULL);
assert(evidence_record != NULL);
identifier =
evidence_record_get_identifier(
evidence_record
);
internal_name =
evidence_record_get_internal_name(
evidence_record
);
assert(identifier != NULL);
assert(internal_name != NULL);
/*
* Le nom fourni par lutilisateur doit être conservé
* exactement dans le modèle.
*/
assert(
strcmp(
evidence_record_get_original_name(
evidence_record
),
"Capture été.Version Finale.PDF"
) == 0
);
/*
* Le nom interne ne conserve que lUUID et
* lextension finale normalisée.
*/
assert(
g_str_has_prefix(
internal_name,
identifier
)
);
assert(
g_str_has_suffix(
internal_name,
".pdf"
)
);
assert(
strlen(
internal_name
) ==
strlen(identifier) + strlen(".pdf")
);
assert(
strchr(
internal_name,
' '
) == NULL
);
assert(
strchr(
internal_name,
'/'
) == NULL
);
assert(
strchr(
internal_name,
'\\'
) == NULL
);
destination_path =
g_build_filename(
fixture.destination_directory,
internal_name,
NULL
);
assert(destination_path != NULL);
assert(
g_file_test(
destination_path,
G_FILE_TEST_IS_REGULAR
)
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
&error
)
);
assert(error == NULL);
assert(evidence_count == 1);
assert(
!database_transaction_is_active(
fixture.database
)
);
evidence_record_free(
evidence_record
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le refus dun chemin relatif sortant de lenquête.
*/
static void test_evidence_importer_invalid_relative_directory(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"preuve.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"contenu",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
"../../hors_enquete";
request.type_identifier =
"document";
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_INVALID_ARGUMENT
);
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
assert(
!database_transaction_is_active(
fixture.database
)
);
g_clear_error(
&error
);
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le refus dun fichier source inexistant.
*/
static void test_evidence_importer_missing_source(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
source_path =
g_build_filename(
fixture.source_directory,
"preuve_absente.txt",
NULL
);
assert(source_path != NULL);
assert(
!g_file_test(
source_path,
G_FILE_TEST_EXISTS
)
);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_COPY
);
assert(
strstr(
error->message,
"Impossible de copier"
) != NULL
);
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
assert(
!database_transaction_is_active(
fixture.database
)
);
g_clear_error(
&error
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie lannulation après la création de la copie.
*/
static void test_evidence_importer_cancelled_after_copy_cleanup(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
GCancellable *cancellable = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
evidence_importer_test_reset_hooks();
source_path =
g_build_filename(
fixture.source_directory,
"preuve_annulee_apres_copie.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"annulation après copie",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
cancellable =
g_cancellable_new();
assert(cancellable != NULL);
evidence_importer_test_set_cancel_after_copy(
TRUE
);
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
cancellable,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_CANCELLED
);
/*
* Le fichier a été copié avant lannulation,
* puis supprimé par la compensation.
*/
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
assert(
!database_transaction_is_active(
fixture.database
)
);
assert(
g_file_test(
source_path,
G_FILE_TEST_IS_REGULAR
)
);
evidence_importer_test_reset_hooks();
g_clear_error(
&error
);
g_object_unref(
cancellable
);
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le rollback lorsque le COMMIT SQLite échoue.
*/
static void test_evidence_importer_commit_failure_cleanup(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
char *source_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
evidence_importer_test_reset_hooks();
source_path =
g_build_filename(
fixture.source_directory,
"preuve_commit_echec.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"échec artificiel du commit",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
request.type_identifier =
"document";
request.source =
"Test du rollback après échec du commit.";
evidence_importer_test_set_commit_failure(
TRUE
);
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_DATABASE
);
assert(
strstr(
error->message,
"COMMIT simulé"
) != NULL
);
/*
* Linsertion a eu lieu dans la transaction,
* mais le rollback doit lavoir annulée.
*/
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
/*
* La copie doit également avoir été supprimée.
*/
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 0
);
assert(
!database_transaction_is_active(
fixture.database
)
);
/*
* Le fichier source reste intact.
*/
assert(
g_file_test(
source_path,
G_FILE_TEST_IS_REGULAR
)
);
evidence_importer_test_reset_hooks();
g_clear_error(
&error
);
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le signalement dune copie orpheline.
*/
static void test_evidence_importer_cleanup_failure_reports_orphan(void)
{
TestEvidenceImporterFixture fixture =
test_evidence_importer_fixture_create();
EvidenceImportRequest request = {0};
EvidenceRecord *evidence_record = NULL;
GDir *destination_directory = NULL;
const char *orphan_name = NULL;
char *source_path = NULL;
char *orphan_path = NULL;
guint64 evidence_count = 42;
GError *error = NULL;
GError *directory_error = NULL;
evidence_importer_test_reset_hooks();
source_path =
g_build_filename(
fixture.source_directory,
"preuve_nettoyage_echec.txt",
NULL
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"échec artificiel du nettoyage",
-1,
&error
)
);
assert(error == NULL);
request.source_path =
source_path;
request.destination_directory =
fixture.destination_directory;
request.relative_directory =
TEST_EVIDENCE_RELATIVE_DIRECTORY;
/*
* Le type inconnu provoque léchec après la copie.
*/
request.type_identifier =
"type_inconnu_pour_nettoyage";
evidence_importer_test_set_cleanup_failure(
TRUE
);
evidence_record =
evidence_importer_import(
fixture.evidence_importer,
&request,
NULL,
&error
);
assert(evidence_record == NULL);
assert(error != NULL);
assert(
error->domain ==
EVIDENCE_IMPORTER_ERROR
);
assert(
error->code ==
(gint) EVIDENCE_IMPORTER_ERROR_ROLLBACK
);
assert(
strstr(
error->message,
"na pas pu être supprimée"
) != NULL
);
assert(
strstr(
error->message,
"Cause initiale"
) != NULL
);
/*
* Linsertion SQLite a été annulée.
*/
assert(
evidence_dao_count(
fixture.evidence_dao,
&evidence_count,
NULL
)
);
assert(evidence_count == 0);
assert(
!database_transaction_is_active(
fixture.database
)
);
/*
* Le hook a empêché la suppression :
* une copie orpheline doit donc être présente.
*/
assert(
test_evidence_importer_count_destination_entries(
&fixture
) == 1
);
destination_directory =
g_dir_open(
fixture.destination_directory,
0,
&directory_error
);
assert(destination_directory != NULL);
assert(directory_error == NULL);
orphan_name =
g_dir_read_name(
destination_directory
);
assert(orphan_name != NULL);
assert(orphan_name[0] != '\0');
orphan_path =
g_build_filename(
fixture.destination_directory,
orphan_name,
NULL
);
assert(orphan_path != NULL);
assert(
g_file_test(
orphan_path,
G_FILE_TEST_IS_REGULAR
)
);
/*
* Le message doit permettre de localiser le fichier orphelin.
*/
assert(
strstr(
error->message,
orphan_path
) != NULL
);
g_dir_close(
destination_directory
);
destination_directory = NULL;
/*
* On désactive le hook avant de nettoyer manuellement
* lenvironnement du test.
*/
evidence_importer_test_reset_hooks();
g_clear_error(
&error
);
assert(
g_remove(
orphan_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
orphan_path
);
g_free(
source_path
);
test_evidence_importer_fixture_clear(
&fixture
);
}
int main(void)
{
test_evidence_importer_new_null_database();
test_evidence_importer_new_valid();
test_evidence_importer_import_valid_text_file();
test_evidence_importer_import_empty_optional_null();
test_evidence_importer_import_binary_file();
test_evidence_importer_cancelled_before_copy();
test_evidence_importer_unknown_type_cleanup();
test_evidence_importer_transaction_already_active();
test_evidence_importer_invalid_collected_at_cleanup();
test_evidence_importer_complex_original_name();
test_evidence_importer_invalid_relative_directory();
test_evidence_importer_missing_source();
test_evidence_importer_cancelled_after_copy_cleanup();
test_evidence_importer_commit_failure_cleanup();
test_evidence_importer_cleanup_failure_reports_orphan();
printf(
"EvidenceImporter : premiers tests transactionnels valides.\n"
);
return 0;
}