aboutsummaryrefslogtreecommitdiffhomepage
path: root/objectivec/Tests/GPBStringTests.m
diff options
context:
space:
mode:
Diffstat (limited to 'objectivec/Tests/GPBStringTests.m')
-rw-r--r--objectivec/Tests/GPBStringTests.m516
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