Files
fs25-adsmartpickup/tests/test_adCpBridge.lua
T

169 lines
11 KiB
Lua

-- Kør: luajit tests/test_adCpBridge.lua (fra repo-roden)
-- Kun getWorkWidth: variabel bredde (Unrealistic Pack) vinder over AI-markørernes grundbredde.
dofile("FS25_ADSmartPickup/adCpBridge.lua")
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 function withMarkers(width)
return {getAIMarkers = function() return 1, 2, 3, 4, width end}
end
-- W1: læssevogn med variabel bredde 20,4 + 20,4 = 40,8 m, AI-markører siger 2,4 m
local wagon = withMarkers(2.4)
wagon.getVariableWorkWidth = function(_, isLeft) return isLeft and 20.4 or -20.4, nil, true end
local tractor = {getAttachedImplements = function() return {{object = wagon}} end}
check("W1 variabel bredde", ADCpBridge.getWorkWidth(tractor), 40.8)
-- W2: ugyldig variabel bredde -> AI-markører
local plain = withMarkers(9.5)
plain.getVariableWorkWidth = function() return 0, nil, false end
check("W2 AI-markører", ADCpBridge.getWorkWidth(plain), 9.5)
-- W3: selvkørende slåmaskine uden redskaber, kun variabel bredde
local mower = {getVariableWorkWidth = function(_, isLeft) return isLeft and 20.4 or -20.4, nil, true end}
check("W3 selvkørende", ADCpBridge.getWorkWidth(mower), 40.8)
-- W4: Courseplays egen bredde (HUD'en) vinder — det er den marken køres med
local cpVehicle = {getVariableWorkWidth = function(_, isLeft) return isLeft and 20.4 or -0.4, nil, true end,
getCourseGeneratorSettings = function() return {workWidth = {getValue = function() return 40.8 end}} end}
check("W4 Courseplay-bredde", ADCpBridge.getWorkWidth(cpVehicle), 40.8)
-- W5: Courseplay-indstilling 0/ugyldig -> egen beregning
local zeroCp = {getVariableWorkWidth = function(_, isLeft) return isLeft and 5 or -5, nil, true end,
getCourseGeneratorSettings = function() return {workWidth = {getValue = function() return 0 end}} end}
check("W5 CP 0 -> egen beregning", ADCpBridge.getWorkWidth(zeroCp), 10)
-- WO: skårets sideforskydning på en river, målt fra nedlægningsområdet (venstre positiv), minus rivens
-- egen CP-forskydning. Noder er tal; localToLocal-mock giver nodens x i traktorens ramme.
local nodeX = {[11] = 2.0, [12] = 4.0, [21] = -1.0, [22] = 1.0}
function localToLocal(node) return nodeX[node] or 0, 0, 0 end
local function rake(dropIndex, runtime)
local areas = {
{start = 1, width = 2, height = 3, dropWindrowWorkAreaIndex = runtime and dropIndex or nil},
{start = 10, width = 11, height = 12},
{start = 20, width = 21, height = 22},
}
return {spec_windrower = {}, spec_workArea = {workAreas = areas}, configFileName = "rake.xml"}
end
local sideRake = rake(2, true)
local tractorWithRake = {rootNode = 100, getAttachedImplements = function() return {{object = sideRake}} end,
getCpSettings = function() return {toolOffsetX = {getValue = function() return 0.5 end}} end}
check("WO1 sideriver (runtime-felt)", ADCpBridge.getWindrowOffset(tractorWithRake), 2.5)
local centerRake = rake(3, true)
local tractorCenter = {rootNode = 100, getAttachedImplements = function() return {{object = centerRake}} end}
check("WO2 midterrive", ADCpBridge.getWindrowOffset(tractorCenter), 0)
-- WO3: runtime-felt mangler -> riverens XML (workArea(0) windrower#dropWindrowWorkAreaIndex = 2)
ADCpBridge.readDropIndicesFromXml = function(fileName) return fileName == "rake.xml" and {[1] = 2} or {} end
local xmlRake = rake(2, false)
local tractorXml = {rootNode = 100, getAttachedImplements = function() return {{object = xmlRake}} end}
check("WO3 fra XML", ADCpBridge.getWindrowOffset(tractorXml), 3)
check("WO4 ingen river -> nil", ADCpBridge.getWindrowOffset({rootNode = 100}), nil)
-- SR: sprøjte/spreder -> rolle ud fra fyldet
check("SR gødning", ADCpBridge.sprayRoleForFillType("FERTILIZER"), "fertilizer")
check("SR flydende", ADCpBridge.sprayRoleForFillType("LIQUIDFERTILIZER"), "fertilizer")
check("SR gylle", ADCpBridge.sprayRoleForFillType("LIQUIDMANURE"), "fertilizer")
check("SR møg", ADCpBridge.sprayRoleForFillType("MANURE"), "fertilizer")
check("SR digestat", ADCpBridge.sprayRoleForFillType("DIGESTATE"), "fertilizer")
check("SR kalk", ADCpBridge.sprayRoleForFillType("LIME"), "limer")
check("SR ukrudt", ADCpBridge.sprayRoleForFillType("HERBICIDE"), "weeder")
check("SR vand/ukendt", ADCpBridge.sprayRoleForFillType("WATER"), nil)
-- SR2: tom Bredal-spreder (tager gødning OG kalk) kan begge dele; fyldt med kalk er den primært kalkspreder
local bredal = {FERTILIZER = true, LIME = true}
local p1, r1, f1 = ADCpBridge.sprayRolesFor(nil, bredal)
check("SR2 tom spreder primært gødning", p1, "fertilizer")
check("SR2 tom spreder kan kalke", r1 and r1.limer, true)
check("SR2 tom = intet fyld", f1, nil)
local p2, r2, f2 = ADCpBridge.sprayRolesFor("LIME", bredal)
check("SR2 med kalk = kalkspreder", p2, "limer")
check("SR2 med kalk kan stadig gøde (efter tømning)", r2 and r2.fertilizer, true)
check("SR2 fyldets rolle", f2, "limer")
check("SR2 ukrudtssprøjte", (ADCpBridge.sprayRolesFor(nil, {HERBICIDE = true, WATER = true})), "weeder")
check("SR2 vandvogn er ingen sprøjte", (ADCpBridge.sprayRolesFor(nil, {WATER = true})), nil)
-- SR3: kun en lille rest må hældes ud (100.000 l gødning blev hældt ud in-game 26/9)
check("SR3 tom", ADCpBridge.isDumpable(0, 4000), true)
check("SR3 lille rest 300 af 4000", ADCpBridge.isDumpable(300, 4000), true)
check("SR3 halv tank 2000 af 4000", ADCpBridge.isDumpable(2000, 4000), false)
check("SR3 100000 l aldrig", ADCpBridge.isDumpable(100000, 1000000), false)
check("SR3 over 2000 l aldrig", ADCpBridge.isDumpable(2500, 100000), false)
-- VN: vinmark — i gangen for alt undtagen høsteren; almindelige marker røres ikke
check("VN sprøjte på druer = venstre", ADCpBridge.vineOffsetFor("GRAPEB", "fertilizer"), -1)
check("VN harve på druer = venstre", ADCpBridge.vineOffsetFor("grape", "cultivator"), -1)
check("VN høster på druer = på vinen", ADCpBridge.vineOffsetFor("GRAPEB", "harvester"), 0)
check("VN hvede røres ikke", ADCpBridge.vineOffsetFor("WHEAT", "fertilizer"), nil)
check("VN ukendt afgrøde", ADCpBridge.vineOffsetFor(nil, "weeder"), nil)
check("VN sprøjte springer 1 række over (begge sider)", ADCpBridge.vineSkipFor("GRAPEB", "weeder"), 1)
check("VN gødning springer 1 over", ADCpBridge.vineSkipFor("GRAPEB", "fertilizer"), 1)
check("VN harve springer ingen over", ADCpBridge.vineSkipFor("GRAPEB", "cultivator"), 0)
check("VN høster springer ingen over", ADCpBridge.vineSkipFor("GRAPEB", "harvester"), 0)
check("VN hvede røres ikke", ADCpBridge.vineSkipFor("WHEAT", "weeder"), nil)
-- HF: høsterens afgrøder fra skærebordet (liste eller opslag); finsnitter tager ingen
local list = ADCpBridge.harvestFruitSet({fruitTypes = {3, 5}})
check("HF liste", list[3] and list[5], true)
local lookup = ADCpBridge.harvestFruitSet({fruitTypes = {[3] = true}})
check("HF opslag", lookup[3], true)
local forage = ADCpBridge.harvestFruitSet({fruitTypes = {3}, fruitTypeConverters = {[3] = {}}})
check("HF finsnitter tager intet", next(forage), nil)
check("HF fruitTypeIndices", ADCpBridge.harvestFruitSet({fruitTypeIndices = {7}})[7], true)
-- PL: plantbar i perioden
local fruitPlant = {growthDataSeasonal = {periods = {[3] = {plantingAllowed = true}, [4] = {plantingAllowed = false}}}}
check("PL tilladt", ADCpBridge.isPlantableIn(fruitPlant, 3), true)
check("PL ikke nu", ADCpBridge.isPlantableIn(fruitPlant, 4), false)
check("PL ukendt data = tilladt", ADCpBridge.isPlantableIn({}, 4), true)
-- CR: kursus-genbrug — start på maskinens eget kursus uden at CP beregner et nyt (opts.reuse)
do
local generated, started = 0, 0
AIJobType = {FIELDWORK_CP = 1}
function getWorldTranslation() return 0, 0, 0 end
local job = {cpJobParameters = {}}
function job.applyCurrentState() end
function job.setValues() end
function job.validate() return true end
function job.registerFieldBoundaryDetectionCallback() end
function job.detectFieldBoundary() return true, false, "" end
function job.onClickGenerateFieldWorkCourse(_, callback) generated = generated + 1; callback(true) end
g_currentMission = {aiJobTypeManager = {createJob = function() return job end},
aiSystem = {startJob = function() started = started + 1 end}}
local course = {}
local vehicle = {rootNode = 1, getOwnerFarmId = function() return 1 end, getFieldWorkCourse = function() return course end}
local reason = "?"
ADCpBridge.start(vehicle, 0, 0, function(ok, r) reason = ok and (r or "generated") or "fail" end, {reuse = true})
check("CR1 genbrug: ingen beregning", generated, 0)
check("CR2 genbrug: CP startet", started, 1)
check("CR3 genbrug: reason", reason, "reused")
-- ingen kursus på maskinen -> beregnes alligevel
vehicle.getFieldWorkCourse = function() return nil end
ADCpBridge.start(vehicle, 0, 0, function(ok, r) reason = ok and (r or "generated") or "fail" end, {reuse = true})
check("CR4 intet kursus -> beregnes", generated, 1)
check("CR5 reason ny", reason, "generated")
-- uden reuse: beregnes som før
vehicle.getFieldWorkCourse = function() return course end
ADCpBridge.start(vehicle, 0, 0, function(ok, r) reason = ok and (r or "generated") or "fail" end, {})
check("CR6 uden reuse -> beregnes", generated, 2)
AIJobType, g_currentMission = nil, nil
end
-- forager: 2 runder og start på forageren (så der ikke køres ind i træer o.l. i hjørnerne)
local recorded = {}
local function setting(name) return {setValue = function(_, v) recorded[name] = v end} end
local headlandVehicle = {getCourseGeneratorSettings = function() return {numberOfHeadlands = setting("headlands"), startOnHeadland = setting("startOnHeadland")} end}
check("forager: sat", ADCpBridge.setHeadlands(headlandVehicle, 2), true)
check("forager: 2 runder", recorded.headlands, 2)
check("forager: start på forageren", recorded.startOnHeadland, true)
ADCpBridge.setHeadlands(headlandVehicle, 0)
check("forager: ingen -> ikke start på forageren", recorded.startOnHeadland, false)
check("forager: køretøj uden CP", ADCpBridge.setHeadlands({}, 2), false)
check("forager: standard er 2", ADCpBridge.HEADLANDS, 2)
-- genbrugt kursus uden forager beregnes på ny
check("forager i kursus: 2 runder", ADCpBridge.courseHasHeadlands({getNumberOfHeadlands = function() return 2 end}), true)
check("forager i kursus: ingen", ADCpBridge.courseHasHeadlands({getNumberOfHeadlands = function() return 0 end}), false)
check("forager i kursus: ukendt -> antag ja", ADCpBridge.courseHasHeadlands({}), true)
check("forager i kursus: intet kursus", ADCpBridge.courseHasHeadlands(nil), false)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)