Files
fs25-adsmartpickup/tests/test_adPool.lua
T

183 lines
13 KiB
Lua

-- Kør: luajit tests/test_adPool.lua (fra repo-roden)
dofile("FS25_ADSmartPickup/adFieldFleet.lua")
dofile("FS25_ADSmartPickup/adHitch.lua")
dofile("FS25_ADSmartPickup/adPool.lua")
local P = ADPool
local failures = 0
local function check(name, actual, expected)
if actual == expected then print("OK " .. name) else
failures = failures + 1
print(string.format("FAIL %s: forventede %s, fik %s", name, tostring(expected), tostring(actual)))
end
end
-- rolle ud fra redskabets egne specs
check("rolle: plov", P.roleOf({spec_plow = true}), "plow")
check("rolle: kultivator", P.roleOf({spec_cultivator = true}), "cultivator")
check("rolle: vogn med tip", P.roleOf({spec_trailer = true, spec_dischargeable = true}), "unloader")
check("rolle: vogn der også er læssevogn er læssevogn", P.roleOf({spec_trailer = true, spec_dischargeable = true, spec_forageWagon = true}), "collector")
check("rolle: intet", P.roleOf({}), nil)
-- hk fra butiksdata: tal eller tabel (konfigurationer)
check("tal", P.numberOf(180), 180)
check("tabel: største", P.numberOf({base = 120, config = 150}), 150)
check("tom tabel", P.numberOf({}), nil)
check("nil", P.numberOf(nil), nil)
check("hk: nok", P.powerOk(200, 180), true)
check("hk: for lidt", P.powerOk(150, 180), false)
check("hk: redskab uden data", P.powerOk(150, nil), true)
check("hk: traktor uden data", P.powerOk(nil, 180), true)
-- kategori: markredskaber kun bag traktorer (in-game 29/9: Unimog, kategori "trucks", hentede kultivatoren)
check("kategori: traktor til kultivator", P.categoryOk("TRACTORSM", "cultivator"), true)
check("kategori: lastbil til kultivator", P.categoryOk("TRUCKS", "cultivator"), false)
check("kategori: lastbil til tømmevogn", P.categoryOk("TRUCKS", "unloader"), true)
check("kategori: teleskoplæsser til plov", P.categoryOk("TELELOADERVEHICLES", "plow"), false)
check("kategori: ukendt -> tilladt", P.categoryOk(nil, "cultivator"), true)
check("kategori: små bogstaver", P.categoryOk("tractorsL", "plow"), true)
local unimog = {id = "u", x = 0, z = 0, hp = 155, category = "TRUCKS"}
local fendt = {id = "f", x = 90, z = 0, hp = 250, category = "TRACTORSM"}
local cult = {{id = "c", role = "cultivator", roles = {cultivator = true}, x = 1, z = 0, neededHp = 120, name = "Cult"}}
local picked = P.pairFor("cultivator", 0, 0, cult, {unimog, fendt}, {})
check("parring: nærmeste lastbil springes over", picked ~= nil and picked.tractor.id or nil, "f")
-- Connect-markør til en parkering
local markers = {{name = "Start", id = 1}, {name = "Bredal", id = 4}, {name = "Connect Bredal", id = 9}, {name = "connect plov 1", id = 12}}
check("connect: Bredal", P.connectFor("Bredal", markers).id, 9)
check("connect: små bogstaver", P.connectFor("Plov 1", markers).id, 12)
check("connect: ingen", P.connectFor("Start", markers), nil)
check("connect: uden parkering", P.connectFor(nil, markers), nil)
-- parring: redskab nærmest marken, så traktor nærmest redskabet
local implements = {
{id = "plovFar", name = "Plov far", role = "plow", x = 500, z = 0, connectId = 20, parkId = 21},
{id = "plovNear", name = "Plov nær", role = "plow", x = 100, z = 0, neededHp = 180, connectId = 30, parkId = 31},
{id = "kult", name = "Kultivator", role = "cultivator", x = 0, z = 0, connectId = 40, parkId = 41},
}
local tractors = {
{id = "small", name = "Lille", x = 110, z = 0, hp = 120, parkId = 2},
{id = "big", name = "Stor", x = 300, z = 0, hp = 250, parkId = 3},
{id = "mid", name = "Mellem", x = 150, z = 0, hp = 190, parkId = 5},
}
local pair = P.pairFor("plow", 0, 0, implements, tractors, {})
check("par: nærmeste plov til marken", pair.implement.id, "plovNear")
check("par: nærmeste stærke traktor til ploven", pair.tractor.id, "mid")
local blockedPair = P.pairFor("plow", 0, 0, implements, tractors, {plovNear = true})
check("par: reserveret plov springes over", blockedPair.implement.id, "plovFar")
check("par: plov uden hk-krav tager nærmeste traktor", blockedPair.tractor.id, "big")
local none, why = P.pairFor("seeder", 0, 0, implements, tractors, {})
check("par: ingen såmaskine", none, nil); check("par: grund", why, "noPoolImplement")
local weak, weakWhy, weakArgs = P.pairFor("plow", 0, 0, {implements[2]}, {tractors[1]}, {})
check("par: for svag", weak, nil); check("par: grund tooWeak", weakWhy, "tooWeak"); check("par: hk i args", weakArgs[1], 180)
local noTractor, noTractorWhy = P.pairFor("plow", 0, 0, implements, {}, {})
check("par: ingen traktor", noTractor, nil); check("par: grund noPoolTractor", noTractorWhy, "noPoolTractor")
local rejected, rejectedWhy = P.pairFor("plow", 0, 0, implements, tractors, {}, function() return false end)
check("par: accept afviser alle", rejected, nil); check("par: grund", rejectedWhy, "noPoolImplement")
local multi = P.pairFor("fertilizer", 0, 0, {{id = "spreder", role = "fertilizer", roles = {fertilizer = true, liming = true}, x = 0, z = 0}}, tractors, {})
check("par: redskab med flere roller", multi.implement.id, "spreder")
-- reservationer og karantæne
P.reserve("F12", {"plovNear", "mid"})
check("reserveret: redskab", P.blocked(0).plovNear, true)
check("reserveret: traktor", P.blocked(0).mid, true)
P.release("F12")
check("frigivet", P.blocked(0).plovNear, nil)
P.quarantine("plovNear", 1000)
check("karantæne: aktiv", P.blocked(1000 + P.QUARANTINE_MS - 1).plovNear, true)
check("karantæne: udløbet", P.blocked(1000 + P.QUARANTINE_MS).plovNear, nil)
-- kø: længst ventende først, lige -> lavest mark-id, ikke-ventende bagerst i oprindelig rækkefølge
local infos = {{id = 5}, {id = 3}, {id = 9}, {id = 1}}
local ordered = P.queueOrder(infos, {[9] = 100, [3] = 50, [1] = 50})
check("kø: 1.", ordered[1].id, 1); check("kø: 2.", ordered[2].id, 3); check("kø: 3.", ordered[3].id, 9); check("kø: 4.", ordered[4].id, 5)
check("kø: rører ikke input", infos[1].id, 5)
-- på hjemtur: optaget indtil hjemme
local tractorObject = {}
check("hjemtur: ikke fra start", P.isReturning(tractorObject), false)
P.setReturning(tractorObject, true)
check("hjemtur: markeret", P.isReturning(tractorObject), true)
P.setReturning(tractorObject, false)
check("hjemtur: hjemme", P.isReturning(tractorObject), false)
-- review-rettelser
-- C1: hjemtur også når AD selv ville parkere (påfyldte sæt); aldrig ved manuel transport
check("C1: hjem trods adHandlesEnd", P.shouldReturnHome({adHandlesEnd = true}), true)
check("C1: ikke ved manuel", P.shouldReturnHome({manual = true}), false)
-- I1: kun maskiner uden egen arbejdsrolle kan trække et puljeredskab
check("I1: traktor uden rolle", P.canPull(nil), true)
check("I1: mejetærsker", P.canPull("harvester"), false)
check("I1: selvkørende sprøjte", P.canPull("fertilizer"), false)
-- I2: traktor uden AD-vejnet springes over; fejl uden fremdrift skyldes traktoren
local offNet = P.pairFor("plow", 0, 0, {implements[2]}, {{id = "far", x = 100, z = 0, offNetwork = true}, {id = "ok", x = 400, z = 0, hp = 300}}, {})
check("I2: traktor uden for vejnettet springes over", offNet.tractor.id, "ok")
check("I2: stoppedAway -> traktoren", P.failureBlames("stoppedAway"), "tractor")
check("I2: noAttachable -> redskabet", P.failureBlames("noAttachable"), "implement")
-- I3: efter koblingen — tom uden påfyldning = fejl, tom med påfyldning = fyld op, ellers kør
check("I3: ingen påfyldningsbehov", P.nextDrive(nil), "drive")
check("I3: fyldt", P.nextDrive({empty = false}), "drive")
check("I3: tom med påfyldning", P.nextDrive({empty = true, refillId = 7}), "load")
check("I3: tom uden påfyldning", P.nextDrive({empty = true}), "empty")
-- I4: puljen kun til hovedopgaver med ét sæt, og ikke når marken har egne faste maskiner til rollen
check("I4: almindelig", P.mayUsePool({count = 1}, false), true)
check("etape 2: tømmevogn må bruge puljen", P.mayUsePool({count = 1, helper = true}, false), true)
check("I4: multi-tool", P.mayUsePool({count = 2}, false), false)
check("I4: marken har faste", P.mayUsePool({count = 1}, true), false)
-- status til flådefanen
local function st(key, arg) return tostring(key) .. "|" .. tostring(arg) end
local function ist(s) return st(P.implementStatus(s)) end
check("redskab: uden parkering", ist({}), "noPark|nil")
check("redskab: uden Connect", ist({parkName = "Plov"}), "noConnect|Plov")
check("redskab: på traktor", ist({parkName = "Plov", hasConnect = true, attachedTo = "MT635"}), "attached|MT635")
check("redskab: karantæne", ist({parkName = "Plov", hasConnect = true, quarantineMin = 8}), "quarantine|8")
check("redskab: reserveret", ist({parkName = "Plov", hasConnect = true, reserved = true}), "reserved|nil")
check("redskab: parkeret", ist({parkName = "Plov", hasConnect = true}), "parked|Plov")
local function tst(s) return st(P.tractorStatus(s)) end
local base = {hasPark = true, enabled = true}
check("traktor: uden parkering", tst({enabled = true}), "noPark|nil")
check("traktor: spiller", tst({hasPark = true, enabled = true, controlled = true}), "player|nil")
check("traktor: hjemtur", tst({hasPark = true, enabled = true, returning = true}), "returning|nil")
check("traktor: opgave", tst({hasPark = true, enabled = true, fieldId = 52}), "job|52")
check("traktor: optaget", tst({hasPark = true, enabled = true, busy = true}), "busy|nil")
check("traktor: ikke i flåden", tst({hasPark = true}), "notInFleet|nil")
check("traktor: uden for vejnet", tst({hasPark = true, enabled = true, offNetwork = true}), "offNetwork|nil")
check("traktor: har andet redskab på", tst({hasPark = true, enabled = true, hitched = true}), "hitched|nil")
check("traktor: ledig", tst(base), "free|nil")
-- karantæne-rest i hele minutter (rundet op) og reservation
P.quarantine("q1", 0)
check("karantæne: minutter tilbage", P.quarantineMinutes("q1", 60000), 9)
check("karantæne: udløbet", P.quarantineMinutes("q1", P.QUARANTINE_MS), 0)
P.reserve("owner", {"r1"})
check("reserveret: ja", P.isReserved("r1"), true)
P.release("owner")
check("reserveret: nej", P.isReserved("r1"), false)
-- M3: ventende marker prøver igen i samme takt (så køens rækkefølge holder)
check("M3: næste takt", P.alignedRetry(61000, 30000), 90000)
check("M3: på grænsen -> næste", P.alignedRetry(60000, 30000), 90000)
check("M3: to marker samme takt", P.alignedRetry(62000, 30000) == P.alignedRetry(89000, 30000), true)
-- M4: for svag nævner redskabets navn
check("M4: navn i args", weakArgs[2], "Plov nær")
-- etape 2: puljevogn skal kunne bære høstens vare
check("bære: vare understøttet", P.canCarry({carries = {[3] = true}}, 3), true)
check("bære: vare ikke understøttet", P.canCarry({carries = {[3] = true}}, 7), false)
check("bære: ingen vare krævet", P.canCarry({carries = {}}, nil), true)
check("bære: ukendt last", P.canCarry({}, 3), false)
-- etape 3: alle puljevogne parret med hver sin nærmeste traktor (en traktor bruges kun én gang)
local wagons = {{id = "v1", role = "unloader", x = 0, z = 0}, {id = "v2", role = "unloader", x = 100, z = 0},
{id = "v3", role = "unloader", x = 200, z = 0}, {id = "plovX", role = "plow", x = 0, z = 0}}
local pairs3 = P.pairAll("unloader", wagons, {{id = "tA", x = 10, z = 0}, {id = "tB", x = 90, z = 0}}, {v2 = true})
check("par-alle: antal (v2 reserveret, 2 traktorer)", #pairs3, 2)
check("par-alle: v1 -> tA", pairs3[1].implement.id .. ">" .. pairs3[1].tractor.id, "v1>tA")
check("par-alle: v3 -> tB (tA er brugt)", pairs3[2].implement.id .. ">" .. pairs3[2].tractor.id, "v3>tB")
check("par-alle: ingen traktorer", #P.pairAll("unloader", wagons, {}, {}), 0)
-- flow-vogne: vogn der hører til et kørende flow vises sådan (og er ikke i puljen)
check("redskab: flowets vogn", ist({parkName = "P Cow Food vogn 1", hasConnect = true, flowName = "Cow Food"}), "flow|Cow Food")
check("redskab: flowets vogn koblet på", ist({parkName = "P Cow Food vogn 1", hasConnect = true, flowName = "Cow Food", attachedTo = "Cow Food 1"}), "attached|Cow Food 1")
-- pasform: mindste traktor med hk nok; afstand kun inden for ±15 %; over 2,5x behovet kun som nødløsning
-- (in-game 29/9: en meget stor traktor blev sendt til et lille job og kunne ikke komme rundt)
local impl120 = {id = "k", x = 0, z = 0, neededHp = 120}
local t150 = {id = "t150", x = 900, z = 0, hp = 150}
local t170 = {id = "t170", x = 300, z = 0, hp = 180}
local t500 = {id = "t500", x = 50, z = 0, hp = 500}
check("pasform: mindste der passer vinder over nærmere", P.bestFit({t500, t170, t150}, impl120, "cultivator").id, "t150")
local t160 = {id = "t160", x = 100, z = 0, hp = 160}
check("pasform: inden for 15 % vinder den nærmeste", P.bestFit({t150, t160}, impl120, "cultivator").id, "t160")
check("pasform: kun for stor -> nødløsning", P.bestFit({t500}, impl120, "cultivator").id, "t500")
check("pasform: for svag -> ingen", P.bestFit({{id = "t90", x = 0, z = 0, hp = 90}}, impl120, "cultivator"), nil)
check("pasform: redskab uden hk-data -> nærmeste", P.bestFit({t150, t500}, {id = "x", x = 0, z = 0}, "cultivator").id, "t500")
check("pasform: ukendt traktor-hk efter kendte", P.bestFit({{id = "u", x = 0, z = 0}, t170}, impl120, "cultivator").id, "t170")
check("pasform: lastbil tæller ikke", P.bestFit({{id = "lb", x = 0, z = 0, hp = 150, category = "TRUCKS"}, t500}, impl120, "cultivator").id, "t500")
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)