mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
json fixes by Larry Campbell
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@37994 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
e57bc44c66
commit
250e0a4d7d
3 changed files with 397 additions and 9 deletions
|
@ -1,3 +1,9 @@
|
|||
2014-02-17 Larry Campbell <lcampbel@akamai.com>
|
||||
|
||||
* Source/NSJSONSerialization.m:
|
||||
* Tests/base/NSJSONSerialization/tests00.m:
|
||||
Fixes for bug #41628
|
||||
|
||||
2014-07-12 Yavor Doganov <yavor@gnu.org>
|
||||
|
||||
* Tests/GNUmakefile:
|
||||
|
|
|
@ -154,23 +154,58 @@ updateStreamBuffer(ParserState* state)
|
|||
{
|
||||
case NSUTF8StringEncoding:
|
||||
{
|
||||
int i = -1;
|
||||
|
||||
// Read one UTF8 character from the stream
|
||||
do
|
||||
NSUInteger i = 0;
|
||||
NSInteger n;
|
||||
|
||||
n = [stream read: &bytes[0] maxLength: 1];
|
||||
if (n != 1)
|
||||
{
|
||||
[stream read: &bytes[++i] maxLength: 1];
|
||||
state->error = [stream streamError];
|
||||
if (state->error == nil)
|
||||
{
|
||||
state->error
|
||||
= [NSError errorWithDomain: NSCocoaErrorDomain
|
||||
code: 0
|
||||
userInfo: nil];
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((bytes[0] & 0xC0) == 0xC0)
|
||||
{
|
||||
for (i = 1; i <= 5; i++)
|
||||
if ((bytes[0] & (0x40 >> i)) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (bytes[i] & 0xf);
|
||||
if (0 == i)
|
||||
{
|
||||
state->buffer[0] = bytes[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
str = [[NSString alloc] initWithUTF8String: (char*)bytes];
|
||||
[str getCharacters: state->buffer range: NSMakeRange(0,1)];
|
||||
[str release];
|
||||
n = [stream read: &bytes[1] maxLength: i];
|
||||
if (n == i)
|
||||
{
|
||||
str = [[NSString alloc] initWithUTF8String: (char*)bytes];
|
||||
[str getCharacters: state->buffer
|
||||
range: NSMakeRange(0,1)];
|
||||
[str release];
|
||||
}
|
||||
else
|
||||
{
|
||||
state->error = [stream streamError];
|
||||
if (state->error == nil)
|
||||
{
|
||||
state->error
|
||||
= [NSError errorWithDomain: NSCocoaErrorDomain
|
||||
code: 0
|
||||
userInfo: nil];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -209,6 +244,7 @@ updateStreamBuffer(ParserState* state)
|
|||
state->sourceIndex = -1;
|
||||
state->bufferIndex = 0;
|
||||
state->bufferLength = 1;
|
||||
return;
|
||||
}
|
||||
// Use an NSString to do the character set conversion. We could do this more
|
||||
// efficiently. We could also reuse the string.
|
||||
|
@ -243,7 +279,7 @@ consumeChar(ParserState *state)
|
|||
{
|
||||
state->sourceIndex++;
|
||||
state->bufferIndex++;
|
||||
if (state->bufferIndex >= BUFFER_SIZE)
|
||||
if (state->bufferIndex >= state->bufferLength)
|
||||
{
|
||||
state->updateBuffer(state);
|
||||
}
|
||||
|
|
346
Tests/base/NSJSONSerialization/tests00.m
Normal file
346
Tests/base/NSJSONSerialization/tests00.m
Normal file
|
@ -0,0 +1,346 @@
|
|||
//
|
||||
// Created by Larry Campbell on 12/12/08.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ObjectTesting.h"
|
||||
|
||||
|
||||
@interface GnustepBaseTests : NSObject {
|
||||
unsigned _successes;
|
||||
unsigned _failures;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GnustepBaseTests
|
||||
|
||||
- (BOOL) performTest: (NSString *)name
|
||||
{
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
BOOL result;
|
||||
|
||||
NSLog(@"Performing test %@", name);
|
||||
NS_DURING
|
||||
{
|
||||
[self performSelector: NSSelectorFromString(name)];
|
||||
_successes++;
|
||||
result = YES;
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"Test %@ failed: %@", name, [localException reason]);
|
||||
_failures++;
|
||||
result = NO;
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
|
||||
[pool release];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (unsigned) successes
|
||||
{
|
||||
return _successes;
|
||||
}
|
||||
|
||||
- (unsigned) failures
|
||||
{
|
||||
return _failures;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface GnustepBaseTests(TheTests)
|
||||
@end
|
||||
|
||||
@implementation GnustepBaseTests(TheTests)
|
||||
|
||||
- (void) cr39118
|
||||
{
|
||||
int x = 1999999999;
|
||||
NSString *s = @"1999999999";
|
||||
NSAssert([s intValue] == x, @"intValue botch");
|
||||
}
|
||||
|
||||
// verify that distinct strings get distinct hashes even if strings are very long
|
||||
- (void) cr48439
|
||||
{
|
||||
NSMutableSet *hashes = [NSMutableSet set];
|
||||
NSArray *strings = [NSArray arrayWithObjects:
|
||||
@"",
|
||||
@"a",
|
||||
@"aa",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123a",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123b",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123c",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123d",
|
||||
@"1234567890123456789012345678901234567890123456789012345678901234",
|
||||
@"1234567890123456789012345678901234567890123456789012345678901234a",
|
||||
@"1234567890123456789012345678901234567890123456789012345678901234b",
|
||||
@"1234567890123456789012345678901234567890123456789012345678901234c",
|
||||
@"1234567890123456789012345678901234567890123456789012345678901234d",
|
||||
@"12345678901234567890123456789012345678901234567890123456789012345",
|
||||
@"12345678901234567890123456789012345678901234567890123456789012345a",
|
||||
@"12345678901234567890123456789012345678901234567890123456789012345b",
|
||||
@"12345678901234567890123456789012345678901234567890123456789012345c",
|
||||
@"12345678901234567890123456789012345678901234567890123456789012345d",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123456789012345",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123456789012345a",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123456789012345b",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123456789012345c",
|
||||
@"123456789012345678901234567890123456789012345678901234567890123456789012345d",
|
||||
nil];
|
||||
NSString *s;
|
||||
NSEnumerator *e;
|
||||
|
||||
e = [strings objectEnumerator];
|
||||
while ((s = [e nextObject]) != nil)
|
||||
[hashes addObject:[NSNumber numberWithUnsignedInt:[s hash]]];
|
||||
|
||||
NSAssert([hashes count] == [strings count], @"hash botch");
|
||||
}
|
||||
|
||||
// this also covers CR 150661
|
||||
- (void)cr153594
|
||||
{
|
||||
NSDate *t1 = [NSDate date];
|
||||
NSDate *t2;
|
||||
NSData *d;
|
||||
|
||||
d = [NSKeyedArchiver archivedDataWithRootObject: t1];
|
||||
t2 = [NSKeyedUnarchiver unarchiveObjectWithData: d];
|
||||
NSAssert([t1 isEqual:t2], @"equality botch");
|
||||
}
|
||||
|
||||
- (void)cr1524466
|
||||
{
|
||||
NSURL *u = [[[NSURL alloc] initWithScheme: @"http" host: @"1.2.3.4" path: @"/a?b;foo"] autorelease];
|
||||
NSString *s = [[u absoluteURL] description];
|
||||
NSAssert([s isEqual: @"http://1.2.3.4/a?b;foo"], @"NSURL encoding botch");
|
||||
}
|
||||
|
||||
- (void)cr2096767
|
||||
{
|
||||
static struct {
|
||||
NSString *inputString;
|
||||
NSTimeInterval increment;
|
||||
NSString *expectedOutput;
|
||||
} tests[] = {
|
||||
{ @"2006-04-22 22:22:22:901", 0.0, @"2006-04-22 22:22:22:901" }, // gnustep bug https://savannah.gnu.org/bugs/?func=detailitem&item_id=16426
|
||||
{ @"2006-04-22 22:22:22:999", 0.0, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.0005, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.0006, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.0007, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.0008, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.00089, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.000899, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.0008999, @"2006-04-22 22:22:22:999" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.00089999, @"2006-04-22 22:22:23:000" },
|
||||
{ @"2006-04-22 22:22:22:999", 0.0009, @"2006-04-22 22:22:23:000" }, // CR https://bugzilla.akamai.com/show_bug.cgi?id=2096767
|
||||
};
|
||||
unsigned i;
|
||||
NSString *fmt = [NSString stringWithFormat: @"%%Y-%%m-%%d %%H:%%M:%%S:%%F"];
|
||||
|
||||
for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
|
||||
{
|
||||
NSString *inputString = tests[i].inputString;
|
||||
NSString *expectedOutput = tests[i].expectedOutput;
|
||||
NSCalendarDate *d1 = [NSCalendarDate dateWithString:inputString calendarFormat:fmt];
|
||||
NSCalendarDate *d2 = [[[NSCalendarDate alloc] initWithTimeInterval:tests[i].increment sinceDate:d1] autorelease];
|
||||
NSString *result = [d2 descriptionWithCalendarFormat:fmt];
|
||||
NSLog(@"input string: %@, increment: %.4f", inputString, tests[i].increment);
|
||||
NSLog(@"input date: %@", d1);
|
||||
NSLog(@"output date: %@", result);
|
||||
NSLog(@"expect: %@", expectedOutput);
|
||||
NSAssert([result isEqualToString:expectedOutput], @"mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cr2549370
|
||||
{
|
||||
NSString *path = @"/tmp/json.data";
|
||||
NSString *string = @"Hello garçon! ¡Ola! A little more coöperation please!";
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
NSData *d;
|
||||
NSInputStream *stream;
|
||||
|
||||
[array addObject:[NSDictionary dictionaryWithObjectsAndKeys:string, @"nickname", nil]];
|
||||
[dict setObject:array forKey: @"datacenters"];
|
||||
|
||||
d = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:0];
|
||||
[d writeToFile:path atomically:NO];
|
||||
|
||||
stream = [NSInputStream inputStreamWithFileAtPath:path];
|
||||
[stream open];
|
||||
dict = [NSJSONSerialization JSONObjectWithStream:stream options:0 error:0];
|
||||
dict = [[dict objectForKey: @"datacenters"] objectAtIndex:0];
|
||||
NSAssert(dict != nil, @"JSON returned nil");
|
||||
NSAssert([string isEqualToString:[dict objectForKey: @"nickname"]], @"data mismatch");
|
||||
}
|
||||
|
||||
void checkstr(NSString *expected, NSString *got)
|
||||
{
|
||||
if ([expected caseInsensitiveCompare:got] != NSOrderedSame) {
|
||||
NSLog(@"expected %@", expected);
|
||||
NSLog(@" got %@", got);
|
||||
[NSException raise: @"error" format: @"test failed"];
|
||||
}
|
||||
}
|
||||
|
||||
// This is copied from servermonitor. We want to use the same quoting rules it does.
|
||||
// We use this only for the username and password; we assume the path/query/fragment
|
||||
// is already escaped.
|
||||
static NSString *percentQuoted(NSString *s)
|
||||
{
|
||||
NSMutableString *retval = [NSMutableString stringWithCapacity:[s length]];
|
||||
const unsigned char *p = (const unsigned char *)[s UTF8String];
|
||||
unsigned char c;
|
||||
const char *allowedNonalnumChars = "-_,.'~!$&*();";
|
||||
|
||||
while ((c = *p++) != '\0') {
|
||||
if (isalnum(c) || strchr(allowedNonalnumChars, c) != 0)
|
||||
[retval appendFormat: @"%c", c];
|
||||
else
|
||||
[retval appendFormat: @"%%%02x", c];
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
- (void)urlTest
|
||||
{
|
||||
static NSString *schemes[] = { @"ftp", @"http", @"https" };
|
||||
static NSString *hosts[] = { @"www.akamai.com", @"10.0.1.1", @"localhost" };
|
||||
static NSString *usernames[] = { nil, @"username", @"foo", @"a_username" };
|
||||
static NSString *passwords[] = { nil, @"password", @"M@nx2y#" };
|
||||
|
||||
// The path/query/fragment part here must be percent-quoted
|
||||
// as it would have to be if pasted into a curl command.
|
||||
struct {
|
||||
NSString *pqf; // path, query, fragment
|
||||
NSString *path; // expected path returned from NSURL (nil if same as pqf)
|
||||
} pqfs[] = {
|
||||
{ @"/", nil },
|
||||
{ @"/foo/bar/zot", nil },
|
||||
{ @"/a%20dillar%20a%20dollar", nil },
|
||||
{ @"/foo:bar:zot", nil },
|
||||
{ @"/a?b;foo", @"/a" },
|
||||
{ @"/a%25b", nil },
|
||||
{ @"/MHcwdTBOMEwwSjAJBgUrDgMCGgUABBScDhI23ZEqCpe2zGqbkoJVvUaDTgQUf/ZMNigUrs0eN6/eWvJbw6CsK/4CEQCbL3Mm0kXS8q7t0jI7E5gdoiMwITAfBgkrBgEFBQcwAQIEEgQQi7kTQMz7QK60KI2PnRR3mg==",
|
||||
nil },
|
||||
{ @"/interface/6/?mode=rc3&outputType=json&url=http%3A%2F%2Fwww.ehow.com%2Fhow_2324118_take-care-paper-cut.html&category=Health&subCategory=Family%20Health&subSubCategory=General%20Family%20Health&pageLocations=PLATFORM_TL|0&flushPage=1",
|
||||
@"/interface/6" },
|
||||
{ @"/d/search/p/enom/xml/domain/multiset/v4/?url=http%3A%2F%2Fnuseek.com&Partner=enom_internal_d2r_derp&config=1234567890&affilData=ip%3d127.0.0.1%26ua%3dIE|6.0|WinNT%26ur%3d&maxListings=10&maxRT=20&maxRTL=20&maxWeb=4&serveUrl=http://parkingweb30/default.pk",
|
||||
@"/d/search/p/enom/xml/domain/multiset/v4" },
|
||||
};
|
||||
unsigned i, j, k, l, m;
|
||||
|
||||
for (i = 0; i < sizeof(schemes)/sizeof(schemes[0]); i++)
|
||||
{
|
||||
NSString *scheme = schemes[i];
|
||||
|
||||
for (j = 0; j < sizeof(hosts)/sizeof(hosts[0]); j++)
|
||||
{
|
||||
NSString *host = hosts[j];
|
||||
|
||||
for (k = 0; k < sizeof(usernames)/sizeof(usernames[0]); k++)
|
||||
{
|
||||
NSString *username = usernames[k];
|
||||
|
||||
for (l = 0; l < sizeof(passwords)/sizeof(passwords[0]); l++)
|
||||
{
|
||||
NSString *password = passwords[l];
|
||||
|
||||
for (m = 0; m < sizeof(pqfs)/sizeof(pqfs[0]); m++)
|
||||
{
|
||||
NSMutableString *hostpart = [NSMutableString string];
|
||||
NSString *pqf = pqfs[m].pqf;
|
||||
NSString *expectedPath = [(pqfs[m].path == nil ? pqf : pqfs[m].path) stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *urlstring;
|
||||
NSURL *url;
|
||||
|
||||
expectedPath = [(pqfs[m].path == nil ? pqf : pqfs[m].path) stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
|
||||
|
||||
if (username != nil)
|
||||
{
|
||||
if (password != nil)
|
||||
{
|
||||
[hostpart appendFormat: @"%@:%@@",
|
||||
percentQuoted(username),
|
||||
percentQuoted(password)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[hostpart appendFormat: @"%@@",
|
||||
percentQuoted(username)];
|
||||
}
|
||||
}
|
||||
[hostpart appendString:host];
|
||||
|
||||
urlstring = [NSString stringWithFormat: @"%@://%@%@",
|
||||
scheme, hostpart, pqf];
|
||||
url = [[[NSURL alloc] initWithString: urlstring]
|
||||
autorelease];
|
||||
|
||||
// work around Apple bug, which rejects
|
||||
// objects containing vertical bar (turns out
|
||||
// gnustep is bug-for-bug compatible here,
|
||||
// so no need to make this Apple-only)
|
||||
if (url == nil && [pqf rangeOfString: @"|"].length != 0)
|
||||
{
|
||||
NSMutableString *fixedObject = [[pqf mutableCopy] autorelease];
|
||||
unsigned n;
|
||||
do {
|
||||
n = [fixedObject replaceOccurrencesOfString: @"|" withString: @"%7C" options:0 range:NSMakeRange(0, [fixedObject length])];
|
||||
} while (n != 0);
|
||||
urlstring = [NSString stringWithFormat: @"%@://%@%@", scheme, hostpart, fixedObject];
|
||||
url = [[[NSURL alloc] initWithString:urlstring] autorelease];
|
||||
}
|
||||
|
||||
NSAssert(url != nil, @"URL creation failed");
|
||||
|
||||
NSAssert([[url scheme] isEqual:schemes[i]], @"scheme botch");
|
||||
NSAssert((username == nil) == ([url user] == nil), @"username existence botch");
|
||||
if (username != nil) {
|
||||
NSAssert([[url user] isEqual:username], @"username botch");
|
||||
NSAssert((password == nil) == ([url password] == nil), @"password existence botch");
|
||||
if (password != nil) {
|
||||
NSString *urlpassword = [[url password] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSAssert([urlpassword isEqual:password], @"password botch");
|
||||
}
|
||||
}
|
||||
checkstr(expectedPath, [url path]);
|
||||
checkstr(urlstring, [[url absoluteURL] description]);
|
||||
NSAssert([[url host] isEqual:host], @"host botch");
|
||||
NSAssert([[url path] isEqual:expectedPath],
|
||||
@"path botch");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int status = 0;
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
GnustepBaseTests *gtb = [GnustepBaseTests new];
|
||||
|
||||
PASS([gtb performTest: @"cr39118"], "cr39118");
|
||||
PASS([gtb performTest: @"cr48439"], "cr48439");
|
||||
PASS([gtb performTest: @"cr153594"], "cr153594");
|
||||
PASS([gtb performTest: @"urlTest"], "urlTest");
|
||||
PASS([gtb performTest: @"cr1524466"], "cr1524466");
|
||||
PASS([gtb performTest: @"cr2096767"], "cr2096767");
|
||||
PASS([gtb performTest: @"cr2549370"], "cr2549370");
|
||||
|
||||
[gtb release];
|
||||
|
||||
[pool release];
|
||||
return status;
|
||||
}
|
Loading…
Reference in a new issue