From 36fe247d6e7bd0eae9524ded69d2f2d1b83178ee Mon Sep 17 00:00:00 2001 From: Johan Kool Date: Sun, 1 Jun 2014 14:13:35 +0800 Subject: [PATCH 1/2] Pretty print errors --- EFMapping/EFMapper.m | 10 +++++----- EFMapping/EFMappingError.m | 34 ++++++++++++++++++---------------- EFMappingTests/EFMappingTest.m | 24 +++++++++++++++++------- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/EFMapping/EFMapper.m b/EFMapping/EFMapper.m index 72a9491..066a6ae 100644 --- a/EFMapping/EFMapper.m +++ b/EFMapping/EFMapper.m @@ -177,7 +177,7 @@ - (BOOL)validateValues:(NSDictionary *)values forClass:(Class)aClass onObject:(i } if ([errorsInArray count] > 0) { - NSString *description = [NSString stringWithFormat:@"Encountered %lu validation error(s) in array for key %@", (unsigned long)[errorsInArray count], mapping.internalKey]; + NSString *description = [NSString stringWithFormat:@"Encountered %lu validation error%@ in array for key %@", (unsigned long)[errorsInArray count], [errorsInArray count] == 1 ? @"" : @"s", mapping.internalKey]; NSError *validationError = [NSError errorWithDomain:EFMappingErrorDomain code:EFMappingUnexpectedClass userInfo:@{NSLocalizedDescriptionKey: description, EFMappingErrorValidationErrorsKey: errorsInArray}]; errors[mapping.internalKey] = validationError; } else { @@ -218,7 +218,7 @@ - (BOOL)validateValues:(NSDictionary *)values forClass:(Class)aClass onObject:(i }]; if ([errorsInDictionary count] > 0) { - NSString *description = [NSString stringWithFormat:@"Encountered %lu validation error(s) in dictionary for key %@", (unsigned long)[errorsInDictionary count], mapping.internalKey]; + NSString *description = [NSString stringWithFormat:@"Encountered %lu validation error%@ in dictionary for key %@", (unsigned long)[errorsInDictionary count], [errorsInDictionary count] == 1 ? @"" : @"s", mapping.internalKey]; NSError *validationError = [NSError errorWithDomain:EFMappingErrorDomain code:EFMappingUnexpectedClass userInfo:@{NSLocalizedDescriptionKey: description, EFMappingErrorValidationErrorsKey: errorsInDictionary}]; errors[mapping.internalKey] = validationError; } else { @@ -265,7 +265,7 @@ - (BOOL)validateValues:(NSDictionary *)values forClass:(Class)aClass onObject:(i if ([errors count] > 0) { if (error != NULL) { - NSString *description = [NSString stringWithFormat:NSLocalizedString(@"Encountered %d validation error(s) in %@", @""), [errors count], NSStringFromClass(aClass)]; + NSString *description = [NSString stringWithFormat:NSLocalizedString(@"Encountered %d validation error%@ in %@", @""), [errors count], [errors count] == 1 ? @"" : @"s", NSStringFromClass(aClass)]; *error = [NSError errorWithDomain:EFMappingErrorDomain code:EFMappingInvalidValues userInfo:@{NSLocalizedDescriptionKey: description, EFMappingErrorValidationErrorsKey: errors}]; } return NO; @@ -409,7 +409,7 @@ - (BOOL)validateValue:(id)value isCollection:(BOOL)isCollection mapping:(EFMappi if (isCollection) { if (value && ![value isKindOfClass:mapping.collectionClass]) { if (error != NULL) { - NSString *description = [NSString stringWithFormat:@"Did not expect value (%@) of class %@ for key %@ but %@ instance", value, NSStringFromClass([value class]), mapping.internalKey, NSStringFromClass(mapping.collectionClass)]; + NSString *description = [NSString stringWithFormat:@"Did not expect value (%@) of class %@ for key %@ but a %@ instance", value, NSStringFromClass([value class]), mapping.internalKey, NSStringFromClass(mapping.collectionClass)]; *error = [NSError errorWithDomain:EFMappingErrorDomain code:EFMappingUnexpectedClass userInfo:@{NSLocalizedDescriptionKey: description}]; } return NO; @@ -424,7 +424,7 @@ - (BOOL)validateValue:(id)value isCollection:(BOOL)isCollection mapping:(EFMappi } } else { if (error != NULL) { - NSString *description = [NSString stringWithFormat:@"Did not expect value (%@) of class %@ for key %@ but %@ instance%@", value, NSStringFromClass([value class]), mapping.internalKey, NSStringFromClass(mapping.internalClass), [self mappingsForClass:mapping.internalClass] ? @" or NSDictionary" : @""]; + NSString *description = [NSString stringWithFormat:@"Did not expect value (%@) of class %@ for key %@ but a %@ instance%@", value, NSStringFromClass([value class]), mapping.internalKey, NSStringFromClass(mapping.internalClass), [self mappingsForClass:mapping.internalClass] ? @" or NSDictionary" : @""]; *error = [NSError errorWithDomain:EFMappingErrorDomain code:EFMappingUnexpectedClass userInfo:@{NSLocalizedDescriptionKey: description}]; } return NO; diff --git a/EFMapping/EFMappingError.m b/EFMapping/EFMappingError.m index c6b9722..253538a 100644 --- a/EFMapping/EFMappingError.m +++ b/EFMapping/EFMappingError.m @@ -11,27 +11,29 @@ NSString * const EFMappingErrorDomain = @"EFMappingErrorDomain"; NSString * const EFMappingErrorValidationErrorsKey = @"validationErrors"; -NSString* EFPrettyMappingError(NSError *error) { +NSString* EFPrettyMappingErrorWithIndentation(NSError *error, NSUInteger indentationLevel) { if ([error.domain isEqualToString:EFMappingErrorDomain]) { NSMutableString *string = [NSMutableString string]; - if (error.code == EFMappingInvalidValues) { - [string appendFormat:@"%@:", error.userInfo[NSLocalizedDescriptionKey]]; - id errors = error.userInfo[EFMappingErrorValidationErrorsKey]; - if ([errors isKindOfClass:[NSArray class]]) { - [errors enumerateObjectsUsingBlock:^(NSError *subError, NSUInteger idx, BOOL *stop) { - [string appendFormat:@"\n\t- %lu: %@", (unsigned long)idx, subError.userInfo[NSLocalizedDescriptionKey]]; - }]; - } else if ([errors isKindOfClass:[NSDictionary class]]) { - [errors enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSError *subError, BOOL *stop) { - [string appendFormat:@"\n\t- %@: %@", key, subError.userInfo[NSLocalizedDescriptionKey]]; - }]; - } - } else { - // Do some recursive stuff here! + [string appendString:error.userInfo[NSLocalizedDescriptionKey]]; + id errors = error.userInfo[EFMappingErrorValidationErrorsKey]; + NSString *tabs = [@"\n" stringByPaddingToLength:indentationLevel + 2 withString:@"\t" startingAtIndex:0]; + if ([errors isKindOfClass:[NSArray class]]) { + [string appendString:@":"]; + [errors enumerateObjectsUsingBlock:^(NSError *subError, NSUInteger idx, BOOL *stop) { + [string appendFormat:@"%@%lu: %@", tabs, (unsigned long)idx, EFPrettyMappingErrorWithIndentation(subError, indentationLevel + 1)]; + }]; + } else if ([errors isKindOfClass:[NSDictionary class]]) { + [string appendString:@":"]; + [errors enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSError *subError, BOOL *stop) { + [string appendFormat:@"%@%@: %@", tabs, key, EFPrettyMappingErrorWithIndentation(subError, indentationLevel + 1)]; + }]; } - [string appendString:@"\n"]; return string; } else { return [error description]; } +} + +NSString* EFPrettyMappingError(NSError *error) { + return EFPrettyMappingErrorWithIndentation(error, 0); } \ No newline at end of file diff --git a/EFMappingTests/EFMappingTest.m b/EFMappingTests/EFMappingTest.m index 38ae60c..02c7f65 100644 --- a/EFMappingTests/EFMappingTest.m +++ b/EFMappingTests/EFMappingTest.m @@ -82,13 +82,6 @@ - (void)testSettingValues { m.externalKey = @"id"; m.internalKey = @"guid"; m.requires = [EFRequires exists]; - m.transformationBlock = ^id(id value, BOOL reverse) { - if (reverse) { - return [(NSURL *)value absoluteString]; - } else { - return [NSURL URLWithString:(NSString *)value]; - } - }; }]] forClass:[EFSample class]]; NSError *error; @@ -201,4 +194,21 @@ - (void)testRequirements { XCTAssertFalse([[EFRequires either:array or:[EFRequires equalTo:@10]] evaluateForValue:@1], @"Value or"); } +- (void)testPrettyErrors { + EFMapper *mapper = [[EFMapper alloc] init]; + [mapper registerMappings:@[[EFMapping mapping:^(EFMapping *m){m.internalClass = [NSString class]; m.externalKey = @"id"; m.internalKey = @"guid"; m.requires = [EFRequires exists];}], + [EFMapping mappingForArrayOfClass:[EFSample class] externalKey:@"children" internalKey:@"relatedSamples"]] forClass:[EFSample class]]; + + NSError *error; + EFSample *sample = [mapper objectOfClass:[EFSample class] withValues:@{@"id": @"1", @"children": @[@{@"id": @"2"}, @{@"id": @3, @"children": @[@{@"id": @"4"}, @{@"id": @5}]}]} error:&error]; + NSString *expectedErrorMsg = @"Encountered 1 validation error in EFSample:\n\ +\trelatedSamples: Encountered 1 validation error in array for key relatedSamples:\n\ +\t\t0: Encountered 2 validation errors in EFSample:\n\ +\t\t\tguid: Did not expect value (3) of class __NSCFNumber for key guid but a NSString instance\n\ +\t\t\trelatedSamples: Encountered 1 validation error in array for key relatedSamples:\n\ +\t\t\t\t0: Encountered 1 validation error in EFSample:\n\ +\t\t\t\t\tguid: Did not expect value (5) of class __NSCFNumber for key guid but a NSString instance"; + XCTAssertEqualObjects(EFPrettyMappingError(error), expectedErrorMsg, @"Pretty print error differs"); +} + @end From 50a9f98ddcf469773559ef41cc6dea76c88faa84 Mon Sep 17 00:00:00 2001 From: Johan Kool Date: Sun, 1 Jun 2014 14:20:20 +0800 Subject: [PATCH 2/2] Bump podspec version --- EFDataMappingKit.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EFDataMappingKit.podspec b/EFDataMappingKit.podspec index 2ca0d4d..5d2b718 100644 --- a/EFDataMappingKit.podspec +++ b/EFDataMappingKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "EFDataMappingKit" - s.version = "0.1.2" + s.version = "0.1.3" s.summary = "EFDataMappingKit maps data such as those coming from JSON onto an instance using mappings" s.description = "EFDataMappingKit maps data such as those coming from JSON onto an instance using mappings. The mappings are also used to simplify implementing the NSCoding protocol for a class, and to create a dictionary representation of an instance." s.homepage = "https://github.com/Egeniq/EFDataMappingKit"