From 53f6cbd3be9c6f5a62daffc964f6c4b1c81fad7b Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Tue, 28 Jan 2025 18:32:27 +0300 Subject: [PATCH 01/10] Try to repair tests for ArkTS Signed-off-by: Sergey Malenkov --- incremental/runtime/arktsconfig-test-app.json | 7 ++++--- incremental/runtime/arktsconfig-test-lib.json | 7 ++++--- incremental/runtime/package.json | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/incremental/runtime/arktsconfig-test-app.json b/incremental/runtime/arktsconfig-test-app.json index efd50c1c3..93bc36d2e 100644 --- a/incremental/runtime/arktsconfig-test-app.json +++ b/incremental/runtime/arktsconfig-test-app.json @@ -1,10 +1,11 @@ { "compilerOptions": { - "baseUrl": ".", + "package": "@koalaui/runtime", + "baseUrl": "./build/unmemoized/src", "outDir": "build/test/app", "paths": { - "@koalaui/common": ["../common/src"], - "@koalaui/compat": ["../compat/src/arkts"] + "@koalaui/common": ["../../../../common/src"], + "@koalaui/compat": ["../../../../compat/src/arkts"] } } } diff --git a/incremental/runtime/arktsconfig-test-lib.json b/incremental/runtime/arktsconfig-test-lib.json index 6fdbd8cf1..0aa667577 100644 --- a/incremental/runtime/arktsconfig-test-lib.json +++ b/incremental/runtime/arktsconfig-test-lib.json @@ -1,10 +1,11 @@ { "compilerOptions": { - "baseUrl": ".", + "package": "@koalaui/runtime", + "baseUrl": "./build/unmemoized/src", "outDir": "build/test/lib", "paths": { - "@koalaui/common": ["../common/src"], - "@koalaui/compat": ["../compat/src/arkts"] + "@koalaui/common": ["../../../../common/src"], + "@koalaui/compat": ["../../../../compat/src/arkts"] } }, "include": ["build/unmemoized/src/**/*.ts", "build/unmemoized/test-arkts/**/*.ts"], diff --git a/incremental/runtime/package.json b/incremental/runtime/package.json index 73cdc7e89..9e9965d8e 100644 --- a/incremental/runtime/package.json +++ b/incremental/runtime/package.json @@ -54,4 +54,4 @@ "mocha": "^9.2.2", "source-map-support": "^0.5.21" } -} \ No newline at end of file +} -- Gitee From aedb716924b4d886f07133989c839c44968bdacd Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 31 Jan 2025 13:54:44 +0300 Subject: [PATCH 02/10] new compilation approach for ArkTS tests Signed-off-by: Sergey Malenkov --- incremental/runtime/arktsconfig-test-app.json | 11 ------ incremental/runtime/arktsconfig-test-lib.json | 13 ------- .../runtime/arktsconfig-test-unmemoized.json | 24 ++++++++++++ incremental/runtime/package.json | 12 +++--- .../test-arkts/animation/Easing.test.ts | 3 +- .../runtime/test-arkts/memo/bind.test.ts | 1 + .../test-arkts/memo/changeListener.test.ts | 3 +- .../test-arkts/memo/contextLocal.test.ts | 3 +- .../runtime/test-arkts/memo/remember.test.ts | 3 +- .../runtime/test-arkts/memo/repeat.test.ts | 3 +- .../runtime/test-arkts/states/State.test.ts | 3 +- .../test-arkts/states/state_basics.test.ts | 3 +- incremental/runtime/test-arkts/tests.ts | 39 +++++++++++++++++++ .../runtime/test-arkts/tree/TreeNode.test.ts | 3 +- .../runtime/test-arkts/tree/TreePath.test.ts | 3 +- 15 files changed, 87 insertions(+), 40 deletions(-) delete mode 100644 incremental/runtime/arktsconfig-test-app.json delete mode 100644 incremental/runtime/arktsconfig-test-lib.json create mode 100644 incremental/runtime/arktsconfig-test-unmemoized.json create mode 100644 incremental/runtime/test-arkts/tests.ts diff --git a/incremental/runtime/arktsconfig-test-app.json b/incremental/runtime/arktsconfig-test-app.json deleted file mode 100644 index 93bc36d2e..000000000 --- a/incremental/runtime/arktsconfig-test-app.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "package": "@koalaui/runtime", - "baseUrl": "./build/unmemoized/src", - "outDir": "build/test/app", - "paths": { - "@koalaui/common": ["../../../../common/src"], - "@koalaui/compat": ["../../../../compat/src/arkts"] - } - } -} diff --git a/incremental/runtime/arktsconfig-test-lib.json b/incremental/runtime/arktsconfig-test-lib.json deleted file mode 100644 index 0aa667577..000000000 --- a/incremental/runtime/arktsconfig-test-lib.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "package": "@koalaui/runtime", - "baseUrl": "./build/unmemoized/src", - "outDir": "build/test/lib", - "paths": { - "@koalaui/common": ["../../../../common/src"], - "@koalaui/compat": ["../../../../compat/src/arkts"] - } - }, - "include": ["build/unmemoized/src/**/*.ts", "build/unmemoized/test-arkts/**/*.ts"], - "exclude": ["build/unmemoized/test-arkts/**/*.test.ts"] -} diff --git a/incremental/runtime/arktsconfig-test-unmemoized.json b/incremental/runtime/arktsconfig-test-unmemoized.json new file mode 100644 index 000000000..e95c51de0 --- /dev/null +++ b/incremental/runtime/arktsconfig-test-unmemoized.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "package": "@koalaui/runtime-tests", + "outDir": "build/unmemoized/abc", + "baseUrl": "./build/unmemoized", + "paths": { + "@koalaui/compat": [ "../../../compat/src/arkts" ], + "@koalaui/common": [ "../../../common/src" ] + } + }, + "include": [ + "build/unmemoized/src/**/*.ts", + "build/unmemoized/src/*.ts", + "build/unmemoized/test-arkts/**/*.ts", + "build/unmemoized/test-arkts/*.ts" + ], + "exclude": [ + "build/unmemoized/test-arkts/memo/changeListener.test.ts", + "build/unmemoized/test-arkts/memo/contextLocal.test.ts", + "build/unmemoized/test-arkts/memo/repeat.test.ts", + "build/unmemoized/test-arkts/states/state_basics.test.ts", + "build/unmemoized/test-arkts/states/State.test.ts" + ] +} diff --git a/incremental/runtime/package.json b/incremental/runtime/package.json index 9e9965d8e..9c2952e5c 100644 --- a/incremental/runtime/package.json +++ b/incremental/runtime/package.json @@ -17,13 +17,10 @@ "test": "mocha", "test:coverage": "nyc mocha", "panda:sdk:install": "cd ../tools/panda && npm run panda:sdk:install", - "arkts:compile:test:lib": "bash ../tools/panda/arkts/arktsc --arktsconfig arktsconfig-test-lib.json --ets-module", - "arkts:compile:test:app": "find build/unmemoized/test-arkts -name '*.test.ts' -exec mkdir -p build/test/app/{} \\; -exec bash ../tools/panda/arkts/arktsc --arktsconfig arktsconfig-test-app.json --output build/test/app/{}/test.abc {} \\;", - "arkts:run:test:harness": "find build/test/app -name test.abc -exec bash ../tools/panda/arkts/ark --ark-boot-files $(find ../compat/build/abc ../common/build/abc ./build/test/lib -name '*.abc' | paste -sd ':' -) {} \\;", - "arkts:compile:test": "npm run compile:arkts && npm run arkts:compile:test:lib && npm run arkts:compile:test:app", - "arkts:run:test": "npm run clean && npm run panda:sdk:install && npm run arkts:compile:test && npm run arkts:run:test:harness", - "unmemoize": "ets-tsc -b arktsconfig-unmemoize.json", - "compile:arkts": "npm run unmemoize && ../tools/panda/arkts/arktsc --arktsconfig arktsconfig-run-unmemoized.json --ets-module", + "arkts:test:run": "bash ../tools/panda/arkts/ark build/runtime-tests.abc --ark-boot-files ../compat/build/compat.abc:../common/build/common.abc --ark-entry-point @koalaui.runtime-tests.test-arkts.tests.ETSGLOBAL::main", + "arkts:test": "npm run panda:sdk:install && npm run build:compat && npm run build:common && npm run build:runtime:with:tests && npm run arkts:test:run", + "unmemoize": "mkdir -p build/unmemoized/abc && mkdir -p build/test/lib && ets-tsc -b arktsconfig-unmemoize.json && mkdir -p build/test/lib", + "compile:arkts": "npm run unmemoize && ../tools/panda/arkts/arktsc --arktsconfig arktsconfig-run-unmemoized.json", "build:compat": "npm run build:compat --prefix ../compat", "build:compat:inc": "npm run build:compat:inc --prefix ../compat", "build:common": "npm run build:common --prefix ../common", @@ -31,6 +28,7 @@ "build:runtime": "npm run build:runtime:inc", "build:runtime:inc": "npm run unmemoize && fast-arktsc --input-files ./arktsconfig-run-unmemoized.json --output-dir ./build --compiler ../tools/panda/arkts/arktsc --link-name runtime && ninja ${NINJA_OPTIONS} -f build/build.ninja", "build:runtime:inc:capi": "npm run unmemoize && fast-arktsc --input-files ./arktsconfig-run-unmemoized.json --output-dir ./build --compiler ../tools/panda/arkts/arktsc-capi --link-name runtime --file-option && PANDA_SDK_PATH=../tools/panda/node_modules/@panda/sdk ninja ${NINJA_OPTIONS} -f build/build.ninja", + "build:runtime:with:tests": "npm run unmemoize && fast-arktsc --input-files ./arktsconfig-test-unmemoized.json --output-dir ./build --compiler ../tools/panda/arkts/arktsc --link-name runtime-tests && ninja ${NINJA_OPTIONS} -f build/build.ninja", "build:incremental:components": "npm run build:compat && npm run build:common && npm run build:runtime", "build:incremental:components:inc": "npm run build:compat:inc && npm run build:common:inc && npm run build:runtime:inc", "link:incremental": "../tools/panda/arkts/arklink --output build/incremental.abc -- ../compat/build/compat.abc ../common/build/common.abc build/runtime.abc", diff --git a/incremental/runtime/test-arkts/animation/Easing.test.ts b/incremental/runtime/test-arkts/animation/Easing.test.ts index b0fa5ea98..5ef8d3bc6 100644 --- a/incremental/runtime/test-arkts/animation/Easing.test.ts +++ b/incremental/runtime/test-arkts/animation/Easing.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -17,6 +17,7 @@ import { Assert, suite, test } from "../harness" import { float64, int32 } from "@koalaui/common" import { Easing, EasingCurve, EasingStepJump } from "../../src/animation/Easing" +export const FileName = "animation/Easing.test" function assertEasing(easing: EasingCurve, ...expected: int32[]) { const last = expected.length - 1 diff --git a/incremental/runtime/test-arkts/memo/bind.test.ts b/incremental/runtime/test-arkts/memo/bind.test.ts index 0f3c4981e..01df7ad81 100644 --- a/incremental/runtime/test-arkts/memo/bind.test.ts +++ b/incremental/runtime/test-arkts/memo/bind.test.ts @@ -23,6 +23,7 @@ import { memoBind, testTick, } from "../../src" +export const FileName = "memo/bind.test" const collector = new Array() diff --git a/incremental/runtime/test-arkts/memo/changeListener.test.ts b/incremental/runtime/test-arkts/memo/changeListener.test.ts index 8ee931071..9b4db48b2 100644 --- a/incremental/runtime/test-arkts/memo/changeListener.test.ts +++ b/incremental/runtime/test-arkts/memo/changeListener.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -24,6 +24,7 @@ import { mutableState, testTick, } from "../../src" +export const FileName = "memo/changeListeners.test" const collector = new Array() diff --git a/incremental/runtime/test-arkts/memo/contextLocal.test.ts b/incremental/runtime/test-arkts/memo/contextLocal.test.ts index fa5fdbe5e..b25c14490 100644 --- a/incremental/runtime/test-arkts/memo/contextLocal.test.ts +++ b/incremental/runtime/test-arkts/memo/contextLocal.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -24,6 +24,7 @@ import { mutableState, testTick, } from "../../src" +export const FileName = "memo/contextLocal.test" const collector = new Array() diff --git a/incremental/runtime/test-arkts/memo/remember.test.ts b/incremental/runtime/test-arkts/memo/remember.test.ts index a21da1831..2fb07379a 100644 --- a/incremental/runtime/test-arkts/memo/remember.test.ts +++ b/incremental/runtime/test-arkts/memo/remember.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -28,6 +28,7 @@ import { rememberMutableState, testTick, } from "../../src" +export const FileName = "memo/remember.test" const collector = new Array() diff --git a/incremental/runtime/test-arkts/memo/repeat.test.ts b/incremental/runtime/test-arkts/memo/repeat.test.ts index 12498c592..07b543387 100644 --- a/incremental/runtime/test-arkts/memo/repeat.test.ts +++ b/incremental/runtime/test-arkts/memo/repeat.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -29,6 +29,7 @@ import { mutableState, testTick, } from "../../src" +export const FileName = "memo/repeat.test" const collector = new Array() diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index 4925a207e..d51d5fc2d 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -18,6 +18,7 @@ import { Assert, suite, test } from "../harness" import { KoalaCallsiteKey, float64, int32 } from "@koalaui/common" import { IncrementalNode, State, StateContext, TestNode, testUpdate, ValueTracker } from "../../src" import { createStateManager } from "../../src/states/State" +export const FileName = "states/State.test" // For tests we compute positional ids from strings. export function key(name: string): KoalaCallsiteKey { diff --git a/incremental/runtime/test-arkts/states/state_basics.test.ts b/incremental/runtime/test-arkts/states/state_basics.test.ts index 2acf313ba..d1a1d1dde 100644 --- a/incremental/runtime/test-arkts/states/state_basics.test.ts +++ b/incremental/runtime/test-arkts/states/state_basics.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -24,6 +24,7 @@ import { testRoot, testTick, } from "../../src" +export const FileName = "states/state_basics.test" function assertResultArray(actual: Array, ...expected: T[]) { Assert.deepEqual(actual, asArray(expected)) diff --git a/incremental/runtime/test-arkts/tests.ts b/incremental/runtime/test-arkts/tests.ts new file mode 100644 index 000000000..dfc16920c --- /dev/null +++ b/incremental/runtime/test-arkts/tests.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022-2025 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 { suite } from "./harness" +import { FileName as Easing } from "./animation/Easing.test" +import { FileName as bind } from "./memo/bind.test" +import { FileName as changeListener } from "./memo/changeListener.test" +import { FileName as contextLocal } from "./memo/contextLocal.test" +import { FileName as remember } from "./memo/remember.test" +import { FileName as repeat } from "./memo/repeat.test" +import { FileName as state_basics } from "./states/state_basics.test" +import { FileName as State } from "./states/State.test" +import { FileName as TreeNode } from "./tree/TreeNode.test" +import { FileName as TreePath } from "./tree/TreePath.test" + +suite("harness", () => { + console.log("register file:", Easing) + console.log("register file:", bind) + // console.log("register file:", changeListener) + // console.log("register file:", contextLocal) + console.log("register file:", remember) + // console.log("register file:", repeat) + // console.log("register file:", state_basics) + // console.log("register file:", State) + console.log("register file:", TreeNode) + console.log("register file:", TreePath) +}) diff --git a/incremental/runtime/test-arkts/tree/TreeNode.test.ts b/incremental/runtime/test-arkts/tree/TreeNode.test.ts index 696f2be60..fa836bfc6 100644 --- a/incremental/runtime/test-arkts/tree/TreeNode.test.ts +++ b/incremental/runtime/test-arkts/tree/TreeNode.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -17,6 +17,7 @@ import { Assert, suite, test } from "../harness" import { float64, int32, uint32 } from "@koalaui/common" import { TreeNode } from "../../src/tree/TreeNode" +export const FileName = "tree/TreeNode.test" class StringNode extends TreeNode { readonly content: string diff --git a/incremental/runtime/test-arkts/tree/TreePath.test.ts b/incremental/runtime/test-arkts/tree/TreePath.test.ts index 8e12e2a03..2b760081e 100644 --- a/incremental/runtime/test-arkts/tree/TreePath.test.ts +++ b/incremental/runtime/test-arkts/tree/TreePath.test.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Copyright (c) 2022-2025 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 @@ -16,6 +16,7 @@ // TODO: the real chai exports 'assert', but 'assert' is still a keyword in ArkTS import { Assert, suite, test } from "../harness" import { TreePath } from "../../src/tree/TreePath" +export const FileName = "tree/TreePath.test" suite("TreePath", () => { -- Gitee From 8ae6593b568031dc0592d7b9c056c72a082cc3cd Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 31 Jan 2025 13:55:09 +0300 Subject: [PATCH 03/10] add CI task Signed-off-by: Sergey Malenkov --- incremental/runtime/.gitlab-ci.yml | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/incremental/runtime/.gitlab-ci.yml b/incremental/runtime/.gitlab-ci.yml index 55db0c9b8..56b5b2e8d 100644 --- a/incremental/runtime/.gitlab-ci.yml +++ b/incremental/runtime/.gitlab-ci.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2022-2023 Huawei Device Co., Ltd. +# Copyright (c) 2022-2025 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 @@ -52,6 +52,25 @@ test runtime: - build compiler-plugin - build runtime +test runtime (ArkTS): + stage: test + interruptible: true + extends: .linux-vm-shell-task + before_script: + - !reference [.setup, script] + - cd incremental/runtime + script: + - npm run arkts:test + needs: + - install node modules (arkoala) + - install node modules (arkoala-arkts) + - install node modules (incremental) + - install node modules (interop) + - build common + - build compat + - build compiler-plugin + - build runtime + pack runtime: extends: - .npm-pack -- Gitee From 4187e7553dc49ead380656792f2f8179878da9a8 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 31 Jan 2025 15:51:44 +0300 Subject: [PATCH 04/10] add some new tests to arkts-tests Signed-off-by: Sergey Malenkov --- .../test-arkts/common/MarkableQueue.test.ts | 109 +++++ .../runtime/test-arkts/states/Journal.test.ts | 101 ++++ .../runtime/test-arkts/states/State.test.ts | 441 ++++++++++++++++++ incremental/runtime/test-arkts/tests.ts | 4 + 4 files changed, 655 insertions(+) create mode 100644 incremental/runtime/test-arkts/common/MarkableQueue.test.ts create mode 100644 incremental/runtime/test-arkts/states/Journal.test.ts diff --git a/incremental/runtime/test-arkts/common/MarkableQueue.test.ts b/incremental/runtime/test-arkts/common/MarkableQueue.test.ts new file mode 100644 index 000000000..c53180bad --- /dev/null +++ b/incremental/runtime/test-arkts/common/MarkableQueue.test.ts @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +// TODO: the real chai exports 'assert', but 'assert' is still a keyword in ArkTS +import { Assert, suite, test } from "../harness" +import { MarkableQueue, markableQueue } from "@koalaui/common" +export const FileName = "common/MarkableQueue.test" + +const collector = new Array() + +function testQueue(queue: MarkableQueue, expected: Array) { + collector.length = 0 + queue.callCallbacks() + Assert.deepEqual(collector, expected) +} + +suite("MarkableQueue tests", () => { + + test("nothing to call without marker", () => { + const queue = markableQueue() + queue.addCallback(() => { collector.push("1a") }) + queue.addCallback(() => { collector.push("1b") }) + queue.addCallback(() => { collector.push("1c") }) + testQueue(queue, Array.of()) + }) + + test("call only marked callbacks", () => { + const queue = markableQueue() + queue.addCallback(() => { collector.push("1a") }) + queue.addCallback(() => { collector.push("1b") }) + queue.addCallback(() => { collector.push("1c") }) + queue.setMarker() + queue.addCallback(() => { collector.push("2a") }) + queue.addCallback(() => { collector.push("2b") }) + queue.addCallback(() => { collector.push("2c") }) + testQueue(queue, Array.of("1a", "1b", "1c")) + testQueue(queue, Array.of()) // called only once + }) + + test("call marked callbacks to the latest marker", () => { + const queue = markableQueue() + queue.addCallback(() => { collector.push("1a") }) + queue.addCallback(() => { collector.push("1b") }) + queue.addCallback(() => { collector.push("1c") }) + queue.setMarker() + queue.addCallback(() => { collector.push("2a") }) + queue.addCallback(() => { collector.push("2b") }) + queue.addCallback(() => { collector.push("2c") }) + queue.setMarker() + queue.addCallback(() => { collector.push("3a") }) + queue.addCallback(() => { collector.push("3b") }) + queue.addCallback(() => { collector.push("3c") }) + testQueue(queue, Array.of("1a", "1b", "1c", "2a", "2b", "2c")) + testQueue(queue, Array.of()) // called only once + }) +}) + +suite("MarkableQueue reversed tests", () => { + + test("nothing to call without marker", () => { + const queue = markableQueue(true) + queue.addCallback(() => { collector.push("1a") }) + queue.addCallback(() => { collector.push("1b") }) + queue.addCallback(() => { collector.push("1c") }) + testQueue(queue, Array.of()) + }) + + test("call only marked callbacks", () => { + const queue = markableQueue(true) + queue.addCallback(() => { collector.push("1a") }) + queue.addCallback(() => { collector.push("1b") }) + queue.addCallback(() => { collector.push("1c") }) + queue.setMarker() + queue.addCallback(() => { collector.push("2a") }) + queue.addCallback(() => { collector.push("2b") }) + queue.addCallback(() => { collector.push("2c") }) + testQueue(queue, Array.of("1c", "1b", "1a")) + testQueue(queue, Array.of()) // called only once + }) + + test("call marked callbacks from the latest marker", () => { + const queue = markableQueue(true) + queue.addCallback(() => { collector.push("1a") }) + queue.addCallback(() => { collector.push("1b") }) + queue.addCallback(() => { collector.push("1c") }) + queue.setMarker() + queue.addCallback(() => { collector.push("2a") }) + queue.addCallback(() => { collector.push("2b") }) + queue.addCallback(() => { collector.push("2c") }) + queue.setMarker() + queue.addCallback(() => { collector.push("3a") }) + queue.addCallback(() => { collector.push("3b") }) + queue.addCallback(() => { collector.push("3c") }) + testQueue(queue, Array.of("2c", "2b", "2a", "1c", "1b", "1a")) + testQueue(queue, Array.of()) // called only once + }) +}) diff --git a/incremental/runtime/test-arkts/states/Journal.test.ts b/incremental/runtime/test-arkts/states/Journal.test.ts new file mode 100644 index 000000000..90c1abcd5 --- /dev/null +++ b/incremental/runtime/test-arkts/states/Journal.test.ts @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022-2025 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. + */ + +// TODO: the real chai exports 'assert', but 'assert' is still a keyword in ArkTS +import { Assert, suite, test } from "../harness" +import { Changes, Journal } from "../../src/states/Journal" +export const FileName = "states/Journal.test" + +function assertChange(changes: Changes | undefined, state: Object, expected: Value) { + const change = changes?.getChange(state) + Assert.isDefined(change) + Assert.equal(change?.value, expected) +} + +function assertNoChange(changes: Changes | undefined, state: Object) { + const change = changes?.getChange(state) + Assert.isUndefined(change) +} + +function assertNoChanges(journal: Journal) { + Assert.isUndefined(journal.getChanges()) +} + +suite("Journal tests", () => { + + test("new journal has no any changes", () => { + const journal = new Journal() + assertNoChanges(journal) + }) + + test("add changes to journal", () => { + const state = new Object() + const journal = new Journal() + journal.addChange(state, "value1") + journal.addChange(state, "value2") + assertChange(journal, state, "value2") + assertNoChanges(journal) + }) + + test("add marked changes to journal", () => { + const state = new Object() + const journal = new Journal() + journal.addChange(state, "value1") + journal.addChange(state, "value2") + journal.setMarker() + assertChange(journal, state, "value2") + assertChange(journal.getChanges(), state, "value2") + }) + + test("add changes to journal after marker", () => { + const state = new Object() + const journal = new Journal() + journal.addChange(state, "value1") + journal.addChange(state, "value2") + journal.setMarker() + journal.addChange(state, "value3") + journal.addChange(state, "value4") + assertChange(journal, state, "value4") + assertChange(journal.getChanges(), state, "value2") + }) + + test("remove all changes from journal", () => { + const state = new Object() + const journal = new Journal() + journal.addChange(state, "value1") + journal.addChange(state, "value2") + journal.setMarker() + journal.addChange(state, "value3") + journal.addChange(state, "value4") + journal.clear() + assertNoChange(journal, state) + assertNoChanges(journal) + }) + + test("remove marked changes from journal", () => { + const state = new Object() + const journal = new Journal() + journal.addChange(state, "value1") + journal.addChange(state, "value2") + journal.setMarker() + journal.addChange(state, "value3") + journal.addChange(state, "value4") + const changes = journal.getChanges() + Assert.isDefined(changes) + changes?.clear() + assertChange(journal, state, "value4") + assertNoChanges(journal) + }) +}) diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index d51d5fc2d..16c2c57b7 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -1362,3 +1362,444 @@ suite("ValueTracker", () => { assertModifiedState(state, 999) }) }) + +suite("ArrayState", () => { + test("managed array state supports #at getter", () => { + const manager = createStateManager() + const array = manager.arrayState(["one", "two", "three"]) + Assert.equal(array.length, 3) + Assert.equal(array.at(0), "one") + Assert.equal(array.at(1), "two") + Assert.equal(array.at(2), "three") + Assert.equal(array.at(-1), "three") + Assert.equal(array.at(-2), "two") + Assert.equal(array.at(-3), "one") + }) + test("computable state depends on managed array state", () => { + const manager = createStateManager() + const state = manager.mutableState(1) + const array = manager.arrayState(["item"]) + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + const prefix = state.value + ": " + return prefix + context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= 1: item =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= 1: item =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + state.value = 2 + array.set(0, "value") + Assert.equal(testUpdate(false, manager), 2) + Assert.equal(result.value, "<= 2: value =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + state.value = 3 + array.set(0, "value") + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= 3: value =>") + assertStringsAndCleanup(computing, "outer ; center") + // compute state only when snapshot updated + state.value = 4 + array.length = 0 + Assert.equal(testUpdate(false, manager), 2) + Assert.equal(result.value, "<= 4: =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= 4: =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #copyWithin", () => { + const manager = createStateManager() + const array = manager.arrayState(["one", "two", "three"]) + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= one two three =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= one two three =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + array.copyWithin(0, 1, 2) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= two two three =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + array.copyWithin(2, 0, 1) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= two two two =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + array.copyWithin(1, 2, 0) + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= two two two =>") + Assert.isEmpty(computing) + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= two two two =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #fill", () => { + const manager = createStateManager() + const array = manager.arrayState(["one", "two", "three"]) + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= one two three =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= one two three =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + array.fill("X", 1, 2) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= one X three =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + array.fill("X") + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= X X X =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + array.fill("X", 1) + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= X X X =>") + Assert.isEmpty(computing) + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= X X X =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #pop", () => { + const manager = createStateManager() + const array = manager.arrayState(["first", "last"]) + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= first last =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= first last =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + Assert.equal(array.pop(), "last") + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= first =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + Assert.equal(array.pop(), "first") + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + Assert.isUndefined(array.pop()) + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #push", () => { + const manager = createStateManager() + const array = manager.arrayState() + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + Assert.equal(array.push(), 0) + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + Assert.equal(array.push("one"), 1) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= one =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + Assert.equal(array.push("two", "three"), 3) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= one two three =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= one two three =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #reverse", () => { + const manager = createStateManager() + const array = manager.arrayState(["one", "two", "three"]) + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= one two three =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= one two three =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + array.reverse() + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= three two one =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= three two one =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #shift", () => { + const manager = createStateManager() + const array = manager.arrayState(["first", "last"]) + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= first last =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= first last =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + Assert.equal(array.shift(), "first") + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= last =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + Assert.equal(array.shift(), "last") + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + Assert.isUndefined(array.shift()) + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #sort", () => { + const manager = createStateManager() + const array = manager.arrayState(["one", "two", "three"]) + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= one two three =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= one two three =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + array.sort() + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= one three two =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + array.sort() + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= one three two =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + array.sort((s1, s2) => s1.length < s2.length ? -1 : s1.length > s2.length ? 1 : s1.localeCompare(s2)) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= one two three =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= one two three =>") + Assert.isEmpty(computing) + }) + test("computable state depends on managed array state #unshift", () => { + const manager = createStateManager() + const array = manager.arrayState() + // create computable state that tracks computing inner scopes + const computing = new Array() + const result = manager.computableState((context) => { + computing.push("outer") + return context.compute(key("left"), () => { + computing.push("left") + return "<= " + }) + context.compute(key("center"), () => { + computing.push("center") + return context.compute(key("inner"), () => { + computing.push("inner") + return array.value.join(" ") + }) + }) + context.compute(key("right"), () => { + computing.push("right") + return " =>" + }) + }) + // initial computation + assertState(result, "<= =>") + assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + Assert.equal(array.unshift(), 0) + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= =>") + Assert.isEmpty(computing) + // compute state only when snapshot updated + Assert.equal(array.unshift("one"), 1) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= one =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // compute state only when snapshot updated + Assert.equal(array.unshift("two", "three"), 3) + Assert.equal(testUpdate(false, manager), 1) + Assert.equal(result.value, "<= two three one =>") + assertStringsAndCleanup(computing, "outer ; center ; inner") + // computable state is not modified + Assert.equal(testUpdate(false, manager), 0) + Assert.equal(result.value, "<= two three one =>") + Assert.isEmpty(computing) + }) +}) diff --git a/incremental/runtime/test-arkts/tests.ts b/incremental/runtime/test-arkts/tests.ts index dfc16920c..24aef43b4 100644 --- a/incremental/runtime/test-arkts/tests.ts +++ b/incremental/runtime/test-arkts/tests.ts @@ -15,11 +15,13 @@ import { suite } from "./harness" import { FileName as Easing } from "./animation/Easing.test" +import { FileName as MarkableQueue } from "./common/MarkableQueue.test" import { FileName as bind } from "./memo/bind.test" import { FileName as changeListener } from "./memo/changeListener.test" import { FileName as contextLocal } from "./memo/contextLocal.test" import { FileName as remember } from "./memo/remember.test" import { FileName as repeat } from "./memo/repeat.test" +import { FileName as Journal } from "./states/Journal.test" import { FileName as state_basics } from "./states/state_basics.test" import { FileName as State } from "./states/State.test" import { FileName as TreeNode } from "./tree/TreeNode.test" @@ -27,11 +29,13 @@ import { FileName as TreePath } from "./tree/TreePath.test" suite("harness", () => { console.log("register file:", Easing) + console.log("register file:", MarkableQueue) console.log("register file:", bind) // console.log("register file:", changeListener) // console.log("register file:", contextLocal) console.log("register file:", remember) // console.log("register file:", repeat) + console.log("register file:", Journal) // console.log("register file:", state_basics) // console.log("register file:", State) console.log("register file:", TreeNode) -- Gitee From 1a7cebf23c442b1a55ceacd40dbe636e403bbb97 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 31 Jan 2025 16:02:57 +0300 Subject: [PATCH 05/10] workaround for 20193 issue in Panda Runtime Signed-off-by: Sergey Malenkov --- incremental/runtime/arktsconfig-test-unmemoized.json | 2 -- incremental/runtime/test-arkts/memo/changeListener.test.ts | 2 +- incremental/runtime/test-arkts/memo/contextLocal.test.ts | 4 ++-- incremental/runtime/test-arkts/tests.ts | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/incremental/runtime/arktsconfig-test-unmemoized.json b/incremental/runtime/arktsconfig-test-unmemoized.json index e95c51de0..d09f771ec 100644 --- a/incremental/runtime/arktsconfig-test-unmemoized.json +++ b/incremental/runtime/arktsconfig-test-unmemoized.json @@ -15,8 +15,6 @@ "build/unmemoized/test-arkts/*.ts" ], "exclude": [ - "build/unmemoized/test-arkts/memo/changeListener.test.ts", - "build/unmemoized/test-arkts/memo/contextLocal.test.ts", "build/unmemoized/test-arkts/memo/repeat.test.ts", "build/unmemoized/test-arkts/states/state_basics.test.ts", "build/unmemoized/test-arkts/states/State.test.ts" diff --git a/incremental/runtime/test-arkts/memo/changeListener.test.ts b/incremental/runtime/test-arkts/memo/changeListener.test.ts index 9b4db48b2..b474a6851 100644 --- a/incremental/runtime/test-arkts/memo/changeListener.test.ts +++ b/incremental/runtime/test-arkts/memo/changeListener.test.ts @@ -47,7 +47,7 @@ export function testChange( expected?: string ) { GlobalStateManager.reset() - const state = mutableState("first") + const state = mutableState("first") const root = TestNode.create((node) => { content(state.value) }) testExpected(root, expected) state.value = "f" + "i" + "r" + "s" + "t" diff --git a/incremental/runtime/test-arkts/memo/contextLocal.test.ts b/incremental/runtime/test-arkts/memo/contextLocal.test.ts index b25c14490..8fcf17edd 100644 --- a/incremental/runtime/test-arkts/memo/contextLocal.test.ts +++ b/incremental/runtime/test-arkts/memo/contextLocal.test.ts @@ -38,7 +38,7 @@ function testExpected(root: State, ...expected: string[]) { suite("contextLocal tests", () => { test("contextLocalScope ensures name is not changed", () => { - const state = mutableState("first") + const state = mutableState("first") const root = TestNode.create((node) => { contextLocalScope(state.value, "value", () => { collector.push(contextLocalValue(state.value)) @@ -50,7 +50,7 @@ suite("contextLocal tests", () => { }) test("contextLocalScope propagates state immediately", () => { - const state = mutableState("first") + const state = mutableState("first") const root = TestNode.create((node) => { const str = state.value collector.push("ui:" + str) diff --git a/incremental/runtime/test-arkts/tests.ts b/incremental/runtime/test-arkts/tests.ts index 24aef43b4..7063bfb7d 100644 --- a/incremental/runtime/test-arkts/tests.ts +++ b/incremental/runtime/test-arkts/tests.ts @@ -31,8 +31,8 @@ suite("harness", () => { console.log("register file:", Easing) console.log("register file:", MarkableQueue) console.log("register file:", bind) - // console.log("register file:", changeListener) - // console.log("register file:", contextLocal) + console.log("register file:", changeListener) + console.log("register file:", contextLocal) console.log("register file:", remember) // console.log("register file:", repeat) console.log("register file:", Journal) -- Gitee From 70cbf751ed46be0d9904cc3b6e9a1c9bbda5beb5 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 31 Jan 2025 16:31:46 +0300 Subject: [PATCH 06/10] workaround issues with type inference and UniqueId Signed-off-by: Sergey Malenkov --- .../runtime/arktsconfig-test-unmemoized.json | 1 - .../runtime/test-arkts/memo/repeat.test.ts | 40 +++++++++++-------- incremental/runtime/test-arkts/tests.ts | 2 +- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/incremental/runtime/arktsconfig-test-unmemoized.json b/incremental/runtime/arktsconfig-test-unmemoized.json index d09f771ec..b0c7acde9 100644 --- a/incremental/runtime/arktsconfig-test-unmemoized.json +++ b/incremental/runtime/arktsconfig-test-unmemoized.json @@ -15,7 +15,6 @@ "build/unmemoized/test-arkts/*.ts" ], "exclude": [ - "build/unmemoized/test-arkts/memo/repeat.test.ts", "build/unmemoized/test-arkts/states/state_basics.test.ts", "build/unmemoized/test-arkts/states/State.test.ts" ] diff --git a/incremental/runtime/test-arkts/memo/repeat.test.ts b/incremental/runtime/test-arkts/memo/repeat.test.ts index 07b543387..a7a07cb51 100644 --- a/incremental/runtime/test-arkts/memo/repeat.test.ts +++ b/incremental/runtime/test-arkts/memo/repeat.test.ts @@ -15,8 +15,7 @@ // TODO: the real chai exports 'assert', but 'assert' is still a keyword in ArkTS import { Assert, suite, test } from "../harness" -import { asArray, int32 } from "@koalaui/common" -import { UniqueId, KoalaCallsiteKey } from "@koalaui/common" +import { asArray, int32, KoalaCallsiteKey } from "@koalaui/common" import { GlobalStateManager, Repeat, @@ -31,13 +30,22 @@ import { } from "../../src" export const FileName = "memo/repeat.test" +// For tests we compute positional ids from strings. +export function key(name: string): KoalaCallsiteKey { + let key: KoalaCallsiteKey = 0 + for (let i = 0; i < name.length; i++) { + key = (key << 3) | (key >> 29) ^ (name[i] as int32) + } + return key +} + const collector = new Array() class Page { readonly id: KoalaCallsiteKey private readonly name: string constructor(name: string) { - this.id = parseInt(new UniqueId().addString(name).compute().slice(0, 10), 16) as KoalaCallsiteKey + this.id = key(name) this.name = name } /** @memo */ @@ -144,10 +152,10 @@ suite("repeat tests", () => { test("RepeatByArray.insert", () => { testInsert((array) => { - RepeatByArray( + RepeatByArray( array, - (element, _) => element.id, - (element, _) => { element.page() }) + (element: Page, _: int32) => element.id, + (element: Page, _: int32) => { element.page() }) }) }) @@ -157,8 +165,8 @@ suite("repeat tests", () => { 0, array.length as int32, (index: int32) => array[index], - (element, _) => element.id, - (element, _) => { element.page() }) + (element: Page, _: int32) => element.id, + (element: Page, _: int32) => { element.page() }) }) }) @@ -176,8 +184,8 @@ suite("repeat tests", () => { testRemove((array) => { RepeatByArray( array, - (element, _) => element.id, - (element, _) => { element.page() }) + (element: Page, _: int32) => element.id, + (element: Page, _: int32) => { element.page() }) }) }) @@ -187,8 +195,8 @@ suite("repeat tests", () => { 0, array.length as int32, (index: int32) => array[index], - (element, _) => element.id, - (element, _) => { element.page() }) + (element: Page, _: int32) => element.id, + (element: Page, _: int32) => { element.page() }) }) }) @@ -206,8 +214,8 @@ suite("repeat tests", () => { testSwap((array) => { RepeatByArray( array, - (element, _) => element.id, - (element, _) => { element.page() }) + (element: Page, _: int32) => element.id, + (element: Page, _: int32) => { element.page() }) }) }) @@ -217,8 +225,8 @@ suite("repeat tests", () => { 0, array.length as int32, (index: int32) => array[index], - (element, _) => element.id, - (element, _) => { element.page() }) + (element: Page, _: int32) => element.id, + (element: Page, _: int32) => { element.page() }) }) }) }) diff --git a/incremental/runtime/test-arkts/tests.ts b/incremental/runtime/test-arkts/tests.ts index 7063bfb7d..ddcbbef37 100644 --- a/incremental/runtime/test-arkts/tests.ts +++ b/incremental/runtime/test-arkts/tests.ts @@ -34,7 +34,7 @@ suite("harness", () => { console.log("register file:", changeListener) console.log("register file:", contextLocal) console.log("register file:", remember) - // console.log("register file:", repeat) + console.log("register file:", repeat) console.log("register file:", Journal) // console.log("register file:", state_basics) // console.log("register file:", State) -- Gitee From 336b4006631a57ac24d980c58d56194c45a7f139 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 31 Jan 2025 17:29:38 +0300 Subject: [PATCH 07/10] workaround for 20193 issue and similar Signed-off-by: Sergey Malenkov --- .../runtime/arktsconfig-test-unmemoized.json | 3 +- .../runtime/test-arkts/states/State.test.ts | 140 +++++++++--------- incremental/runtime/test-arkts/tests.ts | 2 +- 3 files changed, 72 insertions(+), 73 deletions(-) diff --git a/incremental/runtime/arktsconfig-test-unmemoized.json b/incremental/runtime/arktsconfig-test-unmemoized.json index b0c7acde9..963667073 100644 --- a/incremental/runtime/arktsconfig-test-unmemoized.json +++ b/incremental/runtime/arktsconfig-test-unmemoized.json @@ -15,7 +15,6 @@ "build/unmemoized/test-arkts/*.ts" ], "exclude": [ - "build/unmemoized/test-arkts/states/state_basics.test.ts", - "build/unmemoized/test-arkts/states/State.test.ts" + "build/unmemoized/test-arkts/states/state_basics.test.ts" ] } diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index 16c2c57b7..1d072c1e1 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -251,7 +251,7 @@ suite("State", () => { }) test("computable state depends on managed state", () => { let manager = createStateManager() - let name = manager.mutableState("NAME") + let name = manager.mutableState("NAME") // create computable state that tracks computing inner scopes let computing = new Array() let result = manager.computableState((context: StateContext) => { @@ -268,16 +268,16 @@ suite("State", () => { }) }) // initial computation - assertState(result, "<= NAME =>") + assertState(result, "<= NAME =>") assertStringsAndCleanup(computing, "main ; left ; name ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) - assertState(result, "<= NAME =>") + assertState(result, "<= NAME =>") Assert.isEmpty(computing) // compute state only when snapshot updated name.value = "Sergey Malenkov" Assert.equal(testUpdate(false, manager), 1) - assertModifiedState(result, "<= Sergey Malenkov =>") + assertModifiedState(result, "<= Sergey Malenkov =>") assertStringsAndCleanup(computing, "main ; name") }) test("computable state depends on named state managed globally", () => { @@ -300,16 +300,16 @@ suite("State", () => { }) }) // initial computation - assertState(result, "<= NAME =>") + assertState(result, "<= NAME =>") assertStringsAndCleanup(computing, "main ; left ; name ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) - assertState(result, "<= NAME =>") + assertState(result, "<= NAME =>") Assert.isEmpty(computing) // compute state only when snapshot updated manager.stateBy("global")!.value = "Sergey Malenkov" Assert.equal(testUpdate(false, manager), 1) - assertModifiedState(result, "<= Sergey Malenkov =>") + assertModifiedState(result, "<= Sergey Malenkov =>") assertStringsAndCleanup(computing, "main ; name") }) test("computable state depends on named state managed locally", () => { @@ -332,18 +332,18 @@ suite("State", () => { }) }) // initial computation - assertState(result, "<= 1 =>") + assertState(result, "<= 1 =>") assertStringsAndCleanup(computing, "main ; left ; name ; right") // computable state is not modified - assertState(result, "<= 1 =>") + assertState(result, "<= 1 =>") Assert.isEmpty(computing) // compute state only when snapshot updated Assert.equal(testUpdate(true, manager), 1) - assertModifiedState(result, "<= 2 =>") + assertModifiedState(result, "<= 2 =>") assertStringsAndCleanup(computing, "main ; name") // compute state on next snapshot update Assert.equal(testUpdate(true, manager), 1) - assertModifiedState(result, "<= 3 =>") + assertModifiedState(result, "<= 3 =>") assertStringsAndCleanup(computing, "main ; name") }) test("computable state depends on named state managed locally from managed inner scope", () => { @@ -366,18 +366,18 @@ suite("State", () => { }) }) // initial computation - assertState(result, "<= 1 =>") + assertState(result, "<= 1 =>") assertStringsAndCleanup(computing, "main ; left ; name ; right") // computable state is not modified - assertState(result, "<= 1 =>") + assertState(result, "<= 1 =>") Assert.isEmpty(computing) // compute state only when snapshot updated Assert.equal(testUpdate(true, manager), 1) - assertModifiedState(result, "<= 2 =>") + assertModifiedState(result, "<= 2 =>") assertStringsAndCleanup(computing, "main ; name") // compute state on next snapshot update Assert.equal(testUpdate(true, manager), 1) - assertModifiedState(result, "<= 3 =>") + assertModifiedState(result, "<= 3 =>") assertStringsAndCleanup(computing, "main ; name") }) test("computable state allows to cleanup disposed scopes", () => { @@ -484,7 +484,7 @@ suite("State", () => { }) test("do not allow to dispose global mutable state when creating global named state", () => { const manager = createStateManager() - const mutable = manager.mutableState("value") + const mutable = manager.mutableState("value") manager.namedState("prohibited", () => { Assert.throws(() => { mutable.dispose() }) return mutable.value @@ -492,7 +492,7 @@ suite("State", () => { }) test("do not allow to dispose global mutable state when creating local named state", () => { const manager = createStateManager() - const mutable = manager.mutableState("value") + const mutable = manager.mutableState("value") const state = manager.computableState((context: StateContext) => { context.namedState("prohibited", () => { Assert.throws(() => { mutable.dispose() }) @@ -528,7 +528,7 @@ suite("State", () => { }) test("do not allow to dispose global mutable state when updating computable state", () => { const manager = createStateManager() - const mutable = manager.mutableState("value") + const mutable = manager.mutableState("value") const state = manager.computableState((_: StateContext) => { Assert.throws(() => { mutable.dispose() }) return undefined @@ -589,17 +589,17 @@ suite("State", () => { }) test("computable state must not depend on managed state when creating another one", () => { let manager = createStateManager() - let mutable = manager.mutableState("NAME") + let mutable = manager.mutableState("NAME") let computable = manager.computableState((context: StateContext) => { context.namedState("name", () => mutable.value) return context.valueBy("name") }) // initial computation - assertState(computable, "NAME") + assertState(computable, "NAME") // do not update result when snapshot updated mutable.value = "Sergey Malenkov" Assert.equal(testUpdate(false, manager), 1) - assertState(computable, "NAME") + assertState(computable, "NAME") }) test("computable state from specific scope must be forgotten on dispose automatically", () => { const manager = createStateManager() @@ -707,29 +707,29 @@ suite("State", () => { const manager = createStateManager() const computable = manager.computableState((context: StateContext) => context.mutableState(0 as float64, true)) const globalState = computable.value - Assert.equal("GlobalState=0", globalState.toString()) + Assert.equal("GlobalState=0", globalState.toString()) globalState.value = 1 Assert.equal(testUpdate(false, manager), 1) - Assert.equal("GlobalState,modified=1", globalState.toString()) + Assert.equal("GlobalState,modified=1", globalState.toString()) Assert.equal(testUpdate(false, manager), 0) computable.dispose() - Assert.equal("GlobalState=1", globalState.toString()) + Assert.equal("GlobalState=1", globalState.toString()) globalState.dispose() - Assert.equal("GlobalState,disposed=1", globalState.toString()) + Assert.equal("GlobalState,disposed=1", globalState.toString()) }) test("create local mutable state in local context within remember", () => { const manager = createStateManager() const computable = manager.computableState((context: StateContext) => context.compute(0, () => context.mutableState(0 as float64, false), undefined, true)) const localState = computable.value - Assert.equal("LocalState=0", localState.toString()) + Assert.equal("LocalState=0", localState.toString()) localState.value = 1 Assert.equal(testUpdate(false, manager), 1) - Assert.equal("LocalState,modified=1", localState.toString()) + Assert.equal("LocalState,modified=1", localState.toString()) Assert.equal(testUpdate(false, manager), 0) computable.dispose() - Assert.equal("LocalState,disposed=1", localState.toString()) + Assert.equal("LocalState,disposed=1", localState.toString()) localState.dispose() - Assert.equal("LocalState,disposed=1", localState.toString()) + Assert.equal("LocalState,disposed=1", localState.toString()) }) test("create global named state in local context", () => { const manager = createStateManager() @@ -742,15 +742,15 @@ suite("State", () => { }) const globalState = computable.value Assert.equal(globalState, manager.stateBy("global")!) - Assert.equal("GlobalState(global)=0", globalState.toString()) + Assert.equal("GlobalState(global)=0", globalState.toString()) globalState.value = 1 Assert.equal(testUpdate(false, manager), 1) - Assert.equal("GlobalState(global),modified=1", globalState.toString()) + Assert.equal("GlobalState(global),modified=1", globalState.toString()) Assert.equal(testUpdate(false, manager), 0) computable.dispose() - Assert.equal("GlobalState(global)=1", globalState.toString()) + Assert.equal("GlobalState(global)=1", globalState.toString()) globalState.dispose() - Assert.equal("GlobalState(global),disposed=1", globalState.toString()) + Assert.equal("GlobalState(global),disposed=1", globalState.toString()) }) test("create local named state in local context", () => { const manager = createStateManager() @@ -767,15 +767,15 @@ suite("State", () => { }) const localState = computable.value Assert.isUndefined>(manager.stateBy("local")) - Assert.equal("LocalState(local)=0", localState.toString()) + Assert.equal("LocalState(local)=0", localState.toString()) localState.value = 1 Assert.equal(testUpdate(false, manager), 1) - Assert.equal("LocalState(local),modified=1", localState.toString()) + Assert.equal("LocalState(local),modified=1", localState.toString()) Assert.equal(testUpdate(false, manager), 0) computable.dispose() - Assert.equal("LocalState(local),disposed=1", localState.toString()) + Assert.equal("LocalState(local),disposed=1", localState.toString()) localState.dispose() - Assert.equal("LocalState(local),disposed=1", localState.toString()) + Assert.equal("LocalState(local),disposed=1", localState.toString()) }) test("prohibit to create local mutable state in global context", () => { Assert.throws(() => { createStateManager().mutableState(0, false) }) @@ -914,8 +914,8 @@ suite("State", () => { test("build and update simple tree", () => { let manager = createStateManager() let count = manager.mutableState(30) - let first = manager.mutableState("first node") - let second = manager.mutableState("second node") + let first = manager.mutableState("first node") + let second = manager.mutableState("second node") let computing = new Array() const rootNode = new TestNode() let firstNode: TestNode @@ -1366,7 +1366,7 @@ suite("ValueTracker", () => { suite("ArrayState", () => { test("managed array state supports #at getter", () => { const manager = createStateManager() - const array = manager.arrayState(["one", "two", "three"]) + const array = manager.arrayState(Array.of("one", "two", "three")) Assert.equal(array.length, 3) Assert.equal(array.at(0), "one") Assert.equal(array.at(1), "two") @@ -1378,10 +1378,10 @@ suite("ArrayState", () => { test("computable state depends on managed array state", () => { const manager = createStateManager() const state = manager.mutableState(1) - const array = manager.arrayState(["item"]) + const array = manager.arrayState(Array.of("item")) // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1399,7 +1399,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= 1: item =>") + assertState(result, "<= 1: item =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1430,10 +1430,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #copyWithin", () => { const manager = createStateManager() - const array = manager.arrayState(["one", "two", "three"]) + const array = manager.arrayState(Array.of("one", "two", "three")) // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1450,7 +1450,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= one two three =>") + assertState(result, "<= one two three =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1478,10 +1478,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #fill", () => { const manager = createStateManager() - const array = manager.arrayState(["one", "two", "three"]) + const array = manager.arrayState(Array.of("one", "two", "three")) // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1498,7 +1498,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= one two three =>") + assertState(result, "<= one two three =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1526,10 +1526,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #pop", () => { const manager = createStateManager() - const array = manager.arrayState(["first", "last"]) + const array = manager.arrayState(Array.of("first", "last")) // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1546,7 +1546,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= first last =>") + assertState(result, "<= first last =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1563,7 +1563,7 @@ suite("ArrayState", () => { Assert.equal(result.value, "<= =>") assertStringsAndCleanup(computing, "outer ; center ; inner") // compute state only when snapshot updated - Assert.isUndefined(array.pop()) + Assert.isUndefined(array.pop()) Assert.equal(testUpdate(false, manager), 0) Assert.equal(result.value, "<= =>") Assert.isEmpty(computing) @@ -1574,10 +1574,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #push", () => { const manager = createStateManager() - const array = manager.arrayState() + const array = manager.arrayState() // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1594,7 +1594,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= =>") + assertState(result, "<= =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1622,10 +1622,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #reverse", () => { const manager = createStateManager() - const array = manager.arrayState(["one", "two", "three"]) + const array = manager.arrayState(Array.of("one", "two", "three")) // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1642,7 +1642,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= one two three =>") + assertState(result, "<= one two three =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1660,10 +1660,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #shift", () => { const manager = createStateManager() - const array = manager.arrayState(["first", "last"]) + const array = manager.arrayState(Array.of("first", "last")) // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1680,7 +1680,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= first last =>") + assertState(result, "<= first last =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1697,7 +1697,7 @@ suite("ArrayState", () => { Assert.equal(result.value, "<= =>") assertStringsAndCleanup(computing, "outer ; center ; inner") // compute state only when snapshot updated - Assert.isUndefined(array.shift()) + Assert.isUndefined(array.shift()) Assert.equal(testUpdate(false, manager), 0) Assert.equal(result.value, "<= =>") Assert.isEmpty(computing) @@ -1708,10 +1708,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #sort", () => { const manager = createStateManager() - const array = manager.arrayState(["one", "two", "three"]) + const array = manager.arrayState(Array.of("one", "two", "three")) // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1728,7 +1728,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= one two three =>") + assertState(result, "<= one two three =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) @@ -1745,7 +1745,7 @@ suite("ArrayState", () => { Assert.equal(result.value, "<= one three two =>") Assert.isEmpty(computing) // compute state only when snapshot updated - array.sort((s1, s2) => s1.length < s2.length ? -1 : s1.length > s2.length ? 1 : s1.localeCompare(s2)) + array.sort((s1: string, s2: string) => s1.length < s2.length ? -1 : s1.length > s2.length ? 1 : s1.localeCompare(s2)) Assert.equal(testUpdate(false, manager), 1) Assert.equal(result.value, "<= one two three =>") assertStringsAndCleanup(computing, "outer ; center ; inner") @@ -1756,10 +1756,10 @@ suite("ArrayState", () => { }) test("computable state depends on managed array state #unshift", () => { const manager = createStateManager() - const array = manager.arrayState() + const array = manager.arrayState() // create computable state that tracks computing inner scopes const computing = new Array() - const result = manager.computableState((context) => { + const result = manager.computableState((context: StateContext) => { computing.push("outer") return context.compute(key("left"), () => { computing.push("left") @@ -1776,7 +1776,7 @@ suite("ArrayState", () => { }) }) // initial computation - assertState(result, "<= =>") + assertState(result, "<= =>") assertStringsAndCleanup(computing, "outer ; left ; center ; inner ; right") // computable state is not modified Assert.equal(testUpdate(false, manager), 0) diff --git a/incremental/runtime/test-arkts/tests.ts b/incremental/runtime/test-arkts/tests.ts index ddcbbef37..e865029d1 100644 --- a/incremental/runtime/test-arkts/tests.ts +++ b/incremental/runtime/test-arkts/tests.ts @@ -37,7 +37,7 @@ suite("harness", () => { console.log("register file:", repeat) console.log("register file:", Journal) // console.log("register file:", state_basics) - // console.log("register file:", State) + console.log("register file:", State) console.log("register file:", TreeNode) console.log("register file:", TreePath) }) -- Gitee From 914cc506a65176ac709335ed80eb18784572cde4 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 31 Jan 2025 17:34:40 +0300 Subject: [PATCH 08/10] comment out localeCompare Signed-off-by: Sergey Malenkov --- incremental/runtime/test-arkts/states/State.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index 1d072c1e1..a8bdc20c7 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -1744,6 +1744,7 @@ suite("ArrayState", () => { Assert.equal(testUpdate(false, manager), 0) Assert.equal(result.value, "<= one three two =>") Assert.isEmpty(computing) +/* TODO: [TID 00edbb] F/ets: Failed to create the collator for en (US) // compute state only when snapshot updated array.sort((s1: string, s2: string) => s1.length < s2.length ? -1 : s1.length > s2.length ? 1 : s1.localeCompare(s2)) Assert.equal(testUpdate(false, manager), 1) @@ -1753,6 +1754,7 @@ suite("ArrayState", () => { Assert.equal(testUpdate(false, manager), 0) Assert.equal(result.value, "<= one two three =>") Assert.isEmpty(computing) +*/ }) test("computable state depends on managed array state #unshift", () => { const manager = createStateManager() -- Gitee From 2c8de4e980366bb29b485b3b8984738947437c15 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 3 Feb 2025 14:37:14 +0300 Subject: [PATCH 09/10] two failed tests have to correspond original ones Signed-off-by: Sergey Malenkov --- incremental/runtime/test-arkts/states/State.test.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index a8bdc20c7..edc732f72 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -1266,7 +1266,7 @@ suite("Equivalent", () => { assertState(state, equal) Assert.notEqual(state.value, age16) }) - test("frozen state is not modified if values are equivalent, but returns old value", () => { + test("frozen state is not modified if values are equivalent, but returns new value", () => { const manager = createStateManager() manager.frozen = true // NB! const state = manager.mutableState(age16, undefined, Data.equivalent) @@ -1276,8 +1276,8 @@ suite("Equivalent", () => { Assert.isTrue(Data.equivalent(equal, age16)) state.value = equal Assert.equal(testUpdate(false, manager), 0) - assertState(state, age16) - Assert.notEqual(state.value, equal) + assertState(state, equal) + Assert.notEqual(state.value, age16) }) test("state is not modified if the equivalent value is set, but returns new value", () => { const manager = createStateManager() @@ -1290,16 +1290,17 @@ suite("Equivalent", () => { Assert.equal(testUpdate(false, manager), 0) assertState(state, value) }) - test("frozen state is not modified if the equivalent value is set, but returns old value", () => { + test("frozen state is not modified if the equivalent value is set, but returns new value", () => { const manager = createStateManager() manager.frozen = true // NB! const state = manager.mutableState(age16, undefined, Data.equivalent) assertState(state, age16) + let value = age16 for (let age = 0; age <= 16; age++) { - state.value = new Data("age", age) + state.value = value = new Data("age", age) } Assert.equal(testUpdate(false, manager), 0) - assertState(state, age16) + assertState(state, value) }) }) -- Gitee From 89779c6b60f272a5923539b19aeff69a8ade7496 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 3 Feb 2025 16:04:42 +0300 Subject: [PATCH 10/10] workaround for issue with ArkTS optimization Signed-off-by: Sergey Malenkov --- incremental/runtime/test-arkts/states/State.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/incremental/runtime/test-arkts/states/State.test.ts b/incremental/runtime/test-arkts/states/State.test.ts index edc732f72..ee1c54c19 100644 --- a/incremental/runtime/test-arkts/states/State.test.ts +++ b/incremental/runtime/test-arkts/states/State.test.ts @@ -863,7 +863,8 @@ suite("State", () => { let computableCounter = 0 const computable = manager.computableState((_: StateContext) => { computableCounter++ - return mutable.value && false + const value = mutable.value + return value && false }) let stateCounter = 0 const state = manager.computableState((_: StateContext) => { @@ -895,7 +896,8 @@ suite("State", () => { let stateCounter = 0 const state = manager.computableState((_: StateContext) => { stateCounter++ - return computable.value && false + const value = computable.value + return value && false }) Assert.equal(testUpdate(false, manager), 0) Assert.equal(computableCounter, 0) // computable is not recomputed -- Gitee