diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/.gitignore b/Ability/Sensormock/demo/SensorSimulateDemo/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..91d237bb144c7fb1777e50271857ef0f593286fc --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/local.properties +/.idea +**/build +/.hvigor \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/README.md b/Ability/Sensormock/demo/SensorSimulateDemo/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ecae5f8fa9267120b1fc64a09ad748b0ed25709d --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/README.md @@ -0,0 +1 @@ +####传感器模拟的使用说明 \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/build-profile.json5 b/Ability/Sensormock/demo/SensorSimulateDemo/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3854f71fc436e7d67fb03828698562f4dc8a3abb --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/build-profile.json5 @@ -0,0 +1,27 @@ +{ + "app": { + "signingConfigs": [], + "compileSdkVersion": 8, + "compatibleSdkVersion": 8, + "products": [ + { + "name": "default", + "signingConfig": "default", + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/.gitignore b/Ability/Sensormock/demo/SensorSimulateDemo/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5a6ba80fa3d9498a23ae8ae7d9518f8743fa8a96 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/.gitignore @@ -0,0 +1,4 @@ +/node_modules +/.preview +/build +/.cxx \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/build-profile.json5 b/Ability/Sensormock/demo/SensorSimulateDemo/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..cfdc90f805d1f7ef3a6557bc101de47b91895eb7 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/build-profile.json5 @@ -0,0 +1,14 @@ +{ + "apiType": 'faMode', + "buildOption": { + }, + "targets": [ + { + "name": "default", + "runtimeOS": "HarmonyOS" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/hvigorfile.js b/Ability/Sensormock/demo/SensorSimulateDemo/entry/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..bcec4c99653062cbf17702c40a2dd2a7b809b81a --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').legacyHapTasks diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/package.json b/Ability/Sensormock/demo/SensorSimulateDemo/entry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c4e988f30f2ec9e3430a4d0c8f05e89fabbc2659 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/package.json @@ -0,0 +1,13 @@ +{ + "name": "entry", + "version": "1.0.0", + "ohos": { + "org": "huawei", + "buildTool": "hvigor", + "directoryLevel": "module" + }, + "description": "example description", + "repository": {}, + "license": "ISC", + "dependencies": {} +} diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/config.json b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/config.json new file mode 100644 index 0000000000000000000000000000000000000000..4f5234964a8b01fd51bcbe3749ce8c57e639f3c0 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/config.json @@ -0,0 +1,66 @@ +{ + "app": { + "bundleName": "com.example.sensorsimulatedemo", + "vendor": "example", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.entry", + "name": ".entry", + "mainAbility": ".MainAbility", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry", + "installationFree": false + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "formsEnabled": false, + "name": ".MainAbility", + "srcLanguage": "ets", + "srcPath": "MainAbility", + "icon": "$media:icon", + "description": "$string:MainAbility_desc", + "label": "$string:MainAbility_label", + "type": "page", + "visible": true, + "launchType": "standard" + } + ], + "js": [ + { + "mode": { + "syntax": "ets", + "type": "pageAbility" + }, + "pages": [ + "pages/index" + ], + "name": ".MainAbility", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/ets/MainAbility/app.ets b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/ets/MainAbility/app.ets new file mode 100644 index 0000000000000000000000000000000000000000..b7a0995c8e441cac86e21e06e7c9071664482b1c --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/ets/MainAbility/app.ets @@ -0,0 +1,8 @@ +export default { + onCreate() { + console.info('Application onCreate') + }, + onDestroy() { + console.info('Application onDestroy') + }, +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/ets/MainAbility/pages/index.ets b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/ets/MainAbility/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..d6ca48cf43988cd6f270a026f0c1a88b7bc57123 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/ets/MainAbility/pages/index.ets @@ -0,0 +1,17 @@ +@Entry +@Component +struct Index { + @State message: string = 'Hello World' + + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + } + .width('100%') + } + .height('100%') + } +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/element/color.json b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..1bbc9aa9617e97c45440e1d3d66afc1154837012 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "white", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/element/string.json b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..490210a3908f47722dc942d49dacc98b97669a5f --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "entry_desc", + "value": "description" + }, + { + "name": "MainAbility_desc", + "value": "description" + }, + { + "name": "MainAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/media/icon.png b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/main/resources/base/media/icon.png differ diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/config.json b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/config.json new file mode 100644 index 0000000000000000000000000000000000000000..a7d3be2ae277959d40c6df636d4099616f268466 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/config.json @@ -0,0 +1,67 @@ +{ + "app": { + "bundleName": "com.example.sensorsimulatedemo", + "vendor": "example", + "version": { + "code": 1000000, + "name": "1.0.0" + } + }, + "deviceConfig": {}, + "module": { + "package": "com.example.entry_test", + "name": ".entry_test", + "mainAbility": ".TestAbility", + "srcPath": "", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry_test", + "moduleType": "feature", + "installationFree": false + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "visible": true, + "srcPath": "TestAbility", + "name": ".TestAbility", + "srcLanguage": "ets", + "icon": "$media:icon", + "description": "$string:description_TestAbility", + "formsEnabled": false, + "label": "$string:entry_TestAbility", + "type": "page", + "launchType": "standard" + } + ], + "js": [ + { + "mode": { + "syntax": "ets", + "type": "pageAbility" + }, + "pages": [ + "pages/index" + ], + "name": ".TestAbility", + "window": { + "designWidth": 720, + "autoDesignWidth": false + } + } + ] + } +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestAbility/app.ets b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestAbility/app.ets new file mode 100644 index 0000000000000000000000000000000000000000..5fd83b631f1806d46dcdf90ddbe96475ba3339c5 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestAbility/app.ets @@ -0,0 +1,18 @@ +import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' +import { Hypium } from '@ohos/hypium' +import testsuite from '../test/List.test' + +export default { + onCreate() { + console.info('Application onCreate') + var abilityDelegator: any + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() + var abilityDelegatorArguments: any + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() + console.info('start run testcase!!!') + Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) + }, + onDestroy() { + console.info('Application onDestroy') + }, +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestAbility/pages/index.ets b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestAbility/pages/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..539eb9ae7b7cb0870b26b1a69d20fb977b55291d --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestAbility/pages/index.ets @@ -0,0 +1,35 @@ +import router from '@system.router'; + +@Entry +@Component +struct Index { + aboutToAppear() { + console.info('TestAbility index aboutToAppear') + } + + @State message: string = 'Hello World' + build() { + Row() { + Column() { + Text(this.message) + .fontSize(50) + .fontWeight(FontWeight.Bold) + Button() { + Text('next page') + .fontSize(20) + .fontWeight(FontWeight.Bold) + }.type(ButtonType.Capsule) + .margin({ + top: 20 + }) + .backgroundColor('#0D9FFB') + .width('35%') + .height('5%') + .onClick(()=>{ + }) + } + .width('100%') + } + .height('100%') + } + } \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestRunner/OpenHarmonyTestRunner.ts b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestRunner/OpenHarmonyTestRunner.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f5bcf0a2cfbb0478b7993dda7c157a1ab5f862d --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/TestRunner/OpenHarmonyTestRunner.ts @@ -0,0 +1,68 @@ +import TestRunner from '@ohos.application.testRunner' +import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' + +var abilityDelegator = undefined +var abilityDelegatorArguments = undefined + +function translateParamsToString(parameters) { + const keySet = new Set([ + '-s class', '-s notClass', '-s suite', '-s itName', + '-s level', '-s testType', '-s size', '-s timeout', + '-s package', '-s dryRun' + ]) + let targetParams = ''; + for (const key in parameters) { + if (keySet.has(key)) { + targetParams += ' ' + key + ' ' + parameters[key] + } + } + return targetParams.trim() +} + +async function onAbilityCreateCallback() { + console.log('onAbilityCreateCallback'); +} + +async function addAbilityMonitorCallback(err: any) { + console.info('addAbilityMonitorCallback : ' + JSON.stringify(err)) +} + +export default class OpenHarmonyTestRunner implements TestRunner { + constructor() { + } + + onPrepare() { + console.info('OpenHarmonyTestRunner OnPrepare') + } + + onRun() { + console.log('OpenHarmonyTestRunner onRun run') + abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() + abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() + + let lMonitor = { + abilityName: testAbilityName, + onAbilityCreate: onAbilityCreateCallback, + }; + var testAbilityName = abilityDelegatorArguments.parameters['-p'] + '.TestAbility' + abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback) + var cmd = 'aa start -d 0 -a ' + testAbilityName + ' -b ' + abilityDelegatorArguments.bundleName + cmd += ' '+translateParamsToString(abilityDelegatorArguments.parameters) + var debug = abilityDelegatorArguments.parameters["-D"] + if (debug == 'true') + { + cmd += ' -D' + } + console.info('cmd : '+cmd) + abilityDelegator.executeShellCommand(cmd, + (err: any, d: any) => { + console.info('executeShellCommand : err : ' + JSON.stringify(err)); + console.info('executeShellCommand : data : ' + d.stdResult); + console.info('executeShellCommand : data : ' + d.exitCode); + }) + console.info('OpenHarmonyTestRunner onRun call abilityDelegator.getAppContext') + var context = abilityDelegator.getAppContext() + console.info('getAppContext : ' + JSON.stringify(context)) + console.info('OpenHarmonyTestRunner onRun end') + } +}; \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/test/List.test.ets b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..0f1243c9a112d3be3e5173d94e2bd73535681ff2 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import SensorMockTest from './Sensormock.test' + +export default function testsuite() { + SensorMockTest() +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/test/Sensormock.test.ets b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/test/Sensormock.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..fc510cafe18ac2ac48f1d148e00db6f16937235c --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/ets/test/Sensormock.test.ets @@ -0,0 +1,188 @@ +// @ts-nocheck +import { describe, it, expect, MockKit, when } from '@ohos/hypium' +import sensor from '@ohos.sensor'; + +export default function SensorMockTest() { + describe('sensorTest', function () { + it('sensorTest_on', 0, function () { + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.on); + + function NeedData(x, y, z) { + this.x = x + this.y = y + this.z = z + } + + when(mockedOnFunc)(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER).afterReturn(new NeedData(1, 2, 3)); + //从回调中拿到预置的数据 + newObj.on(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function (data) { + console.log("mockSensor - on: " + JSON.stringify(data)); + }); + }); + + it('sensorTest_on_2', 0, function () { + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.on); + + function NeedData(x, y, z) { + this.x = x + this.y = y + this.z = z + } + + when(mockedOnFunc)(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER).afterReturn(new NeedData(1, 2, 3)); + //从回调中拿到预置的数据,并传入轮询周期时间 + newObj.on(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function (data) { + console.log("mockSensor - on: " + JSON.stringify(data)); + }, { + interval: 3000000000 + }); + }); + + it('sensorTest_on_3', 0, function () { + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.on); + + function NeedData(x, y, z) { + this.x = x + this.y = y + this.z = z + } + + when(mockedOnFunc)(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER).afterReturn(new NeedData(1, 2, 3)); //模拟的数据 + let result = newObj.on(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER); + //从返回值中拿到预置的数据 + console.log("mockSensor - on: " + JSON.stringify(result)); + }); + + it('sensorTest_once', 0, function () { + + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.once); + + function NeedData(x, y, z) { + this.x = x + this.y = y + this.z = z + } + + when(mockedOnFunc)(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER).afterReturn(new NeedData(1, 2, 3)); //模拟的数据 + newObj.once(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function (data) { + //从回调中拿到预置的数据 + console.log("mockSensor - once: " + JSON.stringify(data)); + }); + }); + + + it('sensorTest_off', 0, function () { + + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.off); + + function NeedData(x, y, z) { + this.x = x + this.y = y + this.z = z + } + + when(mockedOnFunc)(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER).afterReturn(new NeedData(1, 2, 3)); //模拟的数据 + newObj.off(newObj.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, function (data) { + console.log("mockSensor - off: " + JSON.stringify(data)); //从回调中拿到预置的数据 + }); + }); + + + it('sensorTest_transformCoordinateSystem', 0, function () { + + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.transformCoordinateSystem); + + function SuccessData(x, y, z) { + this.x = x + this.y = y + this.z = z + } + + when(mockedOnFunc)('transformCoordinateSystem').afterReturn(new SuccessData(1, 2, 3)); //模拟的数据 + newObj.transformCoordinateSystem('transformCoordinateSystem', function (data) { + //从回调中拿到预置的数据 + console.log("mockSensor - transformCoordinateSystem: " + JSON.stringify(data)); + }); + }); + + + it('sensorTest_transformCoordinateSystem_async', 0, async function () { + + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.transformCoordinateSystem); + + //模拟的数据 + when(mockedOnFunc)('transformCoordinateSystem').afterReturn(new Promise((data, err) => { + if (true) { + data('data you need'); + } else { + err('some error'); + } + })); + + //从返回值中拿到预置的数据promise + newObj.transformCoordinateSystem('transformCoordinateSystem').then((data)=>{ + console.info("mockSensor - Operation successed :" + data); + }).catch((err) => { + console.info("mockSensor - Operation failed :" + err); + }); + }); + + + it('sensorTest_getDirection', 0, function () { + + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.transformCoordinateSystem); + + function SuccessData(x, y, z) { + this.x = x + this.y = y + this.z = z + } + + when(mockedOnFunc)('getDirection').afterReturn(new SuccessData(1, 2, 3)); //模拟的数据 + newObj.transformCoordinateSystem('getDirection', function (data) { + //从回调中拿到预置的数据 + console.log("mockSensor - getDirection: " + JSON.stringify(data)); + }); + }); + + + it('sensorTest_getDirection_async', 0, async function () { + + let mocker = new MockKit(); + let newObj = mocker.mockObject(sensor); + let mockedOnFunc = mocker.mockFunc(newObj, newObj.getDirection); + + //模拟的数据 + when(mockedOnFunc)('getDirection').afterReturn(new Promise((data, err) => { + if (true) { + data('data you need'); + } else { + err('some error'); + } + })); + + //从返回值中拿到预置的数据promise + newObj.getDirection('getDirection').then((data)=>{ + console.info("mockSensor - Operation successed :" + data); + }).catch((err) => { + console.info("mockSensor - Operation failed :" + err); + }); + }); + }); +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/resources/base/element/string.json b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..a0901cfced5abc1cb836b55896884b769adc7175 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,12 @@ +{ + "string": [ + { + "name": "description_TestAbility", + "value": "eTS_Empty Ability" + }, + { + "name": "entry_TestAbility", + "value": "entry_TestAbility" + } + ] +} \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/resources/base/media/icon.png b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/Ability/Sensormock/demo/SensorSimulateDemo/entry/src/ohosTest/resources/base/media/icon.png differ diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/hvigorfile.js b/Ability/Sensormock/demo/SensorSimulateDemo/hvigorfile.js new file mode 100644 index 0000000000000000000000000000000000000000..cff9f0dfcf8cb00cca34e7f50d61380cf5496868 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/hvigorfile.js @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +module.exports = require('@ohos/hvigor-ohos-plugin').legacyAppTasks \ No newline at end of file diff --git a/Ability/Sensormock/demo/SensorSimulateDemo/package.json b/Ability/Sensormock/demo/SensorSimulateDemo/package.json new file mode 100644 index 0000000000000000000000000000000000000000..dc9cc4081f16f3246ff030d90a026f2ad1bd5a38 --- /dev/null +++ b/Ability/Sensormock/demo/SensorSimulateDemo/package.json @@ -0,0 +1,17 @@ +{ + "name": "sensorsimulatedemo", + "version": "1.0.0", + "ohos": { + "org": "huawei", + "buildTool": "hvigor", + "directoryLevel": "project" + }, + "description": "example description", + "repository": {}, + "license": "ISC", + "dependencies": { + "@ohos/hypium": "1.0.1", + "@ohos/hvigor": "1.1.6", + "@ohos/hvigor-ohos-plugin": "1.1.6" + } +} diff --git a/Ability/Sensormock/hypium/LICENSE b/Ability/Sensormock/hypium/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..4947287f7b5ccb5d1e8b7b2d3aa5d89f322c160d --- /dev/null +++ b/Ability/Sensormock/hypium/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/Ability/Sensormock/hypium/README.OpenSource b/Ability/Sensormock/hypium/README.OpenSource new file mode 100644 index 0000000000000000000000000000000000000000..20515e91546dd51650db24d215f1584a3708e613 --- /dev/null +++ b/Ability/Sensormock/hypium/README.OpenSource @@ -0,0 +1,11 @@ +[ + { + "Name": "@ohos/hypium", + "License": "Apache-2.0 License", + "License File": " LICENSE ", + "Version Number": "1.0.0", + "Owner" : "", + "Upstream URL": "https://gitee.com/openharmony/arkXtest", + "Description": "A unit test framework for OpenHarmony application." + } +] \ No newline at end of file diff --git a/Ability/Sensormock/hypium/README.md b/Ability/Sensormock/hypium/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8b18b6990a77d5029f7ed70c78246d211e4d28f0 --- /dev/null +++ b/Ability/Sensormock/hypium/README.md @@ -0,0 +1,152 @@ +
Hypium
+
A unit test framework for OpenHarmonyOS application
+ +## Hypium是什么? +*** +- Hypium是OpenHarmony上的测试框架,提供测试用例编写、执行、结果显示能力,用于OpenHarmony系统应用接口以及应用界面测试。 +- Hypium结构化模型:hypium工程主要由List.test.js与TestCase.test.js组成。 +``` +rootProject // Hypium工程根目录 +├── moduleA +│   ├── src +│      ├── main // 被测试应用目录 +│      ├── ohosTest // 测试用例目录 +│         ├── js/ets +│            └── test +│               └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀 +│               └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀 +└── moduleB + ... +│               └── List.test.js // 测试用例加载脚本,ets目录下为.ets后缀 +│               └── TestCase.test.js // 测试用例脚本,ets目录下为.ets后缀 +``` + +## 安装使用 +*** +- 在DevEco Studio内使用Hypium +- 工程级package.json内配置: +```json +"dependencies": { + "@ohos/hypium": "1.0.0" +} +``` +注: +hypium服务于OpenHarmonyOS应用对外接口测试、系统对外接口测试(SDK中接口),完成HAP自动化测试。详细指导: +DevEco Studio + +- 通用语法 + + 测试用例采用业内通用语法,describe代表一个测试套, it代表一条用例。 + +| No. | API | 功能说明 | +| ---- | ---------- | ------------------------------------------------------------ | +| 1 | describe | 定义一个测试套,支持两个参数:测试套名称和测试套函数 | +| 2 | beforeAll | 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数 | +| 3 | beforeEach | 在测试套内定义一个单元预置条件,在每条测试用例开始前执行,执行次数与it定义的测试用例数一致,支持一个参数:预置动作函数 | +| 4 | afterEach | 在测试套内定义一个单元清理条件,在每条测试用例结束后执行,执行次数与it定义的测试用例数一致,支持一个参数:清理动作函数 | +| 5 | afterAll | 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数 | +| 6 | it | 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数 | +| 7 | expect | 支持bool类型判断等多种断言方法 | + +- 断言库 + + 示例代码: + +```javascript + expect(${actualvalue}).assertX(${expectvalue}) +``` + + 断言功能列表: + +| No. | API | 功能说明 | +| :--- | :--------------- | ------------------------------------------------------------ | +| 1 | assertClose | 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1) | +| 2 | assertContain | 检验actualvalue中是否包含expectvalue | +| 3 | assertEqual | 检验actualvalue是否等于expectvalue[0] | +| 4 | assertFail | 抛出一个错误 | +| 5 | assertFalse | 检验actualvalue是否是false | +| 6 | assertTrue | 检验actualvalue是否是true | +| 7 | assertInstanceOf | 检验actualvalue是否是expectvalue类型 | +| 8 | assertLarger | 检验actualvalue是否大于expectvalue | +| 9 | assertLess | 检验actualvalue是否小于expectvalue | +| 10 | assertNull | 检验actualvalue是否是null | +| 11 | assertThrowError | 检验actualvalue抛出Error内容是否是expectValue | +| 12 | assertUndefined | 检验actualvalue是否是undefined | + + 示例代码: + +```javascript + import { describe, it, expect } from '@ohos/hypium' + export default async function assertCloseTest() { + describe('assertClose', function () { + it('assertClose_success', 0, function () { + let a = 100 + let b = 0.1 + expect(a).assertClose(99, b) + }) + }) + } +``` +- 公共系统能力 + +| No. | API | 功能描述 | +| ---- | ------------------------------------------------------- | ------------------------------------------------------------ | +| 1 | existKeyword(keyword: string, timeout: number): boolean | hilog日志中查找指定字段是否存在,keyword是待查找关键字,timeout为设置的查找时间 | + + 示例代码: + +```javascript +import { describe, it, expect, SysTestKit} from '@ohos/hypium' + +export default function existKeywordTest() { + describe('existKeywordTest', function () { + it('existKeyword',DEFAULT, async function () { + console.info("HelloTest") + let isExist = await SysTestKit.existKeyword('HelloTest') + console.info('isExist ------>' + isExist) + }) + }) +} +``` +- 专项能力 +用例筛选能力:hypium支持根据用例属性筛选执行指定测试用例,使用方式是在测试应用的启动shell命令后新增" -s ${Key} ${Value}"。 + +| Key | 含义说明 | Value取值范围 | +| ---- | ------------------------------------------------------- | ------------------------------------------------------------ | +| level | 用例级别 | "0","1","2","3","4" | +| size | 用例粒度 | "small","medium","large" | +| testType | 用例测试类型 | "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience" | + + 示例代码 + +```javascript +import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium' + +export default function attributeTest() { + describe('attributeTest', function () { + it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, function () { + console.info('Hello Test') + }) + }) +} +``` + + +## 约束 +*** + 本模块首批接口从OpenHarmony SDK API version 8开始支持。 + +## Hypium开放能力隐私声明 + +- 我们如何收集和使用您的个人信息 + 您在使用集成了Hypium开放能力的测试应用时,Hypium不会处理您的个人信息。 +- SDK处理的个人信息 + 不涉及。 +- SDK集成第三方服务声明 + 不涉及。 +- SDK数据安全保护 + 不涉及。 +- SDK版本更新声明 + 为了向您提供最新的服务,我们会不时更新Hypium版本。我们强烈建议开发者集成使用最新版本的Hypium。 + + diff --git a/Ability/Sensormock/hypium/index.d.ts b/Ability/Sensormock/hypium/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0be3926c7146cc28770d93a5c7718a0f21e2faf2 --- /dev/null +++ b/Ability/Sensormock/hypium/index.d.ts @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const DEFAULT = 0B0000 + +export const when: when; + +export enum TestType { + FUNCTION = 0B1, + PERFORMANCE = 0B1 << 1, + POWER = 0B1 << 2, + RELIABILITY = 0B1 << 3, + SECURITY = 0B1 << 4, + GLOBAL = 0B1 << 5, + COMPATIBILITY = 0B1 << 6, + USER = 0B1 << 7, + STANDARD = 0B1 << 8, + SAFETY = 0B1 << 9, + RESILIENCE = 0B1 << 10 +} + +export enum Size { + SMALLTEST = 0B1 << 16, + MEDIUMTEST = 0B1 << 17, + LARGETEST = 0B1 << 18 +} + +export enum Level { + LEVEL0 = 0B1 << 24, + LEVEL1 = 0B1 << 25, + LEVEL2 = 0B1 << 26, + LEVEL3 = 0B1 << 27, + LEVEL4 = 0B1 << 28 +} + +export function describe(testSuiteName: string, callback: Function): void + +export function beforeEach(callback: Function): void + +export function afterEach(callback: Function): void + +export function beforeAll(callback: Function): void + +export function afterAll(callback: Function): void + +export function it(testCaseName: string, attribute: (TestType | Size | Level), callback: Function) + +export interface Assert { + assertClose(expectValue: number, precision: number): void + assertContain(expectValue: any): void + assertEqual(expectValue: any): void + assertFail(): void + assertFalse(): void + assertTrue(): void + assertInstanceOf(expectValue: string): void + assertLarger(expectValue: number): void + assertLess(expectValue: number): void + assertNull(): void + assertThrowError(expectValue: string): void + assertUndefined(): void +} + +export function expect(actualValue?: any): Assert + +export class ArgumentMatchers { + static any; + static anyString; + static anyBoolean; + static anyNumber; + static anyObj; + static anyFunction; + static matchRegexs(Regex: RegExp): void +} + +declare interface when { + afterReturn(value: any): any + afterReturnNothing(): undefined + afterAction(action: any): any + afterThrow(e_msg: string): string + (argMatchers: any): when; +} + +export interface VerificationMode { + times(count: Number): void + never(): void + once(): void + atLeast(count: Number): void + atMost(count: Number): void +} + +export class MockKit { + constructor() + mockFunc(obj: Object, func: Function): Function + mockObject(obj: Object): Object + verify(methodName: String, argsArray: Array): VerificationMode + ignoreMock(obj: Object, func: Function): void + clear(obj: Object): void + clearAll(): void +} + +export class SysTestKit { + static actionStart(tag: string): void + static actionEnd(tag: string): void + static existKeyword(keyword: string, timeout?: number): boolean +} + +export class Hypium { + static setData(data: {[key: string]: any}): void + static hypiumTest(abilityDelegator: any, abilityDelegatorArguments: any, testsuite: Function): void +} \ No newline at end of file diff --git a/Ability/Sensormock/hypium/index.ets b/Ability/Sensormock/hypium/index.ets new file mode 100644 index 0000000000000000000000000000000000000000..b778d290cc41195afce90a5629c2cfc950b64558 --- /dev/null +++ b/Ability/Sensormock/hypium/index.ets @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Core from './src/core' +import {DEFAULT, TestType, Size, Level} from './src/Constant' +import DataDriver from './src/module/config/DataDriver' +import ExpectExtend from './src/module/assert/ExpectExtend' +import OhReport from './src/module/report/OhReport' +import SysTestKit from './src/module/kit/SysTestKit' +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from './src/interface' +import {MockKit, when} from './src/module/mock/MockKit'; +import ArgumentMatchers from './src/module/mock/ArgumentMatchers'; + +function dryRun(core, testParameters, abilityDelegator) { + if (testParameters['dryRun'] === 'true') { + let testSuitesObj = {} + let suitesArray = [] + const suiteService = core.getDefaultService('suite') + for (const suiteItem of suiteService.rootSuite.childSuites) { + let itArray = [] + let suiteName = suiteItem['description'] + for (const itItem of suiteItem['specs']) { + itArray.push({'itName': itItem['description']}) + } + let obj = {} + obj[suiteName] = itArray + suitesArray.push(obj) + } + testSuitesObj['suites'] = suitesArray + + let strJson = JSON.stringify(testSuitesObj) + let strLen = strJson.length + let maxLen = 500 + let maxCount = Math.floor(strLen / maxLen) + + for (let count = 0; count <= maxCount; count++) { + abilityDelegator.print(strJson.substring(count * maxLen, (count + 1) * maxLen)) + } + console.info('dryRun print success') + abilityDelegator.finishTest('dry run finished!!!', 0, () => { }) + return true + } + return false +} + +class Hypium { + static setData(data) { + const core = Core.getInstance() + const dataDriver = new DataDriver({data}) + core.addService('dataDriver', dataDriver) + } + + static hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) { + const core = Core.getInstance() + const expectExtend = new ExpectExtend({ + 'id': 'extend' + }) + core.addService('expect', expectExtend) + const ohReport = new OhReport({ + 'delegator': abilityDelegator + }) + SysTestKit.delegator = abilityDelegator + core.addService('report', ohReport) + core.init() + core.subscribeEvent('spec', ohReport) + core.subscribeEvent('suite', ohReport) + core.subscribeEvent('task', ohReport) + const configService = core.getDefaultService('config') + let testParameters = configService.translateParams(abilityDelegatorArguments.parameters) + console.info('parameters:' + JSON.stringify(testParameters)) + configService.setConfig(testParameters) + testsuite() + if (dryRun(core, testParameters, abilityDelegator)) { + return + } + if (Object.prototype.hasOwnProperty.call(globalThis, 'setupUiTestEnvironment')) { + globalThis.setupUiTestEnvironment().then(() => { + console.info('UiTestKit::after run uitest setup, start run testcases') + core.execute() + }).catch((error) => { + console.error('UiTestKit:: call setupUiTestEnvironment failure:' + error) + core.execute() + }) + } else { + console.info('UiTestKit:: no need to setup uitest, start run testcases') + core.execute() + } + } +} + +export { + Hypium, + Core, + DEFAULT, + TestType, + Size, + Level, + DataDriver, + ExpectExtend, + OhReport, + SysTestKit, + describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, + MockKit, when, + ArgumentMatchers +} \ No newline at end of file diff --git a/Ability/Sensormock/hypium/index.js b/Ability/Sensormock/hypium/index.js new file mode 100644 index 0000000000000000000000000000000000000000..9ca084f253f0756acae4c64bd6edcf08032746eb --- /dev/null +++ b/Ability/Sensormock/hypium/index.js @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Core from './src/core'; +import {DEFAULT, TestType, Size, Level} from './src/Constant'; +import DataDriver from './src/module/config/DataDriver'; +import ExpectExtend from './src/module/assert/ExpectExtend'; +import OhReport from './src/module/report/OhReport'; +import SysTestKit from './src/module/kit/SysTestKit'; +import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from './src/interface'; +import {MockKit, when} from './src/module/mock/MockKit'; +import ArgumentMatchers from './src/module/mock/ArgumentMatchers'; + +function dryRun(core, testParameters, abilityDelegator) { + if (testParameters['dryRun'] === 'true') { + let testSuitesObj = {}; + let suitesArray = []; + const suiteService = core.getDefaultService('suite'); + for (const suiteItem of suiteService.rootSuite.childSuites) { + let itArray = []; + let suiteName = suiteItem['description']; + for (const itItem of suiteItem['specs']) { + itArray.push({'itName': itItem['description']}); + } + let obj = {}; + obj[suiteName] = itArray; + suitesArray.push(obj); + } + testSuitesObj['suites'] = suitesArray; + + let strJson = JSON.stringify(testSuitesObj); + let strLen = strJson.length; + let maxLen = 500; + let maxCount = Math.floor(strLen / maxLen); + + for (let count = 0; count <= maxCount; count++) { + abilityDelegator.print(strJson.substring(count * maxLen, (count + 1) * maxLen)); + } + console.info('dryRun print success'); + abilityDelegator.finishTest('dry run finished!!!', 0, () => { }); + return true; + } + return false; +} + +class Hypium { + static setData(data) { + const core = Core.getInstance(); + const dataDriver = new DataDriver({data}); + core.addService('dataDriver', dataDriver); + } + + static hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) { + const core = Core.getInstance(); + const expectExtend = new ExpectExtend({ + 'id': 'extend' + }); + core.addService('expect', expectExtend); + const ohReport = new OhReport({ + 'delegator': abilityDelegator + }); + SysTestKit.delegator = abilityDelegator; + core.addService('report', ohReport); + core.init(); + core.subscribeEvent('spec', ohReport); + core.subscribeEvent('suite', ohReport); + core.subscribeEvent('task', ohReport); + const configService = core.getDefaultService('config'); + let testParameters = configService.translateParams(abilityDelegatorArguments.parameters); + console.info('parameters:' + JSON.stringify(testParameters)); + configService.setConfig(testParameters); + testsuite(); + if (dryRun(core, testParameters, abilityDelegator)) { + return; + } + if (Object.prototype.hasOwnProperty.call(globalThis, 'setupUiTestEnvironment')) { + globalThis.setupUiTestEnvironment().then(() => { + console.info('UiTestKit::after run uitest setup, start run testcases'); + core.execute(); + }).catch((error) => { + console.error('UiTestKit:: call setupUiTestEnvironment failure:' + error); + core.execute(); + }); + } else { + console.info('UiTestKit:: no need to setup uitest, start run testcases'); + core.execute(); + } + } +} + +export { + Hypium, + Core, + DEFAULT, + TestType, + Size, + Level, + DataDriver, + ExpectExtend, + OhReport, + SysTestKit, + describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, + MockKit, when, + ArgumentMatchers +}; \ No newline at end of file diff --git a/Ability/Sensormock/hypium/package.json b/Ability/Sensormock/hypium/package.json new file mode 100644 index 0000000000000000000000000000000000000000..dbac727312699a5b8b8a2ad8fb2b8a253b3b1077 --- /dev/null +++ b/Ability/Sensormock/hypium/package.json @@ -0,0 +1,50 @@ +{ + "_from": "@ohos/hypium@1.0.1", + "_id": "@ohos/hypium@1.0.1", + "_inBundle": false, + "_integrity": "sha512-HaztFbgwYZCdVlayXirBlmJaNTXUO65qRgYnUmrhWGEzG7wFU2fyFbeXgQeYMVWFXgeezFOoHAPoS96TEE7TIQ==", + "_location": "/@ohos/hypium", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "@ohos/hypium@1.0.1", + "name": "@ohos/hypium", + "escapedName": "@ohos%2fhypium", + "scope": "@ohos", + "rawSpec": "1.0.1", + "saveSpec": null, + "fetchSpec": "1.0.1" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://repo.harmonyos.com/npm/@ohos/hypium/-/@ohos/hypium-1.0.1.tgz", + "_shasum": "788c286f5b18e41774c606d12fd93f625a4318ed", + "_spec": "@ohos/hypium@1.0.1", + "_where": "C:\\Users\\Administrator\\DevEcoStudioProjects\\SensorSimulateDemo", + "author": "", + "bundleDependencies": false, + "dependencies": {}, + "deprecated": false, + "description": "A unit test framework for OpenHarmony application.", + "keywords": [ + "OpenHarmony", + "hypium" + ], + "license": "Apache-2.0", + "main": "index.js", + "name": "@ohos/hypium", + "ohos": { + "org": "ohos" + }, + "repository": { + "type": "git", + "url": "https://gitee.com/openharmony/arkXtest" + }, + "tags": [ + "OpenHarmony", + "hypium" + ], + "version": "1.0.1" +} diff --git a/Ability/Sensormock/hypium/src/Constant.js b/Ability/Sensormock/hypium/src/Constant.js new file mode 100644 index 0000000000000000000000000000000000000000..f1829107720a64df7b571a4bfd11a25e6d9022b6 --- /dev/null +++ b/Ability/Sensormock/hypium/src/Constant.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * define the testcase type : TestType, Size , Level + */ +export const DEFAULT = 0B0000; + +export class TestType { + static FUNCTION = 0B1; + static PERFORMANCE = 0B1 << 1; + static POWER = 0B1 << 2; + static RELIABILITY = 0B1 << 3; + static SECURITY = 0B1 << 4; + static GLOBAL = 0B1 << 5; + static COMPATIBILITY = 0B1 << 6; + static USER = 0B1 << 7; + static STANDARD = 0B1 << 8; + static SAFETY = 0B1 << 9; + static RESILIENCE = 0B1 << 10; +} + +export class Size { + static SMALLTEST = 0B1 << 16; + static MEDIUMTEST = 0B1 << 17; + static LARGETEST = 0B1 << 18; +} + +export class Level { + static LEVEL0 = 0B1 << 24; + static LEVEL1 = 0B1 << 25; + static LEVEL2 = 0B1 << 26; + static LEVEL3 = 0B1 << 27; + static LEVEL4 = 0B1 << 28; +} diff --git a/Ability/Sensormock/hypium/src/core.js b/Ability/Sensormock/hypium/src/core.js new file mode 100644 index 0000000000000000000000000000000000000000..0daf042635bf5b98815e4e06d96bfcba74e6e756 --- /dev/null +++ b/Ability/Sensormock/hypium/src/core.js @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {SuiteService, SpecService, ExpectService, ReportService} from './service'; +import {ConfigService} from './module/config/configService'; +import {SpecEvent, TaskEvent, SuiteEvent} from './event'; + +/** + * core service for execute testcase. + */ +class Core { + static getInstance() { + if (!this.instance) { + this.instance = new Core(); + } + return this.instance; + } + + constructor() { + this.instance = null; + this.services = { + suite: {}, + spec: {}, + config: {}, + expect: {}, + log: {}, + report: {} + + }; + this.events = { + suite: {}, + spec: {}, + task: {} + }; + } + + addService(name, service) { + let serviceObj = {}; + if (!this.services[name]) { + this.services[name] = serviceObj; + } else { + serviceObj = this.services[name]; + } + serviceObj[service.id] = service; + } + + getDefaultService(name) { + return this.services[name].default; + } + + getServices(name) { + return this.services[name]; + } + + registerEvent(serviceName, event) { + let eventObj = {}; + if (!this.events[serviceName]) { + this.events[serviceName] = eventObj; + } else { + eventObj = this.events[serviceName]; + } + eventObj[event.id] = event; + } + + unRegisterEvent(serviceName, eventID) { + const eventObj = this.events[serviceName]; + if (eventObj) { + delete eventObj[eventID]; + } + } + + subscribeEvent(serviceName, serviceObj) { + const eventObj = this.events[serviceName]; + if (eventObj) { + for (const attr in eventObj) { + eventObj[attr]['subscribeEvent'](serviceObj); + } + } + } + + fireEvents(serviceName, eventName) { + const eventObj = this.events[serviceName]; + if (!eventObj) { + return; + } + for (const attr in eventObj) { + eventObj[attr][eventName](); + } + } + + addToGlobal(apis) { + if (typeof globalThis !== 'undefined') { + for (let api in apis) { + globalThis[api] = apis[api]; + } + } + for (const api in apis) { + this[api] = apis[api]; + } + } + + init() { + this.addService('suite', new SuiteService({id: 'default'})); + this.addService('spec', new SpecService({id: 'default'})); + this.addService('expect', new ExpectService({id: 'default'})); + this.addService('report', new ReportService({id: 'default'})); + this.addService('config', new ConfigService({id: 'default'})); + this.registerEvent('task', new TaskEvent({id: 'default', coreContext: this})); + this.registerEvent('suite', new SuiteEvent({id: 'default', coreContext: this})); + this.registerEvent('spec', new SpecEvent({id: 'default', coreContext: this})); + this.subscribeEvent('spec', this.getDefaultService('report')); + this.subscribeEvent('suite', this.getDefaultService('report')); + this.subscribeEvent('task', this.getDefaultService('report')); + const context = this; + for (const key in this.services) { + const serviceObj = this.services[key]; + for (const serviceID in serviceObj) { + const service = serviceObj[serviceID]; + service.init(context); + + if (typeof service.apis !== 'function') { + continue; + } + const apis = service.apis(); + if (apis) { + this.addToGlobal(apis); + } + } + } + } + + execute() { + const suiteService = this.getDefaultService('suite'); + suiteService.execute(); + } +} + +export default Core; diff --git a/Ability/Sensormock/hypium/src/event.js b/Ability/Sensormock/hypium/src/event.js new file mode 100644 index 0000000000000000000000000000000000000000..28299c36697a833d0a3e7887d2f3439271b69888 --- /dev/null +++ b/Ability/Sensormock/hypium/src/event.js @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class SpecEvent { + constructor(attr) { + this.id = attr.id; + this.coreContext = attr.context; + this.eventMonitors = []; + } + + subscribeEvent(service) { + this.eventMonitors.push(service); + } + + specStart() { + for (let monitor in this.eventMonitors) { + this.eventMonitors[monitor]['specStart'](); + } + } + + specDone() { + for (const monitor in this.eventMonitors) { + this.eventMonitors[monitor]['specDone'](); + } + } +} + +class SuiteEvent { + constructor(attr) { + this.id = attr.id; + this.suiteContext = attr.coreContext; + this.eventMonitors = []; + } + + subscribeEvent(service) { + this.eventMonitors.push(service); + } + + suiteStart() { + for (let monitor in this.eventMonitors) { + this.eventMonitors[monitor]['suiteStart'](); + } + } + + suiteDone() { + for (let monitor in this.eventMonitors) { + this.eventMonitors[monitor]['suiteDone'](); + } + } +} + +class TaskEvent { + constructor(attr) { + this.id = attr.id; + this.coreContext = attr.coreContext; + this.eventMonitors = []; + } + + subscribeEvent(service) { + this.eventMonitors.push(service); + } + + taskStart() { + for (let monitor in this.eventMonitors) { + this.eventMonitors[monitor]['taskStart'](); + } + } + + taskDone() { + for (let monitor in this.eventMonitors) { + this.eventMonitors[monitor]['taskDone'](); + } + } + + incorrectFormat() { + for (let monitor in this.eventMonitors) { + this.eventMonitors[monitor]['incorrectFormat'](); + } + } +} + +export {SpecEvent, TaskEvent, SuiteEvent}; diff --git a/Ability/Sensormock/hypium/src/interface.js b/Ability/Sensormock/hypium/src/interface.js new file mode 100644 index 0000000000000000000000000000000000000000..b4f145dccfa405f90d150a20abd8fd8d10539431 --- /dev/null +++ b/Ability/Sensormock/hypium/src/interface.js @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Core from './core'; + +const core = Core.getInstance(); + +const describe = function (desc, func) { + if (typeof globalThis !== 'undefined') { + return globalThis.describe(desc, func); + } + return core.describe(desc, func); +}; +const it = function (desc, filter, func) { + if (typeof globalThis !== 'undefined') { + return globalThis.it(desc, filter, func); + } + return core.it(desc, filter, func); +}; +const beforeEach = function (func) { + if (typeof globalThis !== 'undefined') { + return globalThis.beforeEach(func); + } + return core.beforeEach(func); +}; +const afterEach = function (func) { + if (typeof globalThis !== 'undefined') { + return globalThis.afterEach(func); + } + return core.afterEach(func); +}; +const beforeAll = function (func) { + if (typeof globalThis !== 'undefined') { + return globalThis.beforeAll(func); + } + return core.beforeAll(func); +}; +const afterAll = function (func) { + if (typeof globalThis !== 'undefined') { + return globalThis.afterAll(func); + } + return core.afterAll(func); +}; +const expect = function (actualValue) { + if (typeof globalThis !== 'undefined') { + return globalThis.expect(actualValue); + } + return core.expect(actualValue); +}; + +export { + describe, it, beforeAll, beforeEach, afterEach, afterAll, expect +}; diff --git a/Ability/Sensormock/hypium/src/module/assert/ExpectExtend.js b/Ability/Sensormock/hypium/src/module/assert/ExpectExtend.js new file mode 100644 index 0000000000000000000000000000000000000000..9ea94a9415bc5f7c5d7cfcddb94cab26a1f01e25 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/ExpectExtend.js @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assertNull from './assertNull'; +import assertClose from './assertClose'; +import assertContain from './assertContain'; +import assertLess from './assertLess'; +import assertLarger from './assertLarger'; +import assertFail from './assertFail'; +import assertUndefined from './assertUndefined'; +import assertFalse from './assertFalse'; +import assertInstanceOf from './assertInstanceOf'; +import assertThrowError from './assertThrowError'; + +class ExpectExtend { + constructor(attr) { + this.id = attr.id; + this.matchers = {}; + } + + extendsMatchers() { + this.matchers.assertNull = assertNull; + this.matchers.assertClose = assertClose; + this.matchers.assertContain = assertContain; + this.matchers.assertLess = assertLess; + this.matchers.assertLarger = assertLarger; + this.matchers.assertFail = assertFail; + this.matchers.assertUndefined = assertUndefined; + this.matchers.assertFalse = assertFalse; + this.matchers.assertInstanceOf = assertInstanceOf; + this.matchers.assertThrowError = assertThrowError; + } + + init(coreContext) { + this.coreContext = coreContext; + this.extendsMatchers(); + const expectService = this.coreContext.getDefaultService('expect'); + expectService.addMatchers(this.matchers); + } + + apis() { + return { + 'expect': function (actualValue) { + return this.coreContext.getDefaultService('expect').expect(actualValue); + } + }; + } +} + +export default ExpectExtend; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertClose.js b/Ability/Sensormock/hypium/src/module/assert/assertClose.js new file mode 100644 index 0000000000000000000000000000000000000000..63635bea5bf1298776de565260e0e0babae56857 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertClose.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertClose(actualValue, expected) { + console.log('expected:' + expected[0] + ',precision:' + expected[1]); + if (actualValue === null && expected[0] === null) { + throw new Error('actualValue and expected can not be both null!!!'); + } + let result; + let diff = Math.abs(expected[0] - actualValue); + let actualAbs = Math.abs(actualValue); + if ((actualAbs - 0) === 0) { + if ((diff - 0) === 0) { + result = true; + } else { + result = false; + } + } else if (diff / actualAbs < expected[1]) { + result = true; + } else { + result = false; + } + return { + pass: result, + message: '|' + actualValue + ' - ' + expected[0] + '|/' + actualValue + ' is not less than ' + expected[1] + }; +} + +export default assertClose; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertContain.js b/Ability/Sensormock/hypium/src/module/assert/assertContain.js new file mode 100644 index 0000000000000000000000000000000000000000..6b33e08ba38479895bfa428957fd02224c08caa8 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertContain.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertContain(actualValue, expect) { + let result = false; + if (Object.prototype.toString.call(actualValue).indexOf('Array')) { + for (let i in actualValue) { + if (actualValue[i] == expect[0]) { + result = true; + } + } + } + let type = Object.prototype.toString.call(actualValue); + if (type === '[object String]') { + result = actualValue.indexOf(expect[0]) >= 0; + } + return { + pass: result, + message: 'except false, ' + actualValue + ' do not have ' + expect[0] + }; +} + +export default assertContain; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertFail.js b/Ability/Sensormock/hypium/src/module/assert/assertFail.js new file mode 100644 index 0000000000000000000000000000000000000000..8ab4ac5caef712c75c4eac49dfbbb91d33669d9a --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertFail.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertFail() { + return { + pass: false, + message: 'fail ' + }; +} + +export default assertFail; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertFalse.js b/Ability/Sensormock/hypium/src/module/assert/assertFalse.js new file mode 100644 index 0000000000000000000000000000000000000000..5800fc7ffd0fdce8189d8af329beba830cfd8350 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertFalse.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertFalse(actualValue) { + return { + pass: (actualValue) === false, + message: 'except false, actualValue is ' + actualValue + }; +} + +export default assertFalse; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertInstanceOf.js b/Ability/Sensormock/hypium/src/module/assert/assertInstanceOf.js new file mode 100644 index 0000000000000000000000000000000000000000..1e11b93f7251c67f5455c5007cd7be268aa53b32 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertInstanceOf.js @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertInstanceOf(actualValue, expected) { + if (Object.prototype.toString.call(actualValue) == '[object ' + expected[0] + ']') { + return { + pass: true + }; + } else { + return { + pass: false, + message: actualValue + ' is ' + Object.prototype.toString.call(actualValue) + 'not ' + expected[0] + }; + } +} + +export default assertInstanceOf; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertLarger.js b/Ability/Sensormock/hypium/src/module/assert/assertLarger.js new file mode 100644 index 0000000000000000000000000000000000000000..a74f4a8cedaf3add9c2dc2d3799081a83198732f --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertLarger.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertLarger(actualValue, expected) { + return { + pass: (actualValue) > expected[0], + message: (actualValue) + ' is not larger than ' + expected[0] + }; +} + +export default assertLarger; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertLess.js b/Ability/Sensormock/hypium/src/module/assert/assertLess.js new file mode 100644 index 0000000000000000000000000000000000000000..17e84b0abaeb20804048a5a15c19e0603634846d --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertLess.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertLess(actualValue, expected) { + return { + pass: (actualValue) < expected[0], + message: (actualValue) + ' is not less than ' + expected[0] + }; +} + +export default assertLess; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertNull.js b/Ability/Sensormock/hypium/src/module/assert/assertNull.js new file mode 100644 index 0000000000000000000000000000000000000000..53a7bad827323a98d3302a4e7eea679551b459c5 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertNull.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertNull(actualValue) { + return { + pass: (actualValue) === null, + message: 'expect null, actualValue is ' + (actualValue) + }; +} + +export default assertNull; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertThrowError.js b/Ability/Sensormock/hypium/src/module/assert/assertThrowError.js new file mode 100644 index 0000000000000000000000000000000000000000..749cab0daee3f156909f60c9375146c23d7aa322 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertThrowError.js @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertThrowError(actualValue, expected) { + let result = false; + let err; + if (typeof actualValue !== 'function') { + throw new Error('actualValue is not a function'); + } + try { + actualValue(); + return { + pass: result, + message: ' An error is not thrown while it is expected!' + }; + } catch (e) { + err = e; + } + + if (err instanceof Error) { + console.log(err.message); + if (err.message == expected[0]) { + result = true; + } + } + return { + pass: result, + message: 'expected throw failed , ' + err.message + ' is not ' + expected[0] + }; +} + +export default assertThrowError; diff --git a/Ability/Sensormock/hypium/src/module/assert/assertUndefined.js b/Ability/Sensormock/hypium/src/module/assert/assertUndefined.js new file mode 100644 index 0000000000000000000000000000000000000000..61f092d715dd1630297518b59ff13ef0940991e1 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/assertUndefined.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function assertUndefined(actualValue) { + return { + pass: undefined === (actualValue), + message: 'expect Undefined, actualValue is ' + (actualValue) + }; +} + +export default assertUndefined; diff --git a/Ability/Sensormock/hypium/src/module/assert/isPromiseLike.js b/Ability/Sensormock/hypium/src/module/assert/isPromiseLike.js new file mode 100644 index 0000000000000000000000000000000000000000..015ab19a2a0c4872d7cb490b61f8e1dd6a8ac90b --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/assert/isPromiseLike.js @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function isPromiseLike(obj) { + return !!obj && isFunction_(obj.then); +} + +function isFunction_(value) { + return isA_('Function', value); +} + +function isA_(typeName, value) { + return getType_(value) === '[object ' + typeName + ']'; +} + +function getType_(value) { + return Object.prototype.toString.apply(value); +} + +export default isPromiseLike; diff --git a/Ability/Sensormock/hypium/src/module/config/DataDriver.js b/Ability/Sensormock/hypium/src/module/config/DataDriver.js new file mode 100644 index 0000000000000000000000000000000000000000..e521e455b26290fefae4c3bb5785b8d32271baad --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/config/DataDriver.js @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const SUITES_KEY = 'suites'; +const SPECS_KEY = 'items'; +const DESCRIBE_KEY = 'describe'; +const IT_KEY = 'it'; +const PARAMS_KEY = 'params'; +const STRESS_KEY = 'stress'; + +class ObjectUtils { + static get(object, name, defaultValue) { + let result = defaultValue; + for (const key in object) { + if (key === name) { + return object[key]; + } + } + return result; + } + + static has(object, key) { + return Object.prototype.hasOwnProperty.call(object, key); + } +} + +class DataDriver { + constructor(attr) { + this.id = 'dataDriver'; + this.data = attr.data || {}; + } + + init(coreContext) { + this.coreContext = coreContext; + this.suiteService = this.coreContext.getDefaultService('suite'); + this.specService = this.coreContext.getDefaultService('spec'); + } + + getSpecParams() { + let specParams = []; + let suiteDesc = this.suiteService.getCurrentRunningSuite().description; + let specDesc = this.specService.getCurrentRunningSpec().description; + let suites = ObjectUtils.get(this.data, SUITES_KEY, []); + for (const suiteItem of suites) { + let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, ''); + if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && describeValue === suiteDesc && (typeof describeValue === 'string') && describeValue.constructor === String) { + let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []); + for (const specItem of specs) { + if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) { + return ObjectUtils.get(specItem, PARAMS_KEY, specParams); + } + } + } + } + return specParams; + } + + getSuiteParams() { + let suiteParams = {}; + let suiteDesc = this.suiteService.getCurrentRunningSuite().description; + let suites = ObjectUtils.get(this.data, SUITES_KEY, []); + for (const suiteItem of suites) { + let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []); + if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) { + suiteParams = Object.assign({}, suiteParams, ObjectUtils.get(suiteItem, PARAMS_KEY, suiteParams)); + } + } + return suiteParams; + } + + getSpecStress(specDesc) { + let stress = 1; + let suiteDesc = this.suiteService.getCurrentRunningSuite().description; + let suites = ObjectUtils.get(this.data, SUITES_KEY, []); + for (const suiteItem of suites) { + let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, ''); + if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && describeValue === suiteDesc && (typeof describeValue === 'string') && describeValue.constructor === String) { + let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []); + for (const specItem of specs) { + if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) { + let tempStress = ObjectUtils.get(specItem, STRESS_KEY, stress); + return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress; + } + } + } + } + return stress; + } + + getSuiteStress(suiteDesc) { + let stress = 1; + let suites = ObjectUtils.get(this.data, SUITES_KEY, []); + for (const suiteItem of suites) { + let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []); + if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && describeValue === suiteDesc && (typeof describeValue === 'string') && describeValue.constructor === String) { + let tempStress = ObjectUtils.get(suiteItem, STRESS_KEY, stress); + return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress; + } + } + return stress; + } +} + +export default DataDriver; diff --git a/Ability/Sensormock/hypium/src/module/config/Filter.js b/Ability/Sensormock/hypium/src/module/config/Filter.js new file mode 100644 index 0000000000000000000000000000000000000000..356e5bc4c00cc04375105461e3ae0acd43494d3e --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/config/Filter.js @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class ClassFilter { + constructor(suiteName, itName, params) { + this.suiteName = suiteName; + this.itName = itName; + this.params = params; + } + + filterSuite() { + return !this.params.split(',').map(item => item.split('#')[0]).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false); + } + + filterIt() { + let classArray = this.params.split(',') || []; + let suiteFilterResult = classArray.filter(item => !item.includes('#')).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false); + let itFilterResult = classArray.filter(item => item.includes('#')).map(item => item == (this.suiteName + '#' + this.itName)).reduce((pre, cur) => pre || cur, false); + return !(suiteFilterResult || itFilterResult); + } +} + +class NotClassFilter { + constructor(suiteName, itName, params) { + this.suiteName = suiteName; + this.itName = itName; + this.params = params; + } + + filterSuite() { + return this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false); + } + + filterIt() { + return this.params.includes(this.suiteName + '#' + this.itName); + } +} + +class SuiteAndItNameFilter { + constructor(suiteName, itName, params) { + this.suiteName = suiteName; + this.itName = itName; + this.params = params; + } + + filterSuite() { + return !this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false); + } + + filterIt() { + return !this.params.split(',').map(item => item == this.itName).reduce((pre, cur) => pre || cur, false); + } +} + + +class TestTypesFilter { + constructor(suiteName, itName, fi, params) { + this.suiteName = suiteName; + this.itName = itName; + this.params = params; + this.fi = fi; + } + + filterIt() { + return !((this.params === (this.fi & this.params)) || this.fi === 0); + } +} + +export {ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter}; diff --git a/Ability/Sensormock/hypium/src/module/config/configService.js b/Ability/Sensormock/hypium/src/module/config/configService.js new file mode 100644 index 0000000000000000000000000000000000000000..682fd1431322dcfa60c05d781966454d80b29400 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/config/configService.js @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter} from './Filter'; + +class ConfigService { + constructor(attr) { + this.id = attr.id; + this.supportAsync = false; + this.random = false; + this.filterValid = []; + } + + init(coreContext) { + this.coreContext = coreContext; + } + + isNormalInteger(str) { + const n = Math.floor(Number(str)); + return n !== Infinity && String(n) === String(str) && n >= 0; + } + + basicParamValidCheck(params) { + let size = params.size; + if (size !== undefined && size !== '' && size !== null) { + let sizeArray = ['small', 'medium', 'large']; + if (sizeArray.indexOf(size) === -1) { + this.filterValid.push('size:' + size); + } + } + let level = params.level; + if (level !== undefined && level !== '' && level !== null) { + let levelArray = ['0', '1', '2', '3', '4']; + if (levelArray.indexOf(level) === -1) { + this.filterValid.push('level:' + level); + } + } + let testType = params.testType; + if (testType !== undefined && testType !== '' && testType !== null) { + let testTypeArray = ['function', 'performance', 'power', 'reliability', 'security', + 'global', 'compatibility', 'user', 'standard', 'safety', 'resilience']; + if (testTypeArray.indexOf(testType) === -1) { + this.filterValid.push('testType:' + testType); + } + } + } + + filterParamValidCheck(params) { + let timeout = params.timeout; + if (timeout !== undefined && timeout !== '' && timeout !== null) { + if (!this.isNormalInteger(timeout)) { + this.filterValid.push('timeout:' + timeout); + } + } + + if (params.dryRun !== undefined && params.dryRun !== 'true' && params.dryRun !== 'false') { + this.filterValid.push('dryRun:' + params.dryRun); + } + + let classes = params.class; + let nameRule = /^[A-Za-z]{1}[\w#,.]*$/; + if (classes !== undefined && classes !== '' && classes !== null) { + let classArray = classes.split(','); + for (let className of classArray) { + if (!className.match(nameRule)) { + this.filterValid.push('class:' + classes); + break; + } + } + } + let notClasses = params.notClass; + if (notClasses !== undefined && notClasses !== '' && notClasses !== null) { + let notClassArray = notClasses.split(','); + for (let notClassName of notClassArray) { + if (!notClassName.match(nameRule)) { + this.filterValid.push('notClass:' + notClasses); + break; + } + } + } + } + + setConfig(params) { + this.basicParamValidCheck(params); + this.filterParamValidCheck(params); + try { + this.class = params.class; + this.notClass = params.notClass; + this.flag = params.flag || {flag: false}; + this.suite = params.suite; + this.itName = params.itName; + this.filter = params.filter; + this.testType = params.testType; + this.level = params.level; + this.size = params.size; + this.timeout = params.timeout; + this.filterParam = { + testType: { + 'function': 1, + 'performance': 1 << 1, + 'power': 1 << 2, + 'reliability': 1 << 3, + 'security': 1 << 4, + 'global': 1 << 5, + 'compatibility': 1 << 6, + 'user': 1 << 7, + 'standard': 1 << 8, + 'safety': 1 << 9, + 'resilience': 1 << 10, + }, + level: { + '0': 1 << 24, + '1': 1 << 25, + '2': 1 << 26, + '3': 1 << 27, + '4': 1 << 28, + }, + size: { + 'small': 1 << 16, + 'medium': 1 << 17, + 'large': 1 << 18, + } + }; + this.parseParams(); + } catch (err) { + this.filter = 0; + this.flag = false; + this.suite = null; + this.itName = null; + this.testType = null; + this.level = null; + this.size = null; + this.class = null; + this.notClass = null; + this.timeout = null; + } + } + + parseParams() { + if (this.filter != null) { + return; + } + let testTypeFilter = 0; + let sizeFilter = 0; + let levelFilter = 0; + if (this.testType != null) { + testTypeFilter = this.testType.split(',') + .map(item => this.filterParam.testType[item] || 0) + .reduce((pre, cur) => pre | cur, 0); + } + if (this.level != null) { + levelFilter = this.level.split(',') + .map(item => this.filterParam.level[item] || 0) + .reduce((pre, cur) => pre | cur, 0); + } + if (this.size != null) { + sizeFilter = this.size.split(',') + .map(item => this.filterParam.size[item] || 0) + .reduce((pre, cur) => pre | cur, 0); + } + this.filter = testTypeFilter | sizeFilter | levelFilter; + console.info('filter params:' + this.filter); + } + + isCurrentSuite(description) { + if (this.suite !== undefined && this.suite !== '' && this.suite !== null) { + let suiteArray = this.suite.split(','); + return suiteArray.indexOf(description) !== -1; + } + return false; + } + + filterSuite(currentSuiteName) { + let filterArray = []; + if (this.suite !== undefined && this.suite !== '' && this.suite !== null) { + filterArray.push(new SuiteAndItNameFilter(currentSuiteName, '', this.suite)); + } + if (this.class !== undefined && this.class !== '' && this.class !== null) { + filterArray.push(new ClassFilter(currentSuiteName, '', this.class)); + } + if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) { + filterArray.push(new NotClassFilter(currentSuiteName, '', this.notClass)); + } + + let result = filterArray.map(item => item.filterSuite()).reduce((pre, cur) => pre || cur, false); + return result; + } + + filterDesc(currentSuiteName, desc, fi, coreContext) { + let filterArray = []; + if (this.itName !== undefined && this.itName !== '' && this.itName !== null) { + filterArray.push(new SuiteAndItNameFilter(currentSuiteName, desc, this.itName)); + } + if (this.class !== undefined && this.class !== '' && this.class !== null) { + filterArray.push(new ClassFilter(currentSuiteName, desc, this.class)); + } + if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) { + filterArray.push(new NotClassFilter(currentSuiteName, desc, this.notClass)); + } + if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && fi !== 0) { + filterArray.push(new TestTypesFilter('', '', fi, this.filter)); + } + let result = filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false); + return result; + } + + isRandom() { + return this.random || false; + } + + setSupportAsync(value) { + this.supportAsync = value; + } + + isSupportAsync() { + return this.supportAsync; + } + + translateParams(parameters) { + const keySet = new Set([ + '-s class', '-s notClass', '-s suite', '-s itName', + '-s level', '-s testType', '-s size', '-s timeout', + '-s dryRun', 'class', 'notClass', 'suite', 'itName', + 'level', 'testType', 'size', 'timeout', 'dryRun' + ]); + let targetParams = {}; + for (const key in parameters) { + if (keySet.has(key)) { + var newKey = key.replace("-s ", ""); + targetParams[newKey] = parameters[key]; + } + } + return targetParams; + } + translateParamsToString(parameters) { + const keySet = new Set([ + '-s class', '-s notClass', '-s suite', '-s itName', + '-s level', '-s testType', '-s size', '-s timeout', + '-s dryRun', 'class', 'notClass', 'suite', 'itName', + 'level', 'testType', 'size', 'timeout', 'dryRun' + ]); + let targetParams = ''; + for (const key in parameters) { + if (keySet.has(key)) { + targetParams += ' ' + key + ' ' + parameters[key]; + } + } + return targetParams.trim(); + } + + execute() { + } +} + +export { + ConfigService +}; diff --git a/Ability/Sensormock/hypium/src/module/kit/SysTestKit.js b/Ability/Sensormock/hypium/src/module/kit/SysTestKit.js new file mode 100644 index 0000000000000000000000000000000000000000..ded7e4bde5939f718da025c519ae5d23d92e6abb --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/kit/SysTestKit.js @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class SysTestKit { + + static delegator = null; + + constructor() { + this.id = 'sysTestKit'; + this.index = 0; + } + + static actionStart(tag) { + console.info(JSON.stringify(tag)); + var message = '\n' + 'OHOS_REPORT_ACTIONSTART: ' + JSON.stringify(tag) + '\n'; + SysTestKit.delegator.print(message).then(() => { + console.info(tag + ' actionStart print success'); + }); + } + + static actionEnd(tag) { + console.info(JSON.stringify(tag)); + var message = '\n' + 'OHOS_REPORT_ACTIONEND: ' + JSON.stringify(tag) + '\n'; + SysTestKit.delegator.print(message).then(() => { + console.info(tag + ' actionEnd print success'); + }); + } + + static async existKeyword(keyword, timeout) { + keyword = keyword || 'jsapp'; + timeout = timeout || 4; + + let searchResult = false; + let cmd = 'hilog -x | grep -i \'' + keyword + '\' | wc -l'; + await executePromise(cmd, timeout).then((data) => { + searchResult = data; + }); + return searchResult; + } +} + +function executePromise(cmd, timeout) { + return new Promise((resolve, reject) => { + SysTestKit.delegator.executeShellCommand(cmd, timeout, + (error, data) => { + console.info('existKeyword CallBack: err : ' + JSON.stringify(error)); + console.info('existKeyword CallBack: data : ' + JSON.stringify(data)); + resolve(parseInt(data.stdResult) > 3 ? true : false); + }); + }); +} + +export default SysTestKit; \ No newline at end of file diff --git a/Ability/Sensormock/hypium/src/module/mock/ArgumentMatchers.js b/Ability/Sensormock/hypium/src/module/mock/ArgumentMatchers.js new file mode 100644 index 0000000000000000000000000000000000000000..6a9d7aac464e95383ea31385284b6603c34e084c --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/mock/ArgumentMatchers.js @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class ArgumentMatchers { + ANY = ""; + ANY_STRING = ""; + ANY_BOOLEAN = ""; + ANY_NUMBER = ""; + ANY_OBJECT = ""; + ANY_FUNCTION = ""; + MATCH_REGEXS = ""; + + static any() { + } + + static anyString() { + } + + static anyBoolean() { + } + + static anyNumber() { + } + + static anyObj() { + } + + static anyFunction() { + } + + static matchRegexs() { + let regex = arguments[0]; + if (ArgumentMatchers.isRegExp(regex)) { + return regex; + } + throw Error("not a regex"); + } + + static isRegExp(value) { + return Object.prototype.toString.call(value) === "[object RegExp]"; + } + + matcheReturnKey() { + let arg = arguments[0]; + let regex = arguments[1]; + let stubSetKey = arguments[2]; + + if (stubSetKey && stubSetKey == this.ANY) { + return this.ANY; + } + + if (typeof arg === "string" && !regex) { + return this.ANY_STRING; + } + + if (typeof arg === "boolean" && !regex) { + return this.ANY_BOOLEAN; + } + + if (typeof arg === "number" && !regex) { + return this.ANY_NUMBER; + } + + if (typeof arg === "object" && !regex) { + return this.ANY_OBJECT; + } + + if (typeof arg === "function" && !regex) { + return this.ANY_FUNCTION; + } + + if (typeof arg === "string" && regex) { + return regex.test(arg); + } + + return null; + } + + matcheStubKey() { + let key = arguments[0]; + + if (key === ArgumentMatchers.any) { + return this.ANY; + } + + if (key === ArgumentMatchers.anyString) { + return this.ANY_STRING; + } + if (key === ArgumentMatchers.anyBoolean) { + return this.ANY_BOOLEAN; + } + if (key === ArgumentMatchers.anyNumber) { + return this.ANY_NUMBER; + } + if (key === ArgumentMatchers.anyObj) { + return this.ANY_OBJECT; + } + if (key === ArgumentMatchers.anyFunction) { + return this.ANY_FUNCTION; + } + + if (ArgumentMatchers.isRegExp(key)) { + return key; + } + + return null; + } +} + +export default ArgumentMatchers; \ No newline at end of file diff --git a/Ability/Sensormock/hypium/src/module/mock/ExtendInterface.js b/Ability/Sensormock/hypium/src/module/mock/ExtendInterface.js new file mode 100644 index 0000000000000000000000000000000000000000..c6a866a6df662ad10a7f6869dcbc2381fa47bcdc --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/mock/ExtendInterface.js @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class ExtendInterface { + constructor(mocker) { + this.mocker = mocker; + } + + stub() { + this.params = arguments; + return this; + } + + stubMockedCall(returnInfo) { + this.mocker.stubApply(this, this.params, returnInfo); + } + + afterReturn(value) { + this.stubMockedCall(function () { + return value; + }); + } + + afterReturnNothing() { + this.stubMockedCall(function () { + return undefined; + }); + } + + afterAction(action) { + this.stubMockedCall(action); + } + + afterThrow(msg) { + this.stubMockedCall(function () { + throw msg; + }); + } + + clear() { + this.mocker.clear(); + } +} + +export default ExtendInterface; \ No newline at end of file diff --git a/Ability/Sensormock/hypium/src/module/mock/MockKit.js b/Ability/Sensormock/hypium/src/module/mock/MockKit.js new file mode 100644 index 0000000000000000000000000000000000000000..bcd7768c5d7aa1678f841e6f91d9e61253e91ac3 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/mock/MockKit.js @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import ExtendInterface from "./ExtendInterface"; +import VerificationMode from "./VerificationMode"; +import ArgumentMatchers from "./ArgumentMatchers"; + +class MockKit { + constructor() { + this.mFunctions = []; + this.stubs = new Map(); + this.recordCalls = new Map(); + this.currentSetKey = null; + this.mockObj = null; + this.recordMockedMethod = new Map(); + } + + init() { + this.reset(); + } + + reset() { + this.mFunctions = []; + this.stubs = {}; + this.recordCalls = {}; + this.currentSetKey = null; + this.mockObj = null; + this.recordMockedMethod = new Map(); + } + + clearAll() { + this.reset(); + var props = Object.keys(this); + for (var i = 0; i < props.length; i++) { + delete this[props[i]]; + } + + var props = Object.getOwnPropertyNames(this); + for (var i = 0; i < props.length; i++) { + delete this[props[i]]; + } + for (var key in this) { + delete this[key]; + } + } + + clear(obj) { + if (!obj) throw Error("Please enter an object to be cleaned"); + if (typeof (obj) != 'object') throw new Error('Not a object'); + this.recordMockedMethod.forEach(function (value, key, map) { + if (key) { + obj[key] = value; + } + }); + } + + ignoreMock(obj, method) { + if (typeof (obj) != 'object') throw new Error('Not a object'); + if (typeof (method) != 'function') throw new Error('Not a function'); + let og = this.recordMockedMethod.get(method.propName); + if (og) { + obj[method.propName] = og; + this.recordMockedMethod.set(method.propName, undefined); + } + } + + extend(dest, source) { + dest["stub"] = source["stub"]; + dest["afterReturn"] = source["afterReturn"]; + dest["afterReturnNothing"] = source["afterReturnNothing"]; + dest["afterAction"] = source["afterAction"]; + dest["afterThrow"] = source["afterThrow"]; + dest["stubMockedCall"] = source["stubMockedCall"]; + dest["clear"] = source["clear"]; + return dest; + } + + stubApply(f, params, returnInfo) { + let values = this.stubs.get(f); + if (!values) { + values = new Map(); + } + let key = params[0]; + let matcher = new ArgumentMatchers(); + if (matcher.matcheStubKey(key)) { + key = matcher.matcheStubKey(key); + if (key) { + this.currentSetKey = key; + } + } + values.set(key, returnInfo); + console.info( + "set stub:" + f + ";" + "key:" + key + ",returnInfo:" + returnInfo + ); + this.stubs.set(f, values); + } + + getReturnInfo(f, params) { + let values = this.stubs.get(f); + console.info( + "getReruntInfo:" + f + ",values:" + values + ",params:" + params[0] + ); + + if (!values) { + return undefined; + } + let retrunKet = params[0]; + let stubSetKey = this.currentSetKey; + + if (this.currentSetKey && retrunKet) { + retrunKet = stubSetKey; + + } + let matcher = new ArgumentMatchers(); + if (matcher.matcheReturnKey(params[0], undefined, stubSetKey) && matcher.matcheReturnKey(params[0], undefined, stubSetKey) != stubSetKey) { + retrunKet = params[0]; + } + + values.forEach(function (value, key, map) { + if (ArgumentMatchers.isRegExp(key) && matcher.matcheReturnKey(params[0], key)) { + retrunKet = key; + } + }); + + console.info("detail:" + values.get(retrunKet)); + return values.get(retrunKet); + } + + findName(obj, value) { + let properties = this.findProperties(obj); + let name = null; + properties.forEach( + function (va1, idx, array) { + if (obj[va1] === value) { + name = va1; + } + } + ); + return name; + } + + isFunctionFromPrototype(f, container, propName) { + if (container.constructor != Object && container.constructor.prototype !== container) { + return container.constructor.prototype[propName] === f; + } + return false; + } + + findProperties(obj, ...arg) { + + function getProperty(new_obj) { + if (new_obj.__proto__ === null) { + return []; + } + let properties = Object.getOwnPropertyNames(new_obj); + return [...properties, ...getProperty(new_obj.__proto__)]; + } + + return getProperty(obj); + } + + recordMethodCall(originalMethod, args) { + Function.prototype.getName = function () { + return this.name || this.toString().match(/function\s*([^(]*)\(/)[1]; + }; + let name = originalMethod.getName(); + let arglistString = name + '(' + Array.from(args).toString() + ')'; + let records = this.recordCalls.get(arglistString); + console.log(records); + if (!records) { + records = 0; + } + records++; + this.recordCalls.set(arglistString, records); + } + + mockFunc(originalObject, originalMethod) { + let tmp = this; + this.originalMethod = originalMethod; + let f = function () { + let args = arguments; + let action = tmp.getReturnInfo(f, args); + if (originalMethod) { + tmp.recordMethodCall(originalMethod, args); + } + //1.0.3版本 新改动 + if (action) { + let result = action.apply(this, args); + if (args[1] && typeof args[1] == 'function') { + if (args[2]) { + let time = 0; + for (let o in args[2]) { + if (o == 'interval') { + time = args[2][o]; + } + } + setInterval(args[1](result), time / 1000000 > 0 ? time / 1000000 : 2000); + } else { + args[1](result); + } + } + return result; + } + ; + }; + + f.container = null || originalObject; + f.original = originalMethod || null; + + if (originalObject && originalMethod) { + if (typeof (originalMethod) != 'function') throw new Error('Not a function'); + var name = this.findName(originalObject, originalMethod); + originalObject[name] = f; + this.recordMockedMethod.set(name, originalMethod); + f.propName = name; + f.originalFromPrototype = this.isFunctionFromPrototype(f.original, originalObject, f.propName); + } + f.mocker = this; + this.mFunctions.push(f); + this.extend(f, new ExtendInterface(this)); + return f; + } + + verify(methodName, argsArray) { + if (!methodName) { + throw Error("not a function name"); + } + let a = this.recordCalls.get(methodName + '(' + argsArray.toString() + ')'); + return new VerificationMode(a ? a : 0); + } + + /** + * 1.0.3版本 传感器,地理位置模拟新增接口 + * @param object + */ + mockObject(object) { + if (!object || typeof object === "string") { + throw Error(`this ${object} cannot be mocked`); + } + const _this = this; + let mockedObject = {}; + let keys = Reflect.ownKeys(object); + keys.filter(key => (typeof Reflect.get(object, key)) === 'function') + .forEach(key => { + mockedObject[key] = object[key]; + mockedObject[key] = _this.mockFunc(mockedObject, mockedObject[key]); + }); + return mockedObject; + } +} + +function ifMockedFunction(f) { + if (Object.prototype.toString.call(f) != "[object Function]" && + Object.prototype.toString.call(f) != "[object AsyncFunction]") { + throw Error("not a function"); + } + if (!f.stub) { + throw Error("not a mock function"); + } + return true; +} + +function when(f) { + if (ifMockedFunction(f)) { + return f.stub.bind(f); + } +} + +export { MockKit, when }; \ No newline at end of file diff --git a/Ability/Sensormock/hypium/src/module/mock/VerificationMode.js b/Ability/Sensormock/hypium/src/module/mock/VerificationMode.js new file mode 100644 index 0000000000000000000000000000000000000000..8103a86399e53e725e45e40985b280b1d0a0b153 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/mock/VerificationMode.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {expect} from "@ohos/hypium"; + +class VerificationMode { + constructor(times) { + this.doTimes = times; + } + + times(count) { + expect(count).assertEqual(this.doTimes); + } + + never() { + console.log(this.doTimes); + expect(0).assertEqual(this.doTimes); + } + + once() { + expect(1).assertEqual(this.doTimes); + } + + atLeast(count) { + if (count > this.doTimes) { + throw Error('failed ' + count + ' greater than the actual execution times of method'); + } + } + + atMost(count) { + if (count < this.doTimes) { + throw Error('failed ' + count + ' less than the actual execution times of method'); + } + } +} + +export default VerificationMode; \ No newline at end of file diff --git a/Ability/Sensormock/hypium/src/module/report/OhReport.js b/Ability/Sensormock/hypium/src/module/report/OhReport.js new file mode 100644 index 0000000000000000000000000000000000000000..0ee22a8782345b6d707c1f383e79bf0970523cff --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/report/OhReport.js @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class OhReport { + constructor(attr) { + this.delegator = attr.delegator; + this.id = 'report'; + this.index = 0; + this.duration = 0; + } + + init(coreContext) { + this.coreContext = coreContext; + this.suiteService = this.coreContext.getDefaultService('suite'); + this.specService = this.coreContext.getDefaultService('spec'); + } + + taskStart() { + this.taskStartTime = new Date().getTime(); + } + + taskDone() { + this.taskDoneTime = new Date().getTime(); + this.duration = this.taskDoneTime - this.taskStartTime; + let summary = this.suiteService.getSummary(); + var message = '\n' + 'OHOS_REPORT_RESULT: stream=Tests run: ' + summary.total + ', Failure: ' + summary.failure; + message += ', Error: ' + summary.error; + message += ', Pass: ' + summary.pass; + message += '\n' + 'OHOS_REPORT_CODE: ' + (summary.failure > 0 ? -1 : 0) + '\n'; + message += 'OHOS_REPORT_STATUS: consuming=' + this.duration + '\n'; + this.delegator.print(message).then(() => { + console.info('report print success'); + this.delegator.finishTest('your test finished!!!', 0, () => { }); + }); + } + + incorrectFormat() { + if (this.coreContext.getDefaultService('config').filterValid.length !== 0) { + var value = this.coreContext.getDefaultService('config').filterValid; + var message = 'this param ' + value.join(',') + ' is invalid' + '\n'; + this.delegator.finishTest(message, 0, () => { }); + } + } + + suiteStart() { + let suiteService = this.coreContext.getDefaultService('suite'); + var message = '\n' + 'OHOS_REPORT_SUM: ' + suiteService.getSummary().total; + message += '\n' + 'OHOS_REPORT_STATUS: class=' + suiteService.getCurrentRunningSuite().description + '\n'; + this.delegator.print(message).then(() => { + console.info(suiteService.getCurrentRunningSuite().description + ' print success'); + }); + } + + suiteDone() { + var message = '\n' + 'OHOS_REPORT_STATUS: class=' + this.suiteService.getCurrentRunningSuite().description; + message += '\n' + 'OHOS_REPORT_STATUS: consuming=' + this.suiteService.currentRunningSuite.duration + '\n'; + this.delegator.print(message).then(() => { + console.info(suiteService.getCurrentRunningSuite().description + ' print success'); + }); + } + + specStart() { + let suiteService = this.coreContext.getDefaultService('suite'); + var message = '\n' + 'OHOS_REPORT_STATUS: class=' + suiteService.getCurrentRunningSuite().description; + message += '\n' + 'OHOS_REPORT_STATUS: current=' + (++this.index); + message += '\n' + 'OHOS_REPORT_STATUS: id=JS'; + message += '\n' + 'OHOS_REPORT_STATUS: numtests=' + suiteService.getSummary().total; + message += '\n' + 'OHOS_REPORT_STATUS: stream='; + message += '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description; + message += '\n' + 'OHOS_REPORT_STATUS_CODE: 1' + '\n'; + this.delegator.print(message).then(() => { + console.info(this.specService.currentRunningSpec.description + ' start print success'); + }); + } + + specDone() { + var message = '\n' + 'OHOS_REPORT_STATUS: class=' + this.suiteService.getCurrentRunningSuite().description; + message += '\n' + 'OHOS_REPORT_STATUS: current=' + (this.index); + message += '\n' + 'OHOS_REPORT_STATUS: id=JS'; + message += '\n' + 'OHOS_REPORT_STATUS: numtests=' + this.suiteService.getSummary().total; + let emsg = ''; + if (this.specService.currentRunningSpec.error) { + message += '\n' + 'OHOS_REPORT_STATUS: stack=' + this.specService.currentRunningSpec.error; + message += '\n' + 'OHOS_REPORT_STATUS: stream='; + message += '\n' + 'Error in ' + this.specService.currentRunningSpec.description; + message += '\n' + this.specService.currentRunningSpec.error; + message += '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description; + message += '\n' + 'OHOS_REPORT_STATUS_CODE: -1' + '\n'; + } else if (this.specService.currentRunningSpec.result) { + if (this.specService.currentRunningSpec.result.failExpects.length > 0) { + this.specService.currentRunningSpec.result.failExpects.forEach(failExpect => { + emsg = failExpect.message || ('expect ' + failExpect.actualValue + ' ' + failExpect.checkFunc + ' ' + (failExpect.expectValue || '')); + }); + message += '\n' + 'OHOS_REPORT_STATUS: stack=' + emsg; + message += '\n' + 'OHOS_REPORT_STATUS: stream='; + message += '\n' + 'Error in ' + this.specService.currentRunningSpec.description; + message += '\n' + emsg + '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description; + message += '\n' + 'OHOS_REPORT_STATUS_CODE: -2' + '\n'; + } else { + message += '\n' + 'OHOS_REPORT_STATUS: stream='; + message += '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description; + message += '\n' + 'OHOS_REPORT_STATUS_CODE: 0' + '\n'; + } + } else { + message += '\n'; + } + message += 'OHOS_REPORT_STATUS: consuming=' + this.specService.currentRunningSpec.duration + '\n'; + this.delegator.print(message).then(() => { + console.info(this.specService.currentRunningSpec.description + ' end print success'); + }); + } +} + +export default OhReport; diff --git a/Ability/Sensormock/hypium/src/module/report/ReportExtend.js b/Ability/Sensormock/hypium/src/module/report/ReportExtend.js new file mode 100644 index 0000000000000000000000000000000000000000..852fbcd5cbf97e776ebe5177a029df0f516594a5 --- /dev/null +++ b/Ability/Sensormock/hypium/src/module/report/ReportExtend.js @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class ReportExtend { + constructor(fileModule) { + this.id = 'extend'; + this.fileModule = fileModule; + } + + init(coreContext) { + this.coreContext = coreContext; + this.suiteService = this.coreContext.getDefaultService('suite'); + } + + taskStart() { + + } + + taskDone() { + const report = { + tag: 'testsuites', + name: 'summary_report', + timestamp: new Date().toDateString(), + time: '1', + errors: 0, + failures: 0, + tests: 0, + children: [] + }; + const rootSuite = this.suiteService.rootSuite; + if (rootSuite && rootSuite.childSuites) { + for (let testsuite of rootSuite.childSuites) { + let suiteReport = { + tag: 'testsuite', + name: testsuite['description'], + errors: 0, + tests: 0, + failures: 0, + time: '0.1', + children: [] + }; + let specs = testsuite['specs']; + for (let testcase of specs) { + report.tests++; + suiteReport.tests++; + let caseReport = { + tag: 'testcase', + name: testcase['description'], + status: 'run', + time: '0.0', + classname: testsuite['description'] + }; + if (testcase.error) { + caseReport['result'] = false; + caseReport['children'] = [{ + tag: 'error', + type: '', + message: testcase.error.message + }]; + report.errors++; + suiteReport.errors++; + } else if (testcase.result.failExpects.length > 0) { + caseReport['result'] = false; + let message = ''; + testcase.result.failExpects.forEach(failExpect => { + message += failExpect.message || ('expect ' + failExpect.actualValue + ' ' + failExpect.checkFunc + ' ' + (failExpect.expectValue || '')) + ';'; + }); + caseReport['children'] = [{ + tag: 'failure', + type: '', + message: message + }]; + report.failures++; + suiteReport.failures++; + } else { + caseReport['result'] = true; + } + suiteReport.children.push(caseReport); + } + report.children.push(suiteReport); + } + } + + let reportXml = '\n' + json2xml(report); + this.fileModule.writeText({ + uri: 'internal://app/report.xml', + text: reportXml, + success: function () { + console.info('call success callback success'); + }, + fail: function (data, code) { + console.info('call fail callback success:'); + }, + complete: function () { + console.info('call complete callback success'); + } + }); + } +} + +function json2xml(json) { + let tagName; + let hasChildren = false; + let childrenStr = ''; + let attrStr = ''; + for (let key in json) { + if (key === 'tag') { + tagName = json[key]; + } else if (key === 'children') { + if (json[key].length > 0) { + hasChildren = true; + for (let child of json[key]) { + childrenStr += json2xml(child); + } + } + } else { + attrStr += ` ${key}="${json[key]}"`; + } + } + let xml = `<${tagName}${attrStr}`; + xml += hasChildren ? `>${childrenStr}` : '/>'; + return xml; +} + +export default ReportExtend; diff --git a/Ability/Sensormock/hypium/src/service.js b/Ability/Sensormock/hypium/src/service.js new file mode 100644 index 0000000000000000000000000000000000000000..dc74de3c4d5c6b5cb9e878c3d858f6729adfdf29 --- /dev/null +++ b/Ability/Sensormock/hypium/src/service.js @@ -0,0 +1,702 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function processFunc(coreContext, func) { + let argNames = ((func || '').toString() + .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '') + .match(/^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m) || ['', '', ''])[2] + .split(',') // split parameters + .map(item => item.replace(/^\s*(_?)(.+?)\1\s*$/, name => name.split('=')[0].trim())) + .filter(String); + let funcLen = func.length; + let processedFunc; + coreContext.getDefaultService('config').setSupportAsync(true); + switch (funcLen) { + case 0: { + processedFunc = func; + break; + } + case 1: { + if (argNames[0] === 'data') { + processedFunc = function (paramItem) { + func(paramItem); + }; + } else { + processedFunc = function () { + return new Promise((resolve, reject) => { + function done() { + resolve(); + } + + let funcType = func(done); + if (funcType instanceof Promise) { + funcType.catch(err => {reject(err);}); + } + }); + }; + } + break; + } + default: { + processedFunc = function (paramItem) { + return new Promise((resolve, reject) => { + function done() { + resolve(); + } + + let funcType = func(done, paramItem); + if (funcType instanceof Promise) { + funcType.catch(err => {reject(err);}); + } + }); + }; + break; + } + } + return processedFunc; +} + +function secureRandomNumber() { + return crypto.randomBytes(8).readUInt32LE() / 0xffffffff; +} + +class SuiteService { + constructor(attr) { + this.id = attr.id; + this.rootSuite = new SuiteService.Suite({}); + this.currentRunningSuite = this.rootSuite; + } + + describe(desc, func) { + if (this.coreContext.getDefaultService('config').filterSuite(desc)) { + console.info('filter suite :' + desc); + return; + } + const suite = new SuiteService.Suite({description: desc}); + if (typeof this.coreContext.getServices('dataDriver') !== 'undefined') { + let suiteStress = this.coreContext.getServices('dataDriver').dataDriver.getSuiteStress(desc); + for (let i = 1; i < suiteStress; i++) { + this.currentRunningSuite.childSuites.push(suite); + } + } + const currentSuiteCache = this.currentRunningSuite; + this.currentRunningSuite.childSuites.push(suite); + this.currentRunningSuite = suite; + func.call(); + this.currentRunningSuite = currentSuiteCache; + } + + beforeAll(func) { + this.currentRunningSuite.beforeAll.push(processFunc(this.coreContext, func)); + } + + beforeEach(func) { + this.currentRunningSuite.beforeEach.push(processFunc(this.coreContext, func)); + } + + afterAll(func) { + this.currentRunningSuite.afterAll.push(processFunc(this.coreContext, func)); + } + + afterEach(func) { + this.currentRunningSuite.afterEach.push(processFunc(this.coreContext, func)); + } + + getCurrentRunningSuite() { + return this.currentRunningSuite; + } + + setCurrentRunningSuite(suite) { + this.currentRunningSuite = suite; + } + + getSummary() { + let total = 0; + let error = 0; + let failure = 0; + let pass = 0; + let rootSuite = this.coreContext.getDefaultService('suite').rootSuite; + if (rootSuite && rootSuite.childSuites) { + for (let i = 0; i < rootSuite.childSuites.length; i++) { + let testsuite = rootSuite.childSuites[i]; + let specs = testsuite['specs']; + for (let j = 0; j < specs.length; j++) { + total++; + let testcase = specs[j]; + if (testcase.error) { + error++; + } else if (testcase.result.failExpects.length > 0) { + failure++; + } else if (testcase.result.pass === true) { + pass++; + } + } + } + } + return {total: total, failure: failure, error: error, pass: pass}; + } + + init(coreContext) { + this.coreContext = coreContext; + } + + execute() { + if (this.coreContext.getDefaultService('config').filterValid.length !== 0) { + this.coreContext.fireEvents('task', 'incorrectFormat'); + return; + } + this.coreContext.fireEvents('task', 'taskStart'); + if (this.coreContext.getDefaultService('config').isSupportAsync()) { + let asyncExecute = async () => { + await this.rootSuite.asyncRun(this.coreContext); + }; + asyncExecute().then(() => { + this.coreContext.fireEvents('task', 'taskDone'); + }); + } else { + this.rootSuite.run(this.coreContext); + this.coreContext.fireEvents('task', 'taskDone'); + } + } + + apis() { + const _this = this; + return { + describe: function (desc, func) { + return _this.describe(desc, func); + }, + beforeAll: function (func) { + return _this.beforeAll(func); + }, + beforeEach: function (func) { + return _this.beforeEach(func); + }, + afterAll: function (func) { + return _this.afterAll(func); + }, + afterEach: function (func) { + return _this.afterEach(func); + } + }; + } +} + +SuiteService.Suite = class { + constructor(attrs) { + this.description = attrs.description || ''; + this.childSuites = []; + this.specs = []; + this.beforeAll = []; + this.afterAll = []; + this.beforeEach = []; + this.afterEach = []; + this.duration = 0; + } + + pushSpec(spec) { + this.specs.push(spec); + } + + removeSpec(desc) { + this.specs = this.specs.filter((item, index) => { + return item.description !== desc; + }); + } + + getSpecsNum() { + return this.specs.length; + } + + run(coreContext) { + const suiteService = coreContext.getDefaultService('suite'); + suiteService.setCurrentRunningSuite(this); + if (this.description !== '') { + coreContext.fireEvents('suite', 'suiteStart', this); + } + let startTime = new Date().getTime(); + this.runHookFunc('beforeAll'); + if (this.specs.length > 0) { + const configService = coreContext.getDefaultService('config'); + if (configService.isRandom()) { + this.specs.sort(function () { + return secureRandomNumber() > 0.5 ? -1 : 1; + }); + } + this.specs.forEach(spec => { + this.runHookFunc('beforeEach'); + spec.run(coreContext); + this.runHookFunc('afterEach'); + }); + } + if (this.childSuites.length > 0) { + this.childSuites.forEach(childSuite => { + childSuite.run(coreContext); + suiteService.setCurrentRunningSuite(childSuite); + }); + } + this.runHookFunc('afterAll'); + let endTime = new Date().getTime(); + this.duration = endTime - startTime; + if (this.description !== '') { + coreContext.fireEvents('suite', 'suiteDone'); + } + } + + asyncRun(coreContext) { + const suiteService = coreContext.getDefaultService('suite'); + suiteService.setCurrentRunningSuite(this); + return new Promise(async resolve => { + if (this.description !== '') { + coreContext.fireEvents('suite', 'suiteStart', this); + } + let startTime = new Date().getTime(); + await this.runAsyncHookFunc('beforeAll'); + if (this.specs.length > 0) { + const configService = coreContext.getDefaultService('config'); + if (configService.isRandom()) { + this.specs.sort(function () { + return secureRandomNumber() > 0.5 ? -1 : 1; + }); + } + for (let i = 0; i < this.specs.length; i++) { + await this.runAsyncHookFunc('beforeEach'); + await this.specs[i].asyncRun(coreContext); + await this.runAsyncHookFunc('afterEach'); + } + } + + if (this.childSuites.length > 0) { + for (let i = 0; i < this.childSuites.length; i++) { + suiteService.setCurrentRunningSuite(this.childSuites[i]); + await this.childSuites[i].asyncRun(coreContext); + } + } + + await this.runAsyncHookFunc('afterAll'); + let endTime = new Date().getTime(); + this.duration = endTime - startTime; + if (this.description !== '') { + coreContext.fireEvents('suite', 'suiteDone'); + } + resolve(); + }); + } + + runHookFunc(hookName) { + if (this[hookName] && this[hookName].length > 0) { + this[hookName].forEach(func => { + try { + func(); + } catch (e) { + console.error(e); + } + }); + } + } + + runAsyncHookFunc(hookName) { + if (this[hookName] && this[hookName].length > 0) { + return new Promise(async resolve => { + for (let i = 0; i < this[hookName].length; i++) { + try { + await this[hookName][i](); + } catch (e) { + console.error(e); + } + } + resolve(); + }); + } + } +}; + +class SpecService { + constructor(attr) { + this.id = attr.id; + } + + init(coreContext) { + this.coreContext = coreContext; + } + + setCurrentRunningSpec(spec) { + this.currentRunningSpec = spec; + } + + getCurrentRunningSpec() { + return this.currentRunningSpec; + } + + it(desc, filter, func) { + const configService = this.coreContext.getDefaultService('config'); + const currentSuiteName = this.coreContext.getDefaultService('suite').getCurrentRunningSuite().description; + if (configService.filterDesc(currentSuiteName, desc, filter, this.coreContext)) { + console.info('filter it :' + desc); + } else { + let processedFunc = processFunc(this.coreContext, func); + const spec = new SpecService.Spec({description: desc, fi: filter, fn: processedFunc}); + const suiteService = this.coreContext.getDefaultService('suite'); + if (typeof this.coreContext.getServices('dataDriver') !== 'undefined') { + let specStress = this.coreContext.getServices('dataDriver').dataDriver.getSpecStress(desc); + for (let i = 1; i < specStress; i++) { + suiteService.getCurrentRunningSuite().pushSpec(spec); + } + } + suiteService.getCurrentRunningSuite().pushSpec(spec); + } + } + + apis() { + const _this = this; + return { + it: function (desc, filter, func) { + return _this.it(desc, filter, func); + } + }; + } +} + +SpecService.Spec = class { + constructor(attrs) { + this.description = attrs.description || ''; + this.fi = attrs.fi; + this.fn = attrs.fn || function () { + }; + this.result = { + failExpects: [], + passExpects: [] + }; + this.error = undefined; + this.duration = 0; + } + + setResult() { + if (this.result.failExpects.length > 0) { + this.result.pass = false; + } else { + this.result.pass = true; + } + console.info('testcase ' + this.description + ' result:' + this.result.pass); + } + + run(coreContext) { + const specService = coreContext.getDefaultService('spec'); + specService.setCurrentRunningSpec(this); + coreContext.fireEvents('spec', 'specStart', this); + let startTime = new Date().getTime(); + try { + let dataDriver = coreContext.getServices('dataDriver'); + if (typeof dataDriver === 'undefined') { + this.fn(); + } else { + let suiteParams = dataDriver.dataDriver.getSuiteParams(); + let specParams = dataDriver.dataDriver.getSpecParams(); + console.info('[suite params] ' + JSON.stringify(suiteParams)); + console.info('[spec params] ' + JSON.stringify(specParams)); + if (this.fn.length === 0) { + this.fn(); + } else if (specParams.length === 0) { + this.fn(suiteParams); + } else { + specParams.forEach(paramItem => this.fn(Object.assign({}, paramItem, suiteParams))); + } + } + this.setResult(); + } catch (e) { + this.error = e; + } + let endTime = new Date().getTime(); + this.duration = endTime - startTime; + coreContext.fireEvents('spec', 'specDone', this); + } + + asyncRun(coreContext) { + const specService = coreContext.getDefaultService('spec'); + specService.setCurrentRunningSpec(this); + const config = coreContext.getDefaultService('config'); + const timeout = + (config.timeout === undefined ? 5000 : config.timeout); + return new Promise(async resolve => { + coreContext.fireEvents('spec', 'specStart', this); + let startTime = new Date().getTime(); + + function timeoutPromise() { + return new Promise(function (resolve, reject) { + setTimeout(() => reject(new Error('execute timeout ' + timeout + 'ms')), timeout); + }); + } + + try { + let dataDriver = coreContext.getServices('dataDriver'); + if (typeof dataDriver === 'undefined') { + const p = Promise.race([this.fn(), timeoutPromise()]); + await p.then(() => { + this.setResult(); + }); + } else { + let suiteParams = dataDriver.dataDriver.getSuiteParams(); + let specParams = dataDriver.dataDriver.getSpecParams(); + console.info('[suite params] ' + JSON.stringify(suiteParams)); + console.info('[spec params] ' + JSON.stringify(specParams)); + if (this.fn.length === 0) { + const p = Promise.race([this.fn(), timeoutPromise()]); + await p.then(() => { + this.setResult(); + }); + } else if (specParams.length === 0) { + const p = Promise.race([this.fn(suiteParams), timeoutPromise()]); + await p.then(() => { + this.setResult(); + }); + } else { + for (const paramItem of specParams) { + const p = Promise.race([this.fn(Object.assign({}, paramItem, suiteParams)), timeoutPromise()]); + await p.then(() => { + this.setResult(); + }); + } + } + } + } catch (e) { + this.error = e; + } + let endTime = new Date().getTime(); + this.duration = endTime - startTime; + coreContext.fireEvents('spec', 'specDone', this); + resolve(); + }); + } + + filterCheck(coreContext) { + const specService = coreContext.getDefaultService('spec'); + specService.setCurrentRunningSpec(this); + return true; + } + + addExpectationResult(expectResult) { + if (expectResult.pass) { + this.result.passExpects.push(expectResult); + } else { + this.result.failExpects.push(expectResult); + } + } +}; + +class ExpectService { + constructor(attr) { + this.id = attr.id; + this.matchers = {}; + } + + expect(actualValue) { + return this.wrapMatchers(actualValue); + } + + init(coreContext) { + this.coreContext = coreContext; + this.addMatchers(this.basicMatchers()); + } + + addMatchers(matchers) { + for (const matcherName in matchers) { + if (Object.prototype.hasOwnProperty.call(matchers, matcherName)) { + this.matchers[matcherName] = matchers[matcherName]; + } + } + } + + basicMatchers() { + return { + assertTrue: function (actualValue) { + return { + pass: (actualValue) === true + }; + }, + assertEqual: function (actualValue, args) { + return { + pass: (actualValue) === args[0], + expectValue: args[0] + }; + }, + assertThrow: function (actual, args) { + const result = { + pass: false + }; + if (typeof actual !== 'function') { + result.message = 'toThrow\'s Actual should be a Function'; + } else { + let hasThrow = false; + let throwError; + try { + actual(); + } catch (e) { + hasThrow = true; + throwError = e; + } + if (!hasThrow) { + result.message = 'function did not throw an exception'; + } else if (throwError && throwError.message === args[0]) { + result.pass = true; + } else { + result.message = `expect to throw ${args[0]} , actual throw ${throwError.message}`; + } + } + return result; + } + }; + } + + wrapMatchers(actualValue) { + const _this = this; + const wrappedMatchers = {}; + const specService = _this.coreContext.getDefaultService('spec'); + const currentRunningSpec = specService.getCurrentRunningSpec(); + for (const matcherName in this.matchers) { + if (Object.prototype.hasOwnProperty.call(this.matchers, matcherName)) { + wrappedMatchers[matcherName] = function () { + const result = _this.matchers[matcherName](actualValue, arguments); + result.actualValue = actualValue; + result.checkFunc = matcherName; + currentRunningSpec.addExpectationResult(result); + }; + } + } + return wrappedMatchers; + } + + apis() { + const _this = this; + return { + expect: function (actualValue) { + return _this.expect(actualValue); + } + }; + } +} + +class ReportService { + constructor(attr) { + this.id = attr.id; + } + + init(coreContext) { + this.coreContext = coreContext; + this.specService = this.coreContext.getDefaultService('spec'); + this.suiteService = this.coreContext.getDefaultService('suite'); + this.duration = 0; + } + + taskStart() { + this.sleep(50); + this.taskStartTime = new Date().getTime(); + console.info('[start] start run suites'); + } + + suiteStart() { + this.sleep(50); + console.info('[suite start]' + this.suiteService.getCurrentRunningSuite().description); + } + + specStart() { + this.sleep(50); + console.info('start running case \'' + this.specService.currentRunningSpec.description + '\''); + this.index = this.index + 1; + } + + specDone() { + this.sleep(50); + let msg = ''; + let spec = this.specService.currentRunningSpec; + if (spec.error) { + this.formatPrint('error', spec.description + ' ; consuming ' + spec.duration + 'ms'); + this.formatPrint('errorDetail', spec.error); + } else if (spec.result) { + if (spec.result.failExpects.length > 0) { + this.formatPrint('fail', spec.description + ' ; consuming ' + spec.duration + 'ms'); + spec.result.failExpects.forEach(failExpect => { + msg = failExpect.message || ('expect ' + failExpect.actualValue + ' ' + + failExpect.checkFunc + ' ' + (failExpect.expectValue || '')); + this.formatPrint('failDetail', msg); + }); + } else { + this.formatPrint('pass', spec.description + ' ; consuming ' + spec.duration + 'ms'); + } + } + this.formatPrint(this.specService.currentRunningSpec.error, msg); + } + + suiteDone() { + this.sleep(50); + let suite = this.suiteService.currentRunningSuite; + console.info('[suite end]' + ' consuming ' + suite.duration + 'ms'); + } + + taskDone() { + this.sleep(50); + let msg = ''; + this.taskDoneTime = new Date().getTime(); + this.duration = this.taskDoneTime - this.taskStartTime; + let summary = this.suiteService.getSummary(); + msg = 'total cases:' + summary.total + ';failure ' + summary.failure + ',' + 'error ' + summary.error; + msg += ',pass ' + summary.pass + '; consuming ' + this.duration + 'ms'; + console.info(msg); + console.info('[end] run suites end'); + } + + incorrectFormat() { + if (this.coreContext.getDefaultService('config').filterValid.length !== 0) { + this.coreContext.getDefaultService('config').filterValid.forEach(function (item) { + console.info('this param ' + item + ' is invalid'); + }); + } + } + + formatPrint(type, msg) { + switch (type) { + case 'pass': + console.info('[pass]' + msg); + break; + case 'fail': + console.info('[fail]' + msg); + break; + case 'failDetail': + console.info('[failDetail]' + msg); + break; + case 'error': + console.info('[error]' + msg); + break; + case 'errorDetail': + console.info('[errorDetail]' + msg); + break; + } + } + + sleep(numberMillis) { + var now = new Date(); + var exitTime = now.getTime() + numberMillis; + while (true) { + now = new Date(); + if (now.getTime() > exitTime) { + return; + } + } + } +} + +export { + SuiteService, + SpecService, + ExpectService, + ReportService +};