FileSystemMocks.h (12422B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DOM_FS_TEST_GTEST_FILESYSTEMMOCKS_H_ 8 #define DOM_FS_TEST_GTEST_FILESYSTEMMOCKS_H_ 9 10 #include <memory> // We don't have a mozilla shared pointer for pod types 11 12 #include "TestHelpers.h" 13 #include "fs/FileSystemChildFactory.h" 14 #include "fs/FileSystemRequestHandler.h" 15 #include "gmock/gmock.h" 16 #include "gtest/gtest.h" 17 #include "js/Promise.h" 18 #include "js/RootingAPI.h" 19 #include "jsapi.h" 20 #include "mozilla/ErrorResult.h" 21 #include "mozilla/ScopeExit.h" 22 #include "mozilla/dom/BindingDeclarations.h" 23 #include "mozilla/dom/BindingUtils.h" 24 #include "mozilla/dom/DOMException.h" 25 #include "mozilla/dom/DOMExceptionBinding.h" 26 #include "mozilla/dom/FileSystemManagerChild.h" 27 #include "mozilla/dom/Promise.h" 28 #include "mozilla/dom/PromiseNativeHandler.h" 29 #include "mozilla/dom/ScriptSettings.h" 30 #include "mozilla/ipc/PBackgroundSharedTypes.h" 31 #include "nsIGlobalObject.h" 32 #include "nsISupports.h" 33 #include "nsISupportsImpl.h" 34 #include "nsITimer.h" 35 36 class MockGlobalObject; 37 38 namespace mozilla::dom::fs { 39 40 inline std::ostream& operator<<(std::ostream& aOut, 41 const FileSystemEntryMetadata& aMetadata) { 42 return aOut; 43 } 44 45 namespace test { 46 47 nsIGlobalObject* GetGlobal(); 48 49 MockGlobalObject* GetMockGlobal(); 50 51 nsresult GetAsString(const RefPtr<Promise>& aPromise, nsAString& aString); 52 53 mozilla::ipc::PrincipalInfo GetPrincipalInfo(); 54 55 class MockFileSystemRequestHandler : public FileSystemRequestHandler { 56 public: 57 MOCK_METHOD(void, GetRootHandle, 58 (RefPtr<FileSystemManager> aManager, RefPtr<Promise> aPromise, 59 ErrorResult& aError), 60 (override)); 61 62 MOCK_METHOD(void, GetDirectoryHandle, 63 (RefPtr<FileSystemManager> & aManager, 64 const FileSystemChildMetadata& aDirectory, bool aCreate, 65 RefPtr<Promise> aPromise, ErrorResult& aError), 66 (override)); 67 68 MOCK_METHOD(void, GetFileHandle, 69 (RefPtr<FileSystemManager> & aManager, 70 const FileSystemChildMetadata& aFile, bool aCreate, 71 RefPtr<Promise> aPromise, ErrorResult& aError), 72 (override)); 73 74 MOCK_METHOD(void, GetFile, 75 (RefPtr<FileSystemManager> & aManager, 76 const FileSystemEntryMetadata& aFile, RefPtr<Promise> aPromise, 77 ErrorResult& aError), 78 (override)); 79 80 MOCK_METHOD(void, GetEntries, 81 (RefPtr<FileSystemManager> & aManager, const EntryId& aDirectory, 82 PageNumber aPage, RefPtr<Promise> aPromise, 83 RefPtr<FileSystemEntryMetadataArray>& aSink, 84 ErrorResult& aError), 85 (override)); 86 87 MOCK_METHOD(void, RemoveEntry, 88 (RefPtr<FileSystemManager> & aManager, 89 const FileSystemChildMetadata& aEntry, bool aRecursive, 90 RefPtr<Promise> aPromise, ErrorResult& aError), 91 (override)); 92 93 MOCK_METHOD(void, MoveEntry, 94 (RefPtr<FileSystemManager> & aManager, FileSystemHandle* aHandle, 95 FileSystemEntryMetadata* const aEntry, 96 const FileSystemChildMetadata& aNewEntry, 97 RefPtr<Promise> aPromise, ErrorResult& aError), 98 (override)); 99 100 MOCK_METHOD(void, RenameEntry, 101 (RefPtr<FileSystemManager> & aManager, FileSystemHandle* aHandle, 102 FileSystemEntryMetadata* const aEntry, const Name& aName, 103 RefPtr<Promise> aPromise, ErrorResult& aError), 104 (override)); 105 106 MOCK_METHOD(void, Resolve, 107 (RefPtr<FileSystemManager> & aManager, 108 const FileSystemEntryPair& aEndpoints, RefPtr<Promise> aPromise, 109 ErrorResult& aError), 110 (override)); 111 }; 112 113 class WaitablePromiseListener { 114 public: 115 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 116 117 virtual void ClearDone() = 0; 118 119 virtual bool IsDone() const = 0; 120 121 virtual PromiseNativeHandler* AsHandler() = 0; 122 123 protected: 124 virtual ~WaitablePromiseListener() = default; 125 }; 126 127 template <class SuccessHandler, class ErrorHandler, 128 uint32_t MilliSeconds = 2000u> 129 class TestPromiseListener : public PromiseNativeHandler, 130 public WaitablePromiseListener { 131 public: 132 TestPromiseListener() 133 : mIsDone(std::make_shared<bool>(false)), mOnSuccess(), mOnError() { 134 ClearDone(); 135 } 136 137 // nsISupports implementation 138 139 NS_IMETHODIMP QueryInterface(REFNSIID aIID, void** aInstancePtr) override { 140 nsresult rv = NS_ERROR_UNEXPECTED; 141 NS_INTERFACE_TABLE0(TestPromiseListener) 142 143 return rv; 144 } 145 146 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestPromiseListener, override) 147 148 // PromiseNativeHandler implementation 149 150 void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue, 151 ErrorResult& aError) override { 152 mozilla::ScopeExit flagAsDone([isDone = mIsDone, timer = mTimer] { 153 timer->Cancel(); 154 *isDone = true; 155 }); 156 157 mOnSuccess(); 158 } 159 160 void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue, 161 ErrorResult& aError) override { 162 mozilla::ScopeExit flagAsDone([isDone = mIsDone, timer = mTimer] { 163 timer->Cancel(); 164 *isDone = true; 165 }); 166 167 if (aValue.isInt32()) { 168 mOnError(static_cast<nsresult>(aValue.toInt32())); 169 return; 170 } 171 172 ASSERT_TRUE(aValue.isObject()); 173 JS::Rooted<JSObject*> exceptionObject(aCx, &aValue.toObject()); 174 175 RefPtr<Exception> exception; 176 UNWRAP_OBJECT(Exception, exceptionObject, exception); 177 if (exception) { 178 mOnError(static_cast<nsresult>(exception->Result())); 179 return; 180 } 181 } 182 183 // WaitablePromiseListener implementation 184 185 void ClearDone() override { 186 *mIsDone = false; 187 if (mTimer) { 188 mTimer->Cancel(); 189 } 190 auto timerCallback = [isDone = mIsDone](nsITimer* aTimer) { 191 *isDone = true; 192 FAIL() << "Timed out!"; 193 }; 194 auto res = NS_NewTimerWithCallback(timerCallback, MilliSeconds, 195 nsITimer::TYPE_ONE_SHOT, 196 "fs::TestPromiseListener::ClearDone"_ns); 197 if (res.isOk()) { 198 mTimer = res.unwrap(); 199 } 200 } 201 202 bool IsDone() const override { return *mIsDone; } 203 204 PromiseNativeHandler* AsHandler() override { return this; } 205 206 SuccessHandler& GetSuccessHandler() { return mOnSuccess; } 207 208 SuccessHandler& GetErrorHandler() { return mOnError; } 209 210 protected: 211 virtual ~TestPromiseListener() = default; 212 213 std::shared_ptr<bool> mIsDone; // We pass this to a callback 214 215 nsCOMPtr<nsITimer> mTimer; 216 217 SuccessHandler mOnSuccess; 218 219 ErrorHandler mOnError; 220 }; 221 222 class TestFileSystemManagerChild : public FileSystemManagerChild { 223 public: 224 MOCK_METHOD(void, SendGetRootHandle, 225 (mozilla::ipc::ResolveCallback<FileSystemGetHandleResponse> && 226 aResolve, 227 mozilla::ipc::RejectCallback&& aReject), 228 (override)); 229 230 MOCK_METHOD( 231 void, SendGetDirectoryHandle, 232 (const FileSystemGetHandleRequest& request, 233 mozilla::ipc::ResolveCallback<FileSystemGetHandleResponse>&& aResolve, 234 mozilla::ipc::RejectCallback&& aReject), 235 (override)); 236 237 MOCK_METHOD( 238 void, SendGetFileHandle, 239 (const FileSystemGetHandleRequest& request, 240 mozilla::ipc::ResolveCallback<FileSystemGetHandleResponse>&& aResolve, 241 mozilla::ipc::RejectCallback&& aReject), 242 (override)); 243 244 MOCK_METHOD( 245 void, SendGetAccessHandle, 246 (const FileSystemGetAccessHandleRequest& request, 247 mozilla::ipc::ResolveCallback<FileSystemGetAccessHandleResponse>&& 248 aResolve, 249 mozilla::ipc::RejectCallback&& aReject), 250 (override)); 251 252 MOCK_METHOD( 253 void, SendGetWritable, 254 (const FileSystemGetWritableRequest& request, 255 mozilla::ipc::ResolveCallback<FileSystemGetWritableFileStreamResponse>&& 256 aResolve, 257 mozilla::ipc::RejectCallback&& aReject), 258 (override)); 259 260 MOCK_METHOD( 261 void, SendGetFile, 262 (const FileSystemGetFileRequest& request, 263 mozilla::ipc::ResolveCallback<FileSystemGetFileResponse>&& aResolve, 264 mozilla::ipc::RejectCallback&& aReject), 265 (override)); 266 267 MOCK_METHOD( 268 void, SendResolve, 269 (const FileSystemResolveRequest& request, 270 mozilla::ipc::ResolveCallback<FileSystemResolveResponse>&& aResolve, 271 mozilla::ipc::RejectCallback&& aReject), 272 (override)); 273 274 MOCK_METHOD( 275 void, SendGetEntries, 276 (const FileSystemGetEntriesRequest& request, 277 mozilla::ipc::ResolveCallback<FileSystemGetEntriesResponse>&& aResolve, 278 mozilla::ipc::RejectCallback&& aReject), 279 (override)); 280 281 MOCK_METHOD( 282 void, SendRemoveEntry, 283 (const FileSystemRemoveEntryRequest& request, 284 mozilla::ipc::ResolveCallback<FileSystemRemoveEntryResponse>&& aResolve, 285 mozilla::ipc::RejectCallback&& aReject), 286 (override)); 287 288 MOCK_METHOD(void, Shutdown, (), (override)); 289 290 protected: 291 virtual ~TestFileSystemManagerChild() = default; 292 }; 293 294 class TestFileSystemChildFactory final : public FileSystemChildFactory { 295 public: 296 explicit TestFileSystemChildFactory(TestFileSystemManagerChild* aChild) 297 : mChild(aChild) {} 298 299 already_AddRefed<FileSystemManagerChild> Create() const override { 300 return RefPtr<TestFileSystemManagerChild>(mChild).forget(); 301 } 302 303 ~TestFileSystemChildFactory() = default; 304 305 private: 306 TestFileSystemManagerChild* mChild; 307 }; 308 309 struct MockExpectMe { 310 MOCK_METHOD0(InvokeMe, void()); 311 312 template <class... Args> 313 void operator()(Args...) { 314 InvokeMe(); 315 } 316 }; 317 318 template <nsresult Expected> 319 struct NSErrorMatcher { 320 void operator()(nsresult aErr) { ASSERT_NSEQ(Expected, aErr); } 321 }; 322 323 struct FailOnCall { 324 template <class... Args> 325 void operator()(Args...) { 326 FAIL(); 327 } 328 }; 329 330 } // namespace test 331 } // namespace mozilla::dom::fs 332 333 #define MOCK_PROMISE_LISTENER(name, ...) \ 334 using name = mozilla::dom::fs::test::TestPromiseListener<__VA_ARGS__>; 335 336 MOCK_PROMISE_LISTENER( 337 ExpectNotImplemented, mozilla::dom::fs::test::FailOnCall, 338 mozilla::dom::fs::test::NSErrorMatcher<NS_ERROR_NOT_IMPLEMENTED>); 339 340 MOCK_PROMISE_LISTENER(ExpectResolveCalled, mozilla::dom::fs::test::MockExpectMe, 341 mozilla::dom::fs::test::FailOnCall); 342 343 #define MOCKGLOBALOBJECT_IID \ 344 {/* c0a93d91-9c15-49e1-abed-890b3679ac6e */ \ 345 0xc0a93d91, \ 346 0x9c15, \ 347 0x49e1, \ 348 {0xab, 0xed, 0x89, 0x0b, 0x36, 0x79, 0xac, 0x6e}} 349 350 class MockGlobalObject : public nsIGlobalObject, public nsWrapperCache { 351 public: 352 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 353 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(MockGlobalObject) 354 355 NS_INLINE_DECL_STATIC_IID(MOCKGLOBALOBJECT_IID) 356 357 explicit MockGlobalObject(nsCOMPtr<nsIGlobalObject>&& aGlobal) 358 : mGlobal(std::move(aGlobal)) {} 359 360 JSObject* GetGlobalJSObject() override { 361 return mGlobal->GetGlobalJSObject(); 362 } 363 364 JSObject* GetGlobalJSObjectPreserveColor() const override { 365 return mGlobal->GetGlobalJSObjectPreserveColor(); 366 } 367 368 MOCK_METHOD(JSObject*, WrapObject, 369 (JSContext * aCx, JS::Handle<JSObject*> aGivenProto), (override)); 370 371 MOCK_METHOD(nsICookieJarSettings*, GetCookieJarSettings, (), (override)); 372 373 MOCK_METHOD(nsIPrincipal*, PrincipalOrNull, (), (const)); 374 375 MOCK_METHOD(mozilla::StorageAccess, GetStorageAccess, (), (override)); 376 377 JS::loader::ModuleLoaderBase* GetModuleLoader(JSContext* aCx) override { 378 return mGlobal->GetModuleLoader(aCx); 379 } 380 381 bool ShouldResistFingerprinting(RFPTarget aTarget) const override { 382 return mGlobal->ShouldResistFingerprinting(std::move(aTarget)); 383 } 384 385 nsISerialEventTarget* SerialEventTarget() const override { 386 return mGlobal->SerialEventTarget(); 387 } 388 389 nsresult Dispatch(already_AddRefed<nsIRunnable>&& aRunnable) const override { 390 return mGlobal->Dispatch(std::move(aRunnable)); 391 } 392 393 mozilla::OriginTrials Trials() const override { return mGlobal->Trials(); } 394 395 protected: 396 ~MockGlobalObject() = default; 397 398 nsCOMPtr<nsIGlobalObject> mGlobal; 399 }; 400 401 #endif // DOM_FS_TEST_GTEST_FILESYSTEMMOCKS_H_