Skip to content

Commit

Permalink
Added Tag model and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Duckett committed Jun 16, 2012
1 parent f179453 commit 7f19501
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 15 deletions.
30 changes: 20 additions & 10 deletions Sculptour.xcodeproj/project.pbxproj
Expand Up @@ -112,13 +112,16 @@
22A5640B158D298600A2AB3E /* 54.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 22A563E7158D1C8400A2AB3E /* 54.jpg */; };
22A5640C158D298600A2AB3E /* 67.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 22A563E8158D1C8400A2AB3E /* 67.jpg */; };
22A5640D158D298600A2AB3E /* 73.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 22A563E9158D1C8400A2AB3E /* 73.jpg */; };
22A56426158D40A700A2AB3E /* Tag.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A56425158D40A700A2AB3E /* Tag.m */; };
22A56427158D40A700A2AB3E /* Tag.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A56425158D40A700A2AB3E /* Tag.m */; };
22A56428158D40A700A2AB3E /* Tag.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A56425158D40A700A2AB3E /* Tag.m */; };
22A5642B158D40A800A2AB3E /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A5642A158D40A800A2AB3E /* Work.m */; };
22A5642C158D40A800A2AB3E /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A5642A158D40A800A2AB3E /* Work.m */; };
22A5642D158D40A800A2AB3E /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A5642A158D40A800A2AB3E /* Work.m */; };
22A59A6A158CDD37007D2FA1 /* CMJsonIngest.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A69158CDD37007D2FA1 /* CMJsonIngest.m */; };
22A59A6B158CDD37007D2FA1 /* CMJsonIngest.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A69158CDD37007D2FA1 /* CMJsonIngest.m */; };
22A59A6D158CE295007D2FA1 /* harlow.json in Resources */ = {isa = PBXBuildFile; fileRef = 22A59A6C158CE295007D2FA1 /* harlow.json */; };
22A59A6E158CE295007D2FA1 /* harlow.json in Resources */ = {isa = PBXBuildFile; fileRef = 22A59A6C158CE295007D2FA1 /* harlow.json */; };
22A59A71158CE69C007D2FA1 /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A70158CE69C007D2FA1 /* Work.m */; };
22A59A72158CE69C007D2FA1 /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A70158CE69C007D2FA1 /* Work.m */; };
22A59A73158CE69C007D2FA1 /* Work.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A70158CE69C007D2FA1 /* Work.m */; };
22A59A80158CE7E9007D2FA1 /* TestJsonIngest.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59A7F158CE7E9007D2FA1 /* TestJsonIngest.m */; };
22A59A82158CE8D9007D2FA1 /* TestJson.json in Resources */ = {isa = PBXBuildFile; fileRef = 22A59A81158CE8D9007D2FA1 /* TestJson.json */; };
22A59AA2158CEDA3007D2FA1 /* CMAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A59AA1158CEDA3007D2FA1 /* CMAppDelegate.m */; };
Expand Down Expand Up @@ -319,11 +322,13 @@
22A563E7158D1C8400A2AB3E /* 54.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 54.jpg; sourceTree = "<group>"; };
22A563E8158D1C8400A2AB3E /* 67.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 67.jpg; sourceTree = "<group>"; };
22A563E9158D1C8400A2AB3E /* 73.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 73.jpg; sourceTree = "<group>"; };
22A56424158D40A600A2AB3E /* Tag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Tag.h; sourceTree = "<group>"; };
22A56425158D40A700A2AB3E /* Tag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Tag.m; sourceTree = "<group>"; };
22A56429158D40A700A2AB3E /* Work.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Work.h; sourceTree = "<group>"; };
22A5642A158D40A800A2AB3E /* Work.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Work.m; sourceTree = "<group>"; };
22A59A68158CDD37007D2FA1 /* CMJsonIngest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMJsonIngest.h; sourceTree = "<group>"; };
22A59A69158CDD37007D2FA1 /* CMJsonIngest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CMJsonIngest.m; sourceTree = "<group>"; };
22A59A6C158CE295007D2FA1 /* harlow.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = harlow.json; sourceTree = "<group>"; };
22A59A6F158CE69C007D2FA1 /* Work.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Work.h; sourceTree = "<group>"; };
22A59A70158CE69C007D2FA1 /* Work.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Work.m; sourceTree = "<group>"; };
22A59A7F158CE7E9007D2FA1 /* TestJsonIngest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestJsonIngest.m; sourceTree = "<group>"; };
22A59A81158CE8D9007D2FA1 /* TestJson.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = TestJson.json; sourceTree = "<group>"; };
22A59AA0158CEDA3007D2FA1 /* CMAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMAppDelegate.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -530,10 +535,12 @@
isa = PBXGroup;
children = (
22A59AA7158CF7E0007D2FA1 /* Sculptour.xcdatamodeld */,
22A56429158D40A700A2AB3E /* Work.h */,
22A5642A158D40A800A2AB3E /* Work.m */,
22A56424158D40A600A2AB3E /* Tag.h */,
22A56425158D40A700A2AB3E /* Tag.m */,
2297C730158CB82F0073492A /* Image.h */,
2297C731158CB82F0073492A /* Image.m */,
22A59A6F158CE69C007D2FA1 /* Work.h */,
22A59A70158CE69C007D2FA1 /* Work.m */,
);
name = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -1160,7 +1167,6 @@
4C5F0547158CC82A009B77C4 /* CMCollectionGridViewController.m in Sources */,
4C5F0566158CE795009B77C4 /* CMWorkGridView.m in Sources */,
22A59A6A158CDD37007D2FA1 /* CMJsonIngest.m in Sources */,
22A59A71158CE69C007D2FA1 /* Work.m in Sources */,
22A59AA2158CEDA3007D2FA1 /* CMAppDelegate.m in Sources */,
4C6AF263158CFD99005E76FB /* CMWorkViewController_iPhone.m in Sources */,
4C6AF2A4158D162E005E76FB /* CMWorkDetailViewController_iPhone.m in Sources */,
Expand All @@ -1169,6 +1175,8 @@
4C4482AD158D25F4007CC4EC /* CMWorkCollectionViewController_iPhone.m in Sources */,
4C4482B2158D26B8007CC4EC /* CMMapViewController.m in Sources */,
4C4482B6158D28C8007CC4EC /* CMPlacemark.m in Sources */,
22A56426158D40A700A2AB3E /* Tag.m in Sources */,
22A5642B158D40A800A2AB3E /* Work.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1205,8 +1213,9 @@
2297C7B0158CBAAD0073492A /* MagicalRecord+Setup.m in Sources */,
2297C7B2158CBAAD0073492A /* MagicalRecord+ShorthandSupport.m in Sources */,
2297C7B4158CBAAD0073492A /* MagicalRecord.m in Sources */,
22A59A72158CE69C007D2FA1 /* Work.m in Sources */,
22A59AAA158CF7E0007D2FA1 /* Sculptour.xcdatamodeld in Sources */,
22A56427158D40A700A2AB3E /* Tag.m in Sources */,
22A5642C158D40A800A2AB3E /* Work.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -1247,9 +1256,10 @@
22B2D6B8158CC5E5004ADAEE /* CoreDataTest.m in Sources */,
22B2D773158CCF25004ADAEE /* CMDataCreater.m in Sources */,
22A59A6B158CDD37007D2FA1 /* CMJsonIngest.m in Sources */,
22A59A73158CE69C007D2FA1 /* Work.m in Sources */,
22A59A80158CE7E9007D2FA1 /* TestJsonIngest.m in Sources */,
22A59AAB158CF7E0007D2FA1 /* Sculptour.xcdatamodeld in Sources */,
22A56428158D40A700A2AB3E /* Tag.m in Sources */,
22A5642D158D40A800A2AB3E /* Work.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
25 changes: 25 additions & 0 deletions Sculptour/CMJsonIngest.m
Expand Up @@ -10,6 +10,7 @@

#import "Work.h"
#import "Image.h"
#import "Tag.h"

@implementation CMJsonIngest

Expand Down Expand Up @@ -87,6 +88,30 @@ -(void)ingestJsonWithFilename:(NSString *)filename {
[newWork addImagesObject:newImage];

}

// Handle tags
NSArray *tagsArray = [theDict objectForKey:@"tags"];
NSLog(@"tagsArray = %@", tagsArray);

// Iterate across the tags array
for (NSDictionary *tagDict in tagsArray) {

NSLog(@"tagDict = %@", tagDict);
NSLog(@"value = %@", [tagDict valueForKey:@"tag"]);

// See if there's already an existing tag with this name
NSArray *tags = [Tag MR_findByAttribute:@"name" withValue:[tagDict valueForKey:@"tag"]];
if ([tags count] == 0) {
// No tag currently exists, create a new one
Tag *newTag = [Tag MR_createEntity];
[newTag setName:[tagDict objectForKey:@"tag"]];
[newWork addTagsObject:newTag];
} else {
Tag *theTag = [tags objectAtIndex:0];
[newWork addTagsObject:theTag];
}

}

NSString *key;
for (key in theDict) {
Expand Down
Expand Up @@ -5,6 +5,10 @@
<attribute name="url" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="work" optional="YES" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="Work" inverseName="images" inverseEntity="Work" syncable="YES"/>
</entity>
<entity name="Tag" representedClassName="Tag" syncable="YES">
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="work" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Work" inverseName="tags" inverseEntity="Work" syncable="YES"/>
</entity>
<entity name="Work" representedClassName="Work" syncable="YES">
<attribute name="artist" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="collected" optional="YES" attributeType="Boolean" syncable="YES"/>
Expand All @@ -19,9 +23,11 @@
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="url" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="images" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Image" inverseName="work" inverseEntity="Image" syncable="YES"/>
<relationship name="tags" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Tag" inverseName="work" inverseEntity="Tag" syncable="YES"/>
</entity>
<elements>
<element name="Image" positionX="187" positionY="90" width="128" height="90"/>
<element name="Work" positionX="-63" positionY="-18" width="128" height="240"/>
<element name="Tag" positionX="205" positionY="282" width="128" height="75"/>
</elements>
</model>
27 changes: 27 additions & 0 deletions Sculptour/Tag.h
@@ -0,0 +1,27 @@
//
// Tag.h
// Sculptour
//
// Created by Tim Duckett on 16/06/2012.
// Copyright (c) 2012 Charismatic Megafauna Ltd. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Work;

@interface Tag : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSSet *work;
@end

@interface Tag (CoreDataGeneratedAccessors)

- (void)addWorkObject:(Work *)value;
- (void)removeWorkObject:(Work *)value;
- (void)addWork:(NSSet *)values;
- (void)removeWork:(NSSet *)values;

@end
18 changes: 18 additions & 0 deletions Sculptour/Tag.m
@@ -0,0 +1,18 @@
//
// Tag.m
// Sculptour
//
// Created by Tim Duckett on 16/06/2012.
// Copyright (c) 2012 Charismatic Megafauna Ltd. All rights reserved.
//

#import "Tag.h"
#import "Work.h"


@implementation Tag

@dynamic name;
@dynamic work;

@end
20 changes: 17 additions & 3 deletions Sculptour/TestJson.json
Expand Up @@ -9,7 +9,12 @@
"size": "Size 1",
"latitude": 1.23456,
"longitude": 9.8765,
"image":"1"
"image":"1",
"tags": [
{
"tag": "foo"
}
]
},
{
"artist": "Artist 2",
Expand All @@ -21,7 +26,8 @@
"size": "Size 2",
"latitude": null,
"longitude": null,
"image":"2"
"image":"2",
"tags": []
},
{
"artist": "Artist 3",
Expand All @@ -33,6 +39,14 @@
"size": "Size 3",
"latitude": null,
"longitude": null,
"image": null
"image": null,
"tags": [
{
"tag": "bar"
},
{
"tag": "foo"
}
]
}
]
8 changes: 7 additions & 1 deletion Sculptour/Work.h
Expand Up @@ -9,7 +9,7 @@
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class Image;
@class Image, Tag;

@interface Work : NSManagedObject

Expand All @@ -26,6 +26,7 @@
@property (nonatomic, retain) NSString * title;
@property (nonatomic, retain) NSString * url;
@property (nonatomic, retain) NSSet *images;
@property (nonatomic, retain) NSSet *tags;
@end

@interface Work (CoreDataGeneratedAccessors)
Expand All @@ -35,4 +36,9 @@
- (void)addImages:(NSSet *)values;
- (void)removeImages:(NSSet *)values;

- (void)addTagsObject:(Tag *)value;
- (void)removeTagsObject:(Tag *)value;
- (void)addTags:(NSSet *)values;
- (void)removeTags:(NSSet *)values;

@end
2 changes: 2 additions & 0 deletions Sculptour/Work.m
Expand Up @@ -8,6 +8,7 @@

#import "Work.h"
#import "Image.h"
#import "Tag.h"


@implementation Work
Expand All @@ -25,5 +26,6 @@ @implementation Work
@dynamic title;
@dynamic url;
@dynamic images;
@dynamic tags;

@end
90 changes: 89 additions & 1 deletion Tests/TestJsonIngest.m
Expand Up @@ -9,6 +9,7 @@
#import <GHUnitIOS/GHUnit.h>
#import "Work.h"
#import "Image.h"
#import "Tag.h"

#import "CMDataCreater.h"
#import "CMJsonIngest.h"
Expand Down Expand Up @@ -50,7 +51,7 @@ -(void)testJson {
NSError *error;
self.jsonArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];

GHAssertNotNil(self.jsonArray, @"is nil, should not be nil");
GHAssertNotNil(self.jsonArray, @"is nil: got error %@", error);

int jsonArrayCount = [self.jsonArray count];
GHAssertEquals(jsonArrayCount, 3, @"expected 3 elements, got %d", jsonArrayCount);
Expand Down Expand Up @@ -198,4 +199,91 @@ -(void)testPresenceOfImages {

}

-(void)testCreationOfTags {

CMJsonIngest *ingester = [[CMJsonIngest alloc] init];

[ingester ingestJsonWithFilename:@"TestJson"];

Work *workOne = [Work MR_findFirstByAttribute:@"artist" withValue:@"Artist 1"];
GHAssertNotNil(workOne, @"workOne was not found");

// Given the test JSON
// When I ingest the JSON
// Then the first work should have one tag
// And the tag name should be "foo"

NSSet *tags = workOne.tags;
NSArray *tagsArray = [tags allObjects];
int tagsCount = [tagsArray count];
GHAssertEquals(tagsCount, 1, @"expected 1 tag, got %d", tagsCount);

Tag *theTag = [tagsArray objectAtIndex:0];
GHAssertEqualStrings(theTag.name, @"foo", @"expected tag.name = foo, got %@", theTag.name);

// Given the test JSON
// When I ingest the JSON
// Then the second work should have no tags

Work *workTwo = [Work MR_findFirstByAttribute:@"artist" withValue:@"Artist 2"];
GHAssertNotNil(workTwo, @"workTwo was not found");

NSSet *workTwoTags = workTwo.tags;
NSArray *workTwoTagsArray = [workTwoTags allObjects];
int workTwoTagCount = [workTwoTagsArray count];
GHAssertEquals(workTwoTagCount, 0, @"expected 0 tag, got %d", tagsCount);

// Given the test JSON
// When I ingest the JSON
// Then the third work should have two tags
// And the first tag should be foo
// And the second tag should be bar

Work *workThree = [Work MR_findFirstByAttribute:@"artist" withValue:@"Artist 3"];
GHAssertNotNil(workThree, @"workThree was not found");

NSSet *workThreeTags = workThree.tags;
NSArray *workThreeTagsArray = [workThreeTags allObjects];
int workThreeTagCount = [workThreeTagsArray count];
GHAssertEquals(workThreeTagCount, 2, @"expected 0 tag, got %d", tagsCount);

NSInteger fooIndex = [workThreeTagsArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
Tag *theTag = (Tag *)obj;
return ([theTag.name isEqualToString:@"foo"]);
}];

GHAssertNotEquals(NSNotFound, fooIndex, @"should have found a foo tag");

NSInteger barIndex = [workThreeTagsArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
Tag *theTag = (Tag *)obj;
return ([theTag.name isEqualToString:@"bar"]);
}];

GHAssertNotEquals(NSNotFound, barIndex, @"should have found a bar tag");

// Given the test JSON
// When I ingest the JSON
// Then the tag "foo" should have two Works
// And the tag "bar" should have one Work

NSArray *tagFooArray = [Tag MR_findByAttribute:@"name" withValue:@"foo"];
int tagFooArrayCount = [tagFooArray count];
GHAssertEquals(tagFooArrayCount, 1, @"there should be 1 tagFoo, got %d", tagFooArrayCount);

Tag *fooTag = [tagFooArray objectAtIndex:0];
NSSet *fooWorksSet = fooTag.work;
int fooWorksCount = [fooWorksSet count];
GHAssertEquals(fooWorksCount, 2, @"foo should have 2 works, got %d", fooWorksCount);

NSArray *tagBarArray = [Tag MR_findByAttribute:@"name" withValue:@"bar"];
int tagBarArrayCount = [tagBarArray count];
GHAssertEquals(tagBarArrayCount, 1, @"there should be 1 tagBars, got %d", tagFooArrayCount);

Tag *barTag = [tagBarArray objectAtIndex:0];
NSSet *barWorksSet = barTag.work;
int barWorksCount = [barWorksSet count];
GHAssertEquals(barWorksCount, 1, @"bar should have 1 work, got %d", fooWorksCount);

}

@end

0 comments on commit 7f19501

Please sign in to comment.