labfy-investigation/tests/test_evidence_copy.c
2026-07-19 16:51:06 +02:00

3194 lines
59 KiB
C
Raw Permalink 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_copy.c
* @brief Tests de la copie sûre des fichiers de preuve.
******************************************************************************/
#define _POSIX_C_SOURCE 200809L
#ifndef EVIDENCE_COPY_ENABLE_TEST_HOOKS
#define EVIDENCE_COPY_ENABLE_TEST_HOOKS
#endif
#include "core/evidence_copy.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <sys/stat.h>
/**
* @brief Environnement temporaire des tests EvidenceCopy.
*/
typedef struct
{
char *root_directory;
char *source_directory;
char *destination_directory;
} TestEvidenceCopyFixture;
/**
* @brief Contexte dannulation pendant la copie.
*/
typedef struct
{
GCancellable *cancellable;
guint block_count;
} TestEvidenceCopyCancellationContext;
/**
* @brief Contexte dune erreur décriture simulée.
*/
typedef struct
{
guint64 fail_after_size_bytes;
guint call_count;
} TestEvidenceCopyWriteFailureContext;
/**
* @brief Contexte de corruption avant vérification.
*/
typedef struct
{
guint call_count;
} TestEvidenceCopyVerifyFailureContext;
/**
* @brief Contexte de modification du fichier source.
*/
typedef struct
{
const char *source_path;
guint call_count;
} TestEvidenceCopySourceModificationContext;
/**
* @brief Contexte dun échec de nettoyage simulé.
*/
typedef struct
{
guint call_count;
} TestEvidenceCopyCleanupFailureContext;
/**
* @brief Crée un environnement temporaire isolé.
*/
static TestEvidenceCopyFixture
test_evidence_copy_fixture_create(void)
{
TestEvidenceCopyFixture fixture = {0};
GError *error = NULL;
fixture.root_directory =
g_dir_make_tmp(
"labfy-evidence-copy-test-XXXXXX",
&error
);
assert(error == NULL);
assert(fixture.root_directory != NULL);
fixture.source_directory =
g_build_filename(
fixture.root_directory,
"source",
NULL
);
fixture.destination_directory =
g_build_filename(
fixture.root_directory,
"destination",
NULL
);
assert(fixture.source_directory != NULL);
assert(fixture.destination_directory != NULL);
assert(
g_mkdir(
fixture.source_directory,
0700
) == 0
);
assert(
g_mkdir(
fixture.destination_directory,
0700
) == 0
);
return fixture;
}
/**
* @brief Vérifie une erreur EvidenceCopy.
*/
static void test_evidence_copy_assert_error(
const GError *error,
EvidenceCopyError expected_error
)
{
assert(error != NULL);
assert(error->domain == EVIDENCE_COPY_ERROR);
assert(
error->code ==
(gint) expected_error
);
assert(error->message != NULL);
assert(error->message[0] != '\0');
}
/**
* @brief Supprime un environnement temporaire vide.
*/
static void test_evidence_copy_fixture_clear(
TestEvidenceCopyFixture *fixture
)
{
assert(fixture != NULL);
assert(fixture->root_directory != NULL);
assert(fixture->source_directory != NULL);
assert(fixture->destination_directory != NULL);
assert(
g_rmdir(
fixture->destination_directory
) == 0
);
assert(
g_rmdir(
fixture->source_directory
) == 0
);
assert(
g_rmdir(
fixture->root_directory
) == 0
);
g_free(
fixture->destination_directory
);
g_free(
fixture->source_directory
);
g_free(
fixture->root_directory
);
fixture->destination_directory = NULL;
fixture->source_directory = NULL;
fixture->root_directory = NULL;
}
/**
* @brief Construit un chemin dans le dossier source.
*/
static char *test_evidence_copy_build_source_path(
const TestEvidenceCopyFixture *fixture,
const char *file_name
)
{
assert(fixture != NULL);
assert(fixture->source_directory != NULL);
assert(file_name != NULL);
return g_build_filename(
fixture->source_directory,
file_name,
NULL
);
}
/**
* @brief Construit un chemin dans le dossier destination.
*/
static char *test_evidence_copy_build_destination_path(
const TestEvidenceCopyFixture *fixture,
const char *file_name
)
{
assert(fixture != NULL);
assert(fixture->destination_directory != NULL);
assert(file_name != NULL);
return g_build_filename(
fixture->destination_directory,
file_name,
NULL
);
}
/**
* @brief Vérifie les accesseurs avec un résultat NULL.
*/
static void test_evidence_copy_null_result(void)
{
assert(
evidence_copy_result_get_destination_path(
NULL
) == NULL
);
assert(
evidence_copy_result_get_destination_name(
NULL
) == NULL
);
assert(
evidence_copy_result_get_sha256(
NULL
) == NULL
);
assert(
evidence_copy_result_get_size_bytes(
NULL
) == 0
);
evidence_copy_result_free(
NULL
);
}
/**
* @brief Vérifie la copie complète du contenu connu « abc ».
*/
static void test_evidence_copy_text_file(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *destination_name = NULL;
char *source_contents = NULL;
char *destination_contents = NULL;
gsize source_contents_size = 0;
gsize destination_contents_size = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"original.txt"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"copie.txt"
);
destination_name =
g_strdup(
"copie.txt"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(destination_name != NULL);
assert(
g_file_set_contents(
source_path,
"abc",
3,
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
destination_name,
NULL,
&error
);
assert(error == NULL);
assert(result != NULL);
/*
* La chaîne fournie par lappelant peut être libérée :
* le résultat doit posséder sa propre copie.
*/
g_free(
destination_name
);
destination_name = NULL;
assert(
strcmp(
evidence_copy_result_get_destination_path(
result
),
destination_path
) == 0
);
assert(
strcmp(
evidence_copy_result_get_destination_name(
result
),
"copie.txt"
) == 0
);
assert(
strcmp(
evidence_copy_result_get_sha256(
result
),
"ba7816bf8f01cfea414140de5dae2223"
"b00361a396177a9cb410ff61f20015ad"
) == 0
);
assert(
evidence_copy_result_get_size_bytes(
result
) == 3
);
/*
* Libérer le résultat ne doit pas supprimer la copie validée.
*/
evidence_copy_result_free(
result
);
result = NULL;
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,
destination_contents,
3
) == 0
);
assert(
memcmp(
source_contents,
"abc",
3
) == 0
);
g_free(
destination_contents
);
g_free(
source_contents
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie la copie dun fichier vide.
*/
static void test_evidence_copy_empty_file(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *destination_contents = NULL;
gsize destination_contents_size = 42;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"empty.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"empty-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"",
0,
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"empty-copy.bin",
NULL,
&error
);
assert(error == NULL);
assert(result != NULL);
assert(
evidence_copy_result_get_size_bytes(
result
) == 0
);
assert(
strcmp(
evidence_copy_result_get_sha256(
result
),
"e3b0c44298fc1c149afbf4c8996fb924"
"27ae41e4649b934ca495991b7852b855"
) == 0
);
assert(
strcmp(
evidence_copy_result_get_destination_path(
result
),
destination_path
) == 0
);
evidence_copy_result_free(
result
);
result = NULL;
assert(
g_file_test(
destination_path,
G_FILE_TEST_IS_REGULAR
)
);
assert(
g_file_get_contents(
destination_path,
&destination_contents,
&destination_contents_size,
&error
)
);
assert(error == NULL);
assert(destination_contents != NULL);
assert(destination_contents_size == 0);
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_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie la copie exacte de données binaires.
*/
static void test_evidence_copy_binary_file(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
static const guint8 binary_data[] =
{
0x00,
0xFF,
0x80,
0x41,
0x00,
0x7F,
0x10
};
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *destination_contents = NULL;
gsize destination_contents_size = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"binary-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"binary-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
(const char *) binary_data,
(gssize) sizeof(binary_data),
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"binary-copy.bin",
NULL,
&error
);
assert(error == NULL);
assert(result != NULL);
assert(
evidence_copy_result_get_size_bytes(
result
) == sizeof(binary_data)
);
assert(
strcmp(
evidence_copy_result_get_sha256(
result
),
"c90d3a7754f84abc867e780e5a0c0f8d"
"a5c663bd1766ad89e538536a3763f367"
) == 0
);
evidence_copy_result_free(
result
);
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
);
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_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie la copie dun fichier supérieur au tampon.
*/
static void test_evidence_copy_multiple_blocks(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
const gsize data_size =
(200U * 1024U) + 123U;
EvidenceCopyResult *result = NULL;
guint8 *source_data = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *destination_contents = NULL;
gsize destination_contents_size = 0;
gsize data_index = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"large-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"large-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
source_data =
g_malloc(
data_size
);
assert(source_data != NULL);
for (data_index = 0;
data_index < data_size;
data_index++)
{
source_data[data_index] =
(guint8) (data_index % 251U);
}
assert(
g_file_set_contents(
source_path,
(const char *) source_data,
(gssize) data_size,
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"large-copy.bin",
NULL,
&error
);
assert(error == NULL);
assert(result != NULL);
assert(
evidence_copy_result_get_size_bytes(
result
) == data_size
);
assert(
strcmp(
evidence_copy_result_get_sha256(
result
),
"bc5ad58e926b1f79d9840418910f47ba"
"1e947fb137170b8d5403a537b888c4af"
) == 0
);
evidence_copy_result_free(
result
);
assert(
g_file_get_contents(
destination_path,
&destination_contents,
&destination_contents_size,
&error
)
);
assert(error == NULL);
assert(destination_contents_size == data_size);
assert(
memcmp(
destination_contents,
source_data,
data_size
) == 0
);
g_free(
destination_contents
);
g_free(
source_data
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie les permissions restrictives de la copie.
*/
static void test_evidence_copy_permissions(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
struct stat destination_status;
char *source_path = NULL;
char *destination_path = NULL;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"permissions-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"permissions-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve",
6,
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"permissions-copy.bin",
NULL,
&error
);
assert(error == NULL);
assert(result != NULL);
assert(
stat(
destination_path,
&destination_status
) == 0
);
assert(
S_ISREG(
destination_status.st_mode
)
);
/*
* Aucun droit pour le groupe ou les autres utilisateurs.
*/
assert(
(destination_status.st_mode & 0077) == 0
);
evidence_copy_result_free(
result
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie quun fichier existant nest jamais écrasé.
*/
static void test_evidence_copy_destination_exists(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *source_contents = NULL;
char *destination_contents = NULL;
gsize source_contents_size = 0;
gsize destination_contents_size = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"existing-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"existing-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"nouvelle preuve",
15,
&error
)
);
assert(error == NULL);
assert(
g_file_set_contents(
destination_path,
"ne pas modifier",
15,
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"existing-copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_DESTINATION_EXISTS
);
g_clear_error(
&error
);
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 == 15);
assert(destination_contents_size == 15);
assert(
memcmp(
source_contents,
"nouvelle preuve",
15
) == 0
);
assert(
memcmp(
destination_contents,
"ne pas modifier",
15
) == 0
);
g_free(
destination_contents
);
g_free(
source_contents
);
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie quaucun fichier destination na été créé.
*/
static void test_evidence_copy_assert_destination_absent(
const char *destination_path
)
{
assert(destination_path != NULL);
assert(
!g_file_test(
destination_path,
G_FILE_TEST_EXISTS
)
);
}
/**
* @brief Vérifie le refus des paramètres obligatoires invalides.
*/
static void test_evidence_copy_invalid_arguments(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
GError *error = NULL;
result =
evidence_copy_file(
NULL,
fixture.destination_directory,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_INVALID_ARGUMENT
);
g_clear_error(
&error
);
result =
evidence_copy_file(
"",
fixture.destination_directory,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_INVALID_ARGUMENT
);
g_clear_error(
&error
);
result =
evidence_copy_file(
"/tmp/source.bin",
NULL,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_INVALID_ARGUMENT
);
g_clear_error(
&error
);
result =
evidence_copy_file(
"/tmp/source.bin",
"",
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_INVALID_ARGUMENT
);
g_clear_error(
&error
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le refus des noms pouvant représenter un chemin.
*/
static void test_evidence_copy_invalid_destination_names(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
static const char *invalid_names[] =
{
NULL,
"",
".",
"..",
"subdirectory/copy.bin",
"subdirectory\\copy.bin"
};
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
gsize name_index = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"valid-source.bin"
);
assert(source_path != NULL);
assert(
g_file_set_contents(
source_path,
"source",
6,
&error
)
);
assert(error == NULL);
for (name_index = 0;
name_index < G_N_ELEMENTS(invalid_names);
name_index++)
{
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
invalid_names[name_index],
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_INVALID_ARGUMENT
);
g_clear_error(
&error
);
}
assert(
g_remove(
source_path
) == 0
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le refus dun fichier source absent.
*/
static void test_evidence_copy_missing_source(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"missing.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_SOURCE_NOT_FOUND
);
g_clear_error(
&error
);
test_evidence_copy_assert_destination_absent(
destination_path
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie quun dossier ne peut pas devenir une preuve.
*/
static void test_evidence_copy_source_directory(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *destination_path = NULL;
GError *error = NULL;
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"copy.bin"
);
assert(destination_path != NULL);
result =
evidence_copy_file(
fixture.source_directory,
fixture.destination_directory,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR
);
g_clear_error(
&error
);
test_evidence_copy_assert_destination_absent(
destination_path
);
g_free(
destination_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie quun lien symbolique source nest jamais suivi.
*/
static void test_evidence_copy_source_symbolic_link(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *target_path = NULL;
char *link_path = NULL;
char *destination_path = NULL;
GError *error = NULL;
target_path =
test_evidence_copy_build_source_path(
&fixture,
"target.bin"
);
link_path =
test_evidence_copy_build_source_path(
&fixture,
"source-link.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"copy.bin"
);
assert(target_path != NULL);
assert(link_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
target_path,
"secret",
6,
&error
)
);
assert(error == NULL);
assert(
symlink(
target_path,
link_path
) == 0
);
result =
evidence_copy_file(
link_path,
fixture.destination_directory,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR
);
g_clear_error(
&error
);
test_evidence_copy_assert_destination_absent(
destination_path
);
assert(
g_remove(
link_path
) == 0
);
assert(
g_remove(
target_path
) == 0
);
g_free(
destination_path
);
g_free(
link_path
);
g_free(
target_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie quun tube nommé est refusé sans blocage.
*/
static void test_evidence_copy_source_named_pipe(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *pipe_path = NULL;
char *destination_path = NULL;
GError *error = NULL;
pipe_path =
test_evidence_copy_build_source_path(
&fixture,
"source.fifo"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"copy.bin"
);
assert(pipe_path != NULL);
assert(destination_path != NULL);
assert(
mkfifo(
pipe_path,
0600
) == 0
);
result =
evidence_copy_file(
pipe_path,
fixture.destination_directory,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR
);
g_clear_error(
&error
);
test_evidence_copy_assert_destination_absent(
destination_path
);
assert(
g_remove(
pipe_path
) == 0
);
g_free(
destination_path
);
g_free(
pipe_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie une annulation demandée avant limport.
*/
static void test_evidence_copy_cancelled_before_start(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
GCancellable *cancellable = NULL;
char *source_path = NULL;
char *destination_path = NULL;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"cancelled-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"cancelled-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"source stable",
13,
&error
)
);
assert(error == NULL);
cancellable =
g_cancellable_new();
assert(cancellable != NULL);
g_cancellable_cancel(
cancellable
);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"cancelled-copy.bin",
cancellable,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_CANCELLED
);
g_clear_error(
&error
);
test_evidence_copy_assert_destination_absent(
destination_path
);
g_object_unref(
cancellable
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie le refus dun dossier destination absent.
*/
static void test_evidence_copy_missing_destination_directory(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *missing_directory = NULL;
char *destination_path = NULL;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"source.bin"
);
missing_directory =
g_build_filename(
fixture.root_directory,
"missing-destination",
NULL
);
destination_path =
g_build_filename(
missing_directory,
"copy.bin",
NULL
);
assert(source_path != NULL);
assert(missing_directory != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve",
6,
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
missing_directory,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_DESTINATION_INVALID
);
g_clear_error(
&error
);
test_evidence_copy_assert_destination_absent(
destination_path
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
missing_directory
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie quun fichier ne peut pas servir de dossier destination.
*/
static void test_evidence_copy_destination_is_file(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *fake_directory_path = NULL;
char *fake_directory_contents = NULL;
gsize fake_directory_contents_size = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"source.bin"
);
fake_directory_path =
g_build_filename(
fixture.root_directory,
"not-a-directory",
NULL
);
assert(source_path != NULL);
assert(fake_directory_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve",
6,
&error
)
);
assert(error == NULL);
assert(
g_file_set_contents(
fake_directory_path,
"contenu intact",
14,
&error
)
);
assert(error == NULL);
result =
evidence_copy_file(
source_path,
fake_directory_path,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_DESTINATION_INVALID
);
g_clear_error(
&error
);
/*
* Le fichier pris pour un dossier doit rester intact.
*/
assert(
g_file_get_contents(
fake_directory_path,
&fake_directory_contents,
&fake_directory_contents_size,
&error
)
);
assert(error == NULL);
assert(fake_directory_contents_size == 14);
assert(
memcmp(
fake_directory_contents,
"contenu intact",
14
) == 0
);
g_free(
fake_directory_contents
);
assert(
g_remove(
fake_directory_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
fake_directory_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie quun dossier destination symbolique nest pas suivi.
*/
static void test_evidence_copy_destination_symbolic_link(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *link_path = NULL;
char *real_destination_path = NULL;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"source.bin"
);
link_path =
g_build_filename(
fixture.root_directory,
"destination-link",
NULL
);
real_destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"copy.bin"
);
assert(source_path != NULL);
assert(link_path != NULL);
assert(real_destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve",
6,
&error
)
);
assert(error == NULL);
assert(
symlink(
fixture.destination_directory,
link_path
) == 0
);
result =
evidence_copy_file(
source_path,
link_path,
"copy.bin",
NULL,
&error
);
assert(result == NULL);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_DESTINATION_INVALID
);
g_clear_error(
&error
);
/*
* La cible réelle du lien ne doit recevoir aucun fichier.
*/
test_evidence_copy_assert_destination_absent(
real_destination_path
);
assert(
g_remove(
link_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
real_destination_path
);
g_free(
link_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Annule la copie après le premier bloc.
*/
static void test_evidence_copy_cancel_after_first_block(
guint64 copied_size_bytes,
gpointer user_data
)
{
TestEvidenceCopyCancellationContext *context =
user_data;
assert(context != NULL);
assert(context->cancellable != NULL);
assert(copied_size_bytes > 0);
context->block_count++;
if (context->block_count == 1)
{
g_cancellable_cancel(
context->cancellable
);
}
}
/**
* @brief Vérifie lannulation pendant une copie en cours.
*/
static void test_evidence_copy_cancelled_during_copy(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
TestEvidenceCopyCancellationContext context = {0};
const gsize data_size =
256U * 1024U;
EvidenceCopyResult *result = NULL;
guint8 *source_data = NULL;
char *source_path = NULL;
char *destination_path = NULL;
gsize data_index = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"cancel-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"cancel-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
source_data =
g_malloc(
data_size
);
assert(source_data != NULL);
for (data_index = 0;
data_index < data_size;
data_index++)
{
source_data[data_index] =
(guint8) (data_index % 251U);
}
assert(
g_file_set_contents(
source_path,
(const char *) source_data,
(gssize) data_size,
&error
)
);
assert(error == NULL);
context.cancellable =
g_cancellable_new();
assert(context.cancellable != NULL);
evidence_copy_test_set_block_hook(
test_evidence_copy_cancel_after_first_block,
&context
);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"cancel-copy.bin",
context.cancellable,
&error
);
/*
* Toujours retirer le crochet avant les assertions suivantes.
*/
evidence_copy_test_set_block_hook(
NULL,
NULL
);
assert(result == NULL);
assert(context.block_count == 1);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_CANCELLED
);
g_clear_error(
&error
);
/*
* La copie partielle doit avoir été supprimée.
*/
test_evidence_copy_assert_destination_absent(
destination_path
);
/*
* Le fichier source doit rester intact.
*/
assert(
g_file_test(
source_path,
G_FILE_TEST_IS_REGULAR
)
);
g_object_unref(
context.cancellable
);
g_free(
source_data
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Déclenche une erreur après la quantité demandée.
*/
static gboolean test_evidence_copy_fail_write_after_size(
guint64 written_size_bytes,
gpointer user_data
)
{
TestEvidenceCopyWriteFailureContext *context =
user_data;
assert(context != NULL);
context->call_count++;
return written_size_bytes >=
context->fail_after_size_bytes;
}
/**
* @brief Vérifie le nettoyage après une erreur décriture.
*/
static void test_evidence_copy_write_failure_cleanup(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
TestEvidenceCopyWriteFailureContext context = {0};
const gsize data_size =
256U * 1024U;
EvidenceCopyResult *result = NULL;
guint8 *source_data = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *source_contents = NULL;
gsize data_index = 0;
gsize source_contents_size = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"write-failure-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"write-failure-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
source_data =
g_malloc(
data_size
);
assert(source_data != NULL);
for (data_index = 0;
data_index < data_size;
data_index++)
{
source_data[data_index] =
(guint8) (data_index % 251U);
}
assert(
g_file_set_contents(
source_path,
(const char *) source_data,
(gssize) data_size,
&error
)
);
assert(error == NULL);
/*
* Le premier bloc de 64 Kio est écrit.
* Lécriture suivante doit échouer.
*/
context.fail_after_size_bytes =
64U * 1024U;
evidence_copy_test_set_before_write_hook(
test_evidence_copy_fail_write_after_size,
&context
);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"write-failure-copy.bin",
NULL,
&error
);
evidence_copy_test_set_before_write_hook(
NULL,
NULL
);
assert(result == NULL);
assert(context.call_count >= 2);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_WRITE
);
g_clear_error(
&error
);
/*
* Le fichier partiel ne doit plus exister.
*/
test_evidence_copy_assert_destination_absent(
destination_path
);
/*
* Le fichier source doit rester strictement intact.
*/
assert(
g_file_get_contents(
source_path,
&source_contents,
&source_contents_size,
&error
)
);
assert(error == NULL);
assert(source_contents_size == data_size);
assert(
memcmp(
source_contents,
source_data,
data_size
) == 0
);
g_free(
source_contents
);
g_free(
source_data
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Corrompt volontairement la destination avant son contrôle.
*/
static void test_evidence_copy_corrupt_before_verify(
const char *destination_path,
gpointer user_data
)
{
TestEvidenceCopyVerifyFailureContext *context =
user_data;
GError *error = NULL;
assert(context != NULL);
assert(destination_path != NULL);
context->call_count++;
assert(
g_file_set_contents(
destination_path,
"copie corrompue",
15,
&error
)
);
assert(error == NULL);
}
/**
* @brief Vérifie le nettoyage après une corruption de la copie.
*/
static void test_evidence_copy_verification_failure_cleanup(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
TestEvidenceCopyVerifyFailureContext context = {0};
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *source_contents = NULL;
gsize source_contents_size = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"verify-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"verify-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve originale",
16,
&error
)
);
assert(error == NULL);
evidence_copy_test_set_before_verify_hook(
test_evidence_copy_corrupt_before_verify,
&context
);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"verify-copy.bin",
NULL,
&error
);
evidence_copy_test_set_before_verify_hook(
NULL,
NULL
);
assert(result == NULL);
assert(context.call_count == 1);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_VERIFY
);
g_clear_error(
&error
);
/*
* La copie corrompue doit avoir été supprimée.
*/
test_evidence_copy_assert_destination_absent(
destination_path
);
/*
* La source doit être restée intacte.
*/
assert(
g_file_get_contents(
source_path,
&source_contents,
&source_contents_size,
&error
)
);
assert(error == NULL);
assert(source_contents_size == 16);
assert(
memcmp(
source_contents,
"preuve originale",
16
) == 0
);
g_free(
source_contents
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Modifie la source après sa copie.
*/
static void test_evidence_copy_modify_source_before_verify(
const char *destination_path,
gpointer user_data
)
{
TestEvidenceCopySourceModificationContext *context =
user_data;
GError *error = NULL;
assert(destination_path != NULL);
assert(context != NULL);
assert(context->source_path != NULL);
context->call_count++;
assert(
g_file_set_contents(
context->source_path,
"source modifiee",
15,
&error
)
);
assert(error == NULL);
}
/**
* @brief Vérifie la détection dune source modifiée pendant la copie.
*/
static void test_evidence_copy_source_modified_during_copy(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
TestEvidenceCopySourceModificationContext context = {0};
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
char *source_contents = NULL;
gsize source_contents_size = 0;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"changing-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"changing-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"source initiale",
15,
&error
)
);
assert(error == NULL);
context.source_path =
source_path;
evidence_copy_test_set_before_verify_hook(
test_evidence_copy_modify_source_before_verify,
&context
);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"changing-copy.bin",
NULL,
&error
);
evidence_copy_test_set_before_verify_hook(
NULL,
NULL
);
assert(result == NULL);
assert(context.call_count == 1);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_VERIFY
);
g_clear_error(
&error
);
/*
* La destination nest pas fiable et doit être supprimée.
*/
test_evidence_copy_assert_destination_absent(
destination_path
);
/*
* EvidenceCopy ne doit pas tenter de restaurer ou modifier la source.
* Elle reste donc dans létat imposé par le test.
*/
assert(
g_file_get_contents(
source_path,
&source_contents,
&source_contents_size,
&error
)
);
assert(error == NULL);
assert(source_contents_size == 15);
assert(
memcmp(
source_contents,
"source modifiee",
15
) == 0
);
g_free(
source_contents
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Simule systématiquement un échec de suppression.
*/
static gboolean test_evidence_copy_fail_cleanup(
const char *destination_path,
gpointer user_data
)
{
TestEvidenceCopyCleanupFailureContext *context =
user_data;
assert(context != NULL);
assert(destination_path != NULL);
assert(destination_path[0] != '\0');
context->call_count++;
return TRUE;
}
/**
* @brief Vérifie le signalement dun fichier orphelin.
*/
static void test_evidence_copy_cleanup_failure_reported(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
TestEvidenceCopyVerifyFailureContext verify_context = {0};
TestEvidenceCopyCleanupFailureContext cleanup_context = {0};
EvidenceCopyResult *result = NULL;
char *source_path = NULL;
char *destination_path = NULL;
GError *error = NULL;
source_path =
test_evidence_copy_build_source_path(
&fixture,
"cleanup-source.bin"
);
destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"cleanup-copy.bin"
);
assert(source_path != NULL);
assert(destination_path != NULL);
assert(
g_file_set_contents(
source_path,
"preuve originale",
16,
&error
)
);
assert(error == NULL);
evidence_copy_test_set_before_verify_hook(
test_evidence_copy_corrupt_before_verify,
&verify_context
);
evidence_copy_test_set_cleanup_hook(
test_evidence_copy_fail_cleanup,
&cleanup_context
);
result =
evidence_copy_file(
source_path,
fixture.destination_directory,
"cleanup-copy.bin",
NULL,
&error
);
/*
* Retirer les deux crochets avant toute autre opération.
*/
evidence_copy_test_set_cleanup_hook(
NULL,
NULL
);
evidence_copy_test_set_before_verify_hook(
NULL,
NULL
);
assert(result == NULL);
assert(verify_context.call_count == 1);
assert(cleanup_context.call_count == 1);
test_evidence_copy_assert_error(
error,
EVIDENCE_COPY_ERROR_CLEANUP
);
/*
* Le message doit identifier le fichier potentiellement orphelin.
*/
assert(
strstr(
error->message,
destination_path
) != NULL
);
/*
* La cause initiale doit rester visible.
*/
assert(
strstr(
error->message,
"Cause initiale"
) != NULL
);
g_clear_error(
&error
);
/*
* Léchec étant simulé, le fichier doit toujours exister.
*/
assert(
g_file_test(
destination_path,
G_FILE_TEST_IS_REGULAR
)
);
/*
* Le test effectue ensuite lui-même le nettoyage réel.
*/
assert(
g_remove(
destination_path
) == 0
);
assert(
g_remove(
source_path
) == 0
);
g_free(
destination_path
);
g_free(
source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
/**
* @brief Vérifie lindépendance de plusieurs copies successives.
*/
static void test_evidence_copy_successive_calls(void)
{
TestEvidenceCopyFixture fixture =
test_evidence_copy_fixture_create();
EvidenceCopyResult *first_result = NULL;
EvidenceCopyResult *second_result = NULL;
char *first_source_path = NULL;
char *second_source_path = NULL;
char *first_destination_path = NULL;
char *second_destination_path = NULL;
GError *error = NULL;
first_source_path =
test_evidence_copy_build_source_path(
&fixture,
"first-source.bin"
);
second_source_path =
test_evidence_copy_build_source_path(
&fixture,
"second-source.bin"
);
first_destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"first-copy.bin"
);
second_destination_path =
test_evidence_copy_build_destination_path(
&fixture,
"second-copy.bin"
);
assert(first_source_path != NULL);
assert(second_source_path != NULL);
assert(first_destination_path != NULL);
assert(second_destination_path != NULL);
assert(
g_file_set_contents(
first_source_path,
"premiere preuve",
15,
&error
)
);
assert(error == NULL);
assert(
g_file_set_contents(
second_source_path,
"deuxieme preuve",
15,
&error
)
);
assert(error == NULL);
first_result =
evidence_copy_file(
first_source_path,
fixture.destination_directory,
"first-copy.bin",
NULL,
&error
);
assert(error == NULL);
assert(first_result != NULL);
second_result =
evidence_copy_file(
second_source_path,
fixture.destination_directory,
"second-copy.bin",
NULL,
&error
);
assert(error == NULL);
assert(second_result != NULL);
assert(
strcmp(
evidence_copy_result_get_destination_path(
first_result
),
first_destination_path
) == 0
);
assert(
strcmp(
evidence_copy_result_get_destination_path(
second_result
),
second_destination_path
) == 0
);
assert(
strcmp(
evidence_copy_result_get_destination_name(
first_result
),
"first-copy.bin"
) == 0
);
assert(
strcmp(
evidence_copy_result_get_destination_name(
second_result
),
"second-copy.bin"
) == 0
);
assert(
evidence_copy_result_get_size_bytes(
first_result
) == 15
);
assert(
evidence_copy_result_get_size_bytes(
second_result
) == 15
);
assert(
strcmp(
evidence_copy_result_get_sha256(
first_result
),
evidence_copy_result_get_sha256(
second_result
)
) != 0
);
assert(
g_file_test(
first_destination_path,
G_FILE_TEST_IS_REGULAR
)
);
assert(
g_file_test(
second_destination_path,
G_FILE_TEST_IS_REGULAR
)
);
evidence_copy_result_free(
second_result
);
evidence_copy_result_free(
first_result
);
assert(
g_remove(
second_destination_path
) == 0
);
assert(
g_remove(
first_destination_path
) == 0
);
assert(
g_remove(
second_source_path
) == 0
);
assert(
g_remove(
first_source_path
) == 0
);
g_free(
second_destination_path
);
g_free(
first_destination_path
);
g_free(
second_source_path
);
g_free(
first_source_path
);
test_evidence_copy_fixture_clear(
&fixture
);
}
int main(void)
{
test_evidence_copy_null_result();
test_evidence_copy_text_file();
test_evidence_copy_empty_file();
test_evidence_copy_binary_file();
test_evidence_copy_multiple_blocks();
test_evidence_copy_permissions();
test_evidence_copy_destination_exists();
test_evidence_copy_invalid_arguments();
test_evidence_copy_invalid_destination_names();
test_evidence_copy_missing_source();
test_evidence_copy_source_directory();
test_evidence_copy_source_symbolic_link();
test_evidence_copy_source_named_pipe();
test_evidence_copy_cancelled_before_start();
test_evidence_copy_missing_destination_directory();
test_evidence_copy_destination_is_file();
test_evidence_copy_destination_symbolic_link();
test_evidence_copy_cancelled_during_copy();
test_evidence_copy_write_failure_cleanup();
test_evidence_copy_verification_failure_cleanup();
test_evidence_copy_source_modified_during_copy();
test_evidence_copy_cleanup_failure_reported();
test_evidence_copy_successive_calls();
printf(
"EvidenceCopy : premiers tests de copie valides.\n"
);
return 0;
}