diff --git a/apps/android/test.js b/apps/android/test.js deleted file mode 100644 index 007b06fc7..000000000 --- a/apps/android/test.js +++ /dev/null @@ -1,153 +0,0 @@ -let result = true; - -function assertTrue(condition, text) { - if (!condition) { - result = false; - print("FAILURE: " + text); - } else print("OK: " + text); -} - -function assertFalse(condition, text) { - assertTrue(!condition, text); -} - -function assertUndefinedOrEmpty(array, text) { - assertTrue(!array || array.length == 0, text); -} - -function assertNotEmpty(array, text) { - assertTrue(array && array.length > 0, text); -} - -let internalOn = () => { - return getPinMode((process.env.HWVERSION==2)?D30:D26) == "input"; -}; - -let sec = { - connected: false -}; - -NRF.getSecurityStatus = () => sec; -// add an empty starting point to make the asserts work -Bangle._PWR={}; - -let teststeps = []; - -teststeps.push(()=>{ - print("Not connected, should use internal GPS"); - assertTrue(!NRF.getSecurityStatus().connected, "Not connected"); - - assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS"); - assertFalse(Bangle.isGPSOn(), "isGPSOn"); - - assertTrue(Bangle.setGPSPower(1, "test"), "Switch GPS on"); - - assertNotEmpty(Bangle._PWR.GPS, "GPS"); - assertTrue(Bangle.isGPSOn(), "isGPSOn"); - assertTrue(internalOn(), "Internal GPS on"); - - assertFalse(Bangle.setGPSPower(0, "test"), "Switch GPS off"); - - assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS"); - assertFalse(Bangle.isGPSOn(), "isGPSOn"); - assertFalse(internalOn(), "Internal GPS off"); - -}); - -teststeps.push(()=>{ - print("Connected, should use GB GPS"); - sec.connected = true; - - assertTrue(NRF.getSecurityStatus().connected, "Connected"); - - assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS"); - assertFalse(Bangle.isGPSOn(), "isGPSOn"); - assertFalse(internalOn(), "Internal GPS off"); - - - print("Internal GPS stays on until the first GadgetBridge event arrives"); - assertTrue(Bangle.setGPSPower(1, "test"), "Switch GPS on"); - - assertNotEmpty(Bangle._PWR.GPS, "GPS"); - assertTrue(Bangle.isGPSOn(), "isGPSOn"); - assertTrue(internalOn(), "Internal GPS on"); - - print("Send minimal GadgetBridge GPS event to trigger switch"); - GB({t:"gps"}); -}); - -teststeps.push(()=>{ - print("GPS should be on, internal off"); - - assertNotEmpty(Bangle._PWR.GPS, "GPS"); - assertTrue(Bangle.isGPSOn(), "isGPSOn"); - assertFalse(internalOn(), "Internal GPS off"); -}); - -teststeps.push(()=>{ - print("Switching GPS off turns both GadgetBridge as well as internal off"); - assertFalse(Bangle.setGPSPower(0, "test"), "Switch GPS off"); - - assertUndefinedOrEmpty(Bangle._PWR.GPS, "No GPS"); - assertFalse(Bangle.isGPSOn(), "isGPSOn"); - assertFalse(internalOn(), "Internal GPS off"); -}); - -teststeps.push(()=>{ - print("Wait for all timeouts to run out"); - return 12000; -}); - -teststeps.push(()=>{ - print("Check auto switch when no GPS event arrives"); - - assertTrue(Bangle.setGPSPower(1, "test"), "Switch GPS on"); - - assertNotEmpty(Bangle._PWR.GPS, "GPS"); - assertTrue(Bangle.isGPSOn(), "isGPSOn"); - assertTrue(internalOn(), "Internal GPS on"); - - print("Send minimal GadgetBridge GPS event to trigger switch"); - GB({t:"gps"}); - - print("Internal should be switched off now"); - - assertNotEmpty(Bangle._PWR.GPS, "GPS"); - assertTrue(Bangle.isGPSOn(), "isGPSOn"); - assertFalse(internalOn(), "Internal GPS off"); - - //wait on next test - return 12000; -}); - -teststeps.push(()=>{ - print("Check state and disable GPS, internal should be on"); - - assertNotEmpty(Bangle._PWR.GPS, "GPS"); - assertTrue(Bangle.isGPSOn(), "isGPSOn"); - assertTrue(internalOn(), "Internal GPS on"); - - assertFalse(Bangle.setGPSPower(0, "test"), "Switch GPS off"); -}); - -teststeps.push(()=>{ - print("Result Overall is " + (result ? "OK" : "FAIL")); -}); - -let wrap = (functions) => { - if (functions.length > 0) { - setTimeout(()=>{ - let waitingTime = functions.shift()(); - if (waitingTime){ - print("WAITING: ", waitingTime); - setTimeout(()=>{wrap(functions);}, waitingTime); - } else - wrap(functions); - },0); - } -}; - -setTimeout(()=>{ - wrap(teststeps); -}, 5000); - diff --git a/apps/android/test.json b/apps/android/test.json index 809fd012c..429fd70fe 100644 --- a/apps/android/test.json +++ b/apps/android/test.json @@ -5,13 +5,22 @@ "steps" : [ {"t":"cmd", "js": "Bangle.setGPSPower=(isOn, appID)=>{if (!appID) appID='?';if (!Bangle._PWR) Bangle._PWR={};if (!Bangle._PWR.GPS) Bangle._PWR.GPS=[];if (isOn && !Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.push(appID);if (!isOn && Bangle._PWR.GPS.includes(appID)) Bangle._PWR.GPS.splice(Bangle._PWR.GPS.indexOf(appID),1);return Bangle._PWR.GPS.length>0;};", "text": "Fake the setGPSPower"}, {"t":"wrap", "fn": "Bangle.setGPSPower", "id": "gpspower"}, - {"t":"cmd", "js": "NRF.getSecurityStatus = () => { return { connected: false };}", "text": "Control the security status"}, {"t":"cmd", "js": "Serial1.println = () => { }", "text": "Fake the serial port println"}, {"t":"cmd", "js": "Bluetooth.println = () => { }", "text": "Fake the Bluetooth println"}, {"t":"cmd", "js": "Bangle._PWR={}", "text": "Prepare an empty _PWR for following asserts"}, {"t":"cmd", "js": "require('Storage').writeJSON('android.settings.json', {overwriteGps: true})", "text": "Enable GPS overwrite"}, {"t":"cmd", "js": "eval(require('Storage').read('android.boot.js'))", "text": "Load the boot code"} ] + },{ + "id": "connected", + "steps" : [ + {"t":"cmd", "js": "NRF.getSecurityStatus = () => { return { connected: true };}", "text": "Control the security status to be connected"} + ] + },{ + "id": "disconnected", + "steps" : [ + {"t":"cmd", "js": "NRF.getSecurityStatus = () => { return { connected: false };}", "text": "Control the security status to be disconnected"} + ] }], "tests" : [{ "description": "Check setGPSPower is replaced", @@ -26,6 +35,7 @@ "description": "Test switching hardware GPS on and off", "steps" : [ {"t":"setup", "id": "default"}, + {"t":"setup", "id": "connected"}, {"t":"assertArray", "js": "Bangle._PWR.GPS", "is":"undefinedOrEmpty", "text": "No GPS clients"}, {"t":"assert", "js": "Bangle.isGPSOn()", "is":"falsy", "text": "isGPSOn shows GPS as off"}, {"t":"assert", "js": "Bangle.setGPSPower(1, 'test')", "is":"truthy", "text": "setGPSPower returns truthy when switching on"}, @@ -37,5 +47,53 @@ {"t":"assert", "js": "Bangle.isGPSOn()", "is":"falsy", "text": "isGPSOn shows GPS as off"}, {"t":"assertCall", "id": "gpspower", "count": 2, "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 0 } ] , "text": "internal GPS switched off"} ] + },{ + "description": "Test switching when GB GPS is available, internal GPS active until GB GPS event arrives", + "steps" : [ + {"t":"setup", "id": "default"}, + {"t":"setup", "id": "connected"}, + {"t":"assertArray", "js": "Bangle._PWR.GPS", "is":"undefinedOrEmpty", "text": "No GPS clients"}, + {"t":"assert", "js": "Bangle.isGPSOn()", "is":"falsy", "text": "isGPSOn shows GPS as off"}, + + {"t":"assert", "js": "Bangle.setGPSPower(1, 'test')", "is":"truthy", "text": "setGPSPower returns truthy when switching on"}, + {"t":"assertArray", "js": "Bangle._PWR.GPS", "is":"notEmpty", "text": "GPS clients"}, + {"t":"assert", "js": "Bangle.isGPSOn()", "is":"truthy", "text": "isGPSOn shows GPS as on"}, + {"t":"assertCall", "id": "gpspower", "count": 1, "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 1 } ], "text": "internal GPS switched on"}, + + {"t":"gb", "obj":{"t":"gps"}}, + {"t":"assertArray", "js": "Bangle._PWR.GPS", "is":"notEmpty", "text": "GPS clients still there"}, + {"t":"assert", "js": "Bangle.isGPSOn()", "is":"truthy", "text": "isGPSOn still shows GPS as on"}, + {"t":"assertCall", "id": "gpspower", "count": 2, "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 0 } ], "text": "internal GPS switched off"} + ] + },{ + "description": "Test switching when GB GPS is available, internal stays off", + "steps" : [ + {"t":"setup", "id": "default"}, + {"t":"setup", "id": "connected"}, + + {"t":"assert", "js": "Bangle.setGPSPower(1, 'test')", "is":"truthy", "text": "setGPSPower returns truthy when switching on"}, + + {"t":"gb", "obj":{"t":"gps"}}, + {"t":"assertCall", "id": "gpspower", "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 0 } ], "text": "internal GPS switched off"}, + + {"t":"assert", "js": "Bangle.setGPSPower(0, 'test')", "is":"falsy", "text": "setGPSPower returns truthy when switching on"}, + {"t":"assertCall", "id": "gpspower", "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 0 } ], "text": "internal GPS still switched off"} + ] + },{ + "description": "Test switching when GB GPS is available, but no event arrives", + "steps" : [ + {"t":"setup", "id": "default"}, + {"t":"setup", "id": "connected"}, + + {"t":"assert", "js": "Bangle.setGPSPower(1, 'test')", "is":"truthy", "text": "setGPSPower returns truthy when switching on"}, + + {"t":"resetCall", "id": "gpspower"}, + {"t":"gb", "obj":{"t":"gps"}, "text": "trigger switch"}, + {"t":"assertCall", "id": "gpspower", "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 0 } ], "text": "internal GPS switched off"}, + + {"t":"resetCall", "id": "gpspower"}, + {"t":"advanceTimers", "ms":"12000", "text": "wait for fallback"}, + {"t":"assertCall", "id": "gpspower", "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 1 } ], "text": "internal GPS switched on caused by missing GB event"} + ] }] } diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 78f4c81a6..98a069664 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -1269,12 +1269,6 @@ module.exports = { "no-undef" ] }, - "android/test.js": { - "hash": "703dad907d9b17d281faca2ecd9099d9f127e7241b48c7617f9147978ddb7c43", - "rules": [ - "no-undef" - ] - }, "android/boot.js": { "hash": "a537b3f7772e11f44615d80d6c6bacfa69c1854c6da3c01666863bcae8a18059", "rules": [ diff --git a/apps/messagesoverlay/test.json b/apps/messagesoverlay/test.json index 40ac14a8b..77e12caa6 100644 --- a/apps/messagesoverlay/test.json +++ b/apps/messagesoverlay/test.json @@ -16,7 +16,7 @@ {"t":"assert", "js": "Bangle['#onswipe']", "is":"function", "text": "One swipe handler restored"} ] },{ - "description": "Test handler backgrounding with fastloading (setUI)", + "description": "Test swipe handler backgrounding with fastloading (setUI)", "steps" : [ {"t":"cmd", "js": "Bangle.on('swipe',print)", "text": "Create listener for swipes"}, {"t":"cmd", "js": "Bangle.setUI({mode: 'clock',remove: ()=>{}})", "text": "Init UI for clock"}, @@ -24,9 +24,17 @@ {"t":"assertArray", "js": "Bangle['#onswipe']", "is":"undefinedOrEmpty", "text": "No swipe handlers while message overlay is on screen"}, {"t":"cmd", "js": "Bangle.setUI()", "text": "Trigger removal of UI"}, {"t":"assertArray", "js": "Bangle['#onswipe']", "is":"undefinedOrEmpty", "text": "Still no swipe handlers"}, - {"t":"cmd", "js": "Bangle.on('touch', print)"}, {"t":"emit", "event":"touch", "paramsArray": [ 1, { "x": 10, "y": 10, "type": 0 } ], "text": "Close message"}, {"t":"assert", "js": "Bangle['#onswipe']", "is":"function", "text": "One swipe handler restored"} ] + },{ + "description": "Test watch backgrounding", + "steps" : [ + {"t":"cmd", "js": "setWatch(print,BTN)", "text": "Create watch"}, + {"t":"cmd", "js": "require('messagesoverlay').message('text', {src:'Messenger',t:'add',type:'text',id:Date.now().toFixed(0),title:'title',body:'body'})", "text": "Show a message overlay"}, + {"t":"assertArray", "js": "global[\"\\xff\"].watches", "is":"undefinedOrEmpty", "text": "No watches while message overlay is on screen"}, + {"t":"emit", "event":"touch", "paramsArray": [ 1, { "x": 10, "y": 10, "type": 0 } ], "text": "Close message"}, + {"t":"assert", "js": "global[\"\\xff\"].watches.length", "is":"equal", "to": "2", "text": "One watch restored, first entry is always empty"} + ] }] } diff --git a/bin/runapptests.js b/bin/runapptests.js index 17d2e9ce2..dcbf13c58 100755 --- a/bin/runapptests.js +++ b/bin/runapptests.js @@ -57,7 +57,16 @@ const DEMOTEST = { {"t":"assertArray", "js": "[1,2,3]", "is":"notEmpty", "text": "Evaluates the content of 'js' on the device and asserts if the result is an array with more than 0 entries"}, {"t":"cmd", "js": "global.testfunction(1)", "text": "Call function for the following asserts"}, {"t":"assertCall", "id": "testfunc", "argAsserts": [ { "t": "assert", "arg": "0", "is": "equal", "to": 1 } ] , "text": "Asserts if a wrapped function has been called with the expected arguments"}, - {"t":"assertCall", "id": "testfunc", "count": 1 , "text": "Asserts if a wrapped function has been called the expected number of times"} + {"t":"resetCall", "id": "testfunc", "text": "Reset the recorded calls"}, + {"t":"assertCall", "id": "testfunc", "count": 0 , "text": "Asserts if a wrapped function has been called the expected number of times"} + ] + }, { + "description": "Emulator timers and intervals can advanced by a given time", + "steps": [ + {"t":"cmd", "js":"setTimeout(()=>{global.waited = true},60000)", "text": "Set a timeout for 60 seconds"}, + {"t":"assert", "js":"global.waited", "is": "falsy", "text": "Timeout has not yet fired"}, + {"t":"advanceTimers", "ms":60000, "text": "Advance timers by 60000 ms to get the timer to fire in the next idle period"}, + {"t":"assert", "js":"global.waited", "is": "true", "text": "Timeout has fired"} ] }] } @@ -126,7 +135,7 @@ function assertArray(step){ } function assertValue(step){ - console.log("> ASSERT " + `\`${step.js}\``, "IS", step.is.toUpperCase(), step.to ? "TO " + `\`${step.js}\`` : "", step.text ? "- " + step.text : ""); + console.log("> ASSERT " + `\`${step.js}\``, "IS", step.is.toUpperCase() + (step.to !== undefined ? " TO " + `\`${step.to}\`` : ""), step.text ? "- " + step.text : ""); let isOK; switch (step.is.toLowerCase()){ case "truthy": isOK = getValue(`!!${step.js}`); break; @@ -231,7 +240,7 @@ function runStep(step, subtest, test, state){ break; case "gb" : p = p.then(() => { - let obj = Object.apply({ + let obj = Object.assign({ src:'Messenger', t: 'notify', type: 'text', @@ -239,6 +248,7 @@ function runStep(step, subtest, test, state){ title:'title', body:'body' }, step.obj || {}); + console.log(`> GB with`, verbose ? "event " + JSON.stringify(obj, null, null) : "type " + obj.t); emu.tx(`GB(${JSON.stringify(obj)})\n`); }); break; @@ -275,6 +285,11 @@ function runStep(step, subtest, test, state){ state.ok &= assertArray(step); }); break; + case "resetCall": + console.log(`> RESET CALL ${step.id}`, step.text ? "- " + step.text : ""); + emu.tx(`global.APPTESTS.funcCalls.${step.id} = 0;\n`); + emu.tx(`global.APPTESTS.funcArgs.${step.id} = undefined;\n`); + break; case "assertCall": p = p.then(() => { state.ok &= assertCall(step); @@ -308,14 +323,12 @@ function runStep(step, subtest, test, state){ } }); break; - case "sleep" : + case "advanceTimers" : p = p.then(()=>{ - return new Promise(resolve => { - setTimeout(()=>{ - console.log("> WAITED FOR", step.ms); - resolve(); - }, step.ms); - }) + console.log("> ADVANCE TIMERS BY", step.ms + "ms"); + emu.tx(`for(let c of global["\xff"].timers){ + if(c) c.time -= ${step.ms * 1000}; + }\n`); }); break; case "upload" :