labfy-investigation/tests/test_financial_dao.c
fy59 d65f9559e6 chore(checkpoint): preserve local investigation workbench
Preserve the local graph-first investigation stack through macro V1.

Include reviewed source, tests, contracts, documentation and synthetic assets.

Retain the standalone financial V21 test foundation without runtime migration.

Runtime remains V20; operational JobStore remains V3.

Local experimental checkpoint, not a stable release.
2026-09-27 08:34:46 +02:00

23 lines
8.4 KiB
C

#include "dao/financial_dao.h"
#include "database/schema.h"
#include "database/statement.h"
#include <glib.h>
#include <glib/gstdio.h>
#include <unistd.h>
static const char*at="2026-08-04T10:00:00Z";static const char*sha="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
static char *temp_path(void){char*p=NULL;int fd=g_file_open_tmp("labfy-specimen-finance-XXXXXX.sqlite",&p,NULL);g_assert_cmpint(fd,>=,0);close(fd);g_unlink(p);return p;}
static gboolean exec(Database*d,const char*sql){DatabaseStatement*s=database_statement_prepare(d,sql);gboolean ok=s&&database_statement_step(s)==DATABASE_STATEMENT_STEP_DONE;database_statement_finalize(s);return ok;}
static Database *fixture(const char*p){Database*d=database_open(p);g_assert_true(schema_install_v21_direct(d));g_assert_true(exec(d,"INSERT INTO metadata VALUES('investigation_uuid','SPECIMEN-INV');"));g_assert_true(exec(d,"INSERT INTO investigation VALUES('SPECIMEN-INV','SPECIMEN','/tmp/SPECIMEN','2026-08-04T10:00:00Z','2026-08-04T10:00:00Z');"));g_assert_true(exec(d,"INSERT INTO preuves(id,name,relative_path,type_id,size_bytes,sha256,imported_at,updated_at,original_name) VALUES('SPECIMEN-EV','SPECIMEN.txt','SPECIMEN.txt',8,1,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','2026-08-04T10:00:00Z','2026-08-04T10:00:00Z','SPECIMEN.txt');"));g_assert_true(exec(d,"INSERT INTO entites(id,type_id,valeur,created_at,updated_at) VALUES('SPECIMEN-ACCOUNT',2,'SPECIMEN ACCOUNT','2026-08-04T10:00:00Z','2026-08-04T10:00:00Z');"));g_assert_true(exec(d,"INSERT INTO entites(id,type_id,valeur,created_at,updated_at) VALUES('SPECIMEN-PERSON',7,'SPECIMEN HOLDER A','2026-08-04T10:00:00Z','2026-08-04T10:00:00Z');"));return d;}
static void test_persistence(void){char*p=temp_path();Database*d=fixture(p);BankObservationDao*od=bank_observation_dao_new(d);BankReviewDao*rd=bank_review_dao_new(d);BankAccountDao*ad=bank_account_dao_new(d);DeclaredBankHolderDao*hd=declared_bank_holder_dao_new(d);FinancialTransactionDao*td=financial_transaction_dao_new(d);
BankAnalysisRecord analysis={.id="SPECIMEN-AN",.investigation_id="SPECIMEN-INV",.evidence_id="SPECIMEN-EV",.evidence_sha256=(char*)sha,.extraction_method="manual",.source_kind="manual_text",.created_at=(char*)at,.origin=BANK_ORIGIN_HUMAN};g_assert_true(bank_observation_dao_insert_analysis(od,&analysis,NULL));
GPtrArray*w=g_ptr_array_new();g_ptr_array_add(w,"SPECIMEN warning");BankObservationRecord observation={.id="SPECIMEN-OBS",.analysis_id="SPECIMEN-AN",.investigation_id="SPECIMEN-INV",.evidence_id="SPECIMEN-EV",.evidence_sha256=(char*)sha,.occurrence_type="iban",.raw_value="FR4830002005500000000000052",.start_offset=0,.end_offset=27,.extraction_rule="manual",.validation=BANK_VALIDATION_VALID,.origin=BANK_ORIGIN_HUMAN,.created_at=(char*)at,.warnings=w};g_assert_true(bank_observation_dao_insert(od,&observation,NULL));g_ptr_array_unref(w);BankObservationRecord*found=bank_observation_dao_find(od,"SPECIMEN-OBS",NULL);g_assert_nonnull(found);g_assert_cmpstr(found->raw_value,==,observation.raw_value);bank_observation_record_free(found);
GPtrArray*ids=g_ptr_array_new();GPtrArray*roles=g_ptr_array_new();GPtrArray*reasons=g_ptr_array_new();g_ptr_array_add(ids,"SPECIMEN-OBS");g_ptr_array_add(roles,"iban");g_ptr_array_add(reasons,"SPECIMEN explicit");BankProposalRecord proposal={.id="SPECIMEN-PROP",.investigation_id="SPECIMEN-INV",.evidence_id="SPECIMEN-EV",.start_offset=0,.end_offset=27,.ambiguous=TRUE,.origin=BANK_ORIGIN_AUTOMATIC,.created_at=(char*)at,.observation_ids=ids,.roles=roles,.reasons=reasons};g_assert_true(bank_review_dao_insert_proposal(rd,&proposal,NULL));g_ptr_array_unref(ids);g_ptr_array_unref(roles);g_ptr_array_unref(reasons);
BankRevisionRecord revision={.id="SPECIMEN-REV",.observation_id="SPECIMEN-OBS",.corrected_value="FR4830002005500000000000052",.normalized_value="FR4830002005500000000000052",.validation=BANK_VALIDATION_VALID,.created_at=(char*)at};g_assert_true(bank_review_dao_insert_revision(rd,&revision,NULL));BankDecisionRecord decision={.id="SPECIMEN-DEC",.observation_id="SPECIMEN-OBS",.revision_id="SPECIMEN-REV",.created_at=(char*)at,.decision=BANK_DECISION_CONFIRMED,.create_account=TRUE,.create_holder=TRUE,.create_transaction=TRUE};g_assert_true(bank_review_dao_insert_decision(rd,&decision,NULL));BankProposalRecord*stored_proposal=bank_review_dao_find_proposal(rd,"SPECIMEN-PROP",NULL);BankRevisionRecord*stored_revision=bank_review_dao_find_revision(rd,"SPECIMEN-REV",NULL);BankDecisionRecord*stored_decision=bank_review_dao_find_decision(rd,"SPECIMEN-DEC",NULL);g_assert_nonnull(stored_proposal);g_assert_nonnull(stored_revision);g_assert_nonnull(stored_decision);g_assert_cmpuint(stored_proposal->observation_ids->len,==,1);bank_proposal_record_free(stored_proposal);bank_revision_record_free(stored_revision);bank_decision_record_free(stored_decision);
BankAccountRecord account={.entity_id="SPECIMEN-ACCOUNT",.investigation_id="SPECIMEN-INV",.iban_normalized="FR4830002005500000000000052",.country_code="FR",.bank_code="30002",.branch_code="00550",.account_number="00000000005",.rib_key="52",.state=BANK_ACCOUNT_STATE_UNKNOWN,.first_observed_at=(char*)at,.last_observed_at=(char*)at};g_assert_true(bank_account_dao_insert(ad,&account,NULL));g_assert_true(bank_account_dao_add_observation_source(ad,"SPECIMEN-ACCOUNT","SPECIMEN-OBS","SPECIMEN-DEC","created",at,NULL));
DeclaredBankHolderRecord holder={.id="SPECIMEN-HOLDER",.investigation_id="SPECIMEN-INV",.evidence_id="SPECIMEN-EV",.observation_id="SPECIMEN-OBS",.revision_id="SPECIMEN-REV",.account_entity_id="SPECIMEN-ACCOUNT",.person_entity_id="SPECIMEN-PERSON",.decision_id="SPECIMEN-DEC",.declared_name_raw="SPECIMEN HOLDER A",.created_at=(char*)at};g_assert_true(declared_bank_holder_dao_insert(hd,&holder,NULL));
FinancialTransactionRecord transaction={.id="SPECIMEN-TX",.investigation_id="SPECIMEN-INV",.transaction_type="transfer",.amount_decimal="1234567890.12",.currency="EUR",.observed_status="envoyé (observé)",.bank_reference="SPECIMEN-REF",.reference_type="UETR",.uetr="11111111-2222-4333-8444-555555555555",.debtor_account_id="SPECIMEN-ACCOUNT",.evidence_id="SPECIMEN-EV",.source_observation_id="SPECIMEN-OBS",.decision_id="SPECIMEN-DEC",.created_at=(char*)at};g_assert_true(financial_transaction_dao_insert(td,&transaction,NULL));g_assert_true(financial_transaction_dao_add_observation_source(td,"SPECIMEN-TX","SPECIMEN-OBS",0,NULL));
g_test_expect_message(NULL,G_LOG_LEVEL_WARNING,"*append-only*");g_assert_false(exec(d,"UPDATE bank_observations SET raw_value='CHANGED' WHERE id='SPECIMEN-OBS';"));g_test_assert_expected_messages();g_test_expect_message(NULL,G_LOG_LEVEL_WARNING,"*append-only*");g_assert_false(exec(d,"DELETE FROM bank_observations WHERE id='SPECIMEN-OBS';"));g_test_assert_expected_messages();g_test_expect_message(NULL,G_LOG_LEVEL_WARNING,"*append-only*");g_assert_false(exec(d,"UPDATE bank_observation_revisions SET normalized_value='X' WHERE id='SPECIMEN-REV';"));g_test_assert_expected_messages();
bank_observation_dao_free(od);bank_review_dao_free(rd);bank_account_dao_free(ad);declared_bank_holder_dao_free(hd);financial_transaction_dao_free(td);database_close(d);
d=database_open(p);ad=bank_account_dao_new(d);td=financial_transaction_dao_new(d);BankAccountRecord*ar=bank_account_dao_find(ad,"SPECIMEN-ACCOUNT",NULL);FinancialTransactionRecord*tr=financial_transaction_dao_find(td,"SPECIMEN-TX",NULL);g_assert_nonnull(ar);g_assert_nonnull(tr);g_assert_cmpstr(tr->amount_decimal,==,"1234567890.12");bank_account_record_free(ar);financial_transaction_record_free(tr);bank_account_dao_free(ad);financial_transaction_dao_free(td);database_close(d);g_unlink(p);g_free(p);}
static void test_negative(void){g_assert_false(financial_record_amount_valid("1,23"));g_assert_false(financial_record_amount_valid("1."));g_assert_false(financial_record_utc_valid("2026-08-04"));g_assert_false(financial_record_sha256_valid("SPECIMEN"));char*p=temp_path();Database*d=fixture(p);BankAccountDao*ad=bank_account_dao_new(d);BankAccountRecord bad={.entity_id="SPECIMEN-ACCOUNT",.investigation_id="SPECIMEN-INV",.iban_normalized="AD1200000000000000000000",.country_code="AD",.state=BANK_ACCOUNT_STATE_UNKNOWN,.first_observed_at=(char*)at,.last_observed_at=(char*)at};g_assert_false(bank_account_dao_insert(ad,&bad,NULL));bank_account_dao_free(ad);database_close(d);g_unlink(p);g_free(p);}
int main(int argc,char**argv){g_test_init(&argc,&argv,NULL);g_test_add_func("/financial-dao/persistence-reopen",test_persistence);g_test_add_func("/financial-dao/negative",test_negative);return g_test_run();}