Files
fs25-adsmartpickup/tests/test_adFieldJobs.lua
T

182 lines
14 KiB
Lua

-- Kør: luajit tests/test_adFieldJobs.lua (fra repo-roden)
dofile("FS25_ADSmartPickup/adFieldModel.lua")
dofile("FS25_ADSmartPickup/adFieldJobs.lua")
local J = ADFieldJobs
local M = ADFieldModel
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
local info = {id = 109, markerId = 5, mowable = true, readyRatio = 1}
-- J1: klar auto-mark med markør -> start; uden markør -> vent
local auto = M.onReadiness(M.newField(109), 1); auto.plan.mode = "auto"
check("J1 start", J.decide(auto, info, {}, 0).action, "start")
check("J1 uden markør", J.decide(auto, {id = 109, mowable = true}, {}, 0).action, "wait")
-- J2: arbejdende trin uden sæt -> send rolle; alle sæt færdige -> næste trin
local mowing = M.start(auto)
local wanted = J.decide(mowing, info, {}, 0)
check("J2 send slåmaskine", wanted.action, "dispatch"); check("J2 rolle", wanted.role, "mower")
check("J2 sæt i gang -> ingenting", J.decide(mowing, info, {{phase = "working"}}, 0).action, "none")
local mowedInfo = {id = 109, markerId = 5, mowable = true, readyRatio = 0}
check("J2 færdig -> videre", J.decide(mowing, mowedInfo, {{phase = "finished"}}, 0).action, "advance")
-- J3: sæt frigivet (spilleren tog det) tæller ikke som færdigt
check("J3 frigivet -> send nyt", J.decide(mowing, info, {{phase = "released"}}, 0).action, "dispatch")
-- J4: slåning færdig men marken stadig klar -> ikke videre (afbrudt)
check("J4 afbrudt slåning", J.decide(mowing, {id = 109, markerId = 5, mowable = true, readyRatio = 0.8}, {{phase = "finished"}}, 0).action, "dispatch")
-- J5: opsamling efter genindlæsning uden sæt -> send læssevogn
local collecting = M.advance(mowing)
check("J5 genoptag opsamling", J.decide(collecting, info, {}, 0).role, "collector")
check("J5 to vogne maks", J.decide(collecting, info, {{phase = "working"}, {phase = "driving"}}, 0).action, "none")
-- J6: Courseplay efterlader et hjørne -> efter 2 færdige slå-ture går marken videre alligevel
local standing = {id = 109, markerId = 5, mowable = true, readyRatio = 0.8}
check("J6 én tur -> slå igen", J.decide(mowing, standing, {{phase = "finished"}}, 0).action, "dispatch")
check("J6 to ture -> videre", J.decide(mowing, standing, {{phase = "finished"}, {phase = "finished"}}, 0).action, "advance")
-- J7: slået mark uden sæt (fx sluppet undervejs) -> videre til opsamling, ikke en ny slå-tur
check("J7 slået uden sæt -> videre", J.decide(mowing, {id = 109, markerId = 5, mowable = true, readyRatio = 0.1}, {}, 0).action, "advance")
check("J7 stående uden sæt -> slå", J.decide(mowing, info, {}, 0).action, "dispatch")
check("J7 slået men sæt i gang -> vent", J.decide(mowing, {id = 109, markerId = 5, mowable = true, readyRatio = 0.1}, {{phase = "working"}}, 0).action, "none")
-- J8: høst — høster først (hovedrolle), aflæsningsvogne kun mens høsteren arbejder
local harvestInfo = {id = 50, markerId = 7, kind = "harvest", readyRatio = 1, fruitIndex = 3}
local harvesting = M.start(M.onReadiness(M.newField(50), 1), "harvest", {})
local d = J.decide(harvesting, harvestInfo, {}, 0)
check("J8 send høster", d.role, "harvester"); check("J8 ikke hjælper", d.helper, false)
local withHarvester = {{phase = "working", stage = "harvesting", helper = false}}
local dHelper = J.decide(harvesting, harvestInfo, withHarvester, 0)
check("J8 så aflæsningsvogn", dHelper.role, "unloader"); check("J8 hjælper", dHelper.helper, true)
check("J8 vogn på plads -> intet", J.decide(harvesting, harvestInfo, {withHarvester[1], {phase = "working", stage = "harvesting", helper = true}}, 0).action, "none")
-- manuel transport: høsteren venter på spilleren -> ingen høster mere og endnu ingen tømmevogn
local awaiting = {{phase = "awaitingPlayer", stage = "harvesting", helper = false}}
check("J8b venter på spilleren -> intet (ingen ny høster, ingen tømmevogn)", J.decide(harvesting, harvestInfo, awaiting, 0).action, "none")
-- høsteren færdig, afgrøden væk (marken er nu bar) -> videre, selv om vognen stadig kører
local afterInfo = {id = 50, markerId = 7, kind = "bare", readyRatio = 0}
check("J8 høst færdig -> videre", J.decide(harvesting, afterInfo, {{phase = "finished", stage = "harvesting"}, {phase = "working", stage = "harvesting", helper = true}}, 0).action, "advance")
-- sæt fra et tidligere trin (vogn på vej hjem) tæller ikke på det nye trin
local cultivating = M.advance(harvesting, {})
check("J8 gammel vogn tæller ikke", J.decide(cultivating, afterInfo, {{phase = "working", stage = "harvesting", helper = true}}, 0).role, "cultivator")
-- J9: multi-tool — hele holdet sendes samlet; mens nogen kører, sendes ingen nye hovedsæt
local multiMow = M.with(mowing, {plan = {rigs = 3}})
local dMulti = J.decide(multiMow, info, {}, 0)
check("J9 tre slåmaskiner", dMulti.count, 3)
check("J9 én kører stadig -> ingen nye", J.decide(multiMow, info, {{phase = "working"}, {phase = "finished"}}, 0).action, "none")
-- J10: pleje under vækst — Auto starter, Manuel viser behovet
local growingInfo = {id = 60, markerId = 8, kind = "harvest", growing = true, fert = 0, fertMax = 2, lime = 2, weed = 0, readyRatio = 0.2}
local autoField = M.with(M.newField(60), {plan = {mode = "auto"}})
local care = J.decide(autoField, growingInfo, {}, 0)
check("J10 auto -> pleje", care.action, "care"); check("J10 gødning", care.stage, "fertilizing")
local manualCare = J.decide(M.newField(60), growingInfo, {}, 0)
check("J10 manuel -> intet, men behov vist", manualCare.action, "none"); check("J10 behov", manualCare.care, "fertilizing")
check("J10 Start nu -> pleje", J.decide(M.with(M.newField(60), {startRequested = true}), growingInfo, {}, 0).action, "care")
check("J10 uden markør -> vent", J.decide(autoField, {id = 60, kind = "harvest", growing = true, fert = 0, fertMax = 2}, {}, 0).action, "wait")
-- J11: regn — vejrfølsomme trin sendes ikke ud (kørende sæt fortsætter); klargøring/pleje kører videre
local rain = {raining = true}
local dRain = J.decide(mowing, info, {}, 0, rain)
check("J11 slåning venter i regn", dRain.action, "wait"); check("J11 grund", dRain.reason, "rain")
check("J11 kørende slåmaskine fortsætter", J.decide(mowing, info, {{phase = "working"}}, 0, rain).action, "none")
check("J11 høst venter", J.decide(harvesting, harvestInfo, {}, 0, rain).reason, "rain")
check("J11 kultivering kører i regn", J.decide(cultivating, afterInfo, {}, 0, rain).role, "cultivator")
check("J11 start af høst venter", J.decide(M.with(M.onReadiness(M.newField(51), 1), {startRequested = true, kind = "harvest"}), harvestInfo, {}, 0, rain).reason, "rain")
local silageCollect = M.advance(mowing)
check("J11 ensilage-opsamling kører i regn", J.decide(silageCollect, info, {}, 0, rain).action, "dispatch")
local hayCollect = M.with(silageCollect, {plan = {product = "hay"}})
check("J11 hø-opsamling venter", J.decide(hayCollect, info, {}, 0, rain).reason, "rain")
check("J11 tørvejr", J.decide(mowing, info, {}, 0, {raining = false}).action, "dispatch")
-- J12: bar mark med mål-afgrøde starter selv når målet kan sås; ellers venter den
local bareInfo = {id = 90, markerId = 9, kind = "bare", readyRatio = 0, needs = {}}
local bareTarget = M.with(M.newField(90), {plan = {targetFruit = "WHEAT", mode = "auto"}})
local canSow = {plantable = function(name) return name == "WHEAT" end}
check("J12 bar + såtid -> start", J.decide(bareTarget, bareInfo, {}, 0, canSow).action, "start")
check("J12 bar + ikke såtid -> intet", J.decide(bareTarget, bareInfo, {}, 0, {plantable = function() return false end}).action, "none")
check("J12 bar uden markør -> vent", J.decide(bareTarget, {id = 90, kind = "bare"}, {}, 0, canSow).action, "wait")
check("J12 voksende mark med mål -> lad den vokse", J.decide(bareTarget, {id = 90, markerId = 9, kind = "harvest", growing = true, readyRatio = 0.3}, {}, 0, canSow).action, "none")
-- J13: afbrudt slåning efter genindlæsning (in-game 27/9 F90): genvækst i mellemhøjde -> vent; hjørne efter en tur -> slå straks
local regrowing = {id = 90, markerId = 9, mowable = true, readyRatio = 0.5, immatureRatio = 0.5}
local dRegrow = J.decide(mowing, regrowing, {}, 0)
check("J13 genvækst -> vent", dRegrow.action, "wait"); check("J13 grund", dRegrow.reason, "regrowing")
check("J13 genvækst men tur færdig -> slå hjørnet", J.decide(mowing, regrowing, {{phase = "finished"}}, 0).action, "dispatch")
check("J13 halvt slået uden genvækst -> slå resten", J.decide(mowing, {id = 90, markerId = 9, mowable = true, readyRatio = 0.6, immatureRatio = 0}, {}, 0).action, "dispatch")
-- J14: kultivering på en mark med uhøstede kartofler (in-game 27/9 F16) -> tilbage til klar; rest efter høst -> ikke
local cultivatingField = M.with(auto, {stage = "cultivating", kind = "harvest"})
check("J14 uhøstet -> spol tilbage", J.decide(cultivatingField, {id = 16, markerId = 9, kind = "harvest", phase = "ready", readyRatio = 1}, {}, 0).action, "rewind")
check("J14 høstrest 30 % -> kultiver", J.decide(cultivatingField, {id = 16, markerId = 9, kind = "harvest", phase = "ready", readyRatio = 0.3}, {}, 0).action ~= "rewind", true)
check("J14 stub -> kultiver", J.decide(cultivatingField, {id = 16, markerId = 9, kind = "bare", phase = "cut", readyRatio = 0}, {}, 0).action ~= "rewind", true)
-- resumeField: efter genindlæsning stopper spillet alle arbejdere; en CP-maskine der står PÅ en mark hvis
-- aktuelle trin passer til maskinens rolle, meldes ind på den mark igen (in-game 27/9)
do
local square = {{x = 0, z = 0}, {x = 100, z = 0}, {x = 100, z = 100}, {x = 0, z = 100}}
local fields = {
{id = 90, stage = "collecting", verts = square},
{id = 111, stage = "harvesting", verts = {{x = 200, z = 0}, {x = 300, z = 0}, {x = 300, z = 100}, {x = 200, z = 100}}},
}
check("RF høster på F111", ADFieldJobs.resumeField(250, 50, "harvester", fields), 111)
check("RF læssevogn på F90", ADFieldJobs.resumeField(50, 50, "collector", fields), 90)
check("RF forkert rolle til trinnet -> nil", ADFieldJobs.resumeField(250, 50, "collector", fields), nil)
check("RF uden for alle marker -> nil", ADFieldJobs.resumeField(150, 50, "harvester", fields), nil)
check("RF mark uden omrids -> nil", ADFieldJobs.resumeField(50, 50, "collector", {{id = 1, stage = "collecting", verts = {}}}), nil)
check("RF på kanten tæller som indenfor", ADFieldJobs.resumeField(0.5, 50, "collector", fields), 90)
end
-- startAt: hvor Courseplay skal starte i kurset (CP's standard er "first" = forfra, også på en halvt høstet mark;
-- in-game 27/9: mejetærskeren startede F111 forfra)
check("SA eget kursus med husket waypoint -> last", ADFieldJobs.startAtFor({reuse = true, remembered = true, stage = "harvesting", standingRatio = 0.4}), "last")
check("SA halvt høstet -> nearest", ADFieldJobs.startAtFor({stage = "harvesting", standingRatio = 0.4}), "nearest")
check("SA halvt slået -> nearest", ADFieldJobs.startAtFor({stage = "mowing", standingRatio = 0.5}), "nearest")
check("SA urørt mark -> first", ADFieldJobs.startAtFor({stage = "harvesting", standingRatio = 1}), "first")
check("SA næsten urørt (97 %) -> first", ADFieldJobs.startAtFor({stage = "harvesting", standingRatio = 0.97}), "first")
check("SA ukendt fremdrift -> first", ADFieldJobs.startAtFor({stage = "harvesting"}), "first")
check("SA klargøring (ingen afgrøde at måle) -> first", ADFieldJobs.startAtFor({stage = "cultivating", standingRatio = 0.3}), "first")
check("SA husket waypoint uden eget kursus -> ikke last", ADFieldJobs.startAtFor({reuse = false, remembered = true, stage = "cultivating"}), "first")
-- shouldResume: kun maskiner der stadig er midt i jobbet genstartes (in-game 27/9: to ROPA'er med et husket
-- waypoint fra et gammelt job kørte ud ad vejene mod det gamle kursus)
check("SR står på en mark i gang med sit trin -> ja", ADFieldJobs.shouldResume({fieldId = 111, distance = 400}), true)
check("SR lige ved sit huskede waypoint -> ja", ADFieldJobs.shouldResume({distance = 12}), true)
check("SR langt fra waypointet og ingen mark -> nej", ADFieldJobs.shouldResume({distance = 850}), false)
check("SR ukendt afstand og ingen mark -> nej", ADFieldJobs.shouldResume({}), false)
-- mayDispatch: markarbejdet sender højst én maskine ud pr. DISPATCH_GAP_MS på tværs af alle marker
-- (in-game 27/9: 6 maskiner kørte fra parkeringen i samme sekund efter Start alle)
check("MD første udsendelse", ADFieldJobs.mayDispatch(5000, nil), true)
check("MD for tæt på forrige", ADFieldJobs.mayDispatch(5000 + ADFieldJobs.DISPATCH_GAP_MS - 1, 5000), false)
check("MD efter mellemrummet", ADFieldJobs.mayDispatch(5000 + ADFieldJobs.DISPATCH_GAP_MS, 5000), true)
-- halvt høstet mark (in-game 27/9 F111): høsten er ikke færdig før næsten intet står; en mark i klargøring med
-- stående afgrøde spoles tilbage
do
local halfInfo = {id = 111, markerId = 5, kind = "harvest", phase = "ready", readyRatio = 0.45, standingRatio = 0.45, fruitIndex = 1}
check("HH halvt høstet uden høster -> send høster (ikke videre)", J.decide(harvesting, halfInfo, {}, 0).action, "dispatch")
local doneInfo = {id = 111, markerId = 5, kind = "harvest", phase = "ready", readyRatio = 0.02, standingRatio = 0.02, fruitIndex = 1}
check("HH næsten intet står -> videre", J.decide(harvesting, doneInfo, {}, 0).action, "advance")
local cultivating = M.with(harvesting, {stage = "cultivating"})
check("HH klargøring med halv mark stående -> spol tilbage", J.decide(cultivating, halfInfo, {}, 0).action, "rewind")
end
-- startTimedOut: CP må beregne kursus i op til 5 min (in-game 27/9 F90: 140 ha tog over 60 s, moden opgav midt i)
check("ST start uden beregning > 60 s -> opgiv", ADFieldJobs.startTimedOut(61000, false), true)
check("ST beregner stadig efter 90 s -> vent", ADFieldJobs.startTimedOut(90000, true), false)
check("ST beregner over 5 min -> opgiv", ADFieldJobs.startTimedOut(301000, true), true)
check("ST under 60 s -> vent", ADFieldJobs.startTimedOut(30000, false), false)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)