diff --git a/src/core/Platform.lua b/src/core/Platform.lua new file mode 100644 index 00000000..ebac81e5 --- /dev/null +++ b/src/core/Platform.lua @@ -0,0 +1,54 @@ +-- Platform capability detection for NX / mobile / desktop. + +local Platform = {} + +local cached + +local function compute() + local osName = (love and love.system and love.system.getOS and love.system.getOS()) + or "Unknown" + local nx = osName == "NX" + local mobile = osName == "Android" or osName == "iOS" + local nativePicker = love and love.system + and type(love.system.pickFile) == "function" + return { + os = osName, + nx = nx, + mobile = mobile, + console = nx, + hasNativePicker = nativePicker, + canSpawnProcess = osName == "OS X" or osName == "Windows" or osName == "Linux", + romImportMode = nx and "save-directory" + or (nativePicker and "native-picker") + or "desktop", + networkValidated = not nx, + } +end + +function Platform.detect() + if not cached then cached = compute() end + return cached +end + +function Platform.isNX() + return Platform.detect().nx +end + +function Platform.romImportMode() + return Platform.detect().romImportMode +end + +function Platform.canSpawnProcess() + return Platform.detect().canSpawnProcess +end + +function Platform.networkValidated() + return Platform.detect().networkValidated +end + +-- Tests may swap love.system between cases. +function Platform._resetForTests() + cached = nil +end + +return Platform diff --git a/tests/platform_nx_test.lua b/tests/platform_nx_test.lua new file mode 100644 index 00000000..91fba03c --- /dev/null +++ b/tests/platform_nx_test.lua @@ -0,0 +1,62 @@ +-- NX / Android / desktop capability detection (SWNX-01). +-- Self-contained: luajit tests/platform_nx_test.lua + +package.path = "./?.lua;./?/init.lua;" .. package.path + +local T = require("tests.harness") +local check = T.check +local eq = T.eq + +local savedLove = _G.love + +local function withOS(osName, pickFile, fn) + _G.love = { + system = { + getOS = function() return osName end, + pickFile = pickFile, + }, + } + package.loaded["src.core.Platform"] = nil + local Platform = require("src.core.Platform") + Platform._resetForTests() + local ok, err = pcall(fn, Platform) + _G.love = savedLove + package.loaded["src.core.Platform"] = nil + if not ok then error(err) end +end + +-- NX: save-directory import, no shell spawn, network gated off +withOS("NX", nil, function(Platform) + local caps = Platform.detect() + eq(caps.os, "NX", "NX detect os") + eq(caps.nx, true, "NX flag") + eq(caps.romImportMode, "save-directory", "NX romImportMode") + eq(caps.canSpawnProcess, false, "NX cannot spawn processes") + eq(caps.networkValidated, false, "NX network not validated") + eq(Platform.isNX(), true, "isNX convenience") + eq(Platform.romImportMode(), "save-directory", "romImportMode helper") +end) + +-- Android: mobile native picker path, not NX semantics +withOS("Android", function() end, function(Platform) + local caps = Platform.detect() + eq(caps.os, "Android", "Android detect os") + eq(caps.nx, false, "Android is not NX") + eq(caps.mobile, true, "Android mobile") + eq(caps.hasNativePicker, true, "Android has pickFile") + eq(caps.romImportMode, "native-picker", "Android romImportMode") + eq(Platform.isNX(), false, "Android isNX false") +end) + +-- Desktop Linux: shell spawn + desktop import mode +withOS("Linux", nil, function(Platform) + local caps = Platform.detect() + eq(caps.os, "Linux", "Linux detect os") + eq(caps.nx, false, "Linux is not NX") + eq(caps.canSpawnProcess, true, "Linux can spawn processes") + eq(caps.romImportMode, "desktop", "Linux romImportMode") + eq(caps.networkValidated, true, "Linux network validated") + eq(Platform.canSpawnProcess(), true, "canSpawnProcess helper") +end) + +T.finish() diff --git a/tests/run_tests.lua b/tests/run_tests.lua index 5443e196..eb7fbf31 100644 --- a/tests/run_tests.lua +++ b/tests/run_tests.lua @@ -3369,6 +3369,8 @@ runSuites({ "tests/rom_importer_android_mod_pick_test.lua" }) -- ---------------------------------------------- import with no picker (#482) runSuites({ "tests/rom_importer_no_picker_test.lua" }) runSuites({ "tests/rom_importer_double_pick_test.lua" }) +-- ---------------------------------------------- Switch platform capabilities +runSuites({ "tests/platform_nx_test.lua" }) -- ---------------------------------------------- parity workstream tests -- Each tests/parity_*.lua is a self-contained file (own bootstrap + check, -- error()s if any assertion fails). Globbed, so dropping a new parity