Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/quota/test/gtest/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 61 kB image not shown  

Quelle  TestQuotaCommon.cpp   Sprache: C

 
/* -*- 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 "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIFile.h"
#include "nsLiteralString.h"
#include "nsString.h"
#include "nsStringFwd.h"
#include "nsTLiteralString.h"

class nsISupports;

namespace mozilla::dom::quota {

namespace {

void CheckUnknownFileEntry(nsIFile& aBase, const nsAString& aName,
                           const bool aWarnIfFile, const bool aWarnIfDir) {
  nsCOMPtr<nsIFile> file;
  nsresult rv = aBase.Clone(getter_AddRefs(file));
  ASSERT_EQ(rv, NS_OK);

  rv = file->Append(aName);
  ASSERT_EQ(rv, NS_OK);

  rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
  ASSERT_EQ(rv, NS_OK);

  auto okOrErr = WARN_IF_FILE_IS_UNKNOWN(*file);
  ASSERT_TRUE(okOrErr.isOk());

#ifdef DEBUG
  EXPECT_TRUE(okOrErr.inspect() == aWarnIfFile);
#else
  EXPECT_TRUE(okOrErr.inspect() == false);
#endif

  rv = file->Remove(false);
  ASSERT_EQ(rv, NS_OK);

  rv = file->Create(nsIFile::DIRECTORY_TYPE, 0700);
  ASSERT_EQ(rv, NS_OK);

  okOrErr = WARN_IF_FILE_IS_UNKNOWN(*file);
  ASSERT_TRUE(okOrErr.isOk());

#ifdef DEBUG
  EXPECT_TRUE(okOrErr.inspect() == aWarnIfDir);
#else
  EXPECT_TRUE(okOrErr.inspect() == false);
#endif

  rv = file->Remove(false);
  ASSERT_EQ(rv, NS_OK);
}

}  // namespace

TEST(QuotaCommon_WarnIfFileIsUnknown, Basics)
{
  nsCOMPtr<nsIFile> base;
  nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(base));
  ASSERT_EQ(rv, NS_OK);

  rv = base->Append(u"mozquotatests"_ns);
  ASSERT_EQ(rv, NS_OK);

  base->Remove(true);

  rv = base->Create(nsIFile::DIRECTORY_TYPE, 0700);
  ASSERT_EQ(rv, NS_OK);

  CheckUnknownFileEntry(*base, u"foo.bar"_ns, truetrue);
  CheckUnknownFileEntry(*base, u".DS_Store"_ns, falsetrue);
  CheckUnknownFileEntry(*base, u".desktop"_ns, falsetrue);
  CheckUnknownFileEntry(*base, u"desktop.ini"_ns, falsetrue);
  CheckUnknownFileEntry(*base, u"DESKTOP.INI"_ns, falsetrue);
  CheckUnknownFileEntry(*base, u"thumbs.db"_ns, falsetrue);
  CheckUnknownFileEntry(*base, u"THUMBS.DB"_ns, falsetrue);
  CheckUnknownFileEntry(*base, u".xyz"_ns, falsetrue);

  rv = base->Remove(true);
  ASSERT_EQ(rv, NS_OK);
}

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, Failure_WithCleanupAndPredicate)
{
  auto predicate = []() {
    static bool calledOnce = false;
    const bool result = !calledOnce;
    calledOnce = true;
    return result;
  };

  {
    bool tryDidNotReturn = false;

    nsresult rv = [&predicate, &tryDidNotReturn]() -> nsresult {
      QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE), QM_PROPAGATE, QM_NO_CLEANUP,
             predicate);

      tryDidNotReturn = true;

      return NS_OK;
    }();

    EXPECT_FALSE(tryDidNotReturn);
    EXPECT_EQ(rv, NS_ERROR_FAILURE);
  }

  {
    bool tryDidNotReturn = false;

    nsresult rv = [&predicate, &tryDidNotReturn]() -> nsresult {
      QM_TRY(MOZ_TO_RESULT(NS_ERROR_FAILURE), QM_PROPAGATE, QM_NO_CLEANUP,
             predicate);

      tryDidNotReturn = true;

      return NS_OK;
    }();

    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(truetrue);
      },
      [&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(truetrue);
      },
      [&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(falsetrue);
      },
      [&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

}  // namespace mozilla::dom::quota

Messung V0.5
C=99 H=100 G=99

¤ Dauer der Verarbeitung: 0.37 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.