This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user