1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28#if DEBUG
29#include "Tests.h"
30
31#include <libkern/c++/OSArray.h>
32#include <libkern/c++/OSSet.h>
33#include <libkern/c++/OSDictionary.h>
34#include <libkern/c++/OSString.h>
35#include <libkern/c++/OSSymbol.h>
36#include <libkern/c++/OSCollectionIterator.h>
37
38void testArray()
39{
40    bool res = true;
41    void *spaceCheck, *spaceCheck2 , *spaceCheck3;
42    int i, j, count, count2;
43    OSObject *cache[numStrCache], *str, *sym;
44    OSArray *array1, *array2;
45
46    // Do first test without memory leak tests to initialise the metaclass
47    array1 = OSArray::withCapacity(1);
48    TEST_ASSERT('A', "0a", array1);
49    if (array1)
50        array1->release();
51
52    // Grow the symbol pool to maximum
53    for (i = 0; i < numStrCache; i++)
54        cache[i] = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
55    for (i = 0; i < numStrCache; i++)
56        cache[i]->release();
57
58    // Create and destroy an array
59    spaceCheck = checkPointSpace();
60    array1 = OSArray::withCapacity(1);
61    TEST_ASSERT('A', "1a", array1);
62    if (array1) {
63        TEST_ASSERT('A', "1b", !array1->getCount());
64        TEST_ASSERT('A', "1c", 1 == array1->getCapacity());
65        TEST_ASSERT('A', "1d", 1 == array1->getCapacityIncrement());
66        TEST_ASSERT('A', "1e", 4 == array1->setCapacityIncrement(4));
67        TEST_ASSERT('A', "1f", 4 == array1->getCapacityIncrement());
68        TEST_ASSERT('A', "1g", 8 == array1->ensureCapacity(5));
69
70        spaceCheck2 = checkPointSpace();
71        cache[0] = IOString::withCStringNoCopy(strCache[0]);
72
73        spaceCheck3 = checkPointSpace();
74        TEST_ASSERT('A', "1h", array1->setObject(cache[0]));
75        TEST_ASSERT('A', "1i", cache[0] == array1->getObject(0));
76        cache[0]->release();
77        res = res && checkSpace("(A)1j", spaceCheck3, 0);
78
79        TEST_ASSERT('A', "1k", 1 == array1->getCount());
80        array1->flushCollection();
81        TEST_ASSERT('A', "1l", !array1->getCount());
82        res = res && checkSpace("(A)1m", spaceCheck2, 0);
83
84        array1->release();
85    }
86    res = res && checkSpace("(A)1", spaceCheck, 0);
87
88    // Check the creation of a sizable OSArray from an array of IOObjects
89    // Also check indexing into the array.
90    spaceCheck = checkPointSpace();
91    for (i = 0; i < numStrCache; i++)
92        cache[i] = OSString::withCStringNoCopy(strCache[i]);
93    array1 = OSArray::withObjects(cache, numStrCache, numStrCache);
94    TEST_ASSERT('A', "2a", array1);
95    for (i = 0; i < numStrCache; i++)
96        cache[i]->release();
97    if (array1) {
98        TEST_ASSERT('A', "2b", numStrCache == (int) array1->getCount());
99        TEST_ASSERT('A', "2c", numStrCache == (int) array1->getCapacity());
100        TEST_ASSERT('A', "2d",
101                    numStrCache == (int) array1->getCapacityIncrement());
102
103        for (i = 0; (str = array1->getObject(i)); i++) {
104            if (str != cache[i]) {
105                verPrintf(("testArray(A) test 2e%d failed\n", i));
106                res = false;
107            }
108        }
109        TEST_ASSERT('A', "2f", numStrCache == i);
110        array1->release();
111    }
112    res = res && checkSpace("(A)2", spaceCheck, 0);
113
114    // Test array creation from another array by both the setObject method
115    // and the withArray factory.  And test __takeObject code first
116    // with tail removal then with head removal
117    spaceCheck = checkPointSpace();
118    for (i = 0; i < numStrCache; i++)
119        cache[i] = OSString::withCStringNoCopy(strCache[i]);
120    array1 = OSArray::withObjects(cache, numStrCache, numStrCache);
121    TEST_ASSERT('A', "3a", array1);
122    for (i = 0; i < numStrCache; i++)
123        cache[i]->release();
124    array2 = 0;
125    if (array1) {
126        array2 = OSArray::withCapacity(1);
127        TEST_ASSERT('A', "3b", array2);
128        TEST_ASSERT('A', "3c", !array2->getCount());
129        TEST_ASSERT('A', "3d", array2->setObject(array1));
130        TEST_ASSERT('A', "3e", array1->getCount() == array2->getCount());
131    }
132    if (array2) {
133        count = 0;
134        TEST_ASSERT('A', "3f", numStrCache == (int) array2->getCount());
135        for (i = array2->getCount(); (str = array2->__takeObject(--i)); ) {
136            if (str != cache[i]) {
137                verPrintf(("testArray(A) test 3g%d failed\n", i));
138                res = false;
139            }
140            count += ((int) array2->getCount() == i);
141            str->release();
142        }
143        TEST_ASSERT('A', "3h", count == numStrCache);
144        TEST_ASSERT('A', "3i", -1 == i);
145        TEST_ASSERT('A', "3j", !array2->getCount());
146
147        spaceCheck2 = checkPointSpace();
148        array2->flushCollection();
149        res = res && checkSpace("(A)3k", spaceCheck2, 0);
150
151        array2->release();
152        array2 = 0;
153    }
154    if (array1) {
155        array2 = OSArray::withArray(array1, numStrCache - 1);
156        TEST_ASSERT('A', "3l", !array2);
157        array2 = OSArray::withArray(array1, array1->getCount());
158        TEST_ASSERT('A', "3m", array2);
159        array1->release();
160    }
161    if (array2) {
162        count = 0;
163        TEST_ASSERT('A', "3o", numStrCache == (int) array2->getCount());
164        for (i = 0; (str = array2->__takeObject(0)); i++) {
165            count += (str == cache[i]);
166            str->release();
167        }
168        TEST_ASSERT('A', "3p", count == numStrCache);
169        TEST_ASSERT('A', "3q", !array2->getCount());
170        array2->release();
171        array2 = 0;
172    }
173    res = res && checkSpace("(A)3", spaceCheck, 0);
174
175    // Test object replacement from one array to another
176    spaceCheck = checkPointSpace();
177    array1 = OSArray::withCapacity(numStrCache);
178    TEST_ASSERT('A', "4a", array1);
179    if (array1) {
180        count = count2 = 0;
181        for (i = 0; i < numStrCache; i++) {
182            str = OSString::withCStringNoCopy(strCache[i]);
183            count += array1->setObject(str);
184            count2 += (str == array1->lastObject());
185            str->release();
186        }
187        TEST_ASSERT('A', "4b", numStrCache == (int) array1->getCount());
188        TEST_ASSERT('A', "4c", count == numStrCache);
189        TEST_ASSERT('A', "4d", count2 == numStrCache);
190    }
191    array2 = OSArray::withCapacity(1);
192    TEST_ASSERT('A', "4e", array2);
193    if (array2) {
194        count = count2 = 0;
195        str = (OSObject *) OSSymbol::withCStringNoCopy(strCache[0]);
196        for (i = 0; i < numStrCache; i++) {
197            sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
198            count += array2->setObject(sym, 0);
199            count2 += (str == array2->lastObject());
200            sym->release();
201        }
202        str->release();
203        TEST_ASSERT('A', "4f", numStrCache == (int) array2->getCount());
204        TEST_ASSERT('A', "4g", count == numStrCache);
205        TEST_ASSERT('A', "4h", count2 == numStrCache);
206    }
207    if (array1 && array2) {
208
209        count = count2 = 0;
210        for (i = array1->getCount() - 1; (sym = array2->__takeObject(0)); i--) {
211            str = array1->replaceObject(sym, i);
212            count  += (str != 0);
213            count2 += (sym != str);
214            if (str)
215                str->release();
216            if (sym)
217                sym->release();
218        }
219        TEST_ASSERT('A', "4k", numStrCache == (int) array1->getCount());
220        TEST_ASSERT('A', "4l", count == numStrCache);
221        TEST_ASSERT('A', "4m", count2 == numStrCache);
222        array1->release();
223        array2->release();
224    }
225    else {
226        if (array1) array1->release();
227        if (array2) array2->release();
228    }
229    res = res && checkSpace("(A)4", spaceCheck, 0);
230
231    // Test array duplicate removal
232    spaceCheck = checkPointSpace();
233    array1 = OSArray::withCapacity(numStrCache);
234    TEST_ASSERT('A', "5a", array1);
235    if (array1) {
236        for (i = 0; i < numStrCache; i++) {
237            sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
238            count += array1->setObject(sym);
239            sym->release();
240        }
241        TEST_ASSERT('A', "5b", numStrCache == (int) array1->getCount());
242
243        // remove duplicates
244        for (i = 0; (sym = array1->getObject(i)); )
245            if (sym->getRetainCount() == 1)
246                i++;
247            else {
248                //sym = array1->__takeObject(i);
249                //sym->release();
250                array1->removeObject(i);
251            }
252        TEST_ASSERT('A', "5c", numStrCache != (int) array1->getCount());
253
254        // check to see that all symbols are really there
255        for (count = 0, i = 0; i < numStrCache; i++) {
256            sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
257            for (count2 = false, j = 0; (str = array1->getObject(j)); j++)
258                if (str == sym) {
259                    count2 = true;
260                    break;
261                }
262            count += count2;
263            sym->release();
264        }
265        TEST_ASSERT('A', "5c", count == numStrCache);
266        array1->release();
267    }
268    res = res && checkSpace("(S)5", spaceCheck, 0);
269
270    if (res)
271        verPrintf(("testArray: All OSArray Tests passed\n"));
272    else
273        logPrintf(("testArray: Some OSArray Tests failed\n"));
274}
275
276void testSet()
277{
278    bool res = true;
279    void *spaceCheck, *spaceCheck2 , *spaceCheck3;
280    int i, count, count2;
281    OSObject *cache[numStrCache], *str, *sym;
282    OSSet *set1, *set2;
283    OSArray *array;
284
285    // Do first test without memory leak tests to initialise the metaclass
286    set1 = OSSet::withCapacity(1);
287    TEST_ASSERT('S', "0a", set1);
288    if (set1)
289        set1->release();
290
291    // Grow the symbol pool to maximum
292    for (i = 0; i < numStrCache; i++)
293        cache[i] = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
294    for (i = 0; i < numStrCache; i++)
295        cache[i]->release();
296
297    // Create and destroy an set
298    spaceCheck = checkPointSpace();
299    set1 = OSSet::withCapacity(1);
300    TEST_ASSERT('S', "1a", set1);
301    if (set1) {
302        TEST_ASSERT('S', "1b", !set1->getCount());
303        TEST_ASSERT('S', "1c", 1 == set1->getCapacity());
304        TEST_ASSERT('S', "1d", 1 == set1->getCapacityIncrement());
305        TEST_ASSERT('S', "1e", 4 == set1->setCapacityIncrement(4));
306        TEST_ASSERT('S', "1f", 4 == set1->getCapacityIncrement());
307        TEST_ASSERT('S', "1g", 8 == set1->ensureCapacity(5));
308
309        spaceCheck2 = checkPointSpace();
310        cache[0] = IOString::withCStringNoCopy(strCache[0]);
311
312        spaceCheck3 = checkPointSpace();
313        TEST_ASSERT('S', "1h", set1->setObject(cache[0]));
314        TEST_ASSERT('S', "1i", set1->containsObject(cache[0]));
315        TEST_ASSERT('S', "1j", cache[0] == set1->getAnyObject());
316        cache[0]->release();
317        res = res && checkSpace("(S)1k", spaceCheck3, 0);
318
319        TEST_ASSERT('S', "1l", 1 == set1->getCount());
320        set1->flushCollection();
321        TEST_ASSERT('S', "1m", !set1->getCount());
322        res = res && checkSpace("(S)1n", spaceCheck2, 0);
323
324        set1->release();
325    }
326    res = res && checkSpace("(S)1", spaceCheck, 0);
327
328    // Check the creation of a sizable OSSet from an set of IOObjects
329    // Also check member test of set.
330    spaceCheck = checkPointSpace();
331    for (i = 0; i < numStrCache; i++)
332        cache[i] = OSString::withCStringNoCopy(strCache[i]);
333    set1 = OSSet::withObjects(cache, numStrCache, numStrCache);
334    TEST_ASSERT('S', "2a", set1);
335    for (i = 0; i < numStrCache; i++)
336        cache[i]->release();
337    if (set1) {
338        TEST_ASSERT('S', "2b", numStrCache == (int) set1->getCount());
339        TEST_ASSERT('S', "2c", numStrCache == (int) set1->getCapacity());
340        TEST_ASSERT('S', "2d",
341                    numStrCache == (int) set1->getCapacityIncrement());
342
343        count = 0;
344        for (i = set1->getCount(); --i >= 0; )
345            count += set1->member(cache[i]);
346
347        TEST_ASSERT('S', "2e", numStrCache == count);
348        set1->release();
349    }
350    res = res && checkSpace("(S)2", spaceCheck, 0);
351
352    // Test set creation from another set by both the setObject method
353    // and the withArray factory.  And test __takeObject code first
354    // with tail removal then with head removal
355    spaceCheck = checkPointSpace();
356    for (i = 0; i < numStrCache; i++)
357        cache[i] = OSString::withCStringNoCopy(strCache[i]);
358    set1 = OSSet::withObjects(cache, numStrCache, numStrCache);
359    TEST_ASSERT('S', "3a", set1);
360    for (i = 0; i < numStrCache; i++)
361        cache[i]->release();
362    set2 = 0;
363    if (set1) {
364        set2 = OSSet::withCapacity(set1->getCount());
365        TEST_ASSERT('S', "3b", set2);
366        TEST_ASSERT('S', "3c", !set2->getCount());
367        TEST_ASSERT('S', "3d", set2->setObject(set1));
368        TEST_ASSERT('S', "3e", set1->getCount() == set2->getCount());
369    }
370    if (set2) {
371        TEST_ASSERT('S', "3f", numStrCache == (int) set2->getCount());
372        count = count2 = 0;
373        while ( (str = set2->getAnyObject()) ) {
374            count  += set2->__takeObject(str);
375            count2 += set1->member(str);
376            str->release();
377        }
378        TEST_ASSERT('S', "3g", !set2->getCount());
379        TEST_ASSERT('S', "3h", numStrCache == count);
380        TEST_ASSERT('S', "3i", numStrCache == count2);
381
382        spaceCheck2 = checkPointSpace();
383        set2->flushCollection();
384        res = res && checkSpace("(S)3j", spaceCheck2, 0);
385
386        set2->release();
387        set2 = 0;
388    }
389    if (set1) {
390        set2 = OSSet::withSet(set1, numStrCache - 1);
391        TEST_ASSERT('S', "3k", !set2);
392        set2 = OSSet::withSet(set1, set1->getCount());
393        TEST_ASSERT('S', "3l", set2);
394        set1->release();
395    }
396    if (set2) {
397        TEST_ASSERT('S', "3m", numStrCache == (int) set2->getCount());
398        i = count = count2 = 0;
399        while ( (str = set2->getAnyObject()) ) {
400            count  += set2->__takeObject(str);
401            count2 += (cache[i++] == str);
402            str->release();
403        }
404        TEST_ASSERT('S', "3n", !set2->getCount());
405        TEST_ASSERT('S', "3o", numStrCache == count);
406        TEST_ASSERT('S', "3p", numStrCache == count2);
407
408        set2->release();
409        set2 = 0;
410    }
411    res = res && checkSpace("(S)3", spaceCheck, 0);
412
413    // Test duplicate removal
414    spaceCheck = checkPointSpace();
415    set2 = 0;
416    set1 = OSSet::withCapacity(numStrCache);
417    TEST_ASSERT('S', "4a", set1);
418    if (set1) {
419        count = 0;
420        for (i = 0; i < numStrCache; i++) {
421            sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
422            count += set1->setObject(sym);
423            sym->release();
424        }
425        TEST_ASSERT('S', "4b", numStrCache != (int) set1->getCount());
426        TEST_ASSERT('S', "4c", count == (int) set1->getCount());
427
428        count = count2 = 0;
429        for (i = 0; i < numStrCache; i++) {
430            sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
431            count += set1->member(sym);
432            count2 += sym->getRetainCount();
433            sym->release();
434        }
435        TEST_ASSERT('S', "4d", count  == numStrCache);
436        TEST_ASSERT('S', "4e", count2 == numStrCache * 2);
437
438        set2 = OSSet::withSet(set1, 2 * set1->getCount());
439    }
440    TEST_ASSERT('S', "4f", set2);
441    if (set2) {
442        set2->setObject(set1);
443        TEST_ASSERT('S', "4g", set1->getCount() == set2->getCount());
444        set1->release();
445        set2->release();
446    }
447    res = res && checkSpace("(S)4", spaceCheck, 0);
448
449    // Test array duplicate removal
450    spaceCheck = checkPointSpace();
451    array = OSArray::withCapacity(numStrCache);
452    for (i = 0; i < numStrCache; i++) {
453        sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]);
454        count += array->setObject(sym);
455        sym->release();
456    }
457    set1 = OSSet::withArray(array, numStrCache);
458    TEST_ASSERT('S', "5a", set1);
459    if (set1) {
460        TEST_ASSERT('S', "5b", array->getCount() != set1->getCount());
461        array->release();
462
463        count = count2 = set1->getCount();
464        while ( (sym = set1->getAnyObject()) ) {
465            count  -= set1->__takeObject(sym);
466            count2 -= sym->getRetainCount();
467            sym->release();
468        }
469        TEST_ASSERT('S', "5c", !count);
470        TEST_ASSERT('S', "5d", !count2);
471        set1->release();
472    }
473    res = res && checkSpace("(S)5", spaceCheck, 0);
474
475    if (res)
476        verPrintf(("testSet: All OSSet Tests passed\n"));
477    else
478        logPrintf(("testSet: Some OSSet Tests failed\n"));
479}
480
481void testDictionary()
482{
483    bool res = true;
484    void *spaceCheck, *spaceCheck2, *spaceCheck3;
485    OSObject *cache[numStrCache];
486    OSString *str;
487    const OSSymbol *symCache[numStrCache], *sym;
488    OSDictionary *dict1, *dict2;
489    int i, numSymbols, count1, count2;
490
491    // Do first test without memory leak tests to initialise the metaclass
492    dict1 = OSDictionary::withCapacity(1);
493    TEST_ASSERT('D', "0a", dict1);
494    if (dict1)
495        dict1->release();
496
497    // Grow the symbol pool to maximum
498    for (i = 0; i < numStrCache; i++)
499        symCache[i] = OSSymbol::withCStringNoCopy(strCache[i]);
500    for (i = 0; i < numStrCache; i++)
501        symCache[i]->release();
502
503    // Create and destroy a dictionary
504    spaceCheck = checkPointSpace();
505    dict1 = OSDictionary::withCapacity(1);
506    TEST_ASSERT('D', "1a", dict1);
507    if (dict1) {
508        TEST_ASSERT('D', "1b", !dict1->getCount());
509        TEST_ASSERT('D', "1c", 1 == dict1->getCapacity());
510        TEST_ASSERT('D', "1d", 1 == dict1->getCapacityIncrement());
511        TEST_ASSERT('D', "1e", 4 == dict1->setCapacityIncrement(4));
512        TEST_ASSERT('D', "1f", 4 == dict1->getCapacityIncrement());
513        TEST_ASSERT('D', "1g", 8 == dict1->ensureCapacity(5));
514
515        spaceCheck2 = checkPointSpace();
516        sym = OSSymbol::withCStringNoCopy(strCache[0]);
517
518        spaceCheck3 = checkPointSpace();
519        TEST_ASSERT('D', "1h", dict1->setObject((OSObject *) sym, sym));
520        TEST_ASSERT('D', "1i", (OSObject *) sym == dict1->getObject(sym));
521        sym->release();
522        TEST_ASSERT('D', "1i", 2 == sym->getRetainCount());
523        res = res && checkSpace("(D)1j", spaceCheck3, 0);
524
525        TEST_ASSERT('D', "1k", 1 == dict1->getCount());
526        dict1->flushCollection();
527        TEST_ASSERT('D', "1l", !dict1->getCount());
528        res = res && checkSpace("(D)1m", spaceCheck2, 0);
529
530        dict1->release();
531    }
532    res = res && checkSpace("(D)1", spaceCheck, 0);
533
534    // Check the creation of a sizable OSDictionary from an array of IOObjects
535    // Also check indexing into the array.
536    spaceCheck = checkPointSpace();
537    for (i = 0, numSymbols = 0; i < numStrCache; i++) {
538        sym = OSSymbol::withCStringNoCopy(strCache[i]);
539        if (1 == sym->getRetainCount())
540            symCache[numSymbols++] = sym;
541        else
542            sym->release();
543    }
544    dict1 = OSDictionary::withObjects(
545                    (OSObject **) symCache, symCache, numSymbols, numSymbols);
546    TEST_ASSERT('D', "2a", dict1);
547    count1 = count2 = 0;
548    for (i = 0; i < numSymbols; i++)
549        count1 += (symCache[i]->getRetainCount() == 3);
550    TEST_ASSERT('D', "2b", count1 == numSymbols);
551    if (dict1) {
552        TEST_ASSERT('D', "2c", numSymbols == (int) dict1->getCount());
553        TEST_ASSERT('D', "2d", numSymbols == (int) dict1->getCapacity());
554        TEST_ASSERT('D', "2e",
555                    numSymbols == (int) dict1->getCapacityIncrement());
556
557        for (i = dict1->getCount(); --i >= 0; ) {
558            str = (OSString *) dict1->getObject(symCache[i]);
559            if (str != (OSString *) symCache[i]) {
560                verPrintf(("testDictionary(D) test 2f%d failed\n", i));
561                res = false;
562            }
563        }
564        dict1->release();
565    }
566    count1 = count2 = 0;
567    for (i = 0; i < numSymbols; i++) {
568        count1 += (symCache[i]->getRetainCount() == 1);
569        symCache[i]->release();
570    }
571    TEST_ASSERT('D', "2g", count1 == numSymbols);
572    res = res && checkSpace("(D)2", spaceCheck, 0);
573
574    // Check the creation of a sizable Dictionary from an array of IOStrings
575    // Also check searching dictionary use OSString for a key.
576    spaceCheck = checkPointSpace();
577    for (i = 0, numSymbols = 0; i < numStrCache; i++) {
578        sym = OSSymbol::withCStringNoCopy(strCache[i]);
579        if (1 == sym->getRetainCount()) {
580            cache[numSymbols] = OSString::withCStringNoCopy(strCache[i]);
581            symCache[numSymbols] = sym;
582            numSymbols++;
583        }
584        else
585            sym->release();
586    }
587    dict1 = OSDictionary::withObjects((OSObject **) symCache,
588                                      (OSString **) cache,
589                                      numSymbols, numSymbols);
590    TEST_ASSERT('D', "3a", dict1);
591    count1 = count2 = 0;
592    for (i = 0; i < numSymbols; i++) {
593        count1 += (symCache[i]->getRetainCount() == 3);
594        count2 += (cache[i]->getRetainCount() == 1);
595    }
596    TEST_ASSERT('D', "3b", count1 == numSymbols);
597    TEST_ASSERT('D', "3c", count2 == numSymbols);
598    if (dict1) {
599        count1 = count2 = 0;
600        for (i = 0; i < numSymbols; i++) {
601            str = (OSString *) cache[i];
602            count1 += (symCache[i] == (const OSSymbol *) dict1->getObject(str));
603            count2 += (symCache[i]->getRetainCount() == 3);
604        }
605        TEST_ASSERT('D', "3d", count1 == numSymbols);
606        TEST_ASSERT('D', "3e", count2 == numSymbols);
607
608        count1 = count2 = 0;
609        for (i = 0; i < numSymbols; i++) {
610            const char *cStr = ((OSString *) cache[i])->getCStringNoCopy();
611
612            count1 += (symCache[i] == (const OSSymbol *) dict1->getObject(cStr));
613            count2 += (symCache[i]->getRetainCount() == 3);
614        }
615        TEST_ASSERT('D', "3f", count1 == numSymbols);
616        TEST_ASSERT('D', "3g", count2 == numSymbols);
617
618        dict1->release();
619    }
620    count1 = count2 = 0;
621    for (i = 0; i < numSymbols; i++) {
622        count1 += (symCache[i]->getRetainCount() == 1);
623        count2 += (cache[i]->getRetainCount() == 1);
624        symCache[i]->release();
625        cache[i]->release();
626    }
627    TEST_ASSERT('D', "3h", count1 == numSymbols);
628    res = res && checkSpace("(D)3", spaceCheck, 0);
629
630    // Check the creation of a small dictionary then grow it one item at a time
631    // Create a new dictionary from the old dictionary.
632    // Finally remove each item permanently.
633    spaceCheck = checkPointSpace();
634    for (i = 0, numSymbols = 0; i < numStrCache; i++) {
635        sym = OSSymbol::withCStringNoCopy(strCache[i]);
636        if (1 == sym->getRetainCount()) {
637            cache[numSymbols] = OSString::withCStringNoCopy(strCache[i]);
638            symCache[numSymbols] = sym;
639            numSymbols++;
640        }
641        else
642            sym->release();
643    }
644    dict2 = 0;
645    dict1 = OSDictionary::withCapacity(1);
646    TEST_ASSERT('D', "4a", dict1);
647    if (dict1) {
648        count1 = count2 = 0;
649        for (i = 0; i < numSymbols; i++) {
650            sym = symCache[i];
651            count1 += ((OSObject *) sym == dict1->setObject((OSObject *) sym,
652                                               sym->getCStringNoCopy()));
653            count2 += (sym->getRetainCount() == 3);
654        }
655        TEST_ASSERT('D', "4b", numSymbols == (int) dict1->getCount());
656        TEST_ASSERT('D', "4c", numSymbols == count1);
657        TEST_ASSERT('D', "4d", numSymbols == count2);
658
659        dict2 = OSDictionary::withDictionary(dict1, numSymbols-1);
660        TEST_ASSERT('D', "4b", !dict2);
661        dict2 = OSDictionary::withDictionary(dict1, numSymbols);
662    }
663    TEST_ASSERT('D', "4e", dict2);
664    if (dict2) {
665        dict1->release(); dict1 = 0;
666
667        TEST_ASSERT('D', "4f", numSymbols == (int) dict2->getCount());
668
669        count1 = count2 = 0;
670        for (i = 0; i < numSymbols; i++) {
671            OSObject *replacedObject;
672
673            sym = symCache[i];
674            str = (OSString *) cache[i];
675            replacedObject = dict2->setObject(str, str);
676            count1 += ((OSString *) sym == replacedObject);
677            replacedObject->release();
678            count2 += (sym->getRetainCount() == 2);
679            str->release();
680        }
681        TEST_ASSERT('D', "4g", numSymbols == count1);
682        TEST_ASSERT('D', "4h", numSymbols == count2);
683
684        count1 = count2 = 0;
685        for (i = 0; i < numSymbols; i++) {
686            sym = symCache[i];
687            str = (OSString *) cache[i];
688            count1 += (str == dict2->__takeObject(sym));
689            str->release();
690            count2 += (sym->getRetainCount() == 1);
691            sym->release();
692        }
693        TEST_ASSERT('D', "4i", numSymbols == count1);
694        TEST_ASSERT('D', "4j", numSymbols == count2);
695        TEST_ASSERT('D', "4k", !dict2->getCount());
696        dict2->release(); dict2 = 0;
697    }
698    else if (dict1)
699        dict1->release();
700    res = res && checkSpace("(D)4", spaceCheck, 0);
701
702    if (res)
703        verPrintf(("testDictionary: All OSDictionary Tests passed\n"));
704    else
705        logPrintf(("testDictionary: Some OSDictionary Tests failed\n"));
706}
707
708void testIterator()
709{
710    bool res = true;
711    void *spaceCheck;
712    OSObject *cache[numStrCache];
713    OSString *str = 0;
714    const OSSymbol *symCache[numStrCache], *sym;
715    OSDictionary *dict;
716    OSSet *set;
717    OSArray *array, *bigReturn;
718    OSCollectionIterator *iter1, *iter2;
719    int i, numSymbols, count1, count2, count3;
720
721    // Setup symbol and string pools
722    for (i = 0, numSymbols = 0; i < numStrCache; i++) {
723        sym = OSSymbol::withCStringNoCopy(strCache[i]);
724        if (1 == sym->getRetainCount()) {
725            cache[numSymbols] = OSString::withCStringNoCopy(strCache[i]);
726            symCache[numSymbols] = sym;
727            numSymbols++;
728        }
729        else
730            sym->release();
731    }
732
733    // Test the array iterator
734    spaceCheck = checkPointSpace();
735    iter1 = iter2 = 0;
736    array = OSArray::withCapacity(numSymbols);
737    TEST_ASSERT('I', "1a", array);
738    if (array) {
739        count1 = count2 = 0;
740        for (i = numSymbols; --i >= 0; )
741            count1 += array->setObject(cache[i], 0);
742        TEST_ASSERT('I', "1b", count1 == numSymbols);
743
744        iter1 = OSCollectionIterator::withCollection(array);
745        iter2 = OSCollectionIterator::withCollection(array);
746    }
747    TEST_ASSERT('I', "1c", iter1);
748    TEST_ASSERT('I', "1d", iter2);
749    if (iter1 && iter2) {
750        count1 = count2 = count3 = 0;
751        for (i = 0; (str = (IOString *) iter1->getNextObject()); i++) {
752            bigReturn = iter2->nextEntries();
753            count1 += (bigReturn->getCount() == 1);
754            count2 += (cache[i] == bigReturn->getObject(0));
755            count3 += (cache[i] == str);
756        }
757        TEST_ASSERT('I', "1e", count1 == numSymbols);
758        TEST_ASSERT('I', "1f", count2 == numSymbols);
759        TEST_ASSERT('I', "1g", count3 == numSymbols);
760        TEST_ASSERT('I', "1h", iter1->valid());
761        TEST_ASSERT('I', "1i", iter2->valid());
762
763        iter1->reset();
764        str = (OSString *) array->__takeObject(0);
765        array->setObject(str, 0);
766        str->release();
767        TEST_ASSERT('I', "1j", !iter1->getNextObject());
768        TEST_ASSERT('I', "1k", !iter1->valid());
769
770        iter1->reset();
771        count1 = count2 = count3 = 0;
772        for (i = 0; ; i++) {
773            if (i & 1)
774                str = (OSString *) iter1->getNextObject();
775            else if ( (bigReturn = iter1->nextEntries()) )
776                str = (OSString *) bigReturn->getObject(0);
777            else
778                str = 0;
779
780            if (!str)
781                break;
782            count1 += (cache[i] == str);
783        }
784        TEST_ASSERT('I', "1l", count1 == numSymbols);
785        TEST_ASSERT('I', "1m", i == numSymbols);
786        TEST_ASSERT('I', "1n", iter1->valid());
787
788        TEST_ASSERT('I', "1o", 3 == array->getRetainCount());
789        array->release();
790    }
791
792    if (iter1) iter1->release();
793    if (iter2) iter2->release();
794    res = res && checkSpace("(I)1", spaceCheck, 0);
795
796    // Test the set iterator
797    spaceCheck = checkPointSpace();
798    iter1 = 0;
799    set = OSSet::withCapacity(numSymbols);
800    TEST_ASSERT('I', "2a", set);
801    if (set) {
802        count1 = count2 = 0;
803        for (i = 0; i < numSymbols; i++)
804            count1 += set->setObject(cache[i]);
805        TEST_ASSERT('I', "2b", count1 == numSymbols);
806
807        iter1 = OSCollectionIterator::withCollection(set);
808        iter2 = OSCollectionIterator::withCollection(set);
809    }
810    TEST_ASSERT('I', "2c", iter1);
811    TEST_ASSERT('I', "2d", iter2);
812    if (iter1 && iter2) {
813        count1 = count2 = count3 = 0;
814        for (i = 0; (str = (IOString *) iter1->getNextObject()); i++) {
815            bigReturn = iter2->nextEntries();
816            count1 += (bigReturn->getCount() == 1);
817            count2 += (cache[i] == bigReturn->getObject(0));
818            count3 += (cache[i] == str);
819        }
820        TEST_ASSERT('I', "2e", count1 == numSymbols);
821        TEST_ASSERT('I', "2f", count2 == numSymbols);
822        TEST_ASSERT('I', "2g", count3 == numSymbols);
823        TEST_ASSERT('I', "2h", iter1->valid());
824        TEST_ASSERT('I', "2i", iter2->valid());
825
826        iter1->reset();
827        count1 = count2 = count3 = 0;
828        for (i = 0; ; i++) {
829            if (i & 1)
830                str = (OSString *) iter1->getNextObject();
831            else if ( (bigReturn = iter1->nextEntries()) )
832                str = (OSString *) bigReturn->getObject(0);
833            else
834                str = 0;
835
836            if (!str)
837                break;
838            count1 += (cache[i] == str);
839        }
840        TEST_ASSERT('I', "2l", count1 == numSymbols);
841        TEST_ASSERT('I', "2m", i == numSymbols);
842        TEST_ASSERT('I', "2n", iter1->valid());
843
844        iter1->reset();
845        str = (OSString *) set->getAnyObject();
846        (void) set->__takeObject(str);
847        set->setObject(str);
848        str->release();
849        TEST_ASSERT('I', "2j", !iter1->getNextObject());
850        TEST_ASSERT('I', "2k", !iter1->valid());
851
852        TEST_ASSERT('I', "2o", 3 == set->getRetainCount());
853        set->release();
854    }
855
856    if (iter1) iter1->release();
857    if (iter2) iter2->release();
858    res = res && checkSpace("(I)2", spaceCheck, 0);
859
860    // Test the dictionary iterator
861    spaceCheck = checkPointSpace();
862    iter1 = 0;
863    dict = OSDictionary::withCapacity(numSymbols);
864    TEST_ASSERT('I', "3a", dict);
865    if (dict) {
866        count1 = count2 = 0;
867        for (i = 0; i < numSymbols; i++)
868            count1 += (0 != dict->setObject(cache[i], symCache[i]));
869        TEST_ASSERT('I', "3b", count1 == numSymbols);
870
871        iter1 = OSCollectionIterator::withCollection(dict);
872        iter2 = OSCollectionIterator::withCollection(dict);
873    }
874    TEST_ASSERT('I', "3c", iter1);
875    TEST_ASSERT('I', "3d", iter2);
876    if (iter1 && iter2) {
877        count1 = count2 = count3 = 0;
878        for (i = 0; (sym = (const IOSymbol *) iter1->getNextObject()); i++) {
879            bigReturn = iter2->nextEntries();
880            count1 += (bigReturn->getCount() == 2);
881            count2 += (cache[i] == bigReturn->getObject(1));
882            count3 += (symCache[i] == sym);
883        }
884        TEST_ASSERT('I', "3e", count1 == numSymbols);
885        TEST_ASSERT('I', "3f", count2 == numSymbols);
886        TEST_ASSERT('I', "3g", count3 == numSymbols);
887        TEST_ASSERT('I', "3h", iter1->valid());
888        TEST_ASSERT('I', "3i", iter2->valid());
889
890        iter1->reset();
891        count1 = count2 = count3 = 0;
892        i = 0;
893        for (i = 0; ; i++) {
894            if (i & 1) {
895                sym = (const OSSymbol *) iter1->getNextObject();
896                str = 0;
897            }
898            else if ( (bigReturn = iter1->nextEntries()) ) {
899                sym = (const OSSymbol *) bigReturn->getObject(0);
900                str = (OSString *) bigReturn->getObject(1);
901            }
902            else
903                sym = 0;
904
905            if (!sym)
906                break;
907
908            count1 += (symCache[i] == sym);
909            count2 += (!str || cache[i] == str);
910        }
911        TEST_ASSERT('I', "3l", count1 == numSymbols);
912        TEST_ASSERT('I', "3m", count2 == numSymbols);
913        TEST_ASSERT('I', "3n", i == numSymbols);
914        TEST_ASSERT('I', "3o", iter1->valid());
915
916        iter1->reset();
917        str = (OSString *) dict->__takeObject(symCache[numSymbols-1]);
918        dict->setObject(str, symCache[numSymbols-1]);
919        str->release();
920        TEST_ASSERT('I', "3j", !iter1->getNextObject());
921        TEST_ASSERT('I', "3k", !iter1->valid());
922
923        TEST_ASSERT('I', "3p", 3 == dict->getRetainCount());
924        dict->release();
925    }
926
927    if (iter1) iter1->release();
928    if (iter2) iter2->release();
929    res = res && checkSpace("(I)3", spaceCheck, 0);
930
931    count1 = count2 = count3 = 0;
932    for (i = 0; i < numSymbols; i++) {
933        count1 += (1 == cache[i]->getRetainCount());
934        count2 += (1 == symCache[i]->getRetainCount());
935        cache[i]->release();
936        symCache[i]->release();
937    }
938    TEST_ASSERT('I', "4a", count1 == numSymbols);
939    TEST_ASSERT('I', "4b", count2 == numSymbols);
940
941    if (res)
942        verPrintf(("testIterator: All OSCollectionIterator Tests passed\n"));
943    else
944        logPrintf(("testIterator: Some OSCollectionIterator Tests failed\n"));
945}
946
947#endif /* DEBUG */
948