ActiveResourceKit  v1.2 (498.0)
 All Classes Files Functions Variables Typedefs Enumerator Properties Macros Pages
IncrementalStoreTests.m
Go to the documentation of this file.
1 // ActiveResourceKitTests IncrementalStoreTests.m
2 //
3 // Copyright © 2012, Roy Ratcliffe, Pioneering Software, United Kingdom
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the “Software”), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EITHER
16 // EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
18 // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
19 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 // DEALINGS IN THE SOFTWARE.
22 //
23 //------------------------------------------------------------------------------
24 
26 
27 // for ARIncrementalStore
28 #import "ARIncrementalStore.h"
29 
30 // for ActiveResourceKitTestsBaseURL
32 
33 @implementation IncrementalStoreTests
34 
35 @synthesize context = _context;
36 
37 - (NSPersistentStoreCoordinator *)coordinator
38 {
39  return [[self context] persistentStoreCoordinator];
40 }
41 
42 - (NSManagedObjectModel *)model
43 {
44  return [[self coordinator] managedObjectModel];
45 }
46 
47 /*!
48  * @brief Builds a Core Data stack. @details Loads the data model, initialises
49  * the coordinator with the model, adds the incremental store to the
50  * coordinator, finally attaches the coordinator to a new main-queue context.
51  */
52 - (void)setUp
53 {
54  // Where is the data model? Does it exist in the main bundle? No. The binary
55  // at /Applications/Xcode.app/Contents/Developer/Tools/otest executes the
56  // tests. Instead, look for the data model within the "octest" bundle from
57  // where the test launcher finds this test class.
58  NSBundle *bundle = [NSBundle bundleForClass:[self class]];
59  NSURL *modelURL = [bundle URLForResource:@"ActiveResourceKitTests" withExtension:@"momd"];
60  NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
61  NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
62 
63  NSError *__autoreleasing error = nil;
64  NSPersistentStore *store = [coordinator addPersistentStoreWithType:[ARIncrementalStore storeType]
65  configuration:nil
66  URL:ActiveResourceKitTestsBaseURL()
67  options:nil
68  error:&error];
69  STAssertNotNil(store, nil);
70  STAssertNil(error, nil);
71 
72  NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
73  [context setPersistentStoreCoordinator:coordinator];
74  [self setContext:context];
75 }
76 
77 - (void)testPeople
78 {
79  // Fetch all the people. Assert their non-nil names. All names are non-nil
80  // including people with no names. People with no names have name equal to
81  // null, where null is not exactly nil albeit equivalent depending its
82  // interpretation.
83  NSError *__autoreleasing error = nil;
84  NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
85  NSArray *people = [[self context] executeFetchRequest:request error:&error];
86  for (NSManagedObject *person in people)
87  {
88  NSString *name = [person valueForKey:@"name"];
89  NSLog(@"person named %@", name);
90  }
91 }
92 
93 - (void)testPosts
94 {
95  NSError *__autoreleasing error = nil;
96  NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Post"];
97  NSArray *posts = [[self context] executeFetchRequest:request error:&error];
98  for (NSManagedObject *post in posts)
99  {
100  NSString *title = [post valueForKey:@"title"];
101  NSManagedObject *person = [post valueForKey:@"poster"];
102  NSString *name = [person valueForKey:@"name"];
103  NSLog(@"post entitled %@ by %@", title, name);
104  }
105 }
106 
108 {
109  NSError *__autoreleasing error = nil;
110  NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Post"];
111  NSArray *posts = [[self context] executeFetchRequest:request error:&error];
112  for (NSManagedObject *post in posts)
113  {
114  NSString *title = [post valueForKey:@"title"];
115  NSLog(@"post entitled %@", title);
116  STAssertNotNil(title, nil);
117  for (NSManagedObject *comment in [post valueForKey:@"comments"])
118  {
119  NSString *text = [comment valueForKey:@"text"];
120  NSLog(@"%@", text);
121  STAssertNotNil(text, nil);
122  }
123  }
124 }
125 
127 {
128  NSError *__autoreleasing error = nil;
129  NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:[self context]];
130  [person setValue:@"Roy Ratcliffe" forKey:@"name"];
131  BOOL yes = [[self context] save:&error];
132  STAssertNotNil(person, nil);
133  STAssertTrue(yes, nil);
134  STAssertNil(error, nil);
135 
136  [[self context] deleteObject:person];
137  yes = [[self context] save:&error];
138  STAssertTrue(yes, nil);
139  STAssertNil(error, nil);
140 }
141 
143 {
144  NSError *__autoreleasing error = nil;
145 
146  NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:[self context]];
147  BOOL yes = [[self context] save:&error];
148  STAssertNotNil(person, nil);
149  STAssertTrue(yes, nil);
150  STAssertNil(error, nil);
151 
152  [person setValue:@"Roy Ratcliffe" forKey:@"name"];
153  yes = [[self context] save:&error];
154  STAssertTrue(yes, nil);
155  STAssertNil(error, nil);
156 }
157 
158 /*!
159  * @brief Tests one post to many comments association
160  * @details What happens when you instantiate two entities and wire them up entirely
161  * at the client side first? Test it! Create a post with one
162  * comment. Construct the post, comment and their relationship within the
163  * client at first. Then save the context in order to transfer the objects
164  * and their relationship to the remote server. Thereafter, throw away the
165  * comment and refetch the comment by dereferencing the post's "comments"
166  * relationship.
167  */
169 {
170  NSError *__autoreleasing error = nil;
171 
172  NSManagedObject *post = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:[self context]];
173  NSManagedObject *comment = [NSEntityDescription insertNewObjectForEntityForName:@"Comment" inManagedObjectContext:[self context]];
174  STAssertNotNil(post, nil);
175  STAssertNotNil(comment, nil);
176 
177  // Set up attributes for the post and the comment.
178  [post setValue:@"De finibus bonorum et malorum" forKey:@"title"];
179  [post setValue:@"Non eram nescius…" forKey:@"body"];
180  [comment setValue:@"Quae cum dixisset…" forKey:@"text"];
181 
182  // Form the one-post-to-many-comments association.
183  [comment setValue:post forKey:@"post"];
184 
185  // Send it all to the server.
186  STAssertTrue([[self context] save:&error], nil);
187  STAssertNil(error, nil);
188 
189  [[[[self coordinator] persistentStores] objectAtIndex:0] evictAllResources];
190  [[post managedObjectContext] refreshObject:post mergeChanges:NO];
191  NSMutableArray *comments = [NSMutableArray array];
192  for (NSManagedObject *comment in [post valueForKey:@"comments"])
193  {
194  [comments addObject:[comment valueForKey:@"text"]];
195  }
196  STAssertFalse([comments count] == 0, nil);
197  STAssertTrue([[comments objectAtIndex:0] rangeOfString:@"Quae cum dixisset…"].location != NSNotFound, nil);
198 }
199 
201 {
202  NSError *__autoreleasing error = nil;
203 
204  // Send the post to the server. This results in one POST request.
205  NSManagedObject *post = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:[self context]];
206  [post setValue:@"title" forKey:@"title"];
207  [post setValue:@"body" forKey:@"body"];
208  STAssertNotNil(post, nil);
209  STAssertTrue([[self context] save:&error], nil);
210  STAssertNil(error, nil);
211 
212  // Send the comment to the server. This results in a second POST request.
213  NSManagedObject *comment = [NSEntityDescription insertNewObjectForEntityForName:@"Comment" inManagedObjectContext:[self context]];
214  [comment setValue:@"text" forKey:@"text"];
215  STAssertNotNil(comment, nil);
216  STAssertTrue([[self context] save:&error], nil);
217  STAssertNil(error, nil);
218 
219  // Send the relationship to the server. This results in a GET request
220  // for the comment and for the post. This always happens because
221  // insertion of objects always evicts the resource from the resource
222  // cache. The server alters attributes when creating and updating. POST
223  // requests therefore desynchronise server and client. Core Data then
224  // asks for all the post's comments, another GET request. Finally, a PUT
225  // request for the comment saves the new association.
226  //
227  // As a side effect, an unwanted one, Core Data also marks the post as
228  // modified and issues an update for it.
229  [comment setValue:post forKey:@"post"];
230  STAssertTrue([[self context] save:&error], nil);
231  STAssertNil(error, nil);
232 
233  [[[[self coordinator] persistentStores] objectAtIndex:0] evictAllResources];
234  [[post managedObjectContext] refreshObject:post mergeChanges:NO];
235  NSMutableArray *comments = [NSMutableArray array];
236  for (NSManagedObject *comment in [post valueForKey:@"comments"])
237  {
238  // Assert that the comment's "post relationship" references back to the
239  // post. This would fail if the relationship resolver only searches
240  // attributes for the post identifier, because loading attributes splits
241  // off the prefix parameters which, in this case, include the post
242  // identifier (post_id). Prefix parameters live in the prefix options,
243  // rather than the attributes. Such play a special role. They carry the
244  // substitution values for the resource's prefix parameters.
245  NSManagedObject *commentPost = [comment valueForKey:@"post"];
246  STAssertEqualObjects(post, commentPost, nil);
247 
248  [comments addObject:[comment valueForKey:@"text"]];
249  }
250  STAssertFalse([comments count] == 0, nil);
251  STAssertTrue([[comments objectAtIndex:0] rangeOfString:@"text"].location != NSNotFound, nil);
252 }
253 
254 /*!
255  * @brief Tests resource attributes carrying NSNull values.
256  * @details Nulls become nils within managed objects. All missing properties
257  * within managed objects become nils when accessed. The following tests that
258  * the nulls within resources become nils when manifested by Core Data.
259  */
261 {
262  NSError *__autoreleasing error = nil;
263 
264  NSManagedObject *post = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:[self context]];
265  STAssertNotNil(post, nil);
266  STAssertTrue([[self context] save:&error], nil);
267  STAssertNil(error, nil);
268 
269  NSManagedObject *comment = [NSEntityDescription insertNewObjectForEntityForName:@"Comment" inManagedObjectContext:[self context]];
270  STAssertNotNil(comment, nil);
271  STAssertTrue([[self context] save:&error], nil);
272  STAssertNil(error, nil);
273 
274  [comment setValue:post forKey:@"post"];
275  STAssertTrue([[self context] save:&error], nil);
276  STAssertNil(error, nil);
277 
278  [[[[self coordinator] persistentStores] objectAtIndex:0] evictAllResources];
279  [[post managedObjectContext] refreshObject:post mergeChanges:NO];
280  NSMutableArray *comments = [NSMutableArray array];
281  for (NSManagedObject *comment in [post valueForKey:@"comments"])
282  {
283  NSString *text = [comment valueForKey:@"text"];
284  if (text)
285  {
286  [comments addObject:text];
287  }
288  STAssertNil(text, nil);
289 
290  // The comment has no text (nil) but it does have a valid back reference.
291  NSManagedObject *commentPost = [comment valueForKey:@"post"];
292  STAssertEqualObjects(post, commentPost, nil);
293  }
294  STAssertTrue([comments count] == 0, nil);
295 }
296 
297 @end