1/*
2 Copyright (C) 2007-2010 Stig Brautaset. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this
8   list of conditions and the following disclaimer.
9
10 * Redistributions in binary form must reproduce the above copyright notice,
11   this list of conditions and the following disclaimer in the documentation
12   and/or other materials provided with the distribution.
13
14 * Neither the name of the author nor the names of its contributors may be used
15   to endorse or promote products derived from this software without specific
16   prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#import "ErrorTest.h"
31#import <JSON/JSON.h>
32
33#define assertErrorContains(e, s) \
34    STAssertTrue([[e localizedDescription] hasPrefix:s], @"%@", [e userInfo])
35
36#define assertUnderlyingErrorContains(e, s) \
37    STAssertTrue([[[[e userInfo] objectForKey:NSUnderlyingErrorKey] localizedDescription] hasPrefix:s], @"%@", [e userInfo])
38
39#define assertUnderlyingErrorContains2(e, s) \
40    STAssertTrue([[[[[[e userInfo] objectForKey:NSUnderlyingErrorKey] userInfo] objectForKey:NSUnderlyingErrorKey] localizedDescription] hasPrefix:s], @"%@", [e userInfo])
41
42@implementation ErrorTest
43
44#pragma mark Generator
45
46- (void)testUnsupportedObject
47{
48    NSError *error = nil;
49    STAssertNil([writer stringWithObject:[NSData data] error:&error], nil);
50    STAssertNotNil(error, nil);
51}
52
53- (void)testNonStringDictionaryKey
54{
55    NSArray *keys = [NSArray arrayWithObjects:[NSNull null],
56                     [NSNumber numberWithInt:1],
57                     [NSArray array],
58                     [NSDictionary dictionary],
59                     nil];
60
61    for (int i = 0; i < [keys count]; i++) {
62        NSError *error = nil;
63        NSDictionary *object = [NSDictionary dictionaryWithObject:@"1" forKey:[keys objectAtIndex:i]];
64        STAssertNil([writer stringWithObject:object error:&error], nil);
65        STAssertNotNil(error, nil);
66    }
67}
68
69
70- (void)testScalar
71{
72    NSArray *fragments = [NSArray arrayWithObjects:@"foo", @"", [NSNull null], [NSNumber numberWithInt:1], [NSNumber numberWithBool:YES], nil];
73    for (int i = 0; i < [fragments count]; i++) {
74        NSString *fragment = [fragments objectAtIndex:i];
75
76        // We don't check the convenience category here, like we do for parsing,
77        // because the category is explicitly on the NSArray and NSDictionary objects.
78        // STAssertNil([fragment JSONRepresentation], nil);
79
80        NSError *error = nil;
81        STAssertNil([writer stringWithObject:fragment error:&error], @"%@", fragment);
82        assertErrorContains(error, @"Not valid type for JSON");
83    }
84}
85
86- (void)testInfinity {
87    NSArray *obj = [NSArray arrayWithObject:[NSNumber numberWithDouble:INFINITY]];
88    NSError *error = nil;
89    STAssertNil([writer stringWithObject:obj error:&error], nil);
90    assertUnderlyingErrorContains(error, @"Infinity is not a valid number in JSON");
91}
92
93- (void)testNegativeInfinity {
94    NSArray *obj = [NSArray arrayWithObject:[NSNumber numberWithDouble:-INFINITY]];
95    NSError *error = nil;
96    STAssertNil([writer stringWithObject:obj error:&error], nil);
97    assertUnderlyingErrorContains(error, @"Infinity is not a valid number in JSON");
98}
99
100- (void)testNaN {
101    NSArray *obj = [NSArray arrayWithObject:[NSDecimalNumber notANumber]];
102    NSError *error = nil;
103    STAssertNil([writer stringWithObject:obj error:&error], nil);
104    assertUnderlyingErrorContains(error, @"NaN is not a valid number in JSON");
105}
106
107#pragma mark Scanner
108
109- (void)testArray {
110    NSError *error;
111
112    STAssertNil([parser objectWithString:@"[1,,2]" error:&error], nil);
113    assertErrorContains(error, @"Expected value");
114
115    STAssertNil([parser objectWithString:@"[1,,]" error:&error], nil);
116    assertErrorContains(error, @"Expected value");
117
118    STAssertNil([parser objectWithString:@"[,1]" error:&error], nil);
119    assertErrorContains(error, @"Expected value");
120
121
122    STAssertNil([parser objectWithString:@"[1,]" error:&error], nil);
123    assertErrorContains(error, @"Trailing comma disallowed");
124
125
126    STAssertNil([parser objectWithString:@"[1" error:&error], nil);
127    assertErrorContains(error, @"End of input while parsing array");
128
129    STAssertNil([parser objectWithString:@"[[]" error:&error], nil);
130    assertErrorContains(error, @"End of input while parsing array");
131
132    // See if seemingly-valid arrays have nasty elements
133    STAssertNil([parser objectWithString:@"[+1]" error:&error], nil);
134    assertErrorContains(error, @"Expected value");
135    assertUnderlyingErrorContains(error, @"Leading + disallowed");
136}
137
138- (void)testObject {
139    NSError *error;
140
141    STAssertNil([parser objectWithString:@"{1" error:&error], nil);
142    assertErrorContains(error, @"Object key string expected");
143
144    STAssertNil([parser objectWithString:@"{null" error:&error], nil);
145    assertErrorContains(error, @"Object key string expected");
146
147    STAssertNil([parser objectWithString:@"{\"a\":1,,}" error:&error], nil);
148    assertErrorContains(error, @"Object key string expected");
149
150    STAssertNil([parser objectWithString:@"{,\"a\":1}" error:&error], nil);
151    assertErrorContains(error, @"Object key string expected");
152
153
154    STAssertNil([parser objectWithString:@"{\"a\"" error:&error], nil);
155    assertErrorContains(error, @"Expected ':'");
156
157
158    STAssertNil([parser objectWithString:@"{\"a\":" error:&error], nil);
159    assertErrorContains(error, @"Object value expected");
160
161    STAssertNil([parser objectWithString:@"{\"a\":," error:&error], nil);
162    assertErrorContains(error, @"Object value expected");
163
164
165    STAssertNil([parser objectWithString:@"{\"a\":1,}" error:&error], nil);
166    assertErrorContains(error, @"Trailing comma disallowed");
167
168
169    STAssertNil([parser objectWithString:@"{" error:&error], nil);
170    assertErrorContains(error, @"End of input while parsing object");
171
172    STAssertNil([parser objectWithString:@"{\"a\":{}" error:&error], nil);
173    assertErrorContains(error, @"End of input while parsing object");
174}
175
176- (void)testNumber {
177    NSError *error;
178
179    STAssertNil([parser objectWithString:@"[-" error:&error], nil);
180    assertUnderlyingErrorContains(error, @"No digits after initial minus");
181
182    STAssertNil([parser objectWithString:@"[+1" error:&error], nil);
183    assertUnderlyingErrorContains(error, @"Leading + disallowed in number");
184
185    STAssertNil([parser objectWithString:@"[01" error:&error], nil);
186    assertUnderlyingErrorContains(error, @"Leading 0 disallowed in number");
187
188    STAssertNil([parser objectWithString:@"[0." error:&error], nil);
189    assertUnderlyingErrorContains(error, @"No digits after decimal point");
190
191
192    STAssertNil([parser objectWithString:@"[1e" error:&error], nil);
193    assertUnderlyingErrorContains(error, @"No digits after exponent");
194
195    STAssertNil([parser objectWithString:@"[1e-" error:&error], nil);
196    assertUnderlyingErrorContains(error, @"No digits after exponent");
197
198    STAssertNil([parser objectWithString:@"[1e+" error:&error], nil);
199    assertUnderlyingErrorContains(error, @"No digits after exponent");
200}
201
202- (void)testNull {
203    NSError *error;
204
205    STAssertNil([parser objectWithString:@"[nil" error:&error], nil);
206    assertUnderlyingErrorContains(error, @"Expected 'null'");
207}
208
209- (void)testBool {
210    NSError *error;
211
212    STAssertNil([parser objectWithString:@"[truth" error:&error], nil);
213    assertUnderlyingErrorContains(error, @"Expected 'true'");
214
215    STAssertNil([parser objectWithString:@"[fake" error:&error], nil);
216    assertUnderlyingErrorContains(error, @"Expected 'false'");
217}
218
219- (void)testString {
220    NSError *error;
221
222    STAssertNil([parser objectWithString:@"" error:&error], nil);
223    assertErrorContains(error, @"Unexpected end of string");
224
225    STAssertNil([parser objectWithString:@"" error:&error], nil);
226    assertErrorContains(error, @"Unexpected end of string");
227
228    STAssertNil([parser objectWithString:@"[\"" error:&error], nil);
229    assertUnderlyingErrorContains(error, @"Unescaped control character");
230
231    STAssertNil([parser objectWithString:@"[\"foo" error:&error], nil);
232    assertUnderlyingErrorContains(error, @"Unescaped control character");
233
234
235    STAssertNil([parser objectWithString:@"[\"\\uD834foo\"" error:&error], nil);
236    assertUnderlyingErrorContains(error, @"Broken unicode character");
237    assertUnderlyingErrorContains2(error, @"Missing low character");
238
239    STAssertNil([parser objectWithString:@"[\"\\uD834\\u001E\"" error:&error], nil);
240    assertUnderlyingErrorContains(error, @"Broken unicode character");
241    assertUnderlyingErrorContains2(error, @"Invalid low surrogate");
242
243    STAssertNil([parser objectWithString:@"[\"\\uDD1Ef\"" error:&error], nil);
244    assertUnderlyingErrorContains(error, @"Broken unicode character");
245    assertUnderlyingErrorContains2(error, @"Invalid high character");
246
247
248    for (NSUInteger i = 0; i < 0x20; i++) {
249        NSString *str = [NSString stringWithFormat:@"\"[%C\"", i];
250        STAssertNil([parser objectWithString:str error:&error], nil);
251        assertErrorContains(error, @"Unescaped control character");
252    }
253}
254
255- (void)testObjectGarbage {
256    NSError *error;
257
258    STAssertNil([parser objectWithString:@"['1'" error:&error], nil);
259    assertUnderlyingErrorContains(error, @"Unrecognised leading character");
260
261    STAssertNil([parser objectWithString:@"['hello'" error:&error], nil);
262    assertUnderlyingErrorContains(error, @"Unrecognised leading character");
263
264    STAssertNil([parser objectWithString:@"[**" error:&error], nil);
265    assertUnderlyingErrorContains(error, @"Unrecognised leading character");
266
267    STAssertNil([parser objectWithString:nil error:&error], nil);
268    assertErrorContains(error, @"Input was 'nil'");
269}
270
271@end
272