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 "js_component_test_matcher.h"
17
18 #include <string>
19
20 #include "component_test/component_test_proxy.h"
21 #include "interfaces/napi/kits/utils/napi_utils.h"
22 #include "js_component_test_utils.h"
23 #include "napi/native_api.h"
24 #include "napi/native_node_api.h"
25
26 #include "base/log/log.h"
27 #include "base/utils/utils.h"
28
29 namespace OHOS::Ace::Napi {
30 namespace {
31 constexpr char CREATE[] = "create";
32 constexpr char TEXT[] = "text";
33 constexpr char ID[] = "id";
34 constexpr char TYPE[] = "type";
35 constexpr char CLICKABLE[] = "clickable";
36 constexpr char LONGPRESSABLE[] = "longPressable";
37 constexpr char SCROLLABLE[] = "scrollable";
38 constexpr char ENABLED[] = "enabled";
39 constexpr char FOCUSED[] = "focused";
40 constexpr char SELECTED[] = "selected";
41 constexpr char CHECKED[] = "checked";
42 constexpr char CHECKABLE[] = "checkable";
43 } // namespace
44
45 thread_local napi_ref ComponentTestMatcher::constructorRef_ = nullptr;
46
DefineComponentTestMatcher(napi_env env,napi_value exports)47 napi_status ComponentTestMatcher::DefineComponentTestMatcher(napi_env env, napi_value exports)
48 {
49 napi_value constructor = nullptr;
50
51 napi_property_descriptor desc[] = {
52 DECLARE_NAPI_STATIC_FUNCTION(CREATE, JSCreate),
53 DECLARE_NAPI_FUNCTION(TEXT, JSText),
54 DECLARE_NAPI_FUNCTION(ID, JSId),
55 DECLARE_NAPI_FUNCTION(TYPE, JSType),
56 DECLARE_NAPI_FUNCTION_WITH_DATA(CLICKABLE, GenericBoolCallback, (void*)CLICKABLE),
57 DECLARE_NAPI_FUNCTION_WITH_DATA(LONGPRESSABLE, GenericBoolCallback, (void*)LONGPRESSABLE),
58 DECLARE_NAPI_FUNCTION_WITH_DATA(SCROLLABLE, GenericBoolCallback, (void*)SCROLLABLE),
59 DECLARE_NAPI_FUNCTION_WITH_DATA(ENABLED, GenericBoolCallback, (void*)ENABLED),
60 DECLARE_NAPI_FUNCTION_WITH_DATA(FOCUSED, GenericBoolCallback, (void*)FOCUSED),
61 DECLARE_NAPI_FUNCTION_WITH_DATA(SELECTED, GenericBoolCallback, (void*)SELECTED),
62 DECLARE_NAPI_FUNCTION_WITH_DATA(CHECKED, GenericBoolCallback, (void*)CHECKED),
63 DECLARE_NAPI_FUNCTION_WITH_DATA(CHECKABLE, GenericBoolCallback, (void*)CHECKABLE),
64 };
65
66 NAPI_CALL_BASE(env,
67 napi_define_class(env, MATCHER_NAME, NAPI_AUTO_LENGTH, Constructor, nullptr,
68 sizeof(desc) / sizeof(napi_property_descriptor), desc, &constructor),
69 NAPI_ERR);
70 NAPI_CALL_BASE(env, napi_set_named_property(env, exports, MATCHER_NAME, constructor), NAPI_ERR);
71 NAPI_CALL_BASE(env, napi_create_reference(env, constructor, 1, &constructorRef_), NAPI_ERR);
72
73 return napi_ok;
74 }
75
Constructor(napi_env env,napi_callback_info info)76 napi_value ComponentTestMatcher::Constructor(napi_env env, napi_callback_info info)
77 {
78 napi_value thisVar = nullptr;
79 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
80 ComponentTest::ComponentTestMatcherImpl* matcherImpl = new (std::nothrow) ComponentTest::ComponentTestMatcherImpl();
81 COMPONENT_TEST_NAPI_ASSERT_CUSTOM(
82 env, matcherImpl != nullptr, ErrCode::RET_ERR_FAILED, "Failed to create matcherImpl.", NapiGetUndefined(env));
83 NAPI_CALL_BASE(env, napi_wrap(env, thisVar, matcherImpl, Destructor, nullptr, nullptr), thisVar);
84 return thisVar;
85 }
86
Destructor(napi_env env,void * data,void * hint)87 void ComponentTestMatcher::Destructor(napi_env env, void* data, void* hint)
88 {
89 ComponentTest::ComponentTestMatcherImpl* matcherImpl =
90 reinterpret_cast<ComponentTest::ComponentTestMatcherImpl*>(data);
91 CHECK_NULL_VOID(matcherImpl);
92 if (constructorRef_ != nullptr) {
93 napi_delete_reference(env, constructorRef_);
94 }
95 delete matcherImpl;
96 matcherImpl = nullptr;
97 }
98
JSCreate(napi_env env,napi_callback_info info)99 napi_value ComponentTestMatcher::JSCreate(napi_env env, napi_callback_info info)
100 {
101 CHECK_COMPONENT_TEST_ENABLED();
102 napi_value constructor = nullptr;
103 napi_value thisVar = nullptr;
104 NAPI_CALL(env, napi_get_reference_value(env, constructorRef_, &constructor));
105 NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &thisVar));
106 COMPONENT_TEST_NAPI_ASSERT(env, thisVar != nullptr, ErrCode::RET_ERR_FAILED);
107 return thisVar;
108 }
109
JSText(napi_env env,napi_callback_info info)110 napi_value ComponentTestMatcher::JSText(napi_env env, napi_callback_info info)
111 {
112 size_t argc = ARG_COUNT_TWO;
113 napi_value argv[ARG_COUNT_TWO] = { nullptr };
114 napi_value thisVar = nullptr;
115 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
116 COMPONENT_TEST_NAPI_ASSERT(env, argc == ARG_COUNT_ONE || argc == ARG_COUNT_TWO, ErrCode::RET_ERROR_PARAM_INVALID);
117
118 std::string text;
119 std::string errMsg;
120 COMPONENT_TEST_NAPI_ASSERT_CUSTOM(env, CheckAndParseStr(env, argv[ARG_COUNT_ZERO], text, errMsg),
121 ErrCode::RET_ERROR_PARAM_INVALID, errMsg, NapiGetUndefined(env));
122 ComponentTest::ComponentTestMatcherImpl* matcherImpl = GetMatcher(env, thisVar);
123 CHECK_NULL_RETURN(matcherImpl, NapiGetUndefined(env));
124 if (argc == ARG_COUNT_TWO) {
125 COMPONENT_TEST_NAPI_ASSERT_CUSTOM(env, GetValueType(env, argv[ARG_COUNT_ONE]) == napi_number,
126 ErrCode::RET_ERROR_PARAM_INVALID, "Parameter is not of type number", NapiGetUndefined(env));
127 int32_t matchType = 0;
128 NAPI_CALL(env, napi_get_value_int32(env, argv[ARG_COUNT_ONE], &matchType));
129 COMPONENT_TEST_NAPI_ASSERT_CUSTOM(
130 env, matchType >= 0, ErrCode::RET_ERROR_PARAM_INVALID, "Exceeds the range of types", NapiGetUndefined(env));
131 ComponentTest::MatchType enumValue = static_cast<ComponentTest::MatchType>(matchType);
132 matcherImpl->SetText(text, enumValue);
133 } else {
134 matcherImpl->SetText(text);
135 }
136 return thisVar;
137 }
138
JSId(napi_env env,napi_callback_info info)139 napi_value ComponentTestMatcher::JSId(napi_env env, napi_callback_info info)
140 {
141 size_t argc = ARG_COUNT_ONE;
142 napi_value argv = nullptr;
143 napi_value thisVar = nullptr;
144 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &argv, &thisVar, nullptr));
145 COMPONENT_TEST_NAPI_ASSERT(env, argc == ARG_COUNT_ONE, ErrCode::RET_ERROR_PARAM_INVALID);
146
147 std::string id;
148 std::string errMsg;
149 COMPONENT_TEST_NAPI_ASSERT_CUSTOM(
150 env, CheckAndParseStr(env, argv, id, errMsg), ErrCode::RET_ERROR_PARAM_INVALID, errMsg, NapiGetUndefined(env));
151 ComponentTest::ComponentTestMatcherImpl* matcherImpl = GetMatcher(env, thisVar);
152 CHECK_NULL_RETURN(matcherImpl, NapiGetUndefined(env));
153 matcherImpl->SetId(id);
154 return thisVar;
155 }
156
JSType(napi_env env,napi_callback_info info)157 napi_value ComponentTestMatcher::JSType(napi_env env, napi_callback_info info)
158 {
159 size_t argc = ARG_COUNT_ONE;
160 napi_value argv = nullptr;
161 napi_value thisVar = nullptr;
162 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &argv, &thisVar, nullptr));
163 COMPONENT_TEST_NAPI_ASSERT(env, argc == ARG_COUNT_ONE, ErrCode::RET_ERROR_PARAM_INVALID);
164
165 std::string type;
166 std::string errMsg;
167 COMPONENT_TEST_NAPI_ASSERT_CUSTOM(env, CheckAndParseStr(env, argv, type, errMsg), ErrCode::RET_ERROR_PARAM_INVALID,
168 errMsg, NapiGetUndefined(env));
169 ComponentTest::ComponentTestMatcherImpl* matcherImpl = GetMatcher(env, thisVar);
170 CHECK_NULL_RETURN(matcherImpl, NapiGetUndefined(env));
171 matcherImpl->SetType(type);
172 return thisVar;
173 }
174
GenericBoolCallback(napi_env env,napi_callback_info info)175 napi_value ComponentTestMatcher::GenericBoolCallback(napi_env env, napi_callback_info info)
176 {
177 size_t argc = ARG_COUNT_ONE;
178 void* data = nullptr;
179 napi_value argv = nullptr;
180 napi_value thisVar = nullptr;
181 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data));
182 COMPONENT_TEST_NAPI_ASSERT(env, argc == ARG_COUNT_ZERO || argc == ARG_COUNT_ONE, ErrCode::RET_ERROR_PARAM_INVALID);
183 COMPONENT_TEST_NAPI_ASSERT(env, data != nullptr, ErrCode::RET_ERR_FAILED);
184 bool res = true;
185 std::string errMsg;
186 if (argc == ARG_COUNT_ONE) {
187 COMPONENT_TEST_NAPI_ASSERT_CUSTOM(env, CheckAndParseBool(env, argv, res, errMsg),
188 ErrCode::RET_ERROR_PARAM_INVALID, errMsg, NapiGetUndefined(env));
189 }
190 ComponentTest::ComponentTestMatcherImpl* matcherImpl = GetMatcher(env, thisVar);
191 CHECK_NULL_RETURN(matcherImpl, NapiGetUndefined(env));
192
193 const char* functionName = static_cast<const char*>(data);
194 if (std::strcmp(functionName, "clickable") == 0) {
195 matcherImpl->SetClickable(res);
196 } else if (std::strcmp(functionName, "longPressable") == 0) {
197 matcherImpl->SetLongPressable(res);
198 } else if (std::strcmp(functionName, "scrollable") == 0) {
199 matcherImpl->SetScrollable(res);
200 } else if (std::strcmp(functionName, "enabled") == 0) {
201 matcherImpl->SetEnabled(res);
202 } else if (std::strcmp(functionName, "focused") == 0) {
203 matcherImpl->SetFocused(res);
204 } else if (std::strcmp(functionName, "selected") == 0) {
205 matcherImpl->SetSelected(res);
206 } else if (std::strcmp(functionName, "checked") == 0) {
207 matcherImpl->SetChecked(res);
208 } else if (std::strcmp(functionName, "checkable") == 0) {
209 matcherImpl->SetCheckable(res);
210 } else {
211 LOGW("Unknown function %{public}s", functionName);
212 }
213 return thisVar;
214 }
215
216 } // namespace OHOS::Ace::Napi
217