ActiveResourceKit  v1.2 (498.0)
 All Classes Files Functions Variables Typedefs Enumerator Properties Macros Pages
ActiveResourceKitTests.m
Go to the documentation of this file.
1 // ActiveResourceKitTests ActiveResourceKitTests.m
2 //
3 // Copyright © 2011, 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 
28 
29 #import "Person.h"
30 
31 // for ARIDFromResponse
32 #import "Private.h"
33 
35 {
36  return [NSURL URLWithString:@RAILS_BASE_URL];
37 }
38 
39 //------------------------------------------------------------------------------
40 #pragma mark Person Class
41 //------------------------------------------------------------------------------
42 
43 @interface MyObject : ARService
44 @end
45 
46 @implementation MyObject
47 @end
48 
49 @interface Post : ARService
50 @end
51 
52 @implementation Post
53 @end
54 
55 @interface PostComment : ARService
56 @end
57 
58 @implementation PostComment
59 @end
60 
61 @implementation ActiveResourceKitTests
62 
63 - (void)setUp
64 {
65  post = [[Post alloc] initWithSite:ActiveResourceKitTestsBaseURL()];
66  postComment = [[PostComment alloc] initWithSite:[NSURL URLWithString:@"/posts/:post_id" relativeToURL:ActiveResourceKitTestsBaseURL()]];
67 
68  // You cannot use Comment as a class name. The CarbonCore framework (a
69  // CoreServices sub-framework) steals this symbol first. Apple has already
70  // polluted the namespace with a Comment type definition. So we will call it
71  // PostComment instead, meaning a comment on a post within a blog. However,
72  // by default, ARService will translate PostComment to post_comment when
73  // constructing the resource paths. There is an incongruence between
74  // Objective-C and Rails, unless Rails uses the same name of course. But the
75  // comments are just comments in the imaginary Rails application. Hence we
76  // need now to override the element name. This makes use of the lazy-getter
77  // approach to configuration. Setting it now overrides the default.
78  [postComment setElementName:@"comment"];
79 }
80 
82 {
83  Person *ryan = [[Person alloc] init];
84  [ryan setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:@"Ryan", @"first", @"Daigle", @"last", nil]];
85 
86  // At this point, service should be nil because nothing has as yet accessed the
87  // service lazily! The resource only exists in memory; hence not persisted, a
88  // new resource, a new record.
89  STAssertNil([ryan service], nil);
90  STAssertFalse([ryan persisted], nil);
91  STAssertTrue([ryan isNew], nil);
92  STAssertTrue([ryan isNewRecord], nil);
93 
94  // Use key-value coding to verify the contents of the active resource
95  // instance, albeit not yet persisted.
96  STAssertEqualObjects([ryan valueForKey:@"first"], @"Ryan", nil);
97  STAssertEqualObjects([ryan valueForKey:@"last"], @"Daigle", nil);
98 }
99 
101 {
102  // Start off with a very simple test. Just set up a resource. Load it with
103  // its site URL. Then ensure that the site property responds as it should,
104  // i.e. as an URL. This test exercises NSURL more than
105  // ARActiveResource. Never mind.
106  //
107  // Make sure that the site URL can accept “prefix parameters,” as Rails dubs
108  // them. This term refers to path elements beginning with a colon and
109  // followed by a regular-expression word. ActiveResourceKit substitutes
110  // these for actual parameters.
111  ARService *service = [[ARService alloc] init];
112  [service setSite:[NSURL URLWithString:@"http://user:password@localhost:3000/resources/:resource_id?x=y;a=b"]];
113  STAssertEqualObjects([[service site] scheme], @"http", nil);
114  STAssertEqualObjects([[service site] user], @"user", nil);
115  STAssertEqualObjects([[service site] password], @"password", nil);
116  STAssertEqualObjects([[service site] host], @"localhost", nil);
117  STAssertEqualObjects([[service site] port], [NSNumber numberWithInt:3000], nil);
118  STAssertEqualObjects([[service site] path], @"/resources/:resource_id", nil);
119  STAssertEqualObjects([[service site] query], @"x=y;a=b", nil);
120 }
121 
123 {
124  // Empty URL paths should become empty strings after parsing. This tests the
125  // Foundation frameworks implementation of an URL.
126  ARService *service = [[ARService alloc] init];
127  [service setSite:[NSURL URLWithString:@"http://user:password@localhost:3000"]];
128  STAssertEqualObjects([[service site] path], @"", nil);
129 }
130 
132 {
133  // Running the following piece of Ruby:
134  //
135  // require 'active_resource'
136  //
137  // class Resource < ActiveResource::Base
138  // self.prefix = '/resources/:resource_id'
139  // end
140  //
141  // p Resource.prefix(:resource_id => 1)
142  //
143  // gives you the following output:
144  //
145  // "/resources/1"
146  //
147  // The following test performs the same thing but using Objective-C.
148  //
149  // Note that the options can contain numbers and other objects. Method
150  // -[ARActiveResource prefixWithOptions:] places the “description” of the
151  // object answering to the prefix-parameter key (resource_id in this test
152  // case). Hence the options dictionary can contain various types answering
153  // to -[NSObject description], not just strings.
154  ARService *service = [[ARService alloc] init];
155  [service setPrefixSource:@"/resources/:resource_id"];
156  NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1] forKey:@"resource_id"];
157  NSString *prefix = [service prefixWithOptions:options];
158  STAssertEqualObjects(prefix, @"/resources/1", nil);
159 }
160 
162 {
163  // What about prefixes applied to nested resources? Note the importance of
164  // the trailing slash. Without it, the tests below fail because NSURL's
165  // implementation uses the trailing slash to differentiate between base URL
166  // with incorporated paths and additional subpaths.
167  ARService *resourceService = [[ARService alloc] initWithSite:[NSURL URLWithString:@"http://localhost/api/"] elementName:@"resource"];
168  ARService *subresourceService = [resourceService serviceForSubelementNamed:@"subresource"];
169  STAssertEqualObjects([resourceService prefixWithOptions:nil], @"/api/", nil);
170  STAssertEqualObjects([subresourceService prefixWithOptions:nil], @"/api/resources/:resource_id/", nil);
171 }
172 
174 {
175  ARService *service = [[ARService alloc] init];
176  [service setPrefixSource:@"/resources/:resource_id"];
177  NSString *prefix = [service prefixWithOptions:[NSDictionary dictionaryWithObject:@"some text" forKey:@"resource_id"]];
178  STAssertEqualObjects(prefix, @"/resources/some%20text", nil);
179 }
180 
182 {
183  STAssertEqualObjects([[[[Person alloc] init] serviceLazily] elementNameLazily], @"person", nil);
184 }
185 
187 {
188  STAssertEqualObjects([[[[Person alloc] init] serviceLazily] collectionNameLazily], @"people", nil);
189 }
190 
192 {
193  NSString *elementPath = [post elementPathForID:[NSNumber numberWithInt:1] prefixOptions:nil queryOptions:nil];
194  STAssertEqualObjects(elementPath, @"/posts/1.json", nil);
195 }
196 
198 {
199  NSDictionary *query = [NSDictionary dictionaryWithObject:@"value string" forKey:@"key string"];
200  NSString *elementPath = [post elementPathForID:[NSNumber numberWithInt:1] prefixOptions:nil queryOptions:query];
201  STAssertEqualObjects(elementPath, @"/posts/1.json?key%20string=value%20string", nil);
202 }
203 
205 {
206  NSString *newElementPath = [post newElementPathWithPrefixOptions:nil];
207  STAssertEqualObjects(newElementPath, @"/posts/new.json", nil);
208 }
209 
211 {
212  NSString *collectionPath = [post collectionPathWithPrefixOptions:nil queryOptions:nil];
213  STAssertEqualObjects(collectionPath, @"/posts.json", nil);
214 }
215 
217 {
219  STAssertEqualObjects([format extension], @"json", nil);
220  STAssertEqualObjects([format MIMEType], @"application/json", nil);
221 }
222 
224 {
225  NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:5] forKey:@"post_id"];
226  STAssertEqualObjects([postComment newElementPathWithPrefixOptions:options], @"/posts/5/comments/new.json", nil);
227  STAssertEqualObjects([postComment collectionPathWithPrefixOptions:options queryOptions:nil], @"/posts/5/comments.json", nil);
228 }
229 
230 - (void)testBuild
231 {
232  // This test only succeeds when the server-side is up and running. It sends
233  // a GET request to localhost, port 3000. The Test scheme launches a Rails
234  // server temporarily, if necessary, in order to answer the requests. The
235  // scheme pre-action comprises a shell script containing:
236  //
237  // cd "$SRCROOT/active-resource-kit-tests"
238  // [ -f tmp/pids/server.pid ] || "$HOME/.rvm/bin/rvm-shell" -c "rake db:setup db:fixtures:load ; rails s -d -P `pwd`/tmp/pids/server-xcode.pid"
239  //
240  // The script launches a Rails server in the background using RVM, if and
241  // only if the default server is not already running. It assumes that RVM is
242  // installed and carries the necessary Ruby gems. The post-action for the
243  // Test scheme contains the following shell script. It sends an interrupt
244  // signal to the server to shut it down.
245  //
246  // cd "$SRCROOT/active-resource-kit-tests"
247  // [ -f tmp/pids/server-xcode.pid ] && kill -INT `cat tmp/pids/server-xcode.pid`
248  //
249  [post buildWithAttributes:nil completionHandler:^(ARHTTPResponse *response, ARResource *resource, NSError *error) {
250  STAssertNotNil(resource, nil);
251  STAssertNil(error, nil);
252  [self setStop:YES];
253  }];
254  [self runUntilStop];
255 }
256 
257 - (void)testFindAll
258 {
259  // Without assuming exactly what the server-side records contain, just// assert that there are some then log their contents.[post findAllWithOptions:nil completionHandler:^(ARHTTPResponse *response, NSArray *resources, NSError *error) {
260  STAssertNotNil(resources, nil);
261  STAssertNil(error, nil);
262 
263 
264  for (ARResource *resource in resources)
265  {
266  NSLog(@"%@", [resource attributes]);
267  }
268  [self setStop:YES];
269  }];
270  [self runUntilStop];
271 }
272 
274 {
275  [post findFirstWithOptions:nil completionHandler:^(ARHTTPResponse *response, ARResource *resource, NSError *error) {
276  STAssertNotNil(resource, nil);
277  STAssertNil(error, nil);
278  NSLog(@"%@", [resource attributes]);
279  [self setStop:YES];
280  }];
281  [self runUntilStop];
282 }
283 
284 - (void)testCreate
285 {
286  Person *person = [[Person alloc] init];
287  [person saveWithCompletionHandler:^(ARHTTPResponse *response, NSError *error) {
288  STAssertNil(error, nil);
289  [self setStop:YES];
290  }];
291  [self runUntilStop];
292 }
293 
295 {
296  NSDictionary *headerFields = [NSDictionary dictionaryWithObject:@"/foo/bar/1" forKey:@"Location"];
297  ARHTTPResponse *response = [[ARHTTPResponse alloc] initWithURLResponse:[[NSHTTPURLResponse alloc] initWithURL:nil statusCode:0 HTTPVersion:nil headerFields:headerFields] body:nil];
298  STAssertEqualObjects(ARIDFromResponse(response), [NSNumber numberWithInt:1], nil);
299 }
300 
301 @end