summaryrefslogtreecommitdiffstats
path: root/dom/quota/test/gtest/TestQuotaCommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/quota/test/gtest/TestQuotaCommon.cpp')
-rw-r--r--dom/quota/test/gtest/TestQuotaCommon.cpp2171
1 files changed, 2171 insertions, 0 deletions
diff --git a/dom/quota/test/gtest/TestQuotaCommon.cpp b/dom/quota/test/gtest/TestQuotaCommon.cpp
new file mode 100644
index 0000000000..c1a047a533
--- /dev/null
+++ b/dom/quota/test/gtest/TestQuotaCommon.cpp
@@ -0,0 +1,2171 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/quota/QuotaCommon.h"
+
+#include "gtest/gtest.h"
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <new>
+#include <ostream>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#include "ErrorList.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Result.h"
+#include "mozilla/ResultExtensions.h"
+#include "mozilla/ResultVariant.h"
+#include "mozilla/Unused.h"
+#include "mozilla/fallible.h"
+#include "mozilla/dom/quota/QuotaTestParent.h"
+#include "mozilla/dom/quota/ResultExtensions.h"
+#include "nsCOMPtr.h"
+#include "nsLiteralString.h"
+#include "nsString.h"
+#include "nsStringFwd.h"
+#include "nsTLiteralString.h"
+
+class nsISupports;
+
+using namespace mozilla;
+using namespace mozilla::dom::quota;
+
+mozilla::ipc::IPCResult QuotaTestParent::RecvTry_Success_CustomErr_QmIpcFail(
+ bool* aTryDidNotReturn) {
+ QM_TRY(MOZ_TO_RESULT(NS_OK), QM_IPC_FAIL(this));
+
+ *aTryDidNotReturn = true;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult QuotaTestParent::RecvTry_Success_CustomErr_IpcFail(
+ bool* aTryDidNotReturn) {
+ QM_TRY(MOZ_TO_RESULT(NS_OK), IPC_FAIL(this, "Custom why"));
+
+ *aTryDidNotReturn = true;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+QuotaTestParent::RecvTryInspect_Success_CustomErr_QmIpcFail(
+ bool* aTryDidNotReturn) {
+ QM_TRY_INSPECT(const auto& x, (mozilla::Result<int32_t, nsresult>{42}),
+ QM_IPC_FAIL(this));
+ Unused << x;
+
+ *aTryDidNotReturn = true;
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+QuotaTestParent::RecvTryInspect_Success_CustomErr_IpcFail(
+ bool* aTryDidNotReturn) {
+ QM_TRY_INSPECT(const auto& x, (mozilla::Result<int32_t, nsresult>{42}),
+ IPC_FAIL(this, "Custom why"));
+ Unused << x;
+
+ *aTryDidNotReturn = true;
+
+ return IPC_OK();
+}
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+
+TEST(QuotaCommon_Try, Success)
+{
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&tryDidNotReturn]() -> nsresult {
+ QM_TRY(MOZ_TO_RESULT(NS_OK));
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_Try, Success_CustomErr_QmIpcFail)
+{
+ auto foo = MakeRefPtr<QuotaTestParent>();
+
+ bool tryDidNotReturn = false;
+
+ auto res = foo->RecvTry_Success_CustomErr_QmIpcFail(&tryDidNotReturn);
+
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_TRUE(res);
+}
+
+TEST(QuotaCommon_Try, Success_CustomErr_IpcFail)
+{
+ auto foo = MakeRefPtr<QuotaTestParent>();
+
+ bool tryDidNotReturn = false;
+
+ auto res = foo->RecvTry_Success_CustomErr_IpcFail(&tryDidNotReturn);
+
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_TRUE(res);
+}
+
+#ifdef DEBUG
+TEST(QuotaCommon_Try, Success_CustomErr_AssertUnreachable)
+{
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&tryDidNotReturn]() -> nsresult {
+ QM_TRY(MOZ_TO_RESULT(NS_OK), QM_ASSERT_UNREACHABLE);
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_Try, Success_NoErr_AssertUnreachable)
+{
+ bool tryDidNotReturn = false;
+
+ [&tryDidNotReturn]() -> void {
+ QM_TRY(MOZ_TO_RESULT(NS_OK), QM_ASSERT_UNREACHABLE_VOID);
+
+ tryDidNotReturn = true;
+ }();
+
+ EXPECT_TRUE(tryDidNotReturn);
+}
+#else
+# if defined(QM_ASSERT_UNREACHABLE) || defined(QM_ASSERT_UNREACHABLE_VOID)
+#error QM_ASSERT_UNREACHABLE and QM_ASSERT_UNREACHABLE_VOID should not be defined.
+# endif
+#endif
+
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+TEST(QuotaCommon_Try, Success_CustomErr_DiagnosticAssertUnreachable)
+{
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&tryDidNotReturn]() -> nsresult {
+ QM_TRY(MOZ_TO_RESULT(NS_OK), QM_DIAGNOSTIC_ASSERT_UNREACHABLE);
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_Try, Success_NoErr_DiagnosticAssertUnreachable)
+{
+ bool tryDidNotReturn = false;
+
+ [&tryDidNotReturn]() -> void {
+ QM_TRY(MOZ_TO_RESULT(NS_OK), QM_DIAGNOSTIC_ASSERT_UNREACHABLE_VOID);
+
+ tryDidNotReturn = true;
+ }();
+
+ EXPECT_TRUE(tryDidNotReturn);
+}
+#else
+# if defined(QM_DIAGNOSTIC_ASSERT_UNREACHABLE) || \
+ defined(QM_DIAGNOSTIC_ASSERT_UNREACHABLE_VOID)
+#error QM_DIAGNOSTIC_ASSERT_UNREACHABLE and QM_DIAGNOSTIC_ASSERT_UNREACHABLE_VOID should not be defined.
+# endif
+#endif
+
+TEST(QuotaCommon_Try, Success_CustomErr_CustomLambda)
+{
+#define SUBTEST(...) \
+ { \
+ bool tryDidNotReturn = false; \
+ \
+ nsresult rv = [&tryDidNotReturn]() -> nsresult { \
+ QM_TRY(MOZ_TO_RESULT(NS_OK), [](__VA_ARGS__) { return aRv; }); \
+ \
+ tryDidNotReturn = true; \
+ \
+ return NS_OK; \
+ }(); \
+ \
+ EXPECT_TRUE(tryDidNotReturn); \
+ EXPECT_EQ(rv, NS_OK); \
+ }
+
+ SUBTEST(const char*, nsresult aRv);
+ SUBTEST(nsresult aRv);
+
+#undef SUBTEST
+}
+
+TEST(QuotaCommon_Try, Success_WithCleanup)
+{
+ bool tryCleanupRan = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&tryCleanupRan, &tryDidNotReturn]() -> nsresult {
+ QM_TRY(MOZ_TO_RESULT(NS_OK), QM_PROPAGATE,
+ [&tryCleanupRan](const auto&) { tryCleanupRan = true; });
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(tryCleanupRan);
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_Try, Failure_PropagateErr)
+{
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&tryDidNotReturn]() -> nsresult {
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE));
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_Try, Failure_CustomErr)
+{
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&tryDidNotReturn]() -> nsresult {
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE), NS_ERROR_UNEXPECTED);
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_Try, Failure_CustomErr_CustomLambda)
+{
+#define SUBTEST(...) \
+ { \
+ bool tryDidNotReturn = false; \
+ \
+ nsresult rv = [&tryDidNotReturn]() -> nsresult { \
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE), \
+ [](__VA_ARGS__) { return NS_ERROR_UNEXPECTED; }); \
+ \
+ tryDidNotReturn = true; \
+ \
+ return NS_OK; \
+ }(); \
+ \
+ EXPECT_FALSE(tryDidNotReturn); \
+ EXPECT_EQ(rv, NS_ERROR_UNEXPECTED); \
+ }
+
+ SUBTEST(const char* aFunc, nsresult);
+ SUBTEST(nsresult rv);
+
+#undef SUBTEST
+}
+
+TEST(QuotaCommon_Try, Failure_NoErr)
+{
+ bool tryDidNotReturn = false;
+
+ [&tryDidNotReturn]() -> void {
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE), QM_VOID);
+
+ tryDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryDidNotReturn);
+}
+
+TEST(QuotaCommon_Try, Failure_WithCleanup)
+{
+ bool tryCleanupRan = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&tryCleanupRan, &tryDidNotReturn]() -> nsresult {
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE), QM_PROPAGATE,
+ [&tryCleanupRan](const auto& result) {
+ EXPECT_EQ(result, NS_ERROR_FAILURE);
+
+ tryCleanupRan = true;
+ });
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(tryCleanupRan);
+ EXPECT_FALSE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_Try, Failure_WithCleanup_UnwrapErr)
+{
+ bool tryCleanupRan = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv;
+
+ [&tryCleanupRan, &tryDidNotReturn](nsresult& aRv) -> void {
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE), QM_VOID,
+ ([&tryCleanupRan, &aRv](auto& result) {
+ EXPECT_EQ(result, NS_ERROR_FAILURE);
+
+ aRv = result;
+
+ tryCleanupRan = true;
+ }));
+
+ tryDidNotReturn = true;
+
+ aRv = NS_OK;
+ }(rv);
+
+ EXPECT_TRUE(tryCleanupRan);
+ EXPECT_FALSE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_Try, SameLine)
+{
+ // clang-format off
+ QM_TRY(MOZ_TO_RESULT(NS_OK), QM_VOID); QM_TRY(MOZ_TO_RESULT(NS_OK), QM_VOID);
+ // clang-format on
+}
+
+TEST(QuotaCommon_Try, NestingMadness_Success)
+{
+ bool nestedTryDidNotReturn = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&nestedTryDidNotReturn, &tryDidNotReturn]() -> nsresult {
+ QM_TRY(([&nestedTryDidNotReturn]() -> Result<Ok, nsresult> {
+ QM_TRY(MOZ_TO_RESULT(NS_OK));
+
+ nestedTryDidNotReturn = true;
+
+ return Ok();
+ }()));
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(nestedTryDidNotReturn);
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_Try, NestingMadness_Failure)
+{
+ bool nestedTryDidNotReturn = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&nestedTryDidNotReturn, &tryDidNotReturn]() -> nsresult {
+ QM_TRY(([&nestedTryDidNotReturn]() -> Result<Ok, nsresult> {
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE));
+
+ nestedTryDidNotReturn = true;
+
+ return Ok();
+ }()));
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(nestedTryDidNotReturn);
+ EXPECT_FALSE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_Try, NestingMadness_Multiple_Success)
+{
+ bool nestedTry1DidNotReturn = false;
+ bool nestedTry2DidNotReturn = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&nestedTry1DidNotReturn, &nestedTry2DidNotReturn,
+ &tryDidNotReturn]() -> nsresult {
+ QM_TRY(([&nestedTry1DidNotReturn,
+ &nestedTry2DidNotReturn]() -> Result<Ok, nsresult> {
+ QM_TRY(MOZ_TO_RESULT(NS_OK));
+
+ nestedTry1DidNotReturn = true;
+
+ QM_TRY(MOZ_TO_RESULT(NS_OK));
+
+ nestedTry2DidNotReturn = true;
+
+ return Ok();
+ }()));
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(nestedTry1DidNotReturn);
+ EXPECT_TRUE(nestedTry2DidNotReturn);
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_Try, NestingMadness_Multiple_Failure1)
+{
+ bool nestedTry1DidNotReturn = false;
+ bool nestedTry2DidNotReturn = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&nestedTry1DidNotReturn, &nestedTry2DidNotReturn,
+ &tryDidNotReturn]() -> nsresult {
+ QM_TRY(([&nestedTry1DidNotReturn,
+ &nestedTry2DidNotReturn]() -> Result<Ok, nsresult> {
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE));
+
+ nestedTry1DidNotReturn = true;
+
+ QM_TRY(MOZ_TO_RESULT(NS_OK));
+
+ nestedTry2DidNotReturn = true;
+
+ return Ok();
+ }()));
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(nestedTry1DidNotReturn);
+ EXPECT_FALSE(nestedTry2DidNotReturn);
+ EXPECT_FALSE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_Try, NestingMadness_Multiple_Failure2)
+{
+ bool nestedTry1DidNotReturn = false;
+ bool nestedTry2DidNotReturn = false;
+ bool tryDidNotReturn = false;
+
+ nsresult rv = [&nestedTry1DidNotReturn, &nestedTry2DidNotReturn,
+ &tryDidNotReturn]() -> nsresult {
+ QM_TRY(([&nestedTry1DidNotReturn,
+ &nestedTry2DidNotReturn]() -> Result<Ok, nsresult> {
+ QM_TRY(MOZ_TO_RESULT(NS_OK));
+
+ nestedTry1DidNotReturn = true;
+
+ QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE));
+
+ nestedTry2DidNotReturn = true;
+
+ return Ok();
+ }()));
+
+ tryDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(nestedTry1DidNotReturn);
+ EXPECT_FALSE(nestedTry2DidNotReturn);
+ EXPECT_FALSE(tryDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryInspect, Success)
+{
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(const auto& x, (Result<int32_t, nsresult>{42}));
+ EXPECT_EQ(x, 42);
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_TryInspect, Success_CustomErr_QmIpcFail)
+{
+ auto foo = MakeRefPtr<QuotaTestParent>();
+
+ bool tryDidNotReturn = false;
+
+ auto res = foo->RecvTryInspect_Success_CustomErr_QmIpcFail(&tryDidNotReturn);
+
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_TRUE(res);
+}
+
+TEST(QuotaCommon_TryInspect, Success_CustomErr_IpcFail)
+{
+ auto foo = MakeRefPtr<QuotaTestParent>();
+
+ bool tryDidNotReturn = false;
+
+ auto res = foo->RecvTryInspect_Success_CustomErr_IpcFail(&tryDidNotReturn);
+
+ EXPECT_TRUE(tryDidNotReturn);
+ EXPECT_TRUE(res);
+}
+
+#ifdef DEBUG
+TEST(QuotaCommon_TryInspect, Success_CustomErr_AssertUnreachable)
+{
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(const auto& x, (Result<int32_t, nsresult>{42}),
+ QM_ASSERT_UNREACHABLE);
+ EXPECT_EQ(x, 42);
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_TryInspect, Success_NoErr_AssertUnreachable)
+{
+ bool tryInspectDidNotReturn = false;
+
+ [&tryInspectDidNotReturn]() -> void {
+ QM_TRY_INSPECT(const auto& x, (Result<int32_t, nsresult>{42}),
+ QM_ASSERT_UNREACHABLE_VOID);
+ EXPECT_EQ(x, 42);
+
+ tryInspectDidNotReturn = true;
+ }();
+
+ EXPECT_TRUE(tryInspectDidNotReturn);
+}
+#endif
+
+TEST(QuotaCommon_TryInspect, Success_CustomErr_CustomLambda)
+{
+#define SUBTEST(...) \
+ { \
+ bool tryInspectDidNotReturn = false; \
+ \
+ nsresult rv = [&tryInspectDidNotReturn]() -> nsresult { \
+ QM_TRY_INSPECT(const auto& x, (Result<int32_t, nsresult>{42}), \
+ [](__VA_ARGS__) { return aRv; }); \
+ EXPECT_EQ(x, 42); \
+ \
+ tryInspectDidNotReturn = true; \
+ \
+ return NS_OK; \
+ }(); \
+ \
+ EXPECT_TRUE(tryInspectDidNotReturn); \
+ EXPECT_EQ(rv, NS_OK); \
+ }
+
+ SUBTEST(const char*, nsresult aRv);
+ SUBTEST(nsresult aRv);
+
+#undef SUBTEST
+}
+
+TEST(QuotaCommon_TryInspect, Success_WithCleanup)
+{
+ bool tryInspectCleanupRan = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&tryInspectCleanupRan, &tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(
+ const auto& x, (Result<int32_t, nsresult>{42}), QM_PROPAGATE,
+ [&tryInspectCleanupRan](const auto&) { tryInspectCleanupRan = true; });
+ EXPECT_EQ(x, 42);
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(tryInspectCleanupRan);
+ EXPECT_TRUE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_TryInspect, Failure_PropagateErr)
+{
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(const auto& x,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}));
+ Unused << x;
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryInspect, Failure_CustomErr)
+{
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(const auto& x,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}),
+ NS_ERROR_UNEXPECTED);
+ Unused << x;
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_TryInspect, Failure_CustomErr_CustomLambda)
+{
+#define SUBTEST(...) \
+ { \
+ bool tryInspectDidNotReturn = false; \
+ \
+ nsresult rv = [&tryInspectDidNotReturn]() -> nsresult { \
+ QM_TRY_INSPECT(const auto& x, \
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}), \
+ [](__VA_ARGS__) { return NS_ERROR_UNEXPECTED; }); \
+ Unused << x; \
+ \
+ tryInspectDidNotReturn = true; \
+ \
+ return NS_OK; \
+ }(); \
+ \
+ EXPECT_FALSE(tryInspectDidNotReturn); \
+ EXPECT_EQ(rv, NS_ERROR_UNEXPECTED); \
+ }
+
+ SUBTEST(const char*, nsresult);
+ SUBTEST(nsresult);
+
+#undef SUBTEST
+}
+
+TEST(QuotaCommon_TryInspect, Failure_NoErr)
+{
+ bool tryInspectDidNotReturn = false;
+
+ [&tryInspectDidNotReturn]() -> void {
+ QM_TRY_INSPECT(const auto& x,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}), QM_VOID);
+ Unused << x;
+
+ tryInspectDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryInspectDidNotReturn);
+}
+
+TEST(QuotaCommon_TryInspect, Failure_WithCleanup)
+{
+ bool tryInspectCleanupRan = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&tryInspectCleanupRan, &tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(const auto& x,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}),
+ QM_PROPAGATE, [&tryInspectCleanupRan](const auto& result) {
+ EXPECT_EQ(result, NS_ERROR_FAILURE);
+
+ tryInspectCleanupRan = true;
+ });
+ Unused << x;
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(tryInspectCleanupRan);
+ EXPECT_FALSE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryInspect, Failure_WithCleanup_UnwrapErr)
+{
+ bool tryInspectCleanupRan = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv;
+
+ [&tryInspectCleanupRan, &tryInspectDidNotReturn](nsresult& aRv) -> void {
+ QM_TRY_INSPECT(const auto& x,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}), QM_VOID,
+ ([&tryInspectCleanupRan, &aRv](auto& result) {
+ EXPECT_EQ(result, NS_ERROR_FAILURE);
+
+ aRv = result;
+
+ tryInspectCleanupRan = true;
+ }));
+ Unused << x;
+
+ tryInspectDidNotReturn = true;
+
+ aRv = NS_OK;
+ }(rv);
+
+ EXPECT_TRUE(tryInspectCleanupRan);
+ EXPECT_FALSE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryInspect, ConstDecl)
+{
+ QM_TRY_INSPECT(const int32_t& x, (Result<int32_t, nsresult>{42}), QM_VOID);
+
+ static_assert(std::is_same_v<decltype(x), const int32_t&>);
+
+ EXPECT_EQ(x, 42);
+}
+
+TEST(QuotaCommon_TryInspect, SameScopeDecl)
+{
+ QM_TRY_INSPECT(const int32_t& x, (Result<int32_t, nsresult>{42}), QM_VOID);
+ EXPECT_EQ(x, 42);
+
+ QM_TRY_INSPECT(const int32_t& y, (Result<int32_t, nsresult>{42}), QM_VOID);
+ EXPECT_EQ(y, 42);
+}
+
+TEST(QuotaCommon_TryInspect, SameLine)
+{
+ // clang-format off
+ QM_TRY_INSPECT(const auto &x, (Result<int32_t, nsresult>{42}), QM_VOID); QM_TRY_INSPECT(const auto &y, (Result<int32_t, nsresult>{42}), QM_VOID);
+ // clang-format on
+
+ EXPECT_EQ(x, 42);
+ EXPECT_EQ(y, 42);
+}
+
+TEST(QuotaCommon_TryInspect, NestingMadness_Success)
+{
+ bool nestedTryInspectDidNotReturn = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&nestedTryInspectDidNotReturn,
+ &tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(
+ const auto& x,
+ ([&nestedTryInspectDidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_INSPECT(const auto& x, (Result<int32_t, nsresult>{42}));
+
+ nestedTryInspectDidNotReturn = true;
+
+ return x;
+ }()));
+ EXPECT_EQ(x, 42);
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(nestedTryInspectDidNotReturn);
+ EXPECT_TRUE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_TryInspect, NestingMadness_Failure)
+{
+ bool nestedTryInspectDidNotReturn = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&nestedTryInspectDidNotReturn,
+ &tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(
+ const auto& x,
+ ([&nestedTryInspectDidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_INSPECT(const auto& x,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}));
+
+ nestedTryInspectDidNotReturn = true;
+
+ return x;
+ }()));
+ Unused << x;
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(nestedTryInspectDidNotReturn);
+ EXPECT_FALSE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryInspect, NestingMadness_Multiple_Success)
+{
+ bool nestedTryInspect1DidNotReturn = false;
+ bool nestedTryInspect2DidNotReturn = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&nestedTryInspect1DidNotReturn, &nestedTryInspect2DidNotReturn,
+ &tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(
+ const auto& z,
+ ([&nestedTryInspect1DidNotReturn,
+ &nestedTryInspect2DidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_INSPECT(const auto& x, (Result<int32_t, nsresult>{42}));
+
+ nestedTryInspect1DidNotReturn = true;
+
+ QM_TRY_INSPECT(const auto& y, (Result<int32_t, nsresult>{42}));
+
+ nestedTryInspect2DidNotReturn = true;
+
+ return x + y;
+ }()));
+ EXPECT_EQ(z, 84);
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(nestedTryInspect1DidNotReturn);
+ EXPECT_TRUE(nestedTryInspect2DidNotReturn);
+ EXPECT_TRUE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_OK);
+}
+
+TEST(QuotaCommon_TryInspect, NestingMadness_Multiple_Failure1)
+{
+ bool nestedTryInspect1DidNotReturn = false;
+ bool nestedTryInspect2DidNotReturn = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&nestedTryInspect1DidNotReturn, &nestedTryInspect2DidNotReturn,
+ &tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(
+ const auto& z,
+ ([&nestedTryInspect1DidNotReturn,
+ &nestedTryInspect2DidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_INSPECT(const auto& x,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}));
+
+ nestedTryInspect1DidNotReturn = true;
+
+ QM_TRY_INSPECT(const auto& y, (Result<int32_t, nsresult>{42}));
+
+ nestedTryInspect2DidNotReturn = true;
+
+ return x + y;
+ }()));
+ Unused << z;
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(nestedTryInspect1DidNotReturn);
+ EXPECT_FALSE(nestedTryInspect2DidNotReturn);
+ EXPECT_FALSE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryInspect, NestingMadness_Multiple_Failure2)
+{
+ bool nestedTryInspect1DidNotReturn = false;
+ bool nestedTryInspect2DidNotReturn = false;
+ bool tryInspectDidNotReturn = false;
+
+ nsresult rv = [&nestedTryInspect1DidNotReturn, &nestedTryInspect2DidNotReturn,
+ &tryInspectDidNotReturn]() -> nsresult {
+ QM_TRY_INSPECT(
+ const auto& z,
+ ([&nestedTryInspect1DidNotReturn,
+ &nestedTryInspect2DidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_INSPECT(const auto& x, (Result<int32_t, nsresult>{42}));
+
+ nestedTryInspect1DidNotReturn = true;
+
+ QM_TRY_INSPECT(const auto& y,
+ (Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}));
+
+ nestedTryInspect2DidNotReturn = true;
+
+ return x + y;
+ }()));
+ Unused << z;
+
+ tryInspectDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(nestedTryInspect1DidNotReturn);
+ EXPECT_FALSE(nestedTryInspect2DidNotReturn);
+ EXPECT_FALSE(tryInspectDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+// We are not repeating all QM_TRY_INSPECT test cases for QM_TRY_UNWRAP, since
+// they are largely based on the same implementation. We just add some where
+// inspecting and unwrapping differ.
+
+TEST(QuotaCommon_TryUnwrap, NonConstDecl)
+{
+ QM_TRY_UNWRAP(int32_t x, (Result<int32_t, nsresult>{42}), QM_VOID);
+
+ static_assert(std::is_same_v<decltype(x), int32_t>);
+
+ EXPECT_EQ(x, 42);
+}
+
+TEST(QuotaCommon_TryUnwrap, RvalueDecl)
+{
+ QM_TRY_UNWRAP(int32_t && x, (Result<int32_t, nsresult>{42}), QM_VOID);
+
+ static_assert(std::is_same_v<decltype(x), int32_t&&>);
+
+ EXPECT_EQ(x, 42);
+}
+
+TEST(QuotaCommon_TryUnwrap, ParenDecl)
+{
+ QM_TRY_UNWRAP(
+ (auto&& [x, y]),
+ (Result<std::pair<int32_t, bool>, nsresult>{std::pair{42, true}}),
+ QM_VOID);
+
+ static_assert(std::is_same_v<decltype(x), int32_t>);
+ static_assert(std::is_same_v<decltype(y), bool>);
+
+ EXPECT_EQ(x, 42);
+ EXPECT_EQ(y, true);
+}
+
+TEST(QuotaCommon_TryReturn, Success)
+{
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnDidNotReturn] {
+ QM_TRY_RETURN((Result<int32_t, nsresult>{42}));
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), 42);
+}
+
+TEST(QuotaCommon_TryReturn, Success_nsresult)
+{
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnDidNotReturn] {
+ QM_TRY_RETURN(MOZ_TO_RESULT(NS_OK));
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isOk());
+}
+
+#ifdef DEBUG
+TEST(QuotaCommon_TryReturn, Success_CustomErr_AssertUnreachable)
+{
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnDidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_RETURN((Result<int32_t, nsresult>{42}), QM_ASSERT_UNREACHABLE);
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), 42);
+}
+#endif
+
+TEST(QuotaCommon_TryReturn, Success_CustomErr_CustomLambda)
+{
+#define SUBTEST(...) \
+ { \
+ bool tryReturnDidNotReturn = false; \
+ \
+ auto res = [&tryReturnDidNotReturn]() -> Result<Ok, nsresult> { \
+ QM_TRY_RETURN(MOZ_TO_RESULT(NS_OK), \
+ [](__VA_ARGS__) { return Err(aRv); }); \
+ \
+ tryReturnDidNotReturn = true; \
+ }(); \
+ \
+ EXPECT_FALSE(tryReturnDidNotReturn); \
+ EXPECT_TRUE(res.isOk()); \
+ }
+
+ SUBTEST(const char*, nsresult aRv);
+ SUBTEST(nsresult aRv);
+
+#undef SUBTEST
+}
+
+TEST(QuotaCommon_TryReturn, Success_WithCleanup)
+{
+ bool tryReturnCleanupRan = false;
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnCleanupRan,
+ &tryReturnDidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_RETURN(
+ (Result<int32_t, nsresult>{42}), QM_PROPAGATE,
+ [&tryReturnCleanupRan](const auto&) { tryReturnCleanupRan = true; });
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryReturnCleanupRan);
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), 42);
+}
+
+TEST(QuotaCommon_TryReturn, Failure_PropagateErr)
+{
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnDidNotReturn] {
+ QM_TRY_RETURN((Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}));
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryReturn, Failure_PropagateErr_nsresult)
+{
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnDidNotReturn] {
+ QM_TRY_RETURN(MOZ_TO_RESULT(NS_ERROR_FAILURE));
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryReturn, Failure_CustomErr)
+{
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnDidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_RETURN((Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}),
+ Err(NS_ERROR_UNEXPECTED));
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_TryReturn, Failure_CustomErr_CustomLambda)
+{
+#define SUBTEST(...) \
+ { \
+ bool tryReturnDidNotReturn = false; \
+ \
+ auto res = [&tryReturnDidNotReturn]() -> Result<int32_t, nsresult> { \
+ QM_TRY_RETURN((Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}), \
+ [](__VA_ARGS__) { return Err(NS_ERROR_UNEXPECTED); }); \
+ \
+ tryReturnDidNotReturn = true; \
+ }(); \
+ \
+ EXPECT_FALSE(tryReturnDidNotReturn); \
+ EXPECT_TRUE(res.isErr()); \
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED); \
+ }
+
+ SUBTEST(const char*, nsresult);
+ SUBTEST(nsresult);
+
+#undef SUBTEST
+}
+
+TEST(QuotaCommon_TryReturn, Failure_WithCleanup)
+{
+ bool tryReturnCleanupRan = false;
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&tryReturnCleanupRan,
+ &tryReturnDidNotReturn]() -> Result<int32_t, nsresult> {
+ QM_TRY_RETURN((Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}),
+ QM_PROPAGATE, [&tryReturnCleanupRan](const auto& result) {
+ EXPECT_EQ(result, NS_ERROR_FAILURE);
+
+ tryReturnCleanupRan = true;
+ });
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_TRUE(tryReturnCleanupRan);
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_TryReturn, SameLine)
+{
+ // clang-format off
+ auto res1 = [] { QM_TRY_RETURN((Result<int32_t, nsresult>{42})); }(); auto res2 = []() -> Result<int32_t, nsresult> { QM_TRY_RETURN((Result<int32_t, nsresult>{42})); }();
+ // clang-format on
+
+ EXPECT_TRUE(res1.isOk());
+ EXPECT_EQ(res1.unwrap(), 42);
+ EXPECT_TRUE(res2.isOk());
+ EXPECT_EQ(res2.unwrap(), 42);
+}
+
+TEST(QuotaCommon_TryReturn, NestingMadness_Success)
+{
+ bool nestedTryReturnDidNotReturn = false;
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&nestedTryReturnDidNotReturn, &tryReturnDidNotReturn] {
+ QM_TRY_RETURN(([&nestedTryReturnDidNotReturn] {
+ QM_TRY_RETURN((Result<int32_t, nsresult>{42}));
+
+ nestedTryReturnDidNotReturn = true;
+ }()));
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(nestedTryReturnDidNotReturn);
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), 42);
+}
+
+TEST(QuotaCommon_TryReturn, NestingMadness_Failure)
+{
+ bool nestedTryReturnDidNotReturn = false;
+ bool tryReturnDidNotReturn = false;
+
+ auto res = [&nestedTryReturnDidNotReturn, &tryReturnDidNotReturn] {
+ QM_TRY_RETURN(([&nestedTryReturnDidNotReturn] {
+ QM_TRY_RETURN((Result<int32_t, nsresult>{Err(NS_ERROR_FAILURE)}));
+
+ nestedTryReturnDidNotReturn = true;
+ }()));
+
+ tryReturnDidNotReturn = true;
+ }();
+
+ EXPECT_FALSE(nestedTryReturnDidNotReturn);
+ EXPECT_FALSE(tryReturnDidNotReturn);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_Fail, ReturnValue)
+{
+ bool failDidNotReturn = false;
+
+ nsresult rv = [&failDidNotReturn]() -> nsresult {
+ QM_FAIL(NS_ERROR_FAILURE);
+
+ failDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_FALSE(failDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_Fail, ReturnValue_WithCleanup)
+{
+ bool failCleanupRan = false;
+ bool failDidNotReturn = false;
+
+ nsresult rv = [&failCleanupRan, &failDidNotReturn]() -> nsresult {
+ QM_FAIL(NS_ERROR_FAILURE, [&failCleanupRan]() { failCleanupRan = true; });
+
+ failDidNotReturn = true;
+
+ return NS_OK;
+ }();
+
+ EXPECT_TRUE(failCleanupRan);
+ EXPECT_FALSE(failDidNotReturn);
+ EXPECT_EQ(rv, NS_ERROR_FAILURE);
+}
+
+TEST(QuotaCommon_WarnOnlyTry, Success)
+{
+ bool warnOnlyTryDidNotReturn = false;
+
+ const auto res =
+ [&warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY(OkIf(true));
+
+ warnOnlyTryDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(warnOnlyTryDidNotReturn);
+}
+
+TEST(QuotaCommon_WarnOnlyTry, Success_WithCleanup)
+{
+ bool warnOnlyTryCleanupRan = false;
+ bool warnOnlyTryDidNotReturn = false;
+
+ const auto res =
+ [&warnOnlyTryCleanupRan,
+ &warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY(OkIf(true), [&warnOnlyTryCleanupRan](const auto&) {
+ warnOnlyTryCleanupRan = true;
+ });
+
+ warnOnlyTryDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_FALSE(warnOnlyTryCleanupRan);
+ EXPECT_TRUE(warnOnlyTryDidNotReturn);
+}
+
+TEST(QuotaCommon_WarnOnlyTry, Failure)
+{
+ bool warnOnlyTryDidNotReturn = false;
+
+ const auto res =
+ [&warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY(OkIf(false));
+
+ warnOnlyTryDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(warnOnlyTryDidNotReturn);
+}
+
+TEST(QuotaCommon_WarnOnlyTry, Failure_WithCleanup)
+{
+ bool warnOnlyTryCleanupRan = false;
+ bool warnOnlyTryDidNotReturn = false;
+
+ const auto res =
+ [&warnOnlyTryCleanupRan,
+ &warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY(OkIf(false), ([&warnOnlyTryCleanupRan](const auto&) {
+ warnOnlyTryCleanupRan = true;
+ }));
+
+ warnOnlyTryDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(warnOnlyTryCleanupRan);
+ EXPECT_TRUE(warnOnlyTryDidNotReturn);
+}
+
+TEST(QuotaCommon_WarnOnlyTryUnwrap, Success)
+{
+ bool warnOnlyTryUnwrapDidNotReturn = false;
+
+ const auto res = [&warnOnlyTryUnwrapDidNotReturn]()
+ -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY_UNWRAP(const auto x, (Result<int32_t, NotOk>{42}));
+ EXPECT_TRUE(x);
+ EXPECT_EQ(*x, 42);
+
+ warnOnlyTryUnwrapDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
+}
+
+TEST(QuotaCommon_WarnOnlyTryUnwrap, Success_WithCleanup)
+{
+ bool warnOnlyTryUnwrapCleanupRan = false;
+ bool warnOnlyTryUnwrapDidNotReturn = false;
+
+ const auto res = [&warnOnlyTryUnwrapCleanupRan,
+ &warnOnlyTryUnwrapDidNotReturn]()
+ -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY_UNWRAP(const auto x, (Result<int32_t, NotOk>{42}),
+ [&warnOnlyTryUnwrapCleanupRan](const auto&) {
+ warnOnlyTryUnwrapCleanupRan = true;
+ });
+ EXPECT_TRUE(x);
+ EXPECT_EQ(*x, 42);
+
+ warnOnlyTryUnwrapDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_FALSE(warnOnlyTryUnwrapCleanupRan);
+ EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
+}
+
+TEST(QuotaCommon_WarnOnlyTryUnwrap, Failure)
+{
+ bool warnOnlyTryUnwrapDidNotReturn = false;
+
+ const auto res = [&warnOnlyTryUnwrapDidNotReturn]()
+ -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY_UNWRAP(const auto x,
+ (Result<int32_t, NotOk>{Err(NotOk{})}));
+ EXPECT_FALSE(x);
+
+ warnOnlyTryUnwrapDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
+}
+
+TEST(QuotaCommon_WarnOnlyTryUnwrap, Failure_WithCleanup)
+{
+ bool warnOnlyTryUnwrapCleanupRan = false;
+ bool warnOnlyTryUnwrapDidNotReturn = false;
+
+ const auto res = [&warnOnlyTryUnwrapCleanupRan,
+ &warnOnlyTryUnwrapDidNotReturn]()
+ -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_WARNONLY_TRY_UNWRAP(const auto x, (Result<int32_t, NotOk>{Err(NotOk{})}),
+ [&warnOnlyTryUnwrapCleanupRan](const auto&) {
+ warnOnlyTryUnwrapCleanupRan = true;
+ });
+ EXPECT_FALSE(x);
+
+ warnOnlyTryUnwrapDidNotReturn = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(warnOnlyTryUnwrapCleanupRan);
+ EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
+}
+
+TEST(QuotaCommon_OrElseWarn, Success)
+{
+ bool fallbackRun = false;
+ bool tryContinued = false;
+
+ const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_TRY(QM_OR_ELSE_WARN(OkIf(true), ([&fallbackRun](const NotOk) {
+ fallbackRun = true;
+ return mozilla::Result<mozilla::Ok, NotOk>{
+ mozilla::Ok{}};
+ })));
+
+ tryContinued = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_FALSE(fallbackRun);
+ EXPECT_TRUE(tryContinued);
+}
+
+TEST(QuotaCommon_OrElseWarn, Failure_MappedToSuccess)
+{
+ bool fallbackRun = false;
+ bool tryContinued = false;
+
+ // XXX Consider allowing to set a custom error handler, so that we can
+ // actually assert that a warning was emitted.
+ const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_TRY(QM_OR_ELSE_WARN(OkIf(false), ([&fallbackRun](const NotOk) {
+ fallbackRun = true;
+ return mozilla::Result<mozilla::Ok, NotOk>{
+ mozilla::Ok{}};
+ })));
+ tryContinued = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(fallbackRun);
+ EXPECT_TRUE(tryContinued);
+}
+
+TEST(QuotaCommon_OrElseWarn, Failure_MappedToError)
+{
+ bool fallbackRun = false;
+ bool tryContinued = false;
+
+ // XXX Consider allowing to set a custom error handler, so that we can
+ // actually assert that a warning was emitted.
+ const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_TRY(QM_OR_ELSE_WARN(OkIf(false), ([&fallbackRun](const NotOk) {
+ fallbackRun = true;
+ return mozilla::Result<mozilla::Ok, NotOk>{
+ NotOk{}};
+ })));
+ tryContinued = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isErr());
+ EXPECT_TRUE(fallbackRun);
+ EXPECT_FALSE(tryContinued);
+}
+
+TEST(QuotaCommon_OrElseWarnIf, Success)
+{
+ bool predicateRun = false;
+ bool fallbackRun = false;
+ bool tryContinued = false;
+
+ const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_TRY(QM_OR_ELSE_WARN_IF(
+ OkIf(true),
+ [&predicateRun](const NotOk) {
+ predicateRun = true;
+ return false;
+ },
+ ([&fallbackRun](const NotOk) {
+ fallbackRun = true;
+ return mozilla::Result<mozilla::Ok, NotOk>{mozilla::Ok{}};
+ })));
+
+ tryContinued = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_FALSE(predicateRun);
+ EXPECT_FALSE(fallbackRun);
+ EXPECT_TRUE(tryContinued);
+}
+
+TEST(QuotaCommon_OrElseWarnIf, Failure_PredicateReturnsFalse)
+{
+ bool predicateRun = false;
+ bool fallbackRun = false;
+ bool tryContinued = false;
+
+ const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_TRY(QM_OR_ELSE_WARN_IF(
+ OkIf(false),
+ [&predicateRun](const NotOk) {
+ predicateRun = true;
+ return false;
+ },
+ ([&fallbackRun](const NotOk) {
+ fallbackRun = true;
+ return mozilla::Result<mozilla::Ok, NotOk>{mozilla::Ok{}};
+ })));
+
+ tryContinued = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isErr());
+ EXPECT_TRUE(predicateRun);
+ EXPECT_FALSE(fallbackRun);
+ EXPECT_FALSE(tryContinued);
+}
+
+TEST(QuotaCommon_OrElseWarnIf, Failure_PredicateReturnsTrue_MappedToSuccess)
+{
+ bool predicateRun = false;
+ bool fallbackRun = false;
+ bool tryContinued = false;
+
+ const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_TRY(QM_OR_ELSE_WARN_IF(
+ OkIf(false),
+ [&predicateRun](const NotOk) {
+ predicateRun = true;
+ return true;
+ },
+ ([&fallbackRun](const NotOk) {
+ fallbackRun = true;
+ return mozilla::Result<mozilla::Ok, NotOk>{mozilla::Ok{}};
+ })));
+
+ tryContinued = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isOk());
+ EXPECT_TRUE(predicateRun);
+ EXPECT_TRUE(fallbackRun);
+ EXPECT_TRUE(tryContinued);
+}
+
+TEST(QuotaCommon_OrElseWarnIf, Failure_PredicateReturnsTrue_MappedToError)
+{
+ bool predicateRun = false;
+ bool fallbackRun = false;
+ bool tryContinued = false;
+
+ const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
+ QM_TRY(QM_OR_ELSE_WARN_IF(
+ OkIf(false),
+ [&predicateRun](const NotOk) {
+ predicateRun = true;
+ return true;
+ },
+ ([&fallbackRun](const NotOk) {
+ fallbackRun = true;
+ return mozilla::Result<mozilla::Ok, NotOk>{mozilla::NotOk{}};
+ })));
+
+ tryContinued = true;
+ return mozilla::Ok{};
+ }();
+
+ EXPECT_TRUE(res.isErr());
+ EXPECT_TRUE(predicateRun);
+ EXPECT_TRUE(fallbackRun);
+ EXPECT_FALSE(tryContinued);
+}
+
+TEST(QuotaCommon_OkIf, True)
+{
+ auto res = OkIf(true);
+
+ EXPECT_TRUE(res.isOk());
+}
+
+TEST(QuotaCommon_OkIf, False)
+{
+ auto res = OkIf(false);
+
+ EXPECT_TRUE(res.isErr());
+}
+
+TEST(QuotaCommon_OkToOk, Bool_True)
+{
+ auto res = OkToOk<true>(Ok());
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), true);
+}
+
+TEST(QuotaCommon_OkToOk, Bool_False)
+{
+ auto res = OkToOk<false>(Ok());
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), false);
+}
+
+TEST(QuotaCommon_OkToOk, Int_42)
+{
+ auto res = OkToOk<42>(Ok());
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), 42);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, Bool_True)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, true>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), true);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, Bool_True_Err)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, true>(NS_ERROR_UNEXPECTED);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, Bool_False)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, false>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), false);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, Bool_False_Err)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, false>(NS_ERROR_UNEXPECTED);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, Int_42)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, 42>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), 42);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, Int_42_Err)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, 42>(NS_ERROR_UNEXPECTED);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, NsCOMPtr_nullptr)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, nullptr, nsCOMPtr<nsISupports>>(
+ NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), nullptr);
+}
+
+TEST(QuotaCommon_ErrToOkOrErr, NsCOMPtr_nullptr_Err)
+{
+ auto res = ErrToOkOrErr<NS_ERROR_FAILURE, nullptr, nsCOMPtr<nsISupports>>(
+ NS_ERROR_UNEXPECTED);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_ErrToDefaultOkOrErr, Ok)
+{
+ auto res = ErrToDefaultOkOrErr<NS_ERROR_FAILURE, Ok>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+}
+
+TEST(QuotaCommon_ErrToDefaultOkOrErr, Ok_Err)
+{
+ auto res = ErrToDefaultOkOrErr<NS_ERROR_FAILURE, Ok>(NS_ERROR_UNEXPECTED);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_ErrToDefaultOkOrErr, NsCOMPtr)
+{
+ auto res = ErrToDefaultOkOrErr<NS_ERROR_FAILURE, nsCOMPtr<nsISupports>>(
+ NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), nullptr);
+}
+
+TEST(QuotaCommon_ErrToDefaultOkOrErr, NsCOMPtr_Err)
+{
+ auto res = ErrToDefaultOkOrErr<NS_ERROR_FAILURE, nsCOMPtr<nsISupports>>(
+ NS_ERROR_UNEXPECTED);
+ EXPECT_TRUE(res.isErr());
+ EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
+}
+
+TEST(QuotaCommon_IsSpecificError, Match)
+{ EXPECT_TRUE(IsSpecificError<NS_ERROR_FAILURE>(NS_ERROR_FAILURE)); }
+
+TEST(QuotaCommon_IsSpecificError, Mismatch)
+{ EXPECT_FALSE(IsSpecificError<NS_ERROR_FAILURE>(NS_ERROR_UNEXPECTED)); }
+
+TEST(QuotaCommon_ErrToOk, Bool_True)
+{
+ auto res = ErrToOk<true>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), true);
+}
+
+TEST(QuotaCommon_ErrToOk, Bool_False)
+{
+ auto res = ErrToOk<false>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), false);
+}
+
+TEST(QuotaCommon_ErrToOk, Int_42)
+{
+ auto res = ErrToOk<42>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), 42);
+}
+
+TEST(QuotaCommon_ErrToOk, NsCOMPtr_nullptr)
+{
+ auto res = ErrToOk<nullptr, nsCOMPtr<nsISupports>>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), nullptr);
+}
+
+TEST(QuotaCommon_ErrToDefaultOk, Ok)
+{
+ auto res = ErrToDefaultOk<Ok>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+}
+
+TEST(QuotaCommon_ErrToDefaultOk, NsCOMPtr)
+{
+ auto res = ErrToDefaultOk<nsCOMPtr<nsISupports>>(NS_ERROR_FAILURE);
+ EXPECT_TRUE(res.isOk());
+ EXPECT_EQ(res.unwrap(), nullptr);
+}
+
+class StringPairParameterized
+ : public ::testing::TestWithParam<std::pair<const char*, const char*>> {};
+
+TEST_P(StringPairParameterized, AnonymizedOriginString) {
+ const auto [in, expectedAnonymized] = GetParam();
+ const auto anonymized = AnonymizedOriginString(nsDependentCString(in));
+ EXPECT_STREQ(anonymized.get(), expectedAnonymized);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ QuotaCommon, StringPairParameterized,
+ ::testing::Values(
+ // XXX Do we really want to anonymize about: origins?
+ std::pair("about:home", "about:aaaa"),
+ std::pair("https://foo.bar.com", "https://aaa.aaa.aaa"),
+ std::pair("https://foo.bar.com:8000", "https://aaa.aaa.aaa:DDDD"),
+ std::pair("file://UNIVERSAL_FILE_ORIGIN",
+ "file://aaaaaaaaa_aaaa_aaaaaa")));
+
+// BEGIN COPY FROM mfbt/tests/TestResult.cpp
+struct Failed {};
+
+static GenericErrorResult<Failed> Fail() { return Err(Failed()); }
+
+static Result<Ok, Failed> Task1(bool pass) {
+ if (!pass) {
+ return Fail(); // implicit conversion from GenericErrorResult to Result
+ }
+ return Ok();
+}
+// END COPY FROM mfbt/tests/TestResult.cpp
+
+static Result<bool, Failed> Condition(bool aNoError, bool aResult) {
+ return Task1(aNoError).map([aResult](auto) { return aResult; });
+}
+
+TEST(QuotaCommon_CollectWhileTest, NoFailures)
+{
+ const size_t loopCount = 5;
+ size_t conditionExecutions = 0;
+ size_t bodyExecutions = 0;
+ auto result = CollectWhile(
+ [&conditionExecutions] {
+ ++conditionExecutions;
+ return Condition(true, conditionExecutions <= loopCount);
+ },
+ [&bodyExecutions] {
+ ++bodyExecutions;
+ return Task1(true);
+ });
+ static_assert(std::is_same_v<decltype(result), Result<Ok, Failed>>);
+ MOZ_RELEASE_ASSERT(result.isOk());
+ MOZ_RELEASE_ASSERT(loopCount == bodyExecutions);
+ MOZ_RELEASE_ASSERT(1 + loopCount == conditionExecutions);
+}
+
+TEST(QuotaCommon_CollectWhileTest, BodyFailsImmediately)
+{
+ size_t conditionExecutions = 0;
+ size_t bodyExecutions = 0;
+ auto result = CollectWhile(
+ [&conditionExecutions] {
+ ++conditionExecutions;
+ return Condition(true, true);
+ },
+ [&bodyExecutions] {
+ ++bodyExecutions;
+ return Task1(false);
+ });
+ static_assert(std::is_same_v<decltype(result), Result<Ok, Failed>>);
+ MOZ_RELEASE_ASSERT(result.isErr());
+ MOZ_RELEASE_ASSERT(1 == bodyExecutions);
+ MOZ_RELEASE_ASSERT(1 == conditionExecutions);
+}
+
+TEST(QuotaCommon_CollectWhileTest, BodyFailsOnSecondExecution)
+{
+ size_t conditionExecutions = 0;
+ size_t bodyExecutions = 0;
+ auto result = CollectWhile(
+ [&conditionExecutions] {
+ ++conditionExecutions;
+ return Condition(true, true);
+ },
+ [&bodyExecutions] {
+ ++bodyExecutions;
+ return Task1(bodyExecutions < 2);
+ });
+ static_assert(std::is_same_v<decltype(result), Result<Ok, Failed>>);
+ MOZ_RELEASE_ASSERT(result.isErr());
+ MOZ_RELEASE_ASSERT(2 == bodyExecutions);
+ MOZ_RELEASE_ASSERT(2 == conditionExecutions);
+}
+
+TEST(QuotaCommon_CollectWhileTest, ConditionFailsImmediately)
+{
+ size_t conditionExecutions = 0;
+ size_t bodyExecutions = 0;
+ auto result = CollectWhile(
+ [&conditionExecutions] {
+ ++conditionExecutions;
+ return Condition(false, true);
+ },
+ [&bodyExecutions] {
+ ++bodyExecutions;
+ return Task1(true);
+ });
+ static_assert(std::is_same_v<decltype(result), Result<Ok, Failed>>);
+ MOZ_RELEASE_ASSERT(result.isErr());
+ MOZ_RELEASE_ASSERT(0 == bodyExecutions);
+ MOZ_RELEASE_ASSERT(1 == conditionExecutions);
+}
+
+TEST(QuotaCommon_CollectWhileTest, ConditionFailsOnSecondExecution)
+{
+ size_t conditionExecutions = 0;
+ size_t bodyExecutions = 0;
+ auto result = CollectWhile(
+ [&conditionExecutions] {
+ ++conditionExecutions;
+ return Condition(conditionExecutions < 2, true);
+ },
+ [&bodyExecutions] {
+ ++bodyExecutions;
+ return Task1(true);
+ });
+ static_assert(std::is_same_v<decltype(result), Result<Ok, Failed>>);
+ MOZ_RELEASE_ASSERT(result.isErr());
+ MOZ_RELEASE_ASSERT(1 == bodyExecutions);
+ MOZ_RELEASE_ASSERT(2 == conditionExecutions);
+}
+
+TEST(QuotaCommon_CollectEachInRange, Success)
+{
+ size_t bodyExecutions = 0;
+ const auto result = CollectEachInRange(
+ std::array<int, 5>{{1, 2, 3, 4, 5}},
+ [&bodyExecutions](const int val) -> Result<Ok, nsresult> {
+ ++bodyExecutions;
+ return Ok{};
+ });
+
+ MOZ_RELEASE_ASSERT(result.isOk());
+ MOZ_RELEASE_ASSERT(5 == bodyExecutions);
+}
+
+TEST(QuotaCommon_CollectEachInRange, FailureShortCircuit)
+{
+ size_t bodyExecutions = 0;
+ const auto result = CollectEachInRange(
+ std::array<int, 5>{{1, 2, 3, 4, 5}},
+ [&bodyExecutions](const int val) -> Result<Ok, nsresult> {
+ ++bodyExecutions;
+ return val == 3 ? Err(NS_ERROR_FAILURE) : Result<Ok, nsresult>{Ok{}};
+ });
+
+ MOZ_RELEASE_ASSERT(result.isErr());
+ MOZ_RELEASE_ASSERT(NS_ERROR_FAILURE == result.inspectErr());
+ MOZ_RELEASE_ASSERT(3 == bodyExecutions);
+}
+
+TEST(QuotaCommon_ReduceEach, Success)
+{
+ const auto result = ReduceEach(
+ [i = int{0}]() mutable -> Result<int, Failed> {
+ if (i < 5) {
+ return ++i;
+ }
+ return 0;
+ },
+ 0, [](int val, int add) -> Result<int, Failed> { return val + add; });
+ static_assert(std::is_same_v<decltype(result), const Result<int, Failed>>);
+
+ MOZ_RELEASE_ASSERT(result.isOk());
+ MOZ_RELEASE_ASSERT(15 == result.inspect());
+}
+
+TEST(QuotaCommon_ReduceEach, StepError)
+{
+ const auto result = ReduceEach(
+ [i = int{0}]() mutable -> Result<int, Failed> {
+ if (i < 5) {
+ return ++i;
+ }
+ return 0;
+ },
+ 0,
+ [](int val, int add) -> Result<int, Failed> {
+ if (val > 2) {
+ return Err(Failed{});
+ }
+ return val + add;
+ });
+ static_assert(std::is_same_v<decltype(result), const Result<int, Failed>>);
+
+ MOZ_RELEASE_ASSERT(result.isErr());
+}
+
+TEST(QuotaCommon_ReduceEach, GeneratorError)
+{
+ size_t generatorExecutions = 0;
+ const auto result = ReduceEach(
+ [i = int{0}, &generatorExecutions]() mutable -> Result<int, Failed> {
+ ++generatorExecutions;
+ if (i < 1) {
+ return ++i;
+ }
+ return Err(Failed{});
+ },
+ 0,
+ [](int val, int add) -> Result<int, Failed> {
+ if (val > 2) {
+ return Err(Failed{});
+ }
+ return val + add;
+ });
+ static_assert(std::is_same_v<decltype(result), const Result<int, Failed>>);
+
+ MOZ_RELEASE_ASSERT(result.isErr());
+ MOZ_RELEASE_ASSERT(2 == generatorExecutions);
+}
+
+TEST(QuotaCommon_Reduce, Success)
+{
+ const auto range = std::vector{0, 1, 2, 3, 4, 5};
+ const auto result = Reduce(
+ range, 0, [](int val, Maybe<const int&> add) -> Result<int, Failed> {
+ return val + add.ref();
+ });
+ static_assert(std::is_same_v<decltype(result), const Result<int, Failed>>);
+
+ MOZ_RELEASE_ASSERT(result.isOk());
+ MOZ_RELEASE_ASSERT(15 == result.inspect());
+}
+
+TEST(QuotaCommon_CallWithDelayedRetriesIfAccessDenied, NoFailures)
+{
+ uint32_t tries = 0;
+
+ auto res = CallWithDelayedRetriesIfAccessDenied(
+ [&tries]() -> Result<Ok, nsresult> {
+ ++tries;
+ return Ok{};
+ },
+ 10, 2);
+
+ EXPECT_EQ(tries, 1u);
+ EXPECT_TRUE(res.isOk());
+}
+
+TEST(QuotaCommon_CallWithDelayedRetriesIfAccessDenied, PermanentFailures)
+{
+ uint32_t tries = 0;
+
+ auto res = CallWithDelayedRetriesIfAccessDenied(
+ [&tries]() -> Result<Ok, nsresult> {
+ ++tries;
+ return Err(NS_ERROR_FILE_IS_LOCKED);
+ },
+ 10, 2);
+
+ EXPECT_EQ(tries, 11u);
+ EXPECT_TRUE(res.isErr());
+}
+
+TEST(QuotaCommon_CallWithDelayedRetriesIfAccessDenied, FailuresAndSuccess)
+{
+ uint32_t tries = 0;
+
+ auto res = CallWithDelayedRetriesIfAccessDenied(
+ [&tries]() -> Result<Ok, nsresult> {
+ if (++tries == 5) {
+ return Ok{};
+ }
+ return Err(NS_ERROR_FILE_ACCESS_DENIED);
+ },
+ 10, 2);
+
+ EXPECT_EQ(tries, 5u);
+ EXPECT_TRUE(res.isOk());
+}
+
+TEST(QuotaCommon_MakeSourceFileRelativePath, ThisSourceFile)
+{
+ static constexpr auto thisSourceFileRelativePath =
+ "dom/quota/test/gtest/TestQuotaCommon.cpp"_ns;
+
+ const nsCString sourceFileRelativePath{
+ mozilla::dom::quota::detail::MakeSourceFileRelativePath(
+ nsLiteralCString(__FILE__))};
+
+ EXPECT_STREQ(sourceFileRelativePath.get(), thisSourceFileRelativePath.get());
+}
+
+static nsCString MakeTreePath(const nsACString& aBasePath,
+ const nsACString& aRelativePath) {
+ nsCString path{aBasePath};
+
+ path.Append("/");
+ path.Append(aRelativePath);
+
+ return path;
+}
+
+static nsCString MakeSourceTreePath(const nsACString& aRelativePath) {
+ return MakeTreePath(mozilla::dom::quota::detail::GetSourceTreeBase(),
+ aRelativePath);
+}
+
+static nsCString MakeObjdirDistIncludeTreePath(
+ const nsACString& aRelativePath) {
+ return MakeTreePath(
+ mozilla::dom::quota::detail::GetObjdirDistIncludeTreeBase(),
+ aRelativePath);
+}
+
+TEST(QuotaCommon_MakeSourceFileRelativePath, DomQuotaSourceFile)
+{
+ static constexpr auto domQuotaSourceFileRelativePath =
+ "dom/quota/ActorsParent.cpp"_ns;
+
+ const nsCString sourceFileRelativePath{
+ mozilla::dom::quota::detail::MakeSourceFileRelativePath(
+ MakeSourceTreePath(domQuotaSourceFileRelativePath))};
+
+ EXPECT_STREQ(sourceFileRelativePath.get(),
+ domQuotaSourceFileRelativePath.get());
+}
+
+TEST(QuotaCommon_MakeSourceFileRelativePath, DomQuotaSourceFile_Exported)
+{
+ static constexpr auto mozillaDomQuotaSourceFileRelativePath =
+ "mozilla/dom/quota/QuotaCommon.h"_ns;
+
+ static constexpr auto domQuotaSourceFileRelativePath =
+ "dom/quota/QuotaCommon.h"_ns;
+
+ const nsCString sourceFileRelativePath{
+ mozilla::dom::quota::detail::MakeSourceFileRelativePath(
+ MakeObjdirDistIncludeTreePath(
+ mozillaDomQuotaSourceFileRelativePath))};
+
+ EXPECT_STREQ(sourceFileRelativePath.get(),
+ domQuotaSourceFileRelativePath.get());
+}
+
+TEST(QuotaCommon_MakeSourceFileRelativePath, DomIndexedDBSourceFile)
+{
+ static constexpr auto domIndexedDBSourceFileRelativePath =
+ "dom/indexedDB/ActorsParent.cpp"_ns;
+
+ const nsCString sourceFileRelativePath{
+ mozilla::dom::quota::detail::MakeSourceFileRelativePath(
+ MakeSourceTreePath(domIndexedDBSourceFileRelativePath))};
+
+ EXPECT_STREQ(sourceFileRelativePath.get(),
+ domIndexedDBSourceFileRelativePath.get());
+}
+
+TEST(QuotaCommon_MakeSourceFileRelativePath,
+ DomLocalstorageSourceFile_Exported_Mapped)
+{
+ static constexpr auto mozillaDomSourceFileRelativePath =
+ "mozilla/dom/LocalStorageCommon.h"_ns;
+
+ static constexpr auto domLocalstorageSourceFileRelativePath =
+ "dom/localstorage/LocalStorageCommon.h"_ns;
+
+ const nsCString sourceFileRelativePath{
+ mozilla::dom::quota::detail::MakeSourceFileRelativePath(
+ MakeObjdirDistIncludeTreePath(mozillaDomSourceFileRelativePath))};
+
+ EXPECT_STREQ(sourceFileRelativePath.get(),
+ domLocalstorageSourceFileRelativePath.get());
+}
+
+TEST(QuotaCommon_MakeSourceFileRelativePath, NonDomSourceFile)
+{
+ static constexpr auto nonDomSourceFileRelativePath =
+ "storage/mozStorageService.cpp"_ns;
+
+ const nsCString sourceFileRelativePath{
+ mozilla::dom::quota::detail::MakeSourceFileRelativePath(
+ MakeSourceTreePath(nonDomSourceFileRelativePath))};
+
+ EXPECT_STREQ(sourceFileRelativePath.get(),
+ nonDomSourceFileRelativePath.get());
+}
+
+TEST(QuotaCommon_MakeSourceFileRelativePath, OtherSourceFile)
+{
+ constexpr auto otherSourceFilePath = "/foo/bar/Test.cpp"_ns;
+ const nsCString sourceFileRelativePath{
+ mozilla::dom::quota::detail::MakeSourceFileRelativePath(
+ otherSourceFilePath)};
+
+ EXPECT_STREQ(sourceFileRelativePath.get(), "Test.cpp");
+}
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif