xref: /xnu-11215/iokit/Tests/TestCollections.cpp (revision a3bb9fcc)
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 
38 void 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 
276 void 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 
481 void 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 
708 void 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