213 lines
7.0 KiB
Go
213 lines
7.0 KiB
Go
package tests
|
|
|
|
import (
|
|
"gestion/db"
|
|
"gestion/models"
|
|
"testing"
|
|
)
|
|
|
|
// ── Persistance des settings (save→reload) ──────────────────────────────────
|
|
|
|
func TestUpdateSettings_FreeGiftsRoundTrip(t *testing.T) {
|
|
resetSettingsAfterTest(t)
|
|
|
|
s := db.DefaultSettings()
|
|
s.FreeGiftsEnabled = true
|
|
s.FreeGifts = []models.CategoryFreeGiftConfig{
|
|
{
|
|
Category: "test",
|
|
AllProducts: false,
|
|
Products: []models.FreeGiftProductQuantity{
|
|
{ProductID: 111, Tiers: []models.FreeGiftTier{
|
|
{BuyQuantity: 10, FreeQuantity: 1},
|
|
{BuyQuantity: 20, FreeQuantity: 3},
|
|
}},
|
|
},
|
|
},
|
|
}
|
|
if err := testDB.UpdateSettings(s); err != nil {
|
|
t.Fatalf("UpdateSettings: %v", err)
|
|
}
|
|
|
|
loaded, err := testDB.GetSettings()
|
|
if err != nil {
|
|
t.Fatalf("GetSettings: %v", err)
|
|
}
|
|
if !loaded.FreeGiftsEnabled {
|
|
t.Fatal("free_gifts_enabled devrait être true après reload")
|
|
}
|
|
if len(loaded.FreeGifts) != 1 {
|
|
t.Fatalf("free_gifts: got=%d want=1: %+v", len(loaded.FreeGifts), loaded.FreeGifts)
|
|
}
|
|
gift := loaded.FreeGifts[0]
|
|
if gift.Category != "test" || len(gift.Products) != 1 {
|
|
t.Fatalf("free gift mal persistée: got=%+v", gift)
|
|
}
|
|
if len(gift.Products[0].Tiers) != 2 || gift.Products[0].Tiers[1].BuyQuantity != 20 || gift.Products[0].Tiers[1].FreeQuantity != 3 {
|
|
t.Errorf("tiers mal persistés: got=%+v", gift.Products[0].Tiers)
|
|
}
|
|
|
|
// Désactivation : doit persister à false, pas de résurrection (même
|
|
// classe de bug que TestUpdateSettings_DisablingPointsRewardPersistsAsNil).
|
|
s.FreeGiftsEnabled = false
|
|
if err := testDB.UpdateSettings(s); err != nil {
|
|
t.Fatalf("UpdateSettings (désactivation): %v", err)
|
|
}
|
|
loaded, err = testDB.GetSettings()
|
|
if err != nil {
|
|
t.Fatalf("GetSettings (désactivation): %v", err)
|
|
}
|
|
if loaded.FreeGiftsEnabled {
|
|
t.Error("free_gifts_enabled devrait rester false après désactivation")
|
|
}
|
|
}
|
|
|
|
// ── Résolution de la quantité offerte (logique pure) ────────────────────────
|
|
|
|
func TestResolveFreeGift_AllProductsAtOrAboveThreshold(t *testing.T) {
|
|
settings := &models.AppSettings{
|
|
FreeGiftsEnabled: true,
|
|
FreeGifts: []models.CategoryFreeGiftConfig{
|
|
{Category: "fleurs", AllProducts: true, Tiers: []models.FreeGiftTier{
|
|
{BuyQuantity: 10, FreeQuantity: 1},
|
|
}},
|
|
},
|
|
}
|
|
if got := db.ResolveFreeGift(settings, 42, "fleurs", 10); got != 1 {
|
|
t.Errorf("quantité offerte: got=%.2f want=1", got)
|
|
}
|
|
if got := db.ResolveFreeGift(settings, 42, "fleurs", 15); got != 1 {
|
|
t.Errorf("au-dessus du seuil, le cadeau reste dû: got=%.2f want=1", got)
|
|
}
|
|
if got := db.ResolveFreeGift(settings, 42, "fleurs", 9); got != 0 {
|
|
t.Errorf("sous le seuil, aucun cadeau: got=%.2f want=0", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveFreeGift_DisabledReturnsZero(t *testing.T) {
|
|
settings := &models.AppSettings{
|
|
FreeGiftsEnabled: false,
|
|
FreeGifts: []models.CategoryFreeGiftConfig{
|
|
{Category: "fleurs", AllProducts: true, Tiers: []models.FreeGiftTier{
|
|
{BuyQuantity: 10, FreeQuantity: 1},
|
|
}},
|
|
},
|
|
}
|
|
if got := db.ResolveFreeGift(settings, 42, "fleurs", 10); got != 0 {
|
|
t.Errorf("offres désactivées: aucun cadeau attendu: got=%.2f", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveFreeGift_PerProductHighestTierApplies(t *testing.T) {
|
|
settings := &models.AppSettings{
|
|
FreeGiftsEnabled: true,
|
|
FreeGifts: []models.CategoryFreeGiftConfig{
|
|
{
|
|
Category: "fleurs",
|
|
AllProducts: false,
|
|
Products: []models.FreeGiftProductQuantity{
|
|
{ProductID: 111, Tiers: []models.FreeGiftTier{
|
|
{BuyQuantity: 10, FreeQuantity: 1},
|
|
{BuyQuantity: 20, FreeQuantity: 3},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
if got := db.ResolveFreeGift(settings, 111, "fleurs", 10); got != 1 {
|
|
t.Errorf("seuil 10g: got=%.2f want=1", got)
|
|
}
|
|
// 25g dépasse les deux seuils : le plus élevé (20g→3g) doit être retenu,
|
|
// pas le premier de la liste (10g→1g).
|
|
if got := db.ResolveFreeGift(settings, 111, "fleurs", 25); got != 3 {
|
|
t.Errorf("seuil le plus élevé atteint (20g→3g): got=%.2f want=3", got)
|
|
}
|
|
// Produit non listé dans cette config : aucun cadeau.
|
|
if got := db.ResolveFreeGift(settings, 222, "fleurs", 25); got != 0 {
|
|
t.Errorf("produit non couvert: got=%.2f want=0", got)
|
|
}
|
|
}
|
|
|
|
// ── Intégration AddToBasket : la quantité livrée inclut le cadeau, au même prix ──
|
|
|
|
func TestAddToBasket_AppliesFreeGiftQuantityAtSamePrice(t *testing.T) {
|
|
cleanupStockTestData(t)
|
|
resetSettingsAfterTest(t)
|
|
username := newTestClient(t, "freegift_basket_applies")
|
|
productID := newTestProduct(t, "FreeGiftBasketApplies", 50)
|
|
// newTestProduct crée un palier quantity=1 à 10.00€ dans la catégorie "test".
|
|
|
|
s := db.DefaultSettings()
|
|
s.FreeGiftsEnabled = true
|
|
s.FreeGifts = []models.CategoryFreeGiftConfig{
|
|
{Category: "test", AllProducts: true, Tiers: []models.FreeGiftTier{
|
|
{BuyQuantity: 10, FreeQuantity: 1},
|
|
}},
|
|
}
|
|
if err := testDB.UpdateSettings(s); err != nil {
|
|
t.Fatalf("UpdateSettings: %v", err)
|
|
}
|
|
|
|
basket, err := testDB.AddToBasket(username, productID, 10)
|
|
if err != nil {
|
|
t.Fatalf("AddToBasket: %v", err)
|
|
}
|
|
if basket.Quantity != 11 {
|
|
t.Errorf("quantité livrée attendue = 10 + 1 offert = 11: got=%.2f", basket.Quantity)
|
|
}
|
|
if basket.Price != 10.0 {
|
|
t.Errorf("le prix ne doit pas changer (facturé sur les 10g demandés): got=%.2f want=10.00", basket.Price)
|
|
}
|
|
}
|
|
|
|
func TestAddToBasket_NoFreeGiftBelowThreshold(t *testing.T) {
|
|
cleanupStockTestData(t)
|
|
resetSettingsAfterTest(t)
|
|
username := newTestClient(t, "freegift_basket_below")
|
|
productID := newTestProduct(t, "FreeGiftBasketBelow", 50)
|
|
|
|
s := db.DefaultSettings()
|
|
s.FreeGiftsEnabled = true
|
|
s.FreeGifts = []models.CategoryFreeGiftConfig{
|
|
{Category: "test", AllProducts: true, Tiers: []models.FreeGiftTier{
|
|
{BuyQuantity: 10, FreeQuantity: 1},
|
|
}},
|
|
}
|
|
if err := testDB.UpdateSettings(s); err != nil {
|
|
t.Fatalf("UpdateSettings: %v", err)
|
|
}
|
|
|
|
basket, err := testDB.AddToBasket(username, productID, 5)
|
|
if err != nil {
|
|
t.Fatalf("AddToBasket: %v", err)
|
|
}
|
|
if basket.Quantity != 5 {
|
|
t.Errorf("sous le seuil, aucune quantité offerte: got=%.2f want=5", basket.Quantity)
|
|
}
|
|
}
|
|
|
|
// La quantité réellement décomptée du stock doit inclure le cadeau : un stock
|
|
// suffisant pour la quantité demandée mais pas pour demandée+offerte doit
|
|
// faire échouer l'ajout, pas livrer un cadeau partiel.
|
|
func TestAddToBasket_FreeGiftRejectedWhenStockInsufficientForBonus(t *testing.T) {
|
|
cleanupStockTestData(t)
|
|
resetSettingsAfterTest(t)
|
|
username := newTestClient(t, "freegift_basket_stock")
|
|
productID := newTestProduct(t, "FreeGiftBasketStock", 10) // stock = 10, pile la quantité demandée
|
|
|
|
s := db.DefaultSettings()
|
|
s.FreeGiftsEnabled = true
|
|
s.FreeGifts = []models.CategoryFreeGiftConfig{
|
|
{Category: "test", AllProducts: true, Tiers: []models.FreeGiftTier{
|
|
{BuyQuantity: 10, FreeQuantity: 1},
|
|
}},
|
|
}
|
|
if err := testDB.UpdateSettings(s); err != nil {
|
|
t.Fatalf("UpdateSettings: %v", err)
|
|
}
|
|
|
|
if _, err := testDB.AddToBasket(username, productID, 10); err == nil {
|
|
t.Fatal("stock=10 ne doit pas suffire pour livrer 10g + 1g offert")
|
|
}
|
|
}
|