144 lines
7.6 KiB
JavaScript
144 lines
7.6 KiB
JavaScript
// Banchi di prova del motore Henflow (node, fuori dal pacchetto RPM).
|
|
// node tests/engine.test.js
|
|
// I casi replicano il comportamento dell'app Flutter (lib/main.dart) e i dati
|
|
// visibili nello screenshot dello store: Marans 2 galline, Araucana 2,
|
|
// Leghorn 3 (di cui 2 in deposizione) -> 6.0 uova/giorno.
|
|
|
|
var HF = require("../qml/js/henflow.js");
|
|
|
|
var failures = 0;
|
|
function check(name, got, expected) {
|
|
var ok = JSON.stringify(got) === JSON.stringify(expected);
|
|
if (!ok) failures++;
|
|
console.log((ok ? "OK " : "FAIL ") + name + " got=" + JSON.stringify(got)
|
|
+ (ok ? "" : " expected=" + JSON.stringify(expected)));
|
|
}
|
|
|
|
// catalogo (dal breed_catalog.dart: tutte le razze 1.0 uovo/gallina/giorno)
|
|
var CATALOG = [
|
|
{ id: "marans", eggsPerHenPerDay: 1.0 },
|
|
{ id: "araucana", eggsPerHenPerDay: 1.0 },
|
|
{ id: "olive", eggsPerHenPerDay: 1.0 },
|
|
{ id: "livorno", eggsPerHenPerDay: 1.0 }
|
|
];
|
|
|
|
function hen(id, laying) {
|
|
return { id: id, name: id, birthDate: "2025-01-01T00:00:00.000", isLaying: laying };
|
|
}
|
|
|
|
var BREEDS = [
|
|
{ breedId: "marans", hens: [hen("m1", true), hen("m2", true)] },
|
|
{ breedId: "araucana", hens: [hen("a1", true), hen("a2", true)] },
|
|
{ breedId: "livorno", hens: [hen("l1", true), hen("l2", true), hen("l3", false)] }
|
|
];
|
|
|
|
var TODAY = new Date(2026, 3, 27); // 27 aprile 2026, come nello screenshot
|
|
|
|
// --- produzione ---------------------------------------------------------
|
|
check("produzione marans (2 galline)", HF.breedDailyProduction(BREEDS, CATALOG, "marans"), 2.0);
|
|
check("produzione livorno (2 su 3 in deposizione)", HF.breedDailyProduction(BREEDS, CATALOG, "livorno"), 2.0);
|
|
check("produzione totale = 6.0 uova/giorno", HF.totalDailyProduction(BREEDS, CATALOG), 6.0);
|
|
check("razza non configurata -> 0", HF.breedDailyProduction(BREEDS, CATALOG, "olive"), 0);
|
|
check("dettaglio razze attive", HF.productionDetail(BREEDS, CATALOG).map(function (e) { return e.daily; }), [2, 2, 2]);
|
|
|
|
// --- eta' e produttivita' (soglia 6 mesi) --------------------------------
|
|
check("eta' 6 mesi compiuti", HF.ageInMonths(new Date(2025, 9, 27), TODAY), 6);
|
|
check("un giorno prima dei 6 mesi -> 5", HF.ageInMonths(new Date(2025, 9, 28), TODAY), 5);
|
|
check("6 mesi -> produttiva", HF.isProductive(new Date(2025, 9, 27), TODAY), true);
|
|
check("5 mesi -> non ancora produttiva", HF.isProductive(new Date(2025, 10, 28), TODAY), false);
|
|
|
|
// --- magazzino: accrual all'apertura -------------------------------------
|
|
check("3 giorni di produzione", HF.accrueStock({}, BREEDS, CATALOG, 3),
|
|
{ marans: 6, araucana: 6, livorno: 6 });
|
|
check("scorte esistenti incrementate", HF.accrueStock({ marans: 2 }, BREEDS, CATALOG, 1),
|
|
{ marans: 4, araucana: 2, livorno: 2 });
|
|
check("nessun giorno passato -> invariate", HF.accrueStock({ marans: 1 }, BREEDS, CATALOG, 0),
|
|
{ marans: 1 });
|
|
|
|
// --- data di consegna per una nuova prenotazione -------------------------
|
|
check("scorte sufficienti -> oggi",
|
|
HF.estimateDeliveryDate([], { araucana: 3 }, BREEDS, CATALOG, "araucana", 2, TODAY), "2026-04-27");
|
|
check("2 uova senza scorte, 2/giorno -> domani",
|
|
HF.estimateDeliveryDate([], {}, BREEDS, CATALOG, "araucana", 2, TODAY), "2026-04-28");
|
|
check("5 uova senza scorte, 2/giorno -> 3 giorni (ceil)",
|
|
HF.estimateDeliveryDate([], {}, BREEDS, CATALOG, "araucana", 5, TODAY), "2026-04-30");
|
|
check("ordini pendenti contano nelle scorte richieste",
|
|
HF.estimateDeliveryDate([res("p", "araucana", 4)], {}, BREEDS, CATALOG, "araucana", 2, TODAY),
|
|
"2026-04-30");
|
|
check("razza senza galline in deposizione -> oggi (produzione 0)",
|
|
HF.estimateDeliveryDate([], {}, BREEDS, CATALOG, "olive", 3, TODAY), "2026-04-27");
|
|
|
|
// --- coda FIFO ------------------------------------------------------------
|
|
function res(id, breedId, eggs, createdDay, delivered) {
|
|
return {
|
|
id: id,
|
|
customerName: "Cli",
|
|
breedId: breedId,
|
|
eggsRequested: eggs,
|
|
createdAt: "2026-04-2" + createdDay + "T09:00:00.000",
|
|
deliveryDate: "2026-04-20T00:00:00.000",
|
|
isDelivered: !!delivered
|
|
};
|
|
}
|
|
|
|
var queue = HF.refreshDeliveryDates(
|
|
[res("b", "araucana", 2, 5), res("a", "araucana", 1, 1)],
|
|
{ araucana: 0 }, BREEDS, CATALOG, TODAY);
|
|
// ordine FIFO: "a" (creato prima) consuma la prima produzione
|
|
check("FIFO: ordine piu' vecchio prima", [queue[0].id, queue[1].id], ["a", "b"]);
|
|
check("FIFO: date calcolate in ordine di arrivo",
|
|
[queue[0].deliveryDate, queue[1].deliveryDate], ["2026-04-28", "2026-04-29"]);
|
|
check("ordine evaso subito con scorte",
|
|
HF.refreshDeliveryDates([res("c", "araucana", 2, 1)], { araucana: 2 }, BREEDS, CATALOG, TODAY)[0].deliveryDate,
|
|
"2026-04-27");
|
|
check("ordine consegnato: data invariata e nessun consumo di scorte",
|
|
HF.refreshDeliveryDates([res("d", "araucana", 99, 1, true), res("e", "araucana", 1, 2)],
|
|
{ araucana: 1 }, BREEDS, CATALOG, TODAY)[0].deliveryDate,
|
|
"2026-04-20");
|
|
check("razza a produzione 0: data non toccata",
|
|
HF.refreshDeliveryDates([res("f", "olive", 3, 1)], {}, BREEDS, CATALOG, TODAY)[0].deliveryDate,
|
|
"2026-04-20");
|
|
check("la coda modificata non altera l'input (immutabilita')",
|
|
(function () {
|
|
var input = [res("g", "araucana", 1, 1)];
|
|
HF.refreshDeliveryDates(input, {}, BREEDS, CATALOG, TODAY);
|
|
return input[0].deliveryDate;
|
|
})(), "2026-04-20T00:00:00.000");
|
|
|
|
// --- stato della card -----------------------------------------------------
|
|
check("stato: scaduto", HF.statusKey(-1), "late");
|
|
check("stato: oggi", HF.statusKey(0), "today");
|
|
check("stato: domani", HF.statusKey(1), "tomorrow");
|
|
check("stato: fra N giorni", HF.statusKey(4), "in_days");
|
|
|
|
// --- date -----------------------------------------------------------------
|
|
check("dayDiff ignora l'ora", HF.dayDiff(new Date(2026, 3, 27, 23, 59), new Date(2026, 3, 28, 0, 1)), 1);
|
|
check("parseIso -> solo il giorno", HF.isoDay(HF.parseIso("2026-04-28T09:30:00.000")), "2026-04-28");
|
|
check("isoDay con padding", HF.isoDay(new Date(2026, 0, 5)), "2026-01-05");
|
|
check("formatDay gg/mm/aaaa (come la card Android)", HF.formatDay("2026-04-28"), "28/04/2026");
|
|
check("formatDay su stringa vuota", HF.formatDay(""), "");
|
|
check("nowIso in formato ISO", /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.000$/.test(HF.nowIso()), true);
|
|
check("newId unico", HF.newId() !== HF.newId(), true);
|
|
|
|
// --- fedelta' dei campi degli ordini (app Android) ------------------------
|
|
var withNote = { id: "n1", customerName: "Anna", breedId: "marans", eggsRequested: 2,
|
|
createdAt: "2026-04-25T09:00:00.000", deliveryDate: "2026-04-28T00:00:00.000",
|
|
isDelivered: false, source: "client", clientNote: "guscio chiaro" };
|
|
var kept = HF.refreshDeliveryDates([withNote], {}, BREEDS, CATALOG, TODAY);
|
|
check("nota del cliente conservata nel ricalcolo delle date", kept[0].clientNote, "guscio chiaro");
|
|
check("origine dell'ordine conservata", kept[0].source, "client");
|
|
|
|
// --- consegna: le uova escono dal magazzino -------------------------------
|
|
var stock0 = { "marans": 10, "araucana": 3 };
|
|
var afterDelivery = HF.applyDelivery(stock0, { breedId: "marans", eggsRequested: 4 }, true);
|
|
check("consegna: uova scalate dal magazzino della razza", afterDelivery.marans, 6);
|
|
check("consegna: le altre razze non si toccano", afterDelivery.araucana, 3);
|
|
check("consegna: magazzino di partenza non modificato", stock0.marans, 10);
|
|
check("consegna annullata: uova rimesse nel magazzino",
|
|
HF.applyDelivery(afterDelivery, { breedId: "marans", eggsRequested: 4 }, false).marans, 10);
|
|
check("consegna su razza senza scorte: il magazzino va sotto zero",
|
|
HF.applyDelivery({}, { breedId: "olive", eggsRequested: 3 }, true).olive, -3);
|
|
|
|
console.log(failures === 0 ? "\ntutti i controlli superati" : "\n" + failures + " controlli falliti");
|
|
process.exit(failures === 0 ? 0 : 1);
|