From 1623a9eafdb0238a30f94ace1dd6eecef3ea0519 Mon Sep 17 00:00:00 2001 From: Xor290 Date: Tue, 4 Aug 2026 21:09:58 +0200 Subject: [PATCH] chore: fix bug --- backend/gestion/db/db_address.go | 3 +- .../gestion/tests/address_correction_test.go | 118 ++++++++++++++++++ .../tests/utils_normalize_address_test.go | 57 +++++++++ 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 backend/gestion/tests/utils_normalize_address_test.go diff --git a/backend/gestion/db/db_address.go b/backend/gestion/db/db_address.go index ee10a52f..26324967 100644 --- a/backend/gestion/db/db_address.go +++ b/backend/gestion/db/db_address.go @@ -4,6 +4,7 @@ import ( "fmt" "gestion/models" "gestion/utils" + "strings" ) func (d *Database) CheckAddress(addressByUser *models.Command) error { @@ -25,7 +26,7 @@ func (d *Database) CheckAddress(addressByUser *models.Command) error { } normalizedInput := utils.NormalizeAddress(addressByUser.DeliveryAddress) for _, c := range corrections { - if utils.NormalizeAddress(c.InvalidAddress) == normalizedInput { + if strings.EqualFold(utils.NormalizeAddress(c.InvalidAddress), normalizedInput) { addressByUser.DeliveryAddress = c.CorrectAddress return fmt.Errorf("adresse invalide %s", c.CorrectAddress) } diff --git a/backend/gestion/tests/address_correction_test.go b/backend/gestion/tests/address_correction_test.go index c7746130..5317ed1f 100644 --- a/backend/gestion/tests/address_correction_test.go +++ b/backend/gestion/tests/address_correction_test.go @@ -52,6 +52,124 @@ func TestCheckAddress_MatchSubstitutesCorrectAddressAndReturnsError(t *testing.T } } +// addCorrectionForFallback enregistre une correction et retourne une fonction +// de nettoyage à appeler via t.Cleanup par l'appelant (évite de dépendre de +// l'ordre d'exécution entre plusieurs corrections ajoutées dans un même test). +func addCorrectionForFallback(t *testing.T, invalid, correct string) { + t.Helper() + if err := testDB.AddAddress(correct, invalid); err != nil { + t.Fatalf("AddAddress(%q -> %q): %v", invalid, correct, err) + } + var id int64 + testDB.GDB.Raw(`SELECT id FROM adresse_correction WHERE invalid_address = ?`, invalid).Scan(&id) + cleanupAddressCorrections(t, id) +} + +// Les quatre tests suivants couvrent le fallback normalisé de CheckAddress +// (utils.NormalizeAddress + strings.EqualFold) : une correction enregistrée +// par l'admin avec un texte exact donné doit continuer à s'appliquer même si +// le client tape une variante mineure (casse, accents, espaces), plutôt que +// d'échouer silencieusement et laisser passer une adresse non livrable. + +func TestCheckAddress_NormalizedFallback_CaseVariantMatches(t *testing.T) { + invalid := testUserPrefix + "12 Rue Crebillon Nantes" + correct := testUserPrefix + "12 Rue Crébillon, 44000 Nantes" + addCorrectionForFallback(t, invalid, correct) + + cmd := &models.Command{DeliveryAddress: testUserPrefix + "12 RUE CREBILLON NANTES"} + err := testDB.CheckAddress(cmd) + if err == nil { + t.Fatal("attendu une erreur signalant la correction (variante de casse)") + } + if cmd.DeliveryAddress != correct { + t.Errorf("adresse corrigée: got=%q want=%q", cmd.DeliveryAddress, correct) + } +} + +func TestCheckAddress_NormalizedFallback_AccentVariantMatches(t *testing.T) { + invalid := testUserPrefix + "10 Rue du Général Buat Nantes" + correct := testUserPrefix + "10 Rue du Général Buat, 44000 Nantes" + addCorrectionForFallback(t, invalid, correct) + + // Saisie sans accent par le client, alors que la correction enregistrée + // par l'admin en contient un. + cmd := &models.Command{DeliveryAddress: testUserPrefix + "10 Rue du General Buat Nantes"} + err := testDB.CheckAddress(cmd) + if err == nil { + t.Fatal("attendu une erreur signalant la correction (variante d'accent)") + } + if cmd.DeliveryAddress != correct { + t.Errorf("adresse corrigée: got=%q want=%q", cmd.DeliveryAddress, correct) + } +} + +func TestCheckAddress_NormalizedFallback_WhitespaceVariantMatches(t *testing.T) { + invalid := testUserPrefix + "5 Cours des 50 Otages Nantes" + correct := testUserPrefix + "5 Cours des 50 Otages, 44000 Nantes" + addCorrectionForFallback(t, invalid, correct) + + cmd := &models.Command{DeliveryAddress: testUserPrefix + "5 Cours des 50 Otages Nantes "} + err := testDB.CheckAddress(cmd) + if err == nil { + t.Fatal("attendu une erreur signalant la correction (espaces multiples)") + } + if cmd.DeliveryAddress != correct { + t.Errorf("adresse corrigée: got=%q want=%q", cmd.DeliveryAddress, correct) + } +} + +func TestCheckAddress_NormalizedFallback_CombinedCaseAccentWhitespaceMatches(t *testing.T) { + invalid := testUserPrefix + "8 Rue de Verdun Nantes" + correct := testUserPrefix + "8 Rue de Verdun, 44000 Nantes" + addCorrectionForFallback(t, invalid, correct) + + cmd := &models.Command{DeliveryAddress: testUserPrefix + "8 RUE de verdun nantes "} + err := testDB.CheckAddress(cmd) + if err == nil { + t.Fatal("attendu une erreur signalant la correction (casse + espaces combinés)") + } + if cmd.DeliveryAddress != correct { + t.Errorf("adresse corrigée: got=%q want=%q", cmd.DeliveryAddress, correct) + } +} + +// Le fallback compare une égalité normalisée stricte, pas une similarité +// floue : une adresse réellement différente (même partiellement proche) ne +// doit jamais être substituée par erreur. +func TestCheckAddress_NormalizedFallback_DoesNotMatchDifferentAddress(t *testing.T) { + invalid := testUserPrefix + "12 Rue Crebillon Nantes" + correct := testUserPrefix + "12 Rue Crébillon, 44000 Nantes" + addCorrectionForFallback(t, invalid, correct) + + cmd := &models.Command{DeliveryAddress: testUserPrefix + "14 Rue Crebillon Nantes"} + original := cmd.DeliveryAddress + if err := testDB.CheckAddress(cmd); err != nil { + t.Fatalf("une adresse différente ne doit pas déclencher de correction: %v", err) + } + if cmd.DeliveryAddress != original { + t.Errorf("adresse ne doit pas être modifiée: got=%q want=%q", cmd.DeliveryAddress, original) + } +} + +// Avec plusieurs corrections enregistrées, le fallback doit retrouver la +// bonne entrée (pas la première venue) même via une variante normalisée. +func TestCheckAddress_NormalizedFallback_FindsRightEntryAmongMultiple(t *testing.T) { + invalidA := testUserPrefix + "1 Rue A Nantes" + correctA := testUserPrefix + "1 Rue A, 44000 Nantes" + invalidB := testUserPrefix + "2 Rue B Nantes" + correctB := testUserPrefix + "2 Rue B, 44000 Nantes" + addCorrectionForFallback(t, invalidA, correctA) + addCorrectionForFallback(t, invalidB, correctB) + + cmd := &models.Command{DeliveryAddress: testUserPrefix + "2 RUE b nantes"} + if err := testDB.CheckAddress(cmd); err == nil { + t.Fatal("attendu une erreur signalant la correction B") + } + if cmd.DeliveryAddress != correctB { + t.Errorf("adresse corrigée: got=%q want=%q (ne doit pas confondre avec A)", cmd.DeliveryAddress, correctB) + } +} + func TestAddAddress_ThenAllAddressIncludesIt(t *testing.T) { invalid := testUserPrefix + "adresse invalide test" correct := testUserPrefix + "adresse correcte test" diff --git a/backend/gestion/tests/utils_normalize_address_test.go b/backend/gestion/tests/utils_normalize_address_test.go new file mode 100644 index 00000000..cf6fe4fd --- /dev/null +++ b/backend/gestion/tests/utils_normalize_address_test.go @@ -0,0 +1,57 @@ +package tests + +import ( + "gestion/utils" + "strings" + "testing" +) + +// utils.NormalizeAddress supprime les accents et normalise les espaces, mais +// ne touche PAS à la casse — les appelants qui veulent une comparaison +// insensible à la casse doivent combiner avec strings.EqualFold ou +// strings.ToLower (voir services/adresses_correction.go et db/db_address.go). +// Ce fichier fixe ce contrat par des tests, pour éviter qu'un futur appelant +// suppose à tort que la casse est déjà gérée. + +func TestNormalizeAddress_RemovesAccents(t *testing.T) { + got := utils.NormalizeAddress("12 Rue Crébillon, Nantés") + want := "12 Rue Crebillon, Nantes" + if got != want { + t.Errorf("got=%q want=%q", got, want) + } +} + +func TestNormalizeAddress_CollapsesMultipleAndTrailingSpaces(t *testing.T) { + got := utils.NormalizeAddress(" 12 Rue de la Paix ") + want := "12 Rue de la Paix" + if got != want { + t.Errorf("got=%q want=%q", got, want) + } +} + +func TestNormalizeAddress_DoesNotChangeCase(t *testing.T) { + // Contrat volontaire : NormalizeAddress n'abaisse pas la casse. Un + // appelant qui veut une comparaison insensible à la casse doit le faire + // explicitement (strings.EqualFold côté appelant). + got := utils.NormalizeAddress("Rue De La Paix") + if got == strings.ToLower(got) { + t.Fatalf("ce test suppose une entrée avec des majuscules significatives, corrige le cas de test") + } + if got != "Rue De La Paix" { + t.Errorf("NormalizeAddress ne doit pas modifier la casse: got=%q", got) + } +} + +func TestNormalizeAddress_EmptyStringReturnsEmpty(t *testing.T) { + if got := utils.NormalizeAddress(""); got != "" { + t.Errorf("got=%q want=%q", got, "") + } +} + +func TestNormalizeAddress_CombinedAccentsAndSpaces(t *testing.T) { + got := utils.NormalizeAddress(" 20 Boulevard Général de Gaulle, Nantés ") + want := "20 Boulevard General de Gaulle, Nantes" + if got != want { + t.Errorf("got=%q want=%q", got, want) + } +}