feat: controller — bygninger -> markører (resolveMarkers), migration af markør-runs, noMarker-validering, flow-rækker
This commit is contained in:
@@ -428,6 +428,9 @@ function ADOutbound.choosePickup(adEnv, vehicle)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
trips[vehicle] = nil
|
trips[vehicle] = nil
|
||||||
|
if ADRunsController.resolveMarkers ~= nil then
|
||||||
|
pcall(ADRunsController.resolveMarkers, adEnv, run)
|
||||||
|
end
|
||||||
local input, sourcesById = ADOutbound.buildPlanInput(adEnv, run, vehicle)
|
local input, sourcesById = ADOutbound.buildPlanInput(adEnv, run, vehicle)
|
||||||
local trip, reasons = ADOutboundPlanner.plan(input)
|
local trip, reasons = ADOutboundPlanner.plan(input)
|
||||||
local runStatus = getStatus(run)
|
local runStatus = getStatus(run)
|
||||||
|
|||||||
@@ -100,7 +100,19 @@ function ADRunsController.updateRun(runId, changes)
|
|||||||
local run = ADRuns.getRun(ADRunsController.store, runId)
|
local run = ADRuns.getRun(ADRunsController.store, runId)
|
||||||
local parts = {}
|
local parts = {}
|
||||||
for key, value in pairs(changes) do
|
for key, value in pairs(changes) do
|
||||||
table.insert(parts, string.format("%s=%s", tostring(key), type(value) == "table" and table.concat(value, " ") or tostring(value)))
|
local text
|
||||||
|
if type(value) == "table" then
|
||||||
|
if key == "products" then
|
||||||
|
text = ADRuns.serializeProducts(value)
|
||||||
|
else
|
||||||
|
local items = {}
|
||||||
|
for _, item in ipairs(value) do table.insert(items, tostring(item)) end
|
||||||
|
text = table.concat(items, " ")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
text = tostring(value)
|
||||||
|
end
|
||||||
|
table.insert(parts, string.format("%s=%s", tostring(key), text))
|
||||||
end
|
end
|
||||||
table.sort(parts)
|
table.sort(parts)
|
||||||
Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': %s", run ~= nil and tostring(run.name) or tostring(runId), table.concat(parts, ", "))
|
Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': %s", run ~= nil and tostring(run.name) or tostring(runId), table.concat(parts, ", "))
|
||||||
@@ -264,6 +276,132 @@ function ADRunsController.getVehicleLabel(adEnv, vehicle)
|
|||||||
return tostring(vehicle:getName())
|
return tostring(vehicle:getName())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- ---- bygninger (flow-tavlen): bygnings-id'er -> markører ----
|
||||||
|
|
||||||
|
local function listEquals(a, b)
|
||||||
|
if #a ~= #b then return false end
|
||||||
|
for index = 1, #a do
|
||||||
|
if a[index] ~= b[index] then return false end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Udleder run'ets markørlister fra de valgte bygninger: udkørsel -> sourceWayPointIds (bygningens
|
||||||
|
-- læssemarkør), forsyning -> targetWayPointIds (aflæsningsmarkør). Markører der ikke hører til
|
||||||
|
-- nogen bygning ("rå", fra før flow-tavlen) bevares; markører der hører til en FRAVALGT bygning
|
||||||
|
-- fjernes. Returnerer {missing = {bygningsnavne uden markør}}. Store opdateres kun ved ændring.
|
||||||
|
function ADRunsController.resolveMarkers(adEnv, run)
|
||||||
|
local missing = {}
|
||||||
|
if ADBuildings == nil or run == nil then
|
||||||
|
return {missing = missing}
|
||||||
|
end
|
||||||
|
local farmId = g_currentMission:getFarmId()
|
||||||
|
local role = run.kind == "outbound" and "load" or "unload"
|
||||||
|
local buildingIds = run.kind == "outbound" and run.sourceBuildingIds or run.targetBuildingIds
|
||||||
|
local existing = run.kind == "outbound" and run.sourceWayPointIds or ADRunsController.getRunTargets(run)
|
||||||
|
local resolved, seen = {}, {}
|
||||||
|
for _, buildingId in ipairs(buildingIds or {}) do
|
||||||
|
local building = ADBuildings.find(adEnv, farmId, buildingId)
|
||||||
|
local marker = building ~= nil and (role == "load" and building.loadMarker or building.unloadMarker) or nil
|
||||||
|
if marker ~= nil then
|
||||||
|
if not seen[marker.id] then
|
||||||
|
seen[marker.id] = true
|
||||||
|
table.insert(resolved, marker.id)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(missing, building ~= nil and building.name or (tostring(buildingId) .. " (mangler)"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, wayPointId in ipairs(existing or {}) do
|
||||||
|
if not seen[wayPointId] and ADBuildings.byMarker(adEnv, farmId, wayPointId, role) == nil then
|
||||||
|
seen[wayPointId] = true
|
||||||
|
table.insert(resolved, wayPointId)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not listEquals(resolved, existing or {}) then
|
||||||
|
local changes = run.kind == "outbound" and {sourceWayPointIds = resolved} or {targetWayPointIds = resolved}
|
||||||
|
ADRunsController.store = ADRuns.updateRun(ADRunsController.store, run.id, changes)
|
||||||
|
local updated = ADRuns.getRun(ADRunsController.store, run.id)
|
||||||
|
if updated ~= nil then
|
||||||
|
run.sourceWayPointIds, run.targetWayPointIds, run.targetWayPointId = updated.sourceWayPointIds, updated.targetWayPointIds, updated.targetWayPointId
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return {missing = missing}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ved indlæsning: runs fra før flow-tavlen har kun markører — oversæt dem til bygninger, hvor
|
||||||
|
-- markøren er en bygnings læsse-/aflæsningsmarkør. Rå markører uden bygning beholdes.
|
||||||
|
function ADRunsController.migrateBuildings(adEnv)
|
||||||
|
if ADBuildings == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local farmId = g_currentMission:getFarmId()
|
||||||
|
for _, run in ipairs(ADRunsController.store.runs) do
|
||||||
|
local role = run.kind == "outbound" and "load" or "unload"
|
||||||
|
local ids = copyList(run.kind == "outbound" and run.sourceBuildingIds or run.targetBuildingIds)
|
||||||
|
local known = {}
|
||||||
|
for _, id in ipairs(ids) do known[id] = true end
|
||||||
|
local added = {}
|
||||||
|
for _, wayPointId in ipairs(run.kind == "outbound" and run.sourceWayPointIds or ADRunsController.getRunTargets(run)) do
|
||||||
|
local building = ADBuildings.byMarker(adEnv, farmId, wayPointId, role)
|
||||||
|
if building ~= nil and not known[building.id] then
|
||||||
|
known[building.id] = true
|
||||||
|
table.insert(ids, building.id)
|
||||||
|
table.insert(added, building.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #added > 0 then
|
||||||
|
local changes = run.kind == "outbound" and {sourceBuildingIds = ids} or {targetBuildingIds = ids}
|
||||||
|
ADRunsController.store = ADRuns.updateRun(ADRunsController.store, run.id, changes)
|
||||||
|
Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': markører oversat til bygninger: %s", tostring(run.name), table.concat(added, ", "))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Data til én række i flow-tavlen (GUI'et formaterer teksten).
|
||||||
|
function ADRunsController.getFlowRow(adEnv, run)
|
||||||
|
local farmId = g_currentMission:getFarmId()
|
||||||
|
local row = {productNames = {}, productAuto = false, fromNames = {}, toNames = {}, fromAllSilos = run.kind ~= "outbound", missing = {}, policies = {}, vehicleNames = {}, collectRound = run.collectRound == true, sellAtPercent = run.sellAtPercent, storeAbovePercent = run.storeAbovePercent, loops = run.loops, kind = run.kind}
|
||||||
|
local ids = run.kind == "outbound" and run.sourceBuildingIds or run.targetBuildingIds
|
||||||
|
local names = run.kind == "outbound" and row.fromNames or row.toNames
|
||||||
|
for _, buildingId in ipairs(ids or {}) do
|
||||||
|
local building = ADBuildings ~= nil and ADBuildings.find(adEnv, farmId, buildingId) or nil
|
||||||
|
local marker = building ~= nil and (run.kind == "outbound" and building.loadMarker or building.unloadMarker) or nil
|
||||||
|
local name = building ~= nil and building.name or (tostring(buildingId) .. " (mangler)")
|
||||||
|
table.insert(names, name)
|
||||||
|
if marker == nil then table.insert(row.missing, name) end
|
||||||
|
end
|
||||||
|
-- rå markører (uden bygning) vises med markørnavn
|
||||||
|
local raw = run.kind == "outbound" and run.sourceWayPointIds or ADRunsController.getRunTargets(run)
|
||||||
|
for _, wayPointId in ipairs(raw or {}) do
|
||||||
|
if ADBuildings == nil or ADBuildings.byMarker(adEnv, farmId, wayPointId, run.kind == "outbound" and "load" or "unload") == nil then
|
||||||
|
local marker = adEnv.ADGraphManager.getMapMarkerByWayPointId ~= nil and adEnv.ADGraphManager:getMapMarkerByWayPointId(wayPointId) or nil
|
||||||
|
table.insert(names, marker ~= nil and ("markør '" .. tostring(marker.name) .. "'") or ("markør " .. tostring(wayPointId)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if run.kind == "outbound" then
|
||||||
|
for _, product in ipairs(run.products or {}) do
|
||||||
|
table.insert(row.productNames, product.fillType)
|
||||||
|
table.insert(row.policies, product.policy)
|
||||||
|
end
|
||||||
|
local status = ADRunsController.getOutboundStatus(adEnv, run)
|
||||||
|
row.reason, row.warning = status.reasons[1], status.warning
|
||||||
|
else
|
||||||
|
row.productAuto = run.ingredientMode ~= "manual"
|
||||||
|
if not row.productAuto then
|
||||||
|
for _, name in ipairs(run.ingredients or {}) do table.insert(row.productNames, name) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local vehiclesById = getFarmVehiclesById(adEnv)
|
||||||
|
for _, vehicleId in ipairs(run.vehicleIds) do
|
||||||
|
local vehicle = vehiclesById[vehicleId]
|
||||||
|
table.insert(row.vehicleNames, vehicle ~= nil and tostring(vehicle:getName()) or "?")
|
||||||
|
end
|
||||||
|
local status = ADRunsController.getRunStatus(adEnv, run)
|
||||||
|
row.running, row.total, row.isRunning = status.running, status.total, status.isRunning
|
||||||
|
return row
|
||||||
|
end
|
||||||
|
|
||||||
-- ---- validering ----
|
-- ---- validering ----
|
||||||
|
|
||||||
-- Liter-kapacitet for vognen; nil uden vogn. Universal Autoload opgiver ikke liter men ANTAL paller
|
-- Liter-kapacitet for vognen; nil uden vogn. Universal Autoload opgiver ikke liter men ANTAL paller
|
||||||
@@ -406,6 +544,11 @@ local function getCargoTarget(adEnv, run, vehicle)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function validateOutboundVehicle(adEnv, run, vehicle, result)
|
local function validateOutboundVehicle(adEnv, run, vehicle, result)
|
||||||
|
local resolved = ADRunsController.resolveMarkers(adEnv, run)
|
||||||
|
if resolved.missing[1] ~= nil then
|
||||||
|
result.reason, result.missingBuilding = "noMarker", resolved.missing[1]
|
||||||
|
return result
|
||||||
|
end
|
||||||
if #getRunSources(adEnv, run, ADSmartPickup.getFarmId(vehicle)) == 0 then
|
if #getRunSources(adEnv, run, ADSmartPickup.getFarmId(vehicle)) == 0 then
|
||||||
result.reason = "noSource"
|
result.reason = "noSource"
|
||||||
return result
|
return result
|
||||||
@@ -470,6 +613,11 @@ function ADRunsController.validateVehicle(adEnv, run, vehicle)
|
|||||||
if run.kind == "outbound" then
|
if run.kind == "outbound" then
|
||||||
return validateOutboundVehicle(adEnv, run, vehicle, result)
|
return validateOutboundVehicle(adEnv, run, vehicle, result)
|
||||||
end
|
end
|
||||||
|
local resolvedIn = ADRunsController.resolveMarkers(adEnv, run)
|
||||||
|
if resolvedIn.missing[1] ~= nil then
|
||||||
|
result.reason, result.missingBuilding = "noMarker", resolvedIn.missing[1]
|
||||||
|
return result
|
||||||
|
end
|
||||||
local hasTarget = false
|
local hasTarget = false
|
||||||
for _, wayPointId in ipairs(ADRunsController.getRunTargets(run)) do
|
for _, wayPointId in ipairs(ADRunsController.getRunTargets(run)) do
|
||||||
if adEnv.ADGraphManager:getMapMarkerByWayPointId(wayPointId) ~= nil then
|
if adEnv.ADGraphManager:getMapMarkerByWayPointId(wayPointId) ~= nil then
|
||||||
@@ -921,6 +1069,7 @@ function ADRunsController.load(adEnv)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
ADRunsController.store = store
|
ADRunsController.store = store
|
||||||
|
pcall(ADRunsController.migrateBuildings, adEnv)
|
||||||
local vehiclesById = getFarmVehiclesById(adEnv)
|
local vehiclesById = getFarmVehiclesById(adEnv)
|
||||||
for _, run in ipairs(store.runs) do
|
for _, run in ipairs(store.runs) do
|
||||||
for _, vehicleId in ipairs(run.vehicleIds) do
|
for _, vehicleId in ipairs(run.vehicleIds) do
|
||||||
|
|||||||
@@ -657,6 +657,9 @@ end
|
|||||||
-- AD læser først målet når vognen er læsset, så skiftet her gælder for hele turen.
|
-- AD læser først målet når vognen er læsset, så skiftet her gælder for hele turen.
|
||||||
local function chooseRunTarget(adEnv, driver)
|
local function chooseRunTarget(adEnv, driver)
|
||||||
local run = ADRunsController ~= nil and ADRunsController.getRunForVehicle(driver) or nil
|
local run = ADRunsController ~= nil and ADRunsController.getRunForVehicle(driver) or nil
|
||||||
|
if run ~= nil and ADRunsController.resolveMarkers ~= nil then
|
||||||
|
pcall(ADRunsController.resolveMarkers, adEnv, run)
|
||||||
|
end
|
||||||
if run == nil or ADRunsController.chooseTarget == nil or #ADRunsController.getRunTargets(run) < 1 then
|
if run == nil or ADRunsController.chooseTarget == nil or #ADRunsController.getRunTargets(run) < 1 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -584,5 +584,73 @@ check("Cout6 last uden mål -> cargoNoTarget", ADRunsController.validateVehicle(
|
|||||||
bulkTractor.loadType = nil
|
bulkTractor.loadType = nil
|
||||||
ADUnloadWait = nil; ADOutbound = nil; ADSources = nil
|
ADUnloadWait = nil; ADOutbound = nil; ADSources = nil
|
||||||
|
|
||||||
|
-- C-flow: bygninger -> markører (resolveMarkers), migration af gamle markør-runs, noMarker, flow-rækker
|
||||||
|
local buildings = {
|
||||||
|
{id = "barn1", name = "Kostald 1", kind = "husbandry", loadMarker = {id = 10, name = "cow 1 milk", distance = 5}, unloadMarker = {id = 94, name = "Cow 1 Food", distance = 8}, canBeSource = true, canBeTarget = true, canSell = false},
|
||||||
|
{id = "shed", name = "Palleskur", kind = "objectStorage", loadMarker = nil, unloadMarker = nil, canBeSource = true, canBeTarget = false, canSell = false},
|
||||||
|
{id = "mill", name = "Sukkerfabrik", kind = "factory", loadMarker = {id = 12694, name = "Suger Load", distance = 3}, unloadMarker = {id = 77, name = "sugar offload", distance = 4}, canBeSource = true, canBeTarget = true, canSell = false},
|
||||||
|
}
|
||||||
|
ADBuildings = {
|
||||||
|
list = function() return buildings end,
|
||||||
|
find = function(_, _, id) for _, b in ipairs(buildings) do if b.id == id then return b end end end,
|
||||||
|
byMarker = function(_, _, wayPointId, role) for _, b in ipairs(buildings) do local m = role == "unload" and b.unloadMarker or b.loadMarker if m ~= nil and m.id == wayPointId then return b end end end,
|
||||||
|
}
|
||||||
|
ADSources = {identify = function(_, id) return (id == 10 or id == 12694 or id == 555) and {kind = "x", wayPointId = id, name = "k"} or nil end, getProducts = function() return {} end, getSellMarkers = function() return {} end, stationAccepts = function() return false end, getSourcePlaceables = function() return {} end}
|
||||||
|
ADOutbound = {isOutboundVehicle = function() return false end, getRunStatus = function() return {reasons = {"SUGAR 78 % af top"}} end, getHoldFor = function() return nil end, getTripFor = function() return nil end, releaseInactive = function() end}
|
||||||
|
buildWorld()
|
||||||
|
addMarker(10, "cow 1 milk", "Milk", 100, 0); loadAt[10] = {}
|
||||||
|
addMarker(555, "raa markoer", "Pickup", 200, 0); loadAt[555] = {}
|
||||||
|
addMarker(77, "sugar offload", "production", 950, 0); unloadAt[77] = {accepts = {[TMR] = 360000}}
|
||||||
|
-- CF1: udkørsel: bygninger + rå markør -> sourceWayPointIds; manglende markør rapporteres
|
||||||
|
local flowOut = ADRunsController.createRun("Milk", "outbound")
|
||||||
|
ADRunsController.updateRun(flowOut.id, {sourceBuildingIds = {"barn1", "shed"}, sourceWayPointIds = {555}})
|
||||||
|
local resolved = ADRunsController.resolveMarkers(adEnv, ADRuns.getRun(ADRunsController.store, flowOut.id))
|
||||||
|
check("CF1 kildemarkører = bygningens + rå", table.concat(ADRuns.getRun(ADRunsController.store, flowOut.id).sourceWayPointIds, ","), "10,555")
|
||||||
|
check("CF1 manglende markør", resolved.missing[1], "Palleskur")
|
||||||
|
-- en markør der HØRER til en bygning som ikke længere er valgt, fjernes (den er ikke rå)
|
||||||
|
ADRunsController.updateRun(flowOut.id, {sourceWayPointIds = {12694, 555}})
|
||||||
|
ADRunsController.resolveMarkers(adEnv, ADRuns.getRun(ADRunsController.store, flowOut.id))
|
||||||
|
check("CF1 fravalgt bygnings markør fjernes", table.concat(ADRuns.getRun(ADRunsController.store, flowOut.id).sourceWayPointIds, ","), "10,555")
|
||||||
|
-- CF2: forsyning: mål-bygninger -> targetWayPointIds + targetWayPointId
|
||||||
|
local flowIn = ADRunsController.createRun("Foder", "supply")
|
||||||
|
ADRunsController.updateRun(flowIn.id, {targetBuildingIds = {"barn1", "mill"}})
|
||||||
|
ADRunsController.resolveMarkers(adEnv, ADRuns.getRun(ADRunsController.store, flowIn.id))
|
||||||
|
check("CF2 målmarkører", table.concat(ADRunsController.getRunTargets(ADRuns.getRun(ADRunsController.store, flowIn.id)), ","), "94,77")
|
||||||
|
check("CF2 primært mål", ADRuns.getRun(ADRunsController.store, flowIn.id).targetWayPointId, 94)
|
||||||
|
-- CF3: migration: gamle markør-runs får bygninger
|
||||||
|
local oldOut = ADRunsController.createRun("Gammel ud", "outbound")
|
||||||
|
ADRunsController.updateRun(oldOut.id, {sourceWayPointIds = {12694, 555}})
|
||||||
|
local oldIn = ADRunsController.createRun("Gammel ind", "supply")
|
||||||
|
ADRunsController.updateRun(oldIn.id, {targetWayPointIds = {94}})
|
||||||
|
ADRunsController.migrateBuildings(adEnv)
|
||||||
|
check("CF3 ud: markør -> bygning", ADRuns.getRun(ADRunsController.store, oldOut.id).sourceBuildingIds[1], "mill")
|
||||||
|
check("CF3 ud: rå markør uden bygning beholdes", table.concat(ADRuns.getRun(ADRunsController.store, oldOut.id).sourceWayPointIds, ","), "12694,555")
|
||||||
|
check("CF3 ind: markør -> bygning", ADRuns.getRun(ADRunsController.store, oldIn.id).targetBuildingIds[1], "barn1")
|
||||||
|
ADRunsController.migrateBuildings(adEnv)
|
||||||
|
check("CF3 migration er idempotent", #ADRuns.getRun(ADRunsController.store, oldOut.id).sourceBuildingIds, 1)
|
||||||
|
-- CF4: validering: valgt bygning uden markør -> noMarker
|
||||||
|
local cfVehicle = makeVehicle("vehicleCF", "CF", {STRAW, TMR}, 20000, 100, 0)
|
||||||
|
ADRunsController.updateRun(flowOut.id, {sourceBuildingIds = {"shed"}, sourceWayPointIds = {}})
|
||||||
|
local cfValidation = ADRunsController.validateVehicle(adEnv, ADRuns.getRun(ADRunsController.store, flowOut.id), cfVehicle)
|
||||||
|
check("CF4 noMarker", cfValidation.reason, "noMarker")
|
||||||
|
check("CF4 hvilken bygning", cfValidation.missingBuilding, "Palleskur")
|
||||||
|
-- CF5: flow-række til tavlen
|
||||||
|
ADRunsController.updateRun(flowOut.id, {sourceBuildingIds = {"barn1"}, products = {{fillType = "SUGAR", policy = "sell"}, {fillType = "FORAGE", policy = "store"}}, collectRound = true})
|
||||||
|
ADRunsController.assignVehicle(flowOut.id, cfVehicle)
|
||||||
|
local row = ADRunsController.getFlowRow(adEnv, ADRuns.getRun(ADRunsController.store, flowOut.id))
|
||||||
|
check("CF5 vare-navne", table.concat(row.productNames, ","), "SUGAR,FORAGE")
|
||||||
|
check("CF5 fra", row.fromNames[1], "Kostald 1")
|
||||||
|
check("CF5 politikker", table.concat(row.policies, ","), "sell,store")
|
||||||
|
check("CF5 traktor", row.vehicleNames[1], "CF")
|
||||||
|
check("CF5 begrundelse", row.reason, "SUGAR 78 % af top")
|
||||||
|
check("CF5 runde", row.collectRound, true)
|
||||||
|
ADRunsController.updateRun(flowOut.id, {sourceBuildingIds = {"barn1", "shed"}})
|
||||||
|
check("CF5 manglende bygning markeres", ADRunsController.getFlowRow(adEnv, ADRuns.getRun(ADRunsController.store, flowOut.id)).missing[1], "Palleskur")
|
||||||
|
local rowIn = ADRunsController.getFlowRow(adEnv, ADRuns.getRun(ADRunsController.store, flowIn.id))
|
||||||
|
check("CF5 forsyning fra = alle siloer", rowIn.fromAllSilos, true)
|
||||||
|
check("CF5 forsyning til", table.concat(rowIn.toNames, ","), "Kostald 1,Sukkerfabrik")
|
||||||
|
check("CF5 forsyning auto-varer", rowIn.productAuto, true)
|
||||||
|
ADBuildings = nil; ADSources = nil; ADOutbound = nil
|
||||||
|
|
||||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||||
os.exit(failures == 0 and 0 or 1)
|
os.exit(failures == 0 and 0 or 1)
|
||||||
|
|||||||
Reference in New Issue
Block a user