• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/builtins/builtins_boolean.h"
17 #include "ecmascript/builtins/builtins_function.h"
18 #include "ecmascript/builtins/builtins_shared_async_function.h"
19 #include "ecmascript/builtins/builtins_shared_function.h"
20 
21 #include "ecmascript/ecma_runtime_call_info.h"
22 #include "ecmascript/ecma_string.h"
23 #include "ecmascript/ecma_vm.h"
24 #include "ecmascript/global_env.h"
25 #include "ecmascript/js_array.h"
26 #include "ecmascript/js_function.h"
27 #include "ecmascript/js_object-inl.h"
28 
29 #include "ecmascript/object_factory.h"
30 #include "ecmascript/tagged_array-inl.h"
31 #include "ecmascript/tests/test_helper.h"
32 
33 using namespace panda::ecmascript;
34 using namespace panda::ecmascript::builtins;
35 using BuiltinsBase = panda::ecmascript::base::BuiltinsBase;
36 using JSArray = panda::ecmascript::JSArray;
37 
38 namespace panda::test {
39 class BuiltinsSharedFunctionTest : public BaseTestWithScope<false> {
40 };
41 
42 // native function for test apply and call
TestFunctionApplyAndCall(EcmaRuntimeCallInfo * argv)43 JSTaggedValue TestFunctionApplyAndCall(EcmaRuntimeCallInfo *argv)
44 {
45     JSThread *thread = argv->GetThread();
46     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
47 
48     int result = 0;
49     for (uint32_t index = 0; index < argv->GetArgsNumber(); ++index) {
50         result += BuiltinsBase::GetCallArg(argv, index)->GetInt();
51     }
52     JSHandle<JSTaggedValue> thisValue(BuiltinsBase::GetThis(argv));
53 
54     JSTaggedValue testA = JSObject::GetProperty(thread, thisValue,
55         JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a"))).GetValue().GetTaggedValue();
56     JSTaggedValue testB = JSObject::GetProperty(thread, thisValue,
57         JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b"))).GetValue().GetTaggedValue();
58 
59     result = result + testA.GetInt() + testB.GetInt();
60     return BuiltinsBase::GetTaggedInt(result);
61 }
62 
63 enum class AlgorithmType {
64     PROTOTYPE_APPLY,
65     PROTOTYPE_BIND,
66     PROTOTYPE_CALL,
67 };
68 
FunctionAlgorithm(JSThread * thread,JSHandle<JSFunction> & thisArg,std::vector<JSTaggedValue> & args,uint32_t argLen,AlgorithmType type=AlgorithmType::PROTOTYPE_APPLY)69 static JSTaggedValue FunctionAlgorithm(JSThread *thread, JSHandle<JSFunction> &thisArg,
70                                        std::vector<JSTaggedValue> &args, uint32_t argLen,
71                                        AlgorithmType type = AlgorithmType::PROTOTYPE_APPLY)
72 {
73     auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), argLen);
74     ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
75     ecmaRuntimeCallInfos->SetThis(thisArg.GetTaggedValue());
76     for (size_t i = 0; i < args.size(); i++) {
77         ecmaRuntimeCallInfos->SetCallArg(i, args[i]);
78     }
79     auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos);
80     JSTaggedValue result;
81     switch (type) {
82         case AlgorithmType::PROTOTYPE_BIND:
83             result = BuiltinsFunction::FunctionPrototypeBind(ecmaRuntimeCallInfos);
84             break;
85         case AlgorithmType::PROTOTYPE_APPLY:
86             result = BuiltinsFunction::FunctionPrototypeApply(ecmaRuntimeCallInfos);
87             break;
88         case AlgorithmType::PROTOTYPE_CALL:
89             result = BuiltinsFunction::FunctionPrototypeCall(ecmaRuntimeCallInfos);
90             break;
91         default:
92             break;
93     }
94     TestHelper::TearDownFrame(thread, prev);
95     return result;
96 }
97 
98 // func Constructor
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionConstructor)99 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionConstructor)
100 {
101     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
102     JSTaggedValue result = BuiltinsSharedFunction::SharedFunctionConstructor(ecmaRuntimeCallInfo);
103     ASSERT_EQ(result.GetRawData(), JSTaggedValue::Exception().GetRawData());
104 }
105 
106 // async func Constructor
HWTEST_F_L0(BuiltinsSharedFunctionTest,AsyncFunctionConstructor)107 HWTEST_F_L0(BuiltinsSharedFunctionTest, AsyncFunctionConstructor)
108 {
109     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
110     JSTaggedValue result = BuiltinsSharedAsyncFunction::SharedAsyncFunctionConstructor(ecmaRuntimeCallInfo);
111     ASSERT_EQ(result.GetRawData(), JSTaggedValue::Exception().GetRawData());
112 }
113 
114 // func.apply(thisArg)
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeApply)115 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeApply)
116 {
117     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
118     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
119     // ecma 19.2.3.1: func
120     JSHandle<JSFunction> func = factory->NewSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));
121 
122     // ecma 19.2.3.1: thisArg
123     JSHandle<JSObject> thisArg(thread, env->GetGlobalObject());
124     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
125                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")),
126                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)));
127     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
128                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")),
129                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(2)));
130 
131     std::vector<JSTaggedValue> args{thisArg.GetTaggedValue()};
132     auto result = FunctionAlgorithm(thread, func, args, 6, AlgorithmType::PROTOTYPE_APPLY);
133 
134     ASSERT_EQ(result.GetRawData(), JSTaggedValue(3).GetRawData());
135 
136     JSObject::DeleteProperty(thread, (thisArg),
137                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")));
138     JSObject::DeleteProperty(thread, (thisArg),
139                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")));
140 }
141 
142 // func.apply(thisArg, argArray)
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeApply1)143 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeApply1)
144 {
145     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
146     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
147 
148     // ecma 19.2.3.1: func
149     JSHandle<JSFunction> func = factory->NewSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));
150 
151     // ecma 19.2.3.1: thisArg
152     JSHandle<JSObject> thisArg(thread, env->GetGlobalObject());
153     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
154                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")),
155                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(10)));
156     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
157                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")),
158                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(20)));
159 
160     // ecma 19.2.3.1: argArray
161     JSHandle<JSObject> array(JSArray::ArrayCreate(thread, JSTaggedNumber(2)));
162     PropertyDescriptor desc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(30)));
163     JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(0)), desc);
164 
165     PropertyDescriptor desc1(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(40)));
166     JSArray::DefineOwnProperty(thread, array, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)), desc1);
167 
168     std::vector<JSTaggedValue> args{thisArg.GetTaggedValue(), array.GetTaggedValue()};
169     auto result = FunctionAlgorithm(thread, func, args, 8, AlgorithmType::PROTOTYPE_APPLY);
170 
171     ASSERT_EQ(result.GetRawData(), JSTaggedValue(100).GetRawData());
172 
173     JSObject::DeleteProperty(thread, (thisArg),
174                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")));
175     JSObject::DeleteProperty(thread, (thisArg),
176                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")));
177 }
178 
179 // target.bind(thisArg)
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeBind)180 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeBind)
181 {
182     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
183     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
184 
185     JSHandle<JSFunction> target = factory->NewSFunction(env);
186     JSHandle<JSObject> thisArg(thread, env->GetGlobalObject());
187     std::vector<JSTaggedValue> args{thisArg.GetTaggedValue()};
188     auto result = FunctionAlgorithm(thread, target, args, 6, AlgorithmType::PROTOTYPE_BIND);
189     ASSERT_TRUE(result.IsECMAObject());
190 
191     JSHandle<JSBoundFunction> resultFunc(thread, reinterpret_cast<TaggedObject *>(result.GetRawData()));
192     // test BoundTarget
193     ASSERT_EQ(resultFunc->GetBoundTarget(), target.GetTaggedValue());
194     // test BoundThis
195     ASSERT_EQ(resultFunc->GetBoundThis(), thisArg.GetTaggedValue());
196     // test BoundArguments
197     JSHandle<TaggedArray> array(thread, resultFunc->GetBoundArguments());
198     ASSERT_EQ(array->GetLength(), 0U);
199 }
200 
201 // target.bind(thisArg, 123, "helloworld")
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeBind1)202 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeBind1)
203 {
204     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
205     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
206 
207     JSHandle<JSFunction> target = factory->NewSFunction(env);
208     JSHandle<JSObject> thisArg(thread, env->GetGlobalObject());
209     JSHandle<EcmaString> str = factory->NewFromASCII("helloworld");
210 
211     std::vector<JSTaggedValue> args{thisArg.GetTaggedValue(), JSTaggedValue(static_cast<int32_t>(123)),
212         str.GetTaggedValue()};
213     auto result = FunctionAlgorithm(thread, target, args, 10, AlgorithmType::PROTOTYPE_BIND);
214     ASSERT_TRUE(result.IsECMAObject());
215 
216     JSHandle<JSBoundFunction> resultFunc(thread, reinterpret_cast<TaggedObject *>(result.GetRawData()));
217     // test BoundTarget
218     ASSERT_EQ(resultFunc->GetBoundTarget(), target.GetTaggedValue());
219     // test BoundThis
220     ASSERT_EQ(resultFunc->GetBoundThis(), thisArg.GetTaggedValue());
221     // test BoundArguments
222     JSHandle<TaggedArray> array(thread, resultFunc->GetBoundArguments());
223     ASSERT_EQ(array->GetLength(), 2U);
224     JSTaggedValue elem = array->Get(0);
225     JSTaggedValue elem1 = array->Get(1);
226     ASSERT_EQ(elem.GetRawData(), JSTaggedValue(123).GetRawData());
227 
228     ASSERT_EQ(elem1.GetRawData(), str.GetTaggedType());
229     ASSERT_TRUE(elem1.IsString());
230 }
231 
232 // target.bind(thisArg, 123, "helloworld") set target_name = EmptyString()
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeBind2)233 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeBind2)
234 {
235     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
236     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
237 
238     JSHandle<JSFunction> target = factory->NewJSFunction(env);
239     PropertyDescriptor nameDesc(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(123)), false, false, true);
240     JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle<JSTaggedValue>(target),
241                                          thread->GlobalConstants()->GetHandledNameString(), nameDesc);
242     JSFunction::SetFunctionLength(thread, target, JSTaggedValue(5));
243 
244     JSHandle<JSObject> thisArg(thread, env->GetGlobalObject());
245     JSHandle<EcmaString> str = factory->NewFromASCII("helloworld");
246     std::vector<JSTaggedValue> args{thisArg.GetTaggedValue(), JSTaggedValue(static_cast<int32_t>(123)),
247         str.GetTaggedValue()};
248     auto result = FunctionAlgorithm(thread, target, args, 10, AlgorithmType::PROTOTYPE_BIND);
249     ASSERT_TRUE(result.IsECMAObject());
250 
251     JSHandle<JSBoundFunction> resultFunc(thread, reinterpret_cast<TaggedObject *>(result.GetRawData()));
252     // test BoundThis
253     ASSERT_EQ(resultFunc->GetBoundThis(), thisArg.GetTaggedValue());
254     // test BoundTarget
255     ASSERT_EQ(resultFunc->GetBoundTarget(), target.GetTaggedValue());
256     // test BoundArguments
257     JSHandle<TaggedArray> array(thread, resultFunc->GetBoundArguments());
258     ASSERT_EQ(array->GetLength(), 2U);
259     JSTaggedValue elem = array->Get(0);
260     JSTaggedValue elem1 = array->Get(1);
261     ASSERT_EQ(elem.GetRawData(), JSTaggedValue(123).GetRawData());
262 
263     ASSERT_TRUE(elem1.IsString());
264     ASSERT_EQ(elem1.GetRawData(), str.GetTaggedType());
265 }
266 
267 // func.call(thisArg)
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeCall)268 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeCall)
269 {
270     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
271     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
272 
273     // ecma 19.2.3.3: func
274     JSHandle<JSFunction> func = factory->NewSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));
275     // ecma 19.2.3.3: thisArg
276     JSHandle<JSObject> thisArg(thread, env->GetGlobalObject());
277     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
278                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")),
279                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)));
280     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
281                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")),
282                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(2)));
283     std::vector<JSTaggedValue> args{thisArg.GetTaggedValue()};
284     auto result = FunctionAlgorithm(thread, func, args, 6, AlgorithmType::PROTOTYPE_CALL);
285     ASSERT_EQ(result.GetRawData(), JSTaggedValue(3).GetRawData());
286 
287     JSObject::DeleteProperty(thread, (thisArg),
288                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")));
289     JSObject::DeleteProperty(thread, (thisArg),
290                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")));
291 }
292 
293 // func.call(thisArg, 123, 456, 789)
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeCall1)294 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeCall1)
295 {
296     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
297     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
298 
299     // ecma 19.2.3.3: func
300     JSHandle<JSFunction> func = factory->NewSFunction(env, reinterpret_cast<void *>(TestFunctionApplyAndCall));
301     // ecma 19.2.3.3: thisArg
302     JSHandle<JSObject> thisArg(thread, env->GetGlobalObject());
303     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
304                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")),
305                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)));
306     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(thisArg),
307                           JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")),
308                           JSHandle<JSTaggedValue>(thread, JSTaggedValue(2)));
309 
310     // func thisArg ...args
311     std::vector<JSTaggedValue> args{thisArg.GetTaggedValue(), JSTaggedValue(static_cast<int32_t>(123)),
312                                 JSTaggedValue(static_cast<int32_t>(456)), JSTaggedValue(static_cast<int32_t>(789))};
313     auto result = FunctionAlgorithm(thread, func, args, 12, AlgorithmType::PROTOTYPE_CALL);
314 
315     ASSERT_EQ(result.GetRawData(), JSTaggedValue(1371).GetRawData());
316 
317     JSObject::DeleteProperty(thread, (thisArg),
318                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_a")));
319     JSObject::DeleteProperty(thread, (thisArg),
320                              JSHandle<JSTaggedValue>(factory->NewFromASCII("test_builtins_function_b")));
321 }
322 
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeHasInstance)323 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeHasInstance)
324 {
325     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
326     JSHandle<JSFunction> booleanCtor(env->GetBooleanFunction());
327 
328     auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*booleanCtor), 6);
329     ecmaRuntimeCallInfo1->SetFunction(booleanCtor.GetTaggedValue());
330     ecmaRuntimeCallInfo1->SetThis(JSTaggedValue::Undefined());
331     ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(123)));
332 
333     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
334     JSTaggedValue result = BuiltinsBoolean::BooleanConstructor(ecmaRuntimeCallInfo1);
335     TestHelper::TearDownFrame(thread, prev);
336 
337     JSHandle<JSObject> booleanInstance(thread, result);
338 
339     auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
340     ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
341     ecmaRuntimeCallInfo2->SetThis(booleanCtor.GetTaggedValue());
342     ecmaRuntimeCallInfo2->SetCallArg(0, booleanInstance.GetTaggedValue());
343 
344     prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
345     EXPECT_TRUE(BuiltinsFunction::FunctionPrototypeHasInstance(ecmaRuntimeCallInfo2).GetRawData());
346     TestHelper::TearDownFrame(thread, prev);
347 }
348 
349 /**
350  * @tc.name: FunctionPrototypeToString
351  * @tc.desc: Create msgs through "CreateEcmaRuntimeCallInfo" function, Set ArgsNumber and CallArg, then call
352  *           the "FunctionPrototypeToString" function to get the result of Function.prototype.call.toString().
353  * @tc.type: FUNC
354  * @tc.require: issueI5INW1
355  */
HWTEST_F_L0(BuiltinsSharedFunctionTest,FunctionPrototypeToString)356 HWTEST_F_L0(BuiltinsSharedFunctionTest, FunctionPrototypeToString)
357 {
358     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
359     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
360     JSHandle<JSFunction> func = factory->NewSFunction(
361                                 env, reinterpret_cast<void *>(BuiltinsFunction::FunctionPrototypeCall));
362 
363     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
364     ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
365     ecmaRuntimeCallInfo->SetThis(func.GetTaggedValue());
366 
367     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
368     JSTaggedValue result = BuiltinsFunction::FunctionPrototypeToString(ecmaRuntimeCallInfo);
369     ASSERT_TRUE(result.IsString());
370     JSHandle<EcmaString> resultHandle(thread, reinterpret_cast<EcmaString *>(result.GetRawData()));
371     JSHandle<EcmaString> test = factory->NewFromASCII("function undefined() { [native code] }");
372     ASSERT_EQ(EcmaStringAccessor::Compare(instance, resultHandle, test), 0);
373 }
374 }  // namespace panda::test
375