diff --git a/ets-tests/ets/pages/links/LinkCollectionBindingTest.ets b/ets-tests/ets/pages/links/LinkCollectionBindingTest.ets new file mode 100644 index 0000000000000000000000000000000000000000..10407b43fa5e8aa94db59382307f695bb3dece86 --- /dev/null +++ b/ets-tests/ets/pages/links/LinkCollectionBindingTest.ets @@ -0,0 +1,118 @@ +/* + * Copyright (c) 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. + * + * Verify that Map and Set collections can be modified and read through + * the @Link decorator (API 11+ behaviour). + */ + + +@Entry +@Component +struct LinkCollectionBindingTest { + @State mapData: Map = new Map([[1, 'one'], [2, 'two']]); + @State setData: Set = new Set([1, 2, 3]); + @State parentSetLog: string = ''; + + build() { + Column() { + // ===== MAP tests ===================================================== + TestComponent({ id: 710 }) // parent mutates Map by adding/updating + .onChange(() => { + if (!this.mapData.has(3)) { + this.mapData.set(3, 'three'); + } else if (this.mapData.has(1)) { + this.mapData.delete(1); + } else { + this.mapData.clear(); + } + }) + + TestComponent().log(`Parent map size = ${this.mapData.size}`) + for (let entry of this.mapData.entries()) { + TestComponent().log(`Parent map entry = ${entry[0]}, ${entry[1]}`) + } + + // ===== SET tests ====================================================== + TestComponent({ id: 720 }) // parent mutates Set + .onChange(() => { + if (!this.setData.has(4)) { + this.setData.add(4); + this.parentSetLog = `Parent set value = 4`; + } else if (this.setData.has(2)) { + this.setData.delete(2); + } else { + this.setData.clear(); + } + }) + + TestComponent().log(this.parentSetLog) + TestComponent().log(`Parent set size = ${this.setData.size}`) + + for (let value of this.setData.values()) { + TestComponent().log(`Parent set value = ${value}`) + } + + // Pass state down as @Link so child can both read and mutate + MapChildComponent({ mapData: $mapData }) + SetChildComponent({ setData: $setData }) + } + .height('100%') + } +} + +@Component +struct MapChildComponent { + @Link mapData: Map; + + build() { + Column() { + TestComponent().log(`Child map size = ${this.mapData.size}`) + for (let entry of this.mapData.entries()) { + TestComponent().log(`Child map entry = ${entry[0]}, ${entry[1]}`) + } + + // Child mutates Map to verify upward propagation + TestComponent({ id: 711 }) + .onChange(() => { + this.mapData.set(99, 'child'); + }) + } + .width('100%') + } +} + +@Component +struct SetChildComponent { + @Link setData: Set; + @State childSetLog: string = ''; + + build() { + Column() { + TestComponent().log(`Child set size = ${this.setData.size}`) + for (let value of this.setData.values()) { + TestComponent().log(`Child set value = ${value}`) + } + + // Child mutates Set to verify upward propagation + TestComponent({ id: 721 }) + .onChange(() => { + this.setData.add(99); + this.childSetLog = `Child set value = 99`; + }) + + TestComponent().log(this.childSetLog) + } + .width('100%') + } +} diff --git a/ets-tests/src/Page.ts b/ets-tests/src/Page.ts index d474596a9eb093636381c50ec6987e927524bfe8..9db05d059b23792f321108a120db9420e79d1b26 100644 --- a/ets-tests/src/Page.ts +++ b/ets-tests/src/Page.ts @@ -48,6 +48,7 @@ import { DateSyncTest } from "../build/generated/pages/links/DateSyncTest" import { LinkUnionStringNullTest } from "../build/generated/pages/links/LinkUnionStringNullTest" import { DeepLinkPropagationTest } from "../build/generated/pages/links/DeepLinkPropagationTest" import { LinkArrayBindingTest } from "../build/generated/pages/links/LinkArrayBindingTest" +import { LinkCollectionBindingTest } from "../build/generated/pages/links/LinkCollectionBindingTest" const cases: Map = new Map() .set("StartPage", StartPage) @@ -85,6 +86,7 @@ const cases: Map = new Map() .set("LinkUnionStringNullTest", LinkUnionStringNullTest) .set("DeepLinkPropagationTest", DeepLinkPropagationTest) .set("LinkArrayBindingTest", LinkArrayBindingTest) + .set("LinkCollectionBindingTest", LinkCollectionBindingTest) export class EtsHarness extends UserView { private params: String diff --git a/ets-tests/src/suites/LinkDecorator.ts b/ets-tests/src/suites/LinkDecorator.ts index 0dc1a63da9c32f393b3f355ff517bc317b49a259..a9b4276efccb04833deaeb9c2d310cf89dd2edad 100644 --- a/ets-tests/src/suites/LinkDecorator.ts +++ b/ets-tests/src/suites/LinkDecorator.ts @@ -195,5 +195,37 @@ export function linkDecoratorBehaviorTest(control: AppControl) { "Array binding did not synchronize correctly between parent and child" ) }) + + /* + Map and Set collection binding: parent ⇄ child + + Verifies that Map and Set collections passed via @Link maintain synchronization, + and both parent and child can reflect and modify shared data properly. + + Example: LinkCollectionBindingTest + + - Parent mutates Map and Set using onChange (IDs: 710, 720) + - Child mutates Map and Set using onChange (IDs: 711, 721) + - Both directions must reflect changes + */ + test("Map and Set collection binding synchronization", () => { + const actualLog = control + .start() + .loadPage("LinkCollectionBindingTest") + .emitTask(TaskType.OnChange, 710).nextFrame() // parent adds to map + .emitTask(TaskType.OnChange, 710).nextFrame() // parent deletes from map + .emitTask(TaskType.OnChange, 711).nextFrame() // child adds to map + .emitTask(TaskType.OnChange, 720).nextFrame() // parent adds to set + .emitTask(TaskType.OnChange, 720).nextFrame() // parent deletes from set + .emitTask(TaskType.OnChange, 721).nextFrame() // child adds to set + .stop() + .getLog() + + console.log('actualLog:', actualLog) + Assert.equal(actualLog.includes("Parent map size ="), true) + Assert.equal(actualLog.includes("Child map entry = 99, child"), true) + Assert.equal(actualLog.includes("Parent set value = 4"), true) + Assert.equal(actualLog.includes("Child set value = 99"), true) + }) }) -} +} \ No newline at end of file