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:
Richard Frith-MacDonald 2014-07-14 06:38:16 +00:00
parent e57bc44c66
commit 250e0a4d7d
3 changed files with 397 additions and 9 deletions

View file

@ -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:

View file

@ -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);
}

View 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;
}