Adds JSONHelper methods to read strings. (+1 squashed commit)

Squashed commits:
[30b0a71] Adds JSONHelper methods to read strings.
This commit is contained in:
2020-09-13 05:04:22 -07:00
parent 0fe24d767c
commit e821656871
4 changed files with 227 additions and 0 deletions

View File

@@ -15,6 +15,8 @@
E20D032B25031BE500FB6E43 /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032A25031BE500FB6E43 /* LibraryViewController.m */; }; E20D032B25031BE500FB6E43 /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032A25031BE500FB6E43 /* LibraryViewController.m */; };
E20D032E25031BEF00FB6E43 /* CollectionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032D25031BEF00FB6E43 /* CollectionsViewController.m */; }; E20D032E25031BEF00FB6E43 /* CollectionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032D25031BEF00FB6E43 /* CollectionsViewController.m */; };
E20D033125031BFD00FB6E43 /* DashboardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D033025031BFD00FB6E43 /* DashboardViewController.m */; }; E20D033125031BFD00FB6E43 /* DashboardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D033025031BFD00FB6E43 /* DashboardViewController.m */; };
E22F837C2511D14E0072105C /* JSONHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E22F837B2511D14E0072105C /* JSONHelper.m */; };
E22F837F2511E8500072105C /* JSONHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E22F837E2511E8500072105C /* JSONHelperTests.m */; };
E2532E8925038DE100CA4CBA /* StringHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E2532E8825038DE100CA4CBA /* StringHelper.m */; }; E2532E8925038DE100CA4CBA /* StringHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E2532E8825038DE100CA4CBA /* StringHelper.m */; };
E2592B8D250D6B8100906A40 /* EditMonsterViewControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2592B8C250D6B8100906A40 /* EditMonsterViewControllerTests.m */; }; E2592B8D250D6B8100906A40 /* EditMonsterViewControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2592B8C250D6B8100906A40 /* EditMonsterViewControllerTests.m */; };
E25BD5F5250352C4007B04EF /* Monster.m in Sources */ = {isa = PBXBuildFile; fileRef = E25BD5F4250352C4007B04EF /* Monster.m */; }; E25BD5F5250352C4007B04EF /* Monster.m in Sources */ = {isa = PBXBuildFile; fileRef = E25BD5F4250352C4007B04EF /* Monster.m */; };
@@ -82,6 +84,9 @@
E20D032D25031BEF00FB6E43 /* CollectionsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CollectionsViewController.m; sourceTree = "<group>"; }; E20D032D25031BEF00FB6E43 /* CollectionsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CollectionsViewController.m; sourceTree = "<group>"; };
E20D032F25031BFD00FB6E43 /* DashboardViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DashboardViewController.h; sourceTree = "<group>"; }; E20D032F25031BFD00FB6E43 /* DashboardViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DashboardViewController.h; sourceTree = "<group>"; };
E20D033025031BFD00FB6E43 /* DashboardViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DashboardViewController.m; sourceTree = "<group>"; }; E20D033025031BFD00FB6E43 /* DashboardViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DashboardViewController.m; sourceTree = "<group>"; };
E22F837A2511D14E0072105C /* JSONHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSONHelper.h; sourceTree = "<group>"; };
E22F837B2511D14E0072105C /* JSONHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JSONHelper.m; sourceTree = "<group>"; };
E22F837E2511E8500072105C /* JSONHelperTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JSONHelperTests.m; sourceTree = "<group>"; };
E2532E8725038DE100CA4CBA /* StringHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringHelper.h; sourceTree = "<group>"; }; E2532E8725038DE100CA4CBA /* StringHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringHelper.h; sourceTree = "<group>"; };
E2532E8825038DE100CA4CBA /* StringHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StringHelper.m; sourceTree = "<group>"; }; E2532E8825038DE100CA4CBA /* StringHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StringHelper.m; sourceTree = "<group>"; };
E2591EB62509DD4900B396FD /* EditableFormFieldDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EditableFormFieldDelegate.h; sourceTree = "<group>"; }; E2591EB62509DD4900B396FD /* EditableFormFieldDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EditableFormFieldDelegate.h; sourceTree = "<group>"; };
@@ -234,6 +239,16 @@
E2532E8825038DE100CA4CBA /* StringHelper.m */, E2532E8825038DE100CA4CBA /* StringHelper.m */,
E26A73552511BA1900C5677E /* HTMLHelper.h */, E26A73552511BA1900C5677E /* HTMLHelper.h */,
E26A73562511BA1900C5677E /* HTMLHelper.m */, E26A73562511BA1900C5677E /* HTMLHelper.m */,
E22F837A2511D14E0072105C /* JSONHelper.h */,
E22F837B2511D14E0072105C /* JSONHelper.m */,
);
path = Helpers;
sourceTree = "<group>";
};
E22F837D2511E8350072105C /* Helpers */ = {
isa = PBXGroup;
children = (
E22F837E2511E8500072105C /* JSONHelperTests.m */,
); );
path = Helpers; path = Helpers;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -302,6 +317,7 @@
E2F7249425005E8A007D87ED /* MonsterCardsTests */ = { E2F7249425005E8A007D87ED /* MonsterCardsTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
E22F837D2511E8350072105C /* Helpers */,
E2592B8B250D6B6000906A40 /* Views */, E2592B8B250D6B6000906A40 /* Views */,
E2FD91E225047C1D00D5E935 /* Models */, E2FD91E225047C1D00D5E935 /* Models */,
E2F7249525005E8A007D87ED /* MonsterCardsTests.m */, E2F7249525005E8A007D87ED /* MonsterCardsTests.m */,
@@ -591,6 +607,7 @@
E25BD5FB250369D7007B04EF /* Skill.m in Sources */, E25BD5FB250369D7007B04EF /* Skill.m in Sources */,
E2F7247825005E89007D87ED /* SceneDelegate.m in Sources */, E2F7247825005E89007D87ED /* SceneDelegate.m in Sources */,
E20D032425031B9D00FB6E43 /* SearchViewController.m in Sources */, E20D032425031B9D00FB6E43 /* SearchViewController.m in Sources */,
E22F837C2511D14E0072105C /* JSONHelper.m in Sources */,
E25BD60125036BF8007B04EF /* Language.m in Sources */, E25BD60125036BF8007B04EF /* Language.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -609,6 +626,7 @@
E2FD91E425047C4400D5E935 /* AbilityTests.m in Sources */, E2FD91E425047C4400D5E935 /* AbilityTests.m in Sources */,
E2E25805250CC3A7002E7308 /* MonsterCards.xcdatamodeld in Sources */, E2E25805250CC3A7002E7308 /* MonsterCards.xcdatamodeld in Sources */,
E2F7249625005E8A007D87ED /* MonsterCardsTests.m in Sources */, E2F7249625005E8A007D87ED /* MonsterCardsTests.m in Sources */,
E22F837F2511E8500072105C /* JSONHelperTests.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -772,6 +790,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = J793L9LQJ2; DEVELOPMENT_TEAM = J793L9LQJ2;
HEADER_SEARCH_PATHS = "$(SRCROOT)/Pods/**";
INFOPLIST_FILE = MonsterCards/Info.plist; INFOPLIST_FILE = MonsterCards/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
@@ -791,6 +810,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = J793L9LQJ2; DEVELOPMENT_TEAM = J793L9LQJ2;
HEADER_SEARCH_PATHS = "$(SRCROOT)/Pods/**";
INFOPLIST_FILE = MonsterCards/Info.plist; INFOPLIST_FILE = MonsterCards/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (

View File

@@ -0,0 +1,21 @@
//
// JSONHelper.h
// MonsterCards
//
// Created by Tom Hicks on 9/15/20.
// Copyright © 2020 Tom Hicks. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface JSONHelper : NSObject
+(NSString*)readStringFromDictionary:(NSDictionary*)dictionary forKey:(NSString*)key;
+(NSString*)readStringFromDictionary:(NSDictionary*)dictionary forKey:(NSString*)key withDefaultValue:(NSString* _Nullable)defaultValue;
+(NSString*)readStringFromArray:(NSArray*)array forIndex:(NSUInteger)index;
+(NSString*)readStringFromArray:(NSArray*)array forIndex:(NSUInteger)index withDefaultValue:(NSString* _Nullable)defaultValue;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,39 @@
//
// JSONHelper.m
// MonsterCards
//
// Created by Tom Hicks on 9/15/20.
// Copyright © 2020 Tom Hicks. All rights reserved.
//
#import "JSONHelper.h"
@implementation JSONHelper
NSString* coerceObjectToString(NSObject *object, NSString *defaultValue) {
if ([object isKindOfClass:[NSString class]]) {
return (NSString*)object;
}
return defaultValue;
}
+(NSString*)readStringFromDictionary:(NSDictionary*)dictionary forKey:(NSString*)key {
return [JSONHelper readStringFromDictionary:dictionary forKey:key withDefaultValue:nil];
}
+(NSString*)readStringFromDictionary:(NSDictionary*)dictionary forKey:(NSString*)key withDefaultValue:(NSString* _Nullable)defaultValue {
NSObject *object = [dictionary objectForKey:key];
return coerceObjectToString(object, defaultValue);
}
+(NSString*)readStringFromArray:(NSArray*)array forIndex:(NSUInteger)index{
return [JSONHelper readStringFromArray:array forIndex:index withDefaultValue:nil];
}
+(NSString*)readStringFromArray:(NSArray*)array forIndex:(NSUInteger)index withDefaultValue:(NSString* _Nullable)defaultValue {
NSObject *object = [array objectAtIndex:index];
return coerceObjectToString(object, defaultValue);
}
@end

View File

@@ -0,0 +1,147 @@
//
// JSONHelperTests.m
// MonsterCardsTests
//
// Created by Tom Hicks on 9/15/20.
// Copyright © 2020 Tom Hicks. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "JSONHelper.h"
@interface JSONHelperTests : XCTestCase
@end
@implementation JSONHelperTests {
NSString *_jsonStringKey;
NSString *_jsonStringValue;
NSString *_jsonStringFragment;
NSString *_jsonIntegerKey;
NSNumber *_jsonIntegerValue;
NSString *_jsonIntegerFragment;
}
NSString* escapeStringForJSON(NSString *unescaped) {
return [[unescaped stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"] stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
}
NSDictionary* readJSONDictionaryFromString(NSString *jsonString) {
NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonRoot = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
if (![jsonRoot isKindOfClass:[NSDictionary class]]) {
return nil;
} else {
return jsonRoot;
}
}
NSArray* readJSONArrayFromString(NSString *jsonString) {
NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSArray *jsonRoot = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
if (![jsonRoot isKindOfClass:[NSArray class]]) {
return nil;
} else {
return jsonRoot;
}
}
- (void)setUp {
_jsonStringKey = @"my_string";
_jsonStringValue = @"Hello, World!";
_jsonStringFragment = [NSString stringWithFormat:@"\"%@\":\"%@\"", escapeStringForJSON(_jsonStringKey), escapeStringForJSON(_jsonStringValue)];
_jsonIntegerKey = @"my_int";
_jsonIntegerValue = @12345;
_jsonIntegerFragment = [NSString stringWithFormat:@"\"%@\":%@", escapeStringForJSON(_jsonIntegerKey), [_jsonIntegerValue stringValue]];
}
- (void)tearDown {
}
#pragma mark - Strings in Dictionaries
- (void)testReadStringFromDictionaryReturnsNilIfKeyNotPresent {
NSString *jsonString = [NSString stringWithFormat:@"{%@}", _jsonIntegerFragment];
NSDictionary *jsonRoot = readJSONDictionaryFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromDictionary:jsonRoot forKey:_jsonStringKey];
XCTAssertNil(readString);
}
- (void)testReadStringFromDictionaryWithDefaultReturnsDefaultIfKeyNotPresent {
NSString *jsonString = [NSString stringWithFormat:@"{%@}", _jsonIntegerFragment];
NSDictionary *jsonRoot = readJSONDictionaryFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromDictionary:jsonRoot forKey:_jsonStringKey withDefaultValue:_jsonStringValue];
XCTAssertEqualObjects(_jsonStringValue, readString);
}
- (void) testReadStringFromDictionaryReturnsCorrectValue {
NSString *jsonString = [NSString stringWithFormat:@"{%@}", _jsonStringFragment];
NSDictionary *jsonRoot = readJSONDictionaryFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromDictionary:jsonRoot forKey:_jsonStringKey];
XCTAssertEqualObjects(_jsonStringValue, readString);
}
- (void)testReadStringFromDictionaryWithDefaultReturnsCorrectValue {
NSString *jsonString = [NSString stringWithFormat:@"{%@}", _jsonStringFragment];
NSDictionary *jsonRoot = readJSONDictionaryFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromDictionary:jsonRoot forKey:_jsonStringKey withDefaultValue:@"Some other string"];
XCTAssertEqualObjects(_jsonStringValue, readString);
}
- (void) testReadStringFromDictionaryReturnsNilIfWrongType {
NSString *jsonString = [NSString stringWithFormat:@"{\"%@\":%@}", _jsonStringKey, _jsonIntegerValue];
NSDictionary *jsonRoot = readJSONDictionaryFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromDictionary:jsonRoot forKey:_jsonStringKey];
XCTAssertNil(readString);
}
#pragma mark - Strings in Arrays
- (void)testReadStringFromArrayReturnsNilIfNotAString {
NSString *jsonString = [NSString stringWithFormat:@"[%@]", _jsonIntegerValue];
NSArray *jsonRoot = readJSONArrayFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromArray:jsonRoot forIndex:0];
XCTAssertNil(readString);
}
- (void)testReadStringFromArrayWithDefaultReturnsDefaultValueIfNotAString {
NSString *jsonString = [NSString stringWithFormat:@"[%@]", _jsonIntegerValue];
NSArray *jsonRoot = readJSONArrayFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromArray:jsonRoot forIndex:0 withDefaultValue:_jsonStringValue];
XCTAssertEqualObjects(_jsonStringValue, readString);
}
- (void)testReadStringFromArrayThrowsIfIndexOutOfRange {
// TODO: Decide if this should throw or return nil
NSString *jsonString = @"[]";
NSArray *jsonRoot = readJSONArrayFromString(jsonString);
XCTAssertNotNil(jsonRoot);
XCTAssertThrows([JSONHelper readStringFromArray:jsonRoot forIndex:0]);
XCTAssertThrows([JSONHelper readStringFromArray:jsonRoot forIndex:-1]);
}
- (void)testReadStringFromArrayReturnsCorrectValue {
NSString *jsonString = [NSString stringWithFormat:@"[\"%@\"]", _jsonStringValue];
NSArray *jsonRoot = readJSONArrayFromString(jsonString);
XCTAssertNotNil(jsonRoot);
NSString *readString = [JSONHelper readStringFromArray:jsonRoot forIndex:0];
XCTAssertEqualObjects(_jsonStringValue, readString);
}
@end