xpcom/tests/TestTArray.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial