1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/tests/TestTArray.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1066 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/ArrayUtils.h" 1.11 + 1.12 +#include <stdlib.h> 1.13 +#include <stdio.h> 1.14 +#include "nsTArray.h" 1.15 +#include "nsAutoPtr.h" 1.16 +#include "nsStringAPI.h" 1.17 +#include "nsDirectoryServiceDefs.h" 1.18 +#include "nsDirectoryServiceUtils.h" 1.19 +#include "nsComponentManagerUtils.h" 1.20 +#include "nsXPCOM.h" 1.21 +#include "nsIFile.h" 1.22 + 1.23 +using namespace mozilla; 1.24 + 1.25 +namespace TestTArray { 1.26 + 1.27 +// Define this so we can use test_basic_array in test_comptr_array 1.28 +template <class T> 1.29 +inline bool operator<(const nsCOMPtr<T>& lhs, const nsCOMPtr<T>& rhs) { 1.30 + return lhs.get() < rhs.get(); 1.31 +} 1.32 + 1.33 +//---- 1.34 + 1.35 +template <class ElementType> 1.36 +static bool test_basic_array(ElementType *data, 1.37 + uint32_t dataLen, 1.38 + const ElementType& extra) { 1.39 + nsTArray<ElementType> ary; 1.40 + ary.AppendElements(data, dataLen); 1.41 + if (ary.Length() != dataLen) { 1.42 + return false; 1.43 + } 1.44 + if (!(ary == ary)) { 1.45 + return false; 1.46 + } 1.47 + uint32_t i; 1.48 + for (i = 0; i < ary.Length(); ++i) { 1.49 + if (ary[i] != data[i]) 1.50 + return false; 1.51 + } 1.52 + for (i = 0; i < ary.Length(); ++i) { 1.53 + if (ary.SafeElementAt(i, extra) != data[i]) 1.54 + return false; 1.55 + } 1.56 + if (ary.SafeElementAt(ary.Length(), extra) != extra || 1.57 + ary.SafeElementAt(ary.Length() * 10, extra) != extra) 1.58 + return false; 1.59 + // ensure sort results in ascending order 1.60 + ary.Sort(); 1.61 + uint32_t j = 0, k = ary.IndexOfFirstElementGt(extra); 1.62 + if (k != 0 && ary[k-1] == extra) 1.63 + return false; 1.64 + for (i = 0; i < ary.Length(); ++i) { 1.65 + k = ary.IndexOfFirstElementGt(ary[i]); 1.66 + if (k == 0 || ary[k-1] != ary[i]) 1.67 + return false; 1.68 + if (k < j) 1.69 + return false; 1.70 + j = k; 1.71 + } 1.72 + for (i = ary.Length(); --i; ) { 1.73 + if (ary[i] < ary[i - 1]) 1.74 + return false; 1.75 + if (ary[i] == ary[i - 1]) 1.76 + ary.RemoveElementAt(i); 1.77 + } 1.78 + if (!(ary == ary)) { 1.79 + return false; 1.80 + } 1.81 + for (i = 0; i < ary.Length(); ++i) { 1.82 + if (ary.BinaryIndexOf(ary[i]) != i) 1.83 + return false; 1.84 + } 1.85 + if (ary.BinaryIndexOf(extra) != ary.NoIndex) 1.86 + return false; 1.87 + uint32_t oldLen = ary.Length(); 1.88 + ary.RemoveElement(data[dataLen / 2]); 1.89 + if (ary.Length() != (oldLen - 1)) 1.90 + return false; 1.91 + if (!(ary == ary)) 1.92 + return false; 1.93 + 1.94 + uint32_t index = ary.Length() / 2; 1.95 + if (!ary.InsertElementAt(index, extra)) 1.96 + return false; 1.97 + if (!(ary == ary)) 1.98 + return false; 1.99 + if (ary[index] != extra) 1.100 + return false; 1.101 + if (ary.IndexOf(extra) == UINT32_MAX) 1.102 + return false; 1.103 + if (ary.LastIndexOf(extra) == UINT32_MAX) 1.104 + return false; 1.105 + // ensure proper searching 1.106 + if (ary.IndexOf(extra) > ary.LastIndexOf(extra)) 1.107 + return false; 1.108 + if (ary.IndexOf(extra, index) != ary.LastIndexOf(extra, index)) 1.109 + return false; 1.110 + 1.111 + nsTArray<ElementType> copy(ary); 1.112 + if (!(ary == copy)) 1.113 + return false; 1.114 + for (i = 0; i < copy.Length(); ++i) { 1.115 + if (ary[i] != copy[i]) 1.116 + return false; 1.117 + } 1.118 + if (!ary.AppendElements(copy)) 1.119 + return false; 1.120 + uint32_t cap = ary.Capacity(); 1.121 + ary.RemoveElementsAt(copy.Length(), copy.Length()); 1.122 + ary.Compact(); 1.123 + if (ary.Capacity() == cap) 1.124 + return false; 1.125 + 1.126 + ary.Clear(); 1.127 + if (ary.IndexOf(extra) != UINT32_MAX) 1.128 + return false; 1.129 + if (ary.LastIndexOf(extra) != UINT32_MAX) 1.130 + return false; 1.131 + 1.132 + ary.Clear(); 1.133 + if (!ary.IsEmpty() || ary.Elements() == nullptr) 1.134 + return false; 1.135 + if (!(ary == nsTArray<ElementType>())) 1.136 + return false; 1.137 + if (ary == copy) 1.138 + return false; 1.139 + if (ary.SafeElementAt(0, extra) != extra || 1.140 + ary.SafeElementAt(10, extra) != extra) 1.141 + return false; 1.142 + 1.143 + ary = copy; 1.144 + if (!(ary == copy)) 1.145 + return false; 1.146 + for (i = 0; i < copy.Length(); ++i) { 1.147 + if (ary[i] != copy[i]) 1.148 + return false; 1.149 + } 1.150 + 1.151 + if (!ary.InsertElementsAt(0, copy)) 1.152 + return false; 1.153 + if (ary == copy) 1.154 + return false; 1.155 + ary.RemoveElementsAt(0, copy.Length()); 1.156 + for (i = 0; i < copy.Length(); ++i) { 1.157 + if (ary[i] != copy[i]) 1.158 + return false; 1.159 + } 1.160 + 1.161 + // These shouldn't crash! 1.162 + nsTArray<ElementType> empty; 1.163 + ary.AppendElements(reinterpret_cast<ElementType *>(0), 0); 1.164 + ary.AppendElements(empty); 1.165 + 1.166 + // See bug 324981 1.167 + ary.RemoveElement(extra); 1.168 + ary.RemoveElement(extra); 1.169 + 1.170 + return true; 1.171 +} 1.172 + 1.173 +static bool test_int_array() { 1.174 + int data[] = {4,6,8,2,4,1,5,7,3}; 1.175 + return test_basic_array(data, ArrayLength(data), int(14)); 1.176 +} 1.177 + 1.178 +static bool test_int64_array() { 1.179 + int64_t data[] = {4,6,8,2,4,1,5,7,3}; 1.180 + return test_basic_array(data, ArrayLength(data), int64_t(14)); 1.181 +} 1.182 + 1.183 +static bool test_char_array() { 1.184 + char data[] = {4,6,8,2,4,1,5,7,3}; 1.185 + return test_basic_array(data, ArrayLength(data), char(14)); 1.186 +} 1.187 + 1.188 +static bool test_uint32_array() { 1.189 + uint32_t data[] = {4,6,8,2,4,1,5,7,3}; 1.190 + return test_basic_array(data, ArrayLength(data), uint32_t(14)); 1.191 +} 1.192 + 1.193 +//---- 1.194 + 1.195 +class Object { 1.196 + public: 1.197 + Object() : mNum(0) { 1.198 + } 1.199 + Object(const char *str, uint32_t num) : mStr(str), mNum(num) { 1.200 + } 1.201 + Object(const Object& other) : mStr(other.mStr), mNum(other.mNum) { 1.202 + } 1.203 + ~Object() {} 1.204 + 1.205 + Object& operator=(const Object& other) { 1.206 + mStr = other.mStr; 1.207 + mNum = other.mNum; 1.208 + return *this; 1.209 + } 1.210 + 1.211 + bool operator==(const Object& other) const { 1.212 + return mStr == other.mStr && mNum == other.mNum; 1.213 + } 1.214 + 1.215 + bool operator<(const Object& other) const { 1.216 + // sort based on mStr only 1.217 + return mStr.Compare(other.mStr) < 0; 1.218 + } 1.219 + 1.220 + const char *Str() const { return mStr.get(); } 1.221 + uint32_t Num() const { return mNum; } 1.222 + 1.223 + private: 1.224 + nsCString mStr; 1.225 + uint32_t mNum; 1.226 +}; 1.227 + 1.228 +static bool test_object_array() { 1.229 + nsTArray<Object> objArray; 1.230 + const char kdata[] = "hello world"; 1.231 + uint32_t i; 1.232 + for (i = 0; i < ArrayLength(kdata); ++i) { 1.233 + char x[] = {kdata[i],'\0'}; 1.234 + if (!objArray.AppendElement(Object(x, i))) 1.235 + return false; 1.236 + } 1.237 + for (i = 0; i < ArrayLength(kdata); ++i) { 1.238 + if (objArray[i].Str()[0] != kdata[i]) 1.239 + return false; 1.240 + if (objArray[i].Num() != i) 1.241 + return false; 1.242 + } 1.243 + objArray.Sort(); 1.244 + const char ksorted[] = "\0 dehllloorw"; 1.245 + for (i = 0; i < ArrayLength(kdata)-1; ++i) { 1.246 + if (objArray[i].Str()[0] != ksorted[i]) 1.247 + return false; 1.248 + } 1.249 + return true; 1.250 +} 1.251 + 1.252 +// nsTArray<nsAutoPtr<T>> is not supported 1.253 +#if 0 1.254 +static bool test_autoptr_array() { 1.255 + nsTArray< nsAutoPtr<Object> > objArray; 1.256 + const char kdata[] = "hello world"; 1.257 + for (uint32_t i = 0; i < ArrayLength(kdata); ++i) { 1.258 + char x[] = {kdata[i],'\0'}; 1.259 + nsAutoPtr<Object> obj(new Object(x,i)); 1.260 + if (!objArray.AppendElement(obj)) // XXX does not call copy-constructor for nsAutoPtr!!! 1.261 + return false; 1.262 + if (obj.get() == nullptr) 1.263 + return false; 1.264 + obj.forget(); // the array now owns the reference 1.265 + } 1.266 + for (uint32_t i = 0; i < ArrayLength(kdata); ++i) { 1.267 + if (objArray[i]->Str()[0] != kdata[i]) 1.268 + return false; 1.269 + if (objArray[i]->Num() != i) 1.270 + return false; 1.271 + } 1.272 + return true; 1.273 +} 1.274 +#endif 1.275 + 1.276 +//---- 1.277 + 1.278 +static bool test_string_array() { 1.279 + nsTArray<nsCString> strArray; 1.280 + const char kdata[] = "hello world"; 1.281 + uint32_t i; 1.282 + for (i = 0; i < ArrayLength(kdata); ++i) { 1.283 + nsCString str; 1.284 + str.Assign(kdata[i]); 1.285 + if (!strArray.AppendElement(str)) 1.286 + return false; 1.287 + } 1.288 + for (i = 0; i < ArrayLength(kdata); ++i) { 1.289 + if (strArray[i].CharAt(0) != kdata[i]) 1.290 + return false; 1.291 + } 1.292 + 1.293 + const char kextra[] = "foo bar"; 1.294 + uint32_t oldLen = strArray.Length(); 1.295 + if (!strArray.AppendElement(kextra)) 1.296 + return false; 1.297 + strArray.RemoveElement(kextra); 1.298 + if (oldLen != strArray.Length()) 1.299 + return false; 1.300 + 1.301 + if (strArray.IndexOf("e") != 1) 1.302 + return false; 1.303 + 1.304 + strArray.Sort(); 1.305 + const char ksorted[] = "\0 dehllloorw"; 1.306 + for (i = ArrayLength(kdata); i--; ) { 1.307 + if (strArray[i].CharAt(0) != ksorted[i]) 1.308 + return false; 1.309 + if (i > 0 && strArray[i] == strArray[i - 1]) 1.310 + strArray.RemoveElementAt(i); 1.311 + } 1.312 + for (i = 0; i < strArray.Length(); ++i) { 1.313 + if (strArray.BinaryIndexOf(strArray[i]) != i) 1.314 + return false; 1.315 + } 1.316 + if (strArray.BinaryIndexOf(EmptyCString()) != strArray.NoIndex) 1.317 + return false; 1.318 + 1.319 + nsCString rawArray[MOZ_ARRAY_LENGTH(kdata) - 1]; 1.320 + for (i = 0; i < ArrayLength(rawArray); ++i) 1.321 + rawArray[i].Assign(kdata + i); // substrings of kdata 1.322 + return test_basic_array(rawArray, ArrayLength(rawArray), 1.323 + nsCString("foopy")); 1.324 +} 1.325 + 1.326 +//---- 1.327 + 1.328 +typedef nsCOMPtr<nsIFile> FilePointer; 1.329 + 1.330 +class nsFileNameComparator { 1.331 + public: 1.332 + bool Equals(const FilePointer &a, const char *b) const { 1.333 + nsAutoCString name; 1.334 + a->GetNativeLeafName(name); 1.335 + return name.Equals(b); 1.336 + } 1.337 +}; 1.338 + 1.339 +static bool test_comptr_array() { 1.340 + FilePointer tmpDir; 1.341 + NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir)); 1.342 + if (!tmpDir) 1.343 + return false; 1.344 + const char *kNames[] = { 1.345 + "foo.txt", "bar.html", "baz.gif" 1.346 + }; 1.347 + nsTArray<FilePointer> fileArray; 1.348 + uint32_t i; 1.349 + for (i = 0; i < ArrayLength(kNames); ++i) { 1.350 + FilePointer f; 1.351 + tmpDir->Clone(getter_AddRefs(f)); 1.352 + if (!f) 1.353 + return false; 1.354 + if (NS_FAILED(f->AppendNative(nsDependentCString(kNames[i])))) 1.355 + return false; 1.356 + fileArray.AppendElement(f); 1.357 + } 1.358 + 1.359 + if (fileArray.IndexOf(kNames[1], 0, nsFileNameComparator()) != 1) 1.360 + return false; 1.361 + 1.362 + // It's unclear what 'operator<' means for nsCOMPtr, but whatever... 1.363 + return test_basic_array(fileArray.Elements(), fileArray.Length(), 1.364 + tmpDir); 1.365 +} 1.366 + 1.367 +//---- 1.368 + 1.369 +class RefcountedObject { 1.370 + public: 1.371 + RefcountedObject() : rc(0) {} 1.372 + void AddRef() { 1.373 + ++rc; 1.374 + } 1.375 + void Release() { 1.376 + if (--rc == 0) 1.377 + delete this; 1.378 + } 1.379 + ~RefcountedObject() {} 1.380 + private: 1.381 + int32_t rc; 1.382 +}; 1.383 + 1.384 +static bool test_refptr_array() { 1.385 + bool rv = true; 1.386 + 1.387 + nsTArray< nsRefPtr<RefcountedObject> > objArray; 1.388 + 1.389 + RefcountedObject *a = new RefcountedObject(); a->AddRef(); 1.390 + RefcountedObject *b = new RefcountedObject(); b->AddRef(); 1.391 + RefcountedObject *c = new RefcountedObject(); c->AddRef(); 1.392 + 1.393 + objArray.AppendElement(a); 1.394 + objArray.AppendElement(b); 1.395 + objArray.AppendElement(c); 1.396 + 1.397 + if (objArray.IndexOf(b) != 1) 1.398 + rv = false; 1.399 + 1.400 + a->Release(); 1.401 + b->Release(); 1.402 + c->Release(); 1.403 + return rv; 1.404 +} 1.405 + 1.406 +//---- 1.407 + 1.408 +static bool test_ptrarray() { 1.409 + nsTArray<uint32_t*> ary; 1.410 + if (ary.SafeElementAt(0) != nullptr) 1.411 + return false; 1.412 + if (ary.SafeElementAt(1000) != nullptr) 1.413 + return false; 1.414 + uint32_t a = 10; 1.415 + ary.AppendElement(&a); 1.416 + if (*ary[0] != a) 1.417 + return false; 1.418 + if (*ary.SafeElementAt(0) != a) 1.419 + return false; 1.420 + 1.421 + nsTArray<const uint32_t*> cary; 1.422 + if (cary.SafeElementAt(0) != nullptr) 1.423 + return false; 1.424 + if (cary.SafeElementAt(1000) != nullptr) 1.425 + return false; 1.426 + const uint32_t b = 14; 1.427 + cary.AppendElement(&a); 1.428 + cary.AppendElement(&b); 1.429 + if (*cary[0] != a || *cary[1] != b) 1.430 + return false; 1.431 + if (*cary.SafeElementAt(0) != a || *cary.SafeElementAt(1) != b) 1.432 + return false; 1.433 + 1.434 + return true; 1.435 +} 1.436 + 1.437 +//---- 1.438 + 1.439 +// This test relies too heavily on the existence of DebugGetHeader to be 1.440 +// useful in non-debug builds. 1.441 +#ifdef DEBUG 1.442 +static bool test_autoarray() { 1.443 + uint32_t data[] = {4,6,8,2,4,1,5,7,3}; 1.444 + nsAutoTArray<uint32_t, MOZ_ARRAY_LENGTH(data)> array; 1.445 + 1.446 + void* hdr = array.DebugGetHeader(); 1.447 + if (hdr == nsTArray<uint32_t>().DebugGetHeader()) 1.448 + return false; 1.449 + if (hdr == nsAutoTArray<uint32_t, MOZ_ARRAY_LENGTH(data)>().DebugGetHeader()) 1.450 + return false; 1.451 + 1.452 + array.AppendElement(1u); 1.453 + if (hdr != array.DebugGetHeader()) 1.454 + return false; 1.455 + 1.456 + array.RemoveElement(1u); 1.457 + array.AppendElements(data, ArrayLength(data)); 1.458 + if (hdr != array.DebugGetHeader()) 1.459 + return false; 1.460 + 1.461 + array.AppendElement(2u); 1.462 + if (hdr == array.DebugGetHeader()) 1.463 + return false; 1.464 + 1.465 + array.Clear(); 1.466 + array.Compact(); 1.467 + if (hdr != array.DebugGetHeader()) 1.468 + return false; 1.469 + array.AppendElements(data, ArrayLength(data)); 1.470 + if (hdr != array.DebugGetHeader()) 1.471 + return false; 1.472 + 1.473 + nsTArray<uint32_t> array2; 1.474 + void* emptyHdr = array2.DebugGetHeader(); 1.475 + array.SwapElements(array2); 1.476 + if (emptyHdr == array.DebugGetHeader()) 1.477 + return false; 1.478 + if (hdr == array2.DebugGetHeader()) 1.479 + return false; 1.480 + uint32_t i; 1.481 + for (i = 0; i < ArrayLength(data); ++i) { 1.482 + if (array2[i] != data[i]) 1.483 + return false; 1.484 + } 1.485 + if (!array.IsEmpty()) 1.486 + return false; 1.487 + 1.488 + array.Compact(); 1.489 + array.AppendElements(data, ArrayLength(data)); 1.490 + uint32_t data3[] = {5, 7, 11}; 1.491 + nsAutoTArray<uint32_t, MOZ_ARRAY_LENGTH(data3)> array3; 1.492 + array3.AppendElements(data3, ArrayLength(data3)); 1.493 + array.SwapElements(array3); 1.494 + for (i = 0; i < ArrayLength(data); ++i) { 1.495 + if (array3[i] != data[i]) 1.496 + return false; 1.497 + } 1.498 + for (i = 0; i < ArrayLength(data3); ++i) { 1.499 + if (array[i] != data3[i]) 1.500 + return false; 1.501 + } 1.502 + 1.503 + return true; 1.504 +} 1.505 +#endif 1.506 + 1.507 +//---- 1.508 + 1.509 +// IndexOf used to potentially scan beyond the end of the array. Test for 1.510 +// this incorrect behavior by adding a value (5), removing it, then seeing 1.511 +// if IndexOf finds it. 1.512 +static bool test_indexof() { 1.513 + nsTArray<int> array; 1.514 + array.AppendElement(0); 1.515 + // add and remove the 5 1.516 + array.AppendElement(5); 1.517 + array.RemoveElementAt(1); 1.518 + // we should not find the 5! 1.519 + return array.IndexOf(5, 1) == array.NoIndex; 1.520 +} 1.521 + 1.522 +//---- 1.523 + 1.524 +template <class Array> 1.525 +static bool is_heap(const Array& ary, uint32_t len) { 1.526 + uint32_t index = 1; 1.527 + while (index < len) { 1.528 + if (ary[index] > ary[(index - 1) >> 1]) 1.529 + return false; 1.530 + index++; 1.531 + } 1.532 + return true; 1.533 +} 1.534 + 1.535 +static bool test_heap() { 1.536 + const int data[] = {4,6,8,2,4,1,5,7,3}; 1.537 + nsTArray<int> ary; 1.538 + ary.AppendElements(data, ArrayLength(data)); 1.539 + // make a heap and make sure it's a heap 1.540 + ary.MakeHeap(); 1.541 + if (!is_heap(ary, ArrayLength(data))) 1.542 + return false; 1.543 + // pop the root and make sure it's still a heap 1.544 + int root = ary[0]; 1.545 + ary.PopHeap(); 1.546 + if (!is_heap(ary, ArrayLength(data) - 1)) 1.547 + return false; 1.548 + // push the previously poped value back on and make sure it's still a heap 1.549 + ary.PushHeap(root); 1.550 + if (!is_heap(ary, ArrayLength(data))) 1.551 + return false; 1.552 + // make sure the heap looks like what we expect 1.553 + const int expected_data[] = {8,7,5,6,4,1,4,2,3}; 1.554 + uint32_t index; 1.555 + for (index = 0; index < ArrayLength(data); index++) 1.556 + if (ary[index] != expected_data[index]) 1.557 + return false; 1.558 + return true; 1.559 +} 1.560 + 1.561 +//---- 1.562 + 1.563 +// An array |arr| is using its auto buffer if |&arr < arr.Elements()| and 1.564 +// |arr.Elements() - &arr| is small. 1.565 + 1.566 +#define IS_USING_AUTO(arr) \ 1.567 + ((uintptr_t) &(arr) < (uintptr_t) arr.Elements() && \ 1.568 + ((ptrdiff_t)arr.Elements() - (ptrdiff_t)&arr) <= 16) 1.569 + 1.570 +#define CHECK_IS_USING_AUTO(arr) \ 1.571 + do { \ 1.572 + if (!(IS_USING_AUTO(arr))) { \ 1.573 + printf("%s:%d CHECK_IS_USING_AUTO(%s) failed.\n", \ 1.574 + __FILE__, __LINE__, #arr); \ 1.575 + return false; \ 1.576 + } \ 1.577 + } while(0) 1.578 + 1.579 +#define CHECK_NOT_USING_AUTO(arr) \ 1.580 + do { \ 1.581 + if (IS_USING_AUTO(arr)) { \ 1.582 + printf("%s:%d CHECK_NOT_USING_AUTO(%s) failed.\n", \ 1.583 + __FILE__, __LINE__, #arr); \ 1.584 + return false; \ 1.585 + } \ 1.586 + } while(0) 1.587 + 1.588 +#define CHECK_USES_SHARED_EMPTY_HDR(arr) \ 1.589 + do { \ 1.590 + nsTArray<int> _empty; \ 1.591 + if (_empty.Elements() != arr.Elements()) { \ 1.592 + printf("%s:%d CHECK_USES_EMPTY_HDR(%s) failed.\n", \ 1.593 + __FILE__, __LINE__, #arr); \ 1.594 + return false; \ 1.595 + } \ 1.596 + } while(0) 1.597 + 1.598 +#define CHECK_EQ_INT(actual, expected) \ 1.599 + do { \ 1.600 + if ((actual) != (expected)) { \ 1.601 + printf("%s:%d CHECK_EQ_INT(%s=%u, %s=%u) failed.\n", \ 1.602 + __FILE__, __LINE__, #actual, (actual), #expected, (expected)); \ 1.603 + return false; \ 1.604 + } \ 1.605 + } while(0) 1.606 + 1.607 +#define CHECK_ARRAY(arr, data) \ 1.608 + do { \ 1.609 + CHECK_EQ_INT((arr).Length(), (uint32_t)ArrayLength(data)); \ 1.610 + for (uint32_t _i = 0; _i < ArrayLength(data); _i++) { \ 1.611 + CHECK_EQ_INT((arr)[_i], (data)[_i]); \ 1.612 + } \ 1.613 + } while(0) 1.614 + 1.615 +static bool test_swap() { 1.616 + // Test nsTArray::SwapElements. Unfortunately there are many cases. 1.617 + int data1[] = {8, 6, 7, 5}; 1.618 + int data2[] = {3, 0, 9}; 1.619 + 1.620 + // Swap two auto arrays. 1.621 + { 1.622 + nsAutoTArray<int, 8> a; 1.623 + nsAutoTArray<int, 6> b; 1.624 + 1.625 + a.AppendElements(data1, ArrayLength(data1)); 1.626 + b.AppendElements(data2, ArrayLength(data2)); 1.627 + CHECK_IS_USING_AUTO(a); 1.628 + CHECK_IS_USING_AUTO(b); 1.629 + 1.630 + a.SwapElements(b); 1.631 + 1.632 + CHECK_IS_USING_AUTO(a); 1.633 + CHECK_IS_USING_AUTO(b); 1.634 + CHECK_ARRAY(a, data2); 1.635 + CHECK_ARRAY(b, data1); 1.636 + } 1.637 + 1.638 + // Swap two auto arrays -- one whose data lives on the heap, the other whose 1.639 + // data lives on the stack -- which each fits into the other's auto storage. 1.640 + { 1.641 + nsAutoTArray<int, 3> a; 1.642 + nsAutoTArray<int, 3> b; 1.643 + 1.644 + a.AppendElements(data1, ArrayLength(data1)); 1.645 + a.RemoveElementAt(3); 1.646 + b.AppendElements(data2, ArrayLength(data2)); 1.647 + 1.648 + // Here and elsewhere, we assert that if we start with an auto array 1.649 + // capable of storing N elements, we store N+1 elements into the array, and 1.650 + // then we remove one element, that array is still not using its auto 1.651 + // buffer. 1.652 + // 1.653 + // This isn't at all required by the TArray API. It would be fine if, when 1.654 + // we shrink back to N elements, the TArray frees its heap storage and goes 1.655 + // back to using its stack storage. But we assert here as a check that the 1.656 + // test does what we expect. If the TArray implementation changes, just 1.657 + // change the failing assertions. 1.658 + CHECK_NOT_USING_AUTO(a); 1.659 + 1.660 + // This check had better not change, though. 1.661 + CHECK_IS_USING_AUTO(b); 1.662 + 1.663 + a.SwapElements(b); 1.664 + 1.665 + CHECK_IS_USING_AUTO(b); 1.666 + CHECK_ARRAY(a, data2); 1.667 + int expectedB[] = {8, 6, 7}; 1.668 + CHECK_ARRAY(b, expectedB); 1.669 + } 1.670 + 1.671 + // Swap two auto arrays which are using heap storage such that one fits into 1.672 + // the other's auto storage, but the other needs to stay on the heap. 1.673 + { 1.674 + nsAutoTArray<int, 3> a; 1.675 + nsAutoTArray<int, 2> b; 1.676 + a.AppendElements(data1, ArrayLength(data1)); 1.677 + a.RemoveElementAt(3); 1.678 + 1.679 + b.AppendElements(data2, ArrayLength(data2)); 1.680 + b.RemoveElementAt(2); 1.681 + 1.682 + CHECK_NOT_USING_AUTO(a); 1.683 + CHECK_NOT_USING_AUTO(b); 1.684 + 1.685 + a.SwapElements(b); 1.686 + 1.687 + CHECK_NOT_USING_AUTO(b); 1.688 + 1.689 + int expected1[] = {3, 0}; 1.690 + int expected2[] = {8, 6, 7}; 1.691 + 1.692 + CHECK_ARRAY(a, expected1); 1.693 + CHECK_ARRAY(b, expected2); 1.694 + } 1.695 + 1.696 + // Swap two arrays, neither of which fits into the other's auto-storage. 1.697 + { 1.698 + nsAutoTArray<int, 1> a; 1.699 + nsAutoTArray<int, 3> b; 1.700 + 1.701 + a.AppendElements(data1, ArrayLength(data1)); 1.702 + b.AppendElements(data2, ArrayLength(data2)); 1.703 + 1.704 + a.SwapElements(b); 1.705 + 1.706 + CHECK_ARRAY(a, data2); 1.707 + CHECK_ARRAY(b, data1); 1.708 + } 1.709 + 1.710 + // Swap an empty nsTArray with a non-empty nsAutoTArray. 1.711 + { 1.712 + nsTArray<int> a; 1.713 + nsAutoTArray<int, 3> b; 1.714 + 1.715 + b.AppendElements(data2, ArrayLength(data2)); 1.716 + CHECK_IS_USING_AUTO(b); 1.717 + 1.718 + a.SwapElements(b); 1.719 + 1.720 + CHECK_ARRAY(a, data2); 1.721 + CHECK_EQ_INT(b.Length(), 0); 1.722 + CHECK_IS_USING_AUTO(b); 1.723 + } 1.724 + 1.725 + // Swap two big auto arrays. 1.726 + { 1.727 + const unsigned size = 8192; 1.728 + nsAutoTArray<unsigned, size> a; 1.729 + nsAutoTArray<unsigned, size> b; 1.730 + 1.731 + for (unsigned i = 0; i < size; i++) { 1.732 + a.AppendElement(i); 1.733 + b.AppendElement(i + 1); 1.734 + } 1.735 + 1.736 + CHECK_IS_USING_AUTO(a); 1.737 + CHECK_IS_USING_AUTO(b); 1.738 + 1.739 + a.SwapElements(b); 1.740 + 1.741 + CHECK_IS_USING_AUTO(a); 1.742 + CHECK_IS_USING_AUTO(b); 1.743 + 1.744 + CHECK_EQ_INT(a.Length(), size); 1.745 + CHECK_EQ_INT(b.Length(), size); 1.746 + 1.747 + for (unsigned i = 0; i < size; i++) { 1.748 + CHECK_EQ_INT(a[i], i + 1); 1.749 + CHECK_EQ_INT(b[i], i); 1.750 + } 1.751 + } 1.752 + 1.753 + // Swap two arrays and make sure that their capacities don't increase 1.754 + // unnecessarily. 1.755 + { 1.756 + nsTArray<int> a; 1.757 + nsTArray<int> b; 1.758 + b.AppendElements(data2, ArrayLength(data2)); 1.759 + 1.760 + CHECK_EQ_INT(a.Capacity(), 0); 1.761 + uint32_t bCapacity = b.Capacity(); 1.762 + 1.763 + a.SwapElements(b); 1.764 + 1.765 + // Make sure that we didn't increase the capacity of either array. 1.766 + CHECK_ARRAY(a, data2); 1.767 + CHECK_EQ_INT(b.Length(), 0); 1.768 + CHECK_EQ_INT(b.Capacity(), 0); 1.769 + CHECK_EQ_INT(a.Capacity(), bCapacity); 1.770 + } 1.771 + 1.772 + // Swap an auto array with a TArray, then clear the auto array and make sure 1.773 + // it doesn't forget the fact that it has an auto buffer. 1.774 + { 1.775 + nsTArray<int> a; 1.776 + nsAutoTArray<int, 3> b; 1.777 + 1.778 + a.AppendElements(data1, ArrayLength(data1)); 1.779 + 1.780 + a.SwapElements(b); 1.781 + 1.782 + CHECK_EQ_INT(a.Length(), 0); 1.783 + CHECK_ARRAY(b, data1); 1.784 + 1.785 + b.Clear(); 1.786 + 1.787 + CHECK_USES_SHARED_EMPTY_HDR(a); 1.788 + CHECK_IS_USING_AUTO(b); 1.789 + } 1.790 + 1.791 + // Same thing as the previous test, but with more auto arrays. 1.792 + { 1.793 + nsAutoTArray<int, 16> a; 1.794 + nsAutoTArray<int, 3> b; 1.795 + 1.796 + a.AppendElements(data1, ArrayLength(data1)); 1.797 + 1.798 + a.SwapElements(b); 1.799 + 1.800 + CHECK_EQ_INT(a.Length(), 0); 1.801 + CHECK_ARRAY(b, data1); 1.802 + 1.803 + b.Clear(); 1.804 + 1.805 + CHECK_IS_USING_AUTO(a); 1.806 + CHECK_IS_USING_AUTO(b); 1.807 + } 1.808 + 1.809 + // Swap an empty nsTArray and an empty nsAutoTArray. 1.810 + { 1.811 + nsAutoTArray<int, 8> a; 1.812 + nsTArray<int> b; 1.813 + 1.814 + a.SwapElements(b); 1.815 + 1.816 + CHECK_IS_USING_AUTO(a); 1.817 + CHECK_NOT_USING_AUTO(b); 1.818 + CHECK_EQ_INT(a.Length(), 0); 1.819 + CHECK_EQ_INT(b.Length(), 0); 1.820 + } 1.821 + 1.822 + // Swap empty auto array with non-empty nsAutoTArray using malloc'ed storage. 1.823 + // I promise, all these tests have a point. 1.824 + { 1.825 + nsAutoTArray<int, 2> a; 1.826 + nsAutoTArray<int, 1> b; 1.827 + 1.828 + a.AppendElements(data1, ArrayLength(data1)); 1.829 + 1.830 + a.SwapElements(b); 1.831 + 1.832 + CHECK_IS_USING_AUTO(a); 1.833 + CHECK_NOT_USING_AUTO(b); 1.834 + CHECK_ARRAY(b, data1); 1.835 + CHECK_EQ_INT(a.Length(), 0); 1.836 + } 1.837 + 1.838 + return true; 1.839 +} 1.840 + 1.841 +static bool test_fallible() 1.842 +{ 1.843 + // Test that FallibleTArray works properly; that is, it never OOMs, but 1.844 + // instead eventually returns false. 1.845 + // 1.846 + // This test is only meaningful on 32-bit systems. On a 64-bit system, we 1.847 + // might never OOM. 1.848 + if (sizeof(void*) > 4) { 1.849 + return true; 1.850 + } 1.851 + 1.852 + // Allocate a bunch of 128MB arrays. Larger allocations will fail on some 1.853 + // platforms without actually hitting OOM. 1.854 + // 1.855 + // 36 * 128MB > 4GB, so we should definitely OOM by the 36th array. 1.856 + const unsigned numArrays = 36; 1.857 + FallibleTArray<char> arrays[numArrays]; 1.858 + for (uint32_t i = 0; i < numArrays; i++) { 1.859 + bool success = arrays[i].SetCapacity(128 * 1024 * 1024); 1.860 + if (!success) { 1.861 + // We got our OOM. Check that it didn't come too early. 1.862 + if (i < 8) { 1.863 + printf("test_fallible: Got OOM on iteration %d. Too early!\n", i); 1.864 + return false; 1.865 + } 1.866 + return true; 1.867 + } 1.868 + } 1.869 + 1.870 + // No OOM? That's...weird. 1.871 + printf("test_fallible: Didn't OOM or crash? nsTArray::SetCapacity " 1.872 + "must be lying.\n"); 1.873 + return false; 1.874 +} 1.875 + 1.876 +static bool test_conversion_operator() { 1.877 + FallibleTArray<int> f; 1.878 + const FallibleTArray<int> fconst; 1.879 + AutoFallibleTArray<int, 8> fauto; 1.880 + const AutoFallibleTArray<int, 8> fautoconst; 1.881 + 1.882 + InfallibleTArray<int> i; 1.883 + const InfallibleTArray<int> iconst; 1.884 + AutoInfallibleTArray<int, 8> iauto; 1.885 + const AutoInfallibleTArray<int, 8> iautoconst; 1.886 + 1.887 + nsTArray<int> t; 1.888 + const nsTArray<int> tconst; 1.889 + nsAutoTArray<int, 8> tauto; 1.890 + const nsAutoTArray<int, 8> tautoconst; 1.891 + 1.892 +#define CHECK_ARRAY_CAST(type) \ 1.893 + do { \ 1.894 + const type<int>& z1 = f; \ 1.895 + if ((void*)&z1 != (void*)&f) return false; \ 1.896 + const type<int>& z2 = fconst; \ 1.897 + if ((void*)&z2 != (void*)&fconst) return false; \ 1.898 + const type<int>& z3 = fauto; \ 1.899 + if ((void*)&z3 != (void*)&fauto) return false; \ 1.900 + const type<int>& z4 = fautoconst; \ 1.901 + if ((void*)&z4 != (void*)&fautoconst) return false; \ 1.902 + const type<int>& z5 = i; \ 1.903 + if ((void*)&z5 != (void*)&i) return false; \ 1.904 + const type<int>& z6 = iconst; \ 1.905 + if ((void*)&z6 != (void*)&iconst) return false; \ 1.906 + const type<int>& z7 = iauto; \ 1.907 + if ((void*)&z7 != (void*)&iauto) return false; \ 1.908 + const type<int>& z8 = iautoconst; \ 1.909 + if ((void*)&z8 != (void*)&iautoconst) return false; \ 1.910 + const type<int>& z9 = t; \ 1.911 + if ((void*)&z9 != (void*)&t) return false; \ 1.912 + const type<int>& z10 = tconst; \ 1.913 + if ((void*)&z10 != (void*)&tconst) return false; \ 1.914 + const type<int>& z11 = tauto; \ 1.915 + if ((void*)&z11 != (void*)&tauto) return false; \ 1.916 + const type<int>& z12 = tautoconst; \ 1.917 + if ((void*)&z12 != (void*)&tautoconst) return false; \ 1.918 + } while (0) 1.919 + 1.920 + CHECK_ARRAY_CAST(FallibleTArray); 1.921 + CHECK_ARRAY_CAST(InfallibleTArray); 1.922 + CHECK_ARRAY_CAST(nsTArray); 1.923 + 1.924 +#undef CHECK_ARRAY_CAST 1.925 + 1.926 + return true; 1.927 +} 1.928 + 1.929 +template<class T> 1.930 +struct BufAccessor : public T 1.931 +{ 1.932 + void* GetHdr() { return T::mHdr; } 1.933 +}; 1.934 + 1.935 +static bool test_SetLengthAndRetainStorage_no_ctor() { 1.936 + // 1050 because sizeof(int)*1050 is more than a page typically. 1.937 + const int N = 1050; 1.938 + FallibleTArray<int> f; 1.939 + AutoFallibleTArray<int, N> fauto; 1.940 + 1.941 + InfallibleTArray<int> i; 1.942 + AutoInfallibleTArray<int, N> iauto; 1.943 + 1.944 + nsTArray<int> t; 1.945 + nsAutoTArray<int, N> tauto; 1.946 + 1.947 +#define LPAREN ( 1.948 +#define RPAREN ) 1.949 +#define FOR_EACH(pre, post) \ 1.950 + do { \ 1.951 + pre f post; \ 1.952 + pre fauto post; \ 1.953 + pre i post; \ 1.954 + pre iauto post; \ 1.955 + pre t post; \ 1.956 + pre tauto post; \ 1.957 + } while (0) 1.958 + 1.959 + // Setup test arrays. 1.960 + FOR_EACH(;, .SetLength(N)); 1.961 + for (int n = 0; n < N; ++n) { 1.962 + FOR_EACH(;, [n] = n); 1.963 + } 1.964 + 1.965 + void* initial_Hdrs[] = { 1.966 + static_cast<BufAccessor<FallibleTArray<int> >&>(f).GetHdr(), 1.967 + static_cast<BufAccessor<AutoFallibleTArray<int, N> >&>(fauto).GetHdr(), 1.968 + static_cast<BufAccessor<InfallibleTArray<int> >&>(i).GetHdr(), 1.969 + static_cast<BufAccessor<AutoInfallibleTArray<int, N> >&>(iauto).GetHdr(), 1.970 + static_cast<BufAccessor<nsTArray<int> >&>(t).GetHdr(), 1.971 + static_cast<BufAccessor<nsAutoTArray<int, N> >&>(tauto).GetHdr(), 1.972 + nullptr 1.973 + }; 1.974 + 1.975 + // SetLengthAndRetainStorage(n), should NOT overwrite memory when T hasn't 1.976 + // a default constructor. 1.977 + FOR_EACH(;, .SetLengthAndRetainStorage(8)); 1.978 + FOR_EACH(;, .SetLengthAndRetainStorage(12)); 1.979 + for (int n = 0; n < 12; ++n) { 1.980 + FOR_EACH(if LPAREN, [n] != n RPAREN return false); 1.981 + } 1.982 + FOR_EACH(;, .SetLengthAndRetainStorage(0)); 1.983 + FOR_EACH(;, .SetLengthAndRetainStorage(N)); 1.984 + for (int n = 0; n < N; ++n) { 1.985 + FOR_EACH(if LPAREN, [n] != n RPAREN return false); 1.986 + } 1.987 + 1.988 + void* current_Hdrs[] = { 1.989 + static_cast<BufAccessor<FallibleTArray<int> >&>(f).GetHdr(), 1.990 + static_cast<BufAccessor<AutoFallibleTArray<int, N> >&>(fauto).GetHdr(), 1.991 + static_cast<BufAccessor<InfallibleTArray<int> >&>(i).GetHdr(), 1.992 + static_cast<BufAccessor<AutoInfallibleTArray<int, N> >&>(iauto).GetHdr(), 1.993 + static_cast<BufAccessor<nsTArray<int> >&>(t).GetHdr(), 1.994 + static_cast<BufAccessor<nsAutoTArray<int, N> >&>(tauto).GetHdr(), 1.995 + nullptr 1.996 + }; 1.997 + 1.998 + // SetLengthAndRetainStorage(n) should NOT have reallocated the internal 1.999 + // memory. 1.1000 + if (sizeof(initial_Hdrs) != sizeof(current_Hdrs)) return false; 1.1001 + for (size_t n = 0; n < sizeof(current_Hdrs) / sizeof(current_Hdrs[0]); ++n) { 1.1002 + if (current_Hdrs[n] != initial_Hdrs[n]) { 1.1003 + return false; 1.1004 + } 1.1005 + } 1.1006 + 1.1007 + 1.1008 +#undef FOR_EACH 1.1009 +#undef LPAREN 1.1010 +#undef RPAREN 1.1011 + 1.1012 + return true; 1.1013 +} 1.1014 + 1.1015 +//---- 1.1016 + 1.1017 +typedef bool (*TestFunc)(); 1.1018 +#define DECL_TEST(name) { #name, name } 1.1019 + 1.1020 +static const struct Test { 1.1021 + const char* name; 1.1022 + TestFunc func; 1.1023 +} tests[] = { 1.1024 + DECL_TEST(test_int_array), 1.1025 + DECL_TEST(test_int64_array), 1.1026 + DECL_TEST(test_char_array), 1.1027 + DECL_TEST(test_uint32_array), 1.1028 + DECL_TEST(test_object_array), 1.1029 + DECL_TEST(test_string_array), 1.1030 + DECL_TEST(test_comptr_array), 1.1031 + DECL_TEST(test_refptr_array), 1.1032 + DECL_TEST(test_ptrarray), 1.1033 +#ifdef DEBUG 1.1034 + DECL_TEST(test_autoarray), 1.1035 +#endif 1.1036 + DECL_TEST(test_indexof), 1.1037 + DECL_TEST(test_heap), 1.1038 + DECL_TEST(test_swap), 1.1039 + DECL_TEST(test_fallible), 1.1040 + DECL_TEST(test_conversion_operator), 1.1041 + DECL_TEST(test_SetLengthAndRetainStorage_no_ctor), 1.1042 + { nullptr, nullptr } 1.1043 +}; 1.1044 + 1.1045 +} 1.1046 + 1.1047 +using namespace TestTArray; 1.1048 + 1.1049 +int main(int argc, char **argv) { 1.1050 + int count = 1; 1.1051 + if (argc > 1) 1.1052 + count = atoi(argv[1]); 1.1053 + 1.1054 + if (NS_FAILED(NS_InitXPCOM2(nullptr, nullptr, nullptr))) 1.1055 + return -1; 1.1056 + 1.1057 + bool success = true; 1.1058 + while (count--) { 1.1059 + for (const Test* t = tests; t->name != nullptr; ++t) { 1.1060 + bool test_result = t->func(); 1.1061 + printf("%25s : %s\n", t->name, test_result ? "SUCCESS" : "FAILURE"); 1.1062 + if (!test_result) 1.1063 + success = false; 1.1064 + } 1.1065 + } 1.1066 + 1.1067 + NS_ShutdownXPCOM(nullptr); 1.1068 + return success ? 0 : -1; 1.1069 +}