1 /*
2 * Copyright (C) 2025 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 "atomicfile_mock.h"
17
18 #include <dlfcn.h>
19
20 namespace OHOS::FileManagement::ModuleFileIO::Test {
21 using namespace OHOS::FileManagement::ModuleFileIO;
22
23 thread_local std::shared_ptr<AtomicfileMock> AtomicfileMock::atomicfileMock = nullptr;
24 thread_local bool AtomicfileMock::mockable = false;
25
GetMock()26 std::shared_ptr<AtomicfileMock> AtomicfileMock::GetMock()
27 {
28 if (atomicfileMock == nullptr) {
29 atomicfileMock = std::make_shared<AtomicfileMock>();
30 }
31 return atomicfileMock;
32 }
33
EnableMock()34 void AtomicfileMock::EnableMock()
35 {
36 mockable = true;
37 }
38
DisableMock()39 void AtomicfileMock::DisableMock()
40 {
41 atomicfileMock = nullptr;
42 mockable = false;
43 }
44
IsMockable()45 bool AtomicfileMock::IsMockable()
46 {
47 return mockable;
48 }
49
50 } // namespace OHOS::FileManagement::ModuleFileIO::Test
51
52 #ifdef __cplusplus
53 using namespace OHOS::FileManagement::ModuleFileIO::Test;
54
55 extern "C" {
rename(const char * old_filename,const char * new_filename)56 int rename(const char *old_filename, const char *new_filename)
57 {
58 if (AtomicfileMock::IsMockable()) {
59 return AtomicfileMock::GetMock()->rename(old_filename, new_filename);
60 }
61
62 static int (*realRename)(const char *, const char *) = []() {
63 auto func = (int (*)(const char *, const char *))dlsym(RTLD_NEXT, "rename");
64 if (!func) {
65 GTEST_LOG_(ERROR) << "Failed to resolve real rename: " << dlerror();
66 }
67 return func;
68 }();
69
70 if (!realRename) {
71 return -1;
72 }
73
74 return realRename(old_filename, new_filename);
75 }
76
remove(const char * filename)77 int remove(const char *filename)
78 {
79 if (AtomicfileMock::IsMockable()) {
80 return AtomicfileMock::GetMock()->remove(filename);
81 }
82
83 static int (*realRemove)(const char *) = []() {
84 auto func = (int (*)(const char *))dlsym(RTLD_NEXT, "remove");
85 if (!func) {
86 GTEST_LOG_(ERROR) << "Failed to resolve real remove: " << dlerror();
87 }
88 return func;
89 }();
90
91 if (!realRemove) {
92 return -1;
93 }
94
95 return realRemove(filename);
96 }
97
napi_get_reference_value(napi_env env,napi_ref ref,napi_value * result)98 napi_status napi_get_reference_value(napi_env env, napi_ref ref, napi_value *result)
99 {
100 if (AtomicfileMock::IsMockable()) {
101 return AtomicfileMock::GetMock()->napi_get_reference_value(env, ref, result);
102 }
103
104 static napi_status (*realNapi)(napi_env, napi_ref, napi_value *) = []() {
105 auto func = (napi_status(*)(napi_env, napi_ref, napi_value *))dlsym(RTLD_NEXT, "napi_get_reference_value");
106 if (!func) {
107 GTEST_LOG_(ERROR) << "Failed to resolve real napi_get_reference_value: " << dlerror();
108 }
109 return func;
110 }();
111
112 if (!realNapi) {
113 return napi_ok;
114 }
115
116 return realNapi(env, ref, result);
117 }
118
napi_delete_reference(napi_env env,napi_ref ref)119 napi_status napi_delete_reference(napi_env env, napi_ref ref)
120 {
121 if (AtomicfileMock::IsMockable()) {
122 return AtomicfileMock::GetMock()->napi_delete_reference(env, ref);
123 }
124
125 static napi_status (*realNapi)(napi_env, napi_ref) = []() {
126 auto func = (napi_status(*)(napi_env, napi_ref))dlsym(RTLD_NEXT, "napi_delete_reference");
127 if (!func) {
128 GTEST_LOG_(ERROR) << "Failed to resolve real napi_delete_reference: " << dlerror();
129 }
130 return func;
131 }();
132
133 if (!realNapi) {
134 return napi_ok;
135 }
136
137 return realNapi(env, ref);
138 }
139
napi_unwrap(napi_env env,napi_value js_object,void ** result)140 napi_status napi_unwrap(napi_env env, napi_value js_object, void **result)
141 {
142 if (AtomicfileMock::IsMockable()) {
143 return AtomicfileMock::GetMock()->napi_unwrap(env, js_object, result);
144 }
145
146 static napi_status (*realNapi)(napi_env, napi_value, void **) = []() {
147 auto func = (napi_status(*)(napi_env, napi_value, void **))dlsym(RTLD_NEXT, "napi_unwrap");
148 if (!func) {
149 GTEST_LOG_(ERROR) << "Failed to resolve real napi_unwrap: " << dlerror();
150 }
151 return func;
152 }();
153
154 if (!realNapi) {
155 return napi_ok;
156 }
157
158 return realNapi(env, js_object, result);
159 }
160
napi_typeof(napi_env env,napi_value value,napi_valuetype * result)161 napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype *result)
162 {
163 return AtomicfileMock::GetMock()->napi_typeof(env, value, result);
164 }
165 } // extern "C"
166
InitArgs(std::function<bool ()> argcChecker)167 bool NFuncArg::InitArgs(std::function<bool()> argcChecker)
168 {
169 if (AtomicfileMock::IsMockable()) {
170 return AtomicfileMock::GetMock()->InitArgs(argcChecker);
171 }
172
173 static bool (*realInitArgs)(std::function<bool()>) = []() {
174 auto func = (bool (*)(std::function<bool()>))dlsym(RTLD_NEXT, "InitArgs");
175 if (!func) {
176 GTEST_LOG_(ERROR) << "Failed to resolve real InitArgs: " << dlerror();
177 }
178 return func;
179 }();
180
181 if (!realInitArgs) {
182 return false;
183 }
184
185 return realInitArgs(argcChecker);
186 }
187
GetThisVar() const188 napi_value NFuncArg::GetThisVar() const
189 {
190 if (AtomicfileMock::IsMockable()) {
191 return AtomicfileMock::GetMock()->GetThisVar();
192 }
193
194 static napi_value (*realGetThisVar)() = []() {
195 auto func = (napi_value(*)())dlsym(RTLD_NEXT, "GetThisVar");
196 if (!func) {
197 GTEST_LOG_(ERROR) << "Failed to resolve real GetThisVar: " << dlerror();
198 }
199 return func;
200 }();
201
202 if (!realGetThisVar) {
203 return nullptr;
204 }
205
206 return realGetThisVar();
207 }
208
ThrowErr(napi_env env,std::string errMsg)209 void NError::ThrowErr(napi_env env, std::string errMsg)
210 {
211 if (AtomicfileMock::IsMockable()) {
212 return AtomicfileMock::GetMock()->ThrowErr(env, errMsg);
213 }
214
215 static void (*realThrowErr)(napi_env, std::string) = []() {
216 auto func = (void (*)(napi_env, std::string))dlsym(RTLD_NEXT, "ThrowErr");
217 if (!func) {
218 GTEST_LOG_(ERROR) << "Failed to resolve real ThrowErr: " << dlerror();
219 }
220 return func;
221 }();
222
223 if (!realThrowErr) {
224 return;
225 }
226
227 return realThrowErr(env, errMsg);
228 }
229 #endif