1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/*
17 * @tc.name:sendablemap
18 * @tc.desc:test sendablemap
19 * @tc.type: FUNC
20 * @tc.require: issue#I93TZC
21 */
22
23// @ts-nocheck
24declare function print(str: any): string;
25
26function FillMap(map: SendableMap): void {
27  for (let i = 0; i < 5; i++) {
28    map.set(i, 'value' + i);
29  }
30}
31let sharedMap: SendableMap = new SendableMap<number, string>();
32
33// Basic tests
34print("===Basic test begin===")
35FillMap(sharedMap);
36print("map size is " + sharedMap.size);
37print(SendableMap[Symbol.species] == SendableMap);
38print(SendableMap.name == 'SendableMap');
39print(SendableMap[Symbol.species] == Map);
40
41const keyIter = sharedMap.keys();
42let nextEntry = keyIter.next();
43print("keys next:" + nextEntry.value + ", done: " + nextEntry.done);
44nextEntry = keyIter.next();
45print("keys next:" + nextEntry.value + ", done: " + nextEntry.done);
46nextEntry = keyIter.next();
47print("keys next:" + nextEntry.value + ", done: " + nextEntry.done);
48nextEntry = keyIter.next();
49print("keys next:" + nextEntry.value + ", done: " + nextEntry.done);
50nextEntry = keyIter.next();
51print("keys next:" + nextEntry.value + ", done: " + nextEntry.done);
52nextEntry = keyIter.next();
53print("keys next:" + nextEntry.value + ", done: " + nextEntry.done);
54
55const valueIter = sharedMap.values();
56nextEntry = valueIter.next();
57print("values next:" + nextEntry.value + ", done: " + nextEntry.done);
58nextEntry = valueIter.next();
59print("values next:" + nextEntry.value + ", done: " + nextEntry.done);
60nextEntry = valueIter.next();
61print("values next:" + nextEntry.value + ", done: " + nextEntry.done);
62nextEntry = valueIter.next();
63print("values next:" + nextEntry.value + ", done: " + nextEntry.done);
64nextEntry = valueIter.next();
65print("values next:" + nextEntry.value + ", done: " + nextEntry.done);
66nextEntry = valueIter.next();
67print("values next:" + nextEntry.value + ", done: " + nextEntry.done);
68
69sharedMap.forEach((value: string, key: number, map: SendableMap) => {
70  print('map key[forEach]:' + 'key:' + key + ', value:' + value);
71});
72
73print(sharedMap[Symbol.toStringTag] == 'SendableMap');
74for (let iter of sharedMap[Symbol.iterator]()) {
75  print("map key[Symbol.iterator]:" + iter);
76}
77for (let [key, value] of sharedMap.entries()) {
78  print("map entries:[" + key +", " + value + "]");
79}
80print(sharedMap[Symbol.iterator] == sharedMap.entries);
81print(sharedMap[Symbol.iterator] == sharedMap.keys);
82print(sharedMap[Symbol.iterator] == sharedMap.values);
83
84print(sharedMap.has(4));
85sharedMap.set(4, "value4");
86print(sharedMap.size == 5);
87print(sharedMap.has(10));
88sharedMap.set(10, "value10");
89print(sharedMap.get(10) == "value10");
90print(sharedMap.size == 6);
91print(sharedMap.has(10));
92sharedMap.delete(10);
93print(sharedMap.has(10));
94print(sharedMap.size == 5);
95sharedMap.clear();
96print(sharedMap.size == 0);
97print("===Basic test end===");
98
99// No expected Concurrent modification exception while iterating using iterators
100print("===Concurrent modification during iteration Test(iterator) begin===")
101sharedMap.clear();
102FillMap(sharedMap);
103print("map size is " + sharedMap.size);
104
105const iterator = sharedMap.entries();
106for (const [key, _] of iterator) {
107  print("map key[for-of]: " + key);
108}
109try {
110  const iterator = sharedMap.entries();
111  for (const [key, _] of iterator) {
112    if (key == 1) {
113      sharedMap.set(key + 5, "value" + key + 5);
114    }
115  }
116  print("Set Scenario[for-of] updated size: " + sharedMap.size);
117} catch (e) {
118  print("Set Scenario[for-of]: " + e);
119}
120try {
121  const iterator = sharedMap.entries();
122  for (const [key, _] of iterator) {
123    if (key % 2 == 0) {
124      sharedMap.delete(key);
125    }
126  }
127  print("Delete Scenario[for-of] updated size: " + sharedMap.size);
128} catch (e) {
129  print("Delete Scenario[for-of]: " + e);
130}
131try {
132  const iterator = sharedMap.entries();
133  for (const [key, _] of iterator) {
134    sharedMap.clear();
135  }
136  print("Clear Scenario[for-of] updated size: " + sharedMap.size);
137} catch (e) {
138  print("Clear Scenario[for-of]: " + e);
139}
140
141sharedMap.clear();
142FillMap(sharedMap);
143print("map size is " + sharedMap.size);
144try {
145  const iterator = sharedMap.entries();
146  sharedMap.set(6, "value6");
147  iterator.next();
148  print("Set Scenario[next()] updated size: " + sharedMap.size);
149} catch (e) {
150  print("Set Scenario[next()]: " + e);
151}
152try {
153  const iterator = sharedMap.entries();
154  sharedMap.delete(6);
155  iterator.next();
156  print("Delete Scenario[next()] updated size: " + sharedMap.size);
157} catch (e) {
158  print("Delete Scenario[next()]: " + e);
159}
160try {
161  const iterator = sharedMap.entries();
162  sharedMap.clear();
163  iterator.next();
164  print("Clear Scenario[next()] updated size: " + sharedMap.size);
165} catch (e) {
166  print("Clear Scenario[next()]: " + e);
167}
168print("===Concurrent modification during iteration Test(iterator) end===")
169
170// Expected Concurrent modification exception while iterating using forEach
171print("===Concurrent modification during iteration Test(forEach) begin===")
172sharedMap.clear();
173FillMap(sharedMap);
174print("map size is " + sharedMap.size);
175sharedMap.forEach((_: string, key: number, map: SendableMap) => {
176  print('map key[forEach]: ' + key);
177});
178try {
179  sharedMap.forEach((_: string, key: number, map: SendableMap) => {
180    map.set(key + 5, 'value' + key + 5);
181  });
182} catch (e) {
183  print("Set Scenario[forEach]: " + e + ", errCode: " + e.code);
184}
185try {
186  sharedMap.forEach((_: string, key: number, map: SendableMap) => {
187    if (key % 2 == 0) {
188      map.delete(key);
189    }
190  });
191} catch (e) {
192  print("Delete Scenario[forEach]: " + e + ", errCode: " + e.code);
193}
194try {
195  sharedMap.forEach((_: string, key: number, map: SendableMap) => {
196    map.clear();
197  });
198} catch (e) {
199  print("Clear Scenario[forEach]: " + e + ", errCode: " + e.code);
200}
201print("===Concurrent modification during iteration Test(forEach) end===");
202
203print("===Type check begin===");
204class SObject {
205  constructor() {
206    "use sendable"
207  }
208};
209
210try {
211  let sObj = new SObject();
212  sharedMap = new SendableMap([
213    ['str', 1],
214    [sObj, undefined],
215    [true, null],
216  ]);
217  print("sharedMap set[shared] element success");
218} catch (e) {
219  print("sharedMap set[unshared]: " + e + ", errCode: " + e.code);
220}
221
222try {
223  let obj = {}
224  sharedMap = new SendableMap([
225    ['str', 1],
226    [obj, 2],
227  ]);
228} catch (e) {
229  print("sharedMap set[unshared]: " + e + ", errCode: " + e.code);
230}
231
232try {
233  let sym = Symbol("testSymbol")
234  sharedMap = new SendableMap([
235    ['str', 1],
236    [sym, 2],
237  ]);
238} catch (e) {
239  print("sharedMap set[unshared]: " + e + ", errCode: " + e.code);
240}
241print("===Type check end===");
242
243print("===Class inheritance test begin ===");
244class SubSendableMap<K, V> extends SendableMap {
245  desc: string = "I'am SubSendableMap";
246  constructor(entries?: [K, V][] | null) {
247    'use sendable';
248    super(entries);
249  }
250}
251
252let subSendableMap = new SubSendableMap<number, string>();
253subSendableMap.set(1, 'one');
254print(subSendableMap.has(1));
255print(subSendableMap.size);
256
257try {
258  subSendableMap['extension'] = 'value';
259} catch(e) {
260  print("add extension(.): " + e);
261}
262try {
263  subSendableMap.extension = 'value';
264} catch(e) {
265  print("add extension([]): " + e);
266}
267
268try {
269  let obj = {};
270  subSendableMap = new SubSendableMap<string, Object>([['object', obj]]);
271  print(subSendableMap.size);
272} catch (e) {
273  print('SubSendableMap set[unshared]: ' + e + ', errCode: ' + e.code);
274}
275
276subSendableMap = new SubSendableMap<number, string>([
277  [1, 'one'],
278  [2, 'two'],
279  [3, 'three'],
280]);
281print(subSendableMap.size);
282for (const [key, value] of subSendableMap.entries()) {
283  print('SubSendableMap [key, value][for-of]: ' + '[' + key + ', ' + value + ']');
284}
285
286try {
287  subSendableMap.forEach((value: string, key: number, map: SubSendableMap) => {
288    if (key % 2 == 0) {
289      map.delete(key);
290    }
291  });
292} catch (e) {
293  print('SubSendableMap Delete Scenario[forEach]: ' + e + ', errCode: ' + e.code);
294}
295
296class SubSubSendableMap<K, V> extends SubSendableMap {
297  constructor(entries?: [K, V][] | null) {
298    'use sendable';
299    super(entries);
300  }
301}
302
303let subSubSendableMap = new SubSubSendableMap<number, string>();
304subSubSendableMap.set(1, 'one');
305print(subSubSendableMap.has(1));
306print(subSubSendableMap.size);
307
308try {
309  let obj = {};
310  subSubSendableMap = new SubSubSendableMap<string, Object>([['object', obj]]);
311  print(subSubSendableMap.size);
312} catch (e) {
313  print('SubSubSendableMap set[unshared]: ' + e + ', errCode: ' + e.code);
314}
315
316subSubSendableMap = new SubSubSendableMap<number, string>([
317  [1, 'one'],
318  [2, 'two'],
319  [3, 'three'],
320]);
321print(subSendableMap.size);
322for (const [key, value] of subSendableMap.entries()) {
323  print('SubSubSendableMap [key, value][for-of]: ' + '[' + key + ', ' + value + ']');
324}
325
326try {
327  subSubSendableMap.forEach((value: string, key: number, map: SubSubSendableMap) => {
328    if (key % 2 == 0) {
329      map.delete(key);
330    }
331  });
332} catch (e) {
333  print('SubSubSendableMap Delete Scenario[forEach]: ' + e + ', errCode: ' + e.code);
334}
335
336print("=== An iterable object to convert to an ArkTS Map begin===")
337sharedMap.clear();
338FillMap(sharedMap);
339print("map size is " + sharedMap.size);
340try {
341  const iterator = sharedMap.entries();
342  let sharedMap1: SendableMap = new SendableMap(iterator);
343  sharedMap1.forEach((value: string, key: number, map: SendableMap) => {
344    print("map key[forEach]:" + "key:" + key + ", value:" + value);
345  });
346} catch (e) {
347  print("SendableMapConstructor Scenario[next()]: " + e);
348}
349
350print("===Class inheritance test end ===");
351