xpcom/tests/TestTArray.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:996f5e6744c7
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/. */
6
7 #include "mozilla/ArrayUtils.h"
8
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"
19
20 using namespace mozilla;
21
22 namespace TestTArray {
23
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 }
29
30 //----
31
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;
90
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;
107
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;
122
123 ary.Clear();
124 if (ary.IndexOf(extra) != UINT32_MAX)
125 return false;
126 if (ary.LastIndexOf(extra) != UINT32_MAX)
127 return false;
128
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;
139
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 }
147
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 }
157
158 // These shouldn't crash!
159 nsTArray<ElementType> empty;
160 ary.AppendElements(reinterpret_cast<ElementType *>(0), 0);
161 ary.AppendElements(empty);
162
163 // See bug 324981
164 ary.RemoveElement(extra);
165 ary.RemoveElement(extra);
166
167 return true;
168 }
169
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 }
174
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 }
179
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 }
184
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 }
189
190 //----
191
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() {}
201
202 Object& operator=(const Object& other) {
203 mStr = other.mStr;
204 mNum = other.mNum;
205 return *this;
206 }
207
208 bool operator==(const Object& other) const {
209 return mStr == other.mStr && mNum == other.mNum;
210 }
211
212 bool operator<(const Object& other) const {
213 // sort based on mStr only
214 return mStr.Compare(other.mStr) < 0;
215 }
216
217 const char *Str() const { return mStr.get(); }
218 uint32_t Num() const { return mNum; }
219
220 private:
221 nsCString mStr;
222 uint32_t mNum;
223 };
224
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 }
248
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
272
273 //----
274
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 }
289
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;
297
298 if (strArray.IndexOf("e") != 1)
299 return false;
300
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;
315
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 }
322
323 //----
324
325 typedef nsCOMPtr<nsIFile> FilePointer;
326
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 };
335
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 }
355
356 if (fileArray.IndexOf(kNames[1], 0, nsFileNameComparator()) != 1)
357 return false;
358
359 // It's unclear what 'operator<' means for nsCOMPtr, but whatever...
360 return test_basic_array(fileArray.Elements(), fileArray.Length(),
361 tmpDir);
362 }
363
364 //----
365
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 };
380
381 static bool test_refptr_array() {
382 bool rv = true;
383
384 nsTArray< nsRefPtr<RefcountedObject> > objArray;
385
386 RefcountedObject *a = new RefcountedObject(); a->AddRef();
387 RefcountedObject *b = new RefcountedObject(); b->AddRef();
388 RefcountedObject *c = new RefcountedObject(); c->AddRef();
389
390 objArray.AppendElement(a);
391 objArray.AppendElement(b);
392 objArray.AppendElement(c);
393
394 if (objArray.IndexOf(b) != 1)
395 rv = false;
396
397 a->Release();
398 b->Release();
399 c->Release();
400 return rv;
401 }
402
403 //----
404
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;
417
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;
430
431 return true;
432 }
433
434 //----
435
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;
442
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;
448
449 array.AppendElement(1u);
450 if (hdr != array.DebugGetHeader())
451 return false;
452
453 array.RemoveElement(1u);
454 array.AppendElements(data, ArrayLength(data));
455 if (hdr != array.DebugGetHeader())
456 return false;
457
458 array.AppendElement(2u);
459 if (hdr == array.DebugGetHeader())
460 return false;
461
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;
469
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;
484
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 }
499
500 return true;
501 }
502 #endif
503
504 //----
505
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 }
518
519 //----
520
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 }
531
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 }
557
558 //----
559
560 // An array |arr| is using its auto buffer if |&arr < arr.Elements()| and
561 // |arr.Elements() - &arr| is small.
562
563 #define IS_USING_AUTO(arr) \
564 ((uintptr_t) &(arr) < (uintptr_t) arr.Elements() && \
565 ((ptrdiff_t)arr.Elements() - (ptrdiff_t)&arr) <= 16)
566
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)
575
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)
584
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)
594
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)
603
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)
611
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};
616
617 // Swap two auto arrays.
618 {
619 nsAutoTArray<int, 8> a;
620 nsAutoTArray<int, 6> b;
621
622 a.AppendElements(data1, ArrayLength(data1));
623 b.AppendElements(data2, ArrayLength(data2));
624 CHECK_IS_USING_AUTO(a);
625 CHECK_IS_USING_AUTO(b);
626
627 a.SwapElements(b);
628
629 CHECK_IS_USING_AUTO(a);
630 CHECK_IS_USING_AUTO(b);
631 CHECK_ARRAY(a, data2);
632 CHECK_ARRAY(b, data1);
633 }
634
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;
640
641 a.AppendElements(data1, ArrayLength(data1));
642 a.RemoveElementAt(3);
643 b.AppendElements(data2, ArrayLength(data2));
644
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);
656
657 // This check had better not change, though.
658 CHECK_IS_USING_AUTO(b);
659
660 a.SwapElements(b);
661
662 CHECK_IS_USING_AUTO(b);
663 CHECK_ARRAY(a, data2);
664 int expectedB[] = {8, 6, 7};
665 CHECK_ARRAY(b, expectedB);
666 }
667
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);
675
676 b.AppendElements(data2, ArrayLength(data2));
677 b.RemoveElementAt(2);
678
679 CHECK_NOT_USING_AUTO(a);
680 CHECK_NOT_USING_AUTO(b);
681
682 a.SwapElements(b);
683
684 CHECK_NOT_USING_AUTO(b);
685
686 int expected1[] = {3, 0};
687 int expected2[] = {8, 6, 7};
688
689 CHECK_ARRAY(a, expected1);
690 CHECK_ARRAY(b, expected2);
691 }
692
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;
697
698 a.AppendElements(data1, ArrayLength(data1));
699 b.AppendElements(data2, ArrayLength(data2));
700
701 a.SwapElements(b);
702
703 CHECK_ARRAY(a, data2);
704 CHECK_ARRAY(b, data1);
705 }
706
707 // Swap an empty nsTArray with a non-empty nsAutoTArray.
708 {
709 nsTArray<int> a;
710 nsAutoTArray<int, 3> b;
711
712 b.AppendElements(data2, ArrayLength(data2));
713 CHECK_IS_USING_AUTO(b);
714
715 a.SwapElements(b);
716
717 CHECK_ARRAY(a, data2);
718 CHECK_EQ_INT(b.Length(), 0);
719 CHECK_IS_USING_AUTO(b);
720 }
721
722 // Swap two big auto arrays.
723 {
724 const unsigned size = 8192;
725 nsAutoTArray<unsigned, size> a;
726 nsAutoTArray<unsigned, size> b;
727
728 for (unsigned i = 0; i < size; i++) {
729 a.AppendElement(i);
730 b.AppendElement(i + 1);
731 }
732
733 CHECK_IS_USING_AUTO(a);
734 CHECK_IS_USING_AUTO(b);
735
736 a.SwapElements(b);
737
738 CHECK_IS_USING_AUTO(a);
739 CHECK_IS_USING_AUTO(b);
740
741 CHECK_EQ_INT(a.Length(), size);
742 CHECK_EQ_INT(b.Length(), size);
743
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 }
749
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));
756
757 CHECK_EQ_INT(a.Capacity(), 0);
758 uint32_t bCapacity = b.Capacity();
759
760 a.SwapElements(b);
761
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 }
768
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;
774
775 a.AppendElements(data1, ArrayLength(data1));
776
777 a.SwapElements(b);
778
779 CHECK_EQ_INT(a.Length(), 0);
780 CHECK_ARRAY(b, data1);
781
782 b.Clear();
783
784 CHECK_USES_SHARED_EMPTY_HDR(a);
785 CHECK_IS_USING_AUTO(b);
786 }
787
788 // Same thing as the previous test, but with more auto arrays.
789 {
790 nsAutoTArray<int, 16> a;
791 nsAutoTArray<int, 3> b;
792
793 a.AppendElements(data1, ArrayLength(data1));
794
795 a.SwapElements(b);
796
797 CHECK_EQ_INT(a.Length(), 0);
798 CHECK_ARRAY(b, data1);
799
800 b.Clear();
801
802 CHECK_IS_USING_AUTO(a);
803 CHECK_IS_USING_AUTO(b);
804 }
805
806 // Swap an empty nsTArray and an empty nsAutoTArray.
807 {
808 nsAutoTArray<int, 8> a;
809 nsTArray<int> b;
810
811 a.SwapElements(b);
812
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 }
818
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;
824
825 a.AppendElements(data1, ArrayLength(data1));
826
827 a.SwapElements(b);
828
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 }
834
835 return true;
836 }
837
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 }
848
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 }
866
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 }
872
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;
878
879 InfallibleTArray<int> i;
880 const InfallibleTArray<int> iconst;
881 AutoInfallibleTArray<int, 8> iauto;
882 const AutoInfallibleTArray<int, 8> iautoconst;
883
884 nsTArray<int> t;
885 const nsTArray<int> tconst;
886 nsAutoTArray<int, 8> tauto;
887 const nsAutoTArray<int, 8> tautoconst;
888
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)
916
917 CHECK_ARRAY_CAST(FallibleTArray);
918 CHECK_ARRAY_CAST(InfallibleTArray);
919 CHECK_ARRAY_CAST(nsTArray);
920
921 #undef CHECK_ARRAY_CAST
922
923 return true;
924 }
925
926 template<class T>
927 struct BufAccessor : public T
928 {
929 void* GetHdr() { return T::mHdr; }
930 };
931
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;
937
938 InfallibleTArray<int> i;
939 AutoInfallibleTArray<int, N> iauto;
940
941 nsTArray<int> t;
942 nsAutoTArray<int, N> tauto;
943
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)
955
956 // Setup test arrays.
957 FOR_EACH(;, .SetLength(N));
958 for (int n = 0; n < N; ++n) {
959 FOR_EACH(;, [n] = n);
960 }
961
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 };
971
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 }
984
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 };
994
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;
1001 }
1002 }
1003
1004
1005 #undef FOR_EACH
1006 #undef LPAREN
1007 #undef RPAREN
1008
1009 return true;
1010 }
1011
1012 //----
1013
1014 typedef bool (*TestFunc)();
1015 #define DECL_TEST(name) { #name, name }
1016
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 };
1041
1042 }
1043
1044 using namespace TestTArray;
1045
1046 int main(int argc, char **argv) {
1047 int count = 1;
1048 if (argc > 1)
1049 count = atoi(argv[1]);
1050
1051 if (NS_FAILED(NS_InitXPCOM2(nullptr, nullptr, nullptr)))
1052 return -1;
1053
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;
1061 }
1062 }
1063
1064 NS_ShutdownXPCOM(nullptr);
1065 return success ? 0 : -1;
1066 }

mercurial