1/*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20//
21//  cfdata.m
22//  Copyright (c) 2008-2001 Apple. All rights reserved.
23//
24
25
26#import <CoreFoundation/CFData.h>
27#import "BlackBoxTest.h"
28
29@interface _CFDataTestObject : NSObject {
30    __strong CFDataRef  subject;
31    __strong CFMutableDataRef mutableSubject;
32
33    __strong CFDataRef subjectCopy;
34    __strong CFMutableDataRef mutableSubjectCopy;
35
36    __strong CFMutableDataRef subjectMutableCopy;
37    __strong CFMutableDataRef mutableSubjectMutableCopy;
38
39}
40
41- init;
42
43@end
44
45@interface _CFDataTestTestObject : _CFDataTestObject {
46    bool shouldDealloc;
47    __strong void *backingData;
48}
49@end
50
51
52@implementation _CFDataTestObject
53- (void) makeCopies {
54    CFIndex size = 32*sizeof(void *);
55    subjectCopy         = CFDataCreateCopy(NULL, subject);
56    mutableSubjectCopy  = CFDataCreateMutableCopy(NULL, size, mutableSubject);
57
58    subjectMutableCopy          = CFDataCreateMutableCopy(NULL, size, subject);
59    mutableSubjectMutableCopy   = CFDataCreateMutableCopy(NULL, size, mutableSubject);
60}
61
62- (void)makeCollectable {
63    CFMakeCollectable(subjectCopy);
64    CFMakeCollectable(mutableSubjectCopy);
65    CFMakeCollectable(subjectMutableCopy);
66    CFMakeCollectable(mutableSubjectMutableCopy);
67    CFMakeCollectable(subject);
68    CFMakeCollectable(mutableSubject);
69}
70
71- (void)grow {
72    CFIndex size = 32*sizeof(void *);
73    CFDataSetLength(mutableSubjectCopy, 2*size);
74    CFDataSetLength(subjectMutableCopy, 2*size);
75    CFDataSetLength(mutableSubjectMutableCopy, 2*size);
76    CFDataSetLength(mutableSubject, 2*size);
77}
78
79- (void)dealloc {
80    CFRelease(subjectCopy);
81    CFRelease(mutableSubjectCopy);
82    CFRelease(subjectMutableCopy);
83    CFRelease(mutableSubjectMutableCopy);
84    CFRelease(subject);
85    CFRelease(mutableSubject);
86    [super dealloc];
87}
88
89- init {
90    id buffer[32];
91    for (int i = 0; i < 32; ++i)
92        buffer[i] = self;
93    CFIndex size = sizeof(void *)*32;
94    if (!subject) subject         = CFDataCreate(NULL, (uint8_t *)buffer, size);
95    mutableSubject  = CFDataCreateMutable(NULL, size);
96    const UInt8 *bytes  = CFDataGetBytePtr((CFMutableDataRef)mutableSubject);
97    memcpy((void *)bytes, buffer, size);
98
99    [self makeCopies];
100    [self makeCollectable];
101    [self grow];
102    return self;
103}
104
105
106static bool allSame(void *value, void **items, int nitems) {
107    for (int i = 0; i < nitems; ++i)
108        if (items[i] != value) return false;
109    return true;
110}
111
112- (void)test {
113    bool result = true;
114    CFIndex count = CFDataGetLength(subject)/sizeof(void *);
115    result = result && allSame(self, (void **)CFDataGetBytePtr(subject), count);
116    result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubject), count);
117    result = result && allSame(self, (void **)CFDataGetBytePtr(subjectCopy), count);
118    result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubjectCopy), count);
119    result = result && allSame(self, (void **)CFDataGetBytePtr(subjectMutableCopy), count);
120    result = result && allSame(self, (void **)CFDataGetBytePtr(mutableSubjectMutableCopy), count);
121    if (!result) {
122        [[TestCase currentTestCase] fail:@"data changed!"];
123    }
124}
125
126@end
127
128@implementation _CFDataTestTestObject
129
130- (void)allocateBacking:(CFIndex)size {
131    backingData = malloc_zone_malloc((malloc_zone_t*)NSDefaultMallocZone(), size);
132}
133
134- init {
135    id buffer[32];
136    for (int i = 0; i < 32; ++i)
137        buffer[i] = self;
138    CFIndex size = sizeof(void *)*32;
139    [self allocateBacking:size];
140
141    memcpy(backingData, buffer, size);
142    subject         = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, NULL);
143    //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p\n", backingData, subject);
144    return [super init];
145}
146- initExplicit {
147    id buffer[32];
148    for (int i = 0; i < 32; ++i)
149        buffer[i] = self;
150    CFIndex size = sizeof(void *)*32;
151    [self allocateBacking:size];
152    memcpy(backingData, buffer, size);
153    // explicitly use kCFAllocatorDefault
154    subject         = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, kCFAllocatorDefault);
155    //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p\n", backingData, subject);
156    return [super init];
157}
158- initOwned {
159    id buffer[32];
160    for (int i = 0; i < 32; ++i)
161        buffer[i] = self;
162    CFIndex size = sizeof(void *)*32;
163    [self allocateBacking:size];
164    memcpy(backingData, buffer, size);
165    // explicitly use kCFAllocatorNull to say that the memory is owned elsewhere
166    subject         = CFDataCreateWithBytesNoCopy(NULL, (const UInt8*)backingData, size, kCFAllocatorNull);
167    shouldDealloc = true;
168    //if ([NSGarbageCollector defaultCollector]) printf("backing data %p held by %p, will dealloc\n", backingData, subject);
169    return [super init];
170}
171- (void) dealloc {
172    if (shouldDealloc) free(backingData);
173    [super dealloc];
174}
175- (void) finalize {
176    if (shouldDealloc) free(backingData);
177    [super finalize];
178}
179@end
180
181#define LOOPS 10
182
183@interface CFDataTest : BlackBoxTest
184@end
185
186@implementation CFDataTest
187
188- (void)testLoop
189{
190    NSMutableArray *array = [[NSMutableArray alloc] init];
191
192    for (int i = 0; i < LOOPS; ++i) {
193        _CFDataTestObject *to = [[_CFDataTestObject alloc] init];
194        [array addObject:to];
195        [to release];
196    }
197    for (int i = 0; i < LOOPS; ++i) {
198        _CFDataTestTestObject *to = [[_CFDataTestTestObject alloc] init];
199        [array addObject:to];
200        [to release];
201    }
202
203    for (int i = 0; i < LOOPS; ++i) {
204        _CFDataTestTestObject *to = [[_CFDataTestTestObject alloc] initExplicit];
205        [array addObject:to];
206        [to release];
207    }
208
209    for (int i = 0; i < LOOPS; ++i) {
210        _CFDataTestTestObject *to = [[_CFDataTestTestObject alloc] initOwned];
211        [array addObject:to];
212        [to release];
213    }
214
215    [array release];
216}
217
218- (void)performTest {
219    for (int i = 0; i < (1+LOOPS); ++i) {   // just enough for GC to not find things on the stack
220        [self testLoop];
221    }
222    [self clearStack];
223    [self requestFullCollectionWithCompletionCallback:^{
224        [self passed];
225        [self testFinished];
226    }];
227}
228
229@end