Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/xpcom/tests/gtest/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 43 kB image not shown  

Quelle  TestTArray2.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/ArrayUtils.h"
#include "mozilla/Unused.h"
#include "mozilla/TimeStamp.h"

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include "nsTArray.h"
#include "nsString.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsXPCOM.h"
#include "nsIFile.h"

#include "gtest/gtest.h"
#include "mozilla/gtest/MozAssertions.h"

using namespace mozilla;

namespace TestTArray {

// Define this so we can use test_basic_array in test_comptr_array
template <class T>
inline bool operator<(const nsCOMPtr<T>& lhs, const nsCOMPtr<T>& rhs) {
  return lhs.get() < rhs.get();
}

//----

template <class ElementType>
static bool test_basic_array(ElementType* data, size_t dataLen,
                             const ElementType& extra) {
  CopyableTArray<ElementType> ary;
  const nsTArray<ElementType>& cary = ary;

  ary.AppendElements(data, dataLen);
  if (ary.Length() != dataLen) {
    return false;
  }
  if (!(ary == ary)) {
    return false;
  }
  size_t i;
  for (i = 0; i < ary.Length(); ++i) {
    if (ary[i] != data[i]) return false;
  }
  for (i = 0; i < ary.Length(); ++i) {
    if (ary.SafeElementAt(i, extra) != data[i]) return false;
  }
  if (ary.SafeElementAt(ary.Length(), extra) != extra ||
      ary.SafeElementAt(ary.Length() * 10, extra) != extra)
    return false;
  // ensure sort results in ascending order
  ary.Sort();
  size_t j = 0, k = ary.IndexOfFirstElementGt(extra);
  if (k != 0 && ary[k - 1] == extra) return false;
  for (i = 0; i < ary.Length(); ++i) {
    k = ary.IndexOfFirstElementGt(ary[i]);
    if (k == 0 || ary[k - 1] != ary[i]) return false;
    if (k < j) return false;
    j = k;
  }
  for (i = ary.Length(); --i;) {
    if (ary[i] < ary[i - 1]) return false;
    if (ary[i] == ary[i - 1]) ary.RemoveElementAt(i);
  }
  if (!(ary == ary)) {
    return false;
  }
  for (i = 0; i < ary.Length(); ++i) {
    if (ary.BinaryIndexOf(ary[i]) != i) return false;
  }
  if (ary.BinaryIndexOf(extra) != ary.NoIndex) return false;
  size_t oldLen = ary.Length();
  ary.RemoveElement(data[dataLen / 2]);
  if (ary.Length() != (oldLen - 1)) return false;
  if (!(ary == ary)) return false;

  if (ary.ApplyIf(extra, []() { return true; }, []() { return false; }))
    return false;
  if (ary.ApplyIf(extra, [](size_t) { return true; }, []() { return false; }))
    return false;
  // On a non-const array, ApplyIf's first lambda may use either const or non-
  // const element types.
  if (ary.ApplyIf(
          extra, [](ElementType&) { return true; }, []() { return false; }))
    return false;
  if (ary.ApplyIf(
          extra, [](const ElementType&) { return true; },
          []() { return false; }))
    return false;
  if (ary.ApplyIf(
          extra, [](size_t, ElementType&) { return true; },
          []() { return false; }))
    return false;
  if (ary.ApplyIf(
          extra, [](size_t, const ElementType&) { return true; },
          []() { return false; }))
    return false;

  if (cary.ApplyIf(extra, []() { return true; }, []() { return false; }))
    if (cary.ApplyIf(
            extra, [](size_t) { return true; }, []() { return false; }))
      // On a const array, ApplyIf's first lambda must only use const element
      // types.
      if (cary.ApplyIf(
              extra, [](const ElementType&) { return true; },
              []() { return false; }))
        if (cary.ApplyIf(
                extra, [](size_t, const ElementType&) { return true; },
                []() { return false; }))
          return false;

  size_t index = ary.Length() / 2;
  ary.InsertElementAt(index, extra);
  if (!(ary == ary)) return false;
  if (ary[index] != extra) return false;
  if (ary.IndexOf(extra) == ary.NoIndex) return false;
  if (ary.LastIndexOf(extra) == ary.NoIndex) return false;
  // ensure proper searching
  if (ary.IndexOf(extra) > ary.LastIndexOf(extra)) return false;
  if (ary.IndexOf(extra, index) != ary.LastIndexOf(extra, index)) return false;
  if (!ary.ApplyIf(
          extra,
          [&](size_t i, const ElementType& e) {
            return i == index && e == extra;
          },
          []() { return false; }))
    return false;
  if (!cary.ApplyIf(
          extra,
          [&](size_t i, const ElementType& e) {
            return i == index && e == extra;
          },
          []() { return false; }))
    return false;

  nsTArray<ElementType> copy(ary.Clone());
  if (!(ary == copy)) return false;
  for (i = 0; i < copy.Length(); ++i) {
    if (ary[i] != copy[i]) return false;
  }
  ary.AppendElements(copy);
  size_t cap = ary.Capacity();
  ary.RemoveElementsAt(copy.Length(), copy.Length());
  ary.Compact();
  if (ary.Capacity() == cap) return false;

  ary.Clear();
  if (ary.IndexOf(extra) != ary.NoIndex) return false;
  if (ary.LastIndexOf(extra) != ary.NoIndex) return false;
  if (ary.ApplyIf(extra, []() { return true; }, []() { return false; }))
    return false;
  if (cary.ApplyIf(extra, []() { return true; }, []() { return false; }))
    return false;

  ary.Clear();
  if (!ary.IsEmpty()) return false;
  if (!(ary == nsTArray<ElementType>())) return false;
  if (ary == copy) return false;
  if (ary.SafeElementAt(0, extra) != extra ||
      ary.SafeElementAt(10, extra) != extra)
    return false;

  ary = copy;
  if (!(ary == copy)) return false;
  for (i = 0; i < copy.Length(); ++i) {
    if (ary[i] != copy[i]) return false;
  }

  ary.InsertElementsAt(0, copy);
  if (ary == copy) return false;
  ary.RemoveElementsAt(0, copy.Length());
  for (i = 0; i < copy.Length(); ++i) {
    if (ary[i] != copy[i]) return false;
  }

  // These shouldn't crash!
  nsTArray<ElementType> empty;
  ary.AppendElements(reinterpret_cast<ElementType*>(0), 0);
  ary.AppendElements(empty);

  // See bug 324981
  ary.RemoveElement(extra);
  ary.RemoveElement(extra);

  return true;
}

TEST(TArray, test_int_array)
{
  int data[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
  ASSERT_TRUE(test_basic_array(data, std::size(data), int(14)));
}

TEST(TArray, test_int64_array)
{
  int64_t data[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
  ASSERT_TRUE(test_basic_array(data, std::size(data), int64_t(14)));
}

TEST(TArray, test_char_array)
{
  char data[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
  ASSERT_TRUE(test_basic_array(data, std::size(data), char(14)));
}

TEST(TArray, test_uint32_array)
{
  uint32_t data[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
  ASSERT_TRUE(test_basic_array(data, std::size(data), uint32_t(14)));
}

//----

class Object {
 public:
  Object() : mNum(0) {}
  Object(const char* str, uint32_t num) : mStr(str), mNum(num) {}
  Object(const Object& other) = default;
  ~Object() = default;

  Object& operator=(const Object& other) = default;

  bool operator==(const Object& other) const {
    return mStr == other.mStr && mNum == other.mNum;
  }

  bool operator<(const Object& other) const {
    // sort based on mStr only
    return Compare(mStr, other.mStr) < 0;
  }

  const char* Str() const { return mStr.get(); }
  uint32_t Num() const { return mNum; }

 private:
  nsCString mStr;
  uint32_t mNum;
};

TEST(TArray, test_object_array)
{
  nsTArray<Object> objArray;
  const char kdata[] = "hello world";
  size_t i;
  for (i = 0; i < std::size(kdata); ++i) {
    char x[] = {kdata[i], '\0'};
    objArray.AppendElement(Object(x, i));
  }
  for (i = 0; i < std::size(kdata); ++i) {
    ASSERT_EQ(objArray[i].Str()[0], kdata[i]);
    ASSERT_EQ(objArray[i].Num(), i);
  }
  objArray.Sort();
  const char ksorted[] = "\0 dehllloorw";
  for (i = 0; i < std::size(kdata) - 1; ++i) {
    ASSERT_EQ(objArray[i].Str()[0], ksorted[i]);
  }
}

class Countable {
  static int sCount;

 public:
  Countable() { sCount++; }

  Countable(const Countable& aOther) { sCount++; }

  static int Count() { return sCount; }
};

class Moveable {
  static int sCount;

 public:
  Moveable() { sCount++; }

  Moveable(const Moveable& aOther) { sCount++; }

  Moveable(Moveable&& aOther) {
    // Do not increment sCount
  }

  static int Count() { return sCount; }
};

class MoveOnly_RelocateUsingMemutils {
 public:
  MoveOnly_RelocateUsingMemutils() = default;

  MoveOnly_RelocateUsingMemutils(const MoveOnly_RelocateUsingMemutils&) =
      delete;
  MoveOnly_RelocateUsingMemutils(MoveOnly_RelocateUsingMemutils&&) = default;

  MoveOnly_RelocateUsingMemutils& operator=(
      const MoveOnly_RelocateUsingMemutils&) = delete;
  MoveOnly_RelocateUsingMemutils& operator=(MoveOnly_RelocateUsingMemutils&&) =
      default;
};

static_assert(
    std::is_move_constructible_v<nsTArray<MoveOnly_RelocateUsingMemutils>>);
static_assert(
    std::is_move_assignable_v<nsTArray<MoveOnly_RelocateUsingMemutils>>);
static_assert(
    !std::is_copy_constructible_v<nsTArray<MoveOnly_RelocateUsingMemutils>>);
static_assert(
    !std::is_copy_assignable_v<nsTArray<MoveOnly_RelocateUsingMemutils>>);

class MoveOnly_RelocateUsingMoveConstructor {
 public:
  MoveOnly_RelocateUsingMoveConstructor() = default;

  MoveOnly_RelocateUsingMoveConstructor(
      const MoveOnly_RelocateUsingMoveConstructor&) = delete;
  MoveOnly_RelocateUsingMoveConstructor(
      MoveOnly_RelocateUsingMoveConstructor&&) = default;

  MoveOnly_RelocateUsingMoveConstructor& operator=(
      const MoveOnly_RelocateUsingMoveConstructor&) = delete;
  MoveOnly_RelocateUsingMoveConstructor& operator=(
      MoveOnly_RelocateUsingMoveConstructor&&) = default;
};
}  // namespace TestTArray

MOZ_DECLARE_RELOCATE_USING_MOVE_CONSTRUCTOR(
    TestTArray::MoveOnly_RelocateUsingMoveConstructor)

namespace TestTArray {
static_assert(std::is_move_constructible_v<
              nsTArray<MoveOnly_RelocateUsingMoveConstructor>>);
static_assert(
    std::is_move_assignable_v<nsTArray<MoveOnly_RelocateUsingMoveConstructor>>);
static_assert(!std::is_copy_constructible_v<
              nsTArray<MoveOnly_RelocateUsingMoveConstructor>>);
static_assert(!std::is_copy_assignable_v<
              nsTArray<MoveOnly_RelocateUsingMoveConstructor>>);
}  // namespace TestTArray

namespace TestTArray {

/* static */
int Countable::sCount = 0;
/* static */
int Moveable::sCount = 0;

static nsTArray<int> returns_by_value() {
  nsTArray<int> result;
  return result;
}

TEST(TArray, test_return_by_value)
{
  nsTArray<int> result = returns_by_value();
  ASSERT_TRUE(true);  // This is just a compilation test.
}

TEST(TArray, test_move_array)
{
  nsTArray<Countable> countableArray;
  uint32_t i;
  for (i = 0; i < 4; ++i) {
    countableArray.AppendElement(Countable());
  }

  ASSERT_EQ(Countable::Count(), 8);

  const nsTArray<Countable>& constRefCountableArray = countableArray;

  ASSERT_EQ(Countable::Count(), 8);

  nsTArray<Countable> copyCountableArray(constRefCountableArray.Clone());

  ASSERT_EQ(Countable::Count(), 12);

  nsTArray<Countable>&& moveRefCountableArray = std::move(countableArray);
  moveRefCountableArray.Length();  // Make compilers happy.

  ASSERT_EQ(Countable::Count(), 12);

  nsTArray<Countable> movedCountableArray(std::move(countableArray));

  ASSERT_EQ(Countable::Count(), 12);

  // Test ctor
  FallibleTArray<Countable> differentAllocatorCountableArray(
      std::move(copyCountableArray));
  // operator=
  copyCountableArray = std::move(differentAllocatorCountableArray);
  differentAllocatorCountableArray = std::move(copyCountableArray);
  // And the other ctor
  nsTArray<Countable> copyCountableArray2(
      std::move(differentAllocatorCountableArray));
  // with auto
  AutoTArray<Countable, 3> autoCountableArray(std::move(copyCountableArray2));
  // operator=
  copyCountableArray2 = std::move(autoCountableArray);
  // Mix with FallibleTArray
  FallibleTArray<Countable> differentAllocatorCountableArray2(
      std::move(copyCountableArray2));
  AutoTArray<Countable, 4> autoCountableArray2(
      std::move(differentAllocatorCountableArray2));
  differentAllocatorCountableArray2 = std::move(autoCountableArray2);

  ASSERT_EQ(Countable::Count(), 12);

  nsTArray<Moveable> moveableArray;
  for (i = 0; i < 4; ++i) {
    moveableArray.AppendElement(Moveable());
  }

  ASSERT_EQ(Moveable::Count(), 4);

  const nsTArray<Moveable>& constRefMoveableArray = moveableArray;

  ASSERT_EQ(Moveable::Count(), 4);

  nsTArray<Moveable> copyMoveableArray(constRefMoveableArray.Clone());

  ASSERT_EQ(Moveable::Count(), 8);

  nsTArray<Moveable>&& moveRefMoveableArray = std::move(moveableArray);
  moveRefMoveableArray.Length();  // Make compilers happy.

  ASSERT_EQ(Moveable::Count(), 8);

  nsTArray<Moveable> movedMoveableArray(std::move(moveableArray));

  ASSERT_EQ(Moveable::Count(), 8);

  // Test ctor
  FallibleTArray<Moveable> differentAllocatorMoveableArray(
      std::move(copyMoveableArray));
  // operator=
  copyMoveableArray = std::move(differentAllocatorMoveableArray);
  differentAllocatorMoveableArray = std::move(copyMoveableArray);
  // And the other ctor
  nsTArray<Moveable> copyMoveableArray2(
      std::move(differentAllocatorMoveableArray));
  // with auto
  AutoTArray<Moveable, 3> autoMoveableArray(std::move(copyMoveableArray2));
  // operator=
  copyMoveableArray2 = std::move(autoMoveableArray);
  // Mix with FallibleTArray
  FallibleTArray<Moveable> differentAllocatorMoveableArray2(
      std::move(copyMoveableArray2));
  AutoTArray<Moveable, 4> autoMoveableArray2(
      std::move(differentAllocatorMoveableArray2));
  differentAllocatorMoveableArray2 = std::move(autoMoveableArray2);

  ASSERT_EQ(Moveable::Count(), 8);

  AutoTArray<Moveable, 8> moveableAutoArray;
  for (uint32_t i = 0; i < 4; ++i) {
    moveableAutoArray.AppendElement(Moveable());
  }

  ASSERT_EQ(Moveable::Count(), 12);

  const AutoTArray<Moveable, 8>& constRefMoveableAutoArray = moveableAutoArray;

  ASSERT_EQ(Moveable::Count(), 12);

  CopyableAutoTArray<Moveable, 8> copyMoveableAutoArray(
      constRefMoveableAutoArray);

  ASSERT_EQ(Moveable::Count(), 16);

  AutoTArray<Moveable, 8> movedMoveableAutoArray(std::move(moveableAutoArray));

  ASSERT_EQ(Moveable::Count(), 16);
}

template <typename TypeParam>
class TArray_MoveOnlyTest : public ::testing::Test {};

TYPED_TEST_SUITE_P(TArray_MoveOnlyTest);

static constexpr size_t kMoveOnlyTestArrayLength = 4;

template <typename ArrayType>
static auto MakeMoveOnlyArray() {
  ArrayType moveOnlyArray;
  for (size_t i = 0; i < kMoveOnlyTestArrayLength; ++i) {
    EXPECT_TRUE(moveOnlyArray.AppendElement(typename ArrayType::value_type(),
                                            fallible));
  }
  return moveOnlyArray;
}

TYPED_TEST_P(TArray_MoveOnlyTest, nsTArray_MoveConstruct) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  nsTArray<TypeParam> movedMoveOnlyArray(std::move(moveOnlyArray));

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, movedMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, nsTArray_MoveAssign) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  nsTArray<TypeParam> movedMoveOnlyArray;
  movedMoveOnlyArray = std::move(moveOnlyArray);

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, movedMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, nsTArray_MoveReAssign) {
  nsTArray<TypeParam> movedMoveOnlyArray;
  movedMoveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  // Re-assign, to check that move-assign does not only work on an empty array.
  movedMoveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();

  ASSERT_EQ(kMoveOnlyTestArrayLength, movedMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, nsTArray_to_FallibleTArray_MoveConstruct) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  FallibleTArray<TypeParam> differentAllocatorMoveOnlyArray(
      std::move(moveOnlyArray));

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, differentAllocatorMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, nsTArray_to_FallibleTArray_MoveAssign) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  FallibleTArray<TypeParam> differentAllocatorMoveOnlyArray;
  differentAllocatorMoveOnlyArray = std::move(moveOnlyArray);

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, differentAllocatorMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, FallibleTArray_to_nsTArray_MoveConstruct) {
  auto moveOnlyArray = MakeMoveOnlyArray<FallibleTArray<TypeParam>>();
  nsTArray<TypeParam> differentAllocatorMoveOnlyArray(std::move(moveOnlyArray));

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, differentAllocatorMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, FallibleTArray_to_nsTArray_MoveAssign) {
  auto moveOnlyArray = MakeMoveOnlyArray<FallibleTArray<TypeParam>>();
  nsTArray<TypeParam> differentAllocatorMoveOnlyArray;
  differentAllocatorMoveOnlyArray = std::move(moveOnlyArray);

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, differentAllocatorMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, AutoTArray_AutoStorage_MoveConstruct) {
  auto moveOnlyArray =
      MakeMoveOnlyArray<AutoTArray<TypeParam, kMoveOnlyTestArrayLength>>();
  AutoTArray<TypeParam, kMoveOnlyTestArrayLength> autoMoveOnlyArray(
      std::move(moveOnlyArray));

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest, AutoTArray_AutoStorage_MoveAssign) {
  auto moveOnlyArray =
      MakeMoveOnlyArray<AutoTArray<TypeParam, kMoveOnlyTestArrayLength>>();
  AutoTArray<TypeParam, kMoveOnlyTestArrayLength> autoMoveOnlyArray;
  autoMoveOnlyArray = std::move(moveOnlyArray);

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest,
             nsTArray_to_AutoTArray_AutoStorage_MoveConstruct) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  AutoTArray<TypeParam, kMoveOnlyTestArrayLength> autoMoveOnlyArray(
      std::move(moveOnlyArray));

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest,
             nsTArray_to_AutoTArray_AutoStorage_MoveAssign) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  AutoTArray<TypeParam, kMoveOnlyTestArrayLength> autoMoveOnlyArray;
  autoMoveOnlyArray = std::move(moveOnlyArray);

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest,
             nsTArray_to_AutoTArray_HeapStorage_MoveConstruct) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  AutoTArray<TypeParam, kMoveOnlyTestArrayLength - 1> autoMoveOnlyArray(
      std::move(moveOnlyArray));

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest,
             nsTArray_to_AutoTArray_HeapStorage_MoveAssign) {
  auto moveOnlyArray = MakeMoveOnlyArray<nsTArray<TypeParam>>();
  AutoTArray<TypeParam, kMoveOnlyTestArrayLength - 1> autoMoveOnlyArray;
  autoMoveOnlyArray = std::move(moveOnlyArray);

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest,
             FallibleTArray_to_AutoTArray_HeapStorage_MoveConstruct) {
  auto moveOnlyArray = MakeMoveOnlyArray<FallibleTArray<TypeParam>>();
  AutoTArray<TypeParam, 4> autoMoveOnlyArray(std::move(moveOnlyArray));

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

TYPED_TEST_P(TArray_MoveOnlyTest,
             FallibleTArray_to_AutoTArray_HeapStorage_MoveAssign) {
  auto moveOnlyArray = MakeMoveOnlyArray<FallibleTArray<TypeParam>>();
  AutoTArray<TypeParam, 4> autoMoveOnlyArray;
  autoMoveOnlyArray = std::move(moveOnlyArray);

  ASSERT_EQ(0u, moveOnlyArray.Length());
  ASSERT_EQ(kMoveOnlyTestArrayLength, autoMoveOnlyArray.Length());
}

REGISTER_TYPED_TEST_SUITE_P(
    TArray_MoveOnlyTest, nsTArray_MoveConstruct, nsTArray_MoveAssign,
    nsTArray_MoveReAssign, nsTArray_to_FallibleTArray_MoveConstruct,
    nsTArray_to_FallibleTArray_MoveAssign,
    FallibleTArray_to_nsTArray_MoveConstruct,
    FallibleTArray_to_nsTArray_MoveAssign, AutoTArray_AutoStorage_MoveConstruct,
    AutoTArray_AutoStorage_MoveAssign,
    nsTArray_to_AutoTArray_AutoStorage_MoveConstruct,
    nsTArray_to_AutoTArray_AutoStorage_MoveAssign,
    nsTArray_to_AutoTArray_HeapStorage_MoveConstruct,
    nsTArray_to_AutoTArray_HeapStorage_MoveAssign,
    FallibleTArray_to_AutoTArray_HeapStorage_MoveConstruct,
    FallibleTArray_to_AutoTArray_HeapStorage_MoveAssign);

using BothMoveOnlyTypes =
    ::testing::Types<MoveOnly_RelocateUsingMemutils,
                     MoveOnly_RelocateUsingMoveConstructor>;
INSTANTIATE_TYPED_TEST_SUITE_P(InstantiationOf, TArray_MoveOnlyTest,
                               BothMoveOnlyTypes);

//----

TEST(TArray, test_string_array)
{
  nsTArray<nsCString> strArray;
  const char kdata[] = "hello world";
  size_t i;
  for (i = 0; i < std::size(kdata); ++i) {
    nsCString str;
    str.Assign(kdata[i]);
    strArray.AppendElement(str);
  }
  for (i = 0; i < std::size(kdata); ++i) {
    ASSERT_EQ(strArray[i].CharAt(0), kdata[i]);
  }

  const char kextra[] = "foo bar";
  size_t oldLen = strArray.Length();
  strArray.AppendElement(kextra);
  strArray.RemoveElement(kextra);
  ASSERT_EQ(oldLen, strArray.Length());

  ASSERT_EQ(strArray.IndexOf("e"), size_t(1));
  ASSERT_TRUE(strArray.ApplyIf(
      "e", [](size_t i, nsCString& s) { return i == 1 && s == "e"; },
      []() { return false; }));

  strArray.Sort();
  const char ksorted[] = "\0 dehllloorw";
  for (i = std::size(kdata); i--;) {
    ASSERT_EQ(strArray[i].CharAt(0), ksorted[i]);
    if (i > 0 && strArray[i] == strArray[i - 1]) strArray.RemoveElementAt(i);
  }
  for (i = 0; i < strArray.Length(); ++i) {
    ASSERT_EQ(strArray.BinaryIndexOf(strArray[i]), i);
  }
  auto no_index = strArray.NoIndex;  // Fixes gtest compilation error
  ASSERT_EQ(strArray.BinaryIndexOf(""_ns), no_index);

  nsCString rawArray[std::size(kdata) - 1];
  for (i = 0; i < std::size(rawArray); ++i)
    rawArray[i].Assign(kdata + i);  // substrings of kdata

  ASSERT_TRUE(
      test_basic_array(rawArray, std::size(rawArray), nsCString("foopy")));
}

//----

typedef nsCOMPtr<nsIFile> FilePointer;

class nsFileNameComparator {
 public:
  bool Equals(const FilePointer& a, const char* b) const {
    nsAutoCString name;
    a->GetNativeLeafName(name);
    return name.Equals(b);
  }
};

TEST(TArray, test_comptr_array)
{
  FilePointer tmpDir;
  NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
  ASSERT_TRUE(tmpDir);
  const char* kNames[] = {"foo.txt""bar.html""baz.gif"};
  nsTArray<FilePointer> fileArray;
  size_t i;
  for (i = 0; i < std::size(kNames); ++i) {
    FilePointer f;
    tmpDir->Clone(getter_AddRefs(f));
    ASSERT_TRUE(f);
    ASSERT_NS_SUCCEEDED(f->AppendNative(nsDependentCString(kNames[i])));
    fileArray.AppendElement(f);
  }

  ASSERT_EQ(fileArray.IndexOf(kNames[1], 0, nsFileNameComparator()), size_t(1));
  ASSERT_TRUE(fileArray.ApplyIf(
      kNames[1], 0, nsFileNameComparator(), [](size_t i) { return i == 1; },
      []() { return false; }));

  // It's unclear what 'operator<' means for nsCOMPtr, but whatever...
  ASSERT_TRUE(
      test_basic_array(fileArray.Elements(), fileArray.Length(), tmpDir));
}

//----

class RefcountedObject {
 public:
  RefcountedObject() : rc(0) { val = std::rand(); }
  void AddRef() {
    MOZ_DIAGNOSTIC_ASSERT(rcchangeallowed);
    ++rc;
  }
  void Release() {
    MOZ_DIAGNOSTIC_ASSERT(rcchangeallowed);
    if (--rc == 0) delete this;
  }
  ~RefcountedObject() = default;

  int32_t GetVal() const { return val; }

  static void AllowRCChange() { rcchangeallowed = true; }
  static void ForbidRCChange() { rcchangeallowed = false; }

  bool operator<(const RefcountedObject& b) const {
    return this->GetVal() < b.GetVal();
  };

  bool operator==(const RefcountedObject& b) const {
    return this->GetVal() == b.GetVal();
  };

 private:
  int rc;
  int32_t val;
  static bool rcchangeallowed;
};
bool RefcountedObject::rcchangeallowed = true;

class ObjectComparatorRaw {
 public:
  bool Equals(RefcountedObject* const& a, RefcountedObject* const& b) const {
    return a->GetVal() == b->GetVal();
  }

  bool LessThan(RefcountedObject* const& a, RefcountedObject* const& b) const {
    return a->GetVal() < b->GetVal();
  }
};

class ObjectComparatorRefPtr {
 public:
  bool Equals(RefPtr<RefcountedObject> const& a,
              RefPtr<RefcountedObject> const& b) const {
    return a->GetVal() == b->GetVal();
  }

  bool LessThan(RefPtr<RefcountedObject> const& a,
                RefPtr<RefcountedObject> const& b) const {
    return a->GetVal() < b->GetVal();
  }
};

TEST(TArray, test_refptr_array)
{
  nsTArray<RefPtr<RefcountedObject>> objArray;

  RefcountedObject* a = new RefcountedObject();
  a->AddRef();
  RefcountedObject* b = new RefcountedObject();
  b->AddRef();
  RefcountedObject* c = new RefcountedObject();
  c->AddRef();

  objArray.AppendElement(a);
  objArray.AppendElement(b);
  objArray.AppendElement(c);

  ASSERT_EQ(objArray.IndexOf(b), size_t(1));
  ASSERT_TRUE(objArray.ApplyIf(
      b,
      [&](size_t i, RefPtr<RefcountedObject>& r) { return i == 1 && r == b; },
      []() { return false; }));

  a->Release();
  b->Release();
  c->Release();
}

TEST(TArray, test_sort_refptr)
{
  int numobjects = 1111111;
  std::vector<RefPtr<RefcountedObject>> myobjects;
  for (int i = 0; i < numobjects; i++) {
    auto* obj = new RefcountedObject();
    myobjects.push_back(obj);
  }

  {
    nsTArray<RefPtr<RefcountedObject>> objArray(numobjects);
    std::vector<RefPtr<RefcountedObject>> plainRefPtrArray(numobjects, nullptr);

    for (int i = 0; i < numobjects; i++) {
      objArray.AppendElement(myobjects[i]);
      plainRefPtrArray[i] = myobjects[i];
    }

    ASSERT_EQ(objArray.IndexOf(myobjects[1]), size_t(1));
    ASSERT_TRUE(objArray.ApplyIf(
        myobjects[1],
        [&](size_t i, RefPtr<RefcountedObject>& r) {
          return i == 1 && r == myobjects[1];
        },
        []() { return false; }));

    // Do not expect that sorting affects the reference counters of elements.
    RefcountedObject::ForbidRCChange();

    // Sort objArray with explicit, pointee value based comparator
    objArray.Sort(ObjectComparatorRefPtr());
    for (int i = 0; i < numobjects - 1; i++) {
      ASSERT_TRUE(objArray[i]->GetVal() <= objArray[i + 1]->GetVal());
    }

    // std::sort plainRefPtrArray
    auto comp = ObjectComparatorRefPtr();
    std::sort(plainRefPtrArray.begin(), plainRefPtrArray.end(),
              [&comp](auto const& left, auto const& right) {
                return comp.LessThan(left, right);
              });

    // We expect the order to be the same.
    for (int i = 0; i < numobjects; i++) {
      ASSERT_TRUE(objArray[i]->GetVal() == plainRefPtrArray[i]->GetVal());
    }

    RefcountedObject::AllowRCChange();
    // Destroy the arrays
  }

  for (int i = 0; i < numobjects; i++) {
    myobjects.pop_back();
  }
}

//----

TEST(TArray, test_ptrarray)
{
  nsTArray<uint32_t*> ary;
  ASSERT_EQ(ary.SafeElementAt(0), nullptr);
  ASSERT_EQ(ary.SafeElementAt(1000), nullptr);

  uint32_t a = 10;
  ary.AppendElement(&a);
  ASSERT_EQ(*ary[0], a);
  ASSERT_EQ(*ary.SafeElementAt(0), a);

  nsTArray<const uint32_t*> cary;
  ASSERT_EQ(cary.SafeElementAt(0), nullptr);
  ASSERT_EQ(cary.SafeElementAt(1000), nullptr);

  const uint32_t b = 14;
  cary.AppendElement(&a);
  cary.AppendElement(&b);
  ASSERT_EQ(*cary[0], a);
  ASSERT_EQ(*cary[1], b);
  ASSERT_EQ(*cary.SafeElementAt(0), a);
  ASSERT_EQ(*cary.SafeElementAt(1), b);
}

//----

// This test relies too heavily on the existence of DebugGetHeader to be
// useful in non-debug builds.
#ifdef DEBUG
TEST(TArray, test_autoarray)
{
  uint32_t data[] = {4, 6, 8, 2, 4, 1, 5, 7, 3};
  AutoTArray<uint32_t, std::size(data)> array;

  void* hdr = array.DebugGetHeader();
  ASSERT_NE(hdr, nsTArray<uint32_t>().DebugGetHeader());
  ASSERT_NE(hdr, (AutoTArray<uint32_t, std::size(data)>().DebugGetHeader()));

  array.AppendElement(1u);
  ASSERT_EQ(hdr, array.DebugGetHeader());

  array.RemoveElement(1u);
  array.AppendElements(data, std::size(data));
  ASSERT_EQ(hdr, array.DebugGetHeader());

  array.AppendElement(2u);
  ASSERT_NE(hdr, array.DebugGetHeader());

  array.Clear();
  array.Compact();
  ASSERT_EQ(hdr, array.DebugGetHeader());
  array.AppendElements(data, std::size(data));
  ASSERT_EQ(hdr, array.DebugGetHeader());

  nsTArray<uint32_t> array2;
  void* emptyHdr = array2.DebugGetHeader();
  array.SwapElements(array2);
  ASSERT_NE(emptyHdr, array.DebugGetHeader());
  ASSERT_NE(hdr, array2.DebugGetHeader());
  size_t i;
  for (i = 0; i < std::size(data); ++i) {
    ASSERT_EQ(array2[i], data[i]);
  }
  ASSERT_TRUE(array.IsEmpty());

  array.Compact();
  array.AppendElements(data, std::size(data));
  uint32_t data3[] = {5, 7, 11};
  AutoTArray<uint32_t, std::size(data3)> array3;
  array3.AppendElements(data3, std::size(data3));
  array.SwapElements(array3);
  for (i = 0; i < std::size(data); ++i) {
    ASSERT_EQ(array3[i], data[i]);
  }
  for (i = 0; i < std::size(data3); ++i) {
    ASSERT_EQ(array[i], data3[i]);
  }
}
#endif

//----

// IndexOf used to potentially scan beyond the end of the array.  Test for
// this incorrect behavior by adding a value (5), removing it, then seeing
// if IndexOf finds it.
TEST(TArray, test_indexof)
{
  nsTArray<int> array;
  array.AppendElement(0);
  // add and remove the 5
  array.AppendElement(5);
  array.RemoveElementAt(1);
  // we should not find the 5!
  auto no_index = array.NoIndex;  // Fixes gtest compilation error.
  ASSERT_EQ(array.IndexOf(5, 1), no_index);
  ASSERT_FALSE(
      array.ApplyIf(5, 1, []() { return true; }, []() { return false; }));
}

//----

template <class Array>
static bool is_heap(const Array& ary, size_t len) {
  size_t index = 1;
  while (index < len) {
    if (ary[index] > ary[(index - 1) >> 1]) return false;
    index++;
  }
  return true;
}

//----

// An array |arr| is using its auto buffer if |&arr < arr.Elements()| and
// |arr.Elements() - &arr| is small.

#define IS_USING_AUTO(arr)                              \
  ((uintptr_t) & (arr) < (uintptr_t)(arr).Elements() && \
   ((ptrdiff_t)(arr).Elements() - (ptrdiff_t) & (arr)) <= 16)

#define CHECK_IS_USING_AUTO(arr)     \
  do {                               \
    ASSERT_TRUE(IS_USING_AUTO(arr)); \
  } while (0)

#define CHECK_NOT_USING_AUTO(arr)     \
  do {                                \
    ASSERT_FALSE(IS_USING_AUTO(arr)); \
  } while (0)

#define CHECK_USES_SHARED_EMPTY_HDR(arr)            \
  do {                                              \
    nsTArray<int> _empty;                           \
    ASSERT_EQ(_empty.Elements(), (arr).Elements()); \
  } while (0)

#define CHECK_EQ_INT(actual, expected) \
  do {                                 \
    ASSERT_EQ((actual), (expected));   \
  } while (0)

#define CHECK_ARRAY(arr, data)                             \
  do {                                                     \
    CHECK_EQ_INT((arr).Length(), (size_t)std::size(data)); \
    for (size_t _i = 0; _i < std::size(data); _i++) {      \
      CHECK_EQ_INT((arr)[_i], (data)[_i]);                 \
    }                                                      \
  } while (0)

TEST(TArray, test_swap)
{
  // Test nsTArray::SwapElements.  Unfortunately there are many cases.
  int data1[] = {8, 6, 7, 5};
  int data2[] = {3, 0, 9};

  // Swap two auto arrays.
  {
    AutoTArray<int, 8> a;
    AutoTArray<int, 6> b;

    a.AppendElements(data1, std::size(data1));
    b.AppendElements(data2, std::size(data2));
    CHECK_IS_USING_AUTO(a);
    CHECK_IS_USING_AUTO(b);

    a.SwapElements(b);

    CHECK_IS_USING_AUTO(a);
    CHECK_IS_USING_AUTO(b);
    CHECK_ARRAY(a, data2);
    CHECK_ARRAY(b, data1);
  }

  // Swap two auto arrays -- one whose data lives on the heap, the other whose
  // data lives on the stack -- which each fits into the other's auto storage.
  {
    AutoTArray<int, 3> a;
    AutoTArray<int, 3> b;

    a.AppendElements(data1, std::size(data1));
    a.RemoveElementAt(3);
    b.AppendElements(data2, std::size(data2));

    // Here and elsewhere, we assert that if we start with an auto array
    // capable of storing N elements, we store N+1 elements into the array, and
    // then we remove one element, that array is still not using its auto
    // buffer.
    //
    // This isn't at all required by the TArray API. It would be fine if, when
    // we shrink back to N elements, the TArray frees its heap storage and goes
    // back to using its stack storage.  But we assert here as a check that the
    // test does what we expect.  If the TArray implementation changes, just
    // change the failing assertions.
    CHECK_NOT_USING_AUTO(a);

    // This check had better not change, though.
    CHECK_IS_USING_AUTO(b);

    a.SwapElements(b);

    CHECK_IS_USING_AUTO(b);
    CHECK_ARRAY(a, data2);
    int expectedB[] = {8, 6, 7};
    CHECK_ARRAY(b, expectedB);
  }

  // Swap two auto arrays which are using heap storage such that one fits into
  // the other's auto storage, but the other needs to stay on the heap.
  {
    AutoTArray<int, 3> a;
    AutoTArray<int, 2> b;
    a.AppendElements(data1, std::size(data1));
    a.RemoveElementAt(3);

    b.AppendElements(data2, std::size(data2));
    b.RemoveElementAt(2);

    CHECK_NOT_USING_AUTO(a);
    CHECK_NOT_USING_AUTO(b);

    a.SwapElements(b);

    CHECK_NOT_USING_AUTO(b);

    int expected1[] = {3, 0};
    int expected2[] = {8, 6, 7};

    CHECK_ARRAY(a, expected1);
    CHECK_ARRAY(b, expected2);
  }

  // Swap two arrays, neither of which fits into the other's auto-storage.
  {
    AutoTArray<int, 1> a;
    AutoTArray<int, 3> b;

    a.AppendElements(data1, std::size(data1));
    b.AppendElements(data2, std::size(data2));

    a.SwapElements(b);

    CHECK_ARRAY(a, data2);
    CHECK_ARRAY(b, data1);
  }

  // Swap an empty nsTArray with a non-empty AutoTArray.
  {
    nsTArray<int> a;
    AutoTArray<int, 3> b;

    b.AppendElements(data2, std::size(data2));
    CHECK_IS_USING_AUTO(b);

    a.SwapElements(b);

    CHECK_ARRAY(a, data2);
    CHECK_EQ_INT(b.Length(), size_t(0));
    CHECK_IS_USING_AUTO(b);
  }

  // Swap two big auto arrays.
  {
    const unsigned size = 8192;
    AutoTArray<unsigned, size> a;
    AutoTArray<unsigned, size> b;

    for (unsigned i = 0; i < size; i++) {
      a.AppendElement(i);
      b.AppendElement(i + 1);
    }

    CHECK_IS_USING_AUTO(a);
    CHECK_IS_USING_AUTO(b);

    a.SwapElements(b);

    CHECK_IS_USING_AUTO(a);
    CHECK_IS_USING_AUTO(b);

    CHECK_EQ_INT(a.Length(), size_t(size));
    CHECK_EQ_INT(b.Length(), size_t(size));

    for (unsigned i = 0; i < size; i++) {
      CHECK_EQ_INT(a[i], i + 1);
      CHECK_EQ_INT(b[i], i);
    }
  }

  // Swap two arrays and make sure that their capacities don't increase
  // unnecessarily.
  {
    nsTArray<int> a;
    nsTArray<int> b;
    b.AppendElements(data2, std::size(data2));

    CHECK_EQ_INT(a.Capacity(), size_t(0));
    size_t bCapacity = b.Capacity();

    a.SwapElements(b);

    // Make sure that we didn't increase the capacity of either array.
    CHECK_ARRAY(a, data2);
    CHECK_EQ_INT(b.Length(), size_t(0));
    CHECK_EQ_INT(b.Capacity(), size_t(0));
    CHECK_EQ_INT(a.Capacity(), bCapacity);
  }

  // Swap an auto array with a TArray, then clear the auto array and make sure
  // it doesn't forget the fact that it has an auto buffer.
  {
    nsTArray<int> a;
    AutoTArray<int, 3> b;

    a.AppendElements(data1, std::size(data1));

    a.SwapElements(b);

    CHECK_EQ_INT(a.Length(), size_t(0));
    CHECK_ARRAY(b, data1);

    b.Clear();

    CHECK_USES_SHARED_EMPTY_HDR(a);
    CHECK_IS_USING_AUTO(b);
  }

  // Same thing as the previous test, but with more auto arrays.
  {
    AutoTArray<int, 16> a;
    AutoTArray<int, 3> b;

    a.AppendElements(data1, std::size(data1));

    a.SwapElements(b);

    CHECK_EQ_INT(a.Length(), size_t(0));
    CHECK_ARRAY(b, data1);

    b.Clear();

    CHECK_IS_USING_AUTO(a);
    CHECK_IS_USING_AUTO(b);
  }

  // Swap an empty nsTArray and an empty AutoTArray.
  {
    AutoTArray<int, 8> a;
    nsTArray<int> b;

    a.SwapElements(b);

    CHECK_IS_USING_AUTO(a);
    CHECK_NOT_USING_AUTO(b);
    CHECK_EQ_INT(a.Length(), size_t(0));
    CHECK_EQ_INT(b.Length(), size_t(0));
  }

  // Swap empty auto array with non-empty AutoTArray using malloc'ed storage.
  // I promise, all these tests have a point.
  {
    AutoTArray<int, 2> a;
    AutoTArray<int, 1> b;

    a.AppendElements(data1, std::size(data1));

    a.SwapElements(b);

    CHECK_IS_USING_AUTO(a);
    CHECK_NOT_USING_AUTO(b);
    CHECK_ARRAY(b, data1);
    CHECK_EQ_INT(a.Length(), size_t(0));
  }

  // Test fallible SwapElements of nsTArray.
  {
    nsTArray<int> a;
    nsTArray<int> b;

    a.AppendElements(data1, std::size(data1));

    ASSERT_TRUE(a.SwapElements(b, fallible));

    CHECK_ARRAY(b, data1);
    CHECK_EQ_INT(a.Length(), size_t(0));
  }

  // Test fallible SwapElements of FallibleTArray.
  {
    FallibleTArray<int> a;
    FallibleTArray<int> b;

    ASSERT_TRUE(a.AppendElements(data1, std::size(data1), fallible));

    ASSERT_TRUE(a.SwapElements(b, fallible));

    CHECK_ARRAY(b, data1);
    CHECK_EQ_INT(a.Length(), size_t(0));
  }

  // Test fallible SwapElements of FallibleTArray with large AutoTArray.
  {
    FallibleTArray<int> a;
    AutoTArray<int, 8192> b;

    ASSERT_TRUE(a.AppendElements(data1, std::size(data1), fallible));

    ASSERT_TRUE(a.SwapElements(b, fallible));

    CHECK_IS_USING_AUTO(b);
    CHECK_ARRAY(b, data1);
    CHECK_EQ_INT(a.Length(), size_t(0));
  }
}

// Bug 1171296: Disabled on andoid due to crashes.
#if !defined(ANDROID)
TEST(TArray, test_fallible)
{
  // Test that FallibleTArray works properly; that is, it never OOMs, but
  // instead eventually returns false.
  //
  // This test is only meaningful on 32-bit systems.  On a 64-bit system, we
  // might never OOM.
  if (sizeof(void*) > 4) {
    ASSERT_TRUE(true);
    return;
  }

  // Allocate a bunch of 128MB arrays.  Larger allocations will fail on some
  // platforms without actually hitting OOM.
  //
  // 36 * 128MB > 4GB, so we should definitely OOM by the 36th array.
  const unsigned numArrays = 36;
  FallibleTArray<char> arrays[numArrays];
  bool oomed = false;
  for (size_t i = 0; i < numArrays; i++) {
    // SetCapacity allocates the requested capacity + a header, and we want to
    // avoid allocating more than 128MB overall because of the size padding it
    // will cause, which depends on allocator behavior, so use 128MB - an
    // arbitrary size larger than the array header, so that chances are good
    // that allocations will always be 128MB.
    bool success = arrays[i].SetCapacity(128 * 1024 * 1024 - 1024, fallible);
    if (!success) {
      // We got our OOM.  Check that it didn't come too early.
      oomed = true;
#  ifdef XP_WIN
      // 32-bit Windows sometimes OOMs on the 6th, 7th, or 8th.  To keep the
      // test green, choose the lower of those: the important thing here is
      // that some allocations fail and some succeed.  We're not too
      // concerned about how many iterations it takes.
      const size_t kOOMIterations = 6;
#  else
      const size_t kOOMIterations = 8;
#  endif
      ASSERT_GE(i, kOOMIterations)
          << "Got OOM on iteration " << i << ". Too early!";
    }
  }

  ASSERT_TRUE(oomed)
  << "Didn't OOM or crash? nsTArray::SetCapacity"
     "must be lying.";
}
#endif

TEST(TArray, test_conversion_operator)
{
  FallibleTArray<int> f;
  const FallibleTArray<int> fconst;

  nsTArray<int> t;
  const nsTArray<int> tconst;
  AutoTArray<int, 8> tauto;
  const AutoTArray<int, 8> tautoconst;

#define CHECK_ARRAY_CAST(type)                  \
  do {                                          \
    const type<int>& z1 = f;                    \
    ASSERT_EQ((void*)&z1, (void*)&f);           \
    const type<int>& z2 = fconst;               \
    ASSERT_EQ((void*)&z2, (void*)&fconst);      \
    const type<int>& z9 = t;                    \
    ASSERT_EQ((void*)&z9, (void*)&t);           \
    const type<int>& z10 = tconst;              \
    ASSERT_EQ((void*)&z10, (void*)&tconst);     \
    const type<int>& z11 = tauto;               \
    ASSERT_EQ((void*)&z11, (void*)&tauto);      \
    const type<int>& z12 = tautoconst;          \
    ASSERT_EQ((void*)&z12, (void*)&tautoconst); \
  } while (0)

  CHECK_ARRAY_CAST(FallibleTArray);
  CHECK_ARRAY_CAST(nsTArray);

#undef CHECK_ARRAY_CAST
}

template <class T>
struct BufAccessor : public T {
  void* GetHdr() { return T::mHdr; }
};

TEST(TArray, test_SetLengthAndRetainStorage_no_ctor)
{
  // 1050 because sizeof(int)*1050 is more than a page typically.
  const int N = 1050;
  FallibleTArray<int> f;

  nsTArray<int> t;
  AutoTArray<int, N> tauto;

#define LPAREN (
#define RPAREN )
#define FOR_EACH(pre, post) \
  do {                      \
    pre f post;             \
    pre t post;             \
    pre tauto post;         \
  } while (0)

  // Setup test arrays.
  FOR_EACH(; Unused <<, .SetLength(N, fallible));
  for (int n = 0; n < N; ++n) {
    FOR_EACH(;, [n] = n);
  }

  void* initial_Hdrs[] = {
      static_cast<BufAccessor<FallibleTArray<int>>&>(f).GetHdr(),
      static_cast<BufAccessor<nsTArray<int>>&>(t).GetHdr(),
      static_cast<BufAccessor<AutoTArray<int, N>>&>(tauto).GetHdr(), nullptr};

  // SetLengthAndRetainStorage(n), should NOT overwrite memory when T hasn't
  // a default constructor.
  FOR_EACH(;, .SetLengthAndRetainStorage(8));
  FOR_EACH(;, .SetLengthAndRetainStorage(12));
  for (int n = 0; n < 12; ++n) {
    ASSERT_EQ(f[n], n);
    ASSERT_EQ(t[n], n);
    ASSERT_EQ(tauto[n], n);
  }
  FOR_EACH(;, .SetLengthAndRetainStorage(0));
  FOR_EACH(;, .SetLengthAndRetainStorage(N));
  for (int n = 0; n < N; ++n) {
    ASSERT_EQ(f[n], n);
    ASSERT_EQ(t[n], n);
    ASSERT_EQ(tauto[n], n);
  }

  void* current_Hdrs[] = {
      static_cast<BufAccessor<FallibleTArray<int>>&>(f).GetHdr(),
      static_cast<BufAccessor<nsTArray<int>>&>(t).GetHdr(),
      static_cast<BufAccessor<AutoTArray<int, N>>&>(tauto).GetHdr(), nullptr};

  // SetLengthAndRetainStorage(n) should NOT have reallocated the internal
  // memory.
  ASSERT_EQ(sizeof(initial_Hdrs), sizeof(current_Hdrs));
  for (size_t n = 0; n < sizeof(current_Hdrs) / sizeof(current_Hdrs[0]); ++n) {
    ASSERT_EQ(current_Hdrs[n], initial_Hdrs[n]);
  }

#undef FOR_EACH
#undef LPAREN
#undef RPAREN
}

template <typename Comparator>
bool TestCompareMethods(const Comparator& aComp) {
  nsTArray<int> ary({57, 4, 16, 17, 3, 5, 96, 12});

  ary.Sort(aComp);

  const int sorted[] = {3, 4, 5, 12, 16, 17, 57, 96};
  for (size_t i = 0; i < std::size(sorted); i++) {
    if (sorted[i] != ary[i]) {
      return false;
    }
  }

  if (!ary.ContainsSorted(5, aComp)) {
    return false;
  }
  if (ary.ContainsSorted(42, aComp)) {
    return false;
  }

  if (ary.BinaryIndexOf(16, aComp) != 4) {
    return false;
  }

  return true;
}

struct IntComparator {
  bool Equals(int aLeft, int aRight) const { return aLeft == aRight; }

  bool LessThan(int aLeft, int aRight) const { return aLeft < aRight; }
};

TEST(TArray, test_comparator_objects)
{
  ASSERT_TRUE(TestCompareMethods(IntComparator()));
  ASSERT_TRUE(
      TestCompareMethods([](int aLeft, int aRight) { return aLeft - aRight; }));
}

struct Big {
  uint64_t size[40] = {};
};

TEST(TArray, test_AutoTArray_SwapElements)
{
  AutoTArray<Big, 40> oneArray;
  AutoTArray<Big, 40> another;

  for (size_t i = 0; i < 8; ++i) {
    oneArray.AppendElement(Big());
  }
  oneArray[0].size[10] = 1;
  for (size_t i = 0; i < 9; ++i) {
    another.AppendElement(Big());
  }
  oneArray.SwapElements(another);

  ASSERT_EQ(oneArray.Length(), 9u);
  ASSERT_EQ(another.Length(), 8u);

  ASSERT_EQ(oneArray[0].size[10], 0u);
  ASSERT_EQ(another[0].size[10], 1u);
}

}  // namespace TestTArray

88%


¤ Dauer der Verarbeitung: 0.18 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 ist noch experimentell.