feat: add entity record model

This commit is contained in:
grayTerminal-sh 2026-07-20 20:06:22 +02:00
parent 12d201cf8a
commit 59d05b6683
4 changed files with 1381 additions and 2 deletions

View file

@ -41,6 +41,7 @@ EVIDENCE_IMPORT_DIALOG_TEST_LDFLAGS := \
EVIDENCE_INTEGRITY_VERIFIER_TEST_CFLAGS := \
$(TEST_CFLAGS) \
-Wpedantic
ENTITY_RECORD_TEST_CFLAGS := $(TEST_CFLAGS) -Wpedantic
SRC := $(shell find src -name "*.c")
@ -82,6 +83,7 @@ TEST_EVIDENCE_LIST_MODEL := tests/test_evidence_list_model
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
all: $(TARGET)
@ -158,7 +160,8 @@ $(TEST_INVESTIGATION_RECORD): \
$(TEST_EVIDENCE_RECORD): \
tests/test_evidence_record.c \
src/models/evidence_record.c
src/models/evidence_record.c \
src/models/entity_record.c
$(CC) $(EVIDENCE_RECORD_TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
$(TEST_EVIDENCE_LIST_ITEM): \
@ -367,6 +370,11 @@ $(TEST_EVIDENCE_INTEGRITY_TASK): \
-DFILE_HASH_ENABLE_TEST_HOOKS \
$^ -o $@ $(TEST_LDFLAGS)
$(TEST_ENTITY_RECORD): \
tests/test_entity_record.c \
src/models/entity_record.c
$(CC) $(ENTITY_RECORD_TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
test: \
$(TEST_NODE) \
$(TEST_TREE_MODEL) \
@ -401,7 +409,8 @@ test: \
$(TEST_EVIDENCE_IMPORTER) \
$(TEST_EVIDENCE_IMPORT_TASK) \
$(TEST_EVIDENCE_IMPORT_DIALOG) \
$(TEST_EVIDENCE_INTEGRITY_TASK)
$(TEST_EVIDENCE_INTEGRITY_TASK) \
$(TEST_ENTITY_RECORD)
@echo "Exécution des tests..."
@./$(TEST_NODE)
@./$(TEST_TREE_MODEL)
@ -437,6 +446,7 @@ test: \
@$(TEST_EVIDENCE_IMPORT_TASK)
@$(TEST_EVIDENCE_IMPORT_DIALOG)
@$(TEST_EVIDENCE_INTEGRITY_TASK)
@$(TEST_ENTITY_RECORD)
@echo "Tous les tests sont valides."
%.o: %.c

View file

@ -0,0 +1,175 @@
/******************************************************************************
* @file entity_record.h
* @brief Modèle représentant une entité persistée.
******************************************************************************/
#ifndef LABFY_INVESTIGATION_ENTITY_RECORD_H
#define LABFY_INVESTIGATION_ENTITY_RECORD_H
#include <glib.h>
G_BEGIN_DECLS
/**
* @brief Modèle opaque représentant une entité.
*/
typedef struct EntityRecord EntityRecord;
/**
* @brief Statut métier d'une entité.
*
* UNKNOWN sert uniquement de valeur défensive et ne doit jamais être
* persisté dans SQLite.
*/
typedef enum
{
ENTITY_STATUS_UNKNOWN,
ENTITY_STATUS_ACTIVE,
ENTITY_STATUS_ARCHIVED,
ENTITY_STATUS_DELETED
} EntityStatus;
/**
* @brief Codes d'erreur produits par EntityRecord.
*/
typedef enum
{
ENTITY_RECORD_ERROR_INVALID_ARGUMENT,
ENTITY_RECORD_ERROR_INVALID_IDENTIFIER,
ENTITY_RECORD_ERROR_INVALID_TYPE,
ENTITY_RECORD_ERROR_INVALID_VALUE,
ENTITY_RECORD_ERROR_INVALID_CONFIDENCE,
ENTITY_RECORD_ERROR_INVALID_DATE,
ENTITY_RECORD_ERROR_INVALID_STATUS
} EntityRecordError;
/**
* @brief Domaine d'erreur du modèle EntityRecord.
*/
#define ENTITY_RECORD_ERROR \
entity_record_error_quark()
/**
* @brief Retourne le domaine d'erreur du modèle.
*/
GQuark entity_record_error_quark(void);
/**
* @brief Crée une entité métier.
*
* Toutes les chaînes sont copiées.
*
* Les champs identifier, type_identifier, value, created_at et updated_at
* sont obligatoires.
*
* label et description peuvent être NULL ou vides.
*
* confidence doit être compris entre 0 et 100.
*
* status doit être ACTIVE, ARCHIVED ou DELETED.
*
* @param identifier UUID de l'entité.
* @param type_identifier Code métier du type d'entité.
* @param value Valeur principale de l'entité.
* @param label Libellé facultatif.
* @param description Description facultative.
* @param confidence Niveau de confiance compris entre 0 et 100.
* @param created_at Date UTC de création.
* @param updated_at Date UTC de dernière modification.
* @param status Statut métier.
* @param error Emplacement facultatif recevant une erreur.
*
* @return Nouvelle entité, ou NULL lorsque les données sont invalides.
*/
EntityRecord *entity_record_new(
const char *identifier,
const char *type_identifier,
const char *value,
const char *label,
const char *description,
gint confidence,
const char *created_at,
const char *updated_at,
EntityStatus status,
GError **error
);
/**
* @brief Libère une entité.
*
* Cette fonction accepte NULL.
*/
void entity_record_free(
EntityRecord *entity_record
);
/**
* @brief Retourne l'UUID de l'entité.
*/
const char *entity_record_get_identifier(
const EntityRecord *entity_record
);
/**
* @brief Retourne le code métier du type.
*/
const char *entity_record_get_type_identifier(
const EntityRecord *entity_record
);
/**
* @brief Retourne la valeur principale.
*/
const char *entity_record_get_value(
const EntityRecord *entity_record
);
/**
* @brief Retourne le libellé facultatif.
*/
const char *entity_record_get_label(
const EntityRecord *entity_record
);
/**
* @brief Retourne la description facultative.
*/
const char *entity_record_get_description(
const EntityRecord *entity_record
);
/**
* @brief Retourne le niveau de confiance.
*
* @return Valeur comprise entre 0 et 100, ou 0 si entity_record est NULL.
*/
gint entity_record_get_confidence(
const EntityRecord *entity_record
);
/**
* @brief Retourne la date UTC de création.
*/
const char *entity_record_get_created_at(
const EntityRecord *entity_record
);
/**
* @brief Retourne la date UTC de dernière modification.
*/
const char *entity_record_get_updated_at(
const EntityRecord *entity_record
);
/**
* @brief Retourne le statut métier.
*
* @return Statut ou ENTITY_STATUS_UNKNOWN si entity_record est NULL.
*/
EntityStatus entity_record_get_status(
const EntityRecord *entity_record
);
G_END_DECLS
#endif

584
src/models/entity_record.c Normal file
View file

@ -0,0 +1,584 @@
/******************************************************************************
* @file entity_record.c
* @brief Implémentation du modèle représentant une entité persistée.
******************************************************************************/
#include "models/entity_record.h"
#include <string.h>
/**
* @brief Représentation privée d'une entité.
*/
struct EntityRecord
{
char *identifier;
char *type_identifier;
char *value;
char *label;
char *description;
gint confidence;
char *created_at;
char *updated_at;
EntityStatus status;
};
/**
* @brief Copie et nettoie une chaîne.
*/
static char *entity_record_duplicate_trimmed(
const char *value
)
{
char *copy =
NULL;
if (value == NULL)
{
return NULL;
}
copy =
g_strdup(
value
);
g_strstrip(
copy
);
return copy;
}
/**
* @brief Normalise un champ facultatif.
*
* Une chaîne vide après nettoyage devient NULL.
*/
static char *entity_record_duplicate_optional(
const char *value
)
{
char *copy =
NULL;
copy =
entity_record_duplicate_trimmed(
value
);
if (copy != NULL &&
copy[0] == '\0')
{
g_free(
copy
);
copy =
NULL;
}
return copy;
}
/**
* @brief Vérifie qu'une valeur obligatoire est présente.
*/
static gboolean entity_record_required_value_is_valid(
const char *value
)
{
return value != NULL &&
value[0] != '\0';
}
/**
* @brief Vérifie une date UTC stricte YYYY-MM-DDTHH:MM:SSZ.
*/
static gboolean entity_record_timestamp_is_valid(
const char *timestamp
)
{
GDateTime *date_time =
NULL;
char *normalized_timestamp =
NULL;
gboolean valid =
FALSE;
gsize character_index =
0;
if (timestamp == NULL ||
strlen(timestamp) != 20U)
{
return FALSE;
}
if (timestamp[4] != '-' ||
timestamp[7] != '-' ||
timestamp[10] != 'T' ||
timestamp[13] != ':' ||
timestamp[16] != ':' ||
timestamp[19] != 'Z')
{
return FALSE;
}
for (character_index = 0;
character_index < 20U;
character_index++)
{
if (character_index == 4U ||
character_index == 7U ||
character_index == 10U ||
character_index == 13U ||
character_index == 16U ||
character_index == 19U)
{
continue;
}
if (!g_ascii_isdigit(
timestamp[character_index]
))
{
return FALSE;
}
}
date_time =
g_date_time_new_from_iso8601(
timestamp,
NULL
);
if (date_time == NULL)
{
return FALSE;
}
normalized_timestamp =
g_date_time_format(
date_time,
"%Y-%m-%dT%H:%M:%SZ"
);
valid =
normalized_timestamp != NULL &&
g_strcmp0(
normalized_timestamp,
timestamp
) == 0;
g_free(
normalized_timestamp
);
g_date_time_unref(
date_time
);
return valid;
}
/**
* @brief Vérifie qu'un statut peut être persisté.
*/
static gboolean entity_record_status_is_valid(
EntityStatus status
)
{
return status == ENTITY_STATUS_ACTIVE ||
status == ENTITY_STATUS_ARCHIVED ||
status == ENTITY_STATUS_DELETED;
}
GQuark entity_record_error_quark(void)
{
return g_quark_from_static_string(
"entity-record-error-quark"
);
}
EntityRecord *entity_record_new(
const char *identifier,
const char *type_identifier,
const char *value,
const char *label,
const char *description,
gint confidence,
const char *created_at,
const char *updated_at,
EntityStatus status,
GError **error
)
{
EntityRecord *entity_record =
NULL;
char *identifier_copy =
NULL;
char *type_identifier_copy =
NULL;
char *value_copy =
NULL;
char *label_copy =
NULL;
char *description_copy =
NULL;
char *created_at_copy =
NULL;
char *updated_at_copy =
NULL;
g_return_val_if_fail(
error == NULL || *error == NULL,
NULL
);
identifier_copy =
entity_record_duplicate_trimmed(
identifier
);
if (!entity_record_required_value_is_valid(
identifier_copy
) ||
!g_uuid_string_is_valid(
identifier_copy
))
{
g_set_error_literal(
error,
ENTITY_RECORD_ERROR,
ENTITY_RECORD_ERROR_INVALID_IDENTIFIER,
"L'identifiant de l'entité n'est pas un UUID valide."
);
goto cleanup;
}
type_identifier_copy =
entity_record_duplicate_trimmed(
type_identifier
);
if (!entity_record_required_value_is_valid(
type_identifier_copy
))
{
g_set_error_literal(
error,
ENTITY_RECORD_ERROR,
ENTITY_RECORD_ERROR_INVALID_TYPE,
"Le type de l'entité est obligatoire."
);
goto cleanup;
}
value_copy =
entity_record_duplicate_trimmed(
value
);
if (!entity_record_required_value_is_valid(
value_copy
))
{
g_set_error_literal(
error,
ENTITY_RECORD_ERROR,
ENTITY_RECORD_ERROR_INVALID_VALUE,
"La valeur de l'entité est obligatoire."
);
goto cleanup;
}
if (confidence < 0 ||
confidence > 100)
{
g_set_error_literal(
error,
ENTITY_RECORD_ERROR,
ENTITY_RECORD_ERROR_INVALID_CONFIDENCE,
"Le niveau de confiance doit être compris entre 0 et 100."
);
goto cleanup;
}
created_at_copy =
entity_record_duplicate_trimmed(
created_at
);
if (!entity_record_timestamp_is_valid(
created_at_copy
))
{
g_set_error_literal(
error,
ENTITY_RECORD_ERROR,
ENTITY_RECORD_ERROR_INVALID_DATE,
"La date de création de l'entité est invalide."
);
goto cleanup;
}
updated_at_copy =
entity_record_duplicate_trimmed(
updated_at
);
if (!entity_record_timestamp_is_valid(
updated_at_copy
))
{
g_set_error_literal(
error,
ENTITY_RECORD_ERROR,
ENTITY_RECORD_ERROR_INVALID_DATE,
"La date de modification de l'entité est invalide."
);
goto cleanup;
}
if (!entity_record_status_is_valid(
status
))
{
g_set_error_literal(
error,
ENTITY_RECORD_ERROR,
ENTITY_RECORD_ERROR_INVALID_STATUS,
"Le statut de l'entité est invalide."
);
goto cleanup;
}
label_copy =
entity_record_duplicate_optional(
label
);
description_copy =
entity_record_duplicate_optional(
description
);
entity_record =
g_new0(
EntityRecord,
1
);
entity_record->identifier =
identifier_copy;
entity_record->type_identifier =
type_identifier_copy;
entity_record->value =
value_copy;
entity_record->label =
label_copy;
entity_record->description =
description_copy;
entity_record->confidence =
confidence;
entity_record->created_at =
created_at_copy;
entity_record->updated_at =
updated_at_copy;
entity_record->status =
status;
/*
* La propriété a é transférée au modèle.
*/
identifier_copy = NULL;
type_identifier_copy = NULL;
value_copy = NULL;
label_copy = NULL;
description_copy = NULL;
created_at_copy = NULL;
updated_at_copy = NULL;
cleanup:
g_free(
updated_at_copy
);
g_free(
created_at_copy
);
g_free(
description_copy
);
g_free(
label_copy
);
g_free(
value_copy
);
g_free(
type_identifier_copy
);
g_free(
identifier_copy
);
return entity_record;
}
void entity_record_free(
EntityRecord *entity_record
)
{
if (entity_record == NULL)
{
return;
}
g_free(
entity_record->updated_at
);
g_free(
entity_record->created_at
);
g_free(
entity_record->description
);
g_free(
entity_record->label
);
g_free(
entity_record->value
);
g_free(
entity_record->type_identifier
);
g_free(
entity_record->identifier
);
g_free(
entity_record
);
}
const char *entity_record_get_identifier(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->identifier
: NULL;
}
const char *entity_record_get_type_identifier(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->type_identifier
: NULL;
}
const char *entity_record_get_value(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->value
: NULL;
}
const char *entity_record_get_label(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->label
: NULL;
}
const char *entity_record_get_description(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->description
: NULL;
}
gint entity_record_get_confidence(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->confidence
: 0;
}
const char *entity_record_get_created_at(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->created_at
: NULL;
}
const char *entity_record_get_updated_at(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->updated_at
: NULL;
}
EntityStatus entity_record_get_status(
const EntityRecord *entity_record
)
{
return entity_record != NULL
? entity_record->status
: ENTITY_STATUS_UNKNOWN;
}

610
tests/test_entity_record.c Normal file
View file

@ -0,0 +1,610 @@
/******************************************************************************
* @file test_entity_record.c
* @brief Tests unitaires du modèle EntityRecord.
******************************************************************************/
#include "models/entity_record.h"
#include <glib.h>
#define TEST_ENTITY_IDENTIFIER \
"9b6ea3f8-b60b-48ac-908a-94c211f524dd"
typedef struct
{
const char *identifier;
const char *type_identifier;
const char *value;
const char *label;
const char *description;
gint confidence;
const char *created_at;
const char *updated_at;
EntityStatus status;
} TestEntityRecordInput;
static TestEntityRecordInput test_entity_record_valid_input(void)
{
return (TestEntityRecordInput)
{
.identifier = TEST_ENTITY_IDENTIFIER,
.type_identifier = "email_address",
.value = "suspect@example.org",
.label = "Adresse utilisée pour la transaction",
.description = "Adresse communiquée dans la conversation.",
.confidence = 80,
.created_at = "2026-07-20T19:00:00Z",
.updated_at = "2026-07-20T19:00:00Z",
.status = ENTITY_STATUS_ACTIVE
};
}
static EntityRecord *test_entity_record_create(
const TestEntityRecordInput *input,
GError **error
)
{
g_assert_nonnull(
input
);
return entity_record_new(
input->identifier,
input->type_identifier,
input->value,
input->label,
input->description,
input->confidence,
input->created_at,
input->updated_at,
input->status,
error
);
}
static void test_entity_record_assert_invalid(
const TestEntityRecordInput *input,
EntityRecordError expected_error
)
{
EntityRecord *entity_record =
NULL;
GError *error =
NULL;
entity_record =
test_entity_record_create(
input,
&error
);
g_assert_null(
entity_record
);
g_assert_error(
error,
ENTITY_RECORD_ERROR,
(gint) expected_error
);
g_clear_error(
&error
);
}
static void test_entity_record_valid_full(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
EntityRecord *entity_record =
NULL;
GError *error =
NULL;
entity_record =
test_entity_record_create(
&input,
&error
);
g_assert_no_error(
error
);
g_assert_nonnull(
entity_record
);
g_assert_cmpstr(
entity_record_get_identifier(entity_record),
==,
TEST_ENTITY_IDENTIFIER
);
g_assert_cmpstr(
entity_record_get_type_identifier(entity_record),
==,
"email_address"
);
g_assert_cmpstr(
entity_record_get_value(entity_record),
==,
"suspect@example.org"
);
g_assert_cmpstr(
entity_record_get_label(entity_record),
==,
"Adresse utilisée pour la transaction"
);
g_assert_cmpstr(
entity_record_get_description(entity_record),
==,
"Adresse communiquée dans la conversation."
);
g_assert_cmpint(
entity_record_get_confidence(entity_record),
==,
80
);
g_assert_cmpstr(
entity_record_get_created_at(entity_record),
==,
"2026-07-20T19:00:00Z"
);
g_assert_cmpstr(
entity_record_get_updated_at(entity_record),
==,
"2026-07-20T19:00:00Z"
);
g_assert_cmpint(
entity_record_get_status(entity_record),
==,
ENTITY_STATUS_ACTIVE
);
entity_record_free(
entity_record
);
}
static void test_entity_record_optional_fields(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
EntityRecord *entity_record =
NULL;
GError *error =
NULL;
input.label = " ";
input.description = NULL;
entity_record =
test_entity_record_create(
&input,
&error
);
g_assert_no_error(
error
);
g_assert_nonnull(
entity_record
);
g_assert_null(
entity_record_get_label(
entity_record
)
);
g_assert_null(
entity_record_get_description(
entity_record
)
);
entity_record_free(
entity_record
);
}
static void test_entity_record_values_are_trimmed(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
EntityRecord *entity_record =
NULL;
GError *error =
NULL;
input.identifier =
" 9b6ea3f8-b60b-48ac-908a-94c211f524dd ";
input.type_identifier =
" iban ";
input.value =
" FR7612345678901234567890123 ";
input.label =
" Compte destinataire ";
input.description =
" IBAN communiqué par le vendeur. ";
input.created_at =
" 2026-07-20T19:00:00Z ";
input.updated_at =
"\t2026-07-20T19:00:00Z\t";
entity_record =
test_entity_record_create(
&input,
&error
);
g_assert_no_error(
error
);
g_assert_cmpstr(
entity_record_get_type_identifier(entity_record),
==,
"iban"
);
g_assert_cmpstr(
entity_record_get_value(entity_record),
==,
"FR7612345678901234567890123"
);
g_assert_cmpstr(
entity_record_get_label(entity_record),
==,
"Compte destinataire"
);
entity_record_free(
entity_record
);
}
static void test_entity_record_invalid_uuid(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.identifier = "uuid-invalide";
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_IDENTIFIER
);
}
static void test_entity_record_missing_type(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.type_identifier = " ";
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_TYPE
);
}
static void test_entity_record_empty_value(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.value = "\t";
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_VALUE
);
}
static void test_entity_record_confidence_below_range(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.confidence = -1;
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_CONFIDENCE
);
}
static void test_entity_record_confidence_above_range(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.confidence = 101;
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_CONFIDENCE
);
}
static void test_entity_record_invalid_created_at(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.created_at = "2026-02-30T19:00:00Z";
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_DATE
);
}
static void test_entity_record_invalid_updated_at(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.updated_at = "2026-07-20 19:00:00Z";
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_DATE
);
}
static void test_entity_record_valid_statuses(void)
{
EntityStatus statuses[] =
{
ENTITY_STATUS_ACTIVE,
ENTITY_STATUS_ARCHIVED,
ENTITY_STATUS_DELETED
};
guint status_index =
0;
for (status_index = 0;
status_index < G_N_ELEMENTS(statuses);
status_index++)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
EntityRecord *entity_record =
NULL;
GError *error =
NULL;
input.status =
statuses[status_index];
entity_record =
test_entity_record_create(
&input,
&error
);
g_assert_no_error(
error
);
g_assert_nonnull(
entity_record
);
g_assert_cmpint(
entity_record_get_status(entity_record),
==,
statuses[status_index]
);
entity_record_free(
entity_record
);
}
}
static void test_entity_record_invalid_status(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
input.status = ENTITY_STATUS_UNKNOWN;
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_STATUS
);
input.status = (EntityStatus) 999;
test_entity_record_assert_invalid(
&input,
ENTITY_RECORD_ERROR_INVALID_STATUS
);
}
static void test_entity_record_null_accessors(void)
{
g_assert_null(
entity_record_get_identifier(NULL)
);
g_assert_null(
entity_record_get_type_identifier(NULL)
);
g_assert_null(
entity_record_get_value(NULL)
);
g_assert_null(
entity_record_get_label(NULL)
);
g_assert_null(
entity_record_get_description(NULL)
);
g_assert_cmpint(
entity_record_get_confidence(NULL),
==,
0
);
g_assert_null(
entity_record_get_created_at(NULL)
);
g_assert_null(
entity_record_get_updated_at(NULL)
);
g_assert_cmpint(
entity_record_get_status(NULL),
==,
ENTITY_STATUS_UNKNOWN
);
entity_record_free(
NULL
);
}
static void test_entity_record_optional_error(void)
{
TestEntityRecordInput input =
test_entity_record_valid_input();
EntityRecord *entity_record =
NULL;
input.identifier =
"invalide";
entity_record =
test_entity_record_create(
&input,
NULL
);
g_assert_null(
entity_record
);
}
int main(
int argc,
char **argv
)
{
g_test_init(
&argc,
&argv,
NULL
);
g_test_add_func(
"/entity-record/valid-full",
test_entity_record_valid_full
);
g_test_add_func(
"/entity-record/optional-fields",
test_entity_record_optional_fields
);
g_test_add_func(
"/entity-record/values-are-trimmed",
test_entity_record_values_are_trimmed
);
g_test_add_func(
"/entity-record/invalid-uuid",
test_entity_record_invalid_uuid
);
g_test_add_func(
"/entity-record/missing-type",
test_entity_record_missing_type
);
g_test_add_func(
"/entity-record/empty-value",
test_entity_record_empty_value
);
g_test_add_func(
"/entity-record/confidence-below-range",
test_entity_record_confidence_below_range
);
g_test_add_func(
"/entity-record/confidence-above-range",
test_entity_record_confidence_above_range
);
g_test_add_func(
"/entity-record/invalid-created-at",
test_entity_record_invalid_created_at
);
g_test_add_func(
"/entity-record/invalid-updated-at",
test_entity_record_invalid_updated_at
);
g_test_add_func(
"/entity-record/valid-statuses",
test_entity_record_valid_statuses
);
g_test_add_func(
"/entity-record/invalid-status",
test_entity_record_invalid_status
);
g_test_add_func(
"/entity-record/null-accessors",
test_entity_record_null_accessors
);
g_test_add_func(
"/entity-record/optional-error",
test_entity_record_optional_error
);
return g_test_run();
}