/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef DOM_FS_TEST_GTEST_FILESYSTEMMOCKS_H_ #define DOM_FS_TEST_GTEST_FILESYSTEMMOCKS_H_ #include // We don't have a mozilla shared pointer for pod types #include "TestHelpers.h" #include "fs/FileSystemChildFactory.h" #include "fs/FileSystemRequestHandler.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "js/Promise.h" #include "js/RootingAPI.h" #include "jsapi.h" #include "mozilla/ErrorResult.h" #include "mozilla/ScopeExit.h" #include "mozilla/UniquePtr.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/FileSystemManagerChild.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "nsIGlobalObject.h" #include "nsISupports.h" #include "nsISupportsImpl.h" #include "nsITimer.h" namespace mozilla::dom::fs { inline std::ostream& operator<<(std::ostream& aOut, const FileSystemEntryMetadata& aMetadata) { return aOut; } namespace test { nsIGlobalObject* GetGlobal(); nsresult GetAsString(const RefPtr& aPromise, nsAString& aString); mozilla::ipc::PrincipalInfo GetPrincipalInfo(); class MockFileSystemRequestHandler : public FileSystemRequestHandler { public: MOCK_METHOD(void, GetRootHandle, (RefPtr aManager, RefPtr aPromise, ErrorResult& aError), (override)); MOCK_METHOD(void, GetDirectoryHandle, (RefPtr & aManager, const FileSystemChildMetadata& aDirectory, bool aCreate, RefPtr aPromise, ErrorResult& aError), (override)); MOCK_METHOD(void, GetFileHandle, (RefPtr & aManager, const FileSystemChildMetadata& aFile, bool aCreate, RefPtr aPromise, ErrorResult& aError), (override)); MOCK_METHOD(void, GetFile, (RefPtr & aManager, const FileSystemEntryMetadata& aFile, RefPtr aPromise, ErrorResult& aError), (override)); MOCK_METHOD(void, GetEntries, (RefPtr & aManager, const EntryId& aDirectory, PageNumber aPage, RefPtr aPromise, RefPtr& aSink, ErrorResult& aError), (override)); MOCK_METHOD(void, RemoveEntry, (RefPtr & aManager, const FileSystemChildMetadata& aEntry, bool aRecursive, RefPtr aPromise, ErrorResult& aError), (override)); MOCK_METHOD(void, MoveEntry, (RefPtr & aManager, FileSystemHandle* aHandle, FileSystemEntryMetadata* const aEntry, const FileSystemChildMetadata& aNewEntry, RefPtr aPromise, ErrorResult& aError), (override)); MOCK_METHOD(void, RenameEntry, (RefPtr & aManager, FileSystemHandle* aHandle, FileSystemEntryMetadata* const aEntry, const Name& aName, RefPtr aPromise, ErrorResult& aError), (override)); MOCK_METHOD(void, Resolve, (RefPtr & aManager, const FileSystemEntryPair& aEndpoints, RefPtr aPromise, ErrorResult& aError), (override)); }; class WaitablePromiseListener { public: NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING virtual void ClearDone() = 0; virtual bool IsDone() const = 0; virtual PromiseNativeHandler* AsHandler() = 0; protected: virtual ~WaitablePromiseListener() = default; }; template class TestPromiseListener : public PromiseNativeHandler, public WaitablePromiseListener { public: TestPromiseListener() : mIsDone(std::make_shared(false)), mOnSuccess(), mOnError() { ClearDone(); } // nsISupports implementation NS_IMETHODIMP QueryInterface(REFNSIID aIID, void** aInstancePtr) override { nsresult rv = NS_ERROR_UNEXPECTED; NS_INTERFACE_TABLE0(TestPromiseListener) return rv; } NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestPromiseListener, override) // PromiseNativeHandler implementation void ResolvedCallback(JSContext* aCx, JS::Handle aValue, ErrorResult& aError) override { mozilla::ScopeExit flagAsDone([isDone = mIsDone, timer = mTimer] { timer->Cancel(); *isDone = true; }); mOnSuccess(); } void RejectedCallback(JSContext* aCx, JS::Handle aValue, ErrorResult& aError) override { mozilla::ScopeExit flagAsDone([isDone = mIsDone, timer = mTimer] { timer->Cancel(); *isDone = true; }); if (aValue.isInt32()) { mOnError(static_cast(aValue.toInt32())); return; } ASSERT_TRUE(aValue.isObject()); JS::Rooted exceptionObject(aCx, &aValue.toObject()); RefPtr exception; UNWRAP_OBJECT(Exception, exceptionObject, exception); if (exception) { mOnError(static_cast(exception->Result())); return; } } // WaitablePromiseListener implementation void ClearDone() override { *mIsDone = false; if (mTimer) { mTimer->Cancel(); } auto timerCallback = [isDone = mIsDone](nsITimer* aTimer) { *isDone = true; FAIL() << "Timed out!"; }; const char* timerName = "fs::TestPromiseListener::ClearDone"; auto res = NS_NewTimerWithCallback(timerCallback, MilliSeconds, nsITimer::TYPE_ONE_SHOT, timerName); if (res.isOk()) { mTimer = res.unwrap(); } } bool IsDone() const override { return *mIsDone; } PromiseNativeHandler* AsHandler() override { return this; } SuccessHandler& GetSuccessHandler() { return mOnSuccess; } SuccessHandler& GetErrorHandler() { return mOnError; } protected: virtual ~TestPromiseListener() = default; std::shared_ptr mIsDone; // We pass this to a callback nsCOMPtr mTimer; SuccessHandler mOnSuccess; ErrorHandler mOnError; }; class TestFileSystemManagerChild : public FileSystemManagerChild { public: MOCK_METHOD(void, SendGetRootHandle, (mozilla::ipc::ResolveCallback && aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendGetDirectoryHandle, (const FileSystemGetHandleRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendGetFileHandle, (const FileSystemGetHandleRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendGetAccessHandle, (const FileSystemGetAccessHandleRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendGetWritable, (const FileSystemGetWritableRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendGetFile, (const FileSystemGetFileRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendResolve, (const FileSystemResolveRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendGetEntries, (const FileSystemGetEntriesRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD( void, SendRemoveEntry, (const FileSystemRemoveEntryRequest& request, mozilla::ipc::ResolveCallback&& aResolve, mozilla::ipc::RejectCallback&& aReject), (override)); MOCK_METHOD(void, Shutdown, (), (override)); protected: virtual ~TestFileSystemManagerChild() = default; }; class TestFileSystemChildFactory final : public FileSystemChildFactory { public: explicit TestFileSystemChildFactory(TestFileSystemManagerChild* aChild) : mChild(aChild) {} already_AddRefed Create() const override { return RefPtr(mChild).forget(); } ~TestFileSystemChildFactory() = default; private: TestFileSystemManagerChild* mChild; }; struct MockExpectMe { MOCK_METHOD0(InvokeMe, void()); template void operator()(Args...) { InvokeMe(); } }; template struct NSErrorMatcher { void operator()(nsresult aErr) { ASSERT_NSEQ(Expected, aErr); } }; struct FailOnCall { template void operator()(Args...) { FAIL(); } }; } // namespace test } // namespace mozilla::dom::fs #define MOCK_PROMISE_LISTENER(name, ...) \ using name = mozilla::dom::fs::test::TestPromiseListener<__VA_ARGS__>; MOCK_PROMISE_LISTENER( ExpectNotImplemented, mozilla::dom::fs::test::FailOnCall, mozilla::dom::fs::test::NSErrorMatcher); MOCK_PROMISE_LISTENER(ExpectResolveCalled, mozilla::dom::fs::test::MockExpectMe, mozilla::dom::fs::test::FailOnCall); #endif // DOM_FS_TEST_GTEST_FILESYSTEMMOCKS_H_