xpcom/tests/TestTArray.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "mozilla/ArrayUtils.h"
     9 #include <stdlib.h>
    10 #include <stdio.h>
    11 #include "nsTArray.h"
    12 #include "nsAutoPtr.h"
    13 #include "nsStringAPI.h"
    14 #include "nsDirectoryServiceDefs.h"
    15 #include "nsDirectoryServiceUtils.h"
    16 #include "nsComponentManagerUtils.h"
    17 #include "nsXPCOM.h"
    18 #include "nsIFile.h"
    20 using namespace mozilla;
    22 namespace TestTArray {
    24 // Define this so we can use test_basic_array in test_comptr_array
    25 template <class T>
    26 inline bool operator<(const nsCOMPtr<T>& lhs, const nsCOMPtr<T>& rhs) {
    27   return lhs.get() < rhs.get();
    28 }
    30 //----
    32 template <class ElementType>
    33 static bool test_basic_array(ElementType *data,
    34                                uint32_t dataLen,
    35                                const ElementType& extra) {
    36   nsTArray<ElementType> ary;
    37   ary.AppendElements(data, dataLen);
    38   if (ary.Length() != dataLen) {
    39     return false;
    40   }
    41   if (!(ary == ary)) {
    42     return false;
    43   }
    44   uint32_t i;
    45   for (i = 0; i < ary.Length(); ++i) {
    46     if (ary[i] != data[i])
    47       return false;
    48   }
    49   for (i = 0; i < ary.Length(); ++i) {
    50     if (ary.SafeElementAt(i, extra) != data[i])
    51       return false;
    52   }
    53   if (ary.SafeElementAt(ary.Length(), extra) != extra ||
    54       ary.SafeElementAt(ary.Length() * 10, extra) != extra)
    55     return false;
    56   // ensure sort results in ascending order
    57   ary.Sort();
    58   uint32_t j = 0, k = ary.IndexOfFirstElementGt(extra);
    59   if (k != 0 && ary[k-1] == extra)
    60     return false;
    61   for (i = 0; i < ary.Length(); ++i) {
    62     k = ary.IndexOfFirstElementGt(ary[i]);
    63     if (k == 0 || ary[k-1] != ary[i])
    64       return false;
    65     if (k < j)
    66       return false;
    67     j = k;
    68   }
    69   for (i = ary.Length(); --i; ) {
    70     if (ary[i] < ary[i - 1])
    71       return false;
    72     if (ary[i] == ary[i - 1])
    73       ary.RemoveElementAt(i);
    74   }
    75   if (!(ary == ary)) {
    76     return false;
    77   }
    78   for (i = 0; i < ary.Length(); ++i) {
    79     if (ary.BinaryIndexOf(ary[i]) != i)
    80       return false;
    81   }
    82   if (ary.BinaryIndexOf(extra) != ary.NoIndex)
    83     return false;
    84   uint32_t oldLen = ary.Length();
    85   ary.RemoveElement(data[dataLen / 2]);
    86   if (ary.Length() != (oldLen - 1))
    87     return false;
    88   if (!(ary == ary))
    89     return false;
    91   uint32_t index = ary.Length() / 2;
    92   if (!ary.InsertElementAt(index, extra))
    93     return false;
    94   if (!(ary == ary))
    95     return false;
    96   if (ary[index] != extra)
    97     return false;
    98   if (ary.IndexOf(extra) == UINT32_MAX)
    99     return false;
   100   if (ary.LastIndexOf(extra) == UINT32_MAX)
   101     return false;
   102   // ensure proper searching
   103   if (ary.IndexOf(extra) > ary.LastIndexOf(extra))
   104     return false;
   105   if (ary.IndexOf(extra, index) != ary.LastIndexOf(extra, index))
   106     return false;
   108   nsTArray<ElementType> copy(ary);
   109   if (!(ary == copy))
   110     return false;
   111   for (i = 0; i < copy.Length(); ++i) {
   112     if (ary[i] != copy[i])
   113       return false;
   114   }
   115   if (!ary.AppendElements(copy))
   116     return false;
   117   uint32_t cap = ary.Capacity();
   118   ary.RemoveElementsAt(copy.Length(), copy.Length());
   119   ary.Compact();
   120   if (ary.Capacity() == cap)
   121     return false;
   123   ary.Clear();
   124   if (ary.IndexOf(extra) != UINT32_MAX)
   125     return false;
   126   if (ary.LastIndexOf(extra) != UINT32_MAX)
   127     return false;
   129   ary.Clear();
   130   if (!ary.IsEmpty() || ary.Elements() == nullptr)
   131     return false;
   132   if (!(ary == nsTArray<ElementType>()))
   133     return false;
   134   if (ary == copy)
   135     return false;
   136   if (ary.SafeElementAt(0, extra) != extra ||
   137       ary.SafeElementAt(10, extra) != extra)
   138     return false;
   140   ary = copy;
   141   if (!(ary == copy))
   142     return false;
   143   for (i = 0; i < copy.Length(); ++i) {
   144     if (ary[i] != copy[i])
   145       return false;
   146   }
   148   if (!ary.InsertElementsAt(0, copy))
   149     return false;
   150   if (ary == copy)
   151     return false;
   152   ary.RemoveElementsAt(0, copy.Length());
   153   for (i = 0; i < copy.Length(); ++i) {
   154     if (ary[i] != copy[i])
   155       return false;
   156   }
   158   // These shouldn't crash!
   159   nsTArray<ElementType> empty;
   160   ary.AppendElements(reinterpret_cast<ElementType *>(0), 0);
   161   ary.AppendElements(empty);
   163   // See bug 324981
   164   ary.RemoveElement(extra);
   165   ary.RemoveElement(extra);
   167   return true;
   168 }
   170 static bool test_int_array() {
   171   int data[] = {4,6,8,2,4,1,5,7,3};
   172   return test_basic_array(data, ArrayLength(data), int(14));
   173 }
   175 static bool test_int64_array() {
   176   int64_t data[] = {4,6,8,2,4,1,5,7,3};
   177   return test_basic_array(data, ArrayLength(data), int64_t(14));
   178 }
   180 static bool test_char_array() {
   181   char data[] = {4,6,8,2,4,1,5,7,3};
   182   return test_basic_array(data, ArrayLength(data), char(14));
   183 }
   185 static bool test_uint32_array() {
   186   uint32_t data[] = {4,6,8,2,4,1,5,7,3};
   187   return test_basic_array(data, ArrayLength(data), uint32_t(14));
   188 }
   190 //----
   192 class Object {
   193   public:
   194     Object() : mNum(0) {
   195     }
   196     Object(const char *str, uint32_t num) : mStr(str), mNum(num) {
   197     }
   198     Object(const Object& other) : mStr(other.mStr), mNum(other.mNum) {
   199     }
   200     ~Object() {}
   202     Object& operator=(const Object& other) {
   203       mStr = other.mStr;
   204       mNum = other.mNum;
   205       return *this;
   206     }
   208     bool operator==(const Object& other) const {
   209       return mStr == other.mStr && mNum == other.mNum;
   210     }
   212     bool operator<(const Object& other) const {
   213       // sort based on mStr only
   214       return mStr.Compare(other.mStr) < 0;
   215     }
   217     const char *Str() const { return mStr.get(); }
   218     uint32_t Num() const { return mNum; }
   220   private:
   221     nsCString mStr;
   222     uint32_t  mNum;
   223 };
   225 static bool test_object_array() {
   226   nsTArray<Object> objArray;
   227   const char kdata[] = "hello world";
   228   uint32_t i;
   229   for (i = 0; i < ArrayLength(kdata); ++i) {
   230     char x[] = {kdata[i],'\0'};
   231     if (!objArray.AppendElement(Object(x, i)))
   232       return false;
   233   }
   234   for (i = 0; i < ArrayLength(kdata); ++i) {
   235     if (objArray[i].Str()[0] != kdata[i])
   236       return false;
   237     if (objArray[i].Num() != i)
   238       return false;
   239   }
   240   objArray.Sort();
   241   const char ksorted[] = "\0 dehllloorw";
   242   for (i = 0; i < ArrayLength(kdata)-1; ++i) {
   243     if (objArray[i].Str()[0] != ksorted[i])
   244       return false;
   245   }
   246   return true;
   247 }
   249 // nsTArray<nsAutoPtr<T>> is not supported
   250 #if 0
   251 static bool test_autoptr_array() {
   252   nsTArray< nsAutoPtr<Object> > objArray;
   253   const char kdata[] = "hello world";
   254   for (uint32_t i = 0; i < ArrayLength(kdata); ++i) {
   255     char x[] = {kdata[i],'\0'};
   256     nsAutoPtr<Object> obj(new Object(x,i));
   257     if (!objArray.AppendElement(obj))  // XXX does not call copy-constructor for nsAutoPtr!!!
   258       return false;
   259     if (obj.get() == nullptr)
   260       return false;
   261     obj.forget();  // the array now owns the reference
   262   }
   263   for (uint32_t i = 0; i < ArrayLength(kdata); ++i) {
   264     if (objArray[i]->Str()[0] != kdata[i])
   265       return false;
   266     if (objArray[i]->Num() != i)
   267       return false;
   268   }
   269   return true;
   270 }
   271 #endif
   273 //----
   275 static bool test_string_array() {
   276   nsTArray<nsCString> strArray;
   277   const char kdata[] = "hello world";
   278   uint32_t i;
   279   for (i = 0; i < ArrayLength(kdata); ++i) {
   280     nsCString str;
   281     str.Assign(kdata[i]);
   282     if (!strArray.AppendElement(str))
   283       return false;
   284   }
   285   for (i = 0; i < ArrayLength(kdata); ++i) {
   286     if (strArray[i].CharAt(0) != kdata[i])
   287       return false;
   288   }
   290   const char kextra[] = "foo bar";
   291   uint32_t oldLen = strArray.Length();
   292   if (!strArray.AppendElement(kextra))
   293     return false;
   294   strArray.RemoveElement(kextra);
   295   if (oldLen != strArray.Length())
   296     return false;
   298   if (strArray.IndexOf("e") != 1)
   299     return false;
   301   strArray.Sort();
   302   const char ksorted[] = "\0 dehllloorw";
   303   for (i = ArrayLength(kdata); i--; ) {
   304     if (strArray[i].CharAt(0) != ksorted[i])
   305       return false;
   306     if (i > 0 && strArray[i] == strArray[i - 1])
   307       strArray.RemoveElementAt(i);
   308   }
   309   for (i = 0; i < strArray.Length(); ++i) {
   310     if (strArray.BinaryIndexOf(strArray[i]) != i)
   311       return false;
   312   }
   313   if (strArray.BinaryIndexOf(EmptyCString()) != strArray.NoIndex)
   314     return false;
   316   nsCString rawArray[MOZ_ARRAY_LENGTH(kdata) - 1];
   317   for (i = 0; i < ArrayLength(rawArray); ++i)
   318     rawArray[i].Assign(kdata + i);  // substrings of kdata
   319   return test_basic_array(rawArray, ArrayLength(rawArray),
   320                           nsCString("foopy"));
   321 }
   323 //----
   325 typedef nsCOMPtr<nsIFile> FilePointer;
   327 class nsFileNameComparator {
   328   public:
   329     bool Equals(const FilePointer &a, const char *b) const {
   330       nsAutoCString name;
   331       a->GetNativeLeafName(name);
   332       return name.Equals(b);
   333     }
   334 };
   336 static bool test_comptr_array() {
   337   FilePointer tmpDir;
   338   NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
   339   if (!tmpDir)
   340     return false;
   341   const char *kNames[] = {
   342     "foo.txt", "bar.html", "baz.gif"
   343   };
   344   nsTArray<FilePointer> fileArray;
   345   uint32_t i;
   346   for (i = 0; i < ArrayLength(kNames); ++i) {
   347     FilePointer f;
   348     tmpDir->Clone(getter_AddRefs(f));
   349     if (!f)
   350       return false;
   351     if (NS_FAILED(f->AppendNative(nsDependentCString(kNames[i]))))
   352       return false;
   353     fileArray.AppendElement(f);
   354   }
   356   if (fileArray.IndexOf(kNames[1], 0, nsFileNameComparator()) != 1)
   357     return false;
   359   // It's unclear what 'operator<' means for nsCOMPtr, but whatever...
   360   return test_basic_array(fileArray.Elements(), fileArray.Length(), 
   361                           tmpDir);
   362 }
   364 //----
   366 class RefcountedObject {
   367   public:
   368     RefcountedObject() : rc(0) {}
   369     void AddRef() {
   370       ++rc;
   371     }
   372     void Release() {
   373       if (--rc == 0)
   374         delete this;
   375     }
   376     ~RefcountedObject() {}
   377   private:
   378     int32_t rc;
   379 };
   381 static bool test_refptr_array() {
   382   bool rv = true;
   384   nsTArray< nsRefPtr<RefcountedObject> > objArray;
   386   RefcountedObject *a = new RefcountedObject(); a->AddRef();
   387   RefcountedObject *b = new RefcountedObject(); b->AddRef();
   388   RefcountedObject *c = new RefcountedObject(); c->AddRef();
   390   objArray.AppendElement(a);
   391   objArray.AppendElement(b);
   392   objArray.AppendElement(c);
   394   if (objArray.IndexOf(b) != 1)
   395     rv = false;
   397   a->Release();
   398   b->Release();
   399   c->Release();
   400   return rv;
   401 }
   403 //----
   405 static bool test_ptrarray() {
   406   nsTArray<uint32_t*> ary;
   407   if (ary.SafeElementAt(0) != nullptr)
   408     return false;
   409   if (ary.SafeElementAt(1000) != nullptr)
   410     return false;
   411   uint32_t a = 10;
   412   ary.AppendElement(&a);
   413   if (*ary[0] != a)
   414     return false;
   415   if (*ary.SafeElementAt(0) != a)
   416     return false;
   418   nsTArray<const uint32_t*> cary;
   419   if (cary.SafeElementAt(0) != nullptr)
   420     return false;
   421   if (cary.SafeElementAt(1000) != nullptr)
   422     return false;
   423   const uint32_t b = 14;
   424   cary.AppendElement(&a);
   425   cary.AppendElement(&b);
   426   if (*cary[0] != a || *cary[1] != b)
   427     return false;
   428   if (*cary.SafeElementAt(0) != a || *cary.SafeElementAt(1) != b)
   429     return false;
   431   return true;
   432 }
   434 //----
   436 // This test relies too heavily on the existence of DebugGetHeader to be
   437 // useful in non-debug builds.
   438 #ifdef DEBUG
   439 static bool test_autoarray() {
   440   uint32_t data[] = {4,6,8,2,4,1,5,7,3};
   441   nsAutoTArray<uint32_t, MOZ_ARRAY_LENGTH(data)> array;
   443   void* hdr = array.DebugGetHeader();
   444   if (hdr == nsTArray<uint32_t>().DebugGetHeader())
   445     return false;
   446   if (hdr == nsAutoTArray<uint32_t, MOZ_ARRAY_LENGTH(data)>().DebugGetHeader())
   447     return false;
   449   array.AppendElement(1u);
   450   if (hdr != array.DebugGetHeader())
   451     return false;
   453   array.RemoveElement(1u);
   454   array.AppendElements(data, ArrayLength(data));
   455   if (hdr != array.DebugGetHeader())
   456     return false;
   458   array.AppendElement(2u);
   459   if (hdr == array.DebugGetHeader())
   460     return false;
   462   array.Clear();
   463   array.Compact();
   464   if (hdr != array.DebugGetHeader())
   465     return false;
   466   array.AppendElements(data, ArrayLength(data));
   467   if (hdr != array.DebugGetHeader())
   468     return false;
   470   nsTArray<uint32_t> array2;
   471   void* emptyHdr = array2.DebugGetHeader();
   472   array.SwapElements(array2);
   473   if (emptyHdr == array.DebugGetHeader())
   474     return false;
   475   if (hdr == array2.DebugGetHeader())
   476     return false;
   477   uint32_t i;
   478   for (i = 0; i < ArrayLength(data); ++i) {
   479     if (array2[i] != data[i])
   480       return false;
   481   }
   482   if (!array.IsEmpty())
   483     return false;
   485   array.Compact();
   486   array.AppendElements(data, ArrayLength(data));
   487   uint32_t data3[] = {5, 7, 11};
   488   nsAutoTArray<uint32_t, MOZ_ARRAY_LENGTH(data3)> array3;
   489   array3.AppendElements(data3, ArrayLength(data3));  
   490   array.SwapElements(array3);
   491   for (i = 0; i < ArrayLength(data); ++i) {
   492     if (array3[i] != data[i])
   493       return false;
   494   }
   495   for (i = 0; i < ArrayLength(data3); ++i) {
   496     if (array[i] != data3[i])
   497       return false;
   498   }
   500   return true;
   501 }
   502 #endif
   504 //----
   506 // IndexOf used to potentially scan beyond the end of the array.  Test for
   507 // this incorrect behavior by adding a value (5), removing it, then seeing
   508 // if IndexOf finds it.
   509 static bool test_indexof() {
   510   nsTArray<int> array;
   511   array.AppendElement(0);
   512   // add and remove the 5
   513   array.AppendElement(5);
   514   array.RemoveElementAt(1);
   515   // we should not find the 5!
   516   return array.IndexOf(5, 1) == array.NoIndex;
   517 }
   519 //----
   521 template <class Array>
   522 static bool is_heap(const Array& ary, uint32_t len) {
   523   uint32_t index = 1;
   524   while (index < len) {
   525     if (ary[index] > ary[(index - 1) >> 1])
   526       return false;
   527     index++;
   528   }
   529   return true;
   530 } 
   532 static bool test_heap() {
   533   const int data[] = {4,6,8,2,4,1,5,7,3};
   534   nsTArray<int> ary;
   535   ary.AppendElements(data, ArrayLength(data));
   536   // make a heap and make sure it's a heap
   537   ary.MakeHeap();
   538   if (!is_heap(ary, ArrayLength(data)))
   539     return false;
   540   // pop the root and make sure it's still a heap
   541   int root = ary[0];
   542   ary.PopHeap();
   543   if (!is_heap(ary, ArrayLength(data) - 1))
   544     return false;
   545   // push the previously poped value back on and make sure it's still a heap
   546   ary.PushHeap(root);
   547   if (!is_heap(ary, ArrayLength(data)))
   548     return false;
   549   // make sure the heap looks like what we expect
   550   const int expected_data[] = {8,7,5,6,4,1,4,2,3};
   551   uint32_t index;
   552   for (index = 0; index < ArrayLength(data); index++)
   553     if (ary[index] != expected_data[index])
   554       return false;
   555   return true;
   556 }
   558 //----
   560 // An array |arr| is using its auto buffer if |&arr < arr.Elements()| and
   561 // |arr.Elements() - &arr| is small.
   563 #define IS_USING_AUTO(arr) \
   564   ((uintptr_t) &(arr) < (uintptr_t) arr.Elements() && \
   565    ((ptrdiff_t)arr.Elements() - (ptrdiff_t)&arr) <= 16)
   567 #define CHECK_IS_USING_AUTO(arr) \
   568   do {                                                    \
   569     if (!(IS_USING_AUTO(arr))) {                          \
   570       printf("%s:%d CHECK_IS_USING_AUTO(%s) failed.\n",   \
   571              __FILE__, __LINE__, #arr);                   \
   572       return false;                                    \
   573     }                                                     \
   574   } while(0)
   576 #define CHECK_NOT_USING_AUTO(arr) \
   577   do {                                                    \
   578     if (IS_USING_AUTO(arr)) {                             \
   579       printf("%s:%d CHECK_NOT_USING_AUTO(%s) failed.\n",  \
   580              __FILE__, __LINE__, #arr);                   \
   581       return false;                                    \
   582     }                                                     \
   583   } while(0)
   585 #define CHECK_USES_SHARED_EMPTY_HDR(arr) \
   586   do {                                                    \
   587     nsTArray<int> _empty;                                 \
   588     if (_empty.Elements() != arr.Elements()) {            \
   589       printf("%s:%d CHECK_USES_EMPTY_HDR(%s) failed.\n",  \
   590              __FILE__, __LINE__, #arr);                   \
   591       return false;                                    \
   592     }                                                     \
   593   } while(0)
   595 #define CHECK_EQ_INT(actual, expected) \
   596   do {                                                                       \
   597     if ((actual) != (expected)) {                                            \
   598       printf("%s:%d CHECK_EQ_INT(%s=%u, %s=%u) failed.\n",                   \
   599              __FILE__, __LINE__, #actual, (actual), #expected, (expected));  \
   600       return false;                                                       \
   601     }                                                                        \
   602   } while(0)
   604 #define CHECK_ARRAY(arr, data) \
   605   do {                                                          \
   606     CHECK_EQ_INT((arr).Length(), (uint32_t)ArrayLength(data));  \
   607     for (uint32_t _i = 0; _i < ArrayLength(data); _i++) {       \
   608       CHECK_EQ_INT((arr)[_i], (data)[_i]);                      \
   609     }                                                           \
   610   } while(0)
   612 static bool test_swap() {
   613   // Test nsTArray::SwapElements.  Unfortunately there are many cases.
   614   int data1[] = {8, 6, 7, 5};
   615   int data2[] = {3, 0, 9};
   617   // Swap two auto arrays.
   618   {
   619     nsAutoTArray<int, 8> a;
   620     nsAutoTArray<int, 6> b;
   622     a.AppendElements(data1, ArrayLength(data1));
   623     b.AppendElements(data2, ArrayLength(data2));
   624     CHECK_IS_USING_AUTO(a);
   625     CHECK_IS_USING_AUTO(b);
   627     a.SwapElements(b);
   629     CHECK_IS_USING_AUTO(a);
   630     CHECK_IS_USING_AUTO(b);
   631     CHECK_ARRAY(a, data2);
   632     CHECK_ARRAY(b, data1);
   633   }
   635   // Swap two auto arrays -- one whose data lives on the heap, the other whose
   636   // data lives on the stack -- which each fits into the other's auto storage.
   637   {
   638     nsAutoTArray<int, 3> a;
   639     nsAutoTArray<int, 3> b;
   641     a.AppendElements(data1, ArrayLength(data1));
   642     a.RemoveElementAt(3);
   643     b.AppendElements(data2, ArrayLength(data2));
   645     // Here and elsewhere, we assert that if we start with an auto array
   646     // capable of storing N elements, we store N+1 elements into the array, and
   647     // then we remove one element, that array is still not using its auto
   648     // buffer.
   649     //
   650     // This isn't at all required by the TArray API. It would be fine if, when
   651     // we shrink back to N elements, the TArray frees its heap storage and goes
   652     // back to using its stack storage.  But we assert here as a check that the
   653     // test does what we expect.  If the TArray implementation changes, just
   654     // change the failing assertions.
   655     CHECK_NOT_USING_AUTO(a);
   657     // This check had better not change, though.
   658     CHECK_IS_USING_AUTO(b);
   660     a.SwapElements(b);
   662     CHECK_IS_USING_AUTO(b);
   663     CHECK_ARRAY(a, data2);
   664     int expectedB[] = {8, 6, 7};
   665     CHECK_ARRAY(b, expectedB);
   666   }
   668   // Swap two auto arrays which are using heap storage such that one fits into
   669   // the other's auto storage, but the other needs to stay on the heap.
   670   {
   671     nsAutoTArray<int, 3> a;
   672     nsAutoTArray<int, 2> b;
   673     a.AppendElements(data1, ArrayLength(data1));
   674     a.RemoveElementAt(3);
   676     b.AppendElements(data2, ArrayLength(data2));
   677     b.RemoveElementAt(2);
   679     CHECK_NOT_USING_AUTO(a);
   680     CHECK_NOT_USING_AUTO(b);
   682     a.SwapElements(b);
   684     CHECK_NOT_USING_AUTO(b);
   686     int expected1[] = {3, 0};
   687     int expected2[] = {8, 6, 7};
   689     CHECK_ARRAY(a, expected1);
   690     CHECK_ARRAY(b, expected2);
   691   }
   693   // Swap two arrays, neither of which fits into the other's auto-storage.
   694   {
   695     nsAutoTArray<int, 1> a;
   696     nsAutoTArray<int, 3> b;
   698     a.AppendElements(data1, ArrayLength(data1));
   699     b.AppendElements(data2, ArrayLength(data2));
   701     a.SwapElements(b);
   703     CHECK_ARRAY(a, data2);
   704     CHECK_ARRAY(b, data1);
   705   }
   707   // Swap an empty nsTArray with a non-empty nsAutoTArray.
   708   {
   709     nsTArray<int> a;
   710     nsAutoTArray<int, 3> b;
   712     b.AppendElements(data2, ArrayLength(data2));
   713     CHECK_IS_USING_AUTO(b);
   715     a.SwapElements(b);
   717     CHECK_ARRAY(a, data2);
   718     CHECK_EQ_INT(b.Length(), 0);
   719     CHECK_IS_USING_AUTO(b);
   720   }
   722   // Swap two big auto arrays.
   723   {
   724     const unsigned size = 8192;
   725     nsAutoTArray<unsigned, size> a;
   726     nsAutoTArray<unsigned, size> b;
   728     for (unsigned i = 0; i < size; i++) {
   729       a.AppendElement(i);
   730       b.AppendElement(i + 1);
   731     }
   733     CHECK_IS_USING_AUTO(a);
   734     CHECK_IS_USING_AUTO(b);
   736     a.SwapElements(b);
   738     CHECK_IS_USING_AUTO(a);
   739     CHECK_IS_USING_AUTO(b);
   741     CHECK_EQ_INT(a.Length(), size);
   742     CHECK_EQ_INT(b.Length(), size);
   744     for (unsigned i = 0; i < size; i++) {
   745       CHECK_EQ_INT(a[i], i + 1);
   746       CHECK_EQ_INT(b[i], i);
   747     }
   748   }
   750   // Swap two arrays and make sure that their capacities don't increase
   751   // unnecessarily.
   752   {
   753     nsTArray<int> a;
   754     nsTArray<int> b;
   755     b.AppendElements(data2, ArrayLength(data2));
   757     CHECK_EQ_INT(a.Capacity(), 0);
   758     uint32_t bCapacity = b.Capacity();
   760     a.SwapElements(b);
   762     // Make sure that we didn't increase the capacity of either array.
   763     CHECK_ARRAY(a, data2);
   764     CHECK_EQ_INT(b.Length(), 0);
   765     CHECK_EQ_INT(b.Capacity(), 0);
   766     CHECK_EQ_INT(a.Capacity(), bCapacity);
   767   }
   769   // Swap an auto array with a TArray, then clear the auto array and make sure
   770   // it doesn't forget the fact that it has an auto buffer.
   771   {
   772     nsTArray<int> a;
   773     nsAutoTArray<int, 3> b;
   775     a.AppendElements(data1, ArrayLength(data1));
   777     a.SwapElements(b);
   779     CHECK_EQ_INT(a.Length(), 0);
   780     CHECK_ARRAY(b, data1);
   782     b.Clear();
   784     CHECK_USES_SHARED_EMPTY_HDR(a);
   785     CHECK_IS_USING_AUTO(b);
   786   }
   788   // Same thing as the previous test, but with more auto arrays.
   789   {
   790     nsAutoTArray<int, 16> a;
   791     nsAutoTArray<int, 3> b;
   793     a.AppendElements(data1, ArrayLength(data1));
   795     a.SwapElements(b);
   797     CHECK_EQ_INT(a.Length(), 0);
   798     CHECK_ARRAY(b, data1);
   800     b.Clear();
   802     CHECK_IS_USING_AUTO(a);
   803     CHECK_IS_USING_AUTO(b);
   804   }
   806   // Swap an empty nsTArray and an empty nsAutoTArray.
   807   {
   808     nsAutoTArray<int, 8> a;
   809     nsTArray<int> b;
   811     a.SwapElements(b);
   813     CHECK_IS_USING_AUTO(a);
   814     CHECK_NOT_USING_AUTO(b);
   815     CHECK_EQ_INT(a.Length(), 0);
   816     CHECK_EQ_INT(b.Length(), 0);
   817   }
   819   // Swap empty auto array with non-empty nsAutoTArray using malloc'ed storage.
   820   // I promise, all these tests have a point.
   821   {
   822     nsAutoTArray<int, 2> a;
   823     nsAutoTArray<int, 1> b;
   825     a.AppendElements(data1, ArrayLength(data1));
   827     a.SwapElements(b);
   829     CHECK_IS_USING_AUTO(a);
   830     CHECK_NOT_USING_AUTO(b);
   831     CHECK_ARRAY(b, data1);
   832     CHECK_EQ_INT(a.Length(), 0);
   833   }
   835   return true;
   836 }
   838 static bool test_fallible()
   839 {
   840   // Test that FallibleTArray works properly; that is, it never OOMs, but
   841   // instead eventually returns false.
   842   //
   843   // This test is only meaningful on 32-bit systems.  On a 64-bit system, we
   844   // might never OOM.
   845   if (sizeof(void*) > 4) {
   846     return true;
   847   }
   849   // Allocate a bunch of 128MB arrays.  Larger allocations will fail on some
   850   // platforms without actually hitting OOM.
   851   //
   852   // 36 * 128MB > 4GB, so we should definitely OOM by the 36th array.
   853   const unsigned numArrays = 36;
   854   FallibleTArray<char> arrays[numArrays];
   855   for (uint32_t i = 0; i < numArrays; i++) {
   856     bool success = arrays[i].SetCapacity(128 * 1024 * 1024);
   857     if (!success) {
   858       // We got our OOM.  Check that it didn't come too early.
   859       if (i < 8) {
   860         printf("test_fallible: Got OOM on iteration %d.  Too early!\n", i);
   861         return false;
   862       }
   863       return true;
   864     }
   865   }
   867   // No OOM?  That's...weird.
   868   printf("test_fallible: Didn't OOM or crash?  nsTArray::SetCapacity "
   869          "must be lying.\n");
   870   return false;
   871 }
   873 static bool test_conversion_operator() {
   874   FallibleTArray<int> f;
   875   const FallibleTArray<int> fconst;
   876   AutoFallibleTArray<int, 8> fauto;
   877   const AutoFallibleTArray<int, 8> fautoconst;
   879   InfallibleTArray<int> i;
   880   const InfallibleTArray<int> iconst;
   881   AutoInfallibleTArray<int, 8> iauto;
   882   const AutoInfallibleTArray<int, 8> iautoconst;
   884   nsTArray<int> t;
   885   const nsTArray<int> tconst;
   886   nsAutoTArray<int, 8> tauto;
   887   const nsAutoTArray<int, 8> tautoconst;
   889 #define CHECK_ARRAY_CAST(type)                                 \
   890   do {                                                         \
   891     const type<int>& z1 = f;                                   \
   892     if ((void*)&z1 != (void*)&f) return false;                 \
   893     const type<int>& z2 = fconst;                              \
   894     if ((void*)&z2 != (void*)&fconst) return false;            \
   895     const type<int>& z3 = fauto;                               \
   896     if ((void*)&z3 != (void*)&fauto) return false;             \
   897     const type<int>& z4 = fautoconst;                          \
   898     if ((void*)&z4 != (void*)&fautoconst) return false;        \
   899     const type<int>& z5 = i;                                   \
   900     if ((void*)&z5 != (void*)&i) return false;                 \
   901     const type<int>& z6 = iconst;                              \
   902     if ((void*)&z6 != (void*)&iconst) return false;            \
   903     const type<int>& z7 = iauto;                               \
   904     if ((void*)&z7 != (void*)&iauto) return false;             \
   905     const type<int>& z8 = iautoconst;                          \
   906     if ((void*)&z8 != (void*)&iautoconst) return false;        \
   907     const type<int>& z9 = t;                                   \
   908     if ((void*)&z9 != (void*)&t) return false;                 \
   909     const type<int>& z10 = tconst;                             \
   910     if ((void*)&z10 != (void*)&tconst) return false;           \
   911     const type<int>& z11 = tauto;                              \
   912     if ((void*)&z11 != (void*)&tauto) return false;            \
   913     const type<int>& z12 = tautoconst;                         \
   914     if ((void*)&z12 != (void*)&tautoconst) return false;       \
   915   } while (0)
   917   CHECK_ARRAY_CAST(FallibleTArray);
   918   CHECK_ARRAY_CAST(InfallibleTArray);
   919   CHECK_ARRAY_CAST(nsTArray);
   921 #undef CHECK_ARRAY_CAST
   923   return true;
   924 }
   926 template<class T>
   927 struct BufAccessor : public T
   928 {
   929   void* GetHdr() { return T::mHdr; }
   930 };
   932 static bool test_SetLengthAndRetainStorage_no_ctor() {
   933   // 1050 because sizeof(int)*1050 is more than a page typically.
   934   const int N = 1050;
   935   FallibleTArray<int> f;
   936   AutoFallibleTArray<int, N> fauto;
   938   InfallibleTArray<int> i;
   939   AutoInfallibleTArray<int, N> iauto;
   941   nsTArray<int> t;
   942   nsAutoTArray<int, N> tauto;
   944 #define LPAREN (
   945 #define RPAREN )
   946 #define FOR_EACH(pre, post)                                    \
   947   do {                                                         \
   948     pre f post;                                                \
   949     pre fauto post;                                            \
   950     pre i post;                                                \
   951     pre iauto post;                                            \
   952     pre t post;                                                \
   953     pre tauto post;                                            \
   954   } while (0)
   956   // Setup test arrays.
   957   FOR_EACH(;, .SetLength(N));
   958   for (int n = 0; n < N; ++n) {
   959     FOR_EACH(;, [n] = n);
   960   }
   962   void* initial_Hdrs[] = {
   963     static_cast<BufAccessor<FallibleTArray<int> >&>(f).GetHdr(),
   964     static_cast<BufAccessor<AutoFallibleTArray<int, N> >&>(fauto).GetHdr(),
   965     static_cast<BufAccessor<InfallibleTArray<int> >&>(i).GetHdr(),
   966     static_cast<BufAccessor<AutoInfallibleTArray<int, N> >&>(iauto).GetHdr(),
   967     static_cast<BufAccessor<nsTArray<int> >&>(t).GetHdr(),
   968     static_cast<BufAccessor<nsAutoTArray<int, N> >&>(tauto).GetHdr(),
   969     nullptr
   970   };
   972   // SetLengthAndRetainStorage(n), should NOT overwrite memory when T hasn't
   973   // a default constructor.
   974   FOR_EACH(;, .SetLengthAndRetainStorage(8));
   975   FOR_EACH(;, .SetLengthAndRetainStorage(12));
   976   for (int n = 0; n < 12; ++n) {
   977     FOR_EACH(if LPAREN, [n] != n RPAREN return false);
   978   }
   979   FOR_EACH(;, .SetLengthAndRetainStorage(0));
   980   FOR_EACH(;, .SetLengthAndRetainStorage(N));
   981   for (int n = 0; n < N; ++n) {
   982     FOR_EACH(if LPAREN, [n] != n RPAREN return false);
   983   }
   985   void* current_Hdrs[] = {
   986     static_cast<BufAccessor<FallibleTArray<int> >&>(f).GetHdr(),
   987     static_cast<BufAccessor<AutoFallibleTArray<int, N> >&>(fauto).GetHdr(),
   988     static_cast<BufAccessor<InfallibleTArray<int> >&>(i).GetHdr(),
   989     static_cast<BufAccessor<AutoInfallibleTArray<int, N> >&>(iauto).GetHdr(),
   990     static_cast<BufAccessor<nsTArray<int> >&>(t).GetHdr(),
   991     static_cast<BufAccessor<nsAutoTArray<int, N> >&>(tauto).GetHdr(),
   992     nullptr
   993   };
   995   // SetLengthAndRetainStorage(n) should NOT have reallocated the internal
   996   // memory.
   997   if (sizeof(initial_Hdrs) != sizeof(current_Hdrs)) return false;
   998   for (size_t n = 0; n < sizeof(current_Hdrs) / sizeof(current_Hdrs[0]); ++n) {
   999     if (current_Hdrs[n] != initial_Hdrs[n]) {
  1000       return false;
  1005 #undef FOR_EACH
  1006 #undef LPAREN
  1007 #undef RPAREN
  1009   return true;
  1012 //----
  1014 typedef bool (*TestFunc)();
  1015 #define DECL_TEST(name) { #name, name }
  1017 static const struct Test {
  1018   const char* name;
  1019   TestFunc    func;
  1020 } tests[] = {
  1021   DECL_TEST(test_int_array),
  1022   DECL_TEST(test_int64_array),
  1023   DECL_TEST(test_char_array),
  1024   DECL_TEST(test_uint32_array),
  1025   DECL_TEST(test_object_array),
  1026   DECL_TEST(test_string_array),
  1027   DECL_TEST(test_comptr_array),
  1028   DECL_TEST(test_refptr_array),
  1029   DECL_TEST(test_ptrarray),
  1030 #ifdef DEBUG
  1031   DECL_TEST(test_autoarray),
  1032 #endif
  1033   DECL_TEST(test_indexof),
  1034   DECL_TEST(test_heap),
  1035   DECL_TEST(test_swap),
  1036   DECL_TEST(test_fallible),
  1037   DECL_TEST(test_conversion_operator),
  1038   DECL_TEST(test_SetLengthAndRetainStorage_no_ctor),
  1039   { nullptr, nullptr }
  1040 };
  1044 using namespace TestTArray;
  1046 int main(int argc, char **argv) {
  1047   int count = 1;
  1048   if (argc > 1)
  1049     count = atoi(argv[1]);
  1051   if (NS_FAILED(NS_InitXPCOM2(nullptr, nullptr, nullptr)))
  1052     return -1;
  1054   bool success = true;
  1055   while (count--) {
  1056     for (const Test* t = tests; t->name != nullptr; ++t) {
  1057       bool test_result = t->func();
  1058       printf("%25s : %s\n", t->name, test_result ? "SUCCESS" : "FAILURE");
  1059       if (!test_result)
  1060         success = false;
  1064   NS_ShutdownXPCOM(nullptr);
  1065   return success ? 0 : -1;

mercurial