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++/OSData.h>
32#include <libkern/c++/OSString.h>
33#include <libkern/c++/OSSymbol.h>
34
35static const char testC00[] = "The quick brown fox jumps over the lazy dog.  ";
36static const char testC01[] = "The quick brown fox ";
37static const char testC02[] = "jumps over the ";
38static const char testC03[] = "lazy dog.  \n";
39static const char testC04[] = "The ";
40static const char testC05[] = "quick ";
41static const char testC06[] = "brown ";
42static const char testC07[] = "fox ";
43static const char testC08[] = "jumps ";
44static const char testC09[] = "over ";
45static const char testC10[] = "the ";
46static const char testC11[] = "lazy ";
47static const char testC12[] = "dog.  \n";
48static const char testC13[] = "Now is the time for all good "
49                               "men to come to the aid of the party  \n";
50static const char testC14[] = "Now is the time for ";
51static const char testC15[] = "all good men to come ";
52static const char testC16[] = "to the aid of the party  \n";
53static const char testC17[] = "Now ";
54static const char testC18[] = "is ";
55static const char testC19[] = "the ";
56static const char testC20[] = "time ";
57static const char testC21[] = "for ";
58static const char testC22[] = "all ";
59static const char testC23[] = "good ";
60static const char testC24[] = "men ";
61static const char testC25[] = "to ";
62static const char testC26[] = "come ";
63static const char testC27[] = "to ";
64static const char testC28[] = "the ";
65static const char testC29[] = "aid ";
66static const char testC30[] = "of ";
67static const char testC31[] = "the ";
68static const char testC32[] = "party.  \n";
69static const char testC33[] = "Frank Burns eats worms.  \n";
70static const char testC34[] = "Frank Burns ";
71static const char testC35[] = "eats worms.  \n";
72static const char testC36[] = "Frank ";
73static const char testC37[] = "Burns ";
74static const char testC38[] = "eats ";
75static const char testC39[] = "worms.  \n";
76static const char testC40[] = "Tired eyes?  Stiff neck?  Tight shoulders?  "
77                              "Aching back?  The right moves can help "
78                              "prevent these kinds of problem.  ";
79static const char testC41[] = "Tired eyes?  Stiff neck?  ";
80static const char testC42[] = "Tight shoulders?  Aching back?  ";
81static const char testC43[] = "The right moves can help prevent ";
82static const char testC44[] = "these kinds of problem.  ";
83static const char testC45[] = "Tired ";
84static const char testC46[] = "eyes?  ";
85static const char testC47[] = "Stiff ";
86static const char testC48[] = "neck?  ";
87static const char testC49[] = "Tight ";
88static const char testC50[] = "shoulders?  ";
89static const char testC51[] = "Aching ";
90static const char testC52[] = "back?  ";
91static const char testC53[] = "The ";
92static const char testC54[] = "right ";
93static const char testC55[] = "moves ";
94static const char testC56[] = "can ";
95static const char testC57[] = "help ";
96static const char testC58[] = "prevent ";
97static const char testC59[] = "these ";
98static const char testC60[] = "kinds ";
99static const char testC61[] = "of ";
100static const char testC62[] = "problem.  ";
101
102const char *strCache[] = {
103    testC00, testC01, testC02, testC03, testC04, testC05, testC06, testC07,
104    testC08, testC09, testC10, testC11, testC12, testC13, testC14, testC15,
105    testC16, testC17, testC18, testC19, testC20, testC21, testC22, testC23,
106    testC24, testC25, testC26, testC27, testC28, testC29, testC30, testC31,
107    testC32, testC33, testC34, testC35, testC36, testC37, testC38, testC39,
108    testC40, testC41, testC42, testC43, testC44, testC45, testC46, testC47,
109    testC48, testC49, testC50, testC51, testC52, testC53, testC54, testC55,
110    testC56, testC57, testC58, testC59, testC60, testC61, testC62,
111};
112const int numStrCache = ((int) (sizeof(strCache)/sizeof(strCache[0])));
113
114void testData()
115{
116#define DATA_SIZE_1	 256
117#define DATA_SIZE_2	 512
118#define DATA_SIZE_3	1024
119#define DATA_SIZE_4	8192
120
121    OSData *test1, *test2, *test3;
122    void *spaceCheck;
123    unsigned int len;
124    unsigned int i;
125    bool res = true;
126    unsigned short testData[DATA_SIZE_4/sizeof(short)], *cp;
127
128    // very first test initialises the OSMetaClass cache.
129    test1 = OSData::withCapacity(DATA_SIZE_1);
130    TEST_ASSERT('d', "0a", test1);
131    if (test1)
132        test1->release();
133
134    for (i = 0; i < sizeof(testData)/sizeof(short); i++)
135        testData[i] = (unsigned short) i;
136
137    // Check empty data allocation
138    spaceCheck = checkPointSpace();
139    test1 = OSData::withCapacity(DATA_SIZE_1);
140    TEST_ASSERT('d', "1a", test1);
141    if (test1) {
142        TEST_ASSERT('d', "1b", !test1->getLength());
143        TEST_ASSERT('d', "1c", test1->getCapacity() == DATA_SIZE_1);
144        TEST_ASSERT('d', "1d", !test1->getBytesNoCopy());
145        TEST_ASSERT('d', "1e", !test1->getBytesNoCopy(10, DATA_SIZE_1 - 10));
146        TEST_ASSERT('d', "1f", test1->appendBytes(spaceCheck, 0));
147        TEST_ASSERT('d', "1g", !test1->getLength());
148        TEST_ASSERT('d', "1h", test1->getCapacity() == DATA_SIZE_1);
149        TEST_ASSERT('d', "1i", !test1->getBytesNoCopy());
150        test1->release();
151    }
152    res = res && checkSpace("(d)1", spaceCheck, 0);
153
154    // Check appending to empty data allocation
155    spaceCheck = checkPointSpace();
156    test1 = OSData::withCapacity(DATA_SIZE_1);
157    TEST_ASSERT('d', "2a", test1);
158    if (test1) {
159        TEST_ASSERT('d', "2b", !test1->getLength());
160        TEST_ASSERT('d', "2c", !test1->getBytesNoCopy());
161        TEST_ASSERT('d', "2d", test1->appendBytes(testData, DATA_SIZE_1));
162        TEST_ASSERT('d', "2e", test1->getLength() == DATA_SIZE_1);
163        TEST_ASSERT('d', "2f", test1->getBytesNoCopy());
164        cp = (unsigned short *) test1->getBytesNoCopy();
165        for (i = 0; cp && i < (DATA_SIZE_1/sizeof(short)); i++) {
166            TEST_ASSERT('d', "2g", *cp++ == testData[i]);
167            if (*cp != testData[i])
168                break;
169        }
170        TEST_ASSERT('d', "2h", test1->getBytesNoCopy(10, DATA_SIZE_1-10));
171        cp = (unsigned short *) test1->getBytesNoCopy(10, DATA_SIZE_1 - 10);
172        for (i = 5; cp && i < (DATA_SIZE_1/sizeof(short)) - 5; i++) {
173            TEST_ASSERT('d', "2i", *cp++ == testData[i]);
174            if (*cp != testData[i])
175                break;
176        }
177        TEST_ASSERT('d', "2j", test1->isEqualTo(testData, DATA_SIZE_1));
178        test1->release();
179    }
180    res = res && checkSpace("(d)2", spaceCheck, 0);
181
182    // Check data allocation from some constant data
183    spaceCheck = checkPointSpace();
184    test1 = OSData::withBytes(testData, sizeof(testData));
185    TEST_ASSERT('d', "3a", test1);
186    if (test1) {
187        TEST_ASSERT('d', "3b", test1->getLength() == sizeof(testData));
188        TEST_ASSERT('d', "3c", test1->getCapacity() == sizeof(testData));
189        TEST_ASSERT('d', "3d", test1->getBytesNoCopy());
190        TEST_ASSERT('d', "3e", test1->getBytesNoCopy(10, sizeof(testData)-10));
191        TEST_ASSERT('d', "3f", test1->appendBytes(spaceCheck, 0));
192        TEST_ASSERT('d', "3g", test1->getLength() == sizeof(testData));
193        TEST_ASSERT('d', "3h", test1->getCapacity() == sizeof(testData));
194        TEST_ASSERT('d', "3i", test1->getBytesNoCopy());
195        TEST_ASSERT('d', "3j", test1->getBytesNoCopy(10, sizeof(testData)-10));
196        TEST_ASSERT('d', "3k", !test1->appendBytes(testData, 10));
197        test1->release();
198    }
199    res = res && checkSpace("(d)3", spaceCheck, 0);
200
201    // Check and continious addition of more data
202    spaceCheck = checkPointSpace();
203    test1 = OSData::withCapacity(DATA_SIZE_4);
204    test2 = OSData::withBytesNoCopy(testData, DATA_SIZE_3);
205    len = DATA_SIZE_3;
206    TEST_ASSERT('d', "4a", (test1 && test2));
207    if (test1 && test2) {
208        TEST_ASSERT('d', "4b", !test1->getLength());
209        for (i = 0; i < DATA_SIZE_4; i += DATA_SIZE_3)
210            TEST_ASSERT('d', "4c", test1->appendBytes(test2));
211        TEST_ASSERT('d', "4d", !test1->appendBytes(test2));
212        for (i = 0; i < DATA_SIZE_4; i += DATA_SIZE_3) {
213
214            TEST_ASSERT('d', "4e", test2->isEqualTo(
215                                        test1->getBytesNoCopy(i, DATA_SIZE_3),
216                                        DATA_SIZE_3));
217
218            test3 = OSData::withData(test1, i, DATA_SIZE_3);
219            TEST_ASSERT('d', "4f", test3);
220            if (test3) {
221                TEST_ASSERT('d', "4g", test2->isEqualTo(test3));
222                test3->release();
223            }
224
225            test3 = OSData::withData(test1, i, len);
226            TEST_ASSERT('d', "4i", test3);
227            if (test3) {
228                TEST_ASSERT('d', "4j", test2->isEqualTo(test3));
229                test3->release();
230            }
231        }
232        test1->release();
233        test2->release();
234    }
235    res = res && checkSpace("(d)3", spaceCheck, 0);
236
237    if (res)
238        verPrintf(("testData: All OSData Tests passed\n"));
239    else
240        logPrintf(("testData: Some OSData Tests failed\n"));
241#undef DATA_SIZE_4
242#undef DATA_SIZE_3
243#undef DATA_SIZE_2
244#undef DATA_SIZE_1
245}
246
247void testString()
248{
249    OSString *test1, *test2;
250    void *spaceCheck;
251    int i;
252    char c;
253    bool res = true;
254
255    // very first test initialises the OSMetaClass cache.
256    test1 = OSString::withCStringNoCopy(testC00);
257    TEST_ASSERT('s', "0a", test1);
258    if (test1)
259        test1->release();
260
261    // Check c string allocation
262    spaceCheck = checkPointSpace();
263    test1 = OSString::withCString(testC00);
264    TEST_ASSERT('s', "1a", test1);
265    TEST_ASSERT('s', "1b", testC00 != test1->getCStringNoCopy());
266    TEST_ASSERT('s', "1c", strcmp(testC00, test1->getCStringNoCopy()) == 0);
267    TEST_ASSERT('s', "1d", strlen(testC00) == test1->getLength());
268    TEST_ASSERT('s', "1e", test1->isEqualTo(testC00));
269    TEST_ASSERT('s', "1f", !test1->isEqualTo(testC01));
270    if (test1) test1->release();
271    res = res && checkSpace("(s)1", spaceCheck, 0);
272
273    // Check c string no allocation
274    spaceCheck = checkPointSpace();
275    test1 = OSString::withCStringNoCopy(testC00);
276    TEST_ASSERT('s', "2a", test1);
277    TEST_ASSERT('s', "2b", testC00 == test1->getCStringNoCopy());
278    if (test1) test1->release();
279    res = res && checkSpace("(s)2", spaceCheck, 0);
280
281    // Check string from other string generation
282    spaceCheck = checkPointSpace();
283    test1 = OSString::withCStringNoCopy(testC00);
284    TEST_ASSERT('s', "3a", test1);
285    test2 = OSString::withString(test1);
286    TEST_ASSERT('s', "3b", test2);
287    TEST_ASSERT('s', "3c", test1 != test2);
288    TEST_ASSERT('s', "3d", test1->isEqualTo(test2));
289    if (test1) test1->release();
290    if (test2) test2->release();
291    res = res && checkSpace("(s)3", spaceCheck, 0);
292
293    // Check string comparison functionality no copy
294    spaceCheck = checkPointSpace();
295    test1 = OSString::withCStringNoCopy(testC00);
296    test2 = OSString::withCStringNoCopy(testC01);
297    TEST_ASSERT('s', "4a", test1 && test2);
298    TEST_ASSERT('s', "4b", !test1->isEqualTo(test2));
299    TEST_ASSERT('s', "4c", !test1->isEqualTo(testC01));
300    TEST_ASSERT('s', "4d", test1->isEqualTo(testC00));
301    if (test1) test1->release();
302    if (test2) test2->release();
303    res = res && checkSpace("(s)4", spaceCheck, 0);
304
305    // Check string comparison functionality with copy
306    spaceCheck = checkPointSpace();
307    test1 = OSString::withCString(testC00);
308    test2 = OSString::withCString(testC01);
309    TEST_ASSERT('s', "5a", test1 && test2);
310    TEST_ASSERT('s', "5b", !test1->isEqualTo(test2));
311    TEST_ASSERT('s', "5c", !test1->isEqualTo(testC01));
312    TEST_ASSERT('s', "5d", test1->isEqualTo(testC00));
313    if (test1) test1->release();
314    if (test2) test2->release();
315    res = res && checkSpace("(s)5", spaceCheck, 0);
316
317    // Check string inplace modifications
318    spaceCheck = checkPointSpace();
319    test1 = OSString::withCString(testC00);
320    TEST_ASSERT('s', "6a", test1);
321    for (i = 0; (c = test1->getChar(i)); i++)
322        if (c != testC00[i]) {
323            verPrintf(("testString(s) test 6b failed\n")); res = false;
324            break;
325        }
326    TEST_ASSERT('s', "6c", !c);
327    TEST_ASSERT('s', "6d", test1->setChar(' ', 0));
328    TEST_ASSERT('s', "6e", !test1->isEqualTo(testC00));
329    TEST_ASSERT('s', "6f", test1->setChar('T', 0));
330    TEST_ASSERT('s', "6g", !test1->setChar(' ', sizeof(testC00)));
331    TEST_ASSERT('s', "6h", test1->isEqualTo(testC00));
332    if (test1) test1->release();
333    res = res && checkSpace("(s)6", spaceCheck, 0);
334
335    // Check const string fail inplace modifications
336    spaceCheck = checkPointSpace();
337    test1 = OSString::withCStringNoCopy(testC00);
338    TEST_ASSERT('s', "7a", test1);
339    for (i = 0; (c = test1->getChar(i)); i++)
340        if (c != testC00[i]) {
341            verPrintf(("testString(s) test 7b failed\n")); res = false;
342            break;
343        }
344    TEST_ASSERT('s', "7c", !c);
345    TEST_ASSERT('s', "7d", !test1->setChar(' ', 0));
346    TEST_ASSERT('s', "7e", test1->isEqualTo(testC00));
347    TEST_ASSERT('s', "7f", !test1->setChar(' ', sizeof(testC00)));
348    TEST_ASSERT('s', "7g", test1->isEqualTo(testC00));
349    if (test1) test1->release();
350    res = res && checkSpace("(s)7", spaceCheck, 0);
351
352    if (res)
353        verPrintf(("testString: All OSString Tests passed\n"));
354    else
355        logPrintf(("testString: Some OSString Tests failed\n"));
356}
357
358void testSymbol()
359{
360    bool res = true;
361    int i, j;
362    int countDups;
363    const OSSymbol *cache[numStrCache];
364    void *spaceCheck;
365
366    // very first test initialises the OSMetaClass cache.
367    cache[0] = IOSymbol::withCStringNoCopy(testC00);
368    TEST_ASSERT('u', "0a", cache[0]);
369    if (cache[0])
370        cache[0]->release();
371
372    spaceCheck = checkPointSpace();
373
374    // Setup the symbol cache, make sure it grows the symbol unique'ing
375    // hash table.  Also determine that the symbol is created ok and that
376    // it is indeed equal to the creating cString by strcmp.
377    for (i = 0; i < numStrCache; i++) {
378        cache[i] = OSSymbol::withCStringNoCopy(strCache[i]);
379        if (!cache[i]) {
380            verPrintf(("testSymbol(u) test 1a%d failed\n", i)); res = false;
381        }
382        else if (!cache[i]->isEqualTo(strCache[i])) {
383            verPrintf(("testSymbol(u) test 1b%d failed\n", i)); res = false;
384        }
385    }
386
387    // The strCache does have some duplicates in it, mostly 'the'.  Make
388    // sure that we wind them and that different cache entries really are
389    // different by strcmp.  Fundamental to OSSymbol semantics.
390    countDups = 0;
391    for (i = 0; i < numStrCache; i++)
392        for (j = i+1; j < numStrCache; j++) {
393            if (cache[i] != cache[j] && cache[i]->isEqualTo(cache[j])) {
394                verPrintf(("testSymbol(u) test 2a%d,%d failed\n", i, j));
395                res = false;
396            }
397            else if (cache[i] == cache[j]) {
398                if (cache[i]->getRetainCount() == 1) {
399                    verPrintf(("testSymbol(u) test 2b%d,%d failed\n", i, j));
400                    res = false;
401                }
402                countDups++;
403            }
404        }
405    TEST_ASSERT('u', "2c", countDups);
406
407    // Clear out the cache and check that the unique'ing hashtable has grown
408    for (i = 0; i < numStrCache; i++) {
409        if (cache[i]) {
410            cache[i]->release();
411            cache[i] = 0;
412        }
413    }
414    // As of 1998-11-17 the hash growth is 364.
415    res = res && checkSpace("(u)3", spaceCheck, 972);
416    logSpace();
417
418    // Check for leaks by repeating the cacheing and freeing
419    spaceCheck = checkPointSpace();
420    for (i = 0; i < numStrCache; i++)
421        cache[i] = OSSymbol::withCString(strCache[i]);
422    for (i = 0; i < numStrCache; i++) {
423        if (cache[i]) {
424            cache[i]->release();
425            cache[i] = 0;
426        }
427    }
428    res = res && checkSpace("(u)4", spaceCheck, 0);
429
430    // Check that the OSString based symbol constructors work
431    // and that they don't leak, and finally double check that while
432    // the cache is active the symbol semantics still work.
433    spaceCheck = checkPointSpace();
434    for (i = 0; i < numStrCache; i++) {
435        OSString *tmpStr;
436
437        tmpStr = (i&1)
438               ? OSString::withCString(strCache[i])
439               : OSString::withCStringNoCopy(strCache[i]);
440        if (tmpStr) {
441            cache[i] = OSSymbol::withString(tmpStr);
442            if (!cache[i]) {
443                verPrintf(("testSymbol(u) test 5a%d failed\n", i));
444                res = false;
445            }
446            tmpStr->release();
447        }
448    }
449
450    for (i = 0; i < numStrCache; i++) {
451        if (cache[i]) {
452            const OSSymbol *tmpSymb;
453
454            tmpSymb = OSSymbol::withCStringNoCopy(strCache[i]);
455            if (cache[i] != tmpSymb) {
456                verPrintf(("testSymbol(u) test 5b%d failed\n", i));
457                res = false;
458            }
459            tmpSymb->release();
460            cache[i]->release();
461            cache[i] = 0;
462        }
463        else {
464            verPrintf(("testSymbol(u) test 5c%d failed\n", i));
465            res = false;
466        }
467    }
468    res = res && checkSpace("(u)5", spaceCheck, 0);
469
470    if (res)
471        verPrintf(("testSymbol: All OSSymbol Tests passed\n"));
472    else
473        logPrintf(("testSymbol: Some OSSymbol Tests failed\n"));
474}
475
476#endif /* DEBUG */
477