Files
harbour-henflow/tests/engine.test.js
T

125 lines
6.3 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);
console.log(failures === 0 ? "\ntutti i controlli superati" : "\n" + failures + " controlli falliti");
process.exit(failures === 0 ? 0 : 1);