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 #ifdef TEST_DEFINE_CLASS_WITH_OPTIONS
16 #include "jsvmtest.h"
17
18 #define JSVM_PARENT_CLASS_DES_COUNT 2
19 #define JSVM_OBJECT_INTERFAIELD_COUNT 3
20 #define JSVM_DEFINE_CLASS_OPTIONS_COUNT 2
21
22 static JSVM_PropertyHandlerConfigurationStruct propertyCfg{
23 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
24 };
25
26 static bool g_callAsFunctionFlag = false;
27 static bool g_setNamedPropertyFlag = false;
28 static bool g_callAsConstructorFlag = false;
29 static bool g_propertiesFlag = false;
30
SetNamedPropertyCbInfo2(JSVM_Env env,JSVM_Value name,JSVM_Value property,JSVM_Value thisArg,JSVM_Value data)31 static JSVM_Value SetNamedPropertyCbInfo2(JSVM_Env env, JSVM_Value name, JSVM_Value property,
32 JSVM_Value thisArg, JSVM_Value data)
33 {
34 g_setNamedPropertyFlag = true;
35 return property;
36 }
37
Add(JSVM_Env env,JSVM_CallbackInfo info)38 static JSVM_Value Add(JSVM_Env env, JSVM_CallbackInfo info)
39 {
40 g_propertiesFlag = true;
41 size_t argc = 2;
42 JSVM_Value args[2];
43 OH_JSVM_GetCbInfo(env, info, &argc, args, NULL, NULL);
44 double num1, num2;
45 OH_JSVM_GetValueDouble(env, args[0], &num1);
46 OH_JSVM_GetValueDouble(env, args[1], &num2);
47 JSVM_Value sum = nullptr;
48 OH_JSVM_CreateDouble(env, num1 + num2, &sum);
49 return sum;
50 }
51
GenerateParentClass(JSVM_Env env)52 JSVM_Value GenerateParentClass(JSVM_Env env)
53 {
54 JSVM_Value parentClass = nullptr;
55 JSVM_CallbackStruct *parentClassConstructor = new JSVM_CallbackStruct;
56 parentClassConstructor->data = nullptr;
57 parentClassConstructor->callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
58 JSVM_Value thisVar = nullptr;
59 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr);
60 return thisVar;
61 };
62 JSVM_Value fooVal = jsvm::Str("bar");
63 JSVM_PropertyDescriptor des[2];
64 des[0] = {
65 .utf8name = "foo",
66 .value = fooVal,
67 };
68 JSVM_CallbackStruct *addMethod = new JSVM_CallbackStruct;
69 addMethod->data = nullptr;
70 addMethod->callback = Add;
71 des[1] = {
72 .utf8name = "add",
73 .method = addMethod,
74 };
75 JSVM_DefineClassOptions options[1];
76 options[0].id = JSVM_DEFINE_CLASS_WITH_COUNT;
77 options[0].content.num = JSVM_OBJECT_INTERFAIELD_COUNT;
78 JSVMTEST_CALL(OH_JSVM_DefineClassWithOptions(env, "parentClass", JSVM_AUTO_LENGTH,
79 parentClassConstructor, JSVM_PARENT_CLASS_DES_COUNT, des,
80 nullptr, 1, options, &parentClass));
81 return parentClass;
82 }
83
GenerateSubClass(JSVM_Env env,JSVM_Value parentClass)84 JSVM_Value GenerateSubClass(JSVM_Env env, JSVM_Value parentClass)
85 {
86 JSVM_Value subClass = nullptr;
87 JSVM_CallbackStruct *subClassConstructor = new JSVM_CallbackStruct;
88 subClassConstructor->data = nullptr;
89 subClassConstructor->callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
90 JSVM_Value thisVar = nullptr;
91 g_callAsConstructorFlag = true;
92 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr);
93 return thisVar;
94 };
95 JSVM_DefineClassOptions subOptions[2];
96 JSVM_CallbackStruct *callAsFuncParam = new JSVM_CallbackStruct;
97 callAsFuncParam->data = nullptr;
98 callAsFuncParam->callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
99 JSVM_Value thisVar = nullptr;
100 g_callAsFunctionFlag = true;
101 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr);
102 return thisVar;
103 };
104 propertyCfg.genericNamedPropertySetterCallback = SetNamedPropertyCbInfo2;
105 JSVM_PropertyHandler propertyHandler = {
106 .propertyHandlerCfg = &propertyCfg,
107 .callAsFunctionCallback = callAsFuncParam,
108 };
109 subOptions[0].id = JSVM_DEFINE_CLASS_WITH_COUNT;
110 subOptions[0].content.num = JSVM_OBJECT_INTERFAIELD_COUNT;
111 subOptions[1].id = JSVM_DEFINE_CLASS_WITH_PROPERTY_HANDLER;
112 subOptions[1].content.ptr = &propertyHandler;
113 JSVMTEST_CALL(OH_JSVM_DefineClassWithOptions(env, "subClass", JSVM_AUTO_LENGTH, subClassConstructor, 0, nullptr,
114 parentClass, JSVM_DEFINE_CLASS_OPTIONS_COUNT, subOptions, &subClass));
115 return subClass;
116 }
117
118 /**
119 * @brief Verify the validity of the following parameters in the OH_JSVM_DefineClassWithOptions interface:
120 * 'consturctor' | 'properties' | 'parentClass' | 'options'
121 */
TEST(TestParentClassWithCount)122 TEST(TestParentClassWithCount)
123 {
124 g_callAsFunctionFlag = false;
125 g_setNamedPropertyFlag = false;
126 g_callAsConstructorFlag = false;
127 g_propertiesFlag = false;
128 // 1. Define parent-class.
129 JSVM_Value parentClass = GenerateParentClass(env);
130 // 2. Define sub-class.
131 JSVM_Value subClass = GenerateSubClass(env, parentClass);
132 // 3. Verify the validity of 'constructor'.
133 JSVM_Value subInstance;
134 CHECK(g_callAsConstructorFlag == false);
135 JSVM_CALL(OH_JSVM_NewInstance(env, subClass, 0, nullptr, &subInstance));
136 CHECK(g_callAsConstructorFlag == true);
137
138 JSVM_Value globalVal;
139 OH_JSVM_GetGlobal(env, &globalVal);
140 OH_JSVM_SetNamedProperty(env, globalVal, "obj", subInstance);
141
142 // 4. Verify the validity of 'parentClass'.
143 JSVM_Value subRes = nullptr;
144 JSVM_CALL(OH_JSVM_GetNamedProperty(env, subInstance, "foo", &subRes));
145 CHECK(jsvm::ToString(subRes).compare("bar") == 0);
146 // 5. Verify the validity of 'properties'.
147 CHECK(g_propertiesFlag == false);
148 jsvm::Run("obj.add(3, 4);");
149 CHECK(g_propertiesFlag == true);
150 // 6. Verify the validity of 'options'.
151 CHECK(g_callAsFunctionFlag == false);
152 jsvm::Run("obj()");
153 CHECK(g_callAsFunctionFlag == true);
154 CHECK(g_setNamedPropertyFlag == false);
155 jsvm::Run("obj.x = 123;");
156 CHECK(g_setNamedPropertyFlag == true);
157 }
158
159 /**
160 * @brief If parentClass is not an APIFunction, the status code is JSVM_INVALID_ARG.
161 */
TEST(NonAPIFunction)162 TEST(NonAPIFunction) {
163 JSVM_Value script = jsvm::Str("return 2 + 3;");
164 JSVM_Value nonAPIFunction = nullptr;
165 JSVMTEST_CALL(OH_JSVM_CreateFunctionWithScript(env, nullptr, 0, 0,
166 nullptr, script, &nonAPIFunction));
167
168 JSVM_Value subClass = nullptr;
169 JSVM_CallbackStruct constructor;
170 constructor.data = nullptr;
171 constructor.callback = [](JSVM_Env env, JSVM_CallbackInfo info) -> JSVM_Value {
172 JSVM_Value thisVar = nullptr;
173 OH_JSVM_GetCbInfo(env, info, nullptr, nullptr, &thisVar, nullptr);
174 return thisVar;
175 };
176 JSVM_Status status = OH_JSVM_DefineClassWithOptions(env, "subClass", JSVM_AUTO_LENGTH,
177 &constructor, 0, nullptr, nonAPIFunction, 0, nullptr, &subClass);
178 CHECK(status == JSVM_INVALID_ARG);
179 }
180
181 #endif // TEST_DEFINE_CLASS_WITH_OPTIONS