diff options
Diffstat (limited to 'objectivec/Tests/GPBStringTests.m')
-rw-r--r-- | objectivec/Tests/GPBStringTests.m | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/objectivec/Tests/GPBStringTests.m b/objectivec/Tests/GPBStringTests.m new file mode 100644 index 00000000..30f13775 --- /dev/null +++ b/objectivec/Tests/GPBStringTests.m @@ -0,0 +1,516 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#import <XCTest/XCTest.h> + +#import "GPBCodedInputStream_PackagePrivate.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +@interface TestClass : NSObject +@property(nonatomic, retain) NSString *foo; +@end + +@implementation TestClass +@synthesize foo; +@end + +@interface GPBStringTests : XCTestCase { + NSMutableArray *nsStrings_; + NSMutableArray *gpbStrings_; +} + +@end + +@implementation GPBStringTests + +- (void)setUp { + [super setUp]; + const char *strings[] = { + "ascii string", + "non-ascii string \xc3\xa9", // e with acute accent + "\xe2\x99\xa1", // White Heart + "mix \xe2\x99\xa4 string", // White Spade + + // Decomposed forms from http://www.unicode.org/reports/tr15/ + // 1.2 Singletons + "\xe2\x84\xa8 = A\xcc\x8a = \xc3\x85", "\xe2\x84\xa6 = \xce\xa9", + + // 1.2 Canonical Composites + "A\xcc\x8a = \xc3\x85", + "o\xcc\x82 = \xc3\xb4", + + // 1.2 Multiple Combining Marks + "s\xcc\xa3\xcc\x87 = \xe1\xb9\xa9", + "\xe1\xb8\x8b\xcc\xa3 = d\xcc\xa3\xcc\x87 = \xe1\xb8\x8d \xcc\x87", + "q\xcc\x87\xcc\xa3 = q\xcc\xa3\xcc\x87", + + // BOM + "\xEF\xBB\xBF String with BOM", + "String with \xEF\xBB\xBF in middle", + "String with end bom \xEF\xBB\xBF", + "\xEF\xBB\xBF\xe2\x99\xa1", // BOM White Heart + "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM", + + // Supplementary Plane + "\xf0\x9d\x84\x9e", // MUSICAL SYMBOL G CLEF + + // Tags + "\xf3\xa0\x80\x81", // Language Tag + + // Variation Selectors + "\xf3\xa0\x84\x80", // VARIATION SELECTOR-17 + + // Specials + "\xef\xbb\xbf\xef\xbf\xbd\xef\xbf\xbf", + + // Left To Right/Right To Left + // http://unicode.org/reports/tr9/ + + // Hello! <RTL marker>!Merhaba<LTR marker> + "Hello! \xE2\x80\x8F!\xd9\x85\xd8\xb1\xd8\xad\xd8\xa8\xd8\xa7\xE2\x80\x8E", + + "\xE2\x80\x8E LTR At Start", + "LTR At End\xE2\x80\x8E", + "\xE2\x80\x8F RTL At Start", + "RTL At End\xE2\x80\x8F", + "\xE2\x80\x8E\xE2\x80\x8E Double LTR \xE2\x80\x8E\xE2\x80\x8E", + "\xE2\x80\x8F\xE2\x80\x8F Double RTL \xE2\x80\x8F\xE2\x80\x8F", + "\xE2\x80\x8F\xE2\x80\x8E LTR-RTL LTR-RTL \xE2\x80\x8E\xE2\x80\x8F", + }; + size_t stringsSize = GPBARRAYSIZE(strings); + size_t numberUnicodeStrings = 17375; + nsStrings_ = [[NSMutableArray alloc] + initWithCapacity:stringsSize + numberUnicodeStrings]; + gpbStrings_ = [[NSMutableArray alloc] + initWithCapacity:stringsSize + numberUnicodeStrings]; + for (size_t i = 0; i < stringsSize; ++i) { + size_t length = strlen(strings[i]); + NSString *nsString = [[NSString alloc] initWithBytes:strings[i] + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + GPBString *gpbString = GPBCreateGPBStringWithUTF8(strings[i], length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + + // Generate all UTF8 characters in a variety of strings + // UTF8-1 - 1 Byte UTF 8 chars + int length = 0x7F + 1; + char *buffer = (char *)calloc(length, 1); + for (int i = 0; i < length; ++i) { + buffer[i] = (char)i; + } + NSString *nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + GPBString *gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + + // UTF8-2 - 2 Byte UTF 8 chars + int pointLength = 0xbf - 0x80 + 1; + length = pointLength * 2; + buffer = (char *)calloc(length, 1); + for (int i = 0xc2; i <= 0xdf; ++i) { + char *bufferPtr = buffer; + for (int j = 0x80; j <= 0xbf; ++j) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + free(buffer); + + // UTF8-3 - 3 Byte UTF 8 chars + length = pointLength * 3; + buffer = (char *)calloc(length, 1); + for (int i = 0xa0; i <= 0xbf; ++i) { + char *bufferPtr = buffer; + for (int j = 0x80; j <= 0xbf; ++j) { + (*bufferPtr++) = (char)0xE0; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + for (int i = 0xe1; i <= 0xec; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + for (int i = 0x80; i <= 0x9f; ++i) { + char *bufferPtr = buffer; + for (int j = 0x80; j <= 0xbf; ++j) { + (*bufferPtr++) = (char)0xED; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + for (int i = 0xee; i <= 0xef; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + free(buffer); + + // UTF8-4 - 4 Byte UTF 8 chars + length = pointLength * 4; + buffer = (char *)calloc(length, 1); + for (int i = 0x90; i <= 0xbf; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)0xF0; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + for (int i = 0xf1; i <= 0xf3; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + for (int k = 0x80; k <= 0xbf; ++k) { + char *bufferPtr = buffer; + for (int m = 0x80; m <= 0xbf; ++m) { + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + (*bufferPtr++) = (char)m; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + } + for (int i = 0x80; i <= 0x8f; ++i) { + for (int j = 0x80; j <= 0xbf; ++j) { + char *bufferPtr = buffer; + for (int k = 0x80; k <= 0xbf; ++k) { + (*bufferPtr++) = (char)0xF4; + (*bufferPtr++) = (char)i; + (*bufferPtr++) = (char)j; + (*bufferPtr++) = (char)k; + } + nsString = [[NSString alloc] initWithBytes:buffer + length:length + encoding:NSUTF8StringEncoding]; + [nsStrings_ addObject:nsString]; + [nsString release]; + gpbString = GPBCreateGPBStringWithUTF8(buffer, length); + [gpbStrings_ addObject:gpbString]; + [gpbString release]; + } + } + free(buffer); +} + +- (void)tearDown { + [nsStrings_ release]; + [gpbStrings_ release]; + [super tearDown]; +} + +- (void)testLength { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqual([nsString length], [gpbString length], @"%@ %@", nsString, + gpbString); + ++i; + } +} + +- (void)testLengthOfBytesUsingEncoding { + NSStringEncoding encodings[] = { + NSUTF8StringEncoding, + NSASCIIStringEncoding, + NSISOLatin1StringEncoding, + NSMacOSRomanStringEncoding, + NSUTF16StringEncoding, + NSUTF32StringEncoding, + }; + + for (size_t j = 0; j < GPBARRAYSIZE(encodings); ++j) { + NSStringEncoding testEncoding = encodings[j]; + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqual([nsString lengthOfBytesUsingEncoding:testEncoding], + [gpbString lengthOfBytesUsingEncoding:testEncoding], + @"%@ %@", nsString, gpbString); + ++i; + } + } +} + +- (void)testHash { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqual([nsString hash], [gpbString hash], @"%@ %@", nsString, + gpbString); + ++i; + } +} + +- (void)testEquality { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + XCTAssertEqualObjects(nsString, gpbString); + ++i; + } +} + +- (void)testCharacterAtIndex { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + NSUInteger length = [nsString length]; + for (size_t j = 0; j < length; ++j) { + unichar nsChar = [nsString characterAtIndex:j]; + unichar pbChar = [gpbString characterAtIndex:j]; + XCTAssertEqual(nsChar, pbChar, @"%@ %@ %zu", nsString, gpbString, j); + } + ++i; + } +} + +- (void)testCopy { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = [[gpbStrings_[i] copy] autorelease]; + XCTAssertEqualObjects(nsString, gpbString); + ++i; + } +} + +- (void)testMutableCopy { + size_t i = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = [[gpbStrings_[i] mutableCopy] autorelease]; + XCTAssertEqualObjects(nsString, gpbString); + ++i; + } +} + +- (void)testGetBytes { + // Do an attempt at a reasonably exhaustive test of get bytes. + // Get bytes with options other than 0 should always fall through to Apple + // code so we don't bother testing that path. + size_t i = 0; + char pbBuffer[256]; + char nsBuffer[256]; + int count = 0; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i]; + for (int j = 0; j < 100; ++j) { + // [NSString getBytes:maxLength:usedLength:encoding:options:range:remainingRange] + // does not return reliable results if the maxLength argument is 0, + // or range is 0,0. + // Radar 16385183 + NSUInteger length = [nsString length]; + NSUInteger maxBufferCount = (arc4random() % (length + 3)) + 1; + NSUInteger rangeStart = arc4random() % length; + NSUInteger rangeLength = arc4random() % (length - rangeStart); + + NSRange range = NSMakeRange(rangeStart, rangeLength); + + NSStringEncoding encodings[] = { + NSASCIIStringEncoding, + NSUTF8StringEncoding, + NSUTF16StringEncoding, + }; + + for (size_t k = 0; k < GPBARRAYSIZE(encodings); ++k) { + NSStringEncoding encoding = encodings[k]; + NSUInteger pbUsedBufferCount = 0; + NSUInteger nsUsedBufferCount = 0; + NSRange pbLeftOver = NSMakeRange(0, 0); + NSRange nsLeftOver = NSMakeRange(0, 0); + + BOOL pbGotBytes = [gpbString getBytes:pbBuffer + maxLength:maxBufferCount + usedLength:&pbUsedBufferCount + encoding:encoding + options:0 + range:range + remainingRange:&pbLeftOver]; + BOOL nsGotBytes = [nsString getBytes:nsBuffer + maxLength:maxBufferCount + usedLength:&nsUsedBufferCount + encoding:encoding + options:0 + range:range + remainingRange:&nsLeftOver]; + XCTAssertEqual( + (bool)pbGotBytes, (bool)nsGotBytes, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + XCTAssertEqual( + pbUsedBufferCount, nsUsedBufferCount, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + XCTAssertEqual( + pbLeftOver.location, nsLeftOver.location, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + XCTAssertEqual( + pbLeftOver.length, nsLeftOver.length, + @"PB %d '%@' vs '%@' Encoding:%tu MaxLength: %tu Range: %@ " + @"Used: %tu, %tu LeftOver %@, %@)", + count, gpbString, nsString, encoding, maxBufferCount, + NSStringFromRange(range), pbUsedBufferCount, nsUsedBufferCount, + NSStringFromRange(pbLeftOver), NSStringFromRange(nsLeftOver)); + ++count; + } + } + ++i; + } +} + +- (void)testLengthAndGetBytes { + // This test exists as an attempt to ferret out a bug. + // http://b/13516532 + size_t i = 0; + char pbBuffer[256]; + char nsBuffer[256]; + for (NSString *nsString in nsStrings_) { + GPBString *gpbString = gpbStrings_[i++]; + NSUInteger nsLength = + [nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + NSUInteger pbLength = + [gpbString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(nsLength, pbLength, @"%@ %@", nsString, gpbString); + NSUInteger pbUsedBufferCount = 0; + NSUInteger nsUsedBufferCount = 0; + NSRange pbLeftOver = NSMakeRange(0, 0); + NSRange nsLeftOver = NSMakeRange(0, 0); + NSRange range = NSMakeRange(0, [gpbString length]); + BOOL pbGotBytes = [gpbString getBytes:pbBuffer + maxLength:sizeof(pbBuffer) + usedLength:&pbUsedBufferCount + encoding:NSUTF8StringEncoding + options:0 + range:range + remainingRange:&pbLeftOver]; + BOOL nsGotBytes = [nsString getBytes:nsBuffer + maxLength:sizeof(nsBuffer) + usedLength:&nsUsedBufferCount + encoding:NSUTF8StringEncoding + options:0 + range:range + remainingRange:&nsLeftOver]; + XCTAssertTrue(pbGotBytes, @"%@", gpbString); + XCTAssertTrue(nsGotBytes, @"%@", nsString); + XCTAssertEqual(pbUsedBufferCount, pbLength, @"%@", gpbString); + XCTAssertEqual(nsUsedBufferCount, nsLength, @"%@", nsString); + } +} + +@end |