diff --git a/MonsterCards.xcodeproj/project.pbxproj b/MonsterCards.xcodeproj/project.pbxproj index e6ca624..3e50f57 100644 --- a/MonsterCards.xcodeproj/project.pbxproj +++ b/MonsterCards.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ E20D032E25031BEF00FB6E43 /* CollectionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D032D25031BEF00FB6E43 /* CollectionsViewController.m */; }; E20D033125031BFD00FB6E43 /* DashboardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E20D033025031BFD00FB6E43 /* DashboardViewController.m */; }; E2532E8925038DE100CA4CBA /* StringHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E2532E8825038DE100CA4CBA /* StringHelper.m */; }; + E2592B8D250D6B8100906A40 /* EditMonsterViewControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2592B8C250D6B8100906A40 /* EditMonsterViewControllerTests.m */; }; E25BD5F5250352C4007B04EF /* Monster.m in Sources */ = {isa = PBXBuildFile; fileRef = E25BD5F4250352C4007B04EF /* Monster.m */; }; E25BD5F8250368A8007B04EF /* SavingThrow.m in Sources */ = {isa = PBXBuildFile; fileRef = E25BD5F7250368A8007B04EF /* SavingThrow.m */; }; E25BD5FB250369D7007B04EF /* Skill.m in Sources */ = {isa = PBXBuildFile; fileRef = E25BD5FA250369D7007B04EF /* Skill.m */; }; @@ -82,6 +83,7 @@ E2532E8725038DE100CA4CBA /* StringHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringHelper.h; sourceTree = ""; }; E2532E8825038DE100CA4CBA /* StringHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StringHelper.m; sourceTree = ""; }; E2591EB62509DD4900B396FD /* EditableFormFieldDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EditableFormFieldDelegate.h; sourceTree = ""; }; + E2592B8C250D6B8100906A40 /* EditMonsterViewControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EditMonsterViewControllerTests.m; sourceTree = ""; }; E25BD5F3250352C4007B04EF /* Monster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Monster.h; sourceTree = ""; }; E25BD5F4250352C4007B04EF /* Monster.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Monster.m; sourceTree = ""; }; E25BD5F6250368A8007B04EF /* SavingThrow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SavingThrow.h; sourceTree = ""; }; @@ -229,6 +231,14 @@ path = Helpers; sourceTree = ""; }; + E2592B8B250D6B6000906A40 /* Views */ = { + isa = PBXGroup; + children = ( + E2592B8C250D6B8100906A40 /* EditMonsterViewControllerTests.m */, + ); + path = Views; + sourceTree = ""; + }; E2D3E3B12508C2FE0052A8EC /* FormFields */ = { isa = PBXGroup; children = ( @@ -284,6 +294,7 @@ E2F7249425005E8A007D87ED /* MonsterCardsTests */ = { isa = PBXGroup; children = ( + E2592B8B250D6B6000906A40 /* Views */, E2FD91E225047C1D00D5E935 /* Models */, E2F7249525005E8A007D87ED /* MonsterCardsTests.m */, E2F7249725005E8A007D87ED /* Info.plist */, @@ -580,6 +591,7 @@ files = ( E2FD91EA250493C000D5E935 /* LanguageTests.m in Sources */, E2FD91E82504832A00D5E935 /* DamageTypeTests.m in Sources */, + E2592B8D250D6B8100906A40 /* EditMonsterViewControllerTests.m in Sources */, E2FD91EC250496B000D5E935 /* SavingThrowTests.m in Sources */, E2FD91E6250481F300D5E935 /* ActionTests.m in Sources */, E2ECA8F52504BAAD00C1FFA5 /* MonsterTests.m in Sources */, diff --git a/MonsterCards/Models/Monster.m b/MonsterCards/Models/Monster.m index a6d5433..d205b39 100644 --- a/MonsterCards/Models/Monster.m +++ b/MonsterCards/Models/Monster.m @@ -74,6 +74,7 @@ self.name = [jsonRoot objectForKey:@"name"] ?: @""; self.size = [jsonRoot objectForKey:@"size"] ?: @""; self.type = [jsonRoot objectForKey:@"type"] ?: @""; + self.subtype = [jsonRoot objectForKey:@"tag"] ?: @""; return self; } @@ -336,6 +337,7 @@ self.name = monster.name; self.size = monster.size; self.type = monster.type; + self.subtype = monster.subtype; } @end diff --git a/MonsterCards/Views/EditMonsterViewController.m b/MonsterCards/Views/EditMonsterViewController.m index 54409f7..abdd8a3 100644 --- a/MonsterCards/Views/EditMonsterViewController.m +++ b/MonsterCards/Views/EditMonsterViewController.m @@ -59,7 +59,16 @@ // * Subtype // * Alignment - return 3; + return 4; +} + +- (EditableShortStringTableViewCell*) makeShortStringCellFromCell:(UITableViewCell*)cell { + if (cell == nil || ![cell isKindOfClass:[EditableShortStringTableViewCell class]]) { + // TODO: Figure out why this doesn't create a cell with a text field. + return [[EditableShortStringTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"EditableShortString"]; + } else { + return (EditableShortStringTableViewCell*)cell; + } } - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { @@ -70,10 +79,7 @@ case 0: switch (indexPath.row) { case 0: - shortStringCell = [self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]; - if (shortStringCell == nil) { - shortStringCell = [[EditableShortStringTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"EditableShortString"]; - } + shortStringCell = [self makeShortStringCellFromCell:[self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]]; shortStringCell.delegate = self; shortStringCell.identifier = @"monster.name"; // TODO: make these use setters on EditableShortStringTableViewCell @@ -81,10 +87,7 @@ shortStringCell.textField.placeholder = NSLocalizedString(@"Name", @"Placeholder text for the name of a monster or NPC."); return shortStringCell; case 1: - shortStringCell = [self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]; - if (shortStringCell == nil) { - shortStringCell = [[EditableShortStringTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"EditableShortString"]; - } + shortStringCell = [self makeShortStringCellFromCell:[self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]]; shortStringCell.delegate = self; shortStringCell.identifier = @"monster.size"; // TODO: make these use setters on EditableShortStringTableViewCell @@ -92,16 +95,20 @@ shortStringCell.textField.placeholder = NSLocalizedString(@"Size", @"Placehodler text for the size of a monster or NPC."); return shortStringCell; case 2: - shortStringCell = [self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]; - if (shortStringCell == nil) { - shortStringCell = [[EditableShortStringTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"EditableShortString"]; - } + shortStringCell = [self makeShortStringCellFromCell:[self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]]; shortStringCell.delegate = self; shortStringCell.identifier = @"monster.type"; // TODO: make these use setters on EditableShortStringTableViewCell shortStringCell.textField.text = self.editingMonster.type; shortStringCell.textField.placeholder = NSLocalizedString(@"Type", @"Placehodler text for the type of a monster or NPC."); return shortStringCell; + case 3: + shortStringCell = [self makeShortStringCellFromCell:[self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]]; + shortStringCell.delegate = self; + shortStringCell.identifier = @"monster.subtype"; + shortStringCell.textField.text = self.editingMonster.subtype; + shortStringCell.textField.placeholder = NSLocalizedString(@"Subtype", @"Placeholder text for the subtype of a monster or NPC."); + return shortStringCell; } break; } @@ -119,6 +126,8 @@ self.editingMonster.size = (NSString*)value; } else if ([@"monster.type" isEqualToString:identifier]) { self.editingMonster.type = (NSString*)value; + } else if ([@"monster.subtype" isEqualToString:identifier]) { + self.editingMonster.subtype = (NSString*)value; } } } diff --git a/MonsterCardsTests/Models/MonsterTests.m b/MonsterCardsTests/Models/MonsterTests.m index 0bfef45..b4f83eb 100644 --- a/MonsterCardsTests/Models/MonsterTests.m +++ b/MonsterCardsTests/Models/MonsterTests.m @@ -25,7 +25,7 @@ - (void)setUp { _context = nil; _monster = [[Monster alloc] initWithContext:_context]; - _jsonString = @"{\"name\":\"Acolyte\",\"size\":\"medium\",\"type\":\"humanoid\"}"; + _jsonString = @"{\"name\":\"Acolyte\",\"size\":\"medium\",\"type\":\"humanoid\",\"tag\":\"any race\"}"; _jsonData = [_jsonString dataUsingEncoding:NSUTF8StringEncoding]; } @@ -38,6 +38,7 @@ XCTAssertEqualObjects(@"", _monster.name); XCTAssertEqualObjects(@"", _monster.size); XCTAssertEqualObjects(@"", _monster.type); + XCTAssertEqualObjects(@"", _monster.subtype); } - (void)testInitWithJSONString { @@ -47,6 +48,7 @@ XCTAssertEqualObjects(@"Acolyte", _monster.name); XCTAssertEqualObjects(@"medium", _monster.size); XCTAssertEqualObjects(@"humanoid", _monster.type); + XCTAssertEqualObjects(@"any race", _monster.subtype); } - (void)testInitWithEmptyJSONString { @@ -56,6 +58,7 @@ XCTAssertEqualObjects(@"", _monster.name); XCTAssertEqualObjects(@"", _monster.size); XCTAssertEqualObjects(@"", _monster.type); + XCTAssertEqualObjects(@"", _monster.subtype); } - (void)testInitWithJSONData { _monster = [[Monster alloc] initWithJSONData:_jsonData andContext:_context]; @@ -64,6 +67,7 @@ XCTAssertEqualObjects(@"Acolyte", _monster.name); XCTAssertEqualObjects(@"medium", _monster.size); XCTAssertEqualObjects(@"humanoid", _monster.type); + XCTAssertEqualObjects(@"any race", _monster.subtype); } - (void)testNameGetterAndSetter { @@ -84,6 +88,12 @@ XCTAssertEqualObjects(type, _monster.type); } +- (void)testSubtypeGetterAndSetter { + NSString *subtype = @"elf"; + _monster.subtype = subtype; + XCTAssertEqualObjects(subtype, _monster.subtype); +} + - (void)testCopyFromMonster { Monster *otherMonster = [[Monster alloc] initWithJSONString:_jsonString andContext:_context]; [_monster copyFromMonster:otherMonster]; @@ -92,6 +102,52 @@ XCTAssertEqualObjects(@"Acolyte", _monster.name); XCTAssertEqualObjects(@"medium", _monster.size); XCTAssertEqualObjects(@"humanoid", _monster.type); + XCTAssertEqualObjects(@"any race", _monster.subtype); +} + +- (void)testMetaWithNoFieldsSet { + + XCTAssertEqualObjects(@"", _monster.meta); +} + +- (void)testMetaWithSize { + _monster.size = @"large"; + XCTAssertEqualObjects(@"large", _monster.meta); +} + +- (void)testMetaWithType { + _monster.type = @"humanoid"; + XCTAssertEqualObjects(@"humanoid", _monster.meta); +} + +- (void)testMetaWithSizeAndType { + _monster.size = @"large"; + _monster.type = @"humanoid"; + XCTAssertEqualObjects(@"large humanoid", _monster.meta); +} + +- (void)testMetaWithSubtype { + _monster.subtype = @"elf"; + XCTAssertEqualObjects(@"(elf)", _monster.meta); +} + +- (void)testMetaWithSizeAndSubtype { + _monster.size = @"large"; + _monster.subtype = @"elf"; + XCTAssertEqualObjects(@"large (elf)", _monster.meta); +} + +- (void)testMetaWithTypeAndSubtype { + _monster.type = @"humanoid"; + _monster.subtype = @"elf"; + XCTAssertEqualObjects(@"humanoid (elf)", _monster.meta); +} + +- (void)testMetaWithSizeTypeAndSubtype { + _monster.size = @"large"; + _monster.type = @"humanoid"; + _monster.subtype = @"elf"; + XCTAssertEqualObjects(@"large humanoid (elf)", _monster.meta); } @end diff --git a/MonsterCardsTests/Views/EditMonsterViewControllerTests.m b/MonsterCardsTests/Views/EditMonsterViewControllerTests.m new file mode 100644 index 0000000..49c3cc2 --- /dev/null +++ b/MonsterCardsTests/Views/EditMonsterViewControllerTests.m @@ -0,0 +1,93 @@ +// +// EditMonsterViewControllerTests.m +// MonsterCardsTests +// +// Created by Tom Hicks on 9/12/20. +// Copyright © 2020 Tom Hicks. All rights reserved. +// + +#import +@import OCMockito; +@import OCHamcrest; +#import "EditMonsterViewController.h" +#import "AppDelegate.h" + +@interface EditMonsterViewControllerTests : XCTestCase + +@end + +@implementation EditMonsterViewControllerTests { + EditMonsterViewController *_viewController; + NSManagedObjectContext *_context; + AppDelegate *_appDelegate; + NSPersistentCloudKitContainer *_persistentContainer; + Monster *_monster; +} + +- (void)setUp { + _monster = mock([Monster class]); + _viewController = [[EditMonsterViewController alloc] init]; + _context = mock([NSManagedObjectContext class]); + _appDelegate = mock([AppDelegate class]); + _persistentContainer = mock([NSPersistentCloudKitContainer class]); + + UIApplication.sharedApplication.delegate = _appDelegate; +// ((AppDelegate*)UIApplication.sharedApplication.delegate).persistentContainer.viewContext = _context; +} + +- (void)tearDown { +} + +// UIViewController +// UITableViewDelegate +// UITableViewDataSource +// EditableShortStringDeletgate +// Monster *originalMonster +// UITableView *monsterTableView + +- (void)testRendersSubtypeCell { + UITableView *monstersTableView = mock([UITableView class]); + NSIndexPath *path = [NSIndexPath indexPathForRow:3 inSection:0]; + EditableShortStringTableViewCell *shortStringCell = [[EditableShortStringTableViewCell alloc] init]; + //mock([EditableShortStringTableViewCell class]); + UITextField *textField = [[UITextField alloc] init]; + shortStringCell.textField = textField; + + [given([monstersTableView dequeueReusableCellWithIdentifier:@"EditableShortString"]) willReturn:shortStringCell]; + + _monster.subtype = @"elf"; + _viewController.originalMonster = _monster; + _viewController.monsterTableView = monstersTableView; + [_viewController viewDidLoad]; + [_viewController viewWillAppear:NO]; + + UITableViewCell *cell = [_viewController tableView:monstersTableView cellForRowAtIndexPath:path]; + + XCTAssertNotNil(cell); + + XCTAssertTrue([cell isKindOfClass:[EditableShortStringTableViewCell class]]); + shortStringCell = (EditableShortStringTableViewCell*)cell; + XCTAssertEqualObjects(@"monster.subtype", shortStringCell.identifier); + XCTAssertEqualObjects(@"Subtype", shortStringCell.textField.placeholder); + XCTAssertEqualObjects(@"", shortStringCell.textField.text); + XCTAssertEqual(_viewController, shortStringCell.delegate); +} + +- (void)testEditingSubtype { + UIViewController *destinationVC = mock([UIViewController class]); + UIStoryboardSegue *segue = [UIStoryboardSegue segueWithIdentifier:@"SaveChanges" source:_viewController destination:destinationVC performHandler:^{}]; + + _monster = [[Monster alloc] initWithContext:_context]; + _monster.subtype = @"elf"; + _viewController.originalMonster = _monster; + [_viewController viewDidLoad]; + [_viewController viewWillAppear:NO]; + + [_viewController editableValueDidChange:@"newValue" forIdentifier:@"monster.subtype" andType:@"String"]; + + [_viewController prepareForSegue:segue sender:nil]; + + XCTAssertEqualObjects(@"newValue", _viewController.originalMonster.subtype); +} + +@end