Commits

Bill Garrison  committed 1dea951

Jiggery pokery in unit tests.

  • Participants
  • Parent commits dae2101

Comments (0)

Files changed (8)

File Documentation/net.standardorbit.SOExtendedAttributes.docset/Contents/Resources/Documents/Categories/NSURL+SOExtendedAttributes.html

 					<div class="section section-overview">
 						<a title="Overview" name="overview"></a>
 						<h2 class="subtitle subtitle-overview">Overview</h2>
-						<p>When multiple errors are reported from the xattr API, they are collected and reported under this [NSError userInfo] dictionary key.</p>
+						<p>The SOExtendedAttributes category on NSURL enables retrieving and manipulating the extended attributes on a file system item.</p>
+
+<p>These methods are valid only on file URLs. An NSInternalInconsistencyException is thrown if invoked an a non-file URL.</p>
+
+<p>Internally, they&rsquo;re implemented using <a href="x-man-page://listxattr">listxattr(2)</a>, <a href="x-man-page://getxattr">getxattr(2)</a>, <a href="x-man-page://setxattr">setxattr(2)</a>, and <a href="x-man-page://removexattr">removexattr(2)</a>.</p>
+
+<p><strong> Compatibility </strong></p>
+
+<p>SOExtendedAttributes is compatible with Mac OS X 10.6+ and iOS 5. The clang compiler is required. The source file <code>NSURL+SOExtendedAttributes.m</code> must be compiled with ARC enabled. For an alternate Cocoa implementation compatible with Mac OS X 10.4 and greater, see <a href="http://zathras.de/angelweb/sourcecode.htm">UKXattrMetadataStore</a>.</p>
+
+<p><strong> Symbolic links </strong></p>
+
+<p>These methods act on the explicitly given URL. If that URL is to a symbolic link, you&rsquo;ll be manipulating extended attributes on the symlink, not its original file. Use <code>-URLByResolvingSymlinksInPath</code> to obtain a URL for which points to the original file system item.</p>
+
+<p><strong> Use with iCloud Backup </strong></p>
+
+<p>Note 2013-06-03: see <a href="http://developer.apple.com/library/ios/#qa/qa1719/">Apple Tech QA 1719</a> for the recommended way to mark a file for exclusion from iCloud backup. Hint: don&rsquo;t use the @&ldquo;com.apple.MobileMeBackup&rdquo; extended attribute.</p>
+
+<p><strong> Error Reporting </strong></p>
+
+<p>SOExtendedAttributes reports errors under the domain <code>SOExtendedAttributesErrorDomain</code>. When multiple errors occur on getting or setting extended attributes in a batch, the errors are collected in an NSArray and reported via error&rsquo;s -userInfo dictionary under <code>SOUnderlyingErrorsKey</code>.</p>
 					</div>
 					
 					

File Documentation/net.standardorbit.SOExtendedAttributes.docset/Contents/Resources/Tokens1.xml

 		
 		<Token>
 			<TokenIdentifier>//apple_ref/occ/cat/NSURL(SOExtendedAttributes)</TokenIdentifier>
-			<Abstract type="html">When multiple errors are reported from the xattr API, they are collected and reported under this [NSError userInfo] dictionary key.</Abstract>
+			<Abstract type="html">The SOExtendedAttributes category on NSURL enables retrieving and manipulating the extended attributes on a file system item.</Abstract>
 			<DeclaredIn>NSURL+SOExtendedAttributes.h</DeclaredIn>
 			
 			<NodeRef refid="1"/>

File Documentation/net.standardorbit.SOExtendedAttributes.docset/Contents/Resources/docSet.dsidx

Binary file modified.

File Documentation/net.standardorbit.SOExtendedAttributes.docset/Contents/Resources/docSet.skidx

Binary file modified.

File Documentation/net.standardorbit.SOExtendedAttributes.docset/Contents/Resources/docSet.toc

Binary file modified.

File Documentation/net.standardorbit.SOExtendedAttributes.docset/Contents/Resources/docSet.tokencache

Binary file modified.

File NSURL+SOExtendedAttributes.h

  
  ** Use with iCloud Backup **
  
- iCloud (as of iOS 5.0.1) honors the extended attribute `@"com.apple.MobileMeBackup"` as a flag to exclude a file system item from iCloud backup. This category defines the constant `iCloudDoNotBackupAttributeName` to work with this iCloud behavior.
+ Note 2013-06-03: see [Apple Tech QA 1719](http://developer.apple.com/library/ios/#qa/qa1719/) for the recommended way to mark a file for exclusion from iCloud backup. Hint: don't use the @"com.apple.MobileMeBackup" extended attribute.
  
- ** Constants **
+ ** Error Reporting **
  
- `iCloudDoNotBackupAttributeName = @"com.apple.MobileMeBackup"`
- 
- E.g. To determine if a file system item is marked to be excluded from iCloud backup:
- 
-    NSURL fileURL = ...;
-    BOOL isExcludedFromiCloudBackup = [fileURL hasExtendedAttributeWithName:iCloudDoNotBackupAttribute];
- 
+ SOExtendedAttributes reports errors under the domain `SOExtendedAttributesErrorDomain`. When multiple errors occur on getting or setting extended attributes in a batch, those errors are collected in an NSArray and reported via error's -userInfo dictionary under `SOUnderlyingErrorsKey`.
  */
 
 extern NSString * const iCloudDoNotBackupAttributeName;
 extern NSString * const SOExtendedAttributesErrorDomain;
+extern NSString * const SOUnderlyingErrorsKey;
 
 enum {
     SOExtendedAttributesValueCantBeSerialized = 1968,
     SOExtendedAttributesGetValueError,
 };
 
-/** When multiple errors are reported from the xattr API, they are collected and reported under this -[NSError userInfo] dictionary key. */
-extern NSString * const SOUnderlyingErrorsKey;
-
-
 @interface NSURL (SOExtendedAttributes)
 
 /** @name Accessing attributes in batches */
  
  Return all extended attributes that the current user account has permission to access. Attributes will include the HFS compression extended attribute if present.
  
- @param outError A pointer to an error object. On return, if an error has occurred, this pointer references an actual error object containing the error information. Pass NULL if you're not interesting in error reporting.
+ @param outError If an error occurs, upon return contains an NSError object that describes the problem. Pass NULL if you're not interested in error reporting.
  @return An NSDictionary object that describes the extended attributes of the file system object, or nil if an error occurred.
  */
 - (NSDictionary *) extendedAttributesWithError:(NSError * __autoreleasing *)outError;
  
  If the attributes dictionary holds a value object that cannot be encoded as a plist, an NSError with code `SOExtendedAttributesValueCantBeSerialized` is returned via the outError parameter. 
  
- On error, a partial number of the given extended attributes may have been successfully set. The error returned through outError will indicate which attributes could not be set. In particular, `[[*outError userInfo] objectForKey:NSUnderlyingErrorKey]`
+ On error, one or more of the given extended attributes may have failed to be set. Any underlying errors are reported via the -userInfo dictionary as an NSArray under the key `SOUnderlyingErrorsKey`.
  
  @param attributes The extended attribute names and values to be set. All values be instances of NSData, NSString, NSArray, NSDictionary, NSDate or NSNumber.
- @param outError A pointer to an error object. On return, if an error has occurred, this pointer references an actual error object containing the error information. Pass NULL if you're not interesting in error reporting.
+ @param outError If an error occurs, upon return contains an NSError object that describes the problem. Pass NULL if you're not interested in error reporting.
  @return YES if all given attribute values were set. NO if there was an error setting one or more of the values.
  */
 - (BOOL) setExtendedAttributes:(NSDictionary *)attributes error:(NSError * __autoreleasing *)outError;

File UnitTests/SOExtendedAttributes_UnitTests.m

 #include <sys/xattr.h>
 
 @interface SOExtendedAttributes_UnitTests : SenTestCase
-
+{
+    NSURL *targetURL;
+}
 @end
 
 @implementation SOExtendedAttributes_UnitTests
 
+
 #pragma mark
 #pragma mark Fixture
 
-- (NSURL *) generatedTestURL
+- (BOOL) createTestURLForTest:(SEL)testSelector
 {
-    NSURL *generatedURL = [NSURL fileURLWithPath:NSTemporaryDirectory()];
-    if (generatedURL)
+    BOOL didCreate = NO;
+    
+    targetURL = [NSURL fileURLWithPathComponents:[NSArray arrayWithObjects:NSTemporaryDirectory(), NSStringFromSelector(testSelector), SOGeneratedUUID(), nil]];
+    
+    if (targetURL)
     {
-        generatedURL = [generatedURL URLByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@", NSStringFromSelector(_cmd), SOGeneratedUUID()]];
+        /* 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 generatedURL;
+    
+    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];
 }
 {
     /* Test that underlying errors generated from xattr are collected and reported properly. */
     
-    NSURL *targetURL = [self generatedTestURL];
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
     /* Create a test file */
     
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
+
     
-    NSString *excessivelyLongName1 = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,";
-    NSString *excessivelyLongName2 = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, scooby";
-    NSString *excessivelyLongName3 = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, shaggy";
-
-    NSDictionary *badAttribs = [NSDictionary dictionaryWithObjectsAndKeys:
-                                 @"LexLuthor" ,excessivelyLongName1,
-                                @"Magneto", excessivelyLongName2,
-                                @"KhanNoonianSingh", excessivelyLongName3,
-                                nil
-                                ];
+    NSString *excessivelyLongName1 = @"Loremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua.Utenimadminimveniamwangchung";
+    NSString *excessivelyLongName2 = @"Loremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua.Utenimadminimveniamwangchungscooby";
+    NSString *excessivelyLongName3 = @"Loremipsumdolorsitametconsecteturadipisicingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua.Utenimadminimveniamwangchungshaggy";
     
-    BOOL didAdd = [targetURL setExtendedAttributes:badAttribs error:&error];
+    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 Batch Attribute Tests
 
 - (void) testAddRetrieveBatchOfAttributes
-{    
-    NSURL *targetURL = [self generatedTestURL];
+{
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
-    /* Create a test file */
-    
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
-    
     NSMutableDictionary *testAttributes = [NSMutableDictionary dictionary];
     [testAttributes setObject:@"Groucho" forKey:@"Favorite Mood"];
     [testAttributes setObject:@"Harpo" forKey:@"Name of high school"];
 
 - (void) testHasAttributes
 {
-    NSURL *targetURL = [self generatedTestURL];
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
     /* Create a test file */
     
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
+
     
     NSMutableDictionary *testAttributes = [NSMutableDictionary dictionary];
     [testAttributes setObject:@"Groucho" forKey:@"Favorite Mood"];
 
 - (void) testRemoveNonexistentAttribute
 {
-    NSURL *targetURL = [self generatedTestURL];
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
     /* Create a test file */
     
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
+
     
     /* Removing non-existent attribs is OK. */
     BOOL didRemove = [targetURL removeExtendedAttributeWithName:@"Jughead" error:&error];
 }
 
 - (void) testAddRemoveSingleAttribute
-{    
-    NSURL *targetURL = [self generatedTestURL];
+{
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     
     /* Create a test file */
     
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
+
     
     NSError *error = nil;
-    NSString *testName = @"net.standardorbit.latinPlaceholderText";
-    id testValue = @"Lorem ipsum dolor sit amet";
+    NSString *attribName = @"net.standardorbit.latinPlaceholderText";
+    id attribValue = @"Lorem ipsum dolor sit amet";
     
     /* Test setting an extended attribute value */
     
-    STAssertTrue ( [targetURL setExtendedAttributeValue:testValue forName:testName error:&error], @"%@", error);
+    STAssertTrue ( [targetURL setExtendedAttributeValue:attribValue forName:attribName error:&error], @"%@", error);
     
     /* Test retrieving the extended attribute value */
     
-    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:testName error:&error];
+    id retrievedValue = [targetURL valueOfExtendedAttributeWithName:attribName error:&error];
     STAssertNotNil (retrievedValue, @"%@", error);
     
     /* Remove the extended attribute */
     
-    BOOL didRemove = [targetURL removeExtendedAttributeWithName:testName error:&error];
+    BOOL didRemove = [targetURL removeExtendedAttributeWithName:attribName error:&error];
     STAssertTrue (didRemove, @"%@; %@", error, [error userInfo]);
 }
 
 
 - (void) testStringAttribute
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
-    /* Create a test file */
-    
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
     
     NSString *flog = @"flog";
     BOOL didSet = [targetURL setExtendedAttributeValue:flog forName:@"flogger" error:&error];
 
 - (void) testArrayAttribute
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
-    
-    /* Create a test file */
-    
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
+
     
     NSArray *colors = [NSArray arrayWithObjects:@"red", @"orange", @"yellow", @"green", @"blue", @"violet", nil];
     STAssertTrue ([targetURL setExtendedAttributeValue:colors forName:@"colors" error:&error], @"%@", error);
 
 - (void) testDictionaryAttribute
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
-    /* Create a test file */
-    
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
-    
     NSMutableDictionary *movieInfo = [NSMutableDictionary dictionary];
     [movieInfo setObject:@"Star Wars" forKey:@"title"];
     [movieInfo setObject:@"George Lucas" forKey:@"director"];
 
 - (void) testNumberAttribute
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
     /* Create a test file */
     
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
-    
     id testNumber = [NSNumber numberWithFloat:6.28];
     
     STAssertTrue ([targetURL setExtendedAttributeValue:testNumber forName:@"number" error:&error], @"%@", error);
     id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"number" error:&error];
     STAssertNotNil (retrievedValue, @"%@", error);
     STAssertTrue ([retrievedValue isKindOfClass:[NSNumber class]], @"postcondition violated");
-    STAssertTrue ([testNumber isEqualToNumber:retrievedValue], @"postcondition violated");  
+    STAssertTrue ([testNumber isEqualToNumber:retrievedValue], @"postcondition violated");
 }
 
 - (void) testNullAttribute
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
-    /* Create a test file */
-    
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
-    
     id testNull = [NSNull null];
     
     STAssertFalse ([targetURL setExtendedAttributeValue:testNull forName:@"null" error:&error], @"%@", error);
 
 - (void) testBooleanYes
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    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 */
     
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
-    
-    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
-{
-    NSURL *targetURL = [self generatedTestURL];    
-    NSError *error = nil;
-    
-    /* Create a test file */
-    
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
     
     id testBoolean = (id)kCFBooleanFalse;
     STAssertTrue ([targetURL setExtendedAttributeValue:testBoolean forName:@"boolean" error:&error], @"%@", error);
     id retrievedValue = [targetURL valueOfExtendedAttributeWithName:@"boolean" error:&error];
     STAssertNotNil (retrievedValue, @"%@", error);
     STAssertTrue ([retrievedValue isKindOfClass:[NSNumber class]], @"postcondition violated");
-    STAssertTrue ([testBoolean isEqualToNumber:retrievedValue], @"postcondition violated"); 
+    STAssertTrue ([testBoolean isEqualToNumber:retrievedValue], @"postcondition violated");
 }
 
 #pragma mark
 
 - (void) testAttributeNameTooLong
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
     /* Create a test file */
     
-    STAssertTrue ([[NSFileManager defaultManager] createFileAtPath:[targetURL path]  contents:[NSData data] attributes:nil], @"Couldn't create test file");
+
     
-    NSArray *wordList = [NSArray arrayWithObjects:@"red", @"orange", @"yellow", @"green", @"blue", @"violet", nil];    
+    NSArray *wordList = [NSArray arrayWithObjects:@"red", @"orange", @"yellow", @"green", @"blue", @"violet", nil];
     NSMutableString *WayTooLongName = [NSMutableString string];
     while ([WayTooLongName length] <= XATTR_MAXNAMELEN)
     {
 
 - (void) testAddAttributeEmptyName
 {
-    NSURL *targetURL = [self generatedTestURL];    
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     NSError *error = nil;
     
     // test empty name
 - (void) testAccessAttributeEmptyName
 {
     NSError *error = nil;
-    NSURL *targetURL = [self generatedTestURL];
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     
     // test empty name
     STAssertThrows ([targetURL valueOfExtendedAttributeWithName:@"" error:&error], @"expected param exception");
 - (void) testRemoveAttributeEmptyName
 {
     NSError *error = nil;
-    NSURL *targetURL = [self generatedTestURL];
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     
     // test empty name
     STAssertThrows ([targetURL removeExtendedAttributeWithName:@"" error:&error], @"expected param exception");
 - (void) testHasAttributeWithEmptyName
 {
     NSError *error = nil;
-    NSURL *targetURL = [self generatedTestURL];
+    STAssertTrue([self createTestURLForTest:_cmd], @"Couldn't create test file");
     
     // test empty name
     STAssertThrows ([targetURL hasExtendedAttributeWithName:@""], @"expected param exception");