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