From 32a33b485bd61bc01114761466df21c12a19dff9 Mon Sep 17 00:00:00 2001 From: sokolovairina Date: Wed, 21 May 2025 17:27:57 +0300 Subject: [PATCH 1/5] Prop Set and Map tests --- ets-tests/ets/AllPages.ets | 4 ++ ets-tests/ets/pages/props/PropMapTest.ets | 44 ++++++++++++++++++++++ ets-tests/ets/pages/props/PropSetTest.ets | 45 +++++++++++++++++++++++ ets-tests/ets/suites/PropDecorator.ets | 40 +++++++++++++++++++- 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 ets-tests/ets/pages/props/PropMapTest.ets create mode 100644 ets-tests/ets/pages/props/PropSetTest.ets diff --git a/ets-tests/ets/AllPages.ets b/ets-tests/ets/AllPages.ets index 8c84eaa20..3f7ab954a 100644 --- a/ets-tests/ets/AllPages.ets +++ b/ets-tests/ets/AllPages.ets @@ -37,6 +37,8 @@ import { PropMutateTest } from "./pages/props/PropMutateTest" import { PropStringTest } from "./pages/props/PropStringTest" import { PropBoolTest } from "./pages/props/PropBoolTest" import { PropLocalInitTest } from "./pages/props/PropLocalInitTest" +import { PropSetTest } from "./pages/props/PropSetTest" +import { PropMapTest } from "./pages/props/PropMapTest" import { ProvideConsumeBaseTest } from "./pages/provide/ProvideConsumeBaseTest" import { ProvideConsumeObject } from "./pages/provide/ProvideConsumeObject" import { ProvideConsumeChildTest } from "./pages/provide/ProvideConsumeChildTest" @@ -88,6 +90,8 @@ function pageByName(name: string): void { case "PropStringTest": PropStringTest(); break case "PropBoolTest": PropBoolTest(); break case "PropLocalInitTest": PropLocalInitTest(); break + case "PropSetTest": PropSetTest(); break + case "PropMapTest": PropMapTest(); break case "ProvideConsumeBaseTest": ProvideConsumeBaseTest(); break case "ProvideConsumeObject": ProvideConsumeObject(); break case "ProvideConsumeChildTest": ProvideConsumeChildTest(); break diff --git a/ets-tests/ets/pages/props/PropMapTest.ets b/ets-tests/ets/pages/props/PropMapTest.ets new file mode 100644 index 000000000..7a13f9ff8 --- /dev/null +++ b/ets-tests/ets/pages/props/PropMapTest.ets @@ -0,0 +1,44 @@ +/* + * 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. + */ + +@Component +export struct MapChild { + @Prop items: Map + + build() { + this.items.delete("a") + TestComponent().log(`child map: ${JSON.stringify(Array.from(this.items.entries()))}`) + } +} + +@Entry +@Component +export struct PropMapTest { + @State items: Map = new Map([["a", 1]]) + + build() { + TestComponent({ id: 402 }).onChange(() => { + const updated = new Map(this.items) + updated.set("b", 2) + this.items = updated + }) + + TestComponent().log(`Parent sees: ${JSON.stringify(Array.from(this.items.entries()))}`) + + MapChild({ items: this.items }) + + TestComponent().log(`Parent sees: ${JSON.stringify(Array.from(this.items.entries()))}`) + } +} diff --git a/ets-tests/ets/pages/props/PropSetTest.ets b/ets-tests/ets/pages/props/PropSetTest.ets new file mode 100644 index 000000000..9319b5915 --- /dev/null +++ b/ets-tests/ets/pages/props/PropSetTest.ets @@ -0,0 +1,45 @@ +/* + * 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. + */ + +@Component +export struct SetChild { + @Prop items: Set + + build() { + this.items.delete("a") + TestComponent().log(`child set: ${JSON.stringify(Array.from(this.items))}`) + } +} + +@Entry +@Component +export struct PropSetTest { + @State items: Set = new Set(["a"]) + + build() { + TestComponent({ id: 403 }) + .onChange(() => { + const updated = new Set(this.items) + updated.add("b") + this.items = updated + }) + + TestComponent().log(`Parent sees: ${JSON.stringify(Array.from(this.items))}`) + + SetChild({ items: this.items }) + + TestComponent().log(`Parent sees: ${JSON.stringify(Array.from(this.items))}`) + } +} diff --git a/ets-tests/ets/suites/PropDecorator.ets b/ets-tests/ets/suites/PropDecorator.ets index 11abf2f47..96295f194 100644 --- a/ets-tests/ets/suites/PropDecorator.ets +++ b/ets-tests/ets/suites/PropDecorator.ets @@ -103,11 +103,49 @@ export function propDecoratorBehaviorTest(control: AppControl) { as this may override parent-provided values depending on the runtime. The correct approach is to omit the default entirely or set fallback in `aboutToAppear()`. */ - test("Parent overrides child's local default", () => { + test.expectFailure("Parent overrides child's local default", () => { testPageOnLoad(control, "PropLocalInitTest", "child.value = 10\n", "Child's local default was not overridden by parent @Prop") }) + + /* + Set mutation: parent vs. child + + Verifies: + - Parent adds to a Set and child sees the new element. + - Child deletes an element — and this affects the parent (unexpected). + + Example: PropSetTest + */ + test.expectFailure("Set: parent add() works, child delete() not", () => { + testPageOnChange(control, "PropSetTest", 403, + 'Parent sees: ["a"]\n' + + 'parent set: ["a","b"]\n' + + 'Parent sees: ["a","b"]\n' + + 'child set: ["b"]\n' + + 'Parent sees: ["a","b"]\n', + "@Prop Set was mutated by child, violating one-way data flow") + }) + + /* + Map mutation: parent vs. child + + Verifies: + - Parent can add to a Map and child sees the update. + - Child attempts to delete a key — this must NOT affect the parent's state. + + Example: PropMapTest + */ + test.expectFailure("Map: parent set() works, child delete() not", () => { + testPageOnChange(control, "PropMapTest", 402, + 'Parent sees: [["a",1]]\n' + + 'parent map: [["a",1],["b",2]]\n' + + 'Parent sees: [["a",1],["b",2]]\n' + + 'child map: [["b",2]]\n' + + 'Parent sees: [["a",1],["b",2]]\n', + "@Prop Map was mutated by child, violating one-way data flow") + }) }) } -- Gitee From d2c7438d8e345734d0955c746c94a57a835c774d Mon Sep 17 00:00:00 2001 From: Sokolova Irina Date: Wed, 21 May 2025 14:32:21 +0000 Subject: [PATCH 2/5] update ets-tests/ets/suites/PropDecorator.ets. Signed-off-by: Sokolova Irina --- ets-tests/ets/suites/PropDecorator.ets | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ets-tests/ets/suites/PropDecorator.ets b/ets-tests/ets/suites/PropDecorator.ets index 86ec18286..90b23de14 100644 --- a/ets-tests/ets/suites/PropDecorator.ets +++ b/ets-tests/ets/suites/PropDecorator.ets @@ -102,12 +102,13 @@ export function propDecoratorBehaviorTest(control: AppControl) { as this may override parent-provided values depending on the runtime. The correct approach is to omit the default entirely or set fallback in `aboutToAppear()`. */ - test.expectFailure("Parent overrides child's local default", () => { + test("Parent overrides child's local default", () => { testPageOnLoad(control, "PropLocalInitTest", "child.value = 10\n", "Child's local default was not overridden by parent @Prop") }) - + + /* Array mutation from parent vs. child Verifies: -- Gitee From 178414fc654af8001fa2267610327e0b81ed52eb Mon Sep 17 00:00:00 2001 From: Sokolova Irina Date: Wed, 21 May 2025 15:21:50 +0000 Subject: [PATCH 3/5] update ets-tests/ets/pages/props/PropSetTest.ets. Signed-off-by: Sokolova Irina --- ets-tests/ets/pages/props/PropSetTest.ets | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ets-tests/ets/pages/props/PropSetTest.ets b/ets-tests/ets/pages/props/PropSetTest.ets index 9319b5915..49d45deb8 100644 --- a/ets-tests/ets/pages/props/PropSetTest.ets +++ b/ets-tests/ets/pages/props/PropSetTest.ets @@ -18,7 +18,9 @@ export struct SetChild { @Prop items: Set build() { - this.items.delete("a") + TestComponent({ id: 402 }).onChange(() => { + this.items.delete("a") + }) TestComponent().log(`child set: ${JSON.stringify(Array.from(this.items))}`) } } @@ -29,7 +31,7 @@ export struct PropSetTest { @State items: Set = new Set(["a"]) build() { - TestComponent({ id: 403 }) + TestComponent({ id: 402 }) .onChange(() => { const updated = new Set(this.items) updated.add("b") -- Gitee From c2e78c21a34458b4d9cf96e436a52126ae8afc9d Mon Sep 17 00:00:00 2001 From: Sokolova Irina Date: Wed, 21 May 2025 15:22:18 +0000 Subject: [PATCH 4/5] update ets-tests/ets/pages/props/PropMapTest.ets. Signed-off-by: Sokolova Irina --- ets-tests/ets/pages/props/PropMapTest.ets | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ets-tests/ets/pages/props/PropMapTest.ets b/ets-tests/ets/pages/props/PropMapTest.ets index 7a13f9ff8..6ba5caf75 100644 --- a/ets-tests/ets/pages/props/PropMapTest.ets +++ b/ets-tests/ets/pages/props/PropMapTest.ets @@ -18,7 +18,9 @@ export struct MapChild { @Prop items: Map build() { - this.items.delete("a") + TestComponent({ id: 405 }).onChange(() => { + this.items.delete("a") + }) TestComponent().log(`child map: ${JSON.stringify(Array.from(this.items.entries()))}`) } } @@ -29,7 +31,7 @@ export struct PropMapTest { @State items: Map = new Map([["a", 1]]) build() { - TestComponent({ id: 402 }).onChange(() => { + TestComponent({ id: 404 }).onChange(() => { const updated = new Map(this.items) updated.set("b", 2) this.items = updated -- Gitee From f05d5684d4d1304837987d064f02f36366a9284b Mon Sep 17 00:00:00 2001 From: Sokolova Irina Date: Wed, 21 May 2025 15:23:31 +0000 Subject: [PATCH 5/5] update ets-tests/ets/suites/PropDecorator.ets. Signed-off-by: Sokolova Irina --- ets-tests/ets/suites/PropDecorator.ets | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ets-tests/ets/suites/PropDecorator.ets b/ets-tests/ets/suites/PropDecorator.ets index 90b23de14..4fb586833 100644 --- a/ets-tests/ets/suites/PropDecorator.ets +++ b/ets-tests/ets/suites/PropDecorator.ets @@ -145,6 +145,7 @@ export function propDecoratorBehaviorTest(control: AppControl) { "Parent sees: Sat Jan 02 1999\n", "@Prop Date was mutated by child, violating one-way data flow") }) + /* Set mutation: parent vs. child @@ -155,7 +156,7 @@ export function propDecoratorBehaviorTest(control: AppControl) { Example: PropSetTest */ test.expectFailure("Set: parent add() works, child delete() not", () => { - testPageOnChange(control, "PropSetTest", 403, + testPageOnChange(control, "PropSetTest", [402, 403], 'Parent sees: ["a"]\n' + 'parent set: ["a","b"]\n' + 'Parent sees: ["a","b"]\n' + @@ -174,7 +175,7 @@ export function propDecoratorBehaviorTest(control: AppControl) { Example: PropMapTest */ test.expectFailure("Map: parent set() works, child delete() not", () => { - testPageOnChange(control, "PropMapTest", 402, + testPageOnChange(control, "PropMapTest", [404, 405], 'Parent sees: [["a",1]]\n' + 'parent map: [["a",1],["b",2]]\n' + 'Parent sees: [["a",1],["b",2]]\n' + -- Gitee