diff --git a/.gitignore b/.gitignore index b6e3bd6..2514623 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ cmake-build-debug/ *.har package/include +*.so \ No newline at end of file diff --git a/ohos_addon_example/entry/build-profile.json5 b/ohos_addon_example/entry/build-profile.json5 index 646c44c..7252418 100644 --- a/ohos_addon_example/entry/build-profile.json5 +++ b/ohos_addon_example/entry/build-profile.json5 @@ -1,12 +1,12 @@ { "apiType": "stageMode", - "buildOption": { - "externalNativeOptions": { - "path": "./src/main/cpp/CMakeLists.txt", - "arguments": "", - "cppFlags": "", - } - }, +// "buildOption": { +// "externalNativeOptions": { +// "path": "./src/main/cpp/CMakeLists.txt", +// "arguments": "", +// "cppFlags": "", +// } +// }, "buildOptionSet": [ { "name": "release", diff --git a/ohos_addon_example/entry/libs/arm64-v8a/.gitkeep b/ohos_addon_example/entry/libs/arm64-v8a/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ohos_addon_example/entry/oh-package-lock.json5 b/ohos_addon_example/entry/oh-package-lock.json5 index 5c8c8d6..f2cb3d2 100644 --- a/ohos_addon_example/entry/oh-package-lock.json5 +++ b/ohos_addon_example/entry/oh-package-lock.json5 @@ -5,13 +5,13 @@ "lockfileVersion": 3, "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", "specifiers": { - "libentry.so@src/main/cpp/types/libentry": "libentry.so@src/main/cpp/types/libentry" + "libexmaple.so@src/main/cpp/types/libexample": "libexmaple.so@src/main/cpp/types/libexample" }, "packages": { - "libentry.so@src/main/cpp/types/libentry": { - "name": "libentry.so", + "libexmaple.so@src/main/cpp/types/libexample": { + "name": "libexmaple.so", "version": "1.0.0", - "resolved": "src/main/cpp/types/libentry", + "resolved": "src/main/cpp/types/libexample", "registryType": "local" } } diff --git a/ohos_addon_example/entry/oh-package.json5 b/ohos_addon_example/entry/oh-package.json5 index 54cb066..6de0edd 100644 --- a/ohos_addon_example/entry/oh-package.json5 +++ b/ohos_addon_example/entry/oh-package.json5 @@ -6,6 +6,6 @@ "author": "", "license": "", "dependencies": { - "libentry.so": "file:./src/main/cpp/types/libentry" + "libexmaple.so": "file:./src/main/cpp/types/libexample" } } \ No newline at end of file diff --git a/ohos_addon_example/entry/src/main/cpp/CMakeLists.txt b/ohos_addon_example/entry/src/main/cpp/CMakeLists.txt index b98e81a..f058abd 100644 --- a/ohos_addon_example/entry/src/main/cpp/CMakeLists.txt +++ b/ohos_addon_example/entry/src/main/cpp/CMakeLists.txt @@ -3,18 +3,6 @@ cmake_minimum_required(VERSION 3.5.0) project(ohos_addon_exampl) set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) -set(NODE_ADDON_API "${CMAKE_CURRENT_SOURCE_DIR}/../../../../..") -set(EXAMPLE_DIR "${NODE_ADDON_API}/example") - -file(GLOB_RECURSE SOURCES - "${EXAMPLE_DIR}/*.cpp" - "${EXAMPLE_DIR}/*.h" - "${EXAMPLE_DIR}/basic_types/*.cpp" - "${EXAMPLE_DIR}/dataview/*.cpp" - "${EXAMPLE_DIR}/object/*.cpp" - "${EXAMPLE_DIR}/threadsafe_function/*.cpp" - "${EXAMPLE_DIR}/typed_threadsafe_function/*.cpp" -) if(DEFINED PACKAGE_FIND_FILE) include(${PACKAGE_FIND_FILE}) @@ -23,6 +11,5 @@ endif() include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include) -add_library(entry SHARED ${SOURCES} napi_init.cpp) -target_include_directories(entry PUBLIC ${NODE_ADDON_API}) -target_link_libraries(entry PUBLIC libace_napi.z.so) +add_library(example SHARED ${SOURCES} napi_init.cpp) +target_link_libraries(example PUBLIC libace_napi.z.so) diff --git a/ohos_addon_example/entry/src/main/cpp/napi_init.cpp b/ohos_addon_example/entry/src/main/cpp/napi_init.cpp index cd1a639..85330e3 100644 --- a/ohos_addon_example/entry/src/main/cpp/napi_init.cpp +++ b/ohos_addon_example/entry/src/main/cpp/napi_init.cpp @@ -1,192 +1,53 @@ -#include "napi.h" +#include "napi/native_api.h" -using namespace Napi; +static napi_value Add(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value args[2] = {nullptr}; + napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); -#if (NAPI_VERSION > 5) -Object InitAddon(Env env); -Object InitAddonData(Env env); -#endif -Object InitArrayBuffer(Env env); -Object InitAsyncContext(Env env); -#if (NAPI_VERSION > 3) -Object InitAsyncProgressQueueWorker(Env env); -Object InitAsyncProgressWorker(Env env); -#endif -Object InitAsyncWorker(Env env); -Object InitPersistentAsyncWorker(Env env); -Object InitBasicTypesArray(Env env); -Object InitBasicTypesBoolean(Env env); -Object InitBasicTypesNumber(Env env); -Object InitBasicTypesValue(Env env); -#if (NAPI_VERSION > 5) -Object InitBigInt(Env env); -#endif -Object InitBuffer(Env env); -Object InitBufferNoExternal(Env env); -#if (NAPI_VERSION > 2) -Object InitCallbackScope(Env env); -#endif -#if (NAPI_VERSION > 4) -Object InitDate(Env env); -#endif -Object InitCallbackInfo(Env env); -Object InitDataView(Env env); -Object InitDataViewReadWrite(Env env); -Object InitEnvCleanup(Env env); -Object InitErrorHandlingPrim(Env env); -Object InitError(Env env); -Object InitExternal(Env env); -Object InitFunction(Env env); -Object InitFunctionReference(Env env); -Object InitHandleScope(Env env); -Object InitMovableCallbacks(Env env); -//Object InitMemoryManagement(Env env); -Object InitName(Env env); -Object InitObject(Env env); -#ifndef NODE_ADDON_API_DISABLE_DEPRECATED -Object InitObjectDeprecated(Env env); -#endif // !NODE_ADDON_API_DISABLE_DEPRECATED -Object InitPromise(Env env); -//Object InitRunScript(Env env); -#if (NAPI_VERSION > 3) -Object InitThreadSafeFunctionCtx(Env env); -Object InitThreadSafeFunctionException(Env env); -Object InitThreadSafeFunctionExistingTsfn(Env env); -Object InitThreadSafeFunctionPtr(Env env); -Object InitThreadSafeFunctionSum(Env env); -Object InitThreadSafeFunctionUnref(Env env); -Object InitThreadSafeFunction(Env env); -Object InitTypedThreadSafeFunctionCtx(Env env); -Object InitTypedThreadSafeFunctionException(Env env); -Object InitTypedThreadSafeFunctionExistingTsfn(Env env); -Object InitTypedThreadSafeFunctionPtr(Env env); -Object InitTypedThreadSafeFunctionSum(Env env); -Object InitTypedThreadSafeFunctionUnref(Env env); -Object InitTypedThreadSafeFunction(Env env); -#endif -//Object InitSymbol(Env env); -Object InitTypedArray(Env env); -//Object InitGlobalObject(Env env); -Object InitObjectWrap(Env env); -Object InitObjectWrapConstructorException(Env env); -Object InitObjectWrapFunction(Env env); -Object InitObjectWrapRemoveWrap(Env env); -Object InitObjectWrapMultipleInheritance(Env env); -Object InitObjectReference(Env env); -Object InitReference(Env env); -Object InitVersionManagement(Env env); -Object InitThunkingManual(Env env); -#if (NAPI_VERSION > 7) -Object InitObjectFreezeSeal(Env env); -Object InitTypeTaggable(Env env); -#endif -#if (NAPI_VERSION > 8) -Object InitEnvMiscellaneous(Env env); -#endif -#if defined(NODE_ADDON_API_ENABLE_MAYBE) -Object InitMaybeCheck(Env env); -#endif + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); -Object EntryInit(Env env, Object exports) { -#if (NAPI_VERSION > 5) - exports.Set("addon", InitAddon(env)); - exports.Set("addon_data", InitAddonData(env)); -#endif - exports.Set("arraybuffer", InitArrayBuffer(env)); - exports.Set("asynccontext", InitAsyncContext(env)); -#if (NAPI_VERSION > 3) - exports.Set("asyncprogressqueueworker", InitAsyncProgressQueueWorker(env)); - exports.Set("asyncprogressworker", InitAsyncProgressWorker(env)); -#endif -// exports.Set("globalObject", InitGlobalObject(env)); - exports.Set("asyncworker", InitAsyncWorker(env)); - exports.Set("persistentasyncworker", InitPersistentAsyncWorker(env)); - exports.Set("basic_types_array", InitBasicTypesArray(env)); - exports.Set("basic_types_boolean", InitBasicTypesBoolean(env)); - exports.Set("basic_types_number", InitBasicTypesNumber(env)); - exports.Set("basic_types_value", InitBasicTypesValue(env)); -#if (NAPI_VERSION > 5) - exports.Set("bigint", InitBigInt(env)); -#endif -#if (NAPI_VERSION > 4) - exports.Set("date", InitDate(env)); -#endif - exports.Set("buffer", InitBuffer(env)); - exports.Set("bufferNoExternal", InitBufferNoExternal(env)); -#if (NAPI_VERSION > 2) - exports.Set("callbackscope", InitCallbackScope(env)); -#endif - exports.Set("callbackInfo", InitCallbackInfo(env)); - exports.Set("dataview", InitDataView(env)); - exports.Set("dataview_read_write", InitDataView(env)); - exports.Set("dataview_read_write", InitDataViewReadWrite(env)); -#if (NAPI_VERSION > 2) - exports.Set("env_cleanup", InitEnvCleanup(env)); -#endif - exports.Set("error", InitError(env)); - exports.Set("errorHandlingPrim", InitErrorHandlingPrim(env)); - exports.Set("external", InitExternal(env)); - exports.Set("function", InitFunction(env)); - exports.Set("functionreference", InitFunctionReference(env)); - exports.Set("name", InitName(env)); - exports.Set("handlescope", InitHandleScope(env)); - exports.Set("movable_callbacks", InitMovableCallbacks(env)); -// exports.Set("memory_management", InitMemoryManagement(env)); - exports.Set("object", InitObject(env)); -#ifndef NODE_ADDON_API_DISABLE_DEPRECATED - exports.Set("object_deprecated", InitObjectDeprecated(env)); -#endif // !NODE_ADDON_API_DISABLE_DEPRECATED - exports.Set("promise", InitPromise(env)); -// exports.Set("symbol", InitSymbol(env)); -#if (NAPI_VERSION > 3) - exports.Set("threadsafe_function_ctx", InitThreadSafeFunctionCtx(env)); - exports.Set("threadsafe_function_exception", - InitThreadSafeFunctionException(env)); - exports.Set("threadsafe_function_existing_tsfn", - InitThreadSafeFunctionExistingTsfn(env)); - exports.Set("threadsafe_function_ptr", InitThreadSafeFunctionPtr(env)); - exports.Set("threadsafe_function_sum", InitThreadSafeFunctionSum(env)); - exports.Set("threadsafe_function_unref", InitThreadSafeFunctionUnref(env)); - exports.Set("threadsafe_function", InitThreadSafeFunction(env)); - exports.Set("typed_threadsafe_function_ctx", - InitTypedThreadSafeFunctionCtx(env)); - exports.Set("typed_threadsafe_function_exception", - InitTypedThreadSafeFunctionException(env)); - exports.Set("typed_threadsafe_function_existing_tsfn", - InitTypedThreadSafeFunctionExistingTsfn(env)); - exports.Set("typed_threadsafe_function_ptr", - InitTypedThreadSafeFunctionPtr(env)); - exports.Set("typed_threadsafe_function_sum", - InitTypedThreadSafeFunctionSum(env)); - exports.Set("typed_threadsafe_function_unref", - InitTypedThreadSafeFunctionUnref(env)); - exports.Set("typed_threadsafe_function", InitTypedThreadSafeFunction(env)); -#endif - exports.Set("typedarray", InitTypedArray(env)); - exports.Set("objectwrap", InitObjectWrap(env)); - exports.Set("objectwrapConstructorException", - InitObjectWrapConstructorException(env)); - exports.Set("objectwrap_function", InitObjectWrapFunction(env)); - exports.Set("objectwrap_removewrap", InitObjectWrapRemoveWrap(env)); - exports.Set("objectwrap_multiple_inheritance", - InitObjectWrapMultipleInheritance(env)); - exports.Set("objectreference", InitObjectReference(env)); - exports.Set("reference", InitReference(env)); - exports.Set("version_management", InitVersionManagement(env)); - exports.Set("thunking_manual", InitThunkingManual(env)); -#if (NAPI_VERSION > 7) - exports.Set("object_freeze_seal", InitObjectFreezeSeal(env)); - exports.Set("type_taggable", InitTypeTaggable(env)); -#endif -#if (NAPI_VERSION > 8) - exports.Set("env_misc", InitEnvMiscellaneous(env)); -#endif + napi_valuetype valuetype1; + napi_typeof(env, args[1], &valuetype1); -#if defined(NODE_ADDON_API_ENABLE_MAYBE) - exports.Set("maybe_check", InitMaybeCheck(env)); -#endif + double value0; + napi_get_value_double(env, args[0], &value0); + + double value1; + napi_get_value_double(env, args[1], &value1); + + napi_value sum; + napi_create_double(env, value0 + value1, &sum); + + return sum; + +} + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; } +EXTERN_C_END -NODE_API_MODULE(entry, EntryInit) +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) +{ + napi_module_register(&demoModule); +} diff --git a/ohos_addon_example/entry/src/main/cpp/types/libentry/Index.d.ts b/ohos_addon_example/entry/src/main/cpp/types/libentry/Index.d.ts deleted file mode 100644 index 2d734a3..0000000 --- a/ohos_addon_example/entry/src/main/cpp/types/libentry/Index.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -export const basic_types_boolean: basic_types_boolean; -export interface basic_types_boolean { - createBoolean(value: boolean): boolean; - createEmptyBoolean(): boolean; - createBooleanFromExistingValue(value: boolean): boolean; - createBooleanFromPrimitive(value: boolean): boolean; - operatorBool(value: boolean): boolean; -} - -export const basic_types_array: basic_types_array; -export interface basic_types_array{ - createArray(len?: number): []; - getLength(arr: []): number; - get(arr:T[],index: number): T; - set(arr: T[],index: number,ele: T): void; -} diff --git a/ohos_addon_example/entry/src/main/cpp/types/libexample/Index.d.ts b/ohos_addon_example/entry/src/main/cpp/types/libexample/Index.d.ts new file mode 100644 index 0000000..693da49 --- /dev/null +++ b/ohos_addon_example/entry/src/main/cpp/types/libexample/Index.d.ts @@ -0,0 +1 @@ +export {} \ No newline at end of file diff --git a/ohos_addon_example/entry/src/main/cpp/types/libentry/oh-package.json5 b/ohos_addon_example/entry/src/main/cpp/types/libexample/oh-package.json5 similarity index 80% rename from ohos_addon_example/entry/src/main/cpp/types/libentry/oh-package.json5 rename to ohos_addon_example/entry/src/main/cpp/types/libexample/oh-package.json5 index ea41072..b163513 100644 --- a/ohos_addon_example/entry/src/main/cpp/types/libentry/oh-package.json5 +++ b/ohos_addon_example/entry/src/main/cpp/types/libexample/oh-package.json5 @@ -1,5 +1,5 @@ { - "name": "libentry.so", + "name": "libexmaple.so", "types": "./Index.d.ts", "version": "1.0.0", "description": "Please describe the basic information." diff --git a/ohos_addon_example/entry/src/main/ets/pages/Index.ets b/ohos_addon_example/entry/src/main/ets/pages/Index.ets index 03dbdd2..933cde8 100644 --- a/ohos_addon_example/entry/src/main/ets/pages/Index.ets +++ b/ohos_addon_example/entry/src/main/ets/pages/Index.ets @@ -1,5 +1,4 @@ import { hilog } from '@kit.PerformanceAnalysisKit'; -import * as testNapi from 'libentry.so'; @Entry @Component @@ -13,9 +12,7 @@ struct Index { .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { - const a = testNapi; - const ret = testNapi.basic_types_boolean.createBoolean(false); - console.log(`${ret}`); + hilog.debug(0x0000,"",""); }) } .width('100%') diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/Ability.test.ets b/ohos_addon_example/entry/src/ohosTest/ets/test/Ability.test.ets index 85c78f6..e826719 100644 --- a/ohos_addon_example/entry/src/ohosTest/ets/test/Ability.test.ets +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/Ability.test.ets @@ -1,5 +1,5 @@ import { hilog } from '@kit.PerformanceAnalysisKit'; -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from './util/framework.test'; export default function abilityTest() { describe('ActsAbilityTest', () => { diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Array.test.ets b/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Array.test.ts similarity index 82% rename from ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Array.test.ets rename to ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Array.test.ts index 28890b4..5734f17 100644 --- a/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Array.test.ets +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Array.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, it, DEFAULT } from '@ohos/hypium'; -import testNapi, {basic_types_array} from 'libentry.so'; +import { describe, expect, it, DEFAULT } from '../util/framework.test'; +import binding from '../util/binding'; export default function basicTypeArray() { describe("basic_type_array_test", () => { it("RunArray", DEFAULT, () => { - const basic_types_array: basic_types_array = testNapi.basic_types_array; + const basic_types_array: ESObject = binding.basic_types_array; const array = basic_types_array.createArray(); expect(basic_types_array.getLength(array)).assertEqual(0); diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Boolean.test.ets b/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Boolean.test.ts similarity index 79% rename from ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Boolean.test.ets rename to ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Boolean.test.ts index 7f382b2..d5d4a00 100644 --- a/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Boolean.test.ets +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/BasicTypes/Boolean.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, it, DEFAULT } from '@ohos/hypium'; -import testNapi, { basic_types_boolean } from 'libentry.so'; +import { describe, expect, it, DEFAULT } from '../util/framework.test'; +import binding from '../util/binding'; export default function basicTypeBoolean() { describe("basic_type_boolean_test", () => { it("RunBoolean", DEFAULT, () => { - const basic_types_boolean: basic_types_boolean = testNapi.basic_types_boolean; + const basic_types_boolean: ESObject = binding.basic_types_boolean; expect(basic_types_boolean.createBoolean(true)).assertTrue(); expect(basic_types_boolean.createBoolean(false)).assertFalse(); diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/binding.ts b/ohos_addon_example/entry/src/ohosTest/ets/test/util/binding.ts new file mode 100644 index 0000000..352ea29 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/binding.ts @@ -0,0 +1,3 @@ +import * as binding from 'libexample.so'; + +export default binding; \ No newline at end of file diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/Constant.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/Constant.js new file mode 100644 index 0000000..734e988 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/Constant.js @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021-2024 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 TAG = "[Hypium]"; + +export const DEFAULT = 0b0000; + +export class PrintTag { + static OHOS_REPORT_WORKER_STATUS = "OHOS_REPORT_WORKER_STATUS"; + static OHOS_REPORT_ALL_RESULT = "OHOS_REPORT_ALL_RESULT"; + static OHOS_REPORT_ALL_CODE = "OHOS_REPORT_ALL_CODE"; + static OHOS_REPORT_ALL_STATUS = "OHOS_REPORT_ALL_STATUS"; + static OHOS_REPORT_RESULT = "OHOS_REPORT_RESULT"; + static OHOS_REPORT_CODE = "OHOS_REPORT_CODE"; + static OHOS_REPORT_STATUS = "OHOS_REPORT_STATUS"; + static OHOS_REPORT_SUM = "OHOS_REPORT_SUM"; + static OHOS_REPORT_STATUS_CODE = "OHOS_REPORT_STATUS_CODE"; +} + +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; +} + +export const 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 +}; + +export const LEVEL = { + 0: 1 << 24, + 1: 1 << 25, + 2: 1 << 26, + 3: 1 << 27, + 4: 1 << 28 +}; + +export const SIZE = { + small: 1 << 16, + medium: 1 << 17, + large: 1 << 18 +}; + +export const KEYSET = [ + "-s class", + "-s notClass", + "-s suite", + "-s itName", + "-s level", + "-s testType", + "-s size", + "-s timeout", + "-s dryRun", + "-s random", + "-s breakOnError", + "-s stress", + "-s coverage", + "-s skipMessage", + "-s runSkipped", + "class", + "notClass", + "suite", + "itName", + "level", + "testType", + "size", + "timeout", + "dryRun", + "random", + "breakOnError", + "stress", + "coverage", + "skipMessage", + "runSkipped" +]; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/core.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/core.js new file mode 100644 index 0000000..5af1e0e --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/core.js @@ -0,0 +1,172 @@ +/* + * 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); + } + } + } + + async fireEvents(serviceName, eventName) { + const eventObj = this.events[serviceName]; + if (!eventObj) { + return; + } + for (const attr in eventObj) { + await 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(abilityDelegator) { + const suiteService = this.getDefaultService("suite"); + const configService = this.getDefaultService("config"); + if (configService["dryRun"] === "true") { + (async function () { + await suiteService.dryRun(abilityDelegator); + })(); + return; + } + setTimeout(() => { + suiteService.execute(); + }, 10); + } +} + +export default Core; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/event.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/event.js new file mode 100644 index 0000000..8784477 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/event.js @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021-2024 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); + } + + async specStart() { + for (const monitor of this.eventMonitors) { + await monitor["specStart"](); + } + } + + async specDone() { + for (const monitor of this.eventMonitors) { + await monitor["specDone"](); + } + } +} + +class SuiteEvent { + constructor(attr) { + this.id = attr.id; + this.suiteContext = attr.coreContext; + this.eventMonitors = []; + } + + subscribeEvent(service) { + this.eventMonitors.push(service); + } + + async suiteStart() { + for (const monitor of this.eventMonitors) { + await monitor["suiteStart"](); + } + } + + async suiteDone() { + for (const monitor of this.eventMonitors) { + await monitor["suiteDone"](); + } + } +} + +class TaskEvent { + constructor(attr) { + this.id = attr.id; + this.coreContext = attr.coreContext; + this.eventMonitors = []; + } + + subscribeEvent(service) { + this.eventMonitors.push(service); + } + + async taskStart() { + for (const monitor of this.eventMonitors) { + await monitor["taskStart"](); + } + } + + async taskDone() { + for (const monitor of this.eventMonitors) { + await monitor["taskDone"](); + } + } + + incorrectFormat() { + for (const monitor of this.eventMonitors) { + monitor["incorrectFormat"](); + } + } + + incorrectTestSuiteFormat() { + for (const monitor of this.eventMonitors) { + monitor.incorrectTestSuiteFormat(); + } + } +} + +export { SpecEvent, TaskEvent, SuiteEvent }; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/interface.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/interface.js new file mode 100644 index 0000000..2ea300d --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/interface.js @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021-2024 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) { + return Reflect.has(core, "describe") + ? core.describe(desc, func) + : (desc, func) => {}; +}; +const it = function (desc, filter, func) { + return Reflect.has(core, "it") + ? core.it(desc, filter, func) + : (desc, filter, func) => {}; +}; +const beforeItSpecified = function (itDescs, func) { + return Reflect.has(core, "beforeItSpecified") + ? core.beforeItSpecified(itDescs, func) + : (itDescs, func) => {}; +}; + +const afterItSpecified = function (itDescs, func) { + return Reflect.has(core, "afterItSpecified") + ? core.afterItSpecified(itDescs, func) + : (itDescs, func) => {}; +}; +const beforeEach = function (func) { + return Reflect.has(core, "beforeEach") ? core.beforeEach(func) : (func) => {}; +}; +const afterEach = function (func) { + return Reflect.has(core, "afterEach") ? core.afterEach(func) : (func) => {}; +}; +const beforeAll = function (func) { + return Reflect.has(core, "beforeAll") ? core.beforeAll(func) : (func) => {}; +}; +const afterAll = function (func) { + return Reflect.has(core, "afterAll") ? core.afterAll(func) : (func) => {}; +}; +const expect = function (actualValue) { + return Reflect.has(core, "expect") + ? core.expect(actualValue) + : (actualValue) => {}; +}; + +const xdescribe = function (desc, func) { + return Reflect.has(core, "xdescribe") + ? core.xdescribe(desc, func, null) + : (desc, func, reason) => {}; +}; +xdescribe.reason = (reason) => { + return (desc, func) => { + return Reflect.has(core, "xdescribe") + ? core.xdescribe(desc, func, reason) + : (desc, func, reason) => {}; + }; +}; +const xit = function (desc, filter, func) { + return Reflect.has(core, "xit") + ? core.xit(desc, filter, func, null) + : (desc, filter, func, reason) => {}; +}; +xit.reason = (reason) => { + return (desc, filter, func) => { + return Reflect.has(core, "xit") + ? core.xit(desc, filter, func, reason) + : (desc, filter, func, reason) => {}; + }; +}; + +export { + describe, + it, + beforeAll, + beforeEach, + afterEach, + afterAll, + expect, + beforeItSpecified, + afterItSpecified, + xdescribe, + xit +}; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/ExpectExtend.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/ExpectExtend.js new file mode 100644 index 0000000..04557d7 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/ExpectExtend.js @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021-2024 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"; +import assertLargerOrEqual from "./assertLargerOrEqual"; +import assertLessOrEqual from "./assertLessOrEqual"; +import assertNaN from "./assertNaN"; +import assertNegUnlimited from "./assertNegUnlimited"; +import assertPosUnlimited from "./assertPosUnlimited"; +import assertDeepEquals from "./deepEquals/assertDeepEquals"; +import assertPromiseIsPending from "./assertPromiseIsPending"; +import assertPromiseIsRejected from "./assertPromiseIsRejected"; +import assertPromiseIsRejectedWith from "./assertPromiseIsRejectedWith"; +import assertPromiseIsRejectedWithError from "./assertPromiseIsRejectedWithError"; +import assertPromiseIsResolved from "./assertPromiseIsResolved"; +import assertPromiseIsResolvedWith from "./assertPromiseIsResolvedWith"; +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; + this.matchers.assertLargerOrEqual = assertLargerOrEqual; + this.matchers.assertLessOrEqual = assertLessOrEqual; + this.matchers.assertNaN = assertNaN; + this.matchers.assertNegUnlimited = assertNegUnlimited; + this.matchers.assertPosUnlimited = assertPosUnlimited; + this.matchers.assertDeepEquals = assertDeepEquals; + this.matchers.assertPromiseIsPending = assertPromiseIsPending; + this.matchers.assertPromiseIsRejected = assertPromiseIsRejected; + this.matchers.assertPromiseIsRejectedWith = assertPromiseIsRejectedWith; + this.matchers.assertPromiseIsRejectedWithError = + assertPromiseIsRejectedWithError; + this.matchers.assertPromiseIsResolved = assertPromiseIsResolved; + this.matchers.assertPromiseIsResolvedWith = assertPromiseIsResolvedWith; + } + + 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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertClose.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertClose.js new file mode 100644 index 0000000..2d95557 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertClose.js @@ -0,0 +1,48 @@ +/* + * 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) { + 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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertContain.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertContain.js new file mode 100644 index 0000000..661fb03 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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: "expect false, " + actualValue + " do not have " + expect[0] + }; +} + +export default assertContain; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertFail.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertFail.js new file mode 100644 index 0000000..5e16b41 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertFalse.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertFalse.js new file mode 100644 index 0000000..4f172c2 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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: "expect false, actualValue is " + actualValue + }; +} + +export default assertFalse; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertInstanceOf.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertInstanceOf.js new file mode 100644 index 0000000..9dc2c3f --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertInstanceOf.js @@ -0,0 +1,37 @@ +/* + * 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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLarger.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLarger.js new file mode 100644 index 0000000..71c14bd --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLargerOrEqual.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLargerOrEqual.js new file mode 100644 index 0000000..e410132 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLargerOrEqual.js @@ -0,0 +1,23 @@ +/* + * 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. + */ + +function assertLargerOrEqual(actualValue, expected) { + return { + pass: actualValue >= expected[0], + message: actualValue + " is not larger than " + expected[0] + }; +} + +export default assertLargerOrEqual; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLess.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLess.js new file mode 100644 index 0000000..aae6ee4 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLessOrEqual.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLessOrEqual.js new file mode 100644 index 0000000..31e19fc --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertLessOrEqual.js @@ -0,0 +1,23 @@ +/* + * 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. + */ + +function assertLessOrEqual(actualValue, expected) { + return { + pass: actualValue <= expected[0], + message: actualValue + " is not less than " + expected[0] + }; +} + +export default assertLessOrEqual; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNaN.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNaN.js new file mode 100644 index 0000000..23ab16e --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNaN.js @@ -0,0 +1,23 @@ +/* + * 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. + */ + +function assertNaN(actualValue) { + return { + pass: actualValue !== actualValue, + message: "expect NaN, actualValue is " + actualValue + }; +} + +export default assertNaN; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNegUnlimited.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNegUnlimited.js new file mode 100644 index 0000000..e406d96 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNegUnlimited.js @@ -0,0 +1,24 @@ +/* + * 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. + */ + +function assertNegUnlimited(actualValue) { + return { + pass: actualValue === Number.NEGATIVE_INFINITY, + message: + "Expected actualValue not to be -Infinity. actualValue is," + actualValue + }; +} + +export default assertNegUnlimited; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNull.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertNull.js new file mode 100644 index 0000000..cf30c6c --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPosUnlimited.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPosUnlimited.js new file mode 100644 index 0000000..00c2e5e --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPosUnlimited.js @@ -0,0 +1,25 @@ +/* + * 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. + */ + +function assertPosUnlimited(actualValue) { + return { + pass: actualValue === Number.POSITIVE_INFINITY, + message: + "Expected actualValue is POSITIVE_INFINITY. actualValue is," + + actualValue + }; +} + +export default assertPosUnlimited; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsPending.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsPending.js new file mode 100644 index 0000000..9dc5d95 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsPending.js @@ -0,0 +1,46 @@ +/* + * 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 isPromiseLike from "./isPromiseLike"; + +function assertPromiseIsPending(actualPromise) { + if (!isPromiseLike(actualPromise)) { + return Promise.reject().then( + function () {}, + function () { + return { pass: false, message: "Expected not be called on a promise." }; + } + ); + } + const helper = {}; + return Promise.race([actualPromise, Promise.resolve(helper)]).then( + function (got) { + return helper === got + ? { pass: true, message: "actualValue is isPending" } + : { + pass: false, + message: "expect isPending, actualValue is resolve" + }; + }, + function () { + return { + pass: false, + message: "expect isPending, actualValue is reject" + }; + } + ); +} + +export default assertPromiseIsPending; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejected.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejected.js new file mode 100644 index 0000000..093dc25 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejected.js @@ -0,0 +1,40 @@ +/* + * 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 isPromiseLike from "./isPromiseLike"; + +function assertPromiseIsRejected(actualPromise) { + if (!isPromiseLike(actualPromise)) { + return Promise.reject().then( + function () {}, + function () { + return { pass: false, message: "Expected not be called on a promise." }; + } + ); + } + return actualPromise.then( + function (got) { + return { + pass: false, + message: "expect isRejected, but actualValue is resolve" + }; + }, + function () { + return { pass: true, message: "actualValue is isRejected" }; + } + ); +} + +export default assertPromiseIsRejected; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejectedWith.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejectedWith.js new file mode 100644 index 0000000..464d677 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejectedWith.js @@ -0,0 +1,71 @@ +/* + * 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 isPromiseLike from "./isPromiseLike"; + +function assertPromiseIsRejectedWith(actualPromise, expectedValue) { + if (!isPromiseLike(actualPromise)) { + return Promise.reject().then( + function () {}, + function () { + return { pass: false, message: "Expected not be called on a promise." }; + } + ); + } + + function tips(passed) { + return ( + "Expected a promise " + + (passed ? "not " : "") + + "to be rejected with " + + JSON.stringify(expectedValue[0]) + ); + } + + return actualPromise.then( + function (got) { + return { + pass: false, + message: tips(false) + " but actualValue is resolve" + }; + }, + function (actualValue) { + if (actualValue?.message === expectedValue?.message) { + return { + pass: true, + message: "actualValue was rejected with " + actualValue.message + "." + }; + } + if (JSON.stringify(actualValue) == JSON.stringify(expectedValue[0])) { + return { + pass: true, + message: + "actualValue was rejected with " + JSON.stringify(actualValue) + "." + }; + } else { + return { + pass: false, + message: + tips(false) + + " but it was rejected with " + + JSON.stringify(actualValue) + + "." + }; + } + } + ); +} + +export default assertPromiseIsRejectedWith; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejectedWithError.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejectedWithError.js new file mode 100644 index 0000000..121b7ec --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsRejectedWithError.js @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022-2024 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 isPromiseLike from "./isPromiseLike"; + +function assertPromiseIsRejectedWithError(actualPromise, expectedValue) { + if (!isPromiseLike(actualPromise)) { + return Promise.reject().then( + function () {}, + function () { + return { pass: false, message: "Expected not be called on a promise." }; + } + ); + } + return actualPromise.then( + function (got) { + return { + pass: false, + message: "Expected a promise to be rejected but actualValue is resolve" + }; + }, + function (actualValue) { + return matchError(actualValue, expectedValue); + } + ); +} + +function matchError(actualValue, expectedValue) { + if (expectedValue.length == 1 && typeof expectedValue[0] === "function") { + if (expectedValue[0].name === actualValue.__proto__.name) { + return { + pass: true, + message: "actual error type is " + actualValue.name + "." + }; + } + return { + pass: false, + message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.` + }; + } + + if (expectedValue.length == 1 && typeof expectedValue[0] === "string") { + if (expectedValue[0] === actualValue.message) { + return { + pass: true, + message: `actual error message is ${actualValue.message}.` + }; + } + return { + pass: false, + message: `except error message ${expectedValue[0]},but actual is ${actualValue.message}.` + }; + } + + if (expectedValue.length == 1) { + return { + pass: false, + message: + "When only one parameter, it should be error type or error message." + }; + } + + if ( + expectedValue.length == 2 && + typeof expectedValue[0] === "function" && + expectedValue[0].name === actualValue.name + ) { + if ( + typeof expectedValue[1] === "string" && + actualValue.message === expectedValue[1] + ) { + return { + pass: true, + message: "actual error message is " + actualValue.message + "." + }; + } + return { + pass: false, + message: `except error message is ${expectedValue[1]},but actual is ${actualValue.message}.` + }; + } + + if ( + expectedValue.length == 2 && + typeof expectedValue[0] === "function" && + expectedValue[0].name !== actualValue.name + ) { + if ( + typeof expectedValue[1] === "string" && + actualValue.message === expectedValue[1] + ) { + return { + pass: false, + message: `except error type is ${expectedValue[0].name},but actual is ${actualValue.name}.` + }; + } + return { + pass: false, + message: "except error type and message are incorrect." + }; + } + if (expectedValue.length > 2) { + return { pass: false, message: "Up to two parameters are supported." }; + } + return { pass: true, message: "not equal type" }; +} + +export default assertPromiseIsRejectedWithError; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsResolved.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsResolved.js new file mode 100644 index 0000000..7ab977b --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsResolved.js @@ -0,0 +1,45 @@ +/* + * 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 isPromiseLike from "./isPromiseLike"; + +function assertPromiseIsResolved(actualPromise) { + if (!isPromiseLike(actualPromise)) { + return Promise.reject().then( + function () {}, + function () { + return { pass: false, message: "Expected not be called on a promise." }; + } + ); + } + + return actualPromise.then( + function (got) { + return { pass: true, message: "actualValue is isResolved" }; + }, + function (rej) { + return { + pass: false, + message: + "Expected a promise to be resolved but it was " + + "rejected with " + + JSON.stringify(rej) + + "." + }; + } + ); +} + +export default assertPromiseIsResolved; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsResolvedWith.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsResolvedWith.js new file mode 100644 index 0000000..052960c --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertPromiseIsResolvedWith.js @@ -0,0 +1,61 @@ +/* + * 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 isPromiseLike from "./isPromiseLike"; + +function assertPromiseIsResolvedWith(actualPromise, expectedValue) { + if (!isPromiseLike(actualPromise)) { + return Promise.reject().then( + function () {}, + function () { + return { pass: false, message: "Expected not be called on a promise." }; + } + ); + } + + function tips(passed) { + return ( + "Expected a promise " + + (passed ? "not " : "") + + "to be resolved with " + + JSON.stringify(expectedValue[0]) + ); + } + + return actualPromise.then( + function (got) { + if (JSON.stringify(got) == JSON.stringify(expectedValue[0])) { + return { + pass: true, + message: "actualValue was resolved with " + JSON.stringify(got) + "." + }; + } + return { + pass: false, + message: + tips(false) + " but it was resolved with " + JSON.stringify(got) + "." + }; + }, + function (rej) { + return { + pass: false, + message: + tips(false) + " but it was rejected with " + JSON.stringify(rej) + "." + }; + } + ); +} + +export default assertPromiseIsResolvedWith; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertThrowError.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertThrowError.js new file mode 100644 index 0000000..ce6e47a --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertThrowError.js @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021-2024 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 message = ""; + 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 (!expected && !(err instanceof Error)) { + return { + pass: false, + message: "An error is not thrown while it is expected!" + }; + } + if (err instanceof Error) { + let type = typeof expected?.[0]; + if (type === "function") { + result = err.constructor.name === expected[0].name; + message = + "expected throw failed , " + + err.constructor.name + + " is not " + + expected[0].name; + } else if (type === "string") { + result = err.message.includes(expected[0]); + message = + "expected throw failed , " + err.message + " is not " + expected[0]; + } else if (type === "object") { + if (expected[0].message) { + result = err.message.includes(expected[0].message); + message = + "expected throw failed , " + + err.message + + " is not " + + expected[0].message; + } + + if (expected[0].code) { + result = err.code.includes(expected[0].code); + message = + "expected throw failed , " + err.code + " is not " + expected[0].code; + } + } else if (type === "undefined") { + result = true; + } + } + return { + pass: result, + message: message + }; +} + +export default assertThrowError; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertUndefined.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/assertUndefined.js new file mode 100644 index 0000000..9792f00 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/deepEquals/DeepTypeUtils.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/deepEquals/DeepTypeUtils.js new file mode 100644 index 0000000..7310b80 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/deepEquals/DeepTypeUtils.js @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2022-2024 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 DeepTypeUtils { + static getType(value) { + return Object.prototype.toString.apply(value); + } + static isA(typeName, value) { + return this.getType(value) === "[object " + typeName + "]"; + } + static isAsymmetricEqualityTester(obj) { + return obj ? this.isA("Function", obj.asymmetricMatch) : false; + } + + /** + * 是否是function + * @param value + */ + static isFunction(value) { + return this.isA("Function", value); + } + + static isBigInt(value) { + return this.isA("BigInt", value); + } + + static isTypedArray(value) { + return ArrayBuffer.isView(value); + } + + /** + * 是否是undefined + * @param obj + */ + static isUndefined(obj) { + return obj === void 0; + } + + /** + * 是否是Node + * @param obj + */ + static isDomNode(obj) { + return ( + obj !== null && + typeof obj === "object" && + typeof obj.nodeType === "number" && + typeof obj.nodeName === "string" + ); + } + + /** + * 是否是promise对象 + * @param obj + */ + static isPromise(obj) { + return !!obj && obj.constructor === Promise; + } + /** + * 是否是map对象 + * @param obj + */ + static isMap(obj) { + return ( + obj !== null && typeof obj !== "undefined" && obj.constructor === Map + ); + } + + /** + * 是否是set对象 + * @param obj 对象 + */ + static isSet(obj) { + return ( + obj !== null && typeof obj !== "undefined" && obj.constructor === Set + ); + } + + /** + * 对象是否有key属性 + * @param obj 对象 + * @param key 对象属性名称 + */ + static has(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); + } + + /** + * 获取对象的自有属性 + * @param obj 对象 + * @param isArray 是否是数组,[object Array] + */ + static keys(obj, isArray) { + const extraKeys = []; + // 获取对象所有属性 + const allKeys = this.getAllKeys(obj); + if (!isArray) { + return allKeys; + } + if (allKeys.length === 0) { + return allKeys; + } + for (const k of allKeys) { + if (typeof k === "symbol" || !/^[0-9]+$/.test(k)) { + extraKeys.push(k); + } + } + return extraKeys; + } + + /** + * 获取obj对象的所有属性 + * @param obj obj对象 + */ + static getAllKeys(obj) { + const keys = []; + for (let key in obj) { + if (this.has(obj, key)) { + keys.push(key); + } + } + const symbols = Object.getOwnPropertySymbols(obj); + for (const sym of symbols) { + // obj.propertyIsEnumerable(sym) + if (Object.prototype.propertyIsEnumerable.call(obj, sym)) { + keys.push(sym); + } + } + return keys; + } +} +export default DeepTypeUtils; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/deepEquals/assertDeepEquals.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/deepEquals/assertDeepEquals.js new file mode 100644 index 0000000..9a0f35e --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/deepEquals/assertDeepEquals.js @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2022-2024 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 DeepTypeUtils from "./DeepTypeUtils"; +function assertDeepEquals(actualValue, expected) { + let result = eq(actualValue, expected[0]); + let msg = logMsg(actualValue, expected[0]); + return { + pass: result, + message: msg + }; +} + +/** + * 获取失败显示日志 + * @param actualValue 实际对象 + * @param expected 期待比较对象 + */ +function logMsg(actualValue, expected) { + // 获取a的对象名称 + const aClassName = Object.prototype.toString.call(actualValue); + const bClassName = Object.prototype.toString.call(expected); + let actualMsg; + let expectMsg; + if (aClassName == "[object Function]") { + actualMsg = "actualValue Function"; + } else if (aClassName == "[object Promise]") { + actualMsg = "actualValue Promise"; + } else if (aClassName == "[object Set]" || aClassName == "[object Map]") { + actualMsg = JSON.stringify(Array.from(actualValue)); + } else if (aClassName == "[object RegExp]") { + actualMsg = JSON.stringify(actualValue.source.replace("\\", "")); + } else if (aClassName == "[object BigInt]") { + actualMsg = actualValue; + } else if (aClassName == "[object Error]") { + actualMsg = actualValue.message; + } else if (aClassName == "[object ArrayBuffer]") { + actualMsg = actualValue.byteLength; + } else { + actualMsg = String(actualValue); + } + if (bClassName == "[object Function]") { + expectMsg = "expected Function"; + } else if (bClassName == "[object Promise]") { + expectMsg = "expected Promise"; + } else if (bClassName == "[object Set]" || bClassName == "[object Map]") { + expectMsg = JSON.stringify(Array.from(expected)); + } else if (bClassName == "[object RegExp]") { + expectMsg = JSON.stringify(expected.source.replace("\\", "")); + } else if (bClassName == "[object BigInt]") { + expectMsg = expected; + } else if (bClassName == "[object Error]") { + expectMsg = expected.message; + } else if (bClassName == "[object ArrayBuffer]") { + expectMsg = expected.byteLength; + } else { + expectMsg = String(expected); + } + return actualMsg + " is not deep equal " + expectMsg; +} + +function eq(a, b) { + let result = true; + + if (a === b) { + result = a !== 0 || 1 / a === 1 / b; + return result; + } + + if (a === null || b === null) { + result = a === b; + return result; + } + + if (DeepTypeUtils.isBigInt(a)) { + return a.toString() === b.toString(); + } + + if (DeepTypeUtils.isTypedArray(a)) { + if (a.constructor !== b.constructor || a.length !== b.length) { + return false; + } + for (let i = 0; i < a.length; i++) { + if (!eq(a[i], b[i])) { + return false; + } + } + return true; + } + + // 获取a的对象名称 + const aClassName = Object.prototype.toString.call(a); + const bClassName = Object.prototype.toString.call(b); + // 不同类型不同对象 + if (aClassName !== bClassName) { + return false; + } + if ( + aClassName === "[object String]" || + aClassName === "[object Number]" || + aClassName === "[object Date]" || + aClassName === "[object Boolean]" || + aClassName === "[object ArrayBuffer]" || + aClassName === "[object RegExp]" || + aClassName === "[object Error]" + ) { + result = isEqualSampleObj(a, b); + return result; + } + + if (typeof a !== "object" || typeof b !== "object") { + return false; + } + + if ( + DeepTypeUtils.isDomNode(a) || + DeepTypeUtils.isPromise(a) || + DeepTypeUtils.isFunction(a) + ) { + result = isEqualNodeOrPromiseOrFunction(a, b); + return result; + } + + if ( + aClassName === "[object Array]" || + aClassName === "[object Map]" || + aClassName === "[object Set]" + ) { + result = isEqualCollection(a, b); + return result; + } + + result = isEqualObj(a, b); + return result; +} + +function isEqualNodeOrPromiseOrFunction(a, b) { + let equalNodeOrPromiseOrFunction = true; + if (DeepTypeUtils.isDomNode(a) && DeepTypeUtils.isDomNode(b)) { + const aIsDomNode = DeepTypeUtils.isDomNode(a); + const bIsDomNode = DeepTypeUtils.isDomNode(b); + if (aIsDomNode && bIsDomNode) { + // At first try to use DOM3 method isEqualNode + equalNodeOrPromiseOrFunction = a.isEqualNode(b); + return equalNodeOrPromiseOrFunction; + } + if (aIsDomNode || bIsDomNode) { + equalNodeOrPromiseOrFunction = false; + return false; + } + } + + if (DeepTypeUtils.isPromise(a) && DeepTypeUtils.isPromise(b)) { + const aIsPromise = DeepTypeUtils.isPromise(a); + const bIsPromise = DeepTypeUtils.isPromise(b); + // 俩个Promise对象 + if (aIsPromise && bIsPromise) { + equalNodeOrPromiseOrFunction = a === b; + return a === b; + } + } + if (DeepTypeUtils.isFunction(a) && DeepTypeUtils.isFunction(b)) { + // 俩个函数对象 + const aCtor = a.constructor, + bCtor = b.constructor; + if ( + aCtor !== bCtor && + DeepTypeUtils.isFunction(aCtor) && + DeepTypeUtils.isFunction(bCtor) && + a instanceof aCtor && + b instanceof bCtor && + !(aCtor instanceof aCtor && bCtor instanceof bCtor) + ) { + equalNodeOrPromiseOrFunction = false; + return false; + } + } + return equalNodeOrPromiseOrFunction; +} + +function isEqualCollection(a, b) { + let equalCollection = true; + // 获取a的对象名称 + const aClassName = Object.prototype.toString.call(a); + const bClassName = Object.prototype.toString.call(b); + // 都是数组 + if (aClassName === "[object Array]") { + equalCollection = isEqualArray(a, b); + return equalCollection; + } + + // 都是Map + if (DeepTypeUtils.isMap(a) && DeepTypeUtils.isMap(b)) { + equalCollection = isEqualMap(a, b); + return equalCollection; + } + + // 都是Set + if (DeepTypeUtils.isSet(a) && DeepTypeUtils.isSet(b)) { + equalCollection = isEqualSet(a, b); + return equalCollection; + } + + return true; +} + +function isEqualSampleObj(a, b) { + let equalSampleObj = true; + const aClassName = Object.prototype.toString.call(a); + const bClassName = Object.prototype.toString.call(b); + // 俩个string对象 + if (aClassName === "[object String]") { + equalSampleObj = a === String(b); + return equalSampleObj; + } + // 俩个Number对象 + if (aClassName === "[object Number]") { + equalSampleObj = + a !== +a ? b !== +b : a === 0 && b === 0 ? 1 / a === 1 / b : a === +b; + return equalSampleObj; + } + + // 俩个Date对象/ boolean对象 + if (aClassName === "[object Date]" || aClassName === "[object Boolean]") { + equalSampleObj = +a === +b; + return equalSampleObj; + } + + // 俩个ArrayBuffer + if (aClassName === "[object ArrayBuffer]") { + equalSampleObj = eq(new Uint8Array(a), new Uint8Array(b)); + return equalSampleObj; + } + + // 正则表达式 + if (aClassName === "[object RegExp]") { + return ( + a.source === b.source && + a.global === b.global && + a.multiline === b.multiline && + a.ignoreCase === b.ignoreCase + ); + } + + if (a instanceof Error && b instanceof Error) { + equalSampleObj = a.message === b.message; + return equalSampleObj; + } + + return equalSampleObj; +} + +function isEqualObj(a, b) { + let equalObj = true; + const aClassName = Object.prototype.toString.call(a); + const bClassName = Object.prototype.toString.call(b); + const aKeys = DeepTypeUtils.keys(a, aClassName === "[object Array]"); + let size = aKeys.length; + + // 俩个对象属性长度不一致, 俩对象不相同 + if (DeepTypeUtils.keys(b, bClassName === "[object Array]").length !== size) { + return false; + } + + // 俩对象属性数量相同, 递归比较每个属性值得值 + for (const key of aKeys) { + // b 没有 key 属性 + if (!DeepTypeUtils.has(b, key)) { + equalObj = false; + continue; + } + if (!eq(a[key], b[key])) { + equalObj = false; + } + } + return equalObj; +} + +function isEqualArray(a, b) { + let equalArray = true; + const aLength = a.length; + const bLength = b.length; + if (aLength !== bLength) { + // 数组长度不同,不是同一个对象 + return false; + } + for (let i = 0; i < aLength || i < bLength; i++) { + // 递归每一个元素是否相同 + equalArray = + eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0) && + equalArray; + } + return equalArray; +} + +function isEqualMap(a, b) { + let equalMap = true; + if (a.size !== b.size) { + return false; + } + const keysA = []; + const keysB = []; + a.forEach(function (valueA, keyA) { + keysA.push(keyA); + }); + b.forEach(function (valueB, keyB) { + keysB.push(keyB); + }); + const mapKeys = [keysA, keysB]; + const cmpKeys = [keysB, keysA]; + for (let i = 0; equalMap && i < mapKeys.length; i++) { + const mapIter = mapKeys[i]; + const cmpIter = cmpKeys[i]; + + for (let j = 0; equalMap && j < mapIter.length; j++) { + const mapKey = mapIter[j]; + const cmpKey = cmpIter[j]; + const mapValueA = a.get(mapKey); + let mapValueB; + if (eq(mapKey, cmpKey)) { + mapValueB = b.get(cmpKey); + } else { + mapValueB = b.get(mapKey); + } + equalMap = eq(mapValueA, mapValueB); + } + } + return equalMap; +} + +function isEqualSet(a, b) { + let equalSet = true; + if (a.size !== b.size) { + return false; + } + const valuesA = []; + a.forEach(function (valueA) { + valuesA.push(valueA); + }); + const valuesB = []; + b.forEach(function (valueB) { + valuesB.push(valueB); + }); + const setPairs = [ + [valuesA, valuesB], + [valuesB, valuesA] + ]; + for (let i = 0; equalSet && i < setPairs.length; i++) { + const baseValues = setPairs[i][0]; + const otherValues = setPairs[i][1]; + for (const baseValue of baseValues) { + let found = false; + for (let j = 0; !found && j < otherValues.length; j++) { + const otherValue = otherValues[j]; + // 深度比较对象 + found = eq(baseValue, otherValue); + } + equalSet = equalSet && found; + } + } + return equalSet; +} + +export default assertDeepEquals; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/isPromiseLike.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/isPromiseLike.js new file mode 100644 index 0000000..aa00f58 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/assert/isPromiseLike.js @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021-2024 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/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/DataDriver.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/DataDriver.js new file mode 100644 index 0000000..b7bec1e --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/DataDriver.js @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2021-2024 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"); + } + + getSpecParamsValue(specs) { + let specParams = []; + let specDesc = this.specService.getCurrentRunningSpec().description; + if (specs === null || specs === undefined) { + return specParams; + } + 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; + } + + 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) && + typeof describeValue === "object" && + describeValue.constructor === Array && + describeValue.includes(suiteDesc) + ) { + let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []); + return this.getSpecParamsValue(specs); + } + } + 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; + } + + getStressNum(specs, specDesc) { + let stress = 1; + if (specs === null || specs === undefined) { + return stress; + } + 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; + } + + 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) && + typeof describeValue === "object" && + describeValue.constructor === Array && + describeValue.includes(suiteDesc) + ) { + let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []); + return this.getStressNum(specs, specDesc); + } + } + 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) && + typeof describeValue === "object" && + describeValue.constructor === Array && + describeValue.includes(suiteDesc) + ) { + let tempStress = ObjectUtils.get(suiteItem, STRESS_KEY, stress); + return Number.isInteger(tempStress) && tempStress >= 1 + ? tempStress + : stress; + } + } + return stress; + } +} + +export default DataDriver; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/Filter.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/Filter.js new file mode 100644 index 0000000..83bb246 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/Filter.js @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2021-2024 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 { LEVEL, SIZE, TESTTYPE } from "../../Constant"; + +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 + .split(",") + .some((item) => item == 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); + } +} + +class NestFilter { + filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc) { + let targetSuiteName = ""; + for (let key in suiteStack) { + targetSuiteName = targetSuiteName + "." + suiteStack[key].description; + } + targetSuiteName = targetSuiteName.substring(2); + const targetSpecName = targetSuiteName + "#" + desc; + let isFilter = true; + if (targetSpecArray.includes(targetSpecName)) { + return false; + } + for (let index in targetSuiteArray) { + if (targetSuiteName.startsWith(targetSuiteArray[index])) { + return false; + } + } + return isFilter; + } + + filterNotClass(notClass, suiteStack, desc) { + let filterNotClass = false; + if (notClass != null) { + let notClassArray = notClass.split(","); + let targetSuiteName = ""; + for (let key in suiteStack) { + targetSuiteName = targetSuiteName + "." + suiteStack[key].description; + } + targetSuiteName = targetSuiteName.substring(2); + const targetSpecName = targetSuiteName + "#" + desc; + if ( + notClassArray.includes(targetSpecName) || + notClassArray.some((key) => targetSpecName.startsWith(key)) + ) { + filterNotClass = true; + } + } + return filterNotClass; + } + + filterLevelOrSizeOrTestType(level, size, testType, filter) { + let result = false; + if (filter === 0 || filter === "0") { + return result; + } + if (level == null && size == null && testType == null) { + return result; + } + if (level != null) { + let levelFilter = LEVEL[`${level}`]; + result = result || filter === levelFilter; + } + if (size != null) { + let sizeFilter = SIZE[`${size}`]; + result = result || filter === sizeFilter; + } + if (testType != null) { + let testTypeFilter = TESTTYPE[`${testType}`]; + result = result || filter === testTypeFilter; + } + return !result; + } +} +export { + ClassFilter, + NotClassFilter, + SuiteAndItNameFilter, + TestTypesFilter, + NestFilter +}; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/configService.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/configService.js new file mode 100644 index 0000000..749dc37 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/config/configService.js @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2021-2024 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, + NestFilter +} from "./Filter"; +import { TAG, TESTTYPE, LEVEL, SIZE, KEYSET } from "../../Constant"; +const STRESS_RULE = /^[1-9]\d*$/; + +class ConfigService { + constructor(attr) { + this.id = attr.id; + this.supportAsync = true; // 默认异步处理测试用例 + this.random = false; + this.filterValid = []; + 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; + // 遇错即停模式配置 + this.breakOnError = false; + // 压力测试配置 + this.stress = null; + this.skipMessage = false; + this.runSkipped = ""; + this.filterXdescribe = []; + } + + init(coreContext) { + this.coreContext = coreContext; + } + + isNormalInteger(str) { + const n = Math.floor(Number(str)); + return n !== Infinity && String(n) === String(str) && n >= 0; + } + + getStress() { + if ( + this.stress === undefined || + this.stress === "" || + this.stress === null + ) { + return 1; + } + return !this.stress.match(STRESS_RULE) ? 1 : Number.parseInt(this.stress); + } + + 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); + } + } + + let paramKeys = [ + "dryRun", + "random", + "breakOnError", + "coverage", + "skipMessage" + ]; + for (const key of paramKeys) { + if ( + params[key] !== undefined && + params[key] !== "true" && + params[key] !== "false" + ) { + this.filterValid.push(`${key}:${params[key]}`); + } + } + + // 压力测试参数验证,正整数 + if ( + params.stress !== undefined && + params.stress !== "" && + params.stress !== null + ) { + if (!params.stress.match(STRESS_RULE)) { + this.filterValid.push("stress:" + params.stress); + } + } + + let nameRule = /^[A-Za-z]{1}[\w#,.]*$/; + let paramClassKeys = ["class", "notClass"]; + for (const key of paramClassKeys) { + if ( + params[key] !== undefined && + params[key] !== "" && + params[key] !== null + ) { + let classArray = params[key].split(","); + classArray.forEach((item) => + !item.match(nameRule) + ? this.filterValid.push(`${key}:${params[key]}`) + : null + ); + } + } + } + + 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.dryRun = params.dryRun; + this.breakOnError = params.breakOnError; + this.random = params.random === "true" ? true : false; + this.stress = params.stress; + this.coverage = params.coverage; + this.skipMessage = params.skipMessage; + this.runSkipped = params.runSkipped; + this.filterParam = { + testType: TESTTYPE, + level: LEVEL, + size: SIZE + }; + this.parseParams(); + } catch (err) { + console.info(`${TAG}setConfig error: ${err.message}`); + } + } + + 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(`${TAG}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; + } + + filterWithNest(desc, filter) { + let filterArray = []; + const nestFilter = new NestFilter(); + const targetSuiteArray = + this.coreContext.getDefaultService("suite").targetSuiteArray; + const targetSpecArray = + this.coreContext.getDefaultService("suite").targetSpecArray; + const suiteStack = this.coreContext.getDefaultService("suite").suitesStack; + let isFilter = nestFilter.filterNestName( + targetSuiteArray, + targetSpecArray, + suiteStack, + desc + ); + const isFullRun = this.coreContext.getDefaultService("suite").fullRun; + if ( + typeof this.filter !== "undefined" && + this.filter !== 0 && + filter !== 0 + ) { + filterArray.push(new TestTypesFilter("", "", filter, this.filter)); + return filterArray + .map((item) => item.filterIt()) + .reduce((pre, cur) => pre || cur, false); + } + if (isFilter && !isFullRun) { + return true; + } + return nestFilter.filterNotClass(this.notClass, suiteStack, desc); + } + + isRandom() { + return this.random || false; + } + + isBreakOnError() { + return this.breakOnError !== "true" ? false : true; + } + + setSupportAsync(value) { + this.supportAsync = value; + } + + isSupportAsync() { + return this.supportAsync; + } + + translateParams(parameters) { + const keySet = new Set(KEYSET); + 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(KEYSET); + let targetParams = ""; + for (const key in parameters) { + if (keySet.has(key)) { + targetParams += " " + key + " " + parameters[key]; + } + } + return targetParams.trim(); + } + + execute() {} + + checkIfSuiteInSkipRun(desc) { + return this.runSkipped.split(",").some((item) => { + return ( + item === desc || + item.startsWith(desc + ".") || + item.startsWith(desc + "#") || + desc.startsWith(item + ".") || + this.runSkipped === "skipped" + ); + }); + } + + checkIfSpecInSkipRun(desc) { + return this.runSkipped.split(",").some((item) => { + if (item.includes("#")) { + return item === desc; + } else { + return ( + desc.startsWith(item + ".") || + desc.startsWith(item + "#") || + this.runSkipped === "skipped" + ); + } + }); + } +} + +export { ConfigService }; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/coverage/coverageCollect.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/coverage/coverageCollect.js new file mode 100644 index 0000000..c46e9be --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/coverage/coverageCollect.js @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 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 SysTestKit from "../kit/SysTestKit"; +import fs from "@ohos.file.fs"; +import { TAG } from "../../Constant"; + +const jsCoverageFileName = "js_coverage.json"; + +export async function collectCoverageData() { + if (globalThis.__coverage__ === undefined) { + console.info(`${TAG} globalThis not have coverage`); + return; + } + const strJson = JSON.stringify(globalThis.__coverage__); + let testMode = globalThis.__testMode__; + console.info(`${TAG} coverage data testMode: ${testMode}`); + let savePath = globalThis.__savePath__; + console.info(`${TAG} write coverage data to: ${savePath}`); + let readPath = globalThis.__readPath__; + console.info(`${TAG} read coverage data in: ${readPath}`); + + // run callback mode if local test or (save path and read path ) is not defined + if (!testMode || !isCoveragePathValid(savePath)) { + console.info(`${TAG} run coverage data in call back mode`); + const strLen = strJson.length; + const maxLen = 500; + const maxCount = Math.floor(strLen / maxLen); + const OHOS_REPORT_COVERAGE_DATA = "OHOS_REPORT_COVERAGE_DATA:"; + for (let count = 0; count <= maxCount; count++) { + console.info( + `${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}` + ); + await SysTestKit.print( + `${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}` + ); + } + return; + } + console.info(`${TAG} run coverage data in save file mode`); + if (fs.accessSync(savePath)) { + fs.unlinkSync(savePath); + } + + let inputPathDir = savePath.substring( + 0, + savePath.length - jsCoverageFileName.length + ); + if (!fs.accessSync(inputPathDir)) { + console.info(`${TAG} coverage data create dir: ${inputPathDir}`); + fs.mkdirSync(inputPathDir); + } + + let file = fs.openSync(savePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); + let writeLen = fs.writeSync(file.fd, strJson, { encoding: "utf-8" }); + console.info(`${TAG} write coverage data success: ${writeLen}`); + fs.closeSync(file); + const OHOS_REPORT_COVERAGE_PATH = "OHOS_REPORT_COVERAGE_PATH:"; + await SysTestKit.print(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`); + console.info(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`); +} + +function isCoveragePathValid(inputPath) { + if (!inputPath) { + return false; + } + if (inputPath.indexOf(jsCoverageFileName) === -1) { + return false; + } + return true; +} diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/kit/SysTestKit.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/kit/SysTestKit.js new file mode 100644 index 0000000..fc473be --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/kit/SysTestKit.js @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2022-2023 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 { TAG } from "../../Constant"; +import Core from "../../core.js"; + +export default class SysTestKit { + static delegator = null; + static systemTime = null; + static workerPort = null; + + constructor() { + this.id = "sysTestKit"; + this.index = 0; + } + + static getDescribeName() { + return Core.getInstance() + .getDefaultService("suite") + .getCurrentRunningSuite().description; + } + + static getItName() { + return Core.getInstance().getDefaultService("spec").getCurrentRunningSpec() + .description; + } + + static getItAttribute() { + return Core.getInstance().getDefaultService("spec").getCurrentRunningSpec() + .fi; + } + + static actionStart(tag) { + console.info(`${TAG}${JSON.stringify(tag)}`); + var message = + "\n" + "OHOS_REPORT_ACTIONSTART: " + JSON.stringify(tag) + "\n"; + SysTestKit.print(message); + console.info(`${TAG}${JSON.stringify(tag)} actionStart print success`); + } + + static actionEnd(tag) { + console.info(`${TAG}${JSON.stringify(tag)}`); + var message = "\n" + "OHOS_REPORT_ACTIONEND: " + JSON.stringify(tag) + "\n"; + SysTestKit.print(message); + console.info(`${TAG}${JSON.stringify(tag)} actionEnd print success`); + } + + static async existKeyword(keyword, timeout) { + let reg = new RegExp(/^[a-zA-Z0-9]{1,}$/); + if (!reg.test(keyword)) { + throw new Error( + "keyword must contain more than one string, and only letters and numbers are supported." + ); + } + 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; + } + static async print(message) { + if ("printSync" in SysTestKit.delegator) { + console.info(`${TAG}printSync called ...`); + SysTestKit.delegator.printSync(message); + } else { + await SysTestKit.delegator.print(message); + } + } + + static async getRealTime() { + let currentTime = new Date().getTime(); + if (SysTestKit.systemTime !== null && SysTestKit.systemTime !== undefined) { + await SysTestKit.systemTime + .getRealTime() + .then((time) => { + console.info( + `${TAG}systemTime.getRealTime success data: ${JSON.stringify(time)}` + ); + currentTime = time; + }) + .catch((error) => { + console.error( + `${TAG}failed to systemTime.getRealTime because ${JSON.stringify(error)}` + ); + }); + } + return currentTime; + } +} + +function executePromise(cmd, timeout) { + return new Promise((resolve, reject) => { + SysTestKit.delegator.executeShellCommand(cmd, timeout, (error, data) => { + console.info( + `${TAG}existKeyword CallBack: err : ${JSON.stringify(error)}` + ); + console.info( + `${TAG}existKeyword CallBack: data : ${JSON.stringify(data)}` + ); + resolve(parseInt(data.stdResult) > 3 ? true : false); + }); + }); +} diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/ArgumentMatchers.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/ArgumentMatchers.js new file mode 100644 index 0000000..5c7fd3b --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/ArgumentMatchers.js @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2022-2024 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; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/ExtendInterface.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/ExtendInterface.js new file mode 100644 index 0000000..5ad9755 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/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; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/MockKit.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/MockKit.js new file mode 100644 index 0000000..f9e14dc --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/MockKit.js @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2022-2024 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 = new Map(); + this.mockObj = null; + this.recordMockedMethod = new Map(); + } + + init() { + this.reset(); + } + + reset() { + this.mFunctions = []; + this.stubs = {}; + this.recordCalls = {}; + this.currentSetKey = new Map(); + 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" && typeof obj !== "function") { + throw new Error("Not a object or static class"); + } + this.recordMockedMethod.forEach(function (value, key, map) { + if (key) { + obj[key] = value; + } + }); + } + + ignoreMock(obj, method) { + if (typeof obj !== "object" && typeof obj !== "function") { + throw new Error("Not a object or static class"); + } + 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]; + if (typeof key == "undefined") { + key = "anonymous-mock-" + f.propName; + } + let matcher = new ArgumentMatchers(); + if (matcher.matcheStubKey(key)) { + key = matcher.matcheStubKey(key); + if (key) { + this.currentSetKey.set(f, key); + } + } + values.set(key, returnInfo); + this.stubs.set(f, values); + } + + getReturnInfo(f, params) { + let values = this.stubs.get(f); + if (!values) { + return undefined; + } + let retrunKet = params[0]; + if (typeof retrunKet == "undefined") { + retrunKet = "anonymous-mock-" + f.propName; + } + let stubSetKey = this.currentSetKey.get(f); + + if (stubSetKey && typeof retrunKet !== "undefined") { + 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; + } + }); + + return values.get(retrunKet); + } + + findName(obj, value) { + let properties = this.findProperties(obj); + let name = null; + properties + .filter((item) => item !== "caller" && item !== "arguments") + .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(newObj) { + if (newObj.__proto__ === null) { + return []; + } + let properties = Object.getOwnPropertyNames(newObj); + return [...properties, ...getProperty(newObj.__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); + 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); + } + if (action) { + return action.apply(this, args); + } + }; + + 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); + } + + 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)) { + throw Error("not a mock function"); + } + return f.stub.bind(f); +} + +export { MockKit, when }; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/VerificationMode.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/VerificationMode.js new file mode 100644 index 0000000..dbe490d --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/mock/VerificationMode.js @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022-2023 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 "../../interface"; + +class VerificationMode { + constructor(times) { + this.doTimes = times; + } + + times(count) { + expect(count).assertEqual(this.doTimes); + } + + never() { + console.info(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; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/LogExpectError.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/LogExpectError.js new file mode 100644 index 0000000..0800c87 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/LogExpectError.js @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 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 LogExpectError { + static getErrorMsg(matcherName, actualValue, expect, originMsg) { + if (matcherName === "assertNull") { + return "expect not null, actualValue is " + actualValue; + } + if (matcherName === "assertTrue") { + return "expect not true, actualValue is " + actualValue; + } + if (matcherName === "assertFalse") { + return "expect not false, actualValue is " + actualValue; + } + if (matcherName === "assertEqual") { + return ( + "expect not Equal, actualValue is " + actualValue + " equals " + expect + ); + } + if (matcherName === "assertContain") { + return "expect not have, " + actualValue + " have " + expect; + } + if (matcherName === "assertInstanceOf") { + return ( + "expect not InstanceOf, " + + actualValue + + " is " + + Object.prototype.toString.call(actualValue) + + expect + ); + } + if (matcherName === "assertLarger") { + return "expect not Larger, " + actualValue + " is larger than " + expect; + } + if (matcherName === "assertLargerOrEqual") { + return ( + "expect not LargerOrEqual, " + actualValue + " larger than " + expect + ); + } + if (matcherName === "assertLess") { + return "expect not Less, " + actualValue + " less than " + expect; + } + if (matcherName === "assertLessOrEqual") { + return ( + "expect not LessOrEqual, " + actualValue + " is less than " + expect + ); + } + if (matcherName === "assertNaN") { + return "expect not NaN, actualValue is " + actualValue; + } + if (matcherName === "assertNegUnlimited") { + return "expect not NegUnlimited, actualValue is " + actualValue; + } + if (matcherName === "assertPosUnlimited") { + return "expect not PosUnlimited, actualValue is " + actualValue; + } + if (matcherName === "assertUndefined") { + return "expect not Undefined, actualValue is " + actualValue; + } + return originMsg; + } +} +export default LogExpectError; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/OhReport.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/OhReport.js new file mode 100644 index 0000000..a95e4a3 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/OhReport.js @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2021-2024 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 SysTestKit from "../kit/SysTestKit"; +import { collectCoverageData } from "../coverage/coverageCollect"; +import { TAG, PrintTag } from "../../Constant"; + +class OhReport { + constructor(attr) { + this.delegator = attr.delegator; + this.abilityDelegatorArguments = attr.abilityDelegatorArguments; + this.id = "report"; + this.index = 0; + this.duration = 0; + this.currentThreadName = "mainThread"; + } + + init(coreContext) { + this.coreContext = coreContext; + this.suiteService = this.coreContext.getDefaultService("suite"); + this.specService = this.coreContext.getDefaultService("spec"); + if (SysTestKit.workerPort !== null) { + this.currentThreadName = SysTestKit.workerPort.name; + } + } + + taskStart() {} + + async taskDone() { + let summary = this.suiteService.getSummary(); + if (this.abilityDelegatorArguments !== null) { + this.taskDoneTime = new Date().getTime(); + const configService = this.coreContext.getDefaultService("config"); + const suiteService = this.coreContext.getDefaultService("suite"); + const specService = this.coreContext.getDefaultService("spec"); + if (configService["coverage"] === "true") { + await collectCoverageData(); + } + let message = + "\n" + + `${PrintTag.OHOS_REPORT_RESULT}: stream=Tests run: ` + + summary.total + + ", Failure: " + + summary.failure; + message += ", Error: " + summary.error; + message += ", Pass: " + summary.pass; + message += ", Ignore: " + summary.ignore; + if (specService.skipSpecNum > 0) { + message += ", SkipSpec: " + specService.skipSpecNum; + } + message += + "\n" + + `${PrintTag.OHOS_REPORT_CODE}: ` + + (summary.failure > 0 ? -1 : 0) + + "\n"; + let isHasError = summary.failure > 0 || summary.error > 0; + let config = this.coreContext.getDefaultService("config"); + if (config.isBreakOnError() && isHasError) { + // 未执行全部说明 + message += + "\n" + + `${PrintTag.OHOS_REPORT_RESULT}: breakOnError model, Stopping whole test suite if one specific test case failed or error` + + "\n"; + } + message += + `${PrintTag.OHOS_REPORT_STATUS}: taskconsuming=` + + summary.duration + + "\n"; + console.info(`${message}`); + await SysTestKit.print(message); + } + if (SysTestKit.workerPort === null || SysTestKit.workerPort === undefined) { + // 主线程执行完成 结束任务。 + console.info(`${TAG}report print success`); + this.delegator.finishTest("your test finished!!!", 0, () => {}); + } else { + // worker线程执行完成将数据发送到主线程中。 + let sendData = { + currentThreadName: this.currentThreadName, + summary: summary + }; + console.info( + `${TAG}, send data to mainThread, ${this.currentThreadName}, ${JSON.stringify(sendData)}` + ); + SysTestKit.workerPort.postMessage(sendData); + } + } + + 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, () => {}); + } + } + + incorrectTestSuiteFormat() { + if ( + this.coreContext.getDefaultService("config").filterXdescribe.length !== 0 + ) { + let value = this.coreContext.getDefaultService("config").filterXdescribe; + let message = + "xdescribe " + value.join(",") + " should not contain it" + "\n"; + this.delegator.finishTest(message, 0, () => {}); + } + } + async suiteStart() { + if (this.abilityDelegatorArguments !== null) { + let specArr = []; + this.suiteService.getAllChildSuiteNum( + this.suiteService.getCurrentRunningSuite(), + specArr + ); + let message = "\n" + `${PrintTag.OHOS_REPORT_SUM}: ` + specArr.length; + this.suiteService.setCurrentRunningSuiteDesc( + this.suiteService.getRootSuite(), + this.suiteService.getCurrentRunningSuite(), + "" + ); + message += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: class=` + + this.suiteService.getCurrentRunningSuiteDesc() + + "\n"; + if (this.suiteService.currentRunningSuite.isSkip) { + message += + `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + + this.suiteService.currentRunningSuite.skipReason + + "\n"; + } + if (SysTestKit.workerPort !== null) { + message += + `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + + this.currentThreadName; + } + console.info(`${message}`); + await SysTestKit.print(message); + console.info( + `${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteStart print success` + ); + } + } + + async suiteDone() { + if (this.abilityDelegatorArguments !== null) { + const currentRunningSuite = this.suiteService.getCurrentRunningSuite(); + this.suiteService.setCurrentRunningSuiteDesc( + this.suiteService.getRootSuite(), + this.suiteService.getCurrentRunningSuite(), + "" + ); + let message = + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: class=` + + this.suiteService.getCurrentRunningSuiteDesc(); + if ( + this.suiteService.currentRunningSuite.isSkip && + this.suiteService.currentRunningSuite.skipReason !== "" + ) { + message += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + + this.suiteService.currentRunningSuite.skipReason; + } + message += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: suiteconsuming=` + + this.suiteService.getCurrentRunningSuite().duration; + if (currentRunningSuite.hookError) { + message += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: ${currentRunningSuite.hookError.message}`; + } + message += "\n"; + if (SysTestKit.workerPort !== null) { + message += + `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + + this.currentThreadName; + } + console.info(`${message}`); + await SysTestKit.print(message); + console.info( + `${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteDone print success` + ); + } + } + + async specStart() { + if (this.abilityDelegatorArguments !== null) { + let message = + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: class=` + + this.suiteService.getCurrentRunningSuiteDesc(); + message += + "\n" + `${PrintTag.OHOS_REPORT_STATUS}: current=` + ++this.index; + message += "\n" + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`; + message += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + + this.specService.getTestTotal(); + message += "\n" + `${PrintTag.OHOS_REPORT_STATUS}: stream=`; + message += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: test=` + + this.specService.currentRunningSpec.description; + message += "\n" + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 1` + "\n"; + if (this.specService.currentRunningSpec.isSkip) { + message += + `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + + this.specService.currentRunningSpec.skipReason + + "\n"; + } + if (SysTestKit.workerPort !== null) { + message += + `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + + this.currentThreadName; + } + console.info(`${message}`); + await SysTestKit.print(message); + console.info( + `${TAG}${this.specService.currentRunningSpec.description} specStart start print success` + ); + } + } + + async specDone() { + if (this.abilityDelegatorArguments !== null) { + let message = + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: class=` + + this.suiteService.getCurrentRunningSuiteDesc(); + message += "\n" + `${PrintTag.OHOS_REPORT_STATUS}: current=` + this.index; + message += "\n" + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`; + message += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + + this.specService.getTestTotal(); + let messageStack = ""; + let messageCode = ""; + if (this.specService.currentRunningSpec.error) { + messageStack = + `${PrintTag.OHOS_REPORT_STATUS}: stack=` + + this.specService.currentRunningSpec.error?.stack?.slice(0, -1); + messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`; + messageCode += + this.specService.currentRunningSpec.expectMsg !== "" + ? `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}` + : `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}`; + messageCode += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: test=` + + this.specService.currentRunningSpec.description; + messageCode += "\n" + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -1` + "\n"; + } else if (this.specService.currentRunningSpec) { + if (this.specService.currentRunningSpec.fail) { + messageStack += + `${PrintTag.OHOS_REPORT_STATUS}: stack=` + + this.specService.currentRunningSpec.fail?.stack?.slice(0, -1); + messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`; + messageCode += + this.specService.currentRunningSpec.expectMsg !== "" + ? `message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}` + : `Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}`; + messageCode += + "\n" + + `${PrintTag.OHOS_REPORT_STATUS}: test=` + + this.specService.currentRunningSpec.description; + messageCode += + "\n" + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -2` + "\n"; + } else { + messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stream=`; + messageCode += + `${PrintTag.OHOS_REPORT_STATUS}: test=` + + this.specService.currentRunningSpec.description; + messageCode += "\n" + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 0` + "\n"; + messageCode += this.specService.currentRunningSpec.isSkip + ? `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + + this.specService.currentRunningSpec.skipReason + + "\n" + : ""; + } + } else { + messageCode += "\n"; + } + messageCode += + `${PrintTag.OHOS_REPORT_STATUS}: consuming=` + + this.specService.currentRunningSpec.duration + + "\n"; + if (SysTestKit.workerPort !== null) { + messageCode += + `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + + this.currentThreadName; + } + console.info(`${message}`); + console.info(`\n${messageStack}`); + console.info(`\n${messageCode}`); + await SysTestKit.print(message); + await SysTestKit.print(messageStack); + await SysTestKit.print(messageCode); + console.info( + `${TAG}${this.specService.currentRunningSpec.description} specDone end print success` + ); + } + } +} + +export default OhReport; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/ReportExtend.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/ReportExtend.js new file mode 100644 index 0000000..17d7732 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/module/report/ReportExtend.js @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2021-2024 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() {} + + handleSpecs(specs, report, suiteReport, testsuite) { + 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); + } + } + + 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"]; + this.handleSpecs(specs, report, suiteReport, testsuite); + report.children.push(suiteReport); + } + } + + writeXmlReport(report); + } +} + +function writeXmlReport(report) { + 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 handleChild(json, key, hasChildren, childrenStr) { + if (json[key].length > 0) { + hasChildren = true; + for (let child of json[key]) { + childrenStr += json2xml(child); + } + } +} + +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") { + handleChild(json, key, hasChildren, childrenStr); + } else { + attrStr += ` ${key}="${json[key]}"`; + } + } + let xml = `<${tagName}${attrStr}`; + xml += hasChildren ? `>${childrenStr}` : "/>"; + return xml; +} + +export default ReportExtend; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/service.js b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/service.js new file mode 100644 index 0000000..72f7ea0 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/core/service.js @@ -0,0 +1,1440 @@ +/* + * Copyright (c) 2021-2024 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 SysTestKit from "./module/kit/SysTestKit"; +import { TAG } from "./Constant"; +import LogExpectError from "./module/report/LogExpectError"; +import { NestFilter } from "./module/config/Filter"; + +function assertTrueFun(actualValue) { + let result = { + pass: actualValue === true, + message: "expect true, actualValue is " + actualValue + }; + return result; +} + +function assertEqualFun(actualValue, args) { + let msg = "expect " + actualValue + " equals " + args[0]; + if (actualValue === args[0]) { + // 数值相同,提示数据类型 + const aClassName = Object.prototype.toString.call(actualValue); + const bClassName = Object.prototype.toString.call(args[0]); + msg = + "expect " + + actualValue + + aClassName + + " equals " + + args[0] + + bClassName + + "strict mode inspect type"; + } + let result = { + pass: actualValue === args[0], + expectValue: args[0], + message: msg + }; + return result; +} + +function assertThrowFun(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; +} + +class AssertException extends Error { + constructor(message) { + super(); + this.name = "AssertException"; + this.message = message; + } +} + +function getFuncWithArgsZero(func, timeout, isStressTest) { + return new Promise(async (resolve, reject) => { + let timer = null; + if (!isStressTest) { + timer = setTimeout(() => { + reject(new Error("execute timeout " + timeout + "ms")); + }, timeout); + } + try { + await func(); + } catch (err) { + reject(err); + } + timer !== null ? clearTimeout(timer) : null; + resolve(); + }); +} + +function getFuncWithArgsOne(func, timeout, isStressTest) { + return new Promise(async (resolve, reject) => { + let timer = null; + if (!isStressTest) { + timer = setTimeout(() => { + reject(new Error("execute timeout " + timeout + "ms")); + }, timeout); + } + + function done() { + timer !== null ? clearTimeout(timer) : null; + resolve(); + } + + try { + await func(done); + } catch (err) { + timer !== null ? clearTimeout(timer) : null; + reject(err); + } + }); +} + +function getFuncWithArgsTwo(func, timeout, paramItem, isStressTest) { + return new Promise(async (resolve, reject) => { + let timer = null; + if (!isStressTest) { + timer = setTimeout(() => { + reject(new Error("execute timeout " + timeout + "ms")); + }, timeout); + } + + function done() { + timer !== null ? clearTimeout(timer) : null; + resolve(); + } + + try { + await func(done, paramItem); + } catch (err) { + timer !== null ? clearTimeout(timer) : null; + reject(err); + } + }); +} + +function processFunc(coreContext, func) { + let argNames = ((func || "") + .toString() + .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm, "") + .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; + const config = coreContext.getDefaultService("config"); + config.setSupportAsync(true); + const timeout = +(config.timeout === undefined ? 5000 : config.timeout); + const isStressTest = + coreContext.getServices("dataDriver") !== undefined || + config.getStress() > 1; + switch (funcLen) { + case 0: { + processedFunc = function () { + return getFuncWithArgsZero(func, timeout, isStressTest); + }; + break; + } + case 1: { + processedFunc = function () { + return getFuncWithArgsOne(func, timeout, isStressTest); + }; + break; + } + default: { + processedFunc = function (paramItem) { + return getFuncWithArgsTwo(func, timeout, paramItem, isStressTest); + }; + 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; + this.suitesStack = [this.rootSuite]; + this.targetSuiteArray = []; + this.targetSpecArray = []; + this.currentRunningSuiteDesc = null; + this.fullRun = false; + this.isSkipSuite = false; + this.suiteSkipReason = null; + } + + describe(desc, func) { + const configService = this.coreContext.getDefaultService("config"); + if ( + this.suitesStack.some((suite) => { + return suite.description === desc; + }) + ) { + console.error(`${TAG} Loop nesting occurs : ${desc}`); + this.suiteSkipReason = ""; + this.isSkipSuite = false; + return; + } + let isFilter = this.analyzeConfigServiceClass(configService.class, desc); + if (configService.filterSuite(desc) && isFilter) { + if ( + this.currentRunningSuite.description === "" || + this.currentRunningSuite.description == null + ) { + console.info(`${TAG}filter suite : ${desc}`); + this.suiteSkipReason = ""; + this.isSkipSuite = false; + return; + } + } + const suite = new SuiteService.Suite({ description: desc }); + if (this.isSkipSuite) { + suite.isSkip = true; + suite.skipReason = this.suiteSkipReason; + } + this.suiteSkipReason = ""; + this.isSkipSuite = false; + if ( + typeof this.coreContext.getServices("dataDriver") !== "undefined" && + configService["dryRun"] !== "true" + ) { + let suiteStress = this.coreContext + .getServices("dataDriver") + .dataDriver.getSuiteStress(desc); + for (let i = 1; i < suiteStress; i++) { + this.currentRunningSuite.childSuites.push(suite); + } + } + this.currentRunningSuite.childSuites.push(suite); + this.currentRunningSuite = suite; + this.suitesStack.push(suite); + func.call(); + this.suitesStack.pop(); + this.currentRunningSuite = this.suitesStack.pop(); + this.suitesStack.push(this.currentRunningSuite); + } + xdescribe(desc, func, reason) { + const configService = this.coreContext.getDefaultService("config"); + if (!configService.skipMessage && configService.runSkipped !== "all") { + if (configService.runSkipped != null && configService.runSkipped !== "") { + let finalDesc = ""; + this.suitesStack.map((suite) => { + finalDesc = finalDesc + "." + suite.description; + }); + finalDesc = (finalDesc + "." + desc).substring(2); + console.info(`${TAG} finalDesc ${finalDesc}`); + if (configService.checkIfSuiteInSkipRun(finalDesc)) { + console.info(`${TAG} runSkipped suite: ${desc}`); + } else { + console.info( + reason == null + ? `${TAG} skip suite: ${desc}` + : `${TAG} skip suite: ${desc}, and the reason is ${reason}` + ); + return; + } + } else { + console.info( + reason == null + ? `${TAG} skip suite: ${desc}` + : `${TAG} skip suite: ${desc}, and the reason is ${reason}` + ); + return; + } + } + this.isSkipSuite = true; + this.suiteSkipReason = reason; + this.describe(desc, func); + } + + beforeAll(func) { + this.currentRunningSuite.beforeAll.push( + processFunc(this.coreContext, func) + ); + } + + beforeEach(func) { + this.currentRunningSuite.beforeEach.push( + processFunc(this.coreContext, func) + ); + } + + beforeItSpecified(itDescs, func) { + this.currentRunningSuite.beforeItSpecified.set( + itDescs, + processFunc(this.coreContext, func) + ); + } + + afterItSpecified(itDescs, func) { + this.currentRunningSuite.afterItSpecified.set( + itDescs, + 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; + } + + getRootSuite() { + return this.rootSuite; + } + + getCurrentRunningSuiteDesc() { + return this.currentRunningSuiteDesc; + } + + setCurrentRunningSuiteDesc(suite, currentSuite, prefix) { + if (suite != null && suite === currentSuite) { + this.currentRunningSuiteDesc = prefix; + } else if (suite != null && suite !== currentSuite) { + suite.childSuites.forEach((it) => { + let temp = prefix; + if (it.description != null || it.description !== "") { + temp = prefix === "" ? it.description : prefix + "." + it.description; + } + this.setCurrentRunningSuiteDesc(it, currentSuite, temp); + }); + } + } + analyzeConfigServiceClass(configServiceClass, desc) { + if (configServiceClass == null || configServiceClass === "") { + this.fullRun = true; + return false; + } + if (this.targetSuiteArray.length === 0) { + const targetArray = configServiceClass.split(","); + for (let index in targetArray) { + if (targetArray[index].includes("#")) { + this.targetSpecArray.push(targetArray[index]); + } else { + this.targetSuiteArray.push(targetArray[index]); + } + } + } + return !configServiceClass.includes(desc); + } + traversalResults(suite, obj, breakOnError) { + if (suite.childSuites.length === 0 && suite.specs.length === 0) { + return; + } + if (suite.specs.length > 0) { + for (const itItem of suite.specs) { + obj.total++; + let itInfo = { + currentThreadName: "mainThread", + description: suite.description + "#" + itItem.description, + result: -3 + }; + if (SysTestKit.workerPort !== null) { + itInfo.currentThreadName = SysTestKit.workerPort.name; + } + obj.itItemList.push(itInfo); + if (breakOnError && (obj.error > 0 || obj.failure > 0)) { + // breakOnError模式 + continue; + } + if (itItem.error) { + obj.error++; + itInfo.result = -1; + } else if (itItem.fail) { + obj.failure++; + itInfo.result = -2; + } else if (itItem.pass === true) { + obj.pass++; + itInfo.result = 0; + } + } + } + + obj.duration += suite.duration; + + if (suite.childSuites.length > 0) { + for (const suiteItem of suite.childSuites) { + this.traversalResults(suiteItem, obj, breakOnError); + } + } + } + + async setSuiteResults(suite, error, coreContext) { + if (suite.childSuites.length === 0 && suite.specs.length === 0) { + return; + } + if (suite.specs.length > 0) { + const specService = coreContext.getDefaultService("spec"); + for (const specItem of suite.specs) { + specService.setCurrentRunningSpec(specItem); + if (error instanceof AssertException) { + specItem.fail = error; + } else { + specItem.error = error; + } + await coreContext.fireEvents("spec", "specStart", specItem); + await coreContext.fireEvents("spec", "specDone", specItem); + } + } + if (suite.childSuites.length > 0) { + for (const suiteItem of suite.childSuites) { + await this.setSuiteResults(suiteItem, error, coreContext); + } + } + } + + getSummary() { + let suiteService = this.coreContext.getDefaultService("suite"); + let rootSuite = suiteService.rootSuite; + const specService = this.coreContext.getDefaultService("spec"); + const configService = this.coreContext.getDefaultService("config"); + let breakOnError = configService.isBreakOnError(); + let isError = specService.getStatus(); + let isBreaKOnError = breakOnError && isError; + // itItemList 保存当前用例执行情况, 发送到主线程用例计算最终结果 + let obj = { + total: 0, + failure: 0, + error: 0, + pass: 0, + ignore: 0, + duration: 0, + itItemList: [] + }; + for (const suiteItem of rootSuite.childSuites) { + this.traversalResults(suiteItem, obj, isBreaKOnError); + } + obj.ignore = obj.total - obj.pass - obj.failure - obj.error; + return obj; + } + + init(coreContext) { + this.coreContext = coreContext; + } + + traversalSuites(suite, obj, configService) { + if (suite.childSuites.length === 0 && suite.specs.length === 0) { + return []; + } + if (suite.specs.length > 0) { + let itArray = []; + for (const itItem of suite["specs"]) { + if ( + !configService.filterDesc( + suite.description, + itItem.description, + itItem.fi, + null + ) + ) { + itArray.push({ itName: itItem.description }); + } + } + obj[suite.description] = itArray; + } + if (suite.childSuites.length > 0) { + let suiteArray = []; + for (const suiteItem of suite.childSuites) { + let suiteObj = {}; + this.traversalSuites(suiteItem, suiteObj, configService); + if (!configService.filterSuite(suiteItem.description)) { + suiteArray.push(suiteObj); + } + } + obj.suites = suiteArray; + } + } + + async dryRun(abilityDelegator) { + console.info(`${TAG} rootSuite : ` + JSON.stringify(this.rootSuite)); + let obj = this.rootSuite; + let prefixStack = []; + let suiteArray = []; + let skipSuiteArray = []; + this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj); + const configService = this.coreContext.getDefaultService("config"); + let result; + if (configService.skipMessage) { + result = { suites: suiteArray, skipSuites: skipSuiteArray }; + } else { + result = { suites: suiteArray }; + } + let strJson = JSON.stringify(result); + let strLen = strJson.length; + let maxLen = 500; + let maxCount = Math.floor(strLen / maxLen); + for (let count = 0; count <= maxCount; count++) { + await SysTestKit.print( + strJson.substring(count * maxLen, (count + 1) * maxLen) + ); + } + console.info(`${TAG}dryRun print success`); + abilityDelegator.finishTest("dry run finished!!!", 0, () => {}); + } + + //将suitesArray的嵌套结构展开成三层结构 + analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, obj) { + obj.childSuites.map((suite) => { + if (suite.description != null && suite.description !== "") { + let prefix = ""; + if (prefixStack.length > 0) { + prefix = prefixStack.join(".") + "." + suite.description; + } else { + prefix = suite.description; + } + prefixStack.push(suite.description); + let temp = {}; + temp[prefix] = []; + let skipTemp = {}; + skipTemp[prefix] = []; + suite.specs.map((spec) => { + let it = { itName: spec.description }; + spec.isSkip ? skipTemp[prefix].push(it) : temp[prefix].push(it); + }); + suiteArray.push(temp); + skipSuiteArray.push(skipTemp); + } + this.analyzeSuitesArray(prefixStack, suiteArray, skipSuiteArray, suite); + prefixStack.pop(); + }); + } + //获取当前测试套下的所有测试用例数量 + getAllChildSuiteNum(suite, specArray) { + if (suite.specs != null) { + suite.specs.forEach((spec) => specArray.push(spec)); + } + if (suite.childSuites != null) { + suite.childSuites.forEach((it) => + this.getAllChildSuiteNum(it, specArray) + ); + } + } + + execute() { + const configService = this.coreContext.getDefaultService("config"); + if (configService.filterValid.length !== 0) { + this.coreContext.fireEvents("task", "incorrectFormat"); + return; + } + if (configService.filterXdescribe.length !== 0) { + this.coreContext.fireEvents("task", "incorrectTestSuiteFormat"); + return; + } + if (configService.isRandom() && this.rootSuite.childSuites.length > 0) { + this.rootSuite.childSuites.sort(function () { + return +("0." + (+new Date() + "").split("").reverse().join("")) > 0.5 + ? -1 + : 1; + }); + this.currentRunningSuite = this.rootSuite.childSuites[0]; + } + if (configService.isSupportAsync()) { + console.info(`${TAG} rootSuite:` + JSON.stringify(this.rootSuite)); + let asyncExecute = async () => { + await this.coreContext.fireEvents("task", "taskStart"); + await this.rootSuite.asyncRun(this.coreContext); + }; + asyncExecute().then(async () => { + await this.coreContext.fireEvents("task", "taskDone"); + }); + } else { + console.info("${TAG} rootSuite:" + JSON.stringify(this.rootSuite)); + this.coreContext.fireEvents("task", "taskStart"); + this.rootSuite.run(this.coreContext); + this.coreContext.fireEvents("task", "taskDone"); + } + } + + apis() { + const _this = this; + return { + describe: function (desc, func) { + return _this.describe(desc, func); + }, + xdescribe: function (desc, func, reason) { + return _this.xdescribe(desc, func, reason); + }, + beforeItSpecified: function (itDescs, func) { + return _this.beforeItSpecified(itDescs, func); + }, + afterItSpecified: function (itDescs, func) { + return _this.afterItSpecified(itDescs, 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.beforeItSpecified = new Map(); + this.afterItSpecified = new Map(); + this.beforeEach = []; + this.afterEach = []; + this.duration = 0; + this.hookError = null; + this.isSkip = false; + this.skipReason = ""; + } + + pushSpec(spec) { + this.specs.push(spec); + } + + removeSpec(desc) { + this.specs = this.specs.filter((item, index) => { + return item.description !== desc; + }); + } + + getSpecsNum() { + return this.specs.length; + } + + isRun(coreContext) { + const configService = coreContext.getDefaultService("config"); + const suiteService = coreContext.getDefaultService("suite"); + const specService = coreContext.getDefaultService("spec"); + let breakOnError = configService.isBreakOnError(); + let isError = specService.getStatus(); + return breakOnError && isError; + } + + run(coreContext) { + const suiteService = coreContext.getDefaultService("suite"); + suiteService.setCurrentRunningSuite(this); + if (this.description !== "") { + coreContext.fireEvents("suite", "suiteStart", this); + } + this.runHookFunc("beforeAll"); + if (this.specs.length > 0) { + const configService = coreContext.getDefaultService("config"); + if (configService.isRandom()) { + this.specs.sort(function () { + return +("0." + (+new Date() + "").split("").reverse().join("")) > 0.5 + ? -1 + : 1; + }); + } + for (let spec in this.specs) { + let isBreakOnError = this.isRun(coreContext); + if (isBreakOnError) { + break; + } + this.runHookFunc("beforeEach"); + spec.run(coreContext); + this.runHookFunc("afterEach"); + } + } + if (this.childSuites.length > 0) { + for (let suite in this.childSuites) { + let isBreakOnError = this.isRun(coreContext); + if (isBreakOnError) { + break; + } + suite.run(coreContext); + suiteService.setCurrentRunningSuite(suite); + } + } + this.runHookFunc("afterAll"); + if (this.description !== "") { + coreContext.fireEvents("suite", "suiteDone"); + } + } + + async runBeforeItSpecified(beforeItSpecified, specItem) { + for (const [itNames, hookFunc] of beforeItSpecified) { + if ( + (Object.prototype.toString.call(itNames) === "[object Array]" && + itNames.includes(specItem.description)) || + (Object.prototype.toString.call(itNames) === "[object String]" && + itNames === specItem.description) + ) { + await Reflect.apply(hookFunc, null, []); + } + break; + } + } + + async runAfterItSpecified(beforeItSpecified, specItem) { + for (const [itNames, hookFunc] of beforeItSpecified) { + if ( + (Object.prototype.toString.call(itNames) === "[object Array]" && + itNames.includes(specItem.description)) || + (Object.prototype.toString.call(itNames) === "[object String]" && + itNames === specItem.description) + ) { + await Reflect.apply(hookFunc, null, []); + } + break; + } + } + + async asyncRunSpecs(coreContext) { + const configService = coreContext.getDefaultService("config"); + if (configService.isRandom()) { + this.specs.sort(function () { + return +("0." + (+new Date() + "").split("").reverse().join("")) > 0.5 + ? -1 + : 1; + }); + } + const specService = coreContext.getDefaultService("spec"); + for (let specItem of this.specs) { + specService.setCurrentRunningSpec(specItem); + // 遇错即停模式,发现用例有问题,直接返回,不在执行后面的it + let isBreakOnError = this.isRun(coreContext); + if (isBreakOnError) { + console.info("break description :" + this.description); + break; + } + await coreContext.fireEvents("spec", "specStart", specItem); + try { + await this.runBeforeItSpecified(this.beforeItSpecified, specItem); + await this.runAsyncHookFunc("beforeEach"); + await specItem.asyncRun(coreContext); + await this.runAfterItSpecified(this.afterItSpecified, specItem); + await this.runAsyncHookFunc("afterEach"); + } catch (e) { + console.error(`${TAG}stack:${e?.stack}`); + console.error(`${TAG}stack end`); + if (e instanceof AssertException) { + specItem.fail = e; + } else { + specItem.error = e; + } + specService.setStatus(true); + } + specItem.setResult(); + await coreContext.fireEvents("spec", "specDone", specItem); + specService.setCurrentRunningSpec(null); + } + } + + async asyncRunChildSuites(coreContext) { + for (let i = 0; i < this.childSuites.length; i++) { + // 遇错即停模式, 发现用例有问题,直接返回,不在执行后面的description + let isBreakOnError = this.isRun(coreContext); + if (isBreakOnError) { + console.info(`${TAG}break description : ${this.description}`); + break; + } + await this.childSuites[i].asyncRun(coreContext); + } + } + + async asyncRun(coreContext) { + const suiteService = coreContext.getDefaultService("suite"); + const specService = coreContext.getDefaultService("spec"); + + suiteService.setCurrentRunningSuite(this); + suiteService.suitesStack.push(this); + if (this.description !== "") { + await coreContext.fireEvents("suite", "suiteStart", this); + } + + try { + await this.runAsyncHookFunc("beforeAll"); + } catch (error) { + console.error(`${TAG}${error?.stack}`); + this.hookError = error; + } + + if (this.hookError !== null) { + specService.setStatus(true); + await suiteService.setSuiteResults(this, this.hookError, coreContext); + } + + if (this.specs.length > 0 && this.hookError === null) { + await this.asyncRunSpecs(coreContext); + } + + if (this.childSuites.length > 0 && this.hookError === null) { + await this.asyncRunChildSuites(coreContext); + } + + try { + await this.runAsyncHookFunc("afterAll"); + } catch (error) { + console.error(`${TAG}${error?.stack}`); + this.hookError = error; + specService.setStatus(true); + } + + if (this.description !== "") { + await coreContext.fireEvents("suite", "suiteDone"); + let childSuite = suiteService.suitesStack.pop(); + let currentRunningSuite = suiteService.suitesStack.pop(); + suiteService.setCurrentRunningSuite(currentRunningSuite); + suiteService.suitesStack.push(currentRunningSuite); + } + } + + runHookFunc(hookName) { + if (this[hookName] && this[hookName].length > 0) { + this[hookName].forEach((func) => { + try { + func(); + } catch (e) { + console.error(`${TAG}${e.stack}`); + } + }); + } + } + + async runAsyncHookFunc(hookName) { + for (const hookItem of this[hookName]) { + try { + await hookItem(); + } catch (error) { + error["message"] += `, error in ${hookName} function`; + throw error; + } + } + } +}; + +class SpecService { + constructor(attr) { + this.id = attr.id; + this.totalTest = 0; + this.hasError = false; + this.skipSpecNum = 0; + this.isSkipSpec = false; + this.specSkipReason = ""; + } + + init(coreContext) { + this.coreContext = coreContext; + } + + setCurrentRunningSpec(spec) { + this.currentRunningSpec = spec; + } + + setStatus(obj) { + this.hasError = obj; + } + + getStatus() { + return this.hasError; + } + + getTestTotal() { + return this.totalTest; + } + + getCurrentRunningSpec() { + return this.currentRunningSpec; + } + + getSkipSpecNum() { + return this.skipSpecNum; + } + + initSpecService() { + this.isSkipSpec = false; + this.specSkipReason = ""; + } + + it(desc, filter, func) { + const suiteService = this.coreContext.getDefaultService("suite"); + const configService = this.coreContext.getDefaultService("config"); + let isFilter = new NestFilter().filterNestName( + suiteService.targetSuiteArray, + suiteService.targetSpecArray, + suiteService.suitesStack, + desc + ); + if (configService.filterWithNest(desc, filter)) { + console.info(`${TAG}filter it :${desc}`); + this.initSpecService(); + return; + } + if ( + configService.filterDesc( + suiteService.currentRunningSuite.description, + desc, + filter, + this.coreContext + ) && + isFilter && + !suiteService.fullRun + ) { + console.info(`${TAG}filter it :${desc}`); + this.initSpecService(); + } else { + let processedFunc = processFunc(this.coreContext, func); + const spec = new SpecService.Spec({ + description: desc, + fi: filter, + fn: processedFunc + }); + if (this.isSkipSpec) { + spec.isSkip = true; + spec.skipReason = this.specSkipReason; + } + this.initSpecService(); + if (configService.runSkipped === "skipped" && !spec.isSkip) { + console.info( + `${TAG} runSkipped is skipped , just run xit, don't run it: ${spec.description}` + ); + return; + } + if (suiteService.getCurrentRunningSuite().isSkip && !spec.isSkip) { + configService.filterXdescribe.push( + suiteService.getCurrentRunningSuite().description + ); + } + if ( + typeof this.coreContext.getServices("dataDriver") !== "undefined" && + configService["dryRun"] !== "true" + ) { + let specStress = this.coreContext + .getServices("dataDriver") + .dataDriver.getSpecStress(desc); + for (let i = 1; i < specStress; i++) { + this.totalTest++; + suiteService.getCurrentRunningSuite().pushSpec(spec); + } + } + // dryRun 状态下不统计压力测试重复数据 + if (configService["dryRun"] !== "true") { + let stress = configService.getStress(); // 命令配置压力测试 + console.info(`${TAG}stress length : ${stress}`); + for (let i = 1; i < stress; i++) { + this.totalTest++; + suiteService.getCurrentRunningSuite().pushSpec(spec); + } + } + this.totalTest++; + suiteService.getCurrentRunningSuite().pushSpec(spec); + } + } + + xit(desc, filter, func, reason) { + const configService = this.coreContext.getDefaultService("config"); + const suiteService = this.coreContext.getDefaultService("suite"); + if (!configService.skipMessage && configService.runSkipped !== "all") { + if (configService.runSkipped != null && configService.runSkipped !== "") { + let finalDesc = ""; + suiteService.suitesStack.map((suite) => { + finalDesc = finalDesc + "." + suite.description; + }); + finalDesc = (finalDesc + "#" + desc).substring(2); + if (configService.checkIfSpecInSkipRun(finalDesc)) { + console.info(`${TAG} runSkipped spec: ${desc}`); + } else { + console.info( + reason == null + ? `${TAG} skip spec: ${desc}` + : `${TAG} skip spec: ${desc}, and the reason is ${reason}` + ); + return; + } + } else { + console.info( + reason == null + ? `${TAG} skip spec: ${desc}` + : `${TAG} skip spec: ${desc}, and the reason is ${reason}` + ); + return; + } + } + this.skipSpecNum++; + this.isSkipSpec = true; + this.specSkipReason = reason; + this.it(desc, filter, func); + } + + apis() { + const _this = this; + return { + it: function (desc, filter, func) { + return _this.it(desc, filter, func); + }, + xit: function (desc, filter, func, reason) { + return _this.xit(desc, filter, func, reason); + } + }; + } +} + +SpecService.Spec = class { + constructor(attrs) { + this.description = attrs.description || ""; + this.fi = attrs.fi; + this.fn = attrs.fn || function () {}; + this.fail = undefined; + this.error = undefined; + this.duration = 0; + this.startTime = 0; + this.isExecuted = false; // 当前用例是否执行 + this.isSkip = false; + this.skipReason = ""; + this.expectMsg = ""; + } + + setResult() { + if (this.fail) { + this.pass = false; + } else { + this.pass = true; + } + } + + run(coreContext) { + const specService = coreContext.getDefaultService("spec"); + specService.setCurrentRunningSpec(this); + coreContext.fireEvents("spec", "specStart", this); + this.isExecuted = true; + 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(`${TAG}[suite params] ${JSON.stringify(suiteParams)}`); + console.info(`${TAG}[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; + specService.setStatus(true); + } + coreContext.fireEvents("spec", "specDone", this); + } + + async asyncRun(coreContext) { + const dataDriver = coreContext.getServices("dataDriver"); + if (typeof dataDriver === "undefined") { + await this.fn(); + } else { + const suiteParams = dataDriver.dataDriver.getSuiteParams(); + const specParams = dataDriver.dataDriver.getSpecParams(); + console.info(`[suite params] ${JSON.stringify(suiteParams)}`); + console.info(`[spec params] ${JSON.stringify(specParams)}`); + if (this.fn.length === 0) { + await this.fn(); + } else if (specParams.length === 0) { + await this.fn(suiteParams); + } else { + for (const paramItem of specParams) { + await this.fn(Object.assign({}, paramItem, suiteParams)); + } + } + } + + this.isExecuted = true; + } + + filterCheck(coreContext) { + const specService = coreContext.getDefaultService("spec"); + specService.setCurrentRunningSpec(this); + return true; + } +}; + +class ExpectService { + constructor(attr) { + this.id = attr.id; + this.matchers = {}; + this.customMatchers = []; + } + + 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]; + } + } + } + + removeMatchers(customAssertionName) { + if (customAssertionName === "all") { + for (const matcherName in this.matchers) { + this.matchers[matcherName] = this.customMatchers.includes(matcherName) + ? () => { + throw new Error(`${matcherName} is unregistered`); + } + : undefined; + } + } else { + this.matchers[customAssertionName] = () => { + throw new Error(`${customAssertionName} is unregistered`); + }; + } + } + + basicMatchers() { + return { + assertTrue: assertTrueFun, + assertEqual: assertEqualFun, + assertThrow: assertThrowFun + }; + } + + initWrapMatchers(currentRunningSpec) { + return { + // 翻转标识 + isNot: false, + // 翻转方法 + not: function () { + this.isNot = true; + return this; + }, + message: function (msg) { + currentRunningSpec.expectMsg = msg; + console.info(`${TAG} msg: ${msg}`); + return this; + } + }; + } + + handleWithAssertPromise( + _this, + wrappedMatchers, + matcherName, + actualValue, + currentRunningSpec, + currentRunningSuite + ) { + wrappedMatchers[matcherName] = async function (...args) { + await _this.matchers[matcherName](actualValue, args).then( + function (result) { + if (wrappedMatchers.isNot) { + result.pass = !result.pass; + } + result.actualValue = actualValue; + result.checkFunc = matcherName; + if (!result.pass) { + const assertError = new AssertException(result.message); + currentRunningSpec + ? (currentRunningSpec.fail = assertError) + : (currentRunningSuite.hookError = assertError); + throw assertError; + } + } + ); + }; + } + + handleWithoutAssertPromise( + _this, + wrappedMatchers, + matcherName, + actualValue, + currentRunningSpec, + currentRunningSuite + ) { + wrappedMatchers[matcherName] = function (...args) { + const result = _this.customMatchers.includes(matcherName) + ? _this.matchers[matcherName](actualValue, args[0]) + : _this.matchers[matcherName](actualValue, args); + if (wrappedMatchers.isNot) { + result.pass = !result.pass; + result.message = LogExpectError.getErrorMsg( + matcherName, + actualValue, + args[0], + result.message + ); + } + result.actualValue = actualValue; + result.checkFunc = matcherName; + if (!result.pass) { + const assertError = new AssertException(result.message); + currentRunningSpec + ? (currentRunningSpec.fail = assertError) + : (currentRunningSuite.hookError = assertError); + throw assertError; + } + }; + } + + addAssert(wrappedMatchers, matcherName, actualValue) { + const _this = this; + const specService = _this.coreContext.getDefaultService("spec"); + const currentRunningSpec = specService.getCurrentRunningSpec(); + const currentRunningSuite = _this.coreContext + .getDefaultService("suite") + .getCurrentRunningSuite(); + if (matcherName.search("assertPromise") === 0) { + this.handleWithAssertPromise( + _this, + wrappedMatchers, + matcherName, + actualValue, + currentRunningSpec, + currentRunningSuite + ); + } else { + this.handleWithoutAssertPromise( + _this, + wrappedMatchers, + matcherName, + actualValue, + currentRunningSpec, + currentRunningSuite + ); + } + } + + wrapMatchers(actualValue) { + const _this = this; + const specService = _this.coreContext.getDefaultService("spec"); + const currentRunningSpec = specService.getCurrentRunningSpec(); + const wrappedMatchers = this.initWrapMatchers(currentRunningSpec); + const currentRunningSuite = _this.coreContext + .getDefaultService("suite") + .getCurrentRunningSuite(); + for (const matcherName in this.matchers) { + let result = Object.prototype.hasOwnProperty.call( + this.matchers, + matcherName + ); + if (!result) { + continue; + } + this.addAssert(wrappedMatchers, matcherName, actualValue); + } + 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() { + console.info(`${TAG}[start] start run suites`); + } + + async suiteStart() { + console.info( + `${TAG}[suite start]${this.suiteService.getCurrentRunningSuite().description}` + ); + } + + async specStart() { + console.info( + `${TAG}start running case '${this.specService.currentRunningSpec.description}'` + ); + this.index = this.index + 1; + let spec = this.specService.currentRunningSpec; + spec.startTime = await SysTestKit.getRealTime(); + } + + async specDone() { + let msg = ""; + let spec = this.specService.currentRunningSpec; + let suite = this.suiteService.currentRunningSuite; + spec.duration = (await SysTestKit.getRealTime()) - spec.startTime; + suite.duration += spec.duration; + if (spec.error) { + this.formatPrint( + "error", + spec.description + " ; consuming " + spec.duration + "ms" + ); + this.formatPrint("errorDetail", spec.error); + } else if (spec.fail) { + this.formatPrint( + "fail", + spec.description + " ; consuming " + spec.duration + "ms" + ); + this.formatPrint("failDetail", spec.fail?.message); + } else { + this.formatPrint( + "pass", + spec.description + " ; consuming " + spec.duration + "ms" + ); + } + this.formatPrint(this.specService.currentRunningSpec.error, msg); + } + + suiteDone() { + let suite = this.suiteService.currentRunningSuite; + let message = suite.hookError ? `, ${suite.hookError?.message}` : ""; + console.info( + `[suite end] ${suite.description} consuming ${suite.duration} ms${message}` + ); + } + + taskDone() { + let msg = ""; + let summary = this.suiteService.getSummary(); + msg = + "total cases:" + + summary.total + + ";failure " + + summary.failure + + "," + + "error " + + summary.error; + msg += ",pass " + summary.pass + "; consuming " + summary.duration + "ms"; + console.info(`${TAG}${msg}`); + console.info(`${TAG}[end] run suites end`); + } + + incorrectFormat() { + if (this.coreContext.getDefaultService("config").filterValid.length !== 0) { + this.coreContext + .getDefaultService("config") + .filterValid.forEach(function (item) { + console.info(`${TAG}this param ${item} is invalid`); + }); + } + } + + incorrectTestSuiteFormat() { + if ( + this.coreContext.getDefaultService("config").filterXdescribe.length !== 0 + ) { + this.coreContext + .getDefaultService("config") + .filterXdescribe.forEach(function (item) { + console.info(`${TAG}xdescribe: ${item} should not contain it`); + }); + } + } + + formatPrint(type, msg) { + switch (type) { + case "pass": + console.info(`${TAG}[pass]${msg}`); + break; + case "fail": + console.info(`${TAG}[fail]${msg}`); + break; + case "failDetail": + console.info(`${TAG}[failDetail]${msg}`); + break; + case "error": + console.info(`${TAG}[error]${msg}`); + break; + case "errorDetail": + console.info(`${TAG}[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 }; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/test/util/framework.test.ts b/ohos_addon_example/entry/src/ohosTest/ets/test/util/framework.test.ts new file mode 100644 index 0000000..41401f2 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/test/util/framework.test.ts @@ -0,0 +1,338 @@ +import Core from "./core/core"; +import { DEFAULT, TestType, Size, Level, TAG, PrintTag } from "./core/Constant"; +import DataDriver from "./core/module/config/DataDriver"; +import ExpectExtend from "./core/module/assert/ExpectExtend"; +import OhReport from "./core/module/report/OhReport"; +import SysTestKit from "./core/module/kit/SysTestKit"; +import { + describe, + beforeAll, + beforeEach, + afterEach, + afterAll, + it, + expect, + beforeItSpecified, + afterItSpecified, + xdescribe, + xit +} from "./core/interface"; +import { MockKit, when } from "./core/module/mock/MockKit"; +import ArgumentMatchers from "./core/module/mock/ArgumentMatchers"; +import worker from "@ohos.worker"; + +class Hypium { + static context = new Map(); + static setData(data) { + const core = Core.getInstance(); + const dataDriver = new DataDriver({ data }); + core.addService("dataDriver", dataDriver); + } + + static setTimeConfig(systemTime) { + SysTestKit.systemTime = systemTime; + } + + static set(key, value) { + Hypium.context.set(key, value); + } + + static get(key) { + return Hypium.context.get(key); + } + + static hypiumTest( + abilityDelegator, + abilityDelegatorArguments, + ctx, + testsuite + ) { + const core = Core.getInstance(); + const expectExtend = new ExpectExtend({ + id: "extend" + }); + core.addService("expect", expectExtend); + const ohReport = new OhReport({ + delegator: abilityDelegator, + abilityDelegatorArguments: abilityDelegatorArguments + }); + 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"); + if (abilityDelegatorArguments !== null) { + let testParameters = configService.translateParams( + abilityDelegatorArguments.parameters + ); + console.info(`${TAG}parameters:${JSON.stringify(testParameters)}`); + configService.setConfig(testParameters); + } + testsuite(ctx); + core.execute(abilityDelegator); + } + static async hypiumInitWorkers( + abilityDelegator, + scriptURL, + workerNum = 8, + params + ) { + console.info(`${TAG}, hypiumInitWorkers call,${scriptURL}`); + let workerPromiseArray = []; + + // 开始统计时间 + let startTime = await SysTestKit.getRealTime(); + for (let i = 0; i < workerNum; i++) { + // 创建worker线程 + const workerPromise = Hypium.createWorkerPromise(scriptURL, i, params); + workerPromiseArray.push(workerPromise); + } + const ret = { + total: 0, + failure: 0, + error: 0, + pass: 0, + ignore: 0, + duration: 0 + }; + Promise.all(workerPromiseArray) + .then(async (items) => { + console.info( + `${TAG}, all result from workers, ${JSON.stringify(items)}` + ); + let allItemList = new Array(); + // 统计执行结果 + Hypium.handleWorkerTestResult(ret, allItemList, items); + console.info(`${TAG}, all it result, ${JSON.stringify(allItemList)}`); + // 统计用例执行结果 + const retResult = { + total: 0, + failure: 0, + error: 0, + pass: 0, + ignore: 0, + duration: 0 + }; + // 标记用例执行结果 + Hypium.configWorkerItTestResult(retResult, allItemList); + // 打印用例结果 + Hypium.printWorkerTestResult(abilityDelegator, allItemList); + // 用例执行完成统计时间 + let endTime = await SysTestKit.getRealTime(); + const taskConsuming = endTime - startTime; + const message = + `\n${PrintTag.OHOS_REPORT_ALL_RESULT}: stream=Test run: runTimes: ${ret.total},total: ${retResult.total}, Failure: ${retResult.failure}, Error: ${retResult.error}, Pass: ${retResult.pass}, Ignore: ${retResult.ignore}` + + `\n${PrintTag.OHOS_REPORT_ALL_CODE}: ${retResult.failure > 0 || retResult.error > 0 ? -1 : 0}` + + `\n${PrintTag.OHOS_REPORT_ALL_STATUS}: taskconsuming=${taskConsuming > 0 ? taskConsuming : ret.duration}`; + abilityDelegator.printSync(message); + console.info(`${TAG}, [end] you worker test`); + abilityDelegator.finishTest("you worker test finished!!!", 0, () => {}); + }) + .catch((e) => { + console.info( + `${TAG}, [end] error you worker test, ${JSON.stringify(e)}` + ); + abilityDelegator.finishTest( + "you worker test error finished!!!", + 0, + () => {} + ); + }) + .finally(() => { + console.info(`${TAG}, all promise finally end`); + }); + } + // 创建worker线程 + static createWorkerPromise(scriptURL, i, params) { + console.info(`${TAG}, createWorkerPromiser, ${scriptURL}, ${i}`); + const workerPromise = new Promise((resolve, reject) => { + const workerInstance = new worker.ThreadWorker(scriptURL, { + name: `worker_${i}` + }); + console.info(`${TAG}, send data to worker`); + // 发送数据到worker线程中 + workerInstance.postMessage(params); + workerInstance.onmessage = function (e) { + let currentThreadName = e.data?.currentThreadName; + console.info( + `${TAG}, receview data from ${currentThreadName}, ${JSON.stringify(e.data)}` + ); + // + resolve(e.data?.summary); + console.info(`${TAG}, ${currentThreadName} finish`); + workerInstance.terminate(); + }; + workerInstance.onerror = function (e) { + console.info(`${TAG}, worker error, ${JSON.stringify(e)}`); + reject(e); + workerInstance.terminate(); + }; + workerInstance.onmessageerror = function (e) { + console.info(`${TAG}, worker message error, ${JSON.stringify(e)}`); + reject(e); + workerInstance.terminate(); + }; + }); + return workerPromise; + } + static handleWorkerTestResult(ret, allItemList, items) { + console.info(`${TAG}, handleWorkerTestResult, ${JSON.stringify(items)}`); + for (const { + total, + failure, + error, + pass, + ignore, + duration, + itItemList + } of items) { + ret.total += total; + ret.failure += failure; + ret.error += error; + ret.pass += pass; + ret.ignore += ignore; + ret.duration += duration; + Hypium.handleItResult(allItemList, itItemList); + } + } + static handleItResult(allItemList, itItemList) { + // 遍历所有的用例结果统计最终结果 + for (const { currentThreadName, description, result } of itItemList) { + let item = allItemList.find((it) => it.description === description); + if (item) { + let itResult = item.result; + // 当在worker中出现一次failure就标记为failure, 出现一次error就标记为error, 所有线程都pass才标记为pass + if (itResult === 0) { + item.result = result; + item.currentThreadName = currentThreadName; + } + } else { + let it = { + description: description, + currentThreadName: currentThreadName, + result: result + }; + allItemList.push(it); + } + } + } + static configWorkerItTestResult(retResult, allItemList) { + console.info( + `${TAG}, configWorkerItTestResult, ${JSON.stringify(allItemList)}` + ); + for (const { currentThreadName, description, result } of allItemList) { + console.info(`${TAG}, description, ${description}, result,${result}`); + retResult.total++; + if (result === 0) { + retResult.pass++; + } else if (result === -1) { + retResult.error++; + } else if (result === -2) { + retResult.failure++; + } else { + retResult.ignore++; + } + } + } + static printWorkerTestResult(abilityDelegator, allItemList) { + console.info( + `${TAG}, printWorkerTestResult, ${JSON.stringify(allItemList)}` + ); + let index = 1; + for (const { currentThreadName, description, result } of allItemList) { + console.info( + `${TAG}, description print, ${description}, result,${result}` + ); + let itArray = description.split("#"); + let des; + let itName; + if (itArray.length > 1) { + des = itArray[0]; + itName = itArray[1]; + } else if (itArray.length > 1) { + des = itArray[0]; + itName = itArray[0]; + } else { + des = "undefined"; + itName = "undefined"; + } + + let msg = `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: class=${des}`; + msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: test=${itName}`; + msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: current=${index}`; + msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: CODE=${result}`; + abilityDelegator.printSync(msg); + index++; + } + } + static hypiumWorkerTest( + abilityDelegator, + abilityDelegatorArguments, + ctx, + testsuite, + workerPort + ) { + console.info(`${TAG}, hypiumWorkerTest call`); + SysTestKit.workerPort = workerPort; + let currentWorkerName = workerPort.name; + console.info( + `${TAG}, hypiumWorkerTest_currentWorkerName: ${currentWorkerName}` + ); + Hypium.hypiumTest( + abilityDelegator, + abilityDelegatorArguments, + ctx, + testsuite + ); + } + + static registerAssert(customAssertion) { + const core = Core.getInstance(); + const expectService = core.getDefaultService("expect"); + let matchers = {}; + matchers[customAssertion.name] = customAssertion; + expectService.addMatchers(matchers); + expectService.customMatchers.push(customAssertion.name); + console.info(`${TAG}success to register the ${customAssertion.name}`); + } + + static unregisterAssert(customAssertion) { + const core = Core.getInstance(); + const expectService = core.getDefaultService("expect"); + let customAssertionName = + typeof customAssertion === "function" + ? customAssertion.name + : customAssertion; + expectService.removeMatchers(customAssertionName); + console.info(`${TAG}success to unregister the ${customAssertionName}`); + } +} + +export { + Hypium, + Core, + DEFAULT, + TestType, + Size, + Level, + DataDriver, + ExpectExtend, + OhReport, + SysTestKit, + describe, + beforeAll, + beforeEach, + afterEach, + afterAll, + it, + expect, + beforeItSpecified, + afterItSpecified, + xdescribe, + xit, + MockKit, + when, + ArgumentMatchers +}; diff --git a/ohos_addon_example/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets b/ohos_addon_example/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets new file mode 100644 index 0000000..afcff69 --- /dev/null +++ b/ohos_addon_example/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ets @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023-2024 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 { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { resourceManager } from '@kit.LocalizationKit'; +import { util } from '@kit.ArkTS'; +import { Hypium } from '../test/util/framework.test'; +import testsuite from '../test/List.test'; + +let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator; +let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs; +let jsonPath: string = 'mock/mock-config.json'; +let domain: number = 0x0000; //日志标识,0x0000作为测试框架的业务标识 +let tag: string = 'testTag'; //日志标识字符串,作为tag标识当前runner类下的测试行为 + +export default class OpenHarmonyTestRunner implements TestRunner { + constructor() { + } + + onPrepare() { + hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner OnPrepare'); + } + + async onRun() { + hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run'); + abilityDelegatorArguments = abilityDelegatorRegistry.getArguments(); + abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator(); + let moduleName = abilityDelegatorArguments.parameters['-m']; + let ctx = abilityDelegator.getAppContext().getApplicationContext(); + let context = ctx.createModuleContext(moduleName); + let mResourceManager = context.resourceManager; + await checkMock(abilityDelegator, mResourceManager); + hilog.info(domain, tag, '%{public}s', 'start run testcase!!!'); + Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, ctx, testsuite); + hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end'); + } +} + +async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, + resourceManager: resourceManager.ResourceManager) { + let rawFile: Uint8Array; + try { + rawFile = resourceManager.getRawFileContentSync(jsonPath); + hilog.info(domain, tag, 'MockList file exists'); + let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile); + let mockMap: Record = getMockList(mockStr); + try { + abilityDelegator.setMockList(mockMap); + } catch (error) { + let code = (error as BusinessError).code; + let message = (error as BusinessError).message; + hilog.error(domain, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`); + } + } catch (error) { + let code = (error as BusinessError).code; + let message = (error as BusinessError).message; + hilog.error(domain, tag, + `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`); + } +} + +function getMockList(jsonStr: string) { + let jsonObj: Record = JSON.parse(jsonStr); + let map: Map = new Map(Object.entries(jsonObj)); + let mockList: Record = {}; + map.forEach((value: object, key: string) => { + let realValue: string = value['source'].toString(); + mockList[key] = realValue; + }); + hilog.info(domain, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? ''); + return mockList; +} \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh index 7d9bbb1..668ee41 100644 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -6,7 +6,7 @@ script_dir=$(cd "$script_dir" && pwd) parent_dir=$(dirname "$script_dir") -cd $parent_dir/example +pushd $parent_dir/example rm -rf build @@ -14,4 +14,9 @@ mkdir build && pushd build cmake -DOHOS_STL=c++_shared -DOHOS_ARCH=arm64-v8a ../ -cmake --build ./ \ No newline at end of file +cmake --build ./ + +popd + +cp $parent_dir/example/build/libexample.so $parent_dir/ohos_addon_example/entry/libs/arm64-v8a +cp $OHOS_NDK_HOME/native/llvm/lib/aarch64-linux-ohos/libc++_shared.so $parent_dir/ohos_addon_example/entry/libs/arm64-v8a \ No newline at end of file