Source

SOExtendedAttributes / UnitTests / SOExtendedAttributes_UnitTests.m

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
//
//  SOExtendedAttributes_UnitTests.m
//  SOExtendedAttributes.UnitTests
//
//  Created by William Garrison on 1/23/12.
//  Copyright (c) 2012 Standard Orbit Software, LLC. All rights reserved.
//

#import "NSURL+SOExtendedAttributes.h"
#import "SOUsefulFunctions.h"
#include <sys/xattr.h>

@interface SOExtendedAttributes_UnitTests : SenTestCase
{
    NSURL *targetURL;
}
@end

@implementation SOExtendedAttributes_UnitTests


#pragma mark
#pragma mark Fixture

- (BOOL) createTestURLForTest:(SEL)testSelector
{
    BOOL didCreate = NO;
    
    targetURL = [NSURL fileURLWithPathComponents:[NSArray arrayWithObjects:NSTemporaryDirectory(), NSStringFromSelector(testSelector), SOGeneratedUUID(), nil]];
    
    if (targetURL)
    {
        /* First create the intermediate parent directory */
        didCreate = [[NSFileManager defaultManager] createDirectoryAtURL:[targetURL URLByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
        
        /* Then try creating an empty test file. */
        if (didCreate) {
            didCreate = [[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil];
        }
    }
    
    return didCreate;
}


- (void) setUp
{
    [super setUp];
}

- (void) tearDown
{
    if (targetURL) {
        if ( ![[NSFileManager defaultManager] removeItemAtPath:[targetURL path] error:nil]) {
            NSLog (@"Couldn't cleanup test file: %@", targetURL);
        }
    }
    
    [super tearDown];
}

#pragma mark - Error Reporting Tests

- (void) testCollectedErrrors
{
    /* Test that underlying errors generated from xattr are collected and reported properly. */
    
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    /* Create a test file */
    

    
    NSString *excessivelyLongName1 = @"Loremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua.Utenimadminimveniamwangchung";
    NSString *excessivelyLongName2 = @"Loremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua.Utenimadminimveniamwangchungscooby";
    NSString *excessivelyLongName3 = @"Loremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua.Utenimadminimveniamwangchungshaggy";
    
    NSDictionary *badlyNamedAttribs = [NSDictionary dictionaryWithObjectsAndKeys:
                                       @"LexLuthor" ,excessivelyLongName1,
                                       @"Magneto", excessivelyLongName2,
                                       @"KhanNoonianSingh", excessivelyLongName3,
                                       nil
                                       ];
    
    BOOL didAdd = [targetURL setExtendedAttributes:badlyNamedAttribs error:&error];
    
    NSLog (@"error: %@", error);
    
    STAssertFalse (didAdd, @"Expected failure");
    STAssertNotNil (error, @"Expected an error report");
    STAssertTrue ( [[[error userInfo] objectForKey:SOUnderlyingErrorsKey] isKindOfClass:[NSArray class]], @"Expected array of collected errors.");
    STAssertTrue ( [[[error userInfo] objectForKey:SOUnderlyingErrorsKey] count] > 0, @"Expected multiple errors to be collected into an array.");
}

#pragma mark
#pragma mark Batch Attribute Tests

- (void) testAddRetrieveBatchOfAttributes
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    NSMutableDictionary *testAttributes = [NSMutableDictionary dictionary];
    [testAttributes setObject:@"Groucho" forKey:@"Favorite Mood"];
    [testAttributes setObject:@"Harpo" forKey:@"Name of high school"];
    [testAttributes setObject:@"Chico" forKey:@"City in California"];
    [testAttributes setObject:[NSDate date] forKey:@"Birthday"];
    
    /* Test batch add */
    BOOL didAdd = [targetURL setExtendedAttributes:testAttributes error:&error];
    STAssertTrue (didAdd, @"%@", error);
    
    /* Test batch retrieve */
    error = nil;
    NSDictionary *retrievedAttributes = [targetURL extendedAttributesWithError:&error];
    STAssertNotNil (retrievedAttributes, @"postcondition violated");
    STAssertTrue ([retrievedAttributes isEqualToDictionary:testAttributes], @"postcondition violated");
}

- (void) testHasAttributes
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    /* Create a test file */
    

    
    NSMutableDictionary *testAttributes = [NSMutableDictionary dictionary];
    [testAttributes setObject:@"Groucho" forKey:@"Favorite Mood"];
    [testAttributes setObject:@"Harpo" forKey:@"Name of high school"];
    [testAttributes setObject:@"Chico" forKey:@"City in California"];
    [testAttributes setObject:[NSDate date] forKey:@"Birthday"];
    
    BOOL didAdd = [targetURL setExtendedAttributes:testAttributes error:&error];
    STAssertTrue (didAdd, @"%@", error);
    
    STAssertTrue ([targetURL hasExtendedAttributeWithName:@"Favorite Mood"], @"postcondition violated");
    STAssertTrue ([targetURL hasExtendedAttributeWithName:@"Birthday"], @"postcondition violated");
    STAssertFalse ([targetURL hasExtendedAttributeWithName:@"Total Eclipse of the Heart"], @"postcondition violated");
}

#pragma mark -
#pragma mark Removal Tests

- (void) testRemoveNonexistentAttribute
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    /* Create a test file */
    

    
    /* Removing non-existent attribs is OK. */
    BOOL didRemove = [targetURL removeExtendedAttributeWithName:@"Jughead" error:&error];
    STAssertTrue (didRemove, @"%@", error);
}

- (void) testAddRemoveSingleAttribute
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    
    /* Create a test file */
    

    
    NSError *error = nil;
    NSString *attribName = @"net.standardorbit.latinPlaceholderText";
    id attribValue = @"Lorem ipsum dolor sit amet";
    
    /* Test setting an extended attribute value */
    
    STAssertTrue ( [targetURL setExtendedAttributeValue:attribValue forName:attribName error:&error], @"%@", error);
    
    /* Test retrieving the extended attribute value */
    
    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:attribName error:&error];
    STAssertNotNil (retrievedValue, @"%@", error);
    
    /* Remove the extended attribute */
    
    BOOL didRemove = [targetURL removeExtendedAttributeWithName:attribName error:&error];
    STAssertTrue (didRemove, @"%@; %@", error, [error userInfo]);
}

#pragma mark -
#pragma mark Single Attribute Tests

- (void) testStringAttribute
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    
    NSString *flog = @"flog";
    BOOL didSet = [targetURL setExtendedAttributeValue:flog forName:@"flogger" error:&error];
    STAssertTrue (didSet, @"%@", error);
    
    error = nil;
    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"flogger" error:&error];
    STAssertNotNil (retrievedValue, @"%@",error);
    
    STAssertTrue ([retrievedValue isKindOfClass:[NSString class]], @"postcondition violated");
    STAssertTrue ([flog isEqualToString:retrievedValue], @"postcondition violated");
}

- (void) testArrayAttribute
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;

    
    NSArray *colors = [NSArray arrayWithObjects:@"red", @"orange", @"yellow", @"green", @"blue", @"violet", nil];
    STAssertTrue ([targetURL setExtendedAttributeValue:colors forName:@"colors" error:&error], @"%@", error);
    
    error = nil;
    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"colors" error:&error];
    STAssertNotNil (retrievedValue, @"%@", error);
    STAssertTrue ([retrievedValue isKindOfClass:[NSArray class]], @"postcondition violated");
    STAssertTrue ([colors isEqualToArray:retrievedValue], @"postcondition violated");
}

- (void) testDictionaryAttribute
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    NSMutableDictionary *movieInfo = [NSMutableDictionary dictionary];
    [movieInfo setObject:@"Star Wars" forKey:@"title"];
    [movieInfo setObject:@"George Lucas" forKey:@"director"];
    
    NSArray *talent = [NSArray arrayWithObjects:@"Mark Hamill", @"Carrie Fisher", @"Harrison Ford", nil];
    [movieInfo setObject:talent forKey:@"talent"];
    
    STAssertTrue ([targetURL setExtendedAttributeValue:movieInfo forName:@"movieInfo" error:&error], @"%@", error);
    
    error = nil;
    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"movieInfo" error:&error];
    STAssertNotNil (retrievedValue, @"%@", error);
    STAssertTrue ([retrievedValue isKindOfClass:[NSDictionary class]], @"postcondition violated");
    STAssertTrue ([movieInfo isEqualToDictionary:retrievedValue], @"postcondition violated");
}

- (void) testNumberAttribute
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    /* Create a test file */
    
    id testNumber = [NSNumber numberWithFloat:6.28];
    
    STAssertTrue ([targetURL setExtendedAttributeValue:testNumber forName:@"number" error:&error], @"%@", error);
    
    error = nil;
    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"number" error:&error];
    STAssertNotNil (retrievedValue, @"%@", error);
    STAssertTrue ([retrievedValue isKindOfClass:[NSNumber class]], @"postcondition violated");
    STAssertTrue ([testNumber isEqualToNumber:retrievedValue], @"postcondition violated");
}

- (void) testNullAttribute
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    id testNull = [NSNull null];
    
    STAssertFalse ([targetURL setExtendedAttributeValue:testNull forName:@"null" error:&error], @"%@", error);
    STAssertTrue ([error code] == SOExtendedAttributesValueCantBeSerialized, @"postcondition violated");
}

- (void) testBooleanYes
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    
    id testBoolean = (id)kCFBooleanTrue;
    STAssertTrue ([targetURL setExtendedAttributeValue:testBoolean forName:@"boolean" error:&error], @"%@", error);
    
    error = nil;
    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"boolean" error:&error];
    STAssertNotNil (retrievedValue, @"%@", error);
    STAssertTrue ([retrievedValue isKindOfClass:[NSNumber class]], @"postcondition violated");
    STAssertTrue ([testBoolean isEqualToNumber:retrievedValue], @"postcondition violated");
}

- (void) testBooleanNo
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    /* Create a test file */
    

    
    id testBoolean = (id)kCFBooleanFalse;
    STAssertTrue ([targetURL setExtendedAttributeValue:testBoolean forName:@"boolean" error:&error], @"%@", error);
    
    error = nil;
    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"boolean" error:&error];
    STAssertNotNil (retrievedValue, @"%@", error);
    STAssertTrue ([retrievedValue isKindOfClass:[NSNumber class]], @"postcondition violated");
    STAssertTrue ([testBoolean isEqualToNumber:retrievedValue], @"postcondition violated");
}

#pragma mark
#pragma mark Bad Parameter Tests

- (void) testAttributeNameTooLong
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    /* Create a test file */
    

    
    NSArray *wordList = [NSArray arrayWithObjects:@"red", @"orange", @"yellow", @"green", @"blue", @"violet", nil];
    NSMutableString *WayTooLongName = [NSMutableString string];
    while ([WayTooLongName length] <= XATTR_MAXNAMELEN)
    {
        [WayTooLongName appendString:[wordList objectAtIndex:(arc4random() % [wordList count])]];
    }
    
    STAssertFalse ([targetURL setExtendedAttributeValue:@"something" forName:WayTooLongName error:&error], @"%@", error);
    STAssertTrue ([error code] == ENAMETOOLONG, @"postcondition violated");
}


- (void) testAddAttributeEmptyName
{
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    NSError *error = nil;
    
    // test empty name
    STAssertThrows ([targetURL setExtendedAttributeValue:nil forName:@"" error:&error], @"expected param exception");
    
    // Test nil name
    error = nil;
    STAssertThrows ([targetURL setExtendedAttributeValue:nil forName:nil error:&error], @"expected param exception");
}

- (void) testAccessAttributeEmptyName
{
    NSError *error = nil;
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    
    // test empty name
    STAssertThrows ([targetURL valueOfExtendedAttributeWithName:@"" error:&error], @"expected param exception");
    
    // Test nil name
    error = nil;
    STAssertThrows ([targetURL valueOfExtendedAttributeWithName:nil error:&error], @"expected param exception");
}

- (void) testRemoveAttributeEmptyName
{
    NSError *error = nil;
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    
    // test empty name
    STAssertThrows ([targetURL removeExtendedAttributeWithName:@"" error:&error], @"expected param exception");
    
    // Test nil name
    error = nil;
    STAssertThrows ([targetURL removeExtendedAttributeWithName:nil error:&error], @"expected param exception");
    
}

- (void) testHasAttributeWithEmptyName
{
    NSError *error = nil;
    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
    
    // test empty name
    STAssertThrows ([targetURL hasExtendedAttributeWithName:@""], @"expected param exception");
    
    // Test nil name
    error = nil;
    STAssertThrows ([targetURL hasExtendedAttributeWithName:nil], @"expected param exception");
}

- (void) testNonFileURL
{
    NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
    
    STAssertThrows ([url extendedAttributesWithError:NULL], @"expected NSInternalConsistencyExpection");
    STAssertThrows ([url setExtendedAttributes:[NSDictionary dictionary] error:NULL], @"expected NSInternalConsistencyExpection");
    
    STAssertThrows ([url hasExtendedAttributeWithName:@"bob"], @"expected NSInternalConsistencyExpection");
    
    STAssertThrows ([url setExtendedAttributeValue:nil forName:@"bob" error:NULL], @"expected NSInternalConsistencyExpection");
    STAssertThrows ([url valueOfExtendedAttributeWithName:@"bob" error:NULL], @"expected NSInternalConsistencyExpection");
    
    STAssertThrows ([url removeExtendedAttributeWithName:@"bob" error:NULL], @"expected NSInternalConsistencyExpection");
}


@end