This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Adresses réalistes de Nantes (44000) utilisées pour vérifier que l'adresse
|
||||
// de livraison survit intacte à la création puis à toutes les voies de
|
||||
// récupération d'une commande (client, admin, livreur, historique).
|
||||
var nantesAddresses = []string{
|
||||
"12 Rue Crébillon, 44000 Nantes",
|
||||
"3 Place Royale, 44000 Nantes",
|
||||
"5 Cours des 50 Otages, 44000 Nantes",
|
||||
"8 Rue de Verdun, 44000 Nantes",
|
||||
}
|
||||
|
||||
// newTestCommandWithAddress crée directement une commande avec une adresse et
|
||||
// un statut contrôlés (en contournant le checkout), pour tester isolément la
|
||||
// récupération de l'adresse par les différentes fonctions de listing.
|
||||
func newTestCommandWithAddress(t *testing.T, username, status, address, livreurAssign string, productID int, quantite, prix float64) int {
|
||||
t.Helper()
|
||||
var cmdID int
|
||||
if err := testDB.GDB.Raw(
|
||||
`INSERT INTO commandes (username, status, adresse, livreur_assign, total_prix, created_at, updated_at)
|
||||
VALUES (?, ?, ?, NULLIF(?, ''), ?, NOW(), NOW()) RETURNING id`,
|
||||
username, status, address, livreurAssign, prix,
|
||||
).Scan(&cmdID).Error; err != nil {
|
||||
t.Fatalf("création commande test avec adresse: %v", err)
|
||||
}
|
||||
if err := testDB.GDB.Exec(
|
||||
`INSERT INTO command_items (command_id, product_id, produit, quantite, prix, status)
|
||||
VALUES (?, ?, 'item test', ?, ?, 'pending')`,
|
||||
cmdID, productID, quantite, prix,
|
||||
).Error; err != nil {
|
||||
t.Fatalf("création item test: %v", err)
|
||||
}
|
||||
return cmdID
|
||||
}
|
||||
|
||||
// Le checkout réel (panier -> CreateCommandWithAddress) doit stocker l'adresse
|
||||
// telle quelle, et GetCommandByID doit la restituer à l'identique.
|
||||
func TestCreateCommandWithAddress_RoundTripsRealNantesAddress(t *testing.T) {
|
||||
for _, address := range nantesAddresses {
|
||||
t.Run(address, func(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "addr_checkout")
|
||||
productID := newTestProduct(t, "AddrCheckout", 10)
|
||||
|
||||
if _, err := testDB.AddToBasket(username, productID, 1); err != nil {
|
||||
t.Fatalf("AddToBasket: %v", err)
|
||||
}
|
||||
cmd, err := testDB.CreateCommandWithAddress(username, address)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateCommandWithAddress: %v", err)
|
||||
}
|
||||
|
||||
command, err := testDB.GetCommandByID(cmd.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetCommandByID: %v", err)
|
||||
}
|
||||
got, _ := command["adresse"].(string)
|
||||
if got != address {
|
||||
t.Errorf("adresse récupérée: got=%q want=%q", got, address)
|
||||
}
|
||||
if got == "" {
|
||||
t.Error("l'adresse ne doit jamais être vide")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Une adresse vide ou uniquement composée d'espaces doit être rejetée au
|
||||
// checkout — pas de commande créée avec une adresse de livraison absente.
|
||||
func TestCreateCommandWithAddress_RejectsEmptyOrBlankAddress(t *testing.T) {
|
||||
for _, address := range []string{"", " ", "\t\n"} {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "addr_blank")
|
||||
productID := newTestProduct(t, "AddrBlank", 10)
|
||||
|
||||
if _, err := testDB.AddToBasket(username, productID, 1); err != nil {
|
||||
t.Fatalf("AddToBasket: %v", err)
|
||||
}
|
||||
if _, err := testDB.CreateCommandWithAddress(username, address); err == nil {
|
||||
t.Errorf("adresse %q aurait dû être rejetée", address)
|
||||
}
|
||||
|
||||
var count int64
|
||||
testDB.GDB.Raw(`SELECT COUNT(*) FROM commandes WHERE username = ?`, username).Scan(&count)
|
||||
if count != 0 {
|
||||
t.Errorf("aucune commande ne doit être créée avec une adresse %q: got=%d", address, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllCommands (vue admin) doit toujours renvoyer l'adresse de chaque
|
||||
// commande, quel que soit son statut.
|
||||
func TestGetAllCommands_AlwaysIncludesAddress(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "addr_admin_list")
|
||||
productID := newTestProduct(t, "AddrAdminList", 10)
|
||||
|
||||
want := map[int]string{}
|
||||
for i, address := range nantesAddresses {
|
||||
status := []string{"pending", "assigned", "en_route", "livre"}[i%4]
|
||||
cmdID := newTestCommandWithAddress(t, username, status, address, "", productID, 1, 10)
|
||||
want[cmdID] = address
|
||||
}
|
||||
|
||||
commands, err := testDB.GetAllCommands("", username)
|
||||
if err != nil {
|
||||
t.Fatalf("GetAllCommands: %v", err)
|
||||
}
|
||||
if len(commands) != len(want) {
|
||||
t.Fatalf("nombre de commandes: got=%d want=%d", len(commands), len(want))
|
||||
}
|
||||
for _, c := range commands {
|
||||
id, _ := c["id"].(int)
|
||||
address, _ := c["adresse"].(string)
|
||||
if address == "" {
|
||||
t.Errorf("commande %d: adresse vide", id)
|
||||
}
|
||||
if want[id] != address {
|
||||
t.Errorf("commande %d: adresse=%q want=%q", id, address, want[id])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetDeliveryPersonCommands (vue livreur) doit inclure l'adresse de chaque
|
||||
// commande qui lui est assignée.
|
||||
func TestGetDeliveryPersonCommands_IncludesAddress(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "addr_livreur_client")
|
||||
productID := newTestProduct(t, "AddrLivreur", 10)
|
||||
livreurUsername := testUserPrefix + "addr_livreur"
|
||||
address := nantesAddresses[0]
|
||||
|
||||
cmdID := newTestCommandWithAddress(t, username, "assigned", address, livreurUsername, productID, 1, 10)
|
||||
|
||||
commands, err := testDB.GetDeliveryPersonCommands(livreurUsername, "")
|
||||
if err != nil {
|
||||
t.Fatalf("GetDeliveryPersonCommands: %v", err)
|
||||
}
|
||||
if len(commands) != 1 {
|
||||
t.Fatalf("nombre de commandes assignées: got=%d want=1", len(commands))
|
||||
}
|
||||
got, _ := commands[0]["adresse"].(string)
|
||||
if got != address {
|
||||
t.Errorf("adresse: got=%q want=%q", got, address)
|
||||
}
|
||||
// Le type Go concret de la colonne "id" issue d'un Raw(...).Scan(&[]map[string]any)
|
||||
// n'est pas garanti (int64 selon le driver) — même précaution que le code
|
||||
// de production (ex: handlers/deleviry.go, fmt.Sprintf + strconv.Atoi).
|
||||
id, _ := strconv.Atoi(fmt.Sprintf("%v", commands[0]["id"]))
|
||||
if id != cmdID {
|
||||
t.Errorf("id de commande inattendu: got=%d want=%d", id, cmdID)
|
||||
}
|
||||
}
|
||||
|
||||
// GetCancelledCommands doit inclure l'adresse même pour une commande annulée.
|
||||
func TestGetCancelledCommands_IncludesAddress(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "addr_cancelled")
|
||||
productID := newTestProduct(t, "AddrCancelled", 10)
|
||||
address := nantesAddresses[1]
|
||||
|
||||
newTestCommandWithAddress(t, username, "cancelled", address, "", productID, 1, 10)
|
||||
|
||||
commands, err := testDB.GetCancelledCommands(username, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("GetCancelledCommands: %v", err)
|
||||
}
|
||||
if len(commands) != 1 {
|
||||
t.Fatalf("nombre de commandes annulées: got=%d want=1", len(commands))
|
||||
}
|
||||
got, _ := commands[0]["adresse"].(string)
|
||||
if got != address {
|
||||
t.Errorf("adresse: got=%q want=%q", got, address)
|
||||
}
|
||||
}
|
||||
|
||||
// GetCompletedCommandsByUsername (historique client) doit inclure l'adresse
|
||||
// des commandes terminées (approved).
|
||||
func TestGetCompletedCommandsByUsername_IncludesAddress(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "addr_history")
|
||||
productID := newTestProduct(t, "AddrHistory", 10)
|
||||
address := nantesAddresses[2]
|
||||
|
||||
newTestCommandWithAddress(t, username, "approved", address, "", productID, 1, 10)
|
||||
|
||||
commands, err := testDB.GetCompletedCommandsByUsername(username)
|
||||
if err != nil {
|
||||
t.Fatalf("GetCompletedCommandsByUsername: %v", err)
|
||||
}
|
||||
if len(commands) != 1 {
|
||||
t.Fatalf("nombre de commandes terminées: got=%d want=1", len(commands))
|
||||
}
|
||||
got, _ := commands[0]["adresse"].(string)
|
||||
if got != address {
|
||||
t.Errorf("adresse: got=%q want=%q", got, address)
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllCommandsOldestFirst (vue cabine/admin triée) doit également inclure
|
||||
// l'adresse de chaque commande.
|
||||
func TestGetAllCommandsOldestFirst_IncludesAddress(t *testing.T) {
|
||||
cleanupStockTestData(t)
|
||||
username := newTestClient(t, "addr_oldest_first")
|
||||
productID := newTestProduct(t, "AddrOldestFirst", 10)
|
||||
address := nantesAddresses[3]
|
||||
|
||||
newTestCommandWithAddress(t, username, "pending", address, "", productID, 1, 10)
|
||||
|
||||
commands, err := testDB.GetAllCommandsOldestFirst("", username)
|
||||
if err != nil {
|
||||
t.Fatalf("GetAllCommandsOldestFirst: %v", err)
|
||||
}
|
||||
if len(commands) != 1 {
|
||||
t.Fatalf("nombre de commandes: got=%d want=1", len(commands))
|
||||
}
|
||||
got, _ := commands[0]["adresse"].(string)
|
||||
if got != address {
|
||||
t.Errorf("adresse: got=%q want=%q", got, address)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user