From 30650d81d9baa446dbc8deb784ba53794cafda5b Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 1 May 2015 08:57:16 -0400 Subject: Alpha 1 drop of Google's Objective C plugin and runtime support for protobufs. --- objectivec/Tests/Filter1.txt | 40 + objectivec/Tests/Filter2.txt | 35 + objectivec/Tests/GPBARCUnittestProtos.m | 57 + objectivec/Tests/GPBArrayTests.m | 3365 ++++++++++++++++++ objectivec/Tests/GPBCodedInputStreamTests.m | 290 ++ objectivec/Tests/GPBCodedOuputStreamTests.m | 321 ++ objectivec/Tests/GPBConcurrencyTests.m | 157 + objectivec/Tests/GPBDescriptorTests.m | 232 ++ objectivec/Tests/GPBDictionaryTests+Bool.m | 2421 +++++++++++++ objectivec/Tests/GPBDictionaryTests+Int32.m | 3650 ++++++++++++++++++++ objectivec/Tests/GPBDictionaryTests+Int64.m | 3650 ++++++++++++++++++++ objectivec/Tests/GPBDictionaryTests+String.m | 3362 ++++++++++++++++++ objectivec/Tests/GPBDictionaryTests+UInt32.m | 3650 ++++++++++++++++++++ objectivec/Tests/GPBDictionaryTests+UInt64.m | 3649 +++++++++++++++++++ objectivec/Tests/GPBDictionaryTests.pddm | 1044 ++++++ objectivec/Tests/GPBFilteredMessageTests.m | 98 + objectivec/Tests/GPBMessageTests+Merge.m | 700 ++++ objectivec/Tests/GPBMessageTests+Runtime.m | 1978 +++++++++++ objectivec/Tests/GPBMessageTests+Serialization.m | 838 +++++ objectivec/Tests/GPBMessageTests.m | 1728 +++++++++ objectivec/Tests/GPBPerfTests.m | 306 ++ objectivec/Tests/GPBStringTests.m | 516 +++ objectivec/Tests/GPBSwiftTests.swift | 405 +++ objectivec/Tests/GPBTestUtilities.h | 87 + objectivec/Tests/GPBTestUtilities.m | 2350 +++++++++++++ objectivec/Tests/GPBUnittestProtos.m | 56 + objectivec/Tests/GPBUnknownFieldSetTest.m | 255 ++ objectivec/Tests/GPBUtilitiesTests.m | 363 ++ objectivec/Tests/GPBWellKnownTypesTest.m | 102 + objectivec/Tests/GPBWireFormatTests.m | 246 ++ objectivec/Tests/UnitTests-Bridging-Header.h | 6 + objectivec/Tests/UnitTests-Info.plist | 20 + objectivec/Tests/golden_message | Bin 0 -> 493 bytes objectivec/Tests/golden_packed_fields_message | Bin 0 -> 493 bytes objectivec/Tests/iOSTestHarness/AppDelegate.m | 35 + .../AppIcon.appiconset/Contents.json | 116 + .../Images.xcassets/AppIcon.appiconset/iPad6.png | Bin 0 -> 8583 bytes .../AppIcon.appiconset/iPad6@2x.png | Bin 0 -> 17744 bytes .../Images.xcassets/AppIcon.appiconset/iPad7.png | Bin 0 -> 8969 bytes .../AppIcon.appiconset/iPad7@2x.png | Bin 0 -> 18788 bytes .../Images.xcassets/AppIcon.appiconset/iPhone6.png | Bin 0 -> 7021 bytes .../AppIcon.appiconset/iPhone6@2x.png | Bin 0 -> 13348 bytes .../AppIcon.appiconset/iPhone7@2x.png | Bin 0 -> 11128 bytes .../AppIcon.appiconset/iPhone7@3x.png | Bin 0 -> 21792 bytes .../LaunchImage.launchimage/Contents.json | 49 + objectivec/Tests/iOSTestHarness/Info.plist | 43 + objectivec/Tests/iOSTestHarness/LaunchScreen.xib | 33 + .../iOSTestHarness/en.lproj/InfoPlist.strings | 2 + objectivec/Tests/text_format_map_unittest_data.txt | 70 + objectivec/Tests/text_format_unittest_data.txt | 116 + objectivec/Tests/unittest_cycle.proto | 58 + objectivec/Tests/unittest_filter.proto | 71 + objectivec/Tests/unittest_name_mangling.proto | 37 + objectivec/Tests/unittest_objc.proto | 389 +++ objectivec/Tests/unittest_runtime_proto2.proto | 108 + objectivec/Tests/unittest_runtime_proto3.proto | 101 + 56 files changed, 37205 insertions(+) create mode 100644 objectivec/Tests/Filter1.txt create mode 100644 objectivec/Tests/Filter2.txt create mode 100644 objectivec/Tests/GPBARCUnittestProtos.m create mode 100644 objectivec/Tests/GPBArrayTests.m create mode 100644 objectivec/Tests/GPBCodedInputStreamTests.m create mode 100644 objectivec/Tests/GPBCodedOuputStreamTests.m create mode 100644 objectivec/Tests/GPBConcurrencyTests.m create mode 100644 objectivec/Tests/GPBDescriptorTests.m create mode 100644 objectivec/Tests/GPBDictionaryTests+Bool.m create mode 100644 objectivec/Tests/GPBDictionaryTests+Int32.m create mode 100644 objectivec/Tests/GPBDictionaryTests+Int64.m create mode 100644 objectivec/Tests/GPBDictionaryTests+String.m create mode 100644 objectivec/Tests/GPBDictionaryTests+UInt32.m create mode 100644 objectivec/Tests/GPBDictionaryTests+UInt64.m create mode 100644 objectivec/Tests/GPBDictionaryTests.pddm create mode 100644 objectivec/Tests/GPBFilteredMessageTests.m create mode 100644 objectivec/Tests/GPBMessageTests+Merge.m create mode 100644 objectivec/Tests/GPBMessageTests+Runtime.m create mode 100644 objectivec/Tests/GPBMessageTests+Serialization.m create mode 100644 objectivec/Tests/GPBMessageTests.m create mode 100644 objectivec/Tests/GPBPerfTests.m create mode 100644 objectivec/Tests/GPBStringTests.m create mode 100644 objectivec/Tests/GPBSwiftTests.swift create mode 100644 objectivec/Tests/GPBTestUtilities.h create mode 100644 objectivec/Tests/GPBTestUtilities.m create mode 100644 objectivec/Tests/GPBUnittestProtos.m create mode 100644 objectivec/Tests/GPBUnknownFieldSetTest.m create mode 100644 objectivec/Tests/GPBUtilitiesTests.m create mode 100644 objectivec/Tests/GPBWellKnownTypesTest.m create mode 100644 objectivec/Tests/GPBWireFormatTests.m create mode 100644 objectivec/Tests/UnitTests-Bridging-Header.h create mode 100644 objectivec/Tests/UnitTests-Info.plist create mode 100644 objectivec/Tests/golden_message create mode 100644 objectivec/Tests/golden_packed_fields_message create mode 100644 objectivec/Tests/iOSTestHarness/AppDelegate.m create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png create mode 100644 objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 objectivec/Tests/iOSTestHarness/Info.plist create mode 100644 objectivec/Tests/iOSTestHarness/LaunchScreen.xib create mode 100644 objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings create mode 100644 objectivec/Tests/text_format_map_unittest_data.txt create mode 100644 objectivec/Tests/text_format_unittest_data.txt create mode 100644 objectivec/Tests/unittest_cycle.proto create mode 100644 objectivec/Tests/unittest_filter.proto create mode 100644 objectivec/Tests/unittest_name_mangling.proto create mode 100644 objectivec/Tests/unittest_objc.proto create mode 100644 objectivec/Tests/unittest_runtime_proto2.proto create mode 100644 objectivec/Tests/unittest_runtime_proto3.proto (limited to 'objectivec/Tests') diff --git a/objectivec/Tests/Filter1.txt b/objectivec/Tests/Filter1.txt new file mode 100644 index 00000000..88a5cac8 --- /dev/null +++ b/objectivec/Tests/Filter1.txt @@ -0,0 +1,40 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + + +// Test the filter system for the ObjC Protocol Buffer Compiler. + +// Class names are matched using file name globbing rules. +// Whitespace is not allowed at the beginning of a line (except for a line +// that is a single newline). + +Keep +RemoveEnumMessage_KeepNestedInside +RemoveJustKidding diff --git a/objectivec/Tests/Filter2.txt b/objectivec/Tests/Filter2.txt new file mode 100644 index 00000000..5a2bb0f8 --- /dev/null +++ b/objectivec/Tests/Filter2.txt @@ -0,0 +1,35 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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. + + +// Test the filter system for the ObjC Protocol Buffer Compiler to test +// multiple filter support. + +Other diff --git a/objectivec/Tests/GPBARCUnittestProtos.m b/objectivec/Tests/GPBARCUnittestProtos.m new file mode 100644 index 00000000..daf4effc --- /dev/null +++ b/objectivec/Tests/GPBARCUnittestProtos.m @@ -0,0 +1,57 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// 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. + +// Makes sure all the generated headers compile with ARC on. + +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestCustomOptions.pbobjc.h" +#import "google/protobuf/UnittestCycle.pbobjc.h" +#import "google/protobuf/UnittestDropUnknownFields.pbobjc.h" +#import "google/protobuf/UnittestEmbedOptimizeFor.pbobjc.h" +#import "google/protobuf/UnittestEmpty.pbobjc.h" +#import "google/protobuf/UnittestEnormousDescriptor.pbobjc.h" +#import "google/protobuf/UnittestFilter.pbobjc.h" +#import "google/protobuf/UnittestImport.pbobjc.h" +#import "google/protobuf/UnittestImportLite.pbobjc.h" +#import "google/protobuf/UnittestImportPublic.pbobjc.h" +#import "google/protobuf/UnittestImportPublicLite.pbobjc.h" +#import "google/protobuf/UnittestLite.pbobjc.h" +#import "google/protobuf/UnittestMset.pbobjc.h" +#import "google/protobuf/UnittestNameMangling.pbobjc.h" +#import "google/protobuf/UnittestNoGenericServices.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" +#import "google/protobuf/UnittestOptimizeFor.pbobjc.h" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" diff --git a/objectivec/Tests/GPBArrayTests.m b/objectivec/Tests/GPBArrayTests.m new file mode 100644 index 00000000..37724c59 --- /dev/null +++ b/objectivec/Tests/GPBArrayTests.m @@ -0,0 +1,3365 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 + +#import + +#import "GPBArray.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBEnumArray (TestingTweak) ++ (instancetype)arrayWithValue:(int32_t)value; +- (instancetype)initWithValues:(const int32_t [])values + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 71: + case 72: + case 73: + case 74: + return YES; + default: + return NO; + } +} + +static BOOL TestingEnum_IsValidValue2(int32_t value) { + switch (value) { + case 71: + case 72: + case 73: + return YES; + default: + return NO; + } +} + +@implementation GPBEnumArray (TestingTweak) ++ (instancetype)arrayWithValue:(int32_t)value { + return [[[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + count:count]; +} +@end + +#pragma mark - PDDM Macros + +//%PDDM-DEFINE ARRAY_TESTS(NAME, TYPE, VAL1, VAL2, VAL3, VAL4) +//%ARRAY_TESTS2(NAME, TYPE, VAL1, VAL2, VAL3, VAL4, ) +//%PDDM-DEFINE ARRAY_TESTS2(NAME, TYPE, VAL1, VAL2, VAL3, VAL4, HELPER) +//%#pragma mark - NAME +//% +//%@interface GPB##NAME##ArrayTests : XCTestCase +//%@end +//% +//%@implementation GPB##NAME##ArrayTests +//% +//%- (void)testEmpty { +//% GPB##NAME##Array *array = [[GPB##NAME##Array alloc] init]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 0U); +//% XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% #pragma unused(value, idx, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% #pragma unused(value, idx, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [array release]; +//%} +//% +//%- (void)testOne { +//% GPB##NAME##Array *array = [GPB##NAME##Array arrayWithValue:VAL1]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 1U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, 0U); +//% XCTAssertEqual(value, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, 0U); +//% XCTAssertEqual(value, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//%} +//% +//%- (void)testBasics { +//% static const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL4); +//% XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); +//% __block NSUInteger idx2 = 0; +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, idx2); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% ++idx2; +//% }]; +//% idx2 = 0; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, (3 - idx2)); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% ++idx2; +//% }]; +//% // Stopping the enumeration. +//% idx2 = 0; +//% [array enumerateValuesWithBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, idx2); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% if (idx2 == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% XCTAssertNotEqual(idx, 3U); +//% ++idx2; +//% }]; +//% idx2 = 0; +//% [array enumerateValuesWithOptions:NSEnumerationReverse +//% usingBlock:^(TYPE value, NSUInteger idx, BOOL *stop) { +//% XCTAssertEqual(idx, (3 - idx2)); +//% XCTAssertEqual(value, kValues[idx]); +//% XCTAssertNotEqual(stop, NULL); +//% if (idx2 == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 1U); +//% XCTAssertNotEqual(idx, 0U); +//% ++idx2; +//% }]; +//% [array release]; +//%} +//% +//%- (void)testEquality { +//% const TYPE kValues1[] = { VAL1, VAL2, VAL3 }; +//% const TYPE kValues2[] = { VAL1, VAL4, VAL3 }; +//% const TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array1 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues1 +//% NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(array1); +//% GPB##NAME##Array *array1prime = +//% [[GPB##NAME##Array alloc] initWithValues:kValues1 +//% NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(array1prime); +//% GPB##NAME##Array *array2 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues2 +//% NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(array2); +//% GPB##NAME##Array *array3 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues3 +//% NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(array3); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(array1, array1prime); +//% XCTAssertEqualObjects(array1, array1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([array1 hash], [array1prime hash]); +//% +//% // 1/2/3 shouldn't be equal. +//% XCTAssertNotEqualObjects(array1, array2); +//% XCTAssertNotEqualObjects(array1, array3); +//% XCTAssertNotEqualObjects(array2, array3); +//% +//% [array1 release]; +//% [array1prime release]; +//% [array2 release]; +//% [array3 release]; +//%} +//% +//%- (void)testCopy { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% GPB##NAME##Array *array2 = [array copy]; +//% XCTAssertNotNil(array2); +//% +//% // Should be new object but equal. +//% XCTAssertNotEqual(array, array2); +//% XCTAssertEqualObjects(array, array2); +//%} +//% +//%- (void)testArrayFromArray { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% GPB##NAME##Array *array2 = [GPB##NAME##Array arrayWithValueArray:array]; +//% XCTAssertNotNil(array2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(array, array2); +//% XCTAssertEqualObjects(array, array2); +//%} +//% +//%- (void)testAdds { +//% GPB##NAME##Array *array = [GPB##NAME##Array array]; +//% XCTAssertNotNil(array); +//% +//% XCTAssertEqual(array.count, 0U); +//% [array addValue:VAL1]; +//% XCTAssertEqual(array.count, 1U); +//% +//% const TYPE kValues1[] = { VAL2, VAL3 }; +//% [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertEqual(array.count, 3U); +//% +//% const TYPE kValues2[] = { VAL4, VAL1 }; +//% GPB##NAME##Array *array2 = +//% [[GPB##NAME##Array alloc] initWithValues:kValues2 +//% NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(array2); +//% [array add##HELPER##ValuesFromArray:array2]; +//% XCTAssertEqual(array.count, 5U); +//% +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL4); +//% XCTAssertEqual([array valueAtIndex:4], VAL1); +//%} +//% +//%- (void)testInsert { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 3U); +//% +//% // First +//% [array insertValue:VAL4 atIndex:0]; +//% XCTAssertEqual(array.count, 4U); +//% +//% // Middle +//% [array insertValue:VAL4 atIndex:2]; +//% XCTAssertEqual(array.count, 5U); +//% +//% // End +//% [array insertValue:VAL4 atIndex:5]; +//% XCTAssertEqual(array.count, 6U); +//% +//% // Too far. +//% XCTAssertThrowsSpecificNamed([array insertValue:VAL4 atIndex:7], +//% NSException, NSRangeException); +//% +//% XCTAssertEqual([array valueAtIndex:0], VAL4); +//% XCTAssertEqual([array valueAtIndex:1], VAL1); +//% XCTAssertEqual([array valueAtIndex:2], VAL4); +//% XCTAssertEqual([array valueAtIndex:3], VAL2); +//% XCTAssertEqual([array valueAtIndex:4], VAL3); +//% XCTAssertEqual([array valueAtIndex:5], VAL4); +//%} +//% +//%- (void)testRemove { +//% const TYPE kValues[] = { VAL4, VAL1, VAL2, VAL4, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% XCTAssertEqual(array.count, 6U); +//% +//% // First +//% [array removeValueAtIndex:0]; +//% XCTAssertEqual(array.count, 5U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% +//% // Middle +//% [array removeValueAtIndex:2]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% +//% // End +//% [array removeValueAtIndex:3]; +//% XCTAssertEqual(array.count, 3U); +//% +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% +//% // Too far. +//% XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], +//% NSException, NSRangeException); +//% +//% [array removeAll]; +//% XCTAssertEqual(array.count, 0U); +//% XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], +//% NSException, NSRangeException); +//%} +//% +//%- (void)testInplaceMutation { +//% const TYPE kValues[] = { VAL1, VAL1, VAL3, VAL3 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% [array replaceValueAtIndex:1 withValue:VAL2]; +//% [array replaceValueAtIndex:3 withValue:VAL4]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL2); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL4); +//% +//% XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:VAL4], +//% NSException, NSRangeException); +//% +//% [array exchangeValueAtIndex:1 withValueAtIndex:3]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL1); +//% XCTAssertEqual([array valueAtIndex:1], VAL4); +//% XCTAssertEqual([array valueAtIndex:2], VAL3); +//% XCTAssertEqual([array valueAtIndex:3], VAL2); +//% +//% [array exchangeValueAtIndex:2 withValueAtIndex:0]; +//% XCTAssertEqual(array.count, 4U); +//% XCTAssertEqual([array valueAtIndex:0], VAL3); +//% XCTAssertEqual([array valueAtIndex:1], VAL4); +//% XCTAssertEqual([array valueAtIndex:2], VAL1); +//% XCTAssertEqual([array valueAtIndex:3], VAL2); +//% +//% XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], +//% NSException, NSRangeException); +//% XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], +//% NSException, NSRangeException); +//%} +//% +//%- (void)testInternalResizing { +//% const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##NAME##Array *array = +//% [[GPB##NAME##Array alloc] initWithValues:kValues +//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(array); +//% +//% // Add/remove to trigger the intneral buffer to grow/shrink. +//% for (int i = 0; i < 100; ++i) { +//% [array addValues:kValues count:GPBARRAYSIZE(kValues)]; +//% } +//% XCTAssertEqual(array.count, 404U); +//% for (int i = 0; i < 100; ++i) { +//% [array removeValueAtIndex:(i * 2)]; +//% } +//% XCTAssertEqual(array.count, 304U); +//% for (int i = 0; i < 100; ++i) { +//% [array insertValue:VAL4 atIndex:(i * 3)]; +//% } +//% XCTAssertEqual(array.count, 404U); +//% [array removeAll]; +//% XCTAssertEqual(array.count, 0U); +//%} +//% +//%@end +//% +//%PDDM-EXPAND ARRAY_TESTS(Int32, int32_t, 1, 2, 3, 4) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int32 + +@interface GPBInt32ArrayTests : XCTestCase +@end + +@implementation GPBInt32ArrayTests + +- (void)testEmpty { + GPBInt32Array *array = [[GPBInt32Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBInt32Array *array = [GPBInt32Array arrayWithValue:1]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 1); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 1); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 4); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int32_t kValues1[] = { 1, 2, 3 }; + const int32_t kValues2[] = { 1, 4, 3 }; + const int32_t kValues3[] = { 1, 2, 3, 4 }; + GPBInt32Array *array1 = + [[GPBInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBInt32Array *array1prime = + [[GPBInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBInt32Array *array2 = + [[GPBInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBInt32Array *array3 = + [[GPBInt32Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt32Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt32Array *array2 = [GPBInt32Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBInt32Array *array = [GPBInt32Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:1]; + XCTAssertEqual(array.count, 1U); + + const int32_t kValues1[] = { 2, 3 }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int32_t kValues2[] = { 4, 1 }; + GPBInt32Array *array2 = + [[GPBInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 4); + XCTAssertEqual([array valueAtIndex:4], 1); +} + +- (void)testInsert { + const int32_t kValues[] = { 1, 2, 3 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:4 atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:4 atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:4 atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:4 atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 4); + XCTAssertEqual([array valueAtIndex:1], 1); + XCTAssertEqual([array valueAtIndex:2], 4); + XCTAssertEqual([array valueAtIndex:3], 2); + XCTAssertEqual([array valueAtIndex:4], 3); + XCTAssertEqual([array valueAtIndex:5], 4); +} + +- (void)testRemove { + const int32_t kValues[] = { 4, 1, 2, 4, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 1); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 3); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const int32_t kValues[] = { 1, 1, 3, 3 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:2]; + [array replaceValueAtIndex:3 withValue:4]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 2); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 4); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:4], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 1); + XCTAssertEqual([array valueAtIndex:1], 4); + XCTAssertEqual([array valueAtIndex:2], 3); + XCTAssertEqual([array valueAtIndex:3], 2); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 3); + XCTAssertEqual([array valueAtIndex:1], 4); + XCTAssertEqual([array valueAtIndex:2], 1); + XCTAssertEqual([array valueAtIndex:3], 2); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const int32_t kValues[] = { 1, 2, 3, 4 }; + GPBInt32Array *array = + [[GPBInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:4 atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(UInt32, uint32_t, 11U, 12U, 13U, 14U) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt32 + +@interface GPBUInt32ArrayTests : XCTestCase +@end + +@implementation GPBUInt32ArrayTests + +- (void)testEmpty { + GPBUInt32Array *array = [[GPBUInt32Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBUInt32Array *array = [GPBUInt32Array arrayWithValue:11U]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 11U); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 11U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 14U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const uint32_t kValues1[] = { 11U, 12U, 13U }; + const uint32_t kValues2[] = { 11U, 14U, 13U }; + const uint32_t kValues3[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array1 = + [[GPBUInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBUInt32Array *array1prime = + [[GPBUInt32Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBUInt32Array *array2 = + [[GPBUInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBUInt32Array *array3 = + [[GPBUInt32Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt32Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt32Array *array2 = [GPBUInt32Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBUInt32Array *array = [GPBUInt32Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:11U]; + XCTAssertEqual(array.count, 1U); + + const uint32_t kValues1[] = { 12U, 13U }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const uint32_t kValues2[] = { 14U, 11U }; + GPBUInt32Array *array2 = + [[GPBUInt32Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 14U); + XCTAssertEqual([array valueAtIndex:4], 11U); +} + +- (void)testInsert { + const uint32_t kValues[] = { 11U, 12U, 13U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:14U atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:14U atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:14U atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:14U atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 14U); + XCTAssertEqual([array valueAtIndex:1], 11U); + XCTAssertEqual([array valueAtIndex:2], 14U); + XCTAssertEqual([array valueAtIndex:3], 12U); + XCTAssertEqual([array valueAtIndex:4], 13U); + XCTAssertEqual([array valueAtIndex:5], 14U); +} + +- (void)testRemove { + const uint32_t kValues[] = { 14U, 11U, 12U, 14U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 11U); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 13U); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const uint32_t kValues[] = { 11U, 11U, 13U, 13U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:12U]; + [array replaceValueAtIndex:3 withValue:14U]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 12U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 14U); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:14U], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 11U); + XCTAssertEqual([array valueAtIndex:1], 14U); + XCTAssertEqual([array valueAtIndex:2], 13U); + XCTAssertEqual([array valueAtIndex:3], 12U); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 13U); + XCTAssertEqual([array valueAtIndex:1], 14U); + XCTAssertEqual([array valueAtIndex:2], 11U); + XCTAssertEqual([array valueAtIndex:3], 12U); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; + GPBUInt32Array *array = + [[GPBUInt32Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:14U atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Int64, int64_t, 31LL, 32LL, 33LL, 34LL) +// This block of code is generated, do not edit it directly. + +#pragma mark - Int64 + +@interface GPBInt64ArrayTests : XCTestCase +@end + +@implementation GPBInt64ArrayTests + +- (void)testEmpty { + GPBInt64Array *array = [[GPBInt64Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBInt64Array *array = [GPBInt64Array arrayWithValue:31LL]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 31LL); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 31LL); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 34LL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int64_t kValues1[] = { 31LL, 32LL, 33LL }; + const int64_t kValues2[] = { 31LL, 34LL, 33LL }; + const int64_t kValues3[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array1 = + [[GPBInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBInt64Array *array1prime = + [[GPBInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBInt64Array *array2 = + [[GPBInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBInt64Array *array3 = + [[GPBInt64Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt64Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBInt64Array *array2 = [GPBInt64Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBInt64Array *array = [GPBInt64Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:31LL]; + XCTAssertEqual(array.count, 1U); + + const int64_t kValues1[] = { 32LL, 33LL }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int64_t kValues2[] = { 34LL, 31LL }; + GPBInt64Array *array2 = + [[GPBInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 34LL); + XCTAssertEqual([array valueAtIndex:4], 31LL); +} + +- (void)testInsert { + const int64_t kValues[] = { 31LL, 32LL, 33LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:34LL atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:34LL atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:34LL atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:34LL atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 34LL); + XCTAssertEqual([array valueAtIndex:1], 31LL); + XCTAssertEqual([array valueAtIndex:2], 34LL); + XCTAssertEqual([array valueAtIndex:3], 32LL); + XCTAssertEqual([array valueAtIndex:4], 33LL); + XCTAssertEqual([array valueAtIndex:5], 34LL); +} + +- (void)testRemove { + const int64_t kValues[] = { 34LL, 31LL, 32LL, 34LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 33LL); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const int64_t kValues[] = { 31LL, 31LL, 33LL, 33LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:32LL]; + [array replaceValueAtIndex:3 withValue:34LL]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 32LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 34LL); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:34LL], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 31LL); + XCTAssertEqual([array valueAtIndex:1], 34LL); + XCTAssertEqual([array valueAtIndex:2], 33LL); + XCTAssertEqual([array valueAtIndex:3], 32LL); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 33LL); + XCTAssertEqual([array valueAtIndex:1], 34LL); + XCTAssertEqual([array valueAtIndex:2], 31LL); + XCTAssertEqual([array valueAtIndex:3], 32LL); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; + GPBInt64Array *array = + [[GPBInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:34LL atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(UInt64, uint64_t, 41ULL, 42ULL, 43ULL, 44ULL) +// This block of code is generated, do not edit it directly. + +#pragma mark - UInt64 + +@interface GPBUInt64ArrayTests : XCTestCase +@end + +@implementation GPBUInt64ArrayTests + +- (void)testEmpty { + GPBUInt64Array *array = [[GPBUInt64Array alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBUInt64Array *array = [GPBUInt64Array arrayWithValue:41ULL]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 41ULL); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 41ULL); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 44ULL); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(uint64_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const uint64_t kValues1[] = { 41ULL, 42ULL, 43ULL }; + const uint64_t kValues2[] = { 41ULL, 44ULL, 43ULL }; + const uint64_t kValues3[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array1 = + [[GPBUInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBUInt64Array *array1prime = + [[GPBUInt64Array alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBUInt64Array *array2 = + [[GPBUInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBUInt64Array *array3 = + [[GPBUInt64Array alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt64Array *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBUInt64Array *array2 = [GPBUInt64Array arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBUInt64Array *array = [GPBUInt64Array array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:41ULL]; + XCTAssertEqual(array.count, 1U); + + const uint64_t kValues1[] = { 42ULL, 43ULL }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const uint64_t kValues2[] = { 44ULL, 41ULL }; + GPBUInt64Array *array2 = + [[GPBUInt64Array alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 44ULL); + XCTAssertEqual([array valueAtIndex:4], 41ULL); +} + +- (void)testInsert { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:44ULL atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:44ULL atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:44ULL atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:44ULL atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 44ULL); + XCTAssertEqual([array valueAtIndex:1], 41ULL); + XCTAssertEqual([array valueAtIndex:2], 44ULL); + XCTAssertEqual([array valueAtIndex:3], 42ULL); + XCTAssertEqual([array valueAtIndex:4], 43ULL); + XCTAssertEqual([array valueAtIndex:5], 44ULL); +} + +- (void)testRemove { + const uint64_t kValues[] = { 44ULL, 41ULL, 42ULL, 44ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const uint64_t kValues[] = { 41ULL, 41ULL, 43ULL, 43ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:42ULL]; + [array replaceValueAtIndex:3 withValue:44ULL]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 42ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 44ULL); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:44ULL], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); + XCTAssertEqual([array valueAtIndex:1], 44ULL); + XCTAssertEqual([array valueAtIndex:2], 43ULL); + XCTAssertEqual([array valueAtIndex:3], 42ULL); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 43ULL); + XCTAssertEqual([array valueAtIndex:1], 44ULL); + XCTAssertEqual([array valueAtIndex:2], 41ULL); + XCTAssertEqual([array valueAtIndex:3], 42ULL); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; + GPBUInt64Array *array = + [[GPBUInt64Array alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:44ULL atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Float, float, 51.f, 52.f, 53.f, 54.f) +// This block of code is generated, do not edit it directly. + +#pragma mark - Float + +@interface GPBFloatArrayTests : XCTestCase +@end + +@implementation GPBFloatArrayTests + +- (void)testEmpty { + GPBFloatArray *array = [[GPBFloatArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBFloatArray *array = [GPBFloatArray arrayWithValue:51.f]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 51.f); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 51.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 54.f); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(float value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const float kValues1[] = { 51.f, 52.f, 53.f }; + const float kValues2[] = { 51.f, 54.f, 53.f }; + const float kValues3[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array1 = + [[GPBFloatArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBFloatArray *array1prime = + [[GPBFloatArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBFloatArray *array2 = + [[GPBFloatArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBFloatArray *array3 = + [[GPBFloatArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBFloatArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBFloatArray *array2 = [GPBFloatArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBFloatArray *array = [GPBFloatArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:51.f]; + XCTAssertEqual(array.count, 1U); + + const float kValues1[] = { 52.f, 53.f }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const float kValues2[] = { 54.f, 51.f }; + GPBFloatArray *array2 = + [[GPBFloatArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 54.f); + XCTAssertEqual([array valueAtIndex:4], 51.f); +} + +- (void)testInsert { + const float kValues[] = { 51.f, 52.f, 53.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:54.f atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:54.f atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:54.f atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:54.f atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 54.f); + XCTAssertEqual([array valueAtIndex:1], 51.f); + XCTAssertEqual([array valueAtIndex:2], 54.f); + XCTAssertEqual([array valueAtIndex:3], 52.f); + XCTAssertEqual([array valueAtIndex:4], 53.f); + XCTAssertEqual([array valueAtIndex:5], 54.f); +} + +- (void)testRemove { + const float kValues[] = { 54.f, 51.f, 52.f, 54.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 53.f); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const float kValues[] = { 51.f, 51.f, 53.f, 53.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:52.f]; + [array replaceValueAtIndex:3 withValue:54.f]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 52.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 54.f); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:54.f], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 51.f); + XCTAssertEqual([array valueAtIndex:1], 54.f); + XCTAssertEqual([array valueAtIndex:2], 53.f); + XCTAssertEqual([array valueAtIndex:3], 52.f); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 53.f); + XCTAssertEqual([array valueAtIndex:1], 54.f); + XCTAssertEqual([array valueAtIndex:2], 51.f); + XCTAssertEqual([array valueAtIndex:3], 52.f); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; + GPBFloatArray *array = + [[GPBFloatArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:54.f atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Double, double, 61., 62., 63., 64.) +// This block of code is generated, do not edit it directly. + +#pragma mark - Double + +@interface GPBDoubleArrayTests : XCTestCase +@end + +@implementation GPBDoubleArrayTests + +- (void)testEmpty { + GPBDoubleArray *array = [[GPBDoubleArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBDoubleArray *array = [GPBDoubleArray arrayWithValue:61.]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 61.); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 61.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 64.); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(double value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const double kValues1[] = { 61., 62., 63. }; + const double kValues2[] = { 61., 64., 63. }; + const double kValues3[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array1 = + [[GPBDoubleArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBDoubleArray *array1prime = + [[GPBDoubleArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBDoubleArray *array2 = + [[GPBDoubleArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBDoubleArray *array3 = + [[GPBDoubleArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBDoubleArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBDoubleArray *array2 = [GPBDoubleArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBDoubleArray *array = [GPBDoubleArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:61.]; + XCTAssertEqual(array.count, 1U); + + const double kValues1[] = { 62., 63. }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const double kValues2[] = { 64., 61. }; + GPBDoubleArray *array2 = + [[GPBDoubleArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 64.); + XCTAssertEqual([array valueAtIndex:4], 61.); +} + +- (void)testInsert { + const double kValues[] = { 61., 62., 63. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:64. atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:64. atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:64. atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:64. atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 64.); + XCTAssertEqual([array valueAtIndex:1], 61.); + XCTAssertEqual([array valueAtIndex:2], 64.); + XCTAssertEqual([array valueAtIndex:3], 62.); + XCTAssertEqual([array valueAtIndex:4], 63.); + XCTAssertEqual([array valueAtIndex:5], 64.); +} + +- (void)testRemove { + const double kValues[] = { 64., 61., 62., 64., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 61.); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 63.); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const double kValues[] = { 61., 61., 63., 63. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:62.]; + [array replaceValueAtIndex:3 withValue:64.]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 62.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 64.); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:64.], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 61.); + XCTAssertEqual([array valueAtIndex:1], 64.); + XCTAssertEqual([array valueAtIndex:2], 63.); + XCTAssertEqual([array valueAtIndex:3], 62.); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 63.); + XCTAssertEqual([array valueAtIndex:1], 64.); + XCTAssertEqual([array valueAtIndex:2], 61.); + XCTAssertEqual([array valueAtIndex:3], 62.); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const double kValues[] = { 61., 62., 63., 64. }; + GPBDoubleArray *array = + [[GPBDoubleArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:64. atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS(Bool, BOOL, TRUE, TRUE, FALSE, FALSE) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool + +@interface GPBBoolArrayTests : XCTestCase +@end + +@implementation GPBBoolArrayTests + +- (void)testEmpty { + GPBBoolArray *array = [[GPBBoolArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBBoolArray *array = [GPBBoolArray arrayWithValue:TRUE]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, TRUE); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, TRUE); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], FALSE); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(BOOL value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const BOOL kValues1[] = { TRUE, TRUE, FALSE }; + const BOOL kValues2[] = { TRUE, FALSE, FALSE }; + const BOOL kValues3[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array1 = + [[GPBBoolArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBBoolArray *array1prime = + [[GPBBoolArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBBoolArray *array2 = + [[GPBBoolArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBBoolArray *array3 = + [[GPBBoolArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBBoolArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBBoolArray *array2 = [GPBBoolArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBBoolArray *array = [GPBBoolArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:TRUE]; + XCTAssertEqual(array.count, 1U); + + const BOOL kValues1[] = { TRUE, FALSE }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const BOOL kValues2[] = { FALSE, TRUE }; + GPBBoolArray *array2 = + [[GPBBoolArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], FALSE); + XCTAssertEqual([array valueAtIndex:4], TRUE); +} + +- (void)testInsert { + const BOOL kValues[] = { TRUE, TRUE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:FALSE atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:FALSE atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:FALSE atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:FALSE atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], FALSE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], TRUE); + XCTAssertEqual([array valueAtIndex:4], FALSE); + XCTAssertEqual([array valueAtIndex:5], FALSE); +} + +- (void)testRemove { + const BOOL kValues[] = { FALSE, TRUE, TRUE, FALSE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], FALSE); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:TRUE]; + [array replaceValueAtIndex:3 withValue:FALSE]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], TRUE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], FALSE); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:FALSE], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], TRUE); + XCTAssertEqual([array valueAtIndex:1], FALSE); + XCTAssertEqual([array valueAtIndex:2], FALSE); + XCTAssertEqual([array valueAtIndex:3], TRUE); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], FALSE); + XCTAssertEqual([array valueAtIndex:1], FALSE); + XCTAssertEqual([array valueAtIndex:2], TRUE); + XCTAssertEqual([array valueAtIndex:3], TRUE); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; + GPBBoolArray *array = + [[GPBBoolArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:FALSE atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND ARRAY_TESTS2(Enum, int32_t, 71, 72, 73, 74, Raw) +// This block of code is generated, do not edit it directly. + +#pragma mark - Enum + +@interface GPBEnumArrayTests : XCTestCase +@end + +@implementation GPBEnumArrayTests + +- (void)testEmpty { + GPBEnumArray *array = [[GPBEnumArray alloc] init]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array valueAtIndex:0], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + #pragma unused(value, idx, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [array release]; +} + +- (void)testOne { + GPBEnumArray *array = [GPBEnumArray arrayWithValue:71]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 1U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertThrowsSpecificNamed([array valueAtIndex:1], NSException, NSRangeException); + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 71); + XCTAssertNotEqual(stop, NULL); + }]; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, 0U); + XCTAssertEqual(value, 71); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + static const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); + XCTAssertThrowsSpecificNamed([array valueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int32_t kValues1[] = { 71, 72, 73 }; + const int32_t kValues2[] = { 71, 74, 73 }; + const int32_t kValues3[] = { 71, 72, 73, 74 }; + GPBEnumArray *array1 = + [[GPBEnumArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBEnumArray *array1prime = + [[GPBEnumArray alloc] initWithValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBEnumArray *array3 = + [[GPBEnumArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBEnumArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testArrayFromArray { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBEnumArray *array2 = [GPBEnumArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); +} + +- (void)testAdds { + GPBEnumArray *array = [GPBEnumArray array]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addValue:71]; + XCTAssertEqual(array.count, 1U); + + const int32_t kValues1[] = { 72, 73 }; + [array addValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int32_t kValues2[] = { 74, 71 }; + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addRawValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); + XCTAssertEqual([array valueAtIndex:4], 71); +} + +- (void)testInsert { + const int32_t kValues[] = { 71, 72, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertValue:74 atIndex:0]; + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertValue:74 atIndex:2]; + XCTAssertEqual(array.count, 5U); + + // End + [array insertValue:74 atIndex:5]; + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertValue:74 atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array valueAtIndex:0], 74); + XCTAssertEqual([array valueAtIndex:1], 71); + XCTAssertEqual([array valueAtIndex:2], 74); + XCTAssertEqual([array valueAtIndex:3], 72); + XCTAssertEqual([array valueAtIndex:4], 73); + XCTAssertEqual([array valueAtIndex:5], 74); +} + +- (void)testRemove { + const int32_t kValues[] = { 74, 71, 72, 74, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 6U); + + // First + [array removeValueAtIndex:0]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 71); + + // Middle + [array removeValueAtIndex:2]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:2], 73); + + // End + [array removeValueAtIndex:3]; + XCTAssertEqual(array.count, 3U); + + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + + // Too far. + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:3], + NSException, NSRangeException); + + [array removeAll]; + XCTAssertEqual(array.count, 0U); + XCTAssertThrowsSpecificNamed([array removeValueAtIndex:0], + NSException, NSRangeException); +} + +- (void)testInplaceMutation { + const int32_t kValues[] = { 71, 71, 73, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withValue:72]; + [array replaceValueAtIndex:3 withValue:74]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withValue:74], + NSException, NSRangeException); + + [array exchangeValueAtIndex:1 withValueAtIndex:3]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 74); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 72); + + [array exchangeValueAtIndex:2 withValueAtIndex:0]; + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 73); + XCTAssertEqual([array valueAtIndex:1], 74); + XCTAssertEqual([array valueAtIndex:2], 71); + XCTAssertEqual([array valueAtIndex:3], 72); + + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:4 withValueAtIndex:1], + NSException, NSRangeException); + XCTAssertThrowsSpecificNamed([array exchangeValueAtIndex:1 withValueAtIndex:4], + NSException, NSRangeException); +} + +- (void)testInternalResizing { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertValue:74 atIndex:(i * 3)]; + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end + +//%PDDM-EXPAND-END (8 expansions) + +#pragma mark - Non macro-based Enum tests + +// These are hand written tests to cover the verification and raw methods. + +@interface GPBEnumArrayCustomTests : XCTestCase +@end + +@implementation GPBEnumArrayCustomTests + +- (void)testRawBasics { + static const int32_t kValues[] = { 71, 272, 73, 374 }; + static const int32_t kValuesFiltered[] = { + 71, kGPBUnrecognizedEnumeratorValue, 73, kGPBUnrecognizedEnumeratorValue + }; + XCTAssertEqual(GPBARRAYSIZE(kValues), GPBARRAYSIZE(kValuesFiltered)); + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 4U); + GPBEnumValidationFunc func = TestingEnum_IsValidValue; + XCTAssertEqual(array.validationFunc, func); + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 272); + XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:2], 73); + XCTAssertEqual([array rawValueAtIndex:3], 374); + XCTAssertEqual([array valueAtIndex:3], kGPBUnrecognizedEnumeratorValue); + XCTAssertThrowsSpecificNamed([array rawValueAtIndex:4], NSException, NSRangeException); + __block NSUInteger idx2 = 0; + [array enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValuesFiltered[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateRawValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + idx2 = 0; + [array enumerateValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValuesFiltered[idx]); + XCTAssertNotEqual(stop, NULL); + ++idx2; + }]; + // Stopping the enumeration. + idx2 = 0; + [array enumerateRawValuesWithBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, idx2); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + XCTAssertNotEqual(idx, 3U); + ++idx2; + }]; + idx2 = 0; + [array enumerateRawValuesWithOptions:NSEnumerationReverse + usingBlock:^(int32_t value, NSUInteger idx, BOOL *stop) { + XCTAssertEqual(idx, (3 - idx2)); + XCTAssertEqual(value, kValues[idx]); + XCTAssertNotEqual(stop, NULL); + if (idx2 == 1) *stop = YES; + XCTAssertNotEqual(idx, 1U); + XCTAssertNotEqual(idx, 0U); + ++idx2; + }]; + [array release]; +} + +- (void)testEquality { + const int32_t kValues1[] = { 71, 72, 173 }; // With unknown value + const int32_t kValues2[] = { 71, 74, 173 }; // With unknown value + const int32_t kValues3[] = { 71, 72, 173, 74 }; // With unknown value + GPBEnumArray *array1 = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1); + GPBEnumArray *array1prime = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue2 + rawValues:kValues1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(array1prime); + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + GPBEnumArray *array3 = + [[GPBEnumArray alloc] initWithValues:kValues3 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(array3); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(array1, array1prime); + XCTAssertEqualObjects(array1, array1prime); + // Equal, so they must have same hash. + XCTAssertEqual([array1 hash], [array1prime hash]); + // But different validation functions. + XCTAssertNotEqual(array1.validationFunc, array1prime.validationFunc); + + // 1/2/3 shouldn't be equal. + XCTAssertNotEqualObjects(array1, array2); + XCTAssertNotEqualObjects(array1, array3); + XCTAssertNotEqualObjects(array2, array3); + + [array1 release]; + [array1prime release]; + [array2 release]; + [array3 release]; +} + +- (void)testCopy { + const int32_t kValues[] = { 71, 72 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array addRawValue:1000]; // Unknown + XCTAssertEqual(array.count, 3U); + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 72); + XCTAssertEqual([array rawValueAtIndex:2], 1000); + XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); + + GPBEnumArray *array2 = [array copy]; + XCTAssertNotNil(array2); + + // Should be new object but equal. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); + XCTAssertEqual(array.validationFunc, array2.validationFunc); + XCTAssertTrue([array2 isKindOfClass:[GPBEnumArray class]]); + XCTAssertEqual(array2.count, 3U); + XCTAssertEqual([array2 rawValueAtIndex:0], 71); + XCTAssertEqual([array2 rawValueAtIndex:1], 72); + XCTAssertEqual([array2 rawValueAtIndex:2], 1000); + XCTAssertEqual([array2 valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); +} + +- (void)testArrayFromArray { + const int32_t kValues[] = { 71, 172, 173, 74 }; // Unknowns + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + GPBEnumArray *array2 = [GPBEnumArray arrayWithValueArray:array]; + XCTAssertNotNil(array2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(array, array2); + XCTAssertEqualObjects(array, array2); + XCTAssertEqual(array.validationFunc, array2.validationFunc); +} + +- (void)testUnknownAdds { + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(array); + + XCTAssertThrowsSpecificNamed([array addValue:172], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 0U); + + const int32_t kValues1[] = { 172, 173 }; // Unknown + XCTAssertThrowsSpecificNamed([array addValues:kValues1 count:GPBARRAYSIZE(kValues1)], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 0U); + + [array release]; +} + +- (void)testRawAdds { + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(array); + + XCTAssertEqual(array.count, 0U); + [array addRawValue:71]; // Valid + XCTAssertEqual(array.count, 1U); + + const int32_t kValues1[] = { 172, 173 }; // Unknown + [array addRawValues:kValues1 count:GPBARRAYSIZE(kValues1)]; + XCTAssertEqual(array.count, 3U); + + const int32_t kValues2[] = { 74, 71 }; + GPBEnumArray *array2 = + [[GPBEnumArray alloc] initWithValues:kValues2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(array2); + [array addRawValuesFromArray:array2]; + XCTAssertEqual(array.count, 5U); + + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 172); + XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:2], 173); + XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:3], 74); + XCTAssertEqual([array rawValueAtIndex:4], 71); + + [array release]; +} + +- (void)testUnknownInserts { + const int32_t kValues[] = { 71, 72, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + XCTAssertThrowsSpecificNamed([array insertValue:174 atIndex:0], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 3U); + + // Middle + XCTAssertThrowsSpecificNamed([array insertValue:274 atIndex:1], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 3U); + + // End + XCTAssertThrowsSpecificNamed([array insertValue:374 atIndex:3], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 3U); +} + +- (void)testRawInsert { + const int32_t kValues[] = { 71, 72, 73 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + XCTAssertEqual(array.count, 3U); + + // First + [array insertRawValue:174 atIndex:0]; // Unknown + XCTAssertEqual(array.count, 4U); + + // Middle + [array insertRawValue:274 atIndex:2]; // Unknown + XCTAssertEqual(array.count, 5U); + + // End + [array insertRawValue:374 atIndex:5]; // Unknown + XCTAssertEqual(array.count, 6U); + + // Too far. + XCTAssertThrowsSpecificNamed([array insertRawValue:74 atIndex:7], + NSException, NSRangeException); + + XCTAssertEqual([array rawValueAtIndex:0], 174); + XCTAssertEqual([array valueAtIndex:0], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:1], 71); + XCTAssertEqual([array rawValueAtIndex:2], 274); + XCTAssertEqual([array valueAtIndex:2], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:3], 72); + XCTAssertEqual([array rawValueAtIndex:4], 73); + XCTAssertEqual([array rawValueAtIndex:5], 374); + XCTAssertEqual([array valueAtIndex:5], kGPBUnrecognizedEnumeratorValue); + + [array release]; +} + +- (void)testUnknownInplaceMutation { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:1 withValue:172], + NSException, NSInvalidArgumentException); + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:3 withValue:274], + NSException, NSInvalidArgumentException); + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array valueAtIndex:0], 71); + XCTAssertEqual([array valueAtIndex:1], 72); + XCTAssertEqual([array valueAtIndex:2], 73); + XCTAssertEqual([array valueAtIndex:3], 74); +} + + +- (void)testRawInplaceMutation { + const int32_t kValues[] = { 71, 72, 73, 74 }; + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + [array replaceValueAtIndex:1 withRawValue:172]; // Unknown + [array replaceValueAtIndex:3 withRawValue:274]; // Unknown + XCTAssertEqual(array.count, 4U); + XCTAssertEqual([array rawValueAtIndex:0], 71); + XCTAssertEqual([array rawValueAtIndex:1], 172); + XCTAssertEqual([array valueAtIndex:1], kGPBUnrecognizedEnumeratorValue); + XCTAssertEqual([array rawValueAtIndex:2], 73); + XCTAssertEqual([array rawValueAtIndex:3], 274); + XCTAssertEqual([array valueAtIndex:3], kGPBUnrecognizedEnumeratorValue); + + XCTAssertThrowsSpecificNamed([array replaceValueAtIndex:4 withRawValue:74], + NSException, NSRangeException); +} + +- (void)testRawInternalResizing { + const int32_t kValues[] = { 71, 172, 173, 74 }; // Unknown + GPBEnumArray *array = + [[GPBEnumArray alloc] initWithValues:kValues + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(array); + + // Add/remove to trigger the intneral buffer to grow/shrink. + for (int i = 0; i < 100; ++i) { + [array addRawValues:kValues count:GPBARRAYSIZE(kValues)]; + } + XCTAssertEqual(array.count, 404U); + for (int i = 0; i < 100; ++i) { + [array removeValueAtIndex:(i * 2)]; + } + XCTAssertEqual(array.count, 304U); + for (int i = 0; i < 100; ++i) { + [array insertRawValue:274 atIndex:(i * 3)]; // Unknown + } + XCTAssertEqual(array.count, 404U); + [array removeAll]; + XCTAssertEqual(array.count, 0U); +} + +@end diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m new file mode 100644 index 00000000..0a709cbe --- /dev/null +++ b/objectivec/Tests/GPBCodedInputStreamTests.m @@ -0,0 +1,290 @@ +// 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 "GPBTestUtilities.h" + +#import "GPBCodedInputStream.h" +#import "GPBCodedOutputStream.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "GPBUtilities_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface CodedInputStreamTests : GPBTestCase +@end + +@implementation CodedInputStreamTests + +- (NSData*)bytes_with_sentinel:(int32_t)unused, ... { + va_list list; + va_start(list, unused); + + NSMutableData* values = [NSMutableData dataWithCapacity:0]; + int32_t i; + + while ((i = va_arg(list, int32_t)) != 256) { + NSAssert(i >= 0 && i < 256, @""); + uint8_t u = (uint8_t)i; + [values appendBytes:&u length:1]; + } + + va_end(list); + + return values; +} + +#define bytes(...) [self bytes_with_sentinel:0, __VA_ARGS__, 256] + +- (void)testDecodeZigZag { + XCTAssertEqual(0, GPBDecodeZigZag32(0)); + XCTAssertEqual(-1, GPBDecodeZigZag32(1)); + XCTAssertEqual(1, GPBDecodeZigZag32(2)); + XCTAssertEqual(-2, GPBDecodeZigZag32(3)); + XCTAssertEqual((int32_t)0x3FFFFFFF, GPBDecodeZigZag32(0x7FFFFFFE)); + XCTAssertEqual((int32_t)0xC0000000, GPBDecodeZigZag32(0x7FFFFFFF)); + XCTAssertEqual((int32_t)0x7FFFFFFF, GPBDecodeZigZag32(0xFFFFFFFE)); + XCTAssertEqual((int32_t)0x80000000, GPBDecodeZigZag32(0xFFFFFFFF)); + + XCTAssertEqual((int64_t)0, GPBDecodeZigZag64(0)); + XCTAssertEqual((int64_t)-1, GPBDecodeZigZag64(1)); + XCTAssertEqual((int64_t)1, GPBDecodeZigZag64(2)); + XCTAssertEqual((int64_t)-2, GPBDecodeZigZag64(3)); + XCTAssertEqual((int64_t)0x000000003FFFFFFFL, + GPBDecodeZigZag64(0x000000007FFFFFFEL)); + XCTAssertEqual((int64_t)0xFFFFFFFFC0000000L, + GPBDecodeZigZag64(0x000000007FFFFFFFL)); + XCTAssertEqual((int64_t)0x000000007FFFFFFFL, + GPBDecodeZigZag64(0x00000000FFFFFFFEL)); + XCTAssertEqual((int64_t)0xFFFFFFFF80000000L, + GPBDecodeZigZag64(0x00000000FFFFFFFFL)); + XCTAssertEqual((int64_t)0x7FFFFFFFFFFFFFFFL, + GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFEL)); + XCTAssertEqual((int64_t)0x8000000000000000L, + GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFFL)); +} + +- (void)assertReadVarint:(NSData*)data value:(int64_t)value { + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual((int32_t)value, [input readInt32]); + } + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual(value, [input readInt64]); + } +} + +- (void)assertReadLittleEndian32:(NSData*)data value:(int32_t)value { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual(value, [input readSFixed32]); +} + +- (void)assertReadLittleEndian64:(NSData*)data value:(int64_t)value { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertEqual(value, [input readSFixed64]); +} + +- (void)assertReadVarintFailure:(NSData*)data { + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertThrows([input readInt32]); + } + { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + XCTAssertThrows([input readInt64]); + } +} + +- (void)testBytes { + NSData* data = bytes(0xa2, 0x74); + XCTAssertEqual(data.length, (NSUInteger)2); + XCTAssertEqual(((uint8_t*)data.bytes)[0], (uint8_t)0xa2); + XCTAssertEqual(((uint8_t*)data.bytes)[1], (uint8_t)0x74); +} + +- (void)testReadVarint { + [self assertReadVarint:bytes(0x00) value:0]; + [self assertReadVarint:bytes(0x01) value:1]; + [self assertReadVarint:bytes(0x7f) value:127]; + // 14882 + [self assertReadVarint:bytes(0xa2, 0x74) value:(0x22 << 0) | (0x74 << 7)]; + // 2961488830 + [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x0bLL << 28)]; + + // 64-bit + // 7256456126 + [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x1bLL << 28)]; + // 41256202580718336 + [self assertReadVarint:bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49) + value:(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | + (0x1c << 21) | (0x43LL << 28) | (0x49LL << 35) | + (0x24LL << 42) | (0x49LL << 49)]; + // 11964378330978735131 + [self + assertReadVarint:bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, + 0xa6, 0x01) + value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | + (0x3bLL << 28) | (0x56LL << 35) | (0x00LL << 42) | + (0x05LL << 49) | (0x26LL << 56) | (0x01LL << 63)]; + + // Failures + [self assertReadVarintFailure:bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x00)]; + [self assertReadVarintFailure:bytes(0x80)]; +} + +- (void)testReadLittleEndian { + [self assertReadLittleEndian32:bytes(0x78, 0x56, 0x34, 0x12) + value:0x12345678]; + [self assertReadLittleEndian32:bytes(0xf0, 0xde, 0xbc, 0x9a) + value:0x9abcdef0]; + + [self assertReadLittleEndian64:bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, + 0x12) + value:0x123456789abcdef0LL]; + [self assertReadLittleEndian64:bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, + 0x9a) + value:0x9abcdef012345678LL]; +} + +- (void)testReadWholeMessage { + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestAllTypes* message2 = + [TestAllTypes parseFromData:rawBytes extensionRegistry:nil]; + [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSkipWholeMessage { + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + // Create two parallel inputs. Parse one as unknown fields while using + // skipField() to skip each field on the other. Expect the same tags. + GPBCodedInputStream* input1 = [GPBCodedInputStream streamWithData:rawBytes]; + GPBCodedInputStream* input2 = [GPBCodedInputStream streamWithData:rawBytes]; + GPBUnknownFieldSet* unknownFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + + while (YES) { + int32_t tag = [input1 readTag]; + XCTAssertEqual(tag, [input2 readTag]); + if (tag == 0) { + break; + } + [unknownFields mergeFieldFrom:tag input:input1]; + [input2 skipField:tag]; + } +} + +- (void)testReadHugeBlob { + // Allocate and initialize a 1MB blob. + NSMutableData* blob = [NSMutableData dataWithLength:1 << 20]; + for (NSUInteger i = 0; i < blob.length; i++) { + ((uint8_t*)blob.mutableBytes)[i] = (uint8_t)i; + } + + // Make a message containing it. + TestAllTypes* message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [message setOptionalBytes:blob]; + + // Serialize and parse it. Make sure to parse from an InputStream, not + // directly from a ByteString, so that CodedInputStream uses buffered + // reading. + GPBCodedInputStream* stream = + [GPBCodedInputStream streamWithData:message.data]; + TestAllTypes* message2 = + [TestAllTypes parseFromCodedInputStream:stream extensionRegistry:nil]; + + XCTAssertEqualObjects(message.optionalBytes, message2.optionalBytes); + + // Make sure all the other fields were parsed correctly. + TestAllTypes* message3 = [[message2 copy] autorelease]; + TestAllTypes* types = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* data = [types optionalBytes]; + [message3 setOptionalBytes:data]; + + [self assertAllFieldsSet:message3 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testReadMaliciouslyLargeBlob { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + + int32_t tag = GPBWireFormatMakeTag(1, GPBWireFormatLengthDelimited); + [output writeRawVarint32:tag]; + [output writeRawVarint32:0x7FFFFFFF]; + uint8_t bytes[32] = {0}; + [output writeRawData:[NSData dataWithBytes:bytes length:32]]; + [output flush]; + + NSData* data = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + GPBCodedInputStream* input = + [GPBCodedInputStream streamWithData:[NSMutableData dataWithData:data]]; + XCTAssertEqual(tag, [input readTag]); + + XCTAssertThrows([input readData]); +} + +// Verifies fix for b/10315336. +- (void)testReadMalformedString { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + + int32_t tag = GPBWireFormatMakeTag(TestAllTypes_FieldNumber_DefaultString, + GPBWireFormatLengthDelimited); + [output writeRawVarint32:tag]; + [output writeRawVarint32:5]; + // Create an invalid utf-8 byte array. + uint8_t bytes[5] = {0xc2, 0xf2}; + [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]]; + [output flush]; + + NSData* data = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + TestAllTypes* message = + [TestAllTypes parseFromCodedInputStream:input extensionRegistry:nil]; + // Make sure we can read string properties twice without crashing. + XCTAssertEqual([message.defaultString length], (NSUInteger)0); + XCTAssertEqualObjects(@"", message.defaultString); +} + +@end diff --git a/objectivec/Tests/GPBCodedOuputStreamTests.m b/objectivec/Tests/GPBCodedOuputStreamTests.m new file mode 100644 index 00000000..77d88033 --- /dev/null +++ b/objectivec/Tests/GPBCodedOuputStreamTests.m @@ -0,0 +1,321 @@ +// 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 "GPBTestUtilities.h" + +#import "GPBCodedOutputStream.h" +#import "GPBCodedInputStream.h" +#import "GPBUtilities_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface CodedOutputStreamTests : GPBTestCase +@end + +@implementation CodedOutputStreamTests + +- (NSData*)bytes_with_sentinel:(int32_t)unused, ... { + va_list list; + va_start(list, unused); + + NSMutableData* values = [NSMutableData dataWithCapacity:0]; + int32_t i; + + while ((i = va_arg(list, int32_t)) != 256) { + NSAssert(i >= 0 && i < 256, @""); + uint8_t u = (uint8_t)i; + [values appendBytes:&u length:1]; + } + + va_end(list); + + return values; +} + +#define bytes(...) [self bytes_with_sentinel:0, __VA_ARGS__, 256] + +- (void)assertWriteLittleEndian32:(NSData*)data value:(int32_t)value { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawLittleEndian32:(int32_t)value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + rawOutput = [NSOutputStream outputStreamToMemory]; + output = [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + [output writeRawLittleEndian32:(int32_t)value]; + [output flush]; + + actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } +} + +- (void)assertWriteLittleEndian64:(NSData*)data value:(int64_t)value { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawLittleEndian64:value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + rawOutput = [NSOutputStream outputStreamToMemory]; + output = [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + [output writeRawLittleEndian64:value]; + [output flush]; + + actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } +} + +- (void)assertWriteVarint:(NSData*)data value:(int64_t)value { + // Only do 32-bit write if the value fits in 32 bits. + if (GPBLogicalRightShift64(value, 32) == 0) { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawVarint32:(int32_t)value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Also try computing size. + XCTAssertEqual(GPBComputeRawVarint32Size((int32_t)value), + (size_t)data.length); + } + + { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + [output writeRawVarint64:value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + + // Also try computing size. + XCTAssertEqual(GPBComputeRawVarint64Size(value), (size_t)data.length); + } + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + // Only do 32-bit write if the value fits in 32 bits. + if (GPBLogicalRightShift64(value, 32) == 0) { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + + [output writeRawVarint32:(int32_t)value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } + + { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + + [output writeRawVarint64:value]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(data, actual); + } + } +} + +- (void)testWriteVarint1 { + [self assertWriteVarint:bytes(0x00) value:0]; +} + +- (void)testWriteVarint2 { + [self assertWriteVarint:bytes(0x01) value:1]; +} + +- (void)testWriteVarint3 { + [self assertWriteVarint:bytes(0x7f) value:127]; +} + +- (void)testWriteVarint4 { + // 14882 + [self assertWriteVarint:bytes(0xa2, 0x74) value:(0x22 << 0) | (0x74 << 7)]; +} + +- (void)testWriteVarint5 { + // 2961488830 + [self assertWriteVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x0bLL << 28)]; +} + +- (void)testWriteVarint6 { + // 64-bit + // 7256456126 + [self assertWriteVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b) + value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | + (0x04 << 21) | (0x1bLL << 28)]; +} + +- (void)testWriteVarint7 { + // 41256202580718336 + [self assertWriteVarint:bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49) + value:(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | + (0x1c << 21) | (0x43LL << 28) | (0x49LL << 35) | + (0x24LL << 42) | (0x49LL << 49)]; +} + +- (void)testWriteVarint8 { + // 11964378330978735131 + [self assertWriteVarint:bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, + 0xa6, 0x01) + value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | + (0x42 << 21) | (0x3bLL << 28) | (0x56LL << 35) | + (0x00LL << 42) | (0x05LL << 49) | (0x26LL << 56) | + (0x01LL << 63)]; +} + +- (void)testWriteLittleEndian { + [self assertWriteLittleEndian32:bytes(0x78, 0x56, 0x34, 0x12) + value:0x12345678]; + [self assertWriteLittleEndian32:bytes(0xf0, 0xde, 0xbc, 0x9a) + value:0x9abcdef0]; + + [self assertWriteLittleEndian64:bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, + 0x34, 0x12) + value:0x123456789abcdef0LL]; + [self assertWriteLittleEndian64:bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, + 0xbc, 0x9a) + value:0x9abcdef012345678LL]; +} + +- (void)testEncodeZigZag { + XCTAssertEqual(0U, GPBEncodeZigZag32(0)); + XCTAssertEqual(1U, GPBEncodeZigZag32(-1)); + XCTAssertEqual(2U, GPBEncodeZigZag32(1)); + XCTAssertEqual(3U, GPBEncodeZigZag32(-2)); + XCTAssertEqual(0x7FFFFFFEU, GPBEncodeZigZag32(0x3FFFFFFF)); + XCTAssertEqual(0x7FFFFFFFU, GPBEncodeZigZag32(0xC0000000)); + XCTAssertEqual(0xFFFFFFFEU, GPBEncodeZigZag32(0x7FFFFFFF)); + XCTAssertEqual(0xFFFFFFFFU, GPBEncodeZigZag32(0x80000000)); + + XCTAssertEqual(0ULL, GPBEncodeZigZag64(0)); + XCTAssertEqual(1ULL, GPBEncodeZigZag64(-1)); + XCTAssertEqual(2ULL, GPBEncodeZigZag64(1)); + XCTAssertEqual(3ULL, GPBEncodeZigZag64(-2)); + XCTAssertEqual(0x000000007FFFFFFEULL, + GPBEncodeZigZag64(0x000000003FFFFFFFLL)); + XCTAssertEqual(0x000000007FFFFFFFULL, + GPBEncodeZigZag64(0xFFFFFFFFC0000000LL)); + XCTAssertEqual(0x00000000FFFFFFFEULL, + GPBEncodeZigZag64(0x000000007FFFFFFFLL)); + XCTAssertEqual(0x00000000FFFFFFFFULL, + GPBEncodeZigZag64(0xFFFFFFFF80000000LL)); + XCTAssertEqual(0xFFFFFFFFFFFFFFFEULL, + GPBEncodeZigZag64(0x7FFFFFFFFFFFFFFFLL)); + XCTAssertEqual(0xFFFFFFFFFFFFFFFFULL, + GPBEncodeZigZag64(0x8000000000000000LL)); + + // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) + // were chosen semi-randomly via keyboard bashing. + XCTAssertEqual(0U, GPBEncodeZigZag32(GPBDecodeZigZag32(0))); + XCTAssertEqual(1U, GPBEncodeZigZag32(GPBDecodeZigZag32(1))); + XCTAssertEqual(-1U, GPBEncodeZigZag32(GPBDecodeZigZag32(-1))); + XCTAssertEqual(14927U, GPBEncodeZigZag32(GPBDecodeZigZag32(14927))); + XCTAssertEqual(-3612U, GPBEncodeZigZag32(GPBDecodeZigZag32(-3612))); + + XCTAssertEqual(0ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(0))); + XCTAssertEqual(1ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(1))); + XCTAssertEqual(-1ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(-1))); + XCTAssertEqual(14927ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(14927))); + XCTAssertEqual(-3612ULL, GPBEncodeZigZag64(GPBDecodeZigZag64(-3612))); + + XCTAssertEqual(856912304801416ULL, + GPBEncodeZigZag64(GPBDecodeZigZag64(856912304801416LL))); + XCTAssertEqual(-75123905439571256ULL, + GPBEncodeZigZag64(GPBDecodeZigZag64(-75123905439571256LL))); +} + +- (void)testWriteWholeMessage { + // Not kGPBDefaultRepeatCount because we are comparing to a golden master file + // that was generated with 2. + TestAllTypes* message = [self allSetRepeatedCount:2]; + + NSData* rawBytes = message.data; + NSData* goldenData = + [self getDataFileNamed:@"golden_message" dataToWrite:rawBytes]; + XCTAssertEqualObjects(rawBytes, goldenData); + + // Try different block sizes. + for (int blockSize = 1; blockSize < 256; blockSize *= 2) { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput + bufferSize:blockSize]; + [message writeToCodedOutputStream:output]; + [output flush]; + + NSData* actual = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + XCTAssertEqualObjects(rawBytes, actual); + } + + // Not kGPBDefaultRepeatCount because we are comparing to a golden master file + // that was generated with 2. + TestAllExtensions* extensions = [self allExtensionsSetRepeatedCount:2]; + rawBytes = extensions.data; + goldenData = [self getDataFileNamed:@"golden_packed_fields_message" + dataToWrite:rawBytes]; + XCTAssertEqualObjects(rawBytes, goldenData); +} + +@end diff --git a/objectivec/Tests/GPBConcurrencyTests.m b/objectivec/Tests/GPBConcurrencyTests.m new file mode 100644 index 00000000..3749fc34 --- /dev/null +++ b/objectivec/Tests/GPBConcurrencyTests.m @@ -0,0 +1,157 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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 "GPBTestUtilities.h" + +#import "google/protobuf/Unittest.pbobjc.h" + +static const int kNumThreads = 100; +static const int kNumMessages = 100; + +@interface ConcurrencyTests : GPBTestCase +@end + +@implementation ConcurrencyTests + +- (NSArray *)createThreadsWithSelector:(SEL)selector object:(id)object { + NSMutableArray *array = [NSMutableArray array]; + for (NSUInteger i = 0; i < kNumThreads; i++) { + NSThread *thread = + [[NSThread alloc] initWithTarget:self selector:selector object:object]; + [array addObject:thread]; + [thread release]; + } + return array; +} + +- (NSArray *)createMessagesWithType:(Class)msgType { + NSMutableArray *array = [NSMutableArray array]; + for (NSUInteger i = 0; i < kNumMessages; i++) { + [array addObject:[msgType message]]; + } + return array; +} + +- (void)startThreads:(NSArray *)threads { + for (NSThread *thread in threads) { + [thread start]; + } +} + +- (void)joinThreads:(NSArray *)threads { + for (NSThread *thread in threads) { + while (![thread isFinished]) + ; + } +} + +- (void)readForeignMessage:(NSArray *)messages { + for (NSUInteger i = 0; i < 10; i++) { + for (TestAllTypes *message in messages) { + XCTAssertEqual(message.optionalForeignMessage.c, 0); + } + } +} + +- (void)testConcurrentReadOfUnsetMessageField { + NSArray *messages = [self createMessagesWithType:[TestAllTypes class]]; + NSArray *threads = + [self createThreadsWithSelector:@selector(readForeignMessage:) + object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + for (TestAllTypes *message in messages) { + XCTAssertFalse(message.hasOptionalForeignMessage); + } +} + +- (void)readRepeatedInt32:(NSArray *)messages { + for (int i = 0; i < 10; i++) { + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedInt32Array count], (NSUInteger)0); + } + } +} + +- (void)testConcurrentReadOfUnsetRepeatedIntField { + NSArray *messages = [self createMessagesWithType:[TestAllTypes class]]; + NSArray *threads = + [self createThreadsWithSelector:@selector(readRepeatedInt32:) + object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedInt32Array count], (NSUInteger)0); + } +} + +- (void)readRepeatedString:(NSArray *)messages { + for (int i = 0; i < 10; i++) { + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedStringArray count], (NSUInteger)0); + } + } +} + +- (void)testConcurrentReadOfUnsetRepeatedStringField { + NSArray *messages = [self createMessagesWithType:[TestAllTypes class]]; + NSArray *threads = + [self createThreadsWithSelector:@selector(readRepeatedString:) + object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + for (TestAllTypes *message in messages) { + XCTAssertEqual([message.repeatedStringArray count], (NSUInteger)0); + } +} + +- (void)readOptionalForeignMessageExtension:(NSArray *)messages { + for (int i = 0; i < 10; i++) { + for (TestAllExtensions *message in messages) { + ForeignMessage *foreign = + [message getExtension:[UnittestRoot optionalForeignMessageExtension]]; + XCTAssertEqual(foreign.c, 0); + } + } +} + +- (void)testConcurrentReadOfUnsetExtensionField { + NSArray *messages = [self createMessagesWithType:[TestAllExtensions class]]; + SEL sel = @selector(readOptionalForeignMessageExtension:); + NSArray *threads = [self createThreadsWithSelector:sel object:messages]; + [self startThreads:threads]; + [self joinThreads:threads]; + GPBExtensionField *extension = [UnittestRoot optionalForeignMessageExtension]; + for (TestAllExtensions *message in messages) { + XCTAssertFalse([message hasExtension:extension]); + } +} + +@end diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m new file mode 100644 index 00000000..ccdbb645 --- /dev/null +++ b/objectivec/Tests/GPBDescriptorTests.m @@ -0,0 +1,232 @@ +// 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 "GPBTestUtilities.h" + +#import + +#import "GPBDescriptor.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface DescriptorTests : GPBTestCase +@end + +@implementation DescriptorTests + +- (void)testFieldDescriptor { + GPBDescriptor *descriptor = [TestAllTypes descriptor]; + + // Nested Enum + GPBFieldDescriptor *fieldDescriptorWithName = + [descriptor fieldWithName:@"optionalNestedEnum"]; + XCTAssertNotNil(fieldDescriptorWithName); + GPBFieldDescriptor *fieldDescriptorWithNumber = + [descriptor fieldWithNumber:21]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); + XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, + @"TestAllTypes_NestedEnum"); + + // Foreign Enum + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalForeignEnum"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:22]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); + XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, + @"ForeignEnum"); + + // Import Enum + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportEnum"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:23]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); + XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, + @"ImportEnum"); + + // Nested Message + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalNestedMessage"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:18]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); + + // Foreign Message + fieldDescriptorWithName = + [descriptor fieldWithName:@"optionalForeignMessage"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:19]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); + + // Import Message + fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportMessage"]; + XCTAssertNotNil(fieldDescriptorWithName); + fieldDescriptorWithNumber = [descriptor fieldWithNumber:20]; + XCTAssertNotNil(fieldDescriptorWithNumber); + XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); + XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); +} + +- (void)testEnumDescriptor { + GPBEnumDescriptor *descriptor = TestAllTypes_NestedEnum_EnumDescriptor(); + + NSString *enumName = [descriptor enumNameForValue:1]; + XCTAssertNotNil(enumName); + int32_t value; + XCTAssertTrue( + [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Foo"]); + XCTAssertTrue( + [descriptor getValue:NULL forEnumName:@"TestAllTypes_NestedEnum_Foo"]); + XCTAssertEqual(value, TestAllTypes_NestedEnum_Foo); + + enumName = [descriptor enumNameForValue:2]; + XCTAssertNotNil(enumName); + XCTAssertTrue( + [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Bar"]); + XCTAssertEqual(value, TestAllTypes_NestedEnum_Bar); + + enumName = [descriptor enumNameForValue:3]; + XCTAssertNotNil(enumName); + XCTAssertTrue( + [descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Baz"]); + XCTAssertEqual(value, TestAllTypes_NestedEnum_Baz); + + // Bad values + enumName = [descriptor enumNameForValue:0]; + XCTAssertNil(enumName); + XCTAssertFalse([descriptor getValue:&value forEnumName:@"Unknown"]); + XCTAssertFalse([descriptor getValue:NULL forEnumName:@"Unknown"]); + XCTAssertFalse([descriptor getValue:&value + forEnumName:@"TestAllTypes_NestedEnum_Unknown"]); + XCTAssertFalse([descriptor getValue:NULL + forEnumName:@"TestAllTypes_NestedEnum_Unknown"]); +} + +- (void)testEnumValueValidator { + GPBDescriptor *descriptor = [TestAllTypes descriptor]; + GPBFieldDescriptor *fieldDescriptor = + [descriptor fieldWithName:@"optionalNestedEnum"]; + + // Valid values + XCTAssertTrue([fieldDescriptor isValidEnumValue:1]); + XCTAssertTrue([fieldDescriptor isValidEnumValue:2]); + XCTAssertTrue([fieldDescriptor isValidEnumValue:3]); + XCTAssertTrue([fieldDescriptor isValidEnumValue:-1]); + + // Invalid values + XCTAssertFalse([fieldDescriptor isValidEnumValue:4]); + XCTAssertFalse([fieldDescriptor isValidEnumValue:0]); + XCTAssertFalse([fieldDescriptor isValidEnumValue:-2]); +} + +- (void)testEnumDescriptorLookup { + GPBDescriptor *descriptor = [TestAllTypes descriptor]; + GPBEnumDescriptor *enumDescriptor = + [descriptor enumWithName:@"TestAllTypes_NestedEnum"]; + XCTAssertNotNil(enumDescriptor); + + // Descriptor cannot find foreign or imported enums. + enumDescriptor = [descriptor enumWithName:@"ForeignEnumEnum"]; + XCTAssertNil(enumDescriptor); + enumDescriptor = [descriptor enumWithName:@"ImportEnumEnum"]; + XCTAssertNil(enumDescriptor); +} + +- (void)testOneofDescriptor { + GPBDescriptor *descriptor = [TestOneof2 descriptor]; + + // All fields should be listed. + XCTAssertEqual(descriptor.fields.count, 17U); + + // There are two oneofs in there. + XCTAssertEqual(descriptor.oneofs.count, 2U); + + GPBFieldDescriptor *fooStringField = + [descriptor fieldWithNumber:TestOneof2_FieldNumber_FooString]; + XCTAssertNotNil(fooStringField); + GPBFieldDescriptor *barStringField = + [descriptor fieldWithNumber:TestOneof2_FieldNumber_BarString]; + XCTAssertNotNil(barStringField); + + // Check the oneofs to have what is expected. + + GPBOneofDescriptor *oneofFoo = [descriptor oneofWithName:@"foo"]; + XCTAssertNotNil(oneofFoo); + XCTAssertEqual(oneofFoo.fields.count, 9U); + + // Pointer comparisons. + XCTAssertEqual([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_FooString], + fooStringField); + XCTAssertEqual([oneofFoo fieldWithName:@"fooString"], fooStringField); + + GPBOneofDescriptor *oneofBar = [descriptor oneofWithName:@"bar"]; + XCTAssertNotNil(oneofBar); + XCTAssertEqual(oneofBar.fields.count, 6U); + + // Pointer comparisons. + XCTAssertEqual([oneofBar fieldWithNumber:TestOneof2_FieldNumber_BarString], + barStringField); + XCTAssertEqual([oneofBar fieldWithName:@"barString"], barStringField); + + // Unknown oneof not found. + + XCTAssertNil([descriptor oneofWithName:@"mumble"]); + XCTAssertNil([descriptor oneofWithName:@"Foo"]); + + // Unknown oneof item. + + XCTAssertNil([oneofFoo fieldWithName:@"mumble"]); + XCTAssertNil([oneofFoo fieldWithNumber:666]); + + // Field exists, but not in this oneof. + + XCTAssertNil([oneofFoo fieldWithName:@"barString"]); + XCTAssertNil([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_BarString]); + XCTAssertNil([oneofBar fieldWithName:@"fooString"]); + XCTAssertNil([oneofBar fieldWithNumber:TestOneof2_FieldNumber_FooString]); + + // Check pointers back to the enclosing oneofs. + // (pointer comparisions) + XCTAssertEqual(fooStringField.containingOneof, oneofFoo); + XCTAssertEqual(barStringField.containingOneof, oneofBar); + GPBFieldDescriptor *bazString = + [descriptor fieldWithNumber:TestOneof2_FieldNumber_BazString]; + XCTAssertNotNil(bazString); + XCTAssertNil(bazString.containingOneof); +} + +@end diff --git a/objectivec/Tests/GPBDictionaryTests+Bool.m b/objectivec/Tests/GPBDictionaryTests+Bool.m new file mode 100644 index 00000000..bc4998be --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+Bool.m @@ -0,0 +1,2421 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 +#import + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(UInt32, uint32_t, 100U, 101U) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> UInt32 + +@interface GPBBoolUInt32DictionaryTests : XCTestCase +@end + +@implementation GPBBoolUInt32DictionaryTests + +- (void)testEmpty { + GPBBoolUInt32Dictionary *dict = [[GPBBoolUInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolUInt32Dictionary *dict = [GPBBoolUInt32Dictionary dictionaryWithValue:100U forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + uint32_t *seenValues = malloc(2 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const uint32_t kValues1[] = { 100U, 101U }; + const uint32_t kValues2[] = { 101U, 100U }; + const uint32_t kValues3[] = { 101U }; + GPBBoolUInt32Dictionary *dict1 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolUInt32Dictionary *dict1prime = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolUInt32Dictionary *dict2 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolUInt32Dictionary *dict3 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolUInt32Dictionary *dict4 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolUInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt32Dictionary *dict2 = + [GPBBoolUInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolUInt32Dictionary *dict = [GPBBoolUInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const uint32_t kValues[] = { 101U }; + GPBBoolUInt32Dictionary *dict2 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const uint32_t kValues[] = { 100U, 101U }; + GPBBoolUInt32Dictionary *dict = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + [dict setValue:101U forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + [dict setValue:100U forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 100U); + + const BOOL kKeys2[] = { NO, YES }; + const uint32_t kValues2[] = { 101U, 100U }; + GPBBoolUInt32Dictionary *dict2 = + [[GPBBoolUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Int32, int32_t, 200, 201) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Int32 + +@interface GPBBoolInt32DictionaryTests : XCTestCase +@end + +@implementation GPBBoolInt32DictionaryTests + +- (void)testEmpty { + GPBBoolInt32Dictionary *dict = [[GPBBoolInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolInt32Dictionary *dict = [GPBBoolInt32Dictionary dictionaryWithValue:200 forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + int32_t *seenValues = malloc(2 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const int32_t kValues1[] = { 200, 201 }; + const int32_t kValues2[] = { 201, 200 }; + const int32_t kValues3[] = { 201 }; + GPBBoolInt32Dictionary *dict1 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolInt32Dictionary *dict1prime = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolInt32Dictionary *dict2 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolInt32Dictionary *dict3 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolInt32Dictionary *dict4 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt32Dictionary *dict2 = + [GPBBoolInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolInt32Dictionary *dict = [GPBBoolInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const int32_t kValues[] = { 201 }; + GPBBoolInt32Dictionary *dict2 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const int32_t kValues[] = { 200, 201 }; + GPBBoolInt32Dictionary *dict = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int32_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + [dict setValue:201 forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + [dict setValue:200 forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 200); + + const BOOL kKeys2[] = { NO, YES }; + const int32_t kValues2[] = { 201, 200 }; + GPBBoolInt32Dictionary *dict2 = + [[GPBBoolInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(UInt64, uint64_t, 300U, 301U) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> UInt64 + +@interface GPBBoolUInt64DictionaryTests : XCTestCase +@end + +@implementation GPBBoolUInt64DictionaryTests + +- (void)testEmpty { + GPBBoolUInt64Dictionary *dict = [[GPBBoolUInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolUInt64Dictionary *dict = [GPBBoolUInt64Dictionary dictionaryWithValue:300U forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + uint64_t *seenValues = malloc(2 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const uint64_t kValues1[] = { 300U, 301U }; + const uint64_t kValues2[] = { 301U, 300U }; + const uint64_t kValues3[] = { 301U }; + GPBBoolUInt64Dictionary *dict1 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolUInt64Dictionary *dict1prime = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolUInt64Dictionary *dict2 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolUInt64Dictionary *dict3 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolUInt64Dictionary *dict4 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolUInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolUInt64Dictionary *dict2 = + [GPBBoolUInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolUInt64Dictionary *dict = [GPBBoolUInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const uint64_t kValues[] = { 301U }; + GPBBoolUInt64Dictionary *dict2 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const uint64_t kValues[] = { 300U, 301U }; + GPBBoolUInt64Dictionary *dict = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + uint64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + [dict setValue:301U forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + [dict setValue:300U forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 300U); + + const BOOL kKeys2[] = { NO, YES }; + const uint64_t kValues2[] = { 301U, 300U }; + GPBBoolUInt64Dictionary *dict2 = + [[GPBBoolUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Int64, int64_t, 400, 401) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Int64 + +@interface GPBBoolInt64DictionaryTests : XCTestCase +@end + +@implementation GPBBoolInt64DictionaryTests + +- (void)testEmpty { + GPBBoolInt64Dictionary *dict = [[GPBBoolInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolInt64Dictionary *dict = [GPBBoolInt64Dictionary dictionaryWithValue:400 forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + int64_t *seenValues = malloc(2 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const int64_t kValues1[] = { 400, 401 }; + const int64_t kValues2[] = { 401, 400 }; + const int64_t kValues3[] = { 401 }; + GPBBoolInt64Dictionary *dict1 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolInt64Dictionary *dict1prime = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolInt64Dictionary *dict2 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolInt64Dictionary *dict3 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolInt64Dictionary *dict4 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolInt64Dictionary *dict2 = + [GPBBoolInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolInt64Dictionary *dict = [GPBBoolInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const int64_t kValues[] = { 401 }; + GPBBoolInt64Dictionary *dict2 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const int64_t kValues[] = { 400, 401 }; + GPBBoolInt64Dictionary *dict = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + int64_t value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + [dict setValue:401 forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + [dict setValue:400 forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 400); + + const BOOL kKeys2[] = { NO, YES }; + const int64_t kValues2[] = { 401, 400 }; + GPBBoolInt64Dictionary *dict2 = + [[GPBBoolInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Bool, BOOL, NO, YES) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Bool + +@interface GPBBoolBoolDictionaryTests : XCTestCase +@end + +@implementation GPBBoolBoolDictionaryTests + +- (void)testEmpty { + GPBBoolBoolDictionary *dict = [[GPBBoolBoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolBoolDictionary *dict = [GPBBoolBoolDictionary dictionaryWithValue:NO forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, NO); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + BOOL *seenValues = malloc(2 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const BOOL kValues1[] = { NO, YES }; + const BOOL kValues2[] = { YES, NO }; + const BOOL kValues3[] = { YES }; + GPBBoolBoolDictionary *dict1 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolBoolDictionary *dict1prime = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolBoolDictionary *dict2 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolBoolDictionary *dict3 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolBoolDictionary *dict4 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolBoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolBoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolBoolDictionary *dict2 = + [GPBBoolBoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolBoolDictionary *dict = [GPBBoolBoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:NO forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const BOOL kValues[] = { YES }; + GPBBoolBoolDictionary *dict2 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const BOOL kValues[] = { NO, YES }; + GPBBoolBoolDictionary *dict = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + BOOL value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + [dict setValue:YES forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + [dict setValue:NO forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, NO); + + const BOOL kKeys2[] = { NO, YES }; + const BOOL kValues2[] = { YES, NO }; + GPBBoolBoolDictionary *dict2 = + [[GPBBoolBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Float, float, 500.f, 501.f) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Float + +@interface GPBBoolFloatDictionaryTests : XCTestCase +@end + +@implementation GPBBoolFloatDictionaryTests + +- (void)testEmpty { + GPBBoolFloatDictionary *dict = [[GPBBoolFloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolFloatDictionary *dict = [GPBBoolFloatDictionary dictionaryWithValue:500.f forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + float *seenValues = malloc(2 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const float kValues1[] = { 500.f, 501.f }; + const float kValues2[] = { 501.f, 500.f }; + const float kValues3[] = { 501.f }; + GPBBoolFloatDictionary *dict1 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolFloatDictionary *dict1prime = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolFloatDictionary *dict2 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolFloatDictionary *dict3 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolFloatDictionary *dict4 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolFloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolFloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolFloatDictionary *dict2 = + [GPBBoolFloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolFloatDictionary *dict = [GPBBoolFloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const float kValues[] = { 501.f }; + GPBBoolFloatDictionary *dict2 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const float kValues[] = { 500.f, 501.f }; + GPBBoolFloatDictionary *dict = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + float value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + [dict setValue:501.f forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + [dict setValue:500.f forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 500.f); + + const BOOL kKeys2[] = { NO, YES }; + const float kValues2[] = { 501.f, 500.f }; + GPBBoolFloatDictionary *dict2 = + [[GPBBoolFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND BOOL_TESTS_FOR_POD_VALUE(Double, double, 600., 601.) +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Double + +@interface GPBBoolDoubleDictionaryTests : XCTestCase +@end + +@implementation GPBBoolDoubleDictionaryTests + +- (void)testEmpty { + GPBBoolDoubleDictionary *dict = [[GPBBoolDoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolDoubleDictionary *dict = [GPBBoolDoubleDictionary dictionaryWithValue:600. forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + double *seenValues = malloc(2 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const double kValues1[] = { 600., 601. }; + const double kValues2[] = { 601., 600. }; + const double kValues3[] = { 601. }; + GPBBoolDoubleDictionary *dict1 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolDoubleDictionary *dict1prime = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolDoubleDictionary *dict2 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolDoubleDictionary *dict3 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolDoubleDictionary *dict4 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolDoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolDoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolDoubleDictionary *dict2 = + [GPBBoolDoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolDoubleDictionary *dict = [GPBBoolDoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const double kValues[] = { 601. }; + GPBBoolDoubleDictionary *dict2 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:YES value:NULL]); + XCTAssertFalse([dict valueForKey:NO value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const double kValues[] = { 600., 601. }; + GPBBoolDoubleDictionary *dict = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + double value; + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + [dict setValue:601. forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + [dict setValue:600. forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 600.); + + const BOOL kKeys2[] = { NO, YES }; + const double kValues2[] = { 601., 600. }; + GPBBoolDoubleDictionary *dict2 = + [[GPBBoolDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:YES value:NULL]); + XCTAssertTrue([dict valueForKey:YES value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:NO value:NULL]); + XCTAssertTrue([dict valueForKey:NO value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND TESTS_FOR_BOOL_KEY_OBJECT_VALUE(Object, id, @"abc", @"def") +// This block of code is generated, do not edit it directly. + +#pragma mark - Bool -> Object + +@interface GPBBoolObjectDictionaryTests : XCTestCase +@end + +@implementation GPBBoolObjectDictionaryTests + +- (void)testEmpty { + GPBBoolObjectDictionary *dict = [[GPBBoolObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:YES]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBBoolObjectDictionary *dict = [GPBBoolObjectDictionary dictionaryWithValue:@"abc" forKey:YES]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertNil([dict valueForKey:NO]); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, YES); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + __block NSUInteger idx = 0; + BOOL *seenKeys = malloc(2 * sizeof(BOOL)); + id *seenValues = malloc(2 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 2U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 2; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 2) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(BOOL aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 0) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const BOOL kKeys1[] = { YES, NO }; + const BOOL kKeys2[] = { NO, YES }; + const id kValues1[] = { @"abc", @"def" }; + const id kValues2[] = { @"def", @"abc" }; + const id kValues3[] = { @"def" }; + GPBBoolObjectDictionary *dict1 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBBoolObjectDictionary *dict1prime = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBBoolObjectDictionary *dict2 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBBoolObjectDictionary *dict3 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBBoolObjectDictionary *dict4 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 Fewer pairs; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBBoolObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBBoolObjectDictionary *dict2 = + [GPBBoolObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBBoolObjectDictionary *dict = [GPBBoolObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:YES]; + XCTAssertEqual(dict.count, 1U); + + const BOOL kKeys[] = { NO }; + const id kValues[] = { @"def" }; + GPBBoolObjectDictionary *dict2 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + [dict2 release]; +} + +- (void)testRemove { + const BOOL kKeys[] = { YES, NO}; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertNil([dict valueForKey:NO]); + + // Remove again does nothing. + [dict removeValueForKey:NO]; + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertNil([dict valueForKey:NO]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:YES]); + XCTAssertNil([dict valueForKey:NO]); + [dict release]; +} + +- (void)testInplaceMutation { + const BOOL kKeys[] = { YES, NO }; + const id kValues[] = { @"abc", @"def" }; + GPBBoolObjectDictionary *dict = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + [dict setValue:@"def" forKey:YES]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"def"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + [dict setValue:@"abc" forKey:NO]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"def"); + XCTAssertEqualObjects([dict valueForKey:NO], @"abc"); + + const BOOL kKeys2[] = { NO, YES }; + const id kValues2[] = { @"def", @"abc" }; + GPBBoolObjectDictionary *dict2 = + [[GPBBoolObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:YES], @"abc"); + XCTAssertEqualObjects([dict valueForKey:NO], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END (8 expansions) + + diff --git a/objectivec/Tests/GPBDictionaryTests+Int32.m b/objectivec/Tests/GPBDictionaryTests+Int32.m new file mode 100644 index 00000000..5e25799c --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+Int32.m @@ -0,0 +1,3650 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 +#import + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(Int32, int32_t, 11, 12, 13, 14) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int32_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int32_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBInt32EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int32_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - Int32 -> UInt32 + +@interface GPBInt32UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBInt32UInt32DictionaryTests + +- (void)testEmpty { + GPBInt32UInt32Dictionary *dict = [[GPBInt32UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32UInt32Dictionary *dict = [GPBInt32UInt32Dictionary dictionaryWithValue:100U forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict1 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32UInt32Dictionary *dict1prime = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32UInt32Dictionary *dict2 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32UInt32Dictionary *dict3 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32UInt32Dictionary *dict4 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt32Dictionary *dict2 = + [GPBInt32UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32UInt32Dictionary *dict = [GPBInt32UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict2 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt32UInt32Dictionary *dict = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 101U); + + const int32_t kKeys2[] = { 12, 13 }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBInt32UInt32Dictionary *dict2 = + [[GPBInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Int32 + +@interface GPBInt32Int32DictionaryTests : XCTestCase +@end + +@implementation GPBInt32Int32DictionaryTests + +- (void)testEmpty { + GPBInt32Int32Dictionary *dict = [[GPBInt32Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32Int32Dictionary *dict = [GPBInt32Int32Dictionary dictionaryWithValue:200 forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict1 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32Int32Dictionary *dict1prime = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32Int32Dictionary *dict2 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32Int32Dictionary *dict3 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32Int32Dictionary *dict4 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int32Dictionary *dict2 = + [GPBInt32Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32Int32Dictionary *dict = [GPBInt32Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBInt32Int32Dictionary *dict2 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt32Int32Dictionary *dict = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 201); + + const int32_t kKeys2[] = { 12, 13 }; + const int32_t kValues2[] = { 202, 200 }; + GPBInt32Int32Dictionary *dict2 = + [[GPBInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> UInt64 + +@interface GPBInt32UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBInt32UInt64DictionaryTests + +- (void)testEmpty { + GPBInt32UInt64Dictionary *dict = [[GPBInt32UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32UInt64Dictionary *dict = [GPBInt32UInt64Dictionary dictionaryWithValue:300U forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict1 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32UInt64Dictionary *dict1prime = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32UInt64Dictionary *dict2 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32UInt64Dictionary *dict3 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32UInt64Dictionary *dict4 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32UInt64Dictionary *dict2 = + [GPBInt32UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32UInt64Dictionary *dict = [GPBInt32UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict2 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt32UInt64Dictionary *dict = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 301U); + + const int32_t kKeys2[] = { 12, 13 }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBInt32UInt64Dictionary *dict2 = + [[GPBInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Int64 + +@interface GPBInt32Int64DictionaryTests : XCTestCase +@end + +@implementation GPBInt32Int64DictionaryTests + +- (void)testEmpty { + GPBInt32Int64Dictionary *dict = [[GPBInt32Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32Int64Dictionary *dict = [GPBInt32Int64Dictionary dictionaryWithValue:400 forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict1 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32Int64Dictionary *dict1prime = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32Int64Dictionary *dict2 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32Int64Dictionary *dict3 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32Int64Dictionary *dict4 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32Int64Dictionary *dict2 = + [GPBInt32Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32Int64Dictionary *dict = [GPBInt32Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBInt32Int64Dictionary *dict2 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt32Int64Dictionary *dict = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 401); + + const int32_t kKeys2[] = { 12, 13 }; + const int64_t kValues2[] = { 402, 400 }; + GPBInt32Int64Dictionary *dict2 = + [[GPBInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Bool + +@interface GPBInt32BoolDictionaryTests : XCTestCase +@end + +@implementation GPBInt32BoolDictionaryTests + +- (void)testEmpty { + GPBInt32BoolDictionary *dict = [[GPBInt32BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32BoolDictionary *dict = [GPBInt32BoolDictionary dictionaryWithValue:YES forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const BOOL kValues[] = { YES, YES, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict1 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32BoolDictionary *dict1prime = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32BoolDictionary *dict2 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32BoolDictionary *dict3 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32BoolDictionary *dict4 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32BoolDictionary *dict2 = + [GPBInt32BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32BoolDictionary *dict = [GPBInt32BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const BOOL kValues[] = { YES, NO, NO }; + GPBInt32BoolDictionary *dict2 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt32BoolDictionary *dict = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, YES); + + const int32_t kKeys2[] = { 12, 13 }; + const BOOL kValues2[] = { NO, YES }; + GPBInt32BoolDictionary *dict2 = + [[GPBInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Float + +@interface GPBInt32FloatDictionaryTests : XCTestCase +@end + +@implementation GPBInt32FloatDictionaryTests + +- (void)testEmpty { + GPBInt32FloatDictionary *dict = [[GPBInt32FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32FloatDictionary *dict = [GPBInt32FloatDictionary dictionaryWithValue:500.f forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict1 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32FloatDictionary *dict1prime = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32FloatDictionary *dict2 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32FloatDictionary *dict3 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32FloatDictionary *dict4 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32FloatDictionary *dict2 = + [GPBInt32FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32FloatDictionary *dict = [GPBInt32FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict2 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt32FloatDictionary *dict = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 501.f); + + const int32_t kKeys2[] = { 12, 13 }; + const float kValues2[] = { 502.f, 500.f }; + GPBInt32FloatDictionary *dict2 = + [[GPBInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Double + +@interface GPBInt32DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBInt32DoubleDictionaryTests + +- (void)testEmpty { + GPBInt32DoubleDictionary *dict = [[GPBInt32DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32DoubleDictionary *dict = [GPBInt32DoubleDictionary dictionaryWithValue:600. forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const double kValues[] = { 600., 601., 602. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict1 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32DoubleDictionary *dict1prime = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32DoubleDictionary *dict2 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32DoubleDictionary *dict3 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32DoubleDictionary *dict4 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32DoubleDictionary *dict2 = + [GPBInt32DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32DoubleDictionary *dict = [GPBInt32DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const double kValues[] = { 601., 602., 603. }; + GPBInt32DoubleDictionary *dict2 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt32DoubleDictionary *dict = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 601.); + + const int32_t kKeys2[] = { 12, 13 }; + const double kValues2[] = { 602., 600. }; + GPBInt32DoubleDictionary *dict2 = + [[GPBInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Enum + +@interface GPBInt32EnumDictionaryTests : XCTestCase +@end + +@implementation GPBInt32EnumDictionaryTests + +- (void)testEmpty { + GPBInt32EnumDictionary *dict = [[GPBInt32EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32EnumDictionary *dict = [GPBInt32EnumDictionary dictionaryWithValue:700 forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict1 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32EnumDictionary *dict1prime = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32EnumDictionary *dict3 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32EnumDictionary *dict4 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = + [GPBInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32EnumDictionary *dict = [GPBInt32EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 701); + + const int32_t kKeys2[] = { 12, 13 }; + const int32_t kValues2[] = { 702, 700 }; + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Enum (Unknown Enums) + +@interface GPBInt32EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBInt32EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:13 rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 rawValue:NULL]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict1 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32EnumDictionary *dict1prime = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32EnumDictionary *dict3 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32EnumDictionary *dict4 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = + [GPBInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBInt32EnumDictionary *dict = + [GPBInt32EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:12], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:12]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 11, 13, 14 }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:11 value:NULL]); + XCTAssertFalse([dict valueForKey:12 value:NULL]); + XCTAssertFalse([dict valueForKey:13 value:NULL]); + XCTAssertFalse([dict valueForKey:14 value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:11], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 value:NULL]); + XCTAssertTrue([dict valueForKey:11 value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:11]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:14 rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:12 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:12 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:13 value:NULL]); + XCTAssertTrue([dict valueForKey:13 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 700); + + const int32_t kKeys2[] = { 12, 13 }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBInt32EnumDictionary *dict2 = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:11 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:11 rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:12 value:NULL]); + XCTAssertTrue([dict valueForKey:12 value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:13 rawValue:NULL]); + XCTAssertTrue([dict valueForKey:13 rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:14 value:NULL]); + XCTAssertTrue([dict valueForKey:14 value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBInt32EnumDictionary *dict = + [[GPBInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int32 -> Object + +@interface GPBInt32ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBInt32ObjectDictionaryTests + +- (void)testEmpty { + GPBInt32ObjectDictionary *dict = [[GPBInt32ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:11]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt32ObjectDictionary *dict = [GPBInt32ObjectDictionary dictionaryWithValue:@"abc" forKey:11]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 11); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int32_t kKeys[] = { 11, 12, 13 }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertNil([dict valueForKey:14]); + + __block NSUInteger idx = 0; + int32_t *seenKeys = malloc(3 * sizeof(int32_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int32_t kKeys1[] = { 11, 12, 13, 14 }; + const int32_t kKeys2[] = { 12, 11, 14 }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict1 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt32ObjectDictionary *dict1prime = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt32ObjectDictionary *dict2 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt32ObjectDictionary *dict3 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt32ObjectDictionary *dict4 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt32ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt32ObjectDictionary *dict2 = + [GPBInt32ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt32ObjectDictionary *dict = [GPBInt32ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:11]; + XCTAssertEqual(dict.count, 1U); + + const int32_t kKeys[] = { 12, 13, 14 }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict2 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:12]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + [dict removeValueForKey:14]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertNil([dict valueForKey:12]); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertNil([dict valueForKey:14]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:11]); + XCTAssertNil([dict valueForKey:12]); + XCTAssertNil([dict valueForKey:13]); + XCTAssertNil([dict valueForKey:14]); + [dict release]; +} + +- (void)testInplaceMutation { + const int32_t kKeys[] = { 11, 12, 13, 14 }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt32ObjectDictionary *dict = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"abc"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + [dict setValue:@"jkl" forKey:11]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"jkl"); + + [dict setValue:@"def" forKey:14]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:12], @"def"); + XCTAssertEqualObjects([dict valueForKey:13], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:14], @"def"); + + const int32_t kKeys2[] = { 12, 13 }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBInt32ObjectDictionary *dict2 = + [[GPBInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:11], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:12], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:13], @"abc"); + XCTAssertEqualObjects([dict valueForKey:14], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(Int32, int32_t, 11, 12, 13, 14) + diff --git a/objectivec/Tests/GPBDictionaryTests+Int64.m b/objectivec/Tests/GPBDictionaryTests+Int64.m new file mode 100644 index 00000000..6e794d38 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+Int64.m @@ -0,0 +1,3650 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 +#import + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(Int64, int64_t, 21LL, 22LL, 23LL, 24LL) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int64_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(int64_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBInt64EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const int64_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - Int64 -> UInt32 + +@interface GPBInt64UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBInt64UInt32DictionaryTests + +- (void)testEmpty { + GPBInt64UInt32Dictionary *dict = [[GPBInt64UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64UInt32Dictionary *dict = [GPBInt64UInt32Dictionary dictionaryWithValue:100U forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict1 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64UInt32Dictionary *dict1prime = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64UInt32Dictionary *dict2 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64UInt32Dictionary *dict3 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64UInt32Dictionary *dict4 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt32Dictionary *dict2 = + [GPBInt64UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64UInt32Dictionary *dict = [GPBInt64UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict2 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBInt64UInt32Dictionary *dict = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 101U); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBInt64UInt32Dictionary *dict2 = + [[GPBInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Int32 + +@interface GPBInt64Int32DictionaryTests : XCTestCase +@end + +@implementation GPBInt64Int32DictionaryTests + +- (void)testEmpty { + GPBInt64Int32Dictionary *dict = [[GPBInt64Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64Int32Dictionary *dict = [GPBInt64Int32Dictionary dictionaryWithValue:200 forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict1 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64Int32Dictionary *dict1prime = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64Int32Dictionary *dict2 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64Int32Dictionary *dict3 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64Int32Dictionary *dict4 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int32Dictionary *dict2 = + [GPBInt64Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64Int32Dictionary *dict = [GPBInt64Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBInt64Int32Dictionary *dict2 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBInt64Int32Dictionary *dict = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 201); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int32_t kValues2[] = { 202, 200 }; + GPBInt64Int32Dictionary *dict2 = + [[GPBInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> UInt64 + +@interface GPBInt64UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBInt64UInt64DictionaryTests + +- (void)testEmpty { + GPBInt64UInt64Dictionary *dict = [[GPBInt64UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64UInt64Dictionary *dict = [GPBInt64UInt64Dictionary dictionaryWithValue:300U forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict1 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64UInt64Dictionary *dict1prime = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64UInt64Dictionary *dict2 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64UInt64Dictionary *dict3 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64UInt64Dictionary *dict4 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64UInt64Dictionary *dict2 = + [GPBInt64UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64UInt64Dictionary *dict = [GPBInt64UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict2 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBInt64UInt64Dictionary *dict = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 301U); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBInt64UInt64Dictionary *dict2 = + [[GPBInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Int64 + +@interface GPBInt64Int64DictionaryTests : XCTestCase +@end + +@implementation GPBInt64Int64DictionaryTests + +- (void)testEmpty { + GPBInt64Int64Dictionary *dict = [[GPBInt64Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64Int64Dictionary *dict = [GPBInt64Int64Dictionary dictionaryWithValue:400 forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict1 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64Int64Dictionary *dict1prime = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64Int64Dictionary *dict2 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64Int64Dictionary *dict3 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64Int64Dictionary *dict4 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64Int64Dictionary *dict2 = + [GPBInt64Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64Int64Dictionary *dict = [GPBInt64Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBInt64Int64Dictionary *dict2 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBInt64Int64Dictionary *dict = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 401); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int64_t kValues2[] = { 402, 400 }; + GPBInt64Int64Dictionary *dict2 = + [[GPBInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Bool + +@interface GPBInt64BoolDictionaryTests : XCTestCase +@end + +@implementation GPBInt64BoolDictionaryTests + +- (void)testEmpty { + GPBInt64BoolDictionary *dict = [[GPBInt64BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64BoolDictionary *dict = [GPBInt64BoolDictionary dictionaryWithValue:YES forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const BOOL kValues[] = { YES, YES, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict1 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64BoolDictionary *dict1prime = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64BoolDictionary *dict2 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64BoolDictionary *dict3 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64BoolDictionary *dict4 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64BoolDictionary *dict2 = + [GPBInt64BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64BoolDictionary *dict = [GPBInt64BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, NO, NO }; + GPBInt64BoolDictionary *dict2 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBInt64BoolDictionary *dict = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, YES); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const BOOL kValues2[] = { NO, YES }; + GPBInt64BoolDictionary *dict2 = + [[GPBInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Float + +@interface GPBInt64FloatDictionaryTests : XCTestCase +@end + +@implementation GPBInt64FloatDictionaryTests + +- (void)testEmpty { + GPBInt64FloatDictionary *dict = [[GPBInt64FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64FloatDictionary *dict = [GPBInt64FloatDictionary dictionaryWithValue:500.f forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict1 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64FloatDictionary *dict1prime = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64FloatDictionary *dict2 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64FloatDictionary *dict3 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64FloatDictionary *dict4 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64FloatDictionary *dict2 = + [GPBInt64FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64FloatDictionary *dict = [GPBInt64FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict2 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBInt64FloatDictionary *dict = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 501.f); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const float kValues2[] = { 502.f, 500.f }; + GPBInt64FloatDictionary *dict2 = + [[GPBInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Double + +@interface GPBInt64DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBInt64DoubleDictionaryTests + +- (void)testEmpty { + GPBInt64DoubleDictionary *dict = [[GPBInt64DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64DoubleDictionary *dict = [GPBInt64DoubleDictionary dictionaryWithValue:600. forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const double kValues[] = { 600., 601., 602. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict1 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64DoubleDictionary *dict1prime = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64DoubleDictionary *dict2 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64DoubleDictionary *dict3 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64DoubleDictionary *dict4 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64DoubleDictionary *dict2 = + [GPBInt64DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64DoubleDictionary *dict = [GPBInt64DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const double kValues[] = { 601., 602., 603. }; + GPBInt64DoubleDictionary *dict2 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBInt64DoubleDictionary *dict = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 601.); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const double kValues2[] = { 602., 600. }; + GPBInt64DoubleDictionary *dict2 = + [[GPBInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Enum + +@interface GPBInt64EnumDictionaryTests : XCTestCase +@end + +@implementation GPBInt64EnumDictionaryTests + +- (void)testEmpty { + GPBInt64EnumDictionary *dict = [[GPBInt64EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64EnumDictionary *dict = [GPBInt64EnumDictionary dictionaryWithValue:700 forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict1 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64EnumDictionary *dict1prime = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64EnumDictionary *dict3 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64EnumDictionary *dict4 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = + [GPBInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64EnumDictionary *dict = [GPBInt64EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 701); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int32_t kValues2[] = { 702, 700 }; + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Enum (Unknown Enums) + +@interface GPBInt64EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBInt64EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:23LL rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL rawValue:NULL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(int64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict1 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64EnumDictionary *dict1prime = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64EnumDictionary *dict3 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64EnumDictionary *dict4 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = + [GPBInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBInt64EnumDictionary *dict = + [GPBInt64EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:22LL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:22LL]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 21LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:21LL value:NULL]); + XCTAssertFalse([dict valueForKey:22LL value:NULL]); + XCTAssertFalse([dict valueForKey:23LL value:NULL]); + XCTAssertFalse([dict valueForKey:24LL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:21LL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL value:NULL]); + XCTAssertTrue([dict valueForKey:21LL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:21LL]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:24LL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:22LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:22LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:23LL value:NULL]); + XCTAssertTrue([dict valueForKey:23LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 700); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBInt64EnumDictionary *dict2 = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:21LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:21LL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:22LL value:NULL]); + XCTAssertTrue([dict valueForKey:22LL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:23LL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:23LL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:24LL value:NULL]); + XCTAssertTrue([dict valueForKey:24LL value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBInt64EnumDictionary *dict = + [[GPBInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - Int64 -> Object + +@interface GPBInt64ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBInt64ObjectDictionaryTests + +- (void)testEmpty { + GPBInt64ObjectDictionary *dict = [[GPBInt64ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:21LL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBInt64ObjectDictionary *dict = [GPBInt64ObjectDictionary dictionaryWithValue:@"abc" forKey:21LL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 21LL); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const int64_t kKeys[] = { 21LL, 22LL, 23LL }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertNil([dict valueForKey:24LL]); + + __block NSUInteger idx = 0; + int64_t *seenKeys = malloc(3 * sizeof(int64_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(int64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const int64_t kKeys1[] = { 21LL, 22LL, 23LL, 24LL }; + const int64_t kKeys2[] = { 22LL, 21LL, 24LL }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict1 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBInt64ObjectDictionary *dict1prime = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBInt64ObjectDictionary *dict2 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBInt64ObjectDictionary *dict3 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBInt64ObjectDictionary *dict4 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBInt64ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBInt64ObjectDictionary *dict2 = + [GPBInt64ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBInt64ObjectDictionary *dict = [GPBInt64ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:21LL]; + XCTAssertEqual(dict.count, 1U); + + const int64_t kKeys[] = { 22LL, 23LL, 24LL }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict2 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:22LL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + [dict removeValueForKey:24LL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertNil([dict valueForKey:24LL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:21LL]); + XCTAssertNil([dict valueForKey:22LL]); + XCTAssertNil([dict valueForKey:23LL]); + XCTAssertNil([dict valueForKey:24LL]); + [dict release]; +} + +- (void)testInplaceMutation { + const int64_t kKeys[] = { 21LL, 22LL, 23LL, 24LL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBInt64ObjectDictionary *dict = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + [dict setValue:@"jkl" forKey:21LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"jkl"); + + [dict setValue:@"def" forKey:24LL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"def"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"def"); + + const int64_t kKeys2[] = { 22LL, 23LL }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBInt64ObjectDictionary *dict2 = + [[GPBInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:21LL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:22LL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:23LL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:24LL], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(Int64, int64_t, 21LL, 22LL, 23LL, 24LL) + diff --git a/objectivec/Tests/GPBDictionaryTests+String.m b/objectivec/Tests/GPBDictionaryTests+String.m new file mode 100644 index 00000000..95bf2d06 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+String.m @@ -0,0 +1,3362 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 +#import + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble") +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBStringEnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(NSString *)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBStringEnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(NSString *)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBStringEnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const NSString * [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - String -> UInt32 + +@interface GPBStringUInt32DictionaryTests : XCTestCase +@end + +@implementation GPBStringUInt32DictionaryTests + +- (void)testEmpty { + GPBStringUInt32Dictionary *dict = [[GPBStringUInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringUInt32Dictionary *dict = [GPBStringUInt32Dictionary dictionaryWithValue:100U forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict1 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringUInt32Dictionary *dict1prime = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringUInt32Dictionary *dict2 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringUInt32Dictionary *dict3 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringUInt32Dictionary *dict4 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt32Dictionary *dict2 = + [GPBStringUInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringUInt32Dictionary *dict = [GPBStringUInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict2 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBStringUInt32Dictionary *dict = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 101U); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBStringUInt32Dictionary *dict2 = + [[GPBStringUInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Int32 + +@interface GPBStringInt32DictionaryTests : XCTestCase +@end + +@implementation GPBStringInt32DictionaryTests + +- (void)testEmpty { + GPBStringInt32Dictionary *dict = [[GPBStringInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringInt32Dictionary *dict = [GPBStringInt32Dictionary dictionaryWithValue:200 forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict1 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringInt32Dictionary *dict1prime = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringInt32Dictionary *dict2 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringInt32Dictionary *dict3 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringInt32Dictionary *dict4 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt32Dictionary *dict2 = + [GPBStringInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringInt32Dictionary *dict = [GPBStringInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBStringInt32Dictionary *dict2 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBStringInt32Dictionary *dict = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 201); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int32_t kValues2[] = { 202, 200 }; + GPBStringInt32Dictionary *dict2 = + [[GPBStringInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> UInt64 + +@interface GPBStringUInt64DictionaryTests : XCTestCase +@end + +@implementation GPBStringUInt64DictionaryTests + +- (void)testEmpty { + GPBStringUInt64Dictionary *dict = [[GPBStringUInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringUInt64Dictionary *dict = [GPBStringUInt64Dictionary dictionaryWithValue:300U forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict1 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringUInt64Dictionary *dict1prime = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringUInt64Dictionary *dict2 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringUInt64Dictionary *dict3 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringUInt64Dictionary *dict4 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringUInt64Dictionary *dict2 = + [GPBStringUInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringUInt64Dictionary *dict = [GPBStringUInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict2 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBStringUInt64Dictionary *dict = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 301U); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBStringUInt64Dictionary *dict2 = + [[GPBStringUInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Int64 + +@interface GPBStringInt64DictionaryTests : XCTestCase +@end + +@implementation GPBStringInt64DictionaryTests + +- (void)testEmpty { + GPBStringInt64Dictionary *dict = [[GPBStringInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringInt64Dictionary *dict = [GPBStringInt64Dictionary dictionaryWithValue:400 forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict1 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringInt64Dictionary *dict1prime = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringInt64Dictionary *dict2 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringInt64Dictionary *dict3 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringInt64Dictionary *dict4 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringInt64Dictionary *dict2 = + [GPBStringInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringInt64Dictionary *dict = [GPBStringInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBStringInt64Dictionary *dict2 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBStringInt64Dictionary *dict = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 401); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int64_t kValues2[] = { 402, 400 }; + GPBStringInt64Dictionary *dict2 = + [[GPBStringInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Bool + +@interface GPBStringBoolDictionaryTests : XCTestCase +@end + +@implementation GPBStringBoolDictionaryTests + +- (void)testEmpty { + GPBStringBoolDictionary *dict = [[GPBStringBoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringBoolDictionary *dict = [GPBStringBoolDictionary dictionaryWithValue:YES forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const BOOL kValues[] = { YES, YES, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict1 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringBoolDictionary *dict1prime = + [[GPBStringBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringBoolDictionary *dict2 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringBoolDictionary *dict3 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringBoolDictionary *dict4 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringBoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringBoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringBoolDictionary *dict2 = + [GPBStringBoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringBoolDictionary *dict = [GPBStringBoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, NO, NO }; + GPBStringBoolDictionary *dict2 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBStringBoolDictionary *dict = + [[GPBStringBoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, YES); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const BOOL kValues2[] = { NO, YES }; + GPBStringBoolDictionary *dict2 = + [[GPBStringBoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Float + +@interface GPBStringFloatDictionaryTests : XCTestCase +@end + +@implementation GPBStringFloatDictionaryTests + +- (void)testEmpty { + GPBStringFloatDictionary *dict = [[GPBStringFloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringFloatDictionary *dict = [GPBStringFloatDictionary dictionaryWithValue:500.f forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict1 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringFloatDictionary *dict1prime = + [[GPBStringFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringFloatDictionary *dict2 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringFloatDictionary *dict3 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringFloatDictionary *dict4 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringFloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringFloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringFloatDictionary *dict2 = + [GPBStringFloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringFloatDictionary *dict = [GPBStringFloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict2 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBStringFloatDictionary *dict = + [[GPBStringFloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 501.f); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const float kValues2[] = { 502.f, 500.f }; + GPBStringFloatDictionary *dict2 = + [[GPBStringFloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Double + +@interface GPBStringDoubleDictionaryTests : XCTestCase +@end + +@implementation GPBStringDoubleDictionaryTests + +- (void)testEmpty { + GPBStringDoubleDictionary *dict = [[GPBStringDoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringDoubleDictionary *dict = [GPBStringDoubleDictionary dictionaryWithValue:600. forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const double kValues[] = { 600., 601., 602. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict1 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringDoubleDictionary *dict1prime = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringDoubleDictionary *dict2 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringDoubleDictionary *dict3 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringDoubleDictionary *dict4 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringDoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringDoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringDoubleDictionary *dict2 = + [GPBStringDoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringDoubleDictionary *dict = [GPBStringDoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const double kValues[] = { 601., 602., 603. }; + GPBStringDoubleDictionary *dict2 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBStringDoubleDictionary *dict = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 601.); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const double kValues2[] = { 602., 600. }; + GPBStringDoubleDictionary *dict2 = + [[GPBStringDoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Enum + +@interface GPBStringEnumDictionaryTests : XCTestCase +@end + +@implementation GPBStringEnumDictionaryTests + +- (void)testEmpty { + GPBStringEnumDictionary *dict = [[GPBStringEnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBStringEnumDictionary *dict = [GPBStringEnumDictionary dictionaryWithValue:700 forKey:@"foo"]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqualObjects(aKey, @"foo"); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict1 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringEnumDictionary *dict1prime = + [[GPBStringEnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringEnumDictionary *dict3 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringEnumDictionary *dict4 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = + [GPBStringEnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBStringEnumDictionary *dict = [GPBStringEnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:@"foo"]; + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:@"foo"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 701); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int32_t kValues2[] = { 702, 700 }; + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - String -> Enum (Unknown Enums) + +@interface GPBStringEnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBStringEnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const NSString *kKeys[] = { @"foo", @"bar", @"baz" }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" rawValue:NULL]); + + __block NSUInteger idx = 0; + NSString **seenKeys = malloc(3 * sizeof(NSString*)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if ([kKeys[i] isEqual:seenKeys[j]]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" }; + const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict1 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBStringEnumDictionary *dict1prime = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBStringEnumDictionary *dict3 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBStringEnumDictionary *dict4 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = + [GPBStringEnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBStringEnumDictionary *dict = + [GPBStringEnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:@"bar"], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:@"bar"]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const NSString *kKeys[] = { @"foo", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:@"bar"]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:@"mumble"]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:@"foo" value:NULL]); + XCTAssertFalse([dict valueForKey:@"bar" value:NULL]); + XCTAssertFalse([dict valueForKey:@"baz" value:NULL]); + XCTAssertFalse([dict valueForKey:@"mumble" value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:@"foo"], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" value:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:@"foo"]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:@"mumble"]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"baz" value:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 700); + + const NSString *kKeys2[] = { @"bar", @"baz" }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBStringEnumDictionary *dict2 = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"foo" rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:@"bar" value:NULL]); + XCTAssertTrue([dict valueForKey:@"bar" value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:NULL]); + XCTAssertTrue([dict valueForKey:@"baz" rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:@"mumble" value:NULL]); + XCTAssertTrue([dict valueForKey:@"mumble" value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBStringEnumDictionary *dict = + [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBStringEnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble") + diff --git a/objectivec/Tests/GPBDictionaryTests+UInt32.m b/objectivec/Tests/GPBDictionaryTests+UInt32.m new file mode 100644 index 00000000..a89ded3d --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+UInt32.m @@ -0,0 +1,3650 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 +#import + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(UInt32, uint32_t, 1U, 2U, 3U, 4U) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBUInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint32_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBUInt32EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint32_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBUInt32EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint32_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - UInt32 -> UInt32 + +@interface GPBUInt32UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32UInt32DictionaryTests + +- (void)testEmpty { + GPBUInt32UInt32Dictionary *dict = [[GPBUInt32UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32UInt32Dictionary *dict = [GPBUInt32UInt32Dictionary dictionaryWithValue:100U forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict1 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32UInt32Dictionary *dict1prime = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32UInt32Dictionary *dict2 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32UInt32Dictionary *dict3 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32UInt32Dictionary *dict4 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt32Dictionary *dict2 = + [GPBUInt32UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32UInt32Dictionary *dict = [GPBUInt32UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict2 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt32UInt32Dictionary *dict = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 101U); + + const uint32_t kKeys2[] = { 2U, 3U }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBUInt32UInt32Dictionary *dict2 = + [[GPBUInt32UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Int32 + +@interface GPBUInt32Int32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32Int32DictionaryTests + +- (void)testEmpty { + GPBUInt32Int32Dictionary *dict = [[GPBUInt32Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32Int32Dictionary *dict = [GPBUInt32Int32Dictionary dictionaryWithValue:200 forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict1 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32Int32Dictionary *dict1prime = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32Int32Dictionary *dict2 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32Int32Dictionary *dict3 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32Int32Dictionary *dict4 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int32Dictionary *dict2 = + [GPBUInt32Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32Int32Dictionary *dict = [GPBUInt32Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict2 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt32Int32Dictionary *dict = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 201); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int32_t kValues2[] = { 202, 200 }; + GPBUInt32Int32Dictionary *dict2 = + [[GPBUInt32Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> UInt64 + +@interface GPBUInt32UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32UInt64DictionaryTests + +- (void)testEmpty { + GPBUInt32UInt64Dictionary *dict = [[GPBUInt32UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32UInt64Dictionary *dict = [GPBUInt32UInt64Dictionary dictionaryWithValue:300U forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict1 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32UInt64Dictionary *dict1prime = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32UInt64Dictionary *dict2 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32UInt64Dictionary *dict3 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32UInt64Dictionary *dict4 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32UInt64Dictionary *dict2 = + [GPBUInt32UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32UInt64Dictionary *dict = [GPBUInt32UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict2 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt32UInt64Dictionary *dict = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 301U); + + const uint32_t kKeys2[] = { 2U, 3U }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBUInt32UInt64Dictionary *dict2 = + [[GPBUInt32UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Int64 + +@interface GPBUInt32Int64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt32Int64DictionaryTests + +- (void)testEmpty { + GPBUInt32Int64Dictionary *dict = [[GPBUInt32Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32Int64Dictionary *dict = [GPBUInt32Int64Dictionary dictionaryWithValue:400 forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict1 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32Int64Dictionary *dict1prime = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32Int64Dictionary *dict2 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32Int64Dictionary *dict3 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32Int64Dictionary *dict4 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32Int64Dictionary *dict2 = + [GPBUInt32Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32Int64Dictionary *dict = [GPBUInt32Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict2 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt32Int64Dictionary *dict = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 401); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int64_t kValues2[] = { 402, 400 }; + GPBUInt32Int64Dictionary *dict2 = + [[GPBUInt32Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Bool + +@interface GPBUInt32BoolDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32BoolDictionaryTests + +- (void)testEmpty { + GPBUInt32BoolDictionary *dict = [[GPBUInt32BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32BoolDictionary *dict = [GPBUInt32BoolDictionary dictionaryWithValue:YES forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const BOOL kValues[] = { YES, YES, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict1 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32BoolDictionary *dict1prime = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32BoolDictionary *dict2 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32BoolDictionary *dict3 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32BoolDictionary *dict4 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32BoolDictionary *dict2 = + [GPBUInt32BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32BoolDictionary *dict = [GPBUInt32BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const BOOL kValues[] = { YES, NO, NO }; + GPBUInt32BoolDictionary *dict2 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt32BoolDictionary *dict = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, YES); + + const uint32_t kKeys2[] = { 2U, 3U }; + const BOOL kValues2[] = { NO, YES }; + GPBUInt32BoolDictionary *dict2 = + [[GPBUInt32BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Float + +@interface GPBUInt32FloatDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32FloatDictionaryTests + +- (void)testEmpty { + GPBUInt32FloatDictionary *dict = [[GPBUInt32FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32FloatDictionary *dict = [GPBUInt32FloatDictionary dictionaryWithValue:500.f forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict1 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32FloatDictionary *dict1prime = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32FloatDictionary *dict2 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32FloatDictionary *dict3 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32FloatDictionary *dict4 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32FloatDictionary *dict2 = + [GPBUInt32FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32FloatDictionary *dict = [GPBUInt32FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict2 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt32FloatDictionary *dict = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 501.f); + + const uint32_t kKeys2[] = { 2U, 3U }; + const float kValues2[] = { 502.f, 500.f }; + GPBUInt32FloatDictionary *dict2 = + [[GPBUInt32FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Double + +@interface GPBUInt32DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32DoubleDictionaryTests + +- (void)testEmpty { + GPBUInt32DoubleDictionary *dict = [[GPBUInt32DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32DoubleDictionary *dict = [GPBUInt32DoubleDictionary dictionaryWithValue:600. forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const double kValues[] = { 600., 601., 602. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict1 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32DoubleDictionary *dict1prime = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32DoubleDictionary *dict2 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32DoubleDictionary *dict3 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32DoubleDictionary *dict4 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32DoubleDictionary *dict2 = + [GPBUInt32DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32DoubleDictionary *dict = [GPBUInt32DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const double kValues[] = { 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict2 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt32DoubleDictionary *dict = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 601.); + + const uint32_t kKeys2[] = { 2U, 3U }; + const double kValues2[] = { 602., 600. }; + GPBUInt32DoubleDictionary *dict2 = + [[GPBUInt32DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Enum + +@interface GPBUInt32EnumDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32EnumDictionaryTests + +- (void)testEmpty { + GPBUInt32EnumDictionary *dict = [[GPBUInt32EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32EnumDictionary *dict = [GPBUInt32EnumDictionary dictionaryWithValue:700 forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict1 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32EnumDictionary *dict1prime = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32EnumDictionary *dict3 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32EnumDictionary *dict4 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = + [GPBUInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32EnumDictionary *dict = [GPBUInt32EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 701); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int32_t kValues2[] = { 702, 700 }; + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Enum (Unknown Enums) + +@interface GPBUInt32EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBUInt32EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:3U rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U rawValue:NULL]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint32_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict1 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32EnumDictionary *dict1prime = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32EnumDictionary *dict3 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32EnumDictionary *dict4 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = + [GPBUInt32EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBUInt32EnumDictionary *dict = + [GPBUInt32EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:2U], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:2U]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 1U, 3U, 4U }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:1U value:NULL]); + XCTAssertFalse([dict valueForKey:2U value:NULL]); + XCTAssertFalse([dict valueForKey:3U value:NULL]); + XCTAssertFalse([dict valueForKey:4U value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:1U], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U value:NULL]); + XCTAssertTrue([dict valueForKey:1U value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:1U]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:4U rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:2U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:2U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:3U value:NULL]); + XCTAssertTrue([dict valueForKey:3U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 700); + + const uint32_t kKeys2[] = { 2U, 3U }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBUInt32EnumDictionary *dict2 = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:1U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:1U rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:2U value:NULL]); + XCTAssertTrue([dict valueForKey:2U value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:3U rawValue:NULL]); + XCTAssertTrue([dict valueForKey:3U rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:4U value:NULL]); + XCTAssertTrue([dict valueForKey:4U value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBUInt32EnumDictionary *dict = + [[GPBUInt32EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt32 -> Object + +@interface GPBUInt32ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBUInt32ObjectDictionaryTests + +- (void)testEmpty { + GPBUInt32ObjectDictionary *dict = [[GPBUInt32ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:1U]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt32ObjectDictionary *dict = [GPBUInt32ObjectDictionary dictionaryWithValue:@"abc" forKey:1U]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 1U); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint32_t kKeys[] = { 1U, 2U, 3U }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertNil([dict valueForKey:4U]); + + __block NSUInteger idx = 0; + uint32_t *seenKeys = malloc(3 * sizeof(uint32_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint32_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint32_t kKeys1[] = { 1U, 2U, 3U, 4U }; + const uint32_t kKeys2[] = { 2U, 1U, 4U }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict1 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt32ObjectDictionary *dict1prime = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt32ObjectDictionary *dict2 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt32ObjectDictionary *dict3 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt32ObjectDictionary *dict4 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt32ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt32ObjectDictionary *dict2 = + [GPBUInt32ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt32ObjectDictionary *dict = [GPBUInt32ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:1U]; + XCTAssertEqual(dict.count, 1U); + + const uint32_t kKeys[] = { 2U, 3U, 4U }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict2 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:2U]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + [dict removeValueForKey:4U]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertNil([dict valueForKey:4U]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:1U]); + XCTAssertNil([dict valueForKey:2U]); + XCTAssertNil([dict valueForKey:3U]); + XCTAssertNil([dict valueForKey:4U]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint32_t kKeys[] = { 1U, 2U, 3U, 4U }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt32ObjectDictionary *dict = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + [dict setValue:@"jkl" forKey:1U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"jkl"); + + [dict setValue:@"def" forKey:4U]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:2U], @"def"); + XCTAssertEqualObjects([dict valueForKey:3U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:4U], @"def"); + + const uint32_t kKeys2[] = { 2U, 3U }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBUInt32ObjectDictionary *dict2 = + [[GPBUInt32ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:1U], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:2U], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:3U], @"abc"); + XCTAssertEqualObjects([dict valueForKey:4U], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(UInt32, uint32_t, 1U, 2U, 3U, 4U) + diff --git a/objectivec/Tests/GPBDictionaryTests+UInt64.m b/objectivec/Tests/GPBDictionaryTests+UInt64.m new file mode 100644 index 00000000..355639c6 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests+UInt64.m @@ -0,0 +1,3649 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 +#import + +#import "GPBDictionary.h" + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" + +// Pull in the macros (using an external file because expanding all tests +// in a single file makes a file that is failing to work with within Xcode. +//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm + +//%PDDM-EXPAND TEST_FOR_POD_KEY(UInt64, uint64_t, 31ULL, 32ULL, 33ULL, 34ULL) +// This block of code is generated, do not edit it directly. + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +// To let the testing macros work, add some extra methods to simplify things. +@interface GPBUInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint64_t)key; +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count; +@end + +static BOOL TestingEnum_IsValidValue(int32_t value) { + switch (value) { + case 700: + case 701: + case 702: + case 703: + return YES; + default: + return NO; + } +} + +@implementation GPBUInt64EnumDictionary (TestingTweak) ++ (instancetype)dictionaryWithValue:(int32_t)value forKey:(uint64_t)key { + // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the + // type correct. + return [[(GPBUInt64EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:&value + forKeys:&key + count:1] autorelease]; +} +- (instancetype)initWithValues:(const int32_t [])values + forKeys:(const uint64_t [])keys + count:(NSUInteger)count { + return [self initWithValidationFunction:TestingEnum_IsValidValue + rawValues:values + forKeys:keys + count:count]; +} +@end + + +#pragma mark - UInt64 -> UInt32 + +@interface GPBUInt64UInt32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64UInt32DictionaryTests + +- (void)testEmpty { + GPBUInt64UInt32Dictionary *dict = [[GPBUInt64UInt32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64UInt32Dictionary *dict = [GPBUInt64UInt32Dictionary dictionaryWithValue:100U forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 100U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + uint32_t *seenValues = malloc(3 * sizeof(uint32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const uint32_t kValues1[] = { 100U, 101U, 102U }; + const uint32_t kValues2[] = { 100U, 103U, 102U }; + const uint32_t kValues3[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict1 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64UInt32Dictionary *dict1prime = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64UInt32Dictionary *dict2 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64UInt32Dictionary *dict3 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64UInt32Dictionary *dict4 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64UInt32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt32Dictionary *dict2 = + [GPBUInt64UInt32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64UInt32Dictionary *dict = [GPBUInt64UInt32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:100U forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict2 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint32_t kValues[] = { 100U, 101U, 102U, 103U }; + GPBUInt64UInt32Dictionary *dict = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:103U forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 103U); + + [dict setValue:101U forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 101U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 101U); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const uint32_t kValues2[] = { 102U, 100U }; + GPBUInt64UInt32Dictionary *dict2 = + [[GPBUInt64UInt32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 103U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 102U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 100U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 101U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Int32 + +@interface GPBUInt64Int32DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64Int32DictionaryTests + +- (void)testEmpty { + GPBUInt64Int32Dictionary *dict = [[GPBUInt64Int32Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64Int32Dictionary *dict = [GPBUInt64Int32Dictionary dictionaryWithValue:200 forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 200); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int32_t kValues[] = { 200, 201, 202 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int32_t kValues1[] = { 200, 201, 202 }; + const int32_t kValues2[] = { 200, 203, 202 }; + const int32_t kValues3[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict1 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64Int32Dictionary *dict1prime = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64Int32Dictionary *dict2 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64Int32Dictionary *dict3 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64Int32Dictionary *dict4 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int32Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64Int32Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int32Dictionary *dict2 = + [GPBUInt64Int32Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64Int32Dictionary *dict = [GPBUInt64Int32Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:200 forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict2 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 200, 201, 202, 203 }; + GPBUInt64Int32Dictionary *dict = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:203 forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 203); + + [dict setValue:201 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 201); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 201); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int32_t kValues2[] = { 202, 200 }; + GPBUInt64Int32Dictionary *dict2 = + [[GPBUInt64Int32Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 203); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 202); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 200); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 201); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> UInt64 + +@interface GPBUInt64UInt64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64UInt64DictionaryTests + +- (void)testEmpty { + GPBUInt64UInt64Dictionary *dict = [[GPBUInt64UInt64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64UInt64Dictionary *dict = [GPBUInt64UInt64Dictionary dictionaryWithValue:300U forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 300U); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + uint64_t *seenValues = malloc(3 * sizeof(uint64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, uint64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const uint64_t kValues1[] = { 300U, 301U, 302U }; + const uint64_t kValues2[] = { 300U, 303U, 302U }; + const uint64_t kValues3[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict1 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64UInt64Dictionary *dict1prime = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64UInt64Dictionary *dict2 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64UInt64Dictionary *dict3 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64UInt64Dictionary *dict4 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64UInt64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64UInt64Dictionary *dict2 = + [GPBUInt64UInt64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64UInt64Dictionary *dict = [GPBUInt64UInt64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:300U forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict2 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kValues[] = { 300U, 301U, 302U, 303U }; + GPBUInt64UInt64Dictionary *dict = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + uint64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:303U forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 303U); + + [dict setValue:301U forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 301U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 301U); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const uint64_t kValues2[] = { 302U, 300U }; + GPBUInt64UInt64Dictionary *dict2 = + [[GPBUInt64UInt64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 303U); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 302U); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 300U); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 301U); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Int64 + +@interface GPBUInt64Int64DictionaryTests : XCTestCase +@end + +@implementation GPBUInt64Int64DictionaryTests + +- (void)testEmpty { + GPBUInt64Int64Dictionary *dict = [[GPBUInt64Int64Dictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64Int64Dictionary *dict = [GPBUInt64Int64Dictionary dictionaryWithValue:400 forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 400); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int64_t kValues[] = { 400, 401, 402 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int64_t *seenValues = malloc(3 * sizeof(int64_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int64_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int64_t kValues1[] = { 400, 401, 402 }; + const int64_t kValues2[] = { 400, 403, 402 }; + const int64_t kValues3[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict1 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64Int64Dictionary *dict1prime = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64Int64Dictionary *dict2 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64Int64Dictionary *dict3 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64Int64Dictionary *dict4 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int64Dictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64Int64Dictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64Int64Dictionary *dict2 = + [GPBUInt64Int64Dictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64Int64Dictionary *dict = [GPBUInt64Int64Dictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:400 forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict2 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int64_t kValues[] = { 400, 401, 402, 403 }; + GPBUInt64Int64Dictionary *dict = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int64_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:403 forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 403); + + [dict setValue:401 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 401); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 401); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int64_t kValues2[] = { 402, 400 }; + GPBUInt64Int64Dictionary *dict2 = + [[GPBUInt64Int64Dictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 403); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 402); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 400); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 401); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Bool + +@interface GPBUInt64BoolDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64BoolDictionaryTests + +- (void)testEmpty { + GPBUInt64BoolDictionary *dict = [[GPBUInt64BoolDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64BoolDictionary *dict = [GPBUInt64BoolDictionary dictionaryWithValue:YES forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, YES); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const BOOL kValues[] = { YES, YES, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + BOOL *seenValues = malloc(3 * sizeof(BOOL)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, BOOL aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const BOOL kValues1[] = { YES, YES, NO }; + const BOOL kValues2[] = { YES, NO, NO }; + const BOOL kValues3[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict1 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64BoolDictionary *dict1prime = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64BoolDictionary *dict2 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64BoolDictionary *dict3 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64BoolDictionary *dict4 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64BoolDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64BoolDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64BoolDictionary *dict2 = + [GPBUInt64BoolDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64BoolDictionary *dict = [GPBUInt64BoolDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:YES forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, NO, NO }; + GPBUInt64BoolDictionary *dict2 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const BOOL kValues[] = { YES, YES, NO, NO }; + GPBUInt64BoolDictionary *dict = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + BOOL value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:NO forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, NO); + + [dict setValue:YES forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, YES); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const BOOL kValues2[] = { NO, YES }; + GPBUInt64BoolDictionary *dict2 = + [[GPBUInt64BoolDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, NO); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, YES); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, YES); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Float + +@interface GPBUInt64FloatDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64FloatDictionaryTests + +- (void)testEmpty { + GPBUInt64FloatDictionary *dict = [[GPBUInt64FloatDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64FloatDictionary *dict = [GPBUInt64FloatDictionary dictionaryWithValue:500.f forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 500.f); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const float kValues[] = { 500.f, 501.f, 502.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + float *seenValues = malloc(3 * sizeof(float)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, float aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const float kValues1[] = { 500.f, 501.f, 502.f }; + const float kValues2[] = { 500.f, 503.f, 502.f }; + const float kValues3[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict1 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64FloatDictionary *dict1prime = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64FloatDictionary *dict2 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64FloatDictionary *dict3 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64FloatDictionary *dict4 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64FloatDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64FloatDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64FloatDictionary *dict2 = + [GPBUInt64FloatDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64FloatDictionary *dict = [GPBUInt64FloatDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:500.f forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict2 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const float kValues[] = { 500.f, 501.f, 502.f, 503.f }; + GPBUInt64FloatDictionary *dict = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + float value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:503.f forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 503.f); + + [dict setValue:501.f forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 501.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 501.f); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const float kValues2[] = { 502.f, 500.f }; + GPBUInt64FloatDictionary *dict2 = + [[GPBUInt64FloatDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 503.f); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 502.f); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 500.f); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 501.f); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Double + +@interface GPBUInt64DoubleDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64DoubleDictionaryTests + +- (void)testEmpty { + GPBUInt64DoubleDictionary *dict = [[GPBUInt64DoubleDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64DoubleDictionary *dict = [GPBUInt64DoubleDictionary dictionaryWithValue:600. forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 600.); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const double kValues[] = { 600., 601., 602. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + double *seenValues = malloc(3 * sizeof(double)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, double aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const double kValues1[] = { 600., 601., 602. }; + const double kValues2[] = { 600., 603., 602. }; + const double kValues3[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict1 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64DoubleDictionary *dict1prime = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64DoubleDictionary *dict2 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64DoubleDictionary *dict3 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64DoubleDictionary *dict4 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64DoubleDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64DoubleDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64DoubleDictionary *dict2 = + [GPBUInt64DoubleDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64DoubleDictionary *dict = [GPBUInt64DoubleDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:600. forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict2 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const double kValues[] = { 600., 601., 602., 603. }; + GPBUInt64DoubleDictionary *dict = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + double value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:603. forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 603.); + + [dict setValue:601. forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 601.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 601.); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const double kValues2[] = { 602., 600. }; + GPBUInt64DoubleDictionary *dict2 = + [[GPBUInt64DoubleDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 603.); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 602.); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 600.); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 601.); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Enum + +@interface GPBUInt64EnumDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64EnumDictionaryTests + +- (void)testEmpty { + GPBUInt64EnumDictionary *dict = [[GPBUInt64EnumDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64EnumDictionary *dict = [GPBUInt64EnumDictionary dictionaryWithValue:700 forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqual(aValue, 700); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int32_t kValues[] = { 700, 701, 702 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int32_t kValues1[] = { 700, 701, 702 }; + const int32_t kValues2[] = { 700, 703, 702 }; + const int32_t kValues3[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict1 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64EnumDictionary *dict1prime = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64EnumDictionary *dict3 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64EnumDictionary *dict4 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = + [GPBUInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64EnumDictionary *dict = [GPBUInt64EnumDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:700 forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 701, 702, 703 }; + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 701, 702, 703 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:703 forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 703); + + [dict setValue:701 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 701); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 701); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int32_t kValues2[] = { 702, 700 }; + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 703); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 701); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Enum (Unknown Enums) + +@interface GPBUInt64EnumDictionaryUnknownEnumTests : XCTestCase +@end + +@implementation GPBUInt64EnumDictionaryUnknownEnumTests + +- (void)testRawBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const int32_t kValues[] = { 700, 801, 702 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:33ULL rawValue:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL rawValue:NULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + int32_t *seenValues = malloc(3 * sizeof(int32_t)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + if (i == 1) { + XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); + } else { + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndRawValuesUsingBlock:^(uint64_t aKey, int32_t aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEqualityWithUnknowns { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const int32_t kValues1[] = { 700, 801, 702 }; // Unknown + const int32_t kValues2[] = { 700, 803, 702 }; // Unknown + const int32_t kValues3[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict1 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64EnumDictionary *dict1prime = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64EnumDictionary *dict3 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64EnumDictionary *dict4 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopyWithUnknowns { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknown + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertEqualObjects(dict, dict2); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = + [GPBUInt64EnumDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + [dict release]; +} + +- (void)testUnknownAdds { + GPBUInt64EnumDictionary *dict = + [GPBUInt64EnumDictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + XCTAssertThrowsSpecificNamed([dict setValue:801 forKey:32ULL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 0U); + [dict setRawValue:801 forKey:32ULL]; // Unknown + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 31ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 702, 803 }; // Unknown + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + [dict2 release]; +} + +- (void)testUnknownRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertFalse([dict valueForKey:31ULL value:NULL]); + XCTAssertFalse([dict valueForKey:32ULL value:NULL]); + XCTAssertFalse([dict valueForKey:33ULL value:NULL]); + XCTAssertFalse([dict valueForKey:34ULL value:NULL]); + [dict release]; +} + +- (void)testInplaceMutationUnknowns { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; // Unknowns + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + int32_t value; + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + XCTAssertThrowsSpecificNamed([dict setValue:803 forKey:31ULL], // Unknown + NSException, NSInvalidArgumentException); + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL value:NULL]); + XCTAssertTrue([dict valueForKey:31ULL value:&value]); + XCTAssertEqual(value, 700); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:803 forKey:31ULL]; // Unknown + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:34ULL rawValue:&value]); + XCTAssertEqual(value, 803); + + [dict setRawValue:700 forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:32ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:32ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:33ULL value:NULL]); + XCTAssertTrue([dict valueForKey:33ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 700); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const int32_t kValues2[] = { 702, 801 }; // Unknown + GPBUInt64EnumDictionary *dict2 = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addRawEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertTrue([dict valueForKey:31ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:31ULL rawValue:&value]); + XCTAssertEqual(value, 803); + XCTAssertTrue([dict valueForKey:32ULL value:NULL]); + XCTAssertTrue([dict valueForKey:32ULL value:&value]); + XCTAssertEqual(value, 702); + XCTAssertTrue([dict valueForKey:33ULL rawValue:NULL]); + XCTAssertTrue([dict valueForKey:33ULL rawValue:&value]); + XCTAssertEqual(value, 801); + XCTAssertTrue([dict valueForKey:34ULL value:NULL]); + XCTAssertTrue([dict valueForKey:34ULL value:&value]); + XCTAssertEqual(value, 700); + + [dict2 release]; + [dict release]; +} + +- (void)testCopyUnknowns { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const int32_t kValues[] = { 700, 801, 702, 803 }; + GPBUInt64EnumDictionary *dict = + [[GPBUInt64EnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue + rawValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64EnumDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64EnumDictionary class]]); + + [dict2 release]; + [dict release]; +} + +@end + +#pragma mark - UInt64 -> Object + +@interface GPBUInt64ObjectDictionaryTests : XCTestCase +@end + +@implementation GPBUInt64ObjectDictionaryTests + +- (void)testEmpty { + GPBUInt64ObjectDictionary *dict = [[GPBUInt64ObjectDictionary alloc] init]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:31ULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue, stop) + XCTFail(@"Shouldn't get here!"); + }]; + [dict release]; +} + +- (void)testOne { + GPBUInt64ObjectDictionary *dict = [GPBUInt64ObjectDictionary dictionaryWithValue:@"abc" forKey:31ULL]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 1U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + XCTAssertEqual(aKey, 31ULL); + XCTAssertEqualObjects(aValue, @"abc"); + XCTAssertNotEqual(stop, NULL); + }]; +} + +- (void)testBasics { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL }; + const id kValues[] = { @"abc", @"def", @"ghi" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertNil([dict valueForKey:34ULL]); + + __block NSUInteger idx = 0; + uint64_t *seenKeys = malloc(3 * sizeof(uint64_t)); + id *seenValues = malloc(3 * sizeof(id)); + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + XCTAssertLessThan(idx, 3U); + seenKeys[idx] = aKey; + seenValues[idx] = aValue; + XCTAssertNotEqual(stop, NULL); + ++idx; + }]; + for (int i = 0; i < 3; ++i) { + BOOL foundKey = NO; + for (int j = 0; (j < 3) && !foundKey; ++j) { + if (kKeys[i] == seenKeys[j]) { + foundKey = YES; + XCTAssertEqualObjects(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); + } + } + XCTAssertTrue(foundKey, @"i = %d", i); + } + free(seenKeys); + free(seenValues); + + // Stopping the enumeration. + idx = 0; + [dict enumerateKeysAndValuesUsingBlock:^(uint64_t aKey, id aValue, BOOL *stop) { + #pragma unused(aKey, aValue) + if (idx == 1) *stop = YES; + XCTAssertNotEqual(idx, 2U); + ++idx; + }]; + [dict release]; +} + +- (void)testEquality { + const uint64_t kKeys1[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const uint64_t kKeys2[] = { 32ULL, 31ULL, 34ULL }; + const id kValues1[] = { @"abc", @"def", @"ghi" }; + const id kValues2[] = { @"abc", @"jkl", @"ghi" }; + const id kValues3[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict1 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1); + GPBUInt64ObjectDictionary *dict1prime = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict1prime); + GPBUInt64ObjectDictionary *dict2 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + GPBUInt64ObjectDictionary *dict3 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues1 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues1)]; + XCTAssertNotNil(dict3); + GPBUInt64ObjectDictionary *dict4 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues3 + forKeys:kKeys1 + count:GPBARRAYSIZE(kValues3)]; + XCTAssertNotNil(dict4); + + // 1/1Prime should be different objects, but equal. + XCTAssertNotEqual(dict1, dict1prime); + XCTAssertEqualObjects(dict1, dict1prime); + // Equal, so they must have same hash. + XCTAssertEqual([dict1 hash], [dict1prime hash]); + + // 2 is save keys, different values; not equal. + XCTAssertNotEqualObjects(dict1, dict2); + + // 3 is different keys, samae values; not equal. + XCTAssertNotEqualObjects(dict1, dict3); + + // 4 extra pair; not equal + XCTAssertNotEqualObjects(dict1, dict4); + + [dict1 release]; + [dict1prime release]; + [dict2 release]; + [dict3 release]; + [dict4 release]; +} + +- (void)testCopy { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64ObjectDictionary *dict2 = [dict copy]; + XCTAssertNotNil(dict2); + + // Should be new object but equal. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + XCTAssertTrue([dict2 isKindOfClass:[GPBUInt64ObjectDictionary class]]); + + [dict2 release]; + [dict release]; +} + +- (void)testDictionaryFromDictionary { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + + GPBUInt64ObjectDictionary *dict2 = + [GPBUInt64ObjectDictionary dictionaryWithDictionary:dict]; + XCTAssertNotNil(dict2); + + // Should be new pointer, but equal objects. + XCTAssertNotEqual(dict, dict2); + XCTAssertEqualObjects(dict, dict2); + [dict release]; +} + +- (void)testAdds { + GPBUInt64ObjectDictionary *dict = [GPBUInt64ObjectDictionary dictionary]; + XCTAssertNotNil(dict); + + XCTAssertEqual(dict.count, 0U); + [dict setValue:@"abc" forKey:31ULL]; + XCTAssertEqual(dict.count, 1U); + + const uint64_t kKeys[] = { 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict2 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + [dict2 release]; +} + +- (void)testRemove { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + // Remove again does nothing. + [dict removeValueForKey:32ULL]; + XCTAssertEqual(dict.count, 3U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + [dict removeValueForKey:34ULL]; + XCTAssertEqual(dict.count, 2U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertNil([dict valueForKey:34ULL]); + + [dict removeAll]; + XCTAssertEqual(dict.count, 0U); + XCTAssertNil([dict valueForKey:31ULL]); + XCTAssertNil([dict valueForKey:32ULL]); + XCTAssertNil([dict valueForKey:33ULL]); + XCTAssertNil([dict valueForKey:34ULL]); + [dict release]; +} + +- (void)testInplaceMutation { + const uint64_t kKeys[] = { 31ULL, 32ULL, 33ULL, 34ULL }; + const id kValues[] = { @"abc", @"def", @"ghi", @"jkl" }; + GPBUInt64ObjectDictionary *dict = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues + forKeys:kKeys + count:GPBARRAYSIZE(kValues)]; + XCTAssertNotNil(dict); + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + [dict setValue:@"jkl" forKey:31ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"jkl"); + + [dict setValue:@"def" forKey:34ULL]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"def"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"def"); + + const uint64_t kKeys2[] = { 32ULL, 33ULL }; + const id kValues2[] = { @"ghi", @"abc" }; + GPBUInt64ObjectDictionary *dict2 = + [[GPBUInt64ObjectDictionary alloc] initWithValues:kValues2 + forKeys:kKeys2 + count:GPBARRAYSIZE(kValues2)]; + XCTAssertNotNil(dict2); + [dict addEntriesFromDictionary:dict2]; + XCTAssertEqual(dict.count, 4U); + XCTAssertEqualObjects([dict valueForKey:31ULL], @"jkl"); + XCTAssertEqualObjects([dict valueForKey:32ULL], @"ghi"); + XCTAssertEqualObjects([dict valueForKey:33ULL], @"abc"); + XCTAssertEqualObjects([dict valueForKey:34ULL], @"def"); + + [dict2 release]; + [dict release]; +} + +@end + +//%PDDM-EXPAND-END TEST_FOR_POD_KEY(UInt64, uint64_t, 31ULL, 32ULL, 33ULL, 34ULL) diff --git a/objectivec/Tests/GPBDictionaryTests.pddm b/objectivec/Tests/GPBDictionaryTests.pddm new file mode 100644 index 00000000..39793e03 --- /dev/null +++ b/objectivec/Tests/GPBDictionaryTests.pddm @@ -0,0 +1,1044 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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. + +//%PDDM-DEFINE TEST_FOR_POD_KEY(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4) +//%TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4) +//%TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, Object, id, @"abc", @"def", @"ghi", @"jkl") + +//%PDDM-DEFINE TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) +//%TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt32, uint32_t, , 100U, 101U, 102U, 103U) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int32, int32_t, , 200, 201, 202, 203) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt64, uint64_t, , 300U, 301U, 302U, 303U) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int64, int64_t, , 400, 401, 402, 403) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Bool, BOOL, , YES, YES, NO, NO) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Float, float, , 500.f, 501.f, 502.f, 503.f) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Double, double, , 600., 601., 602., 603.) +//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, Raw, 700, 701, 702, 703) +//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) + +//%PDDM-DEFINE TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VACCESSOR, VAL1, VAL2, VAL3, VAL4) +//%TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, , POD, VACCESSOR, VAL1, VAL2, VAL3, VAL4) + +//%PDDM-DEFINE TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VAL1, VAL2, VAL3, VAL4) +//%TESTS_COMMON(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, Objects, OBJECT, , VAL1, VAL2, VAL3, VAL4) + +//%PDDM-DEFINE TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VACCESSOR, VAL1, VAL2, VAL3, VAL4) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase +//%@end +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests +//% +//%- (void)testEmpty { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testOne { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValue:VAL1 forKey:KEY1]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 1U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertEqual##KSUFFIX(aKey, KEY1); +//% XCTAssertEqual##VSUFFIX(aValue, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//%} +//% +//%- (void)testBasics { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 3U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% __block NSUInteger idx = 0; +//% KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP)); +//% VALUE_TYPE *seenValues = malloc(3 * sizeof(VALUE_TYPE)); +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 3U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 3; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 3) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% free(seenKeys); +//% free(seenValues); +//% +//% // Stopping the enumeration. +//% idx = 0; +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue) +//% if (idx == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% ++idx; +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testEquality { +//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 }; +//% const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 }; +//% const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 }; +//% const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1prime); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict3); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues3 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(dict4); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(dict1, dict1prime); +//% XCTAssertEqualObjects(dict1, dict1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([dict1 hash], [dict1prime hash]); +//% +//% // 2 is save keys, different values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict2); +//% +//% // 3 is different keys, samae values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict3); +//% +//% // 4 extra pair; not equal +//% XCTAssertNotEqualObjects(dict1, dict4); +//% +//% [dict1 release]; +//% [dict1prime release]; +//% [dict2 release]; +//% [dict3 release]; +//% [dict4 release]; +//%} +//% +//%- (void)testCopy { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new object but equal. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testDictionaryFromDictionary { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% [dict release]; +//%} +//% +//%- (void)testAdds { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary]; +//% XCTAssertNotNil(dict); +//% +//% XCTAssertEqual(dict.count, 0U); +//% [dict setValue:VAL1 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 1U); +//% +//% const KEY_TYPE KisP##kKeys[] = { KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict2); +//% [dict add##VACCESSOR##EntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//% +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% [dict2 release]; +//%} +//% +//%- (void)testRemove { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//% +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% // Remove again does nothing. +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict removeValueForKey:KEY4]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% [dict removeAll]; +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% [dict release]; +//%} +//% +//%- (void)testInplaceMutation { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setValue:VAL4 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setValue:VAL2 forKey:KEY4]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL2) +//% +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 }; +//% const VALUE_TYPE kValues2[] = { VAL3, VAL1 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% [dict add##VACCESSOR##EntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL2) +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%@end +//% + +//%PDDM-DEFINE TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) +//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS2(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, , POD, 700, 801, 702, 803) +//%PDDM-DEFINE TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS2(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VAL1, VAL2, VAL3, VAL4) +//%#pragma mark - KEY_NAME -> VALUE_NAME (Unknown Enums) +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests : XCTestCase +//%@end +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests +//% +//%- (void)testRawBasics { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 3U); +//% XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, kGPBUnrecognizedEnumeratorValue) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%RAW_VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% __block NSUInteger idx = 0; +//% KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP)); +//% VALUE_TYPE *seenValues = malloc(3 * sizeof(VALUE_TYPE)); +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 3U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 3; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 3) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% if (i == 1) { +//% XCTAssertEqual##VSUFFIX(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); +//% } else { +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% idx = 0; +//% [dict enumerateKeysAndRawValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 3U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 3; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 3) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% free(seenKeys); +//% free(seenValues); +//% +//% // Stopping the enumeration. +//% idx = 0; +//% [dict enumerateKeysAndRawValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue) +//% if (idx == 1) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% ++idx; +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testEqualityWithUnknowns { +//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 }; +//% const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 }; // Unknown +//% const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 }; // Unknown +//% const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1prime); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict3); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues3 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(dict4); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(dict1, dict1prime); +//% XCTAssertEqualObjects(dict1, dict1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([dict1 hash], [dict1prime hash]); +//% +//% // 2 is save keys, different values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict2); +//% +//% // 3 is different keys, samae values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict3); +//% +//% // 4 extra pair; not equal +//% XCTAssertNotEqualObjects(dict1, dict4); +//% +//% [dict1 release]; +//% [dict1prime release]; +//% [dict2 release]; +//% [dict3 release]; +//% [dict4 release]; +//%} +//% +//%- (void)testCopyWithUnknowns { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknown +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison +//% XCTAssertEqualObjects(dict, dict2); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testDictionaryFromDictionary { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison +//% [dict release]; +//%} +//% +//%- (void)testUnknownAdds { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValidationFunction:TestingEnum_IsValidValue]; +//% XCTAssertNotNil(dict); +//% +//% XCTAssertEqual(dict.count, 0U); +//% XCTAssertThrowsSpecificNamed([dict setValue:VAL2 forKey:KEY2], // Unknown +//% NSException, NSInvalidArgumentException); +//% XCTAssertEqual(dict.count, 0U); +//% [dict setRawValue:VAL2 forKey:KEY2]; // Unknown +//% XCTAssertEqual(dict.count, 1U); +//% +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL3, VAL4 }; // Unknown +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict2); +//% [dict addRawEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//% +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, kGPBUnrecognizedEnumeratorValue) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, kGPBUnrecognizedEnumeratorValue) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% [dict2 release]; +//%} +//% +//%- (void)testUnknownRemove { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//% +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% // Remove again does nothing. +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 3U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict removeValueForKey:KEY4]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% +//% [dict removeAll]; +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY3) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY4) +//% [dict release]; +//%} +//% +//%- (void)testInplaceMutationUnknowns { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 4U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% XCTAssertThrowsSpecificNamed([dict setValue:VAL4 forKey:KEY1], // Unknown +//% NSException, NSInvalidArgumentException); +//% XCTAssertEqual(dict.count, 4U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setRawValue:VAL4 forKey:KEY1]; // Unknown +//% XCTAssertEqual(dict.count, 4U); +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) +//% +//% [dict setRawValue:VAL1 forKey:KEY4]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY3, VAL3) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL1) +//% +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 }; +//% const VALUE_TYPE kValues2[] = { VAL3, VAL2 }; // Unknown +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% [dict addRawEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 4U); +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL3) +//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY4, VAL1) +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testCopyUnknowns { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S VALUE_NAME$S rawValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison +//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%@end +//% + +// +// Helpers for PODs +// + +//%PDDM-DEFINE DECLARE_VALUE_STORAGEPOD(VALUE_TYPE, NAME) +//% VALUE_TYPE NAME; +//% +//%PDDM-DEFINE VALUE_NOT_FOUNDPOD(DICT, KEY) +//% XCTAssertFalse([DICT valueForKey:KEY value:NULL]); +//%PDDM-DEFINE TEST_VALUEPOD(DICT, STORAGE, KEY, VALUE) +//% XCTAssertTrue([DICT valueForKey:KEY value:NULL]); +//% XCTAssertTrue([DICT valueForKey:KEY value:&STORAGE]); +//% XCTAssertEqual(STORAGE, VALUE); +//%PDDM-DEFINE COMPARE_KEYS(KEY1, KEY2) +//%KEY1 == KEY2 +//%PDDM-DEFINE RAW_VALUE_NOT_FOUNDPOD(DICT, KEY) +//% XCTAssertFalse([DICT valueForKey:KEY rawValue:NULL]); +//%PDDM-DEFINE TEST_RAW_VALUEPOD(DICT, STORAGE, KEY, VALUE) +//% XCTAssertTrue([DICT valueForKey:KEY rawValue:NULL]); +//% XCTAssertTrue([DICT valueForKey:KEY rawValue:&STORAGE]); +//% XCTAssertEqual(STORAGE, VALUE); + +// +// Helpers for Objects +// + +//%PDDM-DEFINE DECLARE_VALUE_STORAGEOBJECT(VALUE_TYPE, NAME) +// Empty +//%PDDM-DEFINE VALUE_NOT_FOUNDOBJECT(DICT, KEY) +//% XCTAssertNil([DICT valueForKey:KEY]); +//%PDDM-DEFINE TEST_VALUEOBJECT(DICT, STORAGE, KEY, VALUE) +//% XCTAssertEqualObjects([DICT valueForKey:KEY], VALUE); +//%PDDM-DEFINE COMPARE_KEYSObjects(KEY1, KEY2) +//%[KEY1 isEqual:KEY2] + +// +// Helpers for tests. +// + +//%PDDM-DEFINE TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP) +//%#ifndef GPBARRAYSIZE +//%#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +//%#endif // GPBARRAYSIZE +//% +//%// To let the testing macros work, add some extra methods to simplify things. +//%@interface GPB##KEY_NAME##EnumDictionary (TestingTweak) +//%+ (instancetype)dictionaryWithValue:(int32_t)value forKey:(KEY_TYPE##KisP$S##KisP)key; +//%- (instancetype)initWithValues:(const int32_t [])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count; +//%@end +//% +//%static BOOL TestingEnum_IsValidValue(int32_t value) { +//% switch (value) { +//% case 700: +//% case 701: +//% case 702: +//% case 703: +//% return YES; +//% default: +//% return NO; +//% } +//%} +//% +//%@implementation GPB##KEY_NAME##EnumDictionary (TestingTweak) +//%+ (instancetype)dictionaryWithValue:(int32_t)value forKey:(KEY_TYPE##KisP$S##KisP)key { +//% // Cast is needed to compiler knows what class we are invoking initWithValues: on to get the +//% // type correct. +//% return [[(GPB##KEY_NAME##EnumDictionary*)[self alloc] initWithValidationFunction:TestingEnum_IsValidValue +//% KEY_NAME$S rawValues:&value +//% KEY_NAME$S forKeys:&key +//% KEY_NAME$S count:1] autorelease]; +//%} +//%- (instancetype)initWithValues:(const int32_t [])values +//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys +//% count:(NSUInteger)count { +//% return [self initWithValidationFunction:TestingEnum_IsValidValue +//% rawValues:values +//% forKeys:keys +//% count:count]; +//%} +//%@end +//% +//% + + +// +// BOOL test macros +// +//TODO(thomasvl): enum tests + +//%PDDM-DEFINE BOOL_TESTS_FOR_POD_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2) +//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, , POD, VAL1, VAL2) + +//%PDDM-DEFINE TESTS_FOR_BOOL_KEY_OBJECT_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2) +//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, Objects, OBJECT, VAL1, VAL2) + +//%PDDM-DEFINE BOOL_TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, VALUE_NAME, VALUE_TYPE, VSUFFIX, VHELPER, VAL1, VAL2) +//%#pragma mark - KEY_NAME -> VALUE_NAME +//% +//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase +//%@end +//% +//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests +//% +//%- (void)testEmpty { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue, stop) +//% XCTFail(@"Shouldn't get here!"); +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testOne { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithValue:VAL1 forKey:KEY1]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 1U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertEqual##KSUFFIX(aKey, KEY1); +//% XCTAssertEqual##VSUFFIX(aValue, VAL1); +//% XCTAssertNotEqual(stop, NULL); +//% }]; +//%} +//% +//%- (void)testBasics { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 2U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% __block NSUInteger idx = 0; +//% KEY_TYPE KisP##*seenKeys = malloc(2 * sizeof(KEY_TYPE##KisP)); +//% VALUE_TYPE *seenValues = malloc(2 * sizeof(VALUE_TYPE)); +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% XCTAssertLessThan(idx, 2U); +//% seenKeys[idx] = aKey; +//% seenValues[idx] = aValue; +//% XCTAssertNotEqual(stop, NULL); +//% ++idx; +//% }]; +//% for (int i = 0; i < 2; ++i) { +//% BOOL foundKey = NO; +//% for (int j = 0; (j < 2) && !foundKey; ++j) { +//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { +//% foundKey = YES; +//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); +//% } +//% } +//% XCTAssertTrue(foundKey, @"i = %d", i); +//% } +//% free(seenKeys); +//% free(seenValues); +//% +//% // Stopping the enumeration. +//% idx = 0; +//% [dict enumerateKeysAndValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { +//% #pragma unused(aKey, aValue) +//% if (idx == 0) *stop = YES; +//% XCTAssertNotEqual(idx, 2U); +//% ++idx; +//% }]; +//% [dict release]; +//%} +//% +//%- (void)testEquality { +//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2 }; +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 }; +//% const VALUE_TYPE kValues1[] = { VAL1, VAL2 }; +//% const VALUE_TYPE kValues2[] = { VAL2, VAL1 }; +//% const VALUE_TYPE kValues3[] = { VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict1prime = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict1prime); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict3 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues1 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; +//% XCTAssertNotNil(dict3); +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict4 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues3 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues3)]; +//% XCTAssertNotNil(dict4); +//% +//% // 1/1Prime should be different objects, but equal. +//% XCTAssertNotEqual(dict1, dict1prime); +//% XCTAssertEqualObjects(dict1, dict1prime); +//% // Equal, so they must have same hash. +//% XCTAssertEqual([dict1 hash], [dict1prime hash]); +//% +//% // 2 is save keys, different values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict2); +//% +//% // 3 is different keys, samae values; not equal. +//% XCTAssertNotEqualObjects(dict1, dict3); +//% +//% // 4 Fewer pairs; not equal +//% XCTAssertNotEqualObjects(dict1, dict4); +//% +//% [dict1 release]; +//% [dict1prime release]; +//% [dict2 release]; +//% [dict3 release]; +//% [dict4 release]; +//%} +//% +//%- (void)testCopy { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = [dict copy]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new object but equal. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%- (void)testDictionaryFromDictionary { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionaryWithDictionary:dict]; +//% XCTAssertNotNil(dict2); +//% +//% // Should be new pointer, but equal objects. +//% XCTAssertNotEqual(dict, dict2); +//% XCTAssertEqualObjects(dict, dict2); +//% [dict release]; +//%} +//% +//%- (void)testAdds { +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = [GPB##KEY_NAME##VALUE_NAME##Dictionary dictionary]; +//% XCTAssertNotNil(dict); +//% +//% XCTAssertEqual(dict.count, 0U); +//% [dict setValue:VAL1 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 1U); +//% +//% const KEY_TYPE KisP##kKeys[] = { KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict2); +//% [dict addEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 2U); +//% +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% [dict2 release]; +//%} +//% +//%- (void)testRemove { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2}; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 2U); +//% +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 1U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% +//% // Remove again does nothing. +//% [dict removeValueForKey:KEY2]; +//% XCTAssertEqual(dict.count, 1U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% +//% [dict removeAll]; +//% XCTAssertEqual(dict.count, 0U); +//%VALUE_NOT_FOUND##VHELPER(dict, KEY1) +//%VALUE_NOT_FOUND##VHELPER(dict, KEY2) +//% [dict release]; +//%} +//% +//%- (void)testInplaceMutation { +//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; +//% const VALUE_TYPE kValues[] = { VAL1, VAL2 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; +//% XCTAssertNotNil(dict); +//% XCTAssertEqual(dict.count, 2U); +//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% [dict setValue:VAL2 forKey:KEY1]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% [dict setValue:VAL1 forKey:KEY2]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL2) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL1) +//% +//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 }; +//% const VALUE_TYPE kValues2[] = { VAL2, VAL1 }; +//% GPB##KEY_NAME##VALUE_NAME##Dictionary *dict2 = +//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValues:kValues2 +//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 +//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; +//% XCTAssertNotNil(dict2); +//% [dict addEntriesFromDictionary:dict2]; +//% XCTAssertEqual(dict.count, 2U); +//%TEST_VALUE##VHELPER(dict, value, KEY1, VAL1) +//%TEST_VALUE##VHELPER(dict, value, KEY2, VAL2) +//% +//% [dict2 release]; +//% [dict release]; +//%} +//% +//%@end +//% + diff --git a/objectivec/Tests/GPBFilteredMessageTests.m b/objectivec/Tests/GPBFilteredMessageTests.m new file mode 100644 index 00000000..b0588837 --- /dev/null +++ b/objectivec/Tests/GPBFilteredMessageTests.m @@ -0,0 +1,98 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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. + +// Tests our filter system for ObjC. +// The proto being filtered is unittest_filter.proto. +// The filter file is Filter.txt. + +#import "GPBTestUtilities.h" + +#import "google/protobuf/UnittestFilter.pbobjc.h" + +// If we get an error about this already being defined, it is most likely +// because of an error in protoc which is supposed to be filtering +// the Remove message. +enum { Other_FieldNumber_B = 0 }; + +@interface FilteredMessageTests : GPBTestCase +@end + +@implementation FilteredMessageTests + +- (void)testEnumFiltering { + // If compile fails here it is because protoc did not generate KeepEnum. + XCTAssertTrue(KeepEnum_IsValidValue(KeepEnum_KeepValue)); + XCTAssertNotNil(KeepEnum_EnumDescriptor()); + + // If compile fails here it is because protoc did not generate + // KeepEnumInsideEnum and is probably due to nested enum handling being + // broken. + XCTAssertTrue(RemoveEnumMessage_KeepEnumInside_IsValidValue( + RemoveEnumMessage_KeepEnumInside_KeepValue)); + XCTAssertNotNil(RemoveEnumMessage_KeepEnumInside_EnumDescriptor()); +} + +- (void)testMessageFiltering { + // Messages that should be generated. + XCTAssertNil([UnittestFilterRoot extensionRegistry]); + XCTAssertNotNil([[[Keep alloc] init] autorelease]); + XCTAssertNotNil([[[Other alloc] init] autorelease]); + XCTAssertNotNil([[[RemoveJustKidding alloc] init] autorelease]); + XCTAssertNotNil( + [[[RemoveEnumMessage_KeepNestedInside alloc] init] autorelease]); + + // Messages that should not be generated + XCTAssertNil(NSClassFromString(@"Remove")); + XCTAssertNil(NSClassFromString(@"RemoveEnumMessage")); + XCTAssertNil(NSClassFromString(@"RemoveEnumMessage_RemoveNestedInside")); + + // These should all fail compile if protoc is bad. + XCTAssertTrue([Other instancesRespondToSelector:@selector(hasA)]); + XCTAssertTrue([Other instancesRespondToSelector:@selector(setHasA:)]); + XCTAssertTrue([Other instancesRespondToSelector:@selector(a)]); + XCTAssertTrue([Other instancesRespondToSelector:@selector(setA:)]); + + // These the compiler should not generate. + XCTAssertFalse( + [Other instancesRespondToSelector:NSSelectorFromString(@"hasB")]); + XCTAssertFalse( + [Other instancesRespondToSelector:NSSelectorFromString(@"setHasB:")]); + XCTAssertFalse([Other instancesRespondToSelector:NSSelectorFromString(@"b")]); + XCTAssertFalse( + [Other instancesRespondToSelector:NSSelectorFromString(@"setB:")]); + + // This should fail if protoc filters it. + XCTAssertEqual(Other_FieldNumber_A, 1); + + // Make sure the definition at the top of the file is providing the value. + XCTAssertEqual(Other_FieldNumber_B, 0); +} + +@end diff --git a/objectivec/Tests/GPBMessageTests+Merge.m b/objectivec/Tests/GPBMessageTests+Merge.m new file mode 100644 index 00000000..599ad055 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests+Merge.m @@ -0,0 +1,700 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 "GPBTestUtilities.h" + +#import + +#import "GPBMessage.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" + +@interface MessageMergeTests : GPBTestCase +@end + +@implementation MessageMergeTests + +// TODO(thomasvl): Pull tests over from GPBMessageTests that are merge specific. + +- (void)testProto3MergingAndZeroValues { + // Proto2 covered in other tests. + + Message3 *src = [[Message3 alloc] init]; + Message3 *dst = [[Message3 alloc] init]; + NSData *testData1 = [@"abc" dataUsingEncoding:NSUTF8StringEncoding]; + NSData *testData2 = [@"def" dataUsingEncoding:NSUTF8StringEncoding]; + + dst.optionalInt32 = 1; + dst.optionalInt64 = 1; + dst.optionalUint32 = 1; + dst.optionalUint64 = 1; + dst.optionalSint32 = 1; + dst.optionalSint64 = 1; + dst.optionalFixed32 = 1; + dst.optionalFixed64 = 1; + dst.optionalSfixed32 = 1; + dst.optionalSfixed64 = 1; + dst.optionalFloat = 1.0f; + dst.optionalDouble = 1.0; + dst.optionalBool = YES; + dst.optionalString = @"bar"; + dst.optionalBytes = testData1; + dst.optionalEnum = Message3_Enum_Bar; + + // All zeros, nothing should overright. + + src.optionalInt32 = 0; + src.optionalInt64 = 0; + src.optionalUint32 = 0; + src.optionalUint64 = 0; + src.optionalSint32 = 0; + src.optionalSint64 = 0; + src.optionalFixed32 = 0; + src.optionalFixed64 = 0; + src.optionalSfixed32 = 0; + src.optionalSfixed64 = 0; + src.optionalFloat = 0.0f; + src.optionalDouble = 0.0; + src.optionalBool = NO; + src.optionalString = @""; + src.optionalBytes = [NSData data]; + src.optionalEnum = Message3_Enum_Foo; // first value + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.optionalInt32, 1); + XCTAssertEqual(dst.optionalInt64, 1); + XCTAssertEqual(dst.optionalUint32, 1U); + XCTAssertEqual(dst.optionalUint64, 1U); + XCTAssertEqual(dst.optionalSint32, 1); + XCTAssertEqual(dst.optionalSint64, 1); + XCTAssertEqual(dst.optionalFixed32, 1U); + XCTAssertEqual(dst.optionalFixed64, 1U); + XCTAssertEqual(dst.optionalSfixed32, 1); + XCTAssertEqual(dst.optionalSfixed64, 1); + XCTAssertEqual(dst.optionalFloat, 1.0f); + XCTAssertEqual(dst.optionalDouble, 1.0); + XCTAssertEqual(dst.optionalBool, YES); + XCTAssertEqualObjects(dst.optionalString, @"bar"); + XCTAssertEqualObjects(dst.optionalBytes, testData1); + XCTAssertEqual(dst.optionalEnum, Message3_Enum_Bar); + + // Half the values that will replace. + + src.optionalInt32 = 0; + src.optionalInt64 = 2; + src.optionalUint32 = 0; + src.optionalUint64 = 2; + src.optionalSint32 = 0; + src.optionalSint64 = 2; + src.optionalFixed32 = 0; + src.optionalFixed64 = 2; + src.optionalSfixed32 = 0; + src.optionalSfixed64 = 2; + src.optionalFloat = 0.0f; + src.optionalDouble = 2.0; + src.optionalBool = YES; // No other value to use. :( + src.optionalString = @"baz"; + src.optionalBytes = nil; + src.optionalEnum = Message3_Enum_Baz; + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.optionalInt32, 1); + XCTAssertEqual(dst.optionalInt64, 2); + XCTAssertEqual(dst.optionalUint32, 1U); + XCTAssertEqual(dst.optionalUint64, 2U); + XCTAssertEqual(dst.optionalSint32, 1); + XCTAssertEqual(dst.optionalSint64, 2); + XCTAssertEqual(dst.optionalFixed32, 1U); + XCTAssertEqual(dst.optionalFixed64, 2U); + XCTAssertEqual(dst.optionalSfixed32, 1); + XCTAssertEqual(dst.optionalSfixed64, 2); + XCTAssertEqual(dst.optionalFloat, 1.0f); + XCTAssertEqual(dst.optionalDouble, 2.0); + XCTAssertEqual(dst.optionalBool, YES); + XCTAssertEqualObjects(dst.optionalString, @"baz"); + XCTAssertEqualObjects(dst.optionalBytes, testData1); + XCTAssertEqual(dst.optionalEnum, Message3_Enum_Baz); + + // Other half the values that will replace. + + src.optionalInt32 = 3; + src.optionalInt64 = 0; + src.optionalUint32 = 3; + src.optionalUint64 = 0; + src.optionalSint32 = 3; + src.optionalSint64 = 0; + src.optionalFixed32 = 3; + src.optionalFixed64 = 0; + src.optionalSfixed32 = 3; + src.optionalSfixed64 = 0; + src.optionalFloat = 3.0f; + src.optionalDouble = 0.0; + src.optionalBool = YES; // No other value to use. :( + src.optionalString = nil; + src.optionalBytes = testData2; + src.optionalEnum = Message3_Enum_Foo; + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.optionalInt32, 3); + XCTAssertEqual(dst.optionalInt64, 2); + XCTAssertEqual(dst.optionalUint32, 3U); + XCTAssertEqual(dst.optionalUint64, 2U); + XCTAssertEqual(dst.optionalSint32, 3); + XCTAssertEqual(dst.optionalSint64, 2); + XCTAssertEqual(dst.optionalFixed32, 3U); + XCTAssertEqual(dst.optionalFixed64, 2U); + XCTAssertEqual(dst.optionalSfixed32, 3); + XCTAssertEqual(dst.optionalSfixed64, 2); + XCTAssertEqual(dst.optionalFloat, 3.0f); + XCTAssertEqual(dst.optionalDouble, 2.0); + XCTAssertEqual(dst.optionalBool, YES); + XCTAssertEqualObjects(dst.optionalString, @"baz"); + XCTAssertEqualObjects(dst.optionalBytes, testData2); + XCTAssertEqual(dst.optionalEnum, Message3_Enum_Baz); + + [src release]; + [dst release]; +} + +- (void)testProto3MergingEnums { + UnknownEnumsMyMessage *src = [UnknownEnumsMyMessage message]; + UnknownEnumsMyMessage *dst = [UnknownEnumsMyMessage message]; + + // Known value. + + src.e = UnknownEnumsMyEnum_Bar; + src.repeatedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:UnknownEnumsMyEnum_Bar]; + src.repeatedPackedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:UnknownEnumsMyEnum_Bar]; + src.oneofE1 = UnknownEnumsMyEnum_Bar; + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.e, UnknownEnumsMyEnum_Bar); + XCTAssertEqual(dst.repeatedEArray.count, 1U); + XCTAssertEqual([dst.repeatedEArray valueAtIndex:0], UnknownEnumsMyEnum_Bar); + XCTAssertEqual(dst.repeatedPackedEArray.count, 1U); + XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnum_Bar); + XCTAssertEqual(dst.oneofE1, UnknownEnumsMyEnum_Bar); + + // Unknown value. + + const int32_t kUnknownValue = 666; + + SetUnknownEnumsMyMessage_E_RawValue(src, kUnknownValue); + src.repeatedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:kUnknownValue]; + src.repeatedPackedEArray = + [GPBEnumArray arrayWithValidationFunction:UnknownEnumsMyEnum_IsValidValue + rawValue:kUnknownValue]; + SetUnknownEnumsMyMessage_OneofE1_RawValue(src, kUnknownValue); + + [dst mergeFrom:src]; + + XCTAssertEqual(dst.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(dst), kUnknownValue); + XCTAssertEqual(dst.repeatedEArray.count, 2U); + XCTAssertEqual([dst.repeatedEArray valueAtIndex:0], UnknownEnumsMyEnum_Bar); + XCTAssertEqual([dst.repeatedEArray valueAtIndex:1], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([dst.repeatedEArray rawValueAtIndex:1], kUnknownValue); + XCTAssertEqual(dst.repeatedPackedEArray.count, 2U); + XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnum_Bar); + XCTAssertEqual([dst.repeatedPackedEArray valueAtIndex:1], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([dst.repeatedPackedEArray rawValueAtIndex:1], kUnknownValue); + XCTAssertEqual(dst.oneofE1, + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_OneofE1_RawValue(dst), kUnknownValue); +} + +- (void)testProto2MergeOneof { + Message2 *src = [Message2 message]; + Message2 *dst = [Message2 message]; + + // + // Make sure whatever is in dst gets cleared out be merging in something else. + // + + dst.oneofEnum = Message2_Enum_Bar; + +//%PDDM-DEFINE MERGE2_TEST(SET_NAME, SET_VALUE, CLEARED_NAME, CLEARED_DEFAULT) +//% src.oneof##SET_NAME = SET_VALUE; +//% [dst mergeFrom:src]; +//% XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_Oneof##SET_NAME); +//% XCTAssertEqual(dst.oneof##SET_NAME, SET_VALUE); +//% XCTAssertEqual(dst.oneof##CLEARED_NAME, CLEARED_DEFAULT); +//% +//%PDDM-EXPAND MERGE2_TEST(Int32, 10, Enum, Message2_Enum_Baz) +// This block of code is generated, do not edit it directly. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertEqual(dst.oneofInt32, 10); + XCTAssertEqual(dst.oneofEnum, Message2_Enum_Baz); + +//%PDDM-EXPAND MERGE2_TEST(Int64, 11, Int32, 100) +// This block of code is generated, do not edit it directly. + + src.oneofInt64 = 11; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + XCTAssertEqual(dst.oneofInt64, 11); + XCTAssertEqual(dst.oneofInt32, 100); + +//%PDDM-EXPAND MERGE2_TEST(Uint32, 12U, Int64, 101) +// This block of code is generated, do not edit it directly. + + src.oneofUint32 = 12U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + XCTAssertEqual(dst.oneofUint32, 12U); + XCTAssertEqual(dst.oneofInt64, 101); + +//%PDDM-EXPAND MERGE2_TEST(Uint64, 13U, Uint32, 102U) +// This block of code is generated, do not edit it directly. + + src.oneofUint64 = 13U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + XCTAssertEqual(dst.oneofUint64, 13U); + XCTAssertEqual(dst.oneofUint32, 102U); + +//%PDDM-EXPAND MERGE2_TEST(Sint32, 14, Uint64, 103U) +// This block of code is generated, do not edit it directly. + + src.oneofSint32 = 14; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + XCTAssertEqual(dst.oneofSint32, 14); + XCTAssertEqual(dst.oneofUint64, 103U); + +//%PDDM-EXPAND MERGE2_TEST(Sint64, 15, Sint32, 104) +// This block of code is generated, do not edit it directly. + + src.oneofSint64 = 15; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + XCTAssertEqual(dst.oneofSint64, 15); + XCTAssertEqual(dst.oneofSint32, 104); + +//%PDDM-EXPAND MERGE2_TEST(Fixed32, 16U, Sint64, 105) +// This block of code is generated, do not edit it directly. + + src.oneofFixed32 = 16U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + XCTAssertEqual(dst.oneofFixed32, 16U); + XCTAssertEqual(dst.oneofSint64, 105); + +//%PDDM-EXPAND MERGE2_TEST(Fixed64, 17U, Fixed32, 106U) +// This block of code is generated, do not edit it directly. + + src.oneofFixed64 = 17U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + XCTAssertEqual(dst.oneofFixed64, 17U); + XCTAssertEqual(dst.oneofFixed32, 106U); + +//%PDDM-EXPAND MERGE2_TEST(Sfixed32, 18, Fixed64, 107U) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed32 = 18; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(dst.oneofSfixed32, 18); + XCTAssertEqual(dst.oneofFixed64, 107U); + +//%PDDM-EXPAND MERGE2_TEST(Sfixed64, 19, Sfixed32, 108) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed64 = 19; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(dst.oneofSfixed64, 19); + XCTAssertEqual(dst.oneofSfixed32, 108); + +//%PDDM-EXPAND MERGE2_TEST(Float, 20.0f, Sfixed64, 109) +// This block of code is generated, do not edit it directly. + + src.oneofFloat = 20.0f; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + XCTAssertEqual(dst.oneofFloat, 20.0f); + XCTAssertEqual(dst.oneofSfixed64, 109); + +//%PDDM-EXPAND MERGE2_TEST(Double, 21.0, Float, 110.0f) +// This block of code is generated, do not edit it directly. + + src.oneofDouble = 21.0; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + XCTAssertEqual(dst.oneofDouble, 21.0); + XCTAssertEqual(dst.oneofFloat, 110.0f); + +//%PDDM-EXPAND MERGE2_TEST(Bool, NO, Double, 111.0) +// This block of code is generated, do not edit it directly. + + src.oneofBool = NO; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofBool); + XCTAssertEqual(dst.oneofBool, NO); + XCTAssertEqual(dst.oneofDouble, 111.0); + +//%PDDM-EXPAND MERGE2_TEST(Enum, Message2_Enum_Bar, Bool, YES) +// This block of code is generated, do not edit it directly. + + src.oneofEnum = Message2_Enum_Bar; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + XCTAssertEqual(dst.oneofEnum, Message2_Enum_Bar); + XCTAssertEqual(dst.oneofBool, YES); + +//%PDDM-EXPAND-END (14 expansions) + + NSString *oneofStringDefault = @"string"; + NSData *oneofBytesDefault = [@"data" dataUsingEncoding:NSUTF8StringEncoding]; + + src.oneofString = @"foo"; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofString); + XCTAssertEqualObjects(dst.oneofString, @"foo"); + XCTAssertEqual(dst.oneofEnum, Message2_Enum_Baz); + + src.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(dst.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertEqualObjects(dst.oneofString, oneofStringDefault); + + Message2_OneofGroup *group = [Message2_OneofGroup message]; + group.a = 666; + src.oneofGroup = group; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + Message2_OneofGroup *mergedGroup = [[dst.oneofGroup retain] autorelease]; + XCTAssertNotNil(mergedGroup); + XCTAssertNotEqual(mergedGroup, group); // Pointer comparision. + XCTAssertEqualObjects(mergedGroup, group); + XCTAssertEqualObjects(dst.oneofBytes, oneofBytesDefault); + + Message2 *subMessage = [Message2 message]; + subMessage.optionalInt32 = 777; + src.oneofMessage = subMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + Message2 *mergedSubMessage = [[dst.oneofMessage retain] autorelease]; + XCTAssertNotNil(mergedSubMessage); + XCTAssertNotEqual(mergedSubMessage, subMessage); // Pointer comparision. + XCTAssertEqualObjects(mergedSubMessage, subMessage); + XCTAssertNotNil(dst.oneofGroup); + XCTAssertNotEqual(dst.oneofGroup, mergedGroup); // Pointer comparision. + + // Back to something else ot make sure message clears out ok. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertNotNil(dst.oneofMessage); + XCTAssertNotEqual(dst.oneofMessage, + mergedSubMessage); // Pointer comparision. + + // + // Test merging in to message/group when they already had something. + // + + src.oneofGroup = group; + mergedGroup = [Message2_OneofGroup message]; + mergedGroup.b = 888; + dst.oneofGroup = mergedGroup; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + // Shouldn't have been a new object. + XCTAssertEqual(dst.oneofGroup, mergedGroup); // Pointer comparision. + XCTAssertEqual(dst.oneofGroup.a, 666); // Pointer comparision. + XCTAssertEqual(dst.oneofGroup.b, 888); // Pointer comparision. + + src.oneofMessage = subMessage; + mergedSubMessage = [Message2 message]; + mergedSubMessage.optionalInt64 = 999; + dst.oneofMessage = mergedSubMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + // Shouldn't have been a new object. + XCTAssertEqual(dst.oneofMessage, mergedSubMessage); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt32, 777); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt64, 999); // Pointer comparision. +} + +- (void)testProto3MergeOneof { + Message3 *src = [Message3 message]; + Message3 *dst = [Message3 message]; + + // + // Make sure whatever is in dst gets cleared out be merging in something else. + // + + dst.oneofEnum = Message3_Enum_Bar; + +//%PDDM-DEFINE MERGE3_TEST(SET_NAME, SET_VALUE, CLEARED_NAME, CLEARED_DEFAULT) +//% src.oneof##SET_NAME = SET_VALUE; +//% [dst mergeFrom:src]; +//% XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_Oneof##SET_NAME); +//% XCTAssertEqual(dst.oneof##SET_NAME, SET_VALUE); +//% XCTAssertEqual(dst.oneof##CLEARED_NAME, CLEARED_DEFAULT); +//% +//%PDDM-EXPAND MERGE3_TEST(Int32, 10, Enum, Message3_Enum_Foo) +// This block of code is generated, do not edit it directly. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertEqual(dst.oneofInt32, 10); + XCTAssertEqual(dst.oneofEnum, Message3_Enum_Foo); + +//%PDDM-EXPAND MERGE3_TEST(Int64, 11, Int32, 0) +// This block of code is generated, do not edit it directly. + + src.oneofInt64 = 11; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + XCTAssertEqual(dst.oneofInt64, 11); + XCTAssertEqual(dst.oneofInt32, 0); + +//%PDDM-EXPAND MERGE3_TEST(Uint32, 12U, Int64, 0) +// This block of code is generated, do not edit it directly. + + src.oneofUint32 = 12U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + XCTAssertEqual(dst.oneofUint32, 12U); + XCTAssertEqual(dst.oneofInt64, 0); + +//%PDDM-EXPAND MERGE3_TEST(Uint64, 13U, Uint32, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofUint64 = 13U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + XCTAssertEqual(dst.oneofUint64, 13U); + XCTAssertEqual(dst.oneofUint32, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sint32, 14, Uint64, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofSint32 = 14; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + XCTAssertEqual(dst.oneofSint32, 14); + XCTAssertEqual(dst.oneofUint64, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sint64, 15, Sint32, 0) +// This block of code is generated, do not edit it directly. + + src.oneofSint64 = 15; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + XCTAssertEqual(dst.oneofSint64, 15); + XCTAssertEqual(dst.oneofSint32, 0); + +//%PDDM-EXPAND MERGE3_TEST(Fixed32, 16U, Sint64, 0) +// This block of code is generated, do not edit it directly. + + src.oneofFixed32 = 16U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + XCTAssertEqual(dst.oneofFixed32, 16U); + XCTAssertEqual(dst.oneofSint64, 0); + +//%PDDM-EXPAND MERGE3_TEST(Fixed64, 17U, Fixed32, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofFixed64 = 17U; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + XCTAssertEqual(dst.oneofFixed64, 17U); + XCTAssertEqual(dst.oneofFixed32, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sfixed32, 18, Fixed64, 0U) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed32 = 18; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(dst.oneofSfixed32, 18); + XCTAssertEqual(dst.oneofFixed64, 0U); + +//%PDDM-EXPAND MERGE3_TEST(Sfixed64, 19, Sfixed32, 0) +// This block of code is generated, do not edit it directly. + + src.oneofSfixed64 = 19; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(dst.oneofSfixed64, 19); + XCTAssertEqual(dst.oneofSfixed32, 0); + +//%PDDM-EXPAND MERGE3_TEST(Float, 20.0f, Sfixed64, 0) +// This block of code is generated, do not edit it directly. + + src.oneofFloat = 20.0f; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + XCTAssertEqual(dst.oneofFloat, 20.0f); + XCTAssertEqual(dst.oneofSfixed64, 0); + +//%PDDM-EXPAND MERGE3_TEST(Double, 21.0, Float, 0.0f) +// This block of code is generated, do not edit it directly. + + src.oneofDouble = 21.0; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + XCTAssertEqual(dst.oneofDouble, 21.0); + XCTAssertEqual(dst.oneofFloat, 0.0f); + +//%PDDM-EXPAND MERGE3_TEST(Bool, YES, Double, 0.0) +// This block of code is generated, do not edit it directly. + + src.oneofBool = YES; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofBool); + XCTAssertEqual(dst.oneofBool, YES); + XCTAssertEqual(dst.oneofDouble, 0.0); + +//%PDDM-EXPAND MERGE3_TEST(Enum, Message3_Enum_Bar, Bool, NO) +// This block of code is generated, do not edit it directly. + + src.oneofEnum = Message3_Enum_Bar; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + XCTAssertEqual(dst.oneofEnum, Message3_Enum_Bar); + XCTAssertEqual(dst.oneofBool, NO); + +//%PDDM-EXPAND-END (14 expansions) + + NSString *oneofStringDefault = @""; + NSData *oneofBytesDefault = [NSData data]; + + src.oneofString = @"foo"; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofString); + XCTAssertEqualObjects(dst.oneofString, @"foo"); + XCTAssertEqual(dst.oneofEnum, Message3_Enum_Foo); + + src.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(dst.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertEqualObjects(dst.oneofString, oneofStringDefault); + + + Message3 *subMessage = [Message3 message]; + subMessage.optionalInt32 = 777; + src.oneofMessage = subMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + Message3 *mergedSubMessage = [[dst.oneofMessage retain] autorelease]; + XCTAssertNotNil(mergedSubMessage); + XCTAssertNotEqual(mergedSubMessage, subMessage); // Pointer comparision. + XCTAssertEqualObjects(mergedSubMessage, subMessage); + XCTAssertEqualObjects(dst.oneofBytes, oneofBytesDefault); + + // Back to something else ot make sure message clears out ok. + + src.oneofInt32 = 10; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertNotNil(dst.oneofMessage); + XCTAssertNotEqual(dst.oneofMessage, + mergedSubMessage); // Pointer comparision. + + // + // Test merging in to message when they already had something. + // + + src.oneofMessage = subMessage; + mergedSubMessage = [Message3 message]; + mergedSubMessage.optionalInt64 = 999; + dst.oneofMessage = mergedSubMessage; + [dst mergeFrom:src]; + XCTAssertEqual(dst.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + // Shouldn't have been a new object. + XCTAssertEqual(dst.oneofMessage, mergedSubMessage); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt32, 777); // Pointer comparision. + XCTAssertEqual(dst.oneofMessage.optionalInt64, 999); // Pointer comparision. +} + +#pragma mark - Subset from from map_tests.cc + +// TEST(GeneratedMapFieldTest, CopyFromMessageMap) +- (void)testMap_CopyFromMessageMap { + TestMessageMap *msg1 = [[TestMessageMap alloc] init]; + TestMessageMap *msg2 = [[TestMessageMap alloc] init]; + + TestAllTypes *subMsg = [TestAllTypes message]; + subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:100]; + msg1.mapInt32Message = [GPBInt32ObjectDictionary dictionary]; + [msg1.mapInt32Message setValue:subMsg forKey:0]; + subMsg = nil; + + subMsg = [TestAllTypes message]; + subMsg.repeatedInt32Array = [GPBInt32Array arrayWithValue:101]; + msg2.mapInt32Message = [GPBInt32ObjectDictionary dictionary]; + [msg2.mapInt32Message setValue:subMsg forKey:0]; + subMsg = nil; + + [msg1 mergeFrom:msg2]; + + // Checks repeated field is overwritten. + XCTAssertEqual(msg1.mapInt32Message.count, 1U); + subMsg = [msg1.mapInt32Message valueForKey:0]; + XCTAssertNotNil(subMsg); + XCTAssertEqual(subMsg.repeatedInt32Array.count, 1U); + XCTAssertEqual([subMsg.repeatedInt32Array valueAtIndex:0], 101); + + [msg2 release]; + [msg1 release]; +} + +@end diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m new file mode 100644 index 00000000..6ad29ca5 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests+Runtime.m @@ -0,0 +1,1978 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 "GPBTestUtilities.h" + +#import + +#import "GPBMessage.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" + +@interface MessageRuntimeTests : GPBTestCase +@end + +@implementation MessageRuntimeTests + +// TODO(thomasvl): Pull tests over from GPBMessageTests that are runtime +// specific. + +- (void)testProto2HasMethodSupport { + NSArray *names = @[ + @"Int32", + @"Int64", + @"Uint32", + @"Uint64", + @"Sint32", + @"Sint64", + @"Fixed32", + @"Fixed64", + @"Sfixed32", + @"Sfixed64", + @"Float", + @"Double", + @"Bool", + @"String", + @"Bytes", + @"Group", + @"Message", + @"Enum", + ]; + + // Proto2 gets: + // - has* on all non repeated fields. + // - setHas* on all non repeated fields. + + for (NSString *name in names) { + // build the selector, i.e. - hasOptionalInt32/setHasOptionalInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasOptional%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOptional%@:", name]); + XCTAssertTrue([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertTrue([Message2 instancesRespondToSelector:setHasSel], @"field: %@", + name); + } + + // Repeated - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasRepeatedInt32/setHasRepeatedInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasRepeated%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasRepeated%@:", name]); + XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } + + // Oneofs - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasOneofInt32/setHasOneofInt32: + SEL hasSel = + NSSelectorFromString([NSString stringWithFormat:@"hasOneof%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOneof%@:", name]); + XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } +} + +- (void)testProto3HasMethodSupport { + NSArray *names = @[ + @"Int32", + @"Int64", + @"Uint32", + @"Uint64", + @"Sint32", + @"Sint64", + @"Fixed32", + @"Fixed64", + @"Sfixed32", + @"Sfixed64", + @"Float", + @"Double", + @"Bool", + @"String", + @"Bytes", + @"Message", + @"Enum", + ]; + + // Proto3 gets: + // - has* on non repeated message fields. + // - setHas* on all non repeated message fields. + + // Singlular + + for (NSString *name in names) { + // build the selector, i.e. - hasOptionalInt32/setHasOptionalInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasOptional%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOptional%@:", name]); + if ([name isEqual:@"Group"] || [name isEqual:@"Message"]) { + // Sub messages/groups are the exception. + XCTAssertTrue([Message3 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertTrue([Message3 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } else { + XCTAssertFalse([Message3 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message3 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } + } + + // Repeated - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasRepeatedInt32/setHasRepeatedInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasRepeated%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasRepeated%@:", name]); + XCTAssertFalse([Message3 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message3 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } + + // Oneofs - no has/setHas + + for (NSString *name in names) { + // build the selector, i.e. - hasOneofInt32/setHasOneofInt32: + SEL hasSel = + NSSelectorFromString([NSString stringWithFormat:@"hasOneof%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOneof%@:", name]); + XCTAssertFalse([Message2 instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertFalse([Message2 instancesRespondToSelector:setHasSel], + @"field: %@", name); + } +} + +- (void)testProto2SingleFieldHasBehavior { + // + // Setting to any value including the default value (0) should result has* + // being true. + // + +//%PDDM-DEFINE PROTO2_TEST_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE) +//% { // optional##FIELD :: NON_ZERO_VALUE +//% Message2 *msg = [[Message2 alloc] init]; +//% XCTAssertFalse(msg.hasOptional##FIELD); +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = NON_ZERO_VALUE; +//% XCTAssertTrue(msg.hasOptional##FIELD); +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% [msg release]; +//% } +//% { // optional##FIELD :: ZERO_VALUE +//% Message2 *msg = [[Message2 alloc] init]; +//% XCTAssertFalse(msg.hasOptional##FIELD); +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = ZERO_VALUE; +//% XCTAssertTrue(msg.hasOptional##FIELD); +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_Optional##FIELD)); +//% [msg release]; +//% } +//% +//%PDDM-DEFINE PROTO2_TEST_HAS_FIELDS() +//%PROTO2_TEST_HAS_FIELD(Int32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Int64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Uint32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Uint64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sint32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sint64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Fixed32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Fixed64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sfixed32, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Sfixed64, 1, 0) +//%PROTO2_TEST_HAS_FIELD(Float, 1.0f, 0.0f) +//%PROTO2_TEST_HAS_FIELD(Double, 1.0, 0.0) +//%PROTO2_TEST_HAS_FIELD(Bool, YES, NO) +//%PROTO2_TEST_HAS_FIELD(String, @"foo", @"") +//%PROTO2_TEST_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data]) +//% // +//% // Test doesn't apply to optionalGroup/optionalMessage. +//% // +//% +//%PROTO2_TEST_HAS_FIELD(Enum, Message2_Enum_Bar, Message2_Enum_Foo) +//%PDDM-EXPAND PROTO2_TEST_HAS_FIELDS() +// This block of code is generated, do not edit it directly. + + { // optionalInt32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 1; + XCTAssertTrue(msg.hasOptionalInt32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + [msg release]; + } + { // optionalInt32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 0; + XCTAssertTrue(msg.hasOptionalInt32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt32)); + [msg release]; + } + + { // optionalInt64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 1; + XCTAssertTrue(msg.hasOptionalInt64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + [msg release]; + } + { // optionalInt64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalInt64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 0; + XCTAssertTrue(msg.hasOptionalInt64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalInt64)); + [msg release]; + } + + { // optionalUint32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 1; + XCTAssertTrue(msg.hasOptionalUint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + [msg release]; + } + { // optionalUint32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 0; + XCTAssertTrue(msg.hasOptionalUint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint32)); + [msg release]; + } + + { // optionalUint64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 1; + XCTAssertTrue(msg.hasOptionalUint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + [msg release]; + } + { // optionalUint64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalUint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 0; + XCTAssertTrue(msg.hasOptionalUint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalUint64)); + [msg release]; + } + + { // optionalSint32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 1; + XCTAssertTrue(msg.hasOptionalSint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + [msg release]; + } + { // optionalSint32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 0; + XCTAssertTrue(msg.hasOptionalSint32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint32)); + [msg release]; + } + + { // optionalSint64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 1; + XCTAssertTrue(msg.hasOptionalSint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + [msg release]; + } + { // optionalSint64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSint64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 0; + XCTAssertTrue(msg.hasOptionalSint64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSint64)); + [msg release]; + } + + { // optionalFixed32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 1; + XCTAssertTrue(msg.hasOptionalFixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + [msg release]; + } + { // optionalFixed32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 0; + XCTAssertTrue(msg.hasOptionalFixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed32)); + [msg release]; + } + + { // optionalFixed64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 1; + XCTAssertTrue(msg.hasOptionalFixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + [msg release]; + } + { // optionalFixed64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 0; + XCTAssertTrue(msg.hasOptionalFixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFixed64)); + [msg release]; + } + + { // optionalSfixed32 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 1; + XCTAssertTrue(msg.hasOptionalSfixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + [msg release]; + } + { // optionalSfixed32 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed32); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 0; + XCTAssertTrue(msg.hasOptionalSfixed32); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed32)); + [msg release]; + } + + { // optionalSfixed64 :: 1 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 1; + XCTAssertTrue(msg.hasOptionalSfixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + [msg release]; + } + { // optionalSfixed64 :: 0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalSfixed64); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 0; + XCTAssertTrue(msg.hasOptionalSfixed64); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalSfixed64)); + [msg release]; + } + + { // optionalFloat :: 1.0f + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFloat); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + msg.optionalFloat = 1.0f; + XCTAssertTrue(msg.hasOptionalFloat); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + [msg release]; + } + { // optionalFloat :: 0.0f + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalFloat); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + msg.optionalFloat = 0.0f; + XCTAssertTrue(msg.hasOptionalFloat); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalFloat)); + [msg release]; + } + + { // optionalDouble :: 1.0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalDouble); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + msg.optionalDouble = 1.0; + XCTAssertTrue(msg.hasOptionalDouble); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + [msg release]; + } + { // optionalDouble :: 0.0 + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalDouble); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + msg.optionalDouble = 0.0; + XCTAssertTrue(msg.hasOptionalDouble); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalDouble)); + [msg release]; + } + + { // optionalBool :: YES + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBool); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + msg.optionalBool = YES; + XCTAssertTrue(msg.hasOptionalBool); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + [msg release]; + } + { // optionalBool :: NO + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBool); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + msg.optionalBool = NO; + XCTAssertTrue(msg.hasOptionalBool); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBool)); + [msg release]; + } + + { // optionalString :: @"foo" + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalString); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + msg.optionalString = @"foo"; + XCTAssertTrue(msg.hasOptionalString); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + [msg release]; + } + { // optionalString :: @"" + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalString); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + msg.optionalString = @""; + XCTAssertTrue(msg.hasOptionalString); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalString)); + [msg release]; + } + + { // optionalBytes :: [@"foo" dataUsingEncoding:NSUTF8StringEncoding] + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBytes); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertTrue(msg.hasOptionalBytes); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + [msg release]; + } + { // optionalBytes :: [NSData data] + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalBytes); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + msg.optionalBytes = [NSData data]; + XCTAssertTrue(msg.hasOptionalBytes); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalBytes)); + [msg release]; + } + + // + // Test doesn't apply to optionalGroup/optionalMessage. + // + + { // optionalEnum :: Message2_Enum_Bar + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalEnum); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message2_Enum_Bar; + XCTAssertTrue(msg.hasOptionalEnum); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + [msg release]; + } + { // optionalEnum :: Message2_Enum_Foo + Message2 *msg = [[Message2 alloc] init]; + XCTAssertFalse(msg.hasOptionalEnum); + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message2_Enum_Foo; + XCTAssertTrue(msg.hasOptionalEnum); + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message2_FieldNumber_OptionalEnum)); + [msg release]; + } + +//%PDDM-EXPAND-END PROTO2_TEST_HAS_FIELDS() +} + +- (void)testProto3SingleFieldHasBehavior { + // + // Setting to any value including the default value (0) should result has* + // being true. + // + +//%PDDM-DEFINE PROTO3_TEST_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE) +//% { // optional##FIELD +//% Message3 *msg = [[Message3 alloc] init]; +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = NON_ZERO_VALUE; +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = ZERO_VALUE; +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_Optional##FIELD)); +//% [msg release]; +//% } +//% +//%PDDM-DEFINE PROTO3_TEST_HAS_FIELDS() +//%PROTO3_TEST_HAS_FIELD(Int32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Int64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Uint32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Uint64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sint32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sint64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Fixed32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Fixed64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sfixed32, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Sfixed64, 1, 0) +//%PROTO3_TEST_HAS_FIELD(Float, 1.0f, 0.0f) +//%PROTO3_TEST_HAS_FIELD(Double, 1.0, 0.0) +//%PROTO3_TEST_HAS_FIELD(Bool, YES, NO) +//%PROTO3_TEST_HAS_FIELD(String, @"foo", @"") +//%PROTO3_TEST_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data]) +//% // +//% // Test doesn't apply to optionalGroup/optionalMessage. +//% // +//% +//%PROTO3_TEST_HAS_FIELD(Enum, Message3_Enum_Bar, Message3_Enum_Foo) +//%PDDM-EXPAND PROTO3_TEST_HAS_FIELDS() +// This block of code is generated, do not edit it directly. + + { // optionalInt32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt32)); + [msg release]; + } + + { // optionalInt64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalInt64)); + [msg release]; + } + + { // optionalUint32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint32)); + [msg release]; + } + + { // optionalUint64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalUint64)); + [msg release]; + } + + { // optionalSint32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint32)); + [msg release]; + } + + { // optionalSint64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSint64)); + [msg release]; + } + + { // optionalFixed32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed32)); + [msg release]; + } + + { // optionalFixed64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFixed64)); + [msg release]; + } + + { // optionalSfixed32 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed32)); + [msg release]; + } + + { // optionalSfixed64 + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalSfixed64)); + [msg release]; + } + + { // optionalFloat + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat)); + msg.optionalFloat = 1.0f; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat)); + msg.optionalFloat = 0.0f; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalFloat)); + [msg release]; + } + + { // optionalDouble + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble)); + msg.optionalDouble = 1.0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble)); + msg.optionalDouble = 0.0; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalDouble)); + [msg release]; + } + + { // optionalBool + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool)); + msg.optionalBool = YES; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool)); + msg.optionalBool = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBool)); + [msg release]; + } + + { // optionalString + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString)); + msg.optionalString = @"foo"; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString)); + msg.optionalString = @""; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalString)); + [msg release]; + } + + { // optionalBytes + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes)); + msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes)); + msg.optionalBytes = [NSData data]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalBytes)); + [msg release]; + } + + // + // Test doesn't apply to optionalGroup/optionalMessage. + // + + { // optionalEnum + Message3 *msg = [[Message3 alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message3_Enum_Bar; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message3_Enum_Foo; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3_FieldNumber_OptionalEnum)); + [msg release]; + } + +//%PDDM-EXPAND-END PROTO3_TEST_HAS_FIELDS() +} + +- (void)testAccessingProto2UnknownEnumValues { + Message2 *msg = [[Message2 alloc] init]; + + // Set it to something non zero, try and confirm it doesn't change. + + msg.optionalEnum = Message2_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.optionalEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.optionalEnum, Message2_Enum_Bar); + + msg.oneofEnum = Message2_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.oneofEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); +} + +- (void)testAccessingProto3UnknownEnumValues { + Message3 *msg = [[Message3 alloc] init]; + + // Set it to something non zero, try and confirm it doesn't change. + + msg.optionalEnum = Message3_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.optionalEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.optionalEnum, Message3_Enum_Bar); + + msg.oneofEnum = Message3_Enum_Bar; + XCTAssertThrowsSpecificNamed(msg.oneofEnum = 666, NSException, + NSInvalidArgumentException); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Bar); + + // Set via raw api to confirm it works. + + SetMessage3_OptionalEnum_RawValue(msg, 666); + XCTAssertEqual(msg.optionalEnum, + Message3_Enum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(Message3_OptionalEnum_RawValue(msg), 666); + + SetMessage3_OneofEnum_RawValue(msg, 666); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(Message3_OneofEnum_RawValue(msg), 666); + + [msg release]; +} + +- (void)testProto2OneofBasicBehaviors { + Message2 *msg = [[Message2 alloc] init]; + + NSString *oneofStringDefault = @"string"; + NSData *oneofBytesDefault = [@"data" dataUsingEncoding:NSUTF8StringEncoding]; + + // Nothing set. + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + + // Set, check the case, check everyone has default but the one, confirm case + // didn't change. + + msg.oneofInt32 = 1; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + + msg.oneofInt64 = 2; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 2); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + + msg.oneofUint32 = 3; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 3U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + + msg.oneofUint64 = 4; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 4U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + + msg.oneofSint32 = 5; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 5); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + + msg.oneofSint64 = 6; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 6); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + + msg.oneofFixed32 = 7; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 7U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + + msg.oneofFixed64 = 8; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 8U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + + msg.oneofSfixed32 = 9; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 9); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + + msg.oneofSfixed64 = 10; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 10); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + + msg.oneofFloat = 11.0f; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 11.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + + msg.oneofDouble = 12.0; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 12.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + + msg.oneofBool = NO; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool); + + msg.oneofString = @"foo"; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString); + + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + + Message2_OneofGroup *group = [Message2_OneofGroup message]; + msg.oneofGroup = group; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertEqual(msg.oneofGroup, group); // Pointer compare. + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + + Message2 *subMessage = [Message2 message]; + msg.oneofMessage = subMessage; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotEqual(msg.oneofGroup, group); // Pointer compare. + XCTAssertEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + + msg.oneofEnum = Message2_Enum_Bar; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofInt32, 100); + XCTAssertEqual(msg.oneofInt64, 101); + XCTAssertEqual(msg.oneofUint32, 102U); + XCTAssertEqual(msg.oneofUint64, 103U); + XCTAssertEqual(msg.oneofSint32, 104); + XCTAssertEqual(msg.oneofSint64, 105); + XCTAssertEqual(msg.oneofFixed32, 106U); + XCTAssertEqual(msg.oneofFixed64, 107U); + XCTAssertEqual(msg.oneofSfixed32, 108); + XCTAssertEqual(msg.oneofSfixed64, 109); + XCTAssertEqual(msg.oneofFloat, 110.0f); + XCTAssertEqual(msg.oneofDouble, 111.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofGroup); + XCTAssertNotEqual(msg.oneofGroup, group); // Pointer compare. + XCTAssertNotNil(msg.oneofMessage); + XCTAssertNotEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + + // Test setting/calling clear clearing. + + [msg release]; + msg = [[Message2 alloc] init]; + + uint32_t values[] = { + Message2_O_OneOfCase_OneofInt32, + Message2_O_OneOfCase_OneofInt64, + Message2_O_OneOfCase_OneofUint32, + Message2_O_OneOfCase_OneofUint64, + Message2_O_OneOfCase_OneofSint32, + Message2_O_OneOfCase_OneofSint64, + Message2_O_OneOfCase_OneofFixed32, + Message2_O_OneOfCase_OneofFixed64, + Message2_O_OneOfCase_OneofSfixed32, + Message2_O_OneOfCase_OneofSfixed64, + Message2_O_OneOfCase_OneofFloat, + Message2_O_OneOfCase_OneofDouble, + Message2_O_OneOfCase_OneofBool, + Message2_O_OneOfCase_OneofString, + Message2_O_OneOfCase_OneofBytes, + Message2_O_OneOfCase_OneofGroup, + Message2_O_OneOfCase_OneofMessage, + Message2_O_OneOfCase_OneofEnum, + }; + + for (size_t i = 0; i < (sizeof(values) / sizeof((values[0]))); ++i) { + switch (values[i]) { + case Message2_O_OneOfCase_OneofInt32: + msg.oneofInt32 = 1; + break; + case Message2_O_OneOfCase_OneofInt64: + msg.oneofInt64 = 2; + break; + case Message2_O_OneOfCase_OneofUint32: + msg.oneofUint32 = 3; + break; + case Message2_O_OneOfCase_OneofUint64: + msg.oneofUint64 = 4; + break; + case Message2_O_OneOfCase_OneofSint32: + msg.oneofSint32 = 5; + break; + case Message2_O_OneOfCase_OneofSint64: + msg.oneofSint64 = 6; + break; + case Message2_O_OneOfCase_OneofFixed32: + msg.oneofFixed32 = 7; + break; + case Message2_O_OneOfCase_OneofFixed64: + msg.oneofFixed64 = 8; + break; + case Message2_O_OneOfCase_OneofSfixed32: + msg.oneofSfixed32 = 9; + break; + case Message2_O_OneOfCase_OneofSfixed64: + msg.oneofSfixed64 = 10; + break; + case Message2_O_OneOfCase_OneofFloat: + msg.oneofFloat = 11.0f; + break; + case Message2_O_OneOfCase_OneofDouble: + msg.oneofDouble = 12.0; + break; + case Message2_O_OneOfCase_OneofBool: + msg.oneofBool = YES; + break; + case Message2_O_OneOfCase_OneofString: + msg.oneofString = @"foo"; + break; + case Message2_O_OneOfCase_OneofBytes: + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + break; + case Message2_O_OneOfCase_OneofGroup: + msg.oneofGroup = group; + break; + case Message2_O_OneOfCase_OneofMessage: + msg.oneofMessage = subMessage; + break; + case Message2_O_OneOfCase_OneofEnum: + msg.oneofEnum = Message2_Enum_Bar; + break; + default: + XCTFail(@"shouldn't happen, loop: %zd", i); + break; + } + + XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i); + // No need to check the value was set, the above tests did that. + Message2_ClearOOneOfCase(msg); + // Nothing in the case. + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_GPBUnsetOneOfCase, + "Loop: %zd", i); + // Confirm everything is back to defaults after a clear. + XCTAssertEqual(msg.oneofInt32, 100, "Loop: %zd", i); + XCTAssertEqual(msg.oneofInt64, 101, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint32, 102U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint64, 103U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint32, 104, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint64, 105, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed32, 106U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed64, 107U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed32, 108, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed64, 109, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFloat, 110.0f, "Loop: %zd", i); + XCTAssertEqual(msg.oneofDouble, 111.0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofBool, YES, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i); + XCTAssertNotNil(msg.oneofGroup, "Loop: %zd", i); + XCTAssertNotEqual(msg.oneofGroup, group, "Loop: %zd", + i); // Pointer compare. + XCTAssertNotNil(msg.oneofMessage, "Loop: %zd", i); + XCTAssertNotEqual(msg.oneofMessage, subMessage, "Loop: %zd", + i); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Baz, "Loop: %zd", i); + } + + [msg release]; +} + +- (void)testProto3OneofBasicBehaviors { + Message3 *msg = [[Message3 alloc] init]; + + NSString *oneofStringDefault = @""; + NSData *oneofBytesDefault = [NSData data]; + + // Nothing set. + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + + // Set, check the case, check everyone has default but the one, confirm case + // didn't change. + + msg.oneofInt32 = 1; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + + msg.oneofInt64 = 2; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 2); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + + msg.oneofUint32 = 3; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 3U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + + msg.oneofUint64 = 4; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 4U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + + msg.oneofSint32 = 5; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 5); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + + msg.oneofSint64 = 6; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 6); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + + msg.oneofFixed32 = 7; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 7U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + + msg.oneofFixed64 = 8; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 8U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + + msg.oneofSfixed32 = 9; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 9); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + + msg.oneofSfixed64 = 10; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 10); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + + msg.oneofFloat = 11.0f; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 11.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + + msg.oneofDouble = 12.0; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 12.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + + msg.oneofBool = YES; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, YES); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool); + + msg.oneofString = @"foo"; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString); + + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, + [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + + Message3 *subMessage = [Message3 message]; + msg.oneofMessage = subMessage; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + + msg.oneofEnum = Message3_Enum_Bar; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofInt32, 0); + XCTAssertEqual(msg.oneofInt64, 0); + XCTAssertEqual(msg.oneofUint32, 0U); + XCTAssertEqual(msg.oneofUint64, 0U); + XCTAssertEqual(msg.oneofSint32, 0); + XCTAssertEqual(msg.oneofSint64, 0); + XCTAssertEqual(msg.oneofFixed32, 0U); + XCTAssertEqual(msg.oneofFixed64, 0U); + XCTAssertEqual(msg.oneofSfixed32, 0); + XCTAssertEqual(msg.oneofSfixed64, 0); + XCTAssertEqual(msg.oneofFloat, 0.0f); + XCTAssertEqual(msg.oneofDouble, 0.0); + XCTAssertEqual(msg.oneofBool, NO); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault); + XCTAssertNotNil(msg.oneofMessage); + XCTAssertNotEqual(msg.oneofMessage, subMessage); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Bar); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + + // Test setting/calling clear clearing. + + [msg release]; + msg = [[Message3 alloc] init]; + + uint32_t values[] = { + Message3_O_OneOfCase_OneofInt32, + Message3_O_OneOfCase_OneofInt64, + Message3_O_OneOfCase_OneofUint32, + Message3_O_OneOfCase_OneofUint64, + Message3_O_OneOfCase_OneofSint32, + Message3_O_OneOfCase_OneofSint64, + Message3_O_OneOfCase_OneofFixed32, + Message3_O_OneOfCase_OneofFixed64, + Message3_O_OneOfCase_OneofSfixed32, + Message3_O_OneOfCase_OneofSfixed64, + Message3_O_OneOfCase_OneofFloat, + Message3_O_OneOfCase_OneofDouble, + Message3_O_OneOfCase_OneofBool, + Message3_O_OneOfCase_OneofString, + Message3_O_OneOfCase_OneofBytes, + Message3_O_OneOfCase_OneofMessage, + Message3_O_OneOfCase_OneofEnum, + }; + + for (size_t i = 0; i < (sizeof(values) / sizeof((values[0]))); ++i) { + switch (values[i]) { + case Message3_O_OneOfCase_OneofInt32: + msg.oneofInt32 = 1; + break; + case Message3_O_OneOfCase_OneofInt64: + msg.oneofInt64 = 2; + break; + case Message3_O_OneOfCase_OneofUint32: + msg.oneofUint32 = 3; + break; + case Message3_O_OneOfCase_OneofUint64: + msg.oneofUint64 = 4; + break; + case Message3_O_OneOfCase_OneofSint32: + msg.oneofSint32 = 5; + break; + case Message3_O_OneOfCase_OneofSint64: + msg.oneofSint64 = 6; + break; + case Message3_O_OneOfCase_OneofFixed32: + msg.oneofFixed32 = 7; + break; + case Message3_O_OneOfCase_OneofFixed64: + msg.oneofFixed64 = 8; + break; + case Message3_O_OneOfCase_OneofSfixed32: + msg.oneofSfixed32 = 9; + break; + case Message3_O_OneOfCase_OneofSfixed64: + msg.oneofSfixed64 = 10; + break; + case Message3_O_OneOfCase_OneofFloat: + msg.oneofFloat = 11.0f; + break; + case Message3_O_OneOfCase_OneofDouble: + msg.oneofDouble = 12.0; + break; + case Message3_O_OneOfCase_OneofBool: + msg.oneofBool = YES; + break; + case Message3_O_OneOfCase_OneofString: + msg.oneofString = @"foo"; + break; + case Message3_O_OneOfCase_OneofBytes: + msg.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + break; + case Message3_O_OneOfCase_OneofMessage: + msg.oneofMessage = subMessage; + break; + case Message3_O_OneOfCase_OneofEnum: + msg.oneofEnum = Message3_Enum_Baz; + break; + default: + XCTFail(@"shouldn't happen, loop: %zd", i); + break; + } + + XCTAssertEqual(msg.oOneOfCase, values[i], "Loop: %zd", i); + // No need to check the value was set, the above tests did that. + Message3_ClearOOneOfCase(msg); + // Nothing in the case. + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase, + "Loop: %zd", i); + // Confirm everything is back to defaults after a clear. + XCTAssertEqual(msg.oneofInt32, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofInt64, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint32, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofUint64, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint32, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSint64, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed32, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFixed64, 0U, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed32, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofSfixed64, 0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofFloat, 0.0f, "Loop: %zd", i); + XCTAssertEqual(msg.oneofDouble, 0.0, "Loop: %zd", i); + XCTAssertEqual(msg.oneofBool, NO, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofString, oneofStringDefault, "Loop: %zd", i); + XCTAssertEqualObjects(msg.oneofBytes, oneofBytesDefault, "Loop: %zd", i); + XCTAssertNotNil(msg.oneofMessage, "Loop: %zd", i); + XCTAssertNotEqual(msg.oneofMessage, subMessage, "Loop: %zd", + i); // Pointer compare. + XCTAssertEqual(msg.oneofEnum, Message3_Enum_Foo, "Loop: %zd", i); + } + + [msg release]; +} + +- (void)testCopyingMakesUniqueObjects { + const int repeatCount = 5; + TestAllTypes *msg1 = [TestAllTypes message]; + [self setAllFields:msg1 repeatedCount:repeatCount]; + + TestAllTypes *msg2 = [[msg1 copy] autorelease]; + + XCTAssertNotEqual(msg1, msg2); // Ptr compare, new object. + XCTAssertEqualObjects(msg1, msg2); // Equal values. + + // Pointer comparisions, different objects. + + XCTAssertNotEqual(msg1.optionalGroup, msg2.optionalGroup); + XCTAssertNotEqual(msg1.optionalNestedMessage, msg2.optionalNestedMessage); + XCTAssertNotEqual(msg1.optionalForeignMessage, msg2.optionalForeignMessage); + XCTAssertNotEqual(msg1.optionalImportMessage, msg2.optionalImportMessage); + + XCTAssertNotEqual(msg1.repeatedInt32Array, msg2.repeatedInt32Array); + XCTAssertNotEqual(msg1.repeatedInt64Array, msg2.repeatedInt64Array); + XCTAssertNotEqual(msg1.repeatedUint32Array, msg2.repeatedUint32Array); + XCTAssertNotEqual(msg1.repeatedUint64Array, msg2.repeatedUint64Array); + XCTAssertNotEqual(msg1.repeatedSint32Array, msg2.repeatedSint32Array); + XCTAssertNotEqual(msg1.repeatedSint64Array, msg2.repeatedSint64Array); + XCTAssertNotEqual(msg1.repeatedFixed32Array, msg2.repeatedFixed32Array); + XCTAssertNotEqual(msg1.repeatedFixed64Array, msg2.repeatedFixed64Array); + XCTAssertNotEqual(msg1.repeatedSfixed32Array, msg2.repeatedSfixed32Array); + XCTAssertNotEqual(msg1.repeatedSfixed64Array, msg2.repeatedSfixed64Array); + XCTAssertNotEqual(msg1.repeatedFloatArray, msg2.repeatedFloatArray); + XCTAssertNotEqual(msg1.repeatedDoubleArray, msg2.repeatedDoubleArray); + XCTAssertNotEqual(msg1.repeatedBoolArray, msg2.repeatedBoolArray); + XCTAssertNotEqual(msg1.repeatedStringArray, msg2.repeatedStringArray); + XCTAssertNotEqual(msg1.repeatedBytesArray, msg2.repeatedBytesArray); + XCTAssertNotEqual(msg1.repeatedGroupArray, msg2.repeatedGroupArray); + XCTAssertNotEqual(msg1.repeatedNestedMessageArray, + msg2.repeatedNestedMessageArray); + XCTAssertNotEqual(msg1.repeatedForeignMessageArray, + msg2.repeatedForeignMessageArray); + XCTAssertNotEqual(msg1.repeatedImportMessageArray, + msg2.repeatedImportMessageArray); + XCTAssertNotEqual(msg1.repeatedNestedEnumArray, msg2.repeatedNestedEnumArray); + XCTAssertNotEqual(msg1.repeatedForeignEnumArray, + msg2.repeatedForeignEnumArray); + XCTAssertNotEqual(msg1.repeatedImportEnumArray, msg2.repeatedImportEnumArray); + XCTAssertNotEqual(msg1.repeatedStringPieceArray, + msg2.repeatedStringPieceArray); + XCTAssertNotEqual(msg1.repeatedCordArray, msg2.repeatedCordArray); + + for (int i = 0; i < repeatCount; i++) { + XCTAssertNotEqual(msg1.repeatedNestedMessageArray[i], + msg2.repeatedNestedMessageArray[i]); + XCTAssertNotEqual(msg1.repeatedForeignMessageArray[i], + msg2.repeatedForeignMessageArray[i]); + XCTAssertNotEqual(msg1.repeatedImportMessageArray[i], + msg2.repeatedImportMessageArray[i]); + } +} + +- (void)testCopyingMapsMakesUniqueObjects { + TestMap *msg1 = [TestMap message]; + [self setAllMapFields:msg1 numEntries:5]; + + TestMap *msg2 = [[msg1 copy] autorelease]; + + XCTAssertNotEqual(msg1, msg2); // Ptr compare, new object. + XCTAssertEqualObjects(msg1, msg2); // Equal values. + + // Pointer comparisions, different objects. + XCTAssertNotEqual(msg1.mapInt32Int32, msg2.mapInt32Int32); + XCTAssertNotEqual(msg1.mapInt64Int64, msg2.mapInt64Int64); + XCTAssertNotEqual(msg1.mapUint32Uint32, msg2.mapUint32Uint32); + XCTAssertNotEqual(msg1.mapUint64Uint64, msg2.mapUint64Uint64); + XCTAssertNotEqual(msg1.mapSint32Sint32, msg2.mapSint32Sint32); + XCTAssertNotEqual(msg1.mapSint64Sint64, msg2.mapSint64Sint64); + XCTAssertNotEqual(msg1.mapFixed32Fixed32, msg2.mapFixed32Fixed32); + XCTAssertNotEqual(msg1.mapFixed64Fixed64, msg2.mapFixed64Fixed64); + XCTAssertNotEqual(msg1.mapSfixed32Sfixed32, msg2.mapSfixed32Sfixed32); + XCTAssertNotEqual(msg1.mapSfixed64Sfixed64, msg2.mapSfixed64Sfixed64); + XCTAssertNotEqual(msg1.mapInt32Float, msg2.mapInt32Float); + XCTAssertNotEqual(msg1.mapInt32Double, msg2.mapInt32Double); + XCTAssertNotEqual(msg1.mapBoolBool, msg2.mapBoolBool); + XCTAssertNotEqual(msg1.mapStringString, msg2.mapStringString); + XCTAssertNotEqual(msg1.mapInt32Bytes, msg2.mapInt32Bytes); + XCTAssertNotEqual(msg1.mapInt32Enum, msg2.mapInt32Enum); + XCTAssertNotEqual(msg1.mapInt32ForeignMessage, msg2.mapInt32ForeignMessage); + + // Ensure the messages are unique per map. + [msg1.mapInt32ForeignMessage + enumerateKeysAndValuesUsingBlock:^(int32_t key, id value, BOOL *stop) { +#pragma unused(stop) + ForeignMessage *subMsg2 = [msg2.mapInt32ForeignMessage valueForKey:key]; + XCTAssertNotEqual(value, subMsg2); // Ptr compare, new object. + }]; +} + +#pragma mark - Subset from from map_tests.cc + +// TEST(GeneratedMapFieldTest, IsInitialized) +- (void)testMap_IsInitialized { + TestRequiredMessageMap *msg = [[TestRequiredMessageMap alloc] init]; + + // Add an uninitialized message. + TestRequired *subMsg = [[TestRequired alloc] init]; + msg.mapField = [GPBInt32ObjectDictionary dictionary]; + [msg.mapField setValue:subMsg forKey:0]; + XCTAssertFalse(msg.initialized); + + // Initialize uninitialized message + subMsg.a = 0; + subMsg.b = 0; + subMsg.c = 0; + XCTAssertTrue(msg.initialized); + + [subMsg release]; + [msg release]; +} + +@end diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m new file mode 100644 index 00000000..ddc2ae19 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests+Serialization.m @@ -0,0 +1,838 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 "GPBTestUtilities.h" + +#import + +#import "GPBMessage.h" + +#import "google/protobuf/MapProto2Unittest.pbobjc.h" +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/UnittestDropUnknownFields.pbobjc.h" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" + +#ifndef GPBARRAYSIZE +#define GPBARRAYSIZE(a) ((sizeof(a) / sizeof((a[0])))) +#endif // GPBARRAYSIZE + +static NSData *DataFromCStr(const char *str) { + return [NSData dataWithBytes:str length:strlen(str)]; +} + +@interface MessageSerializationTests : GPBTestCase +@end + +@implementation MessageSerializationTests + +// TODO(thomasvl): Pull tests over from GPBMessageTests that are serialization +// specific. + +- (void)testProto3SerializationHandlingDefaults { + // Proto2 covered in other tests. + + Message3 *msg = [[Message3 alloc] init]; + + // Add defaults, no output. + + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + + // All zeros, still nothing. + + msg.optionalInt32 = 0; + msg.optionalInt64 = 0; + msg.optionalUint32 = 0; + msg.optionalUint64 = 0; + msg.optionalSint32 = 0; + msg.optionalSint64 = 0; + msg.optionalFixed32 = 0; + msg.optionalFixed64 = 0; + msg.optionalSfixed32 = 0; + msg.optionalSfixed64 = 0; + msg.optionalFloat = 0.0f; + msg.optionalDouble = 0.0; + msg.optionalBool = NO; + msg.optionalString = @""; + msg.optionalBytes = [NSData data]; + msg.optionalEnum = Message3_Enum_Foo; // first value + + data = [msg data]; + XCTAssertEqual([data length], 0U); + + // The two that also take nil as nothing. + + msg.optionalString = nil; + msg.optionalBytes = nil; + + data = [msg data]; + XCTAssertEqual([data length], 0U); + + // Set one field... + + msg.optionalInt32 = 1; + + data = [msg data]; + const uint8_t expectedBytes[] = {0x08, 0x01}; + NSData *expected = [NSData dataWithBytes:expectedBytes length:2]; + XCTAssertEqualObjects(data, expected); + + // Back to zero... + + msg.optionalInt32 = 0; + + data = [msg data]; + XCTAssertEqual([data length], 0U); + + [msg release]; +} + +- (void)testProto3DroppingUnknownFields { + DropUnknownsFooWithExtraFields *fooWithExtras = + [[DropUnknownsFooWithExtraFields alloc] init]; + + fooWithExtras.int32Value = 1; + fooWithExtras.enumValue = DropUnknownsFooWithExtraFields_NestedEnum_Baz; + fooWithExtras.extraInt32Value = 2; + + DropUnknownsFoo *foo = [DropUnknownsFoo parseFromData:[fooWithExtras data]]; + + XCTAssertEqual(foo.int32Value, 1); + XCTAssertEqual(foo.enumValue, DropUnknownsFoo_NestedEnum_Baz); + // Nothing should end up in the unknowns. + XCTAssertEqual([foo.unknownFields countOfFields], 0U); + + [fooWithExtras release]; + fooWithExtras = [DropUnknownsFooWithExtraFields parseFromData:[foo data]]; + XCTAssertEqual(fooWithExtras.int32Value, 1); + XCTAssertEqual(fooWithExtras.enumValue, + DropUnknownsFooWithExtraFields_NestedEnum_Baz); + // And the extra value is gone (back to the default). + XCTAssertEqual(fooWithExtras.extraInt32Value, 0); + XCTAssertEqual([foo.unknownFields countOfFields], 0U); +} + +- (void)testProto2UnknownEnumToUnknownField { + Message3 *orig = [[Message3 alloc] init]; + + orig.optionalEnum = Message3_Enum_Extra3; + orig.repeatedEnumArray = + [GPBEnumArray arrayWithValidationFunction:Message3_Enum_IsValidValue + rawValue:Message3_Enum_Extra3]; + orig.repeatedPackedEnumArray = + [GPBEnumArray arrayWithValidationFunction:Message3_Enum_IsValidValue + rawValue:Message3_Enum_Extra3]; + orig.oneofEnum = Message3_Enum_Extra3; + + Message2 *msg = [[Message2 alloc] initWithData:[orig data]]; + + // None of the fields should be set. + + XCTAssertFalse(msg.hasOptionalEnum); + XCTAssertEqual(msg.repeatedEnumArray.count, 0U); + XCTAssertEqual(msg.repeatedPackedEnumArray.count, 0U); + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_GPBUnsetOneOfCase); + + // All the values should be in unknown fields. + + GPBUnknownFieldSet *unknownFields = msg.unknownFields; + + XCTAssertEqual([unknownFields countOfFields], 4U); + XCTAssertTrue([unknownFields hasField:Message2_FieldNumber_OptionalEnum]); + XCTAssertTrue( + [unknownFields hasField:Message2_FieldNumber_RepeatedEnumArray]); + XCTAssertTrue( + [unknownFields hasField:Message2_FieldNumber_RepeatedPackedEnumArray]); + XCTAssertTrue([unknownFields hasField:Message2_FieldNumber_OneofEnum]); + + GPBField *field = [unknownFields getField:Message2_FieldNumber_OptionalEnum]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + field = [unknownFields getField:Message2_FieldNumber_RepeatedEnumArray]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + field = [unknownFields getField:Message2_FieldNumber_RepeatedPackedEnumArray]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + field = [unknownFields getField:Message2_FieldNumber_OneofEnum]; + XCTAssertEqual(field.varintList.count, 1U); + XCTAssertEqual([field.varintList valueAtIndex:0], + (uint64_t)Message3_Enum_Extra3); + + [msg release]; + [orig release]; +} + +- (void)testProto3UnknownEnumPreserving { + UnknownEnumsMyMessagePlusExtra *orig = + [UnknownEnumsMyMessagePlusExtra message]; + + orig.e = UnknownEnumsMyEnumPlusExtra_EExtra; + orig.repeatedEArray = [GPBEnumArray + arrayWithValidationFunction:UnknownEnumsMyEnumPlusExtra_IsValidValue + rawValue:UnknownEnumsMyEnumPlusExtra_EExtra]; + orig.repeatedPackedEArray = [GPBEnumArray + arrayWithValidationFunction:UnknownEnumsMyEnumPlusExtra_IsValidValue + rawValue:UnknownEnumsMyEnumPlusExtra_EExtra]; + orig.oneofE1 = UnknownEnumsMyEnumPlusExtra_EExtra; + + // Everything should be there via raw values. + + UnknownEnumsMyMessage *msg = + [UnknownEnumsMyMessage parseFromData:[orig data]]; + + XCTAssertEqual(msg.e, UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_E_RawValue(msg), + UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(msg.repeatedEArray.count, 1U); + XCTAssertEqual([msg.repeatedEArray valueAtIndex:0], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([msg.repeatedEArray rawValueAtIndex:0], + (UnknownEnumsMyEnum)UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(msg.repeatedPackedEArray.count, 1U); + XCTAssertEqual([msg.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual([msg.repeatedPackedEArray rawValueAtIndex:0], + (UnknownEnumsMyEnum)UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(msg.oneofE1, + UnknownEnumsMyEnum_GPBUnrecognizedEnumeratorValue); + XCTAssertEqual(UnknownEnumsMyMessage_OneofE1_RawValue(msg), + UnknownEnumsMyEnumPlusExtra_EExtra); + + // Everything should go out and come back. + + orig = [UnknownEnumsMyMessagePlusExtra parseFromData:[msg data]]; + + XCTAssertEqual(orig.e, UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(orig.repeatedEArray.count, 1U); + XCTAssertEqual([orig.repeatedEArray valueAtIndex:0], + UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(orig.repeatedPackedEArray.count, 1U); + XCTAssertEqual([orig.repeatedPackedEArray valueAtIndex:0], + UnknownEnumsMyEnumPlusExtra_EExtra); + XCTAssertEqual(orig.oneofE1, UnknownEnumsMyEnumPlusExtra_EExtra); +} + +//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOF(MESSAGE, FIELD, VALUE) +//%TEST_ROUNDTRIP_ONEOF_ADV(MESSAGE, FIELD, VALUE, ) +//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOF_ADV(MESSAGE, FIELD, VALUE, EQ_SUFFIX) +//% { // oneof##FIELD +//% MESSAGE *orig = [[MESSAGE alloc] init]; +//% orig.oneof##FIELD = VALUE; +//% XCTAssertEqual(orig.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD); +//% MESSAGE *msg = [MESSAGE parseFromData:[orig data]]; +//% XCTAssertEqual(msg.oOneOfCase, MESSAGE##_O_OneOfCase_Oneof##FIELD); +//% XCTAssertEqual##EQ_SUFFIX(msg.oneof##FIELD, VALUE); +//% [orig release]; +//% } +//% +//%PDDM-DEFINE TEST_ROUNDTRIP_ONEOFS(SYNTAX, BOOL_NON_DEFAULT) +//%- (void)testProto##SYNTAX##RoundTripOneof { +//% +//%GROUP_INIT##SYNTAX() Message##SYNTAX *subMessage = [[Message##SYNTAX alloc] init]; +//% XCTAssertNotNil(subMessage); +//% subMessage.optionalInt32 = 666; +//% +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Int32, 1) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Int64, 2) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Uint32, 3U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Uint64, 4U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sint32, 5) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sint64, 6) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Fixed32, 7U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Fixed64, 8U) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sfixed32, 9) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Sfixed64, 10) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Float, 11.0f) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Double, 12.0) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Bool, BOOL_NON_DEFAULT) +//%TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, String, @"foo", Objects) +//%TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, Bytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding], Objects) +//%GROUP_TEST##SYNTAX()TEST_ROUNDTRIP_ONEOF_ADV(Message##SYNTAX, Message, subMessage, Objects) +//%TEST_ROUNDTRIP_ONEOF(Message##SYNTAX, Enum, Message2_Enum_Bar) +//%GROUP_CLEANUP##SYNTAX() [subMessage release]; +//%} +//% +//%PDDM-DEFINE GROUP_INIT2() +//% Message2_OneofGroup *group = [[Message2_OneofGroup alloc] init]; +//% XCTAssertNotNil(group); +//% group.a = 777; +//% +//%PDDM-DEFINE GROUP_CLEANUP2() +//% [group release]; +//% +//%PDDM-DEFINE GROUP_TEST2() +//%TEST_ROUNDTRIP_ONEOF_ADV(Message2, Group, group, Objects) +//% +//%PDDM-DEFINE GROUP_INIT3() +// Empty +//%PDDM-DEFINE GROUP_CLEANUP3() +// Empty +//%PDDM-DEFINE GROUP_TEST3() +//% // Not "group" in proto3. +//% +//% +//%PDDM-EXPAND TEST_ROUNDTRIP_ONEOFS(2, NO) +// This block of code is generated, do not edit it directly. + +- (void)testProto2RoundTripOneof { + + Message2_OneofGroup *group = [[Message2_OneofGroup alloc] init]; + XCTAssertNotNil(group); + group.a = 777; + Message2 *subMessage = [[Message2 alloc] init]; + XCTAssertNotNil(subMessage); + subMessage.optionalInt32 = 666; + + { // oneofInt32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofInt32 = 1; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + [orig release]; + } + + { // oneofInt64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofInt64 = 2; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt64, 2); + [orig release]; + } + + { // oneofUint32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofUint32 = 3U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofUint32, 3U); + [orig release]; + } + + { // oneofUint64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofUint64 = 4U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofUint64, 4U); + [orig release]; + } + + { // oneofSint32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSint32 = 5; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofSint32, 5); + [orig release]; + } + + { // oneofSint64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSint64 = 6; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofSint64, 6); + [orig release]; + } + + { // oneofFixed32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofFixed32 = 7U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofFixed32, 7U); + [orig release]; + } + + { // oneofFixed64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofFixed64 = 8U; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofFixed64, 8U); + [orig release]; + } + + { // oneofSfixed32 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSfixed32 = 9; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofSfixed32, 9); + [orig release]; + } + + { // oneofSfixed64 + Message2 *orig = [[Message2 alloc] init]; + orig.oneofSfixed64 = 10; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofSfixed64, 10); + [orig release]; + } + + { // oneofFloat + Message2 *orig = [[Message2 alloc] init]; + orig.oneofFloat = 11.0f; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofFloat, 11.0f); + [orig release]; + } + + { // oneofDouble + Message2 *orig = [[Message2 alloc] init]; + orig.oneofDouble = 12.0; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofDouble, 12.0); + [orig release]; + } + + { // oneofBool + Message2 *orig = [[Message2 alloc] init]; + orig.oneofBool = NO; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBool); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofBool, NO); + [orig release]; + } + + { // oneofString + Message2 *orig = [[Message2 alloc] init]; + orig.oneofString = @"foo"; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofString); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofString); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + [orig release]; + } + + { // oneofBytes + Message2 *orig = [[Message2 alloc] init]; + orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + [orig release]; + } + + { // oneofGroup + Message2 *orig = [[Message2 alloc] init]; + orig.oneofGroup = group; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofGroup); + XCTAssertEqualObjects(msg.oneofGroup, group); + [orig release]; + } + + { // oneofMessage + Message2 *orig = [[Message2 alloc] init]; + orig.oneofMessage = subMessage; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofMessage); + XCTAssertEqualObjects(msg.oneofMessage, subMessage); + [orig release]; + } + + { // oneofEnum + Message2 *orig = [[Message2 alloc] init]; + orig.oneofEnum = Message2_Enum_Bar; + XCTAssertEqual(orig.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + Message2 *msg = [Message2 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); + [orig release]; + } + + [group release]; + [subMessage release]; +} + +//%PDDM-EXPAND TEST_ROUNDTRIP_ONEOFS(3, YES) +// This block of code is generated, do not edit it directly. + +- (void)testProto3RoundTripOneof { + + Message3 *subMessage = [[Message3 alloc] init]; + XCTAssertNotNil(subMessage); + subMessage.optionalInt32 = 666; + + { // oneofInt32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofInt32 = 1; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt32); + XCTAssertEqual(msg.oneofInt32, 1); + [orig release]; + } + + { // oneofInt64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofInt64 = 2; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofInt64); + XCTAssertEqual(msg.oneofInt64, 2); + [orig release]; + } + + { // oneofUint32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofUint32 = 3U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint32); + XCTAssertEqual(msg.oneofUint32, 3U); + [orig release]; + } + + { // oneofUint64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofUint64 = 4U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofUint64); + XCTAssertEqual(msg.oneofUint64, 4U); + [orig release]; + } + + { // oneofSint32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSint32 = 5; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint32); + XCTAssertEqual(msg.oneofSint32, 5); + [orig release]; + } + + { // oneofSint64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSint64 = 6; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSint64); + XCTAssertEqual(msg.oneofSint64, 6); + [orig release]; + } + + { // oneofFixed32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofFixed32 = 7U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed32); + XCTAssertEqual(msg.oneofFixed32, 7U); + [orig release]; + } + + { // oneofFixed64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofFixed64 = 8U; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFixed64); + XCTAssertEqual(msg.oneofFixed64, 8U); + [orig release]; + } + + { // oneofSfixed32 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSfixed32 = 9; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed32); + XCTAssertEqual(msg.oneofSfixed32, 9); + [orig release]; + } + + { // oneofSfixed64 + Message3 *orig = [[Message3 alloc] init]; + orig.oneofSfixed64 = 10; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofSfixed64); + XCTAssertEqual(msg.oneofSfixed64, 10); + [orig release]; + } + + { // oneofFloat + Message3 *orig = [[Message3 alloc] init]; + orig.oneofFloat = 11.0f; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofFloat); + XCTAssertEqual(msg.oneofFloat, 11.0f); + [orig release]; + } + + { // oneofDouble + Message3 *orig = [[Message3 alloc] init]; + orig.oneofDouble = 12.0; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofDouble); + XCTAssertEqual(msg.oneofDouble, 12.0); + [orig release]; + } + + { // oneofBool + Message3 *orig = [[Message3 alloc] init]; + orig.oneofBool = YES; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBool); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBool); + XCTAssertEqual(msg.oneofBool, YES); + [orig release]; + } + + { // oneofString + Message3 *orig = [[Message3 alloc] init]; + orig.oneofString = @"foo"; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofString); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofString); + XCTAssertEqualObjects(msg.oneofString, @"foo"); + [orig release]; + } + + { // oneofBytes + Message3 *orig = [[Message3 alloc] init]; + orig.oneofBytes = [@"bar" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofBytes); + XCTAssertEqualObjects(msg.oneofBytes, [@"bar" dataUsingEncoding:NSUTF8StringEncoding]); + [orig release]; + } + + // Not "group" in proto3. + + { // oneofMessage + Message3 *orig = [[Message3 alloc] init]; + orig.oneofMessage = subMessage; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofMessage); + XCTAssertEqualObjects(msg.oneofMessage, subMessage); + [orig release]; + } + + { // oneofEnum + Message3 *orig = [[Message3 alloc] init]; + orig.oneofEnum = Message2_Enum_Bar; + XCTAssertEqual(orig.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + Message3 *msg = [Message3 parseFromData:[orig data]]; + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase_OneofEnum); + XCTAssertEqual(msg.oneofEnum, Message2_Enum_Bar); + [orig release]; + } + + [subMessage release]; +} + +//%PDDM-EXPAND-END (2 expansions) + +#pragma mark - Subset from from map_tests.cc + +// TEST(GeneratedMapFieldTest, StandardWireFormat) +- (void)testMap_StandardWireFormat { + NSData *data = DataFromCStr("\x0A\x04\x08\x01\x10\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, UnorderedWireFormat) +- (void)testMap_UnorderedWireFormat { + // put value before key in wire format + NSData *data = DataFromCStr("\x0A\x04\x10\x01\x08\x02"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, DuplicatedKeyWireFormat) +- (void)testMap_DuplicatedKeyWireFormat { + // Two key fields in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x01\x08\x02\x10\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) +- (void)testMap_DuplicatedValueWireFormat { + // Two value fields in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x01\x10\x01\x10\x02"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]); + XCTAssertEqual(val, 2); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, MissedKeyWireFormat) +- (void)testMap_MissedKeyWireFormat { + // No key field in wire format + NSData *data = DataFromCStr("\x0A\x02\x10\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:0 value:&val]); + XCTAssertEqual(val, 1); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, MissedValueWireFormat) +- (void)testMap_MissedValueWireFormat { + // No value field in wire format + NSData *data = DataFromCStr("\x0A\x02\x08\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:1 value:&val]); + XCTAssertEqual(val, 0); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, UnknownFieldWireFormat) +- (void)testMap_UnknownFieldWireFormat { + // Unknown field in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x02\x10\x03\x18\x01"); + + TestMap *msg = [[TestMap alloc] initWithData:data]; + XCTAssertEqual(msg.mapInt32Int32.count, 1U); + int32_t val = 666; + XCTAssertTrue([msg.mapInt32Int32 valueForKey:2 value:&val]); + XCTAssertEqual(val, 3); + + [msg release]; +} + +// TEST(GeneratedMapFieldTest, CorruptedWireFormat) +- (void)testMap_CorruptedWireFormat { + // corrupted data in wire format + NSData *data = DataFromCStr("\x0A\x06\x08\x02\x11\x03"); + + XCTAssertThrowsSpecificNamed([TestMap parseFromData:data], NSException, + NSParseErrorException); +} + +// TEST(GeneratedMapFieldTest, Proto2UnknownEnum) +- (void)testMap_Proto2UnknownEnum { + TestEnumMapPlusExtra *orig = [[TestEnumMapPlusExtra alloc] init]; + + orig.knownMapField = [GPBInt32EnumDictionary + dictionaryWithValidationFunction:Proto2MapEnumPlusExtra_IsValidValue]; + orig.unknownMapField = [GPBInt32EnumDictionary + dictionaryWithValidationFunction:Proto2MapEnumPlusExtra_IsValidValue]; + [orig.knownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumFoo + forKey:0]; + [orig.unknownMapField setValue:Proto2MapEnumPlusExtra_EProto2MapEnumExtra + forKey:0]; + + TestEnumMap *msg1 = [TestEnumMap parseFromData:[orig data]]; + XCTAssertEqual(msg1.knownMapField.count, 1U); + int32_t val = -1; + XCTAssertTrue([msg1.knownMapField valueForKey:0 value:&val]); + XCTAssertEqual(val, Proto2MapEnum_Proto2MapEnumFoo); + XCTAssertEqual(msg1.unknownFields.countOfFields, 1U); + + TestEnumMapPlusExtra *msg2 = [TestEnumMapPlusExtra parseFromData:[msg1 data]]; + val = -1; + XCTAssertEqual(msg2.knownMapField.count, 1U); + XCTAssertTrue([msg2.knownMapField valueForKey:0 value:&val]); + XCTAssertEqual(val, Proto2MapEnumPlusExtra_EProto2MapEnumFoo); + val = -1; + XCTAssertEqual(msg2.unknownMapField.count, 1U); + XCTAssertTrue([msg2.unknownMapField valueForKey:0 value:&val]); + XCTAssertEqual(val, Proto2MapEnumPlusExtra_EProto2MapEnumExtra); + XCTAssertEqual(msg2.unknownFields.countOfFields, 0U); + + XCTAssertEqualObjects(orig, msg2); + + [orig release]; +} + +#pragma mark - + +@end diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m new file mode 100644 index 00000000..5ec67cd9 --- /dev/null +++ b/objectivec/Tests/GPBMessageTests.m @@ -0,0 +1,1728 @@ +// 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 "GPBTestUtilities.h" + +#import + +#import "GPBArray_PackagePrivate.h" +#import "GPBDescriptor.h" +#import "GPBField_PackagePrivate.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" +#import "google/protobuf/UnittestNameMangling.pbobjc.h" + +@interface MessageTests : GPBTestCase +@end + +@implementation MessageTests + +// TODO(thomasvl): this should get split into a few files of logic junks, it is +// a jumble +// of things at the moment (and the testutils have a bunch of the real +// assertions). + +#ifdef DEBUG +- (void)assertBlock:(void (^)())block + throwsWithMessageInUserInfo:(GPBMessage *)message { + @try { + block(); + XCTAssertTrue(NO); + } + @catch (NSException *e) { + XCTAssertEqualObjects([e userInfo][GPBExceptionMessageKey], message); + } +} +#endif // DEBUG + +- (TestAllTypes *)mergeSource { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt32:1]; + [message setOptionalString:@"foo"]; + [message setOptionalForeignMessage:[ForeignMessage message]]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"bar"]; + return message; +} + +- (TestAllTypes *)mergeDestination { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt64:2]; + [message setOptionalString:@"baz"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:3]; + [message setOptionalForeignMessage:foreignMessage]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + return message; +} + +- (TestAllTypes *)mergeDestinationWithoutForeignMessageIvar { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt64:2]; + [message setOptionalString:@"baz"]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + return message; +} + +- (TestAllTypes *)mergeResult { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt32:1]; + [message setOptionalInt64:2]; + [message setOptionalString:@"foo"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:3]; + [message setOptionalForeignMessage:foreignMessage]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + [message.repeatedStringArray addObject:@"bar"]; + return message; +} + +- (TestAllTypes *)mergeResultForDestinationWithoutForeignMessageIvar { + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt32:1]; + [message setOptionalInt64:2]; + [message setOptionalString:@"foo"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [message setOptionalForeignMessage:foreignMessage]; + message.repeatedStringArray = [NSMutableArray array]; + [message.repeatedStringArray addObject:@"qux"]; + [message.repeatedStringArray addObject:@"bar"]; + return message; +} + +- (TestAllExtensions *)mergeExtensionsDestination { + TestAllExtensions *message = [TestAllExtensions message]; + [message setExtension:[UnittestRoot optionalInt32Extension] value:@5]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"foo"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + foreignMessage.c = 4; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + return message; +} + +- (TestAllExtensions *)mergeExtensionsSource { + TestAllExtensions *message = [TestAllExtensions message]; + [message setExtension:[UnittestRoot optionalInt64Extension] value:@6]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + nestedMessage.bb = 7; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + return message; +} + +- (TestAllExtensions *)mergeExtensionsResult { + TestAllExtensions *message = [TestAllExtensions message]; + [message setExtension:[UnittestRoot optionalInt32Extension] value:@5]; + [message setExtension:[UnittestRoot optionalInt64Extension] value:@6]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + foreignMessage.c = 4; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + nestedMessage.bb = 7; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + return message; +} + +- (void)testMergeFrom { + TestAllTypes *result = [[self.mergeDestination copy] autorelease]; + [result mergeFrom:self.mergeSource]; + NSData *resultData = [result data]; + NSData *mergeResultData = [self.mergeResult data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, self.mergeResult); + + // Test when destination does not have an Ivar (type is an object) but source + // has such Ivar. + // The result must has the Ivar which is same as the one in source. + result = [[self.mergeDestinationWithoutForeignMessageIvar copy] autorelease]; + [result mergeFrom:self.mergeSource]; + resultData = [result data]; + mergeResultData = + [self.mergeResultForDestinationWithoutForeignMessageIvar data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects( + result, self.mergeResultForDestinationWithoutForeignMessageIvar); + + // Test when destination is empty. + // The result must is same as the source. + result = [TestAllTypes message]; + [result mergeFrom:self.mergeSource]; + resultData = [result data]; + mergeResultData = [self.mergeSource data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, self.mergeSource); +} + +- (void)testMergeFromWithExtensions { + TestAllExtensions *result = [self mergeExtensionsDestination]; + [result mergeFrom:[self mergeExtensionsSource]]; + NSData *resultData = [result data]; + NSData *mergeResultData = [[self mergeExtensionsResult] data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, [self mergeExtensionsResult]); + + // Test merging from data. + result = [self mergeExtensionsDestination]; + [result mergeFromData:[[self mergeExtensionsSource] data] + extensionRegistry:[UnittestRoot extensionRegistry]]; + resultData = [result data]; + XCTAssertEqualObjects(resultData, mergeResultData); + XCTAssertEqualObjects(result, [self mergeExtensionsResult]); +} + +- (void)testIsEquals { + TestAllTypes *result = [[self.mergeDestination copy] autorelease]; + [result mergeFrom:self.mergeSource]; + XCTAssertEqualObjects(result.data, self.mergeResult.data); + XCTAssertEqualObjects(result, self.mergeResult); + TestAllTypes *result2 = [[self.mergeDestination copy] autorelease]; + XCTAssertNotEqualObjects(result2.data, self.mergeResult.data); + XCTAssertNotEqualObjects(result2, self.mergeResult); +} + +// ================================================================= +// Required-field-related tests. + +- (TestRequired *)testRequiredInitialized { + TestRequired *message = [TestRequired message]; + [message setA:1]; + [message setB:2]; + [message setC:3]; + return message; +} + +- (void)testRequired { + TestRequired *message = [TestRequired message]; + + XCTAssertFalse(message.initialized); + [message setA:1]; + XCTAssertFalse(message.initialized); + [message setB:1]; + XCTAssertFalse(message.initialized); + [message setC:1]; + XCTAssertTrue(message.initialized); +} + +- (void)testRequiredForeign { + TestRequiredForeign *message = [TestRequiredForeign message]; + + XCTAssertTrue(message.initialized); + + [message setOptionalMessage:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message setOptionalMessage:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); + + message.repeatedMessageArray = [NSMutableArray array]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message.repeatedMessageArray removeAllObjects]; + [message.repeatedMessageArray addObject:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); +} + +- (void)testRequiredExtension { + TestAllExtensions *message = [TestAllExtensions message]; + + XCTAssertTrue(message.initialized); + + [message setExtension:[TestRequired single] value:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message setExtension:[TestRequired single] + value:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); + + [message addExtension:[TestRequired multi] value:[TestRequired message]]; + XCTAssertFalse(message.initialized); + + [message setExtension:[TestRequired multi] + index:0 + value:self.testRequiredInitialized]; + XCTAssertTrue(message.initialized); +} + +#ifdef DEBUG +- (void)testUninitializedException { + TestRequired *message = [TestRequired message]; + [self assertBlock:^{ + [message data]; + } throwsWithMessageInUserInfo:message]; +} +#endif // DEBUG + +- (void)testInitialized { + // We're mostly testing that no exception is thrown. + TestRequired *message = [TestRequired message]; + XCTAssertFalse(message.initialized); +} + +#ifdef DEBUG +- (void)testNestedUninitializedException { + TestRequiredForeign *message = [TestRequiredForeign message]; + [message setOptionalMessage:[TestRequired message]]; + message.repeatedMessageArray = [NSMutableArray array]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + [self assertBlock:^{ + [message data]; + } throwsWithMessageInUserInfo:message]; +} +#endif // DEBUG + +- (void)testNestedInitialized { + // We're mostly testing that no exception is thrown. + + TestRequiredForeign *message = [TestRequiredForeign message]; + [message setOptionalMessage:[TestRequired message]]; + message.repeatedMessageArray = [NSMutableArray array]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + [message.repeatedMessageArray addObject:[TestRequired message]]; + + XCTAssertFalse(message.initialized); +} + +#ifdef DEBUG +- (void)testParseUninitialized { + [self assertBlock:^{ + [TestRequired parseFromData:GPBEmptyNSData()]; + } throwsWithMessageInUserInfo:[TestRequired message]]; +} +#endif // DEBUG + +- (void)testCoding { + NSData *data = + [NSKeyedArchiver archivedDataWithRootObject:[self mergeResult]]; + id unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + + XCTAssertEqualObjects(unarchivedObject, [self mergeResult]); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(unarchivedObject, [self mergeResult]); +} + +- (void)testObjectReset { + // Tests a failure where clearing out defaults values caused an over release. + TestAllTypes *message = [TestAllTypes message]; + message.hasOptionalNestedMessage = NO; + [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]]; + message.hasOptionalNestedMessage = NO; + [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]]; + [message setOptionalNestedMessage:nil]; + message.hasOptionalNestedMessage = NO; +} + +- (void)testSettingHasToYes { + TestAllTypes *message = [TestAllTypes message]; + XCTAssertThrows([message setHasOptionalNestedMessage:YES]); +} + +- (void)testRoot { + XCTAssertNotNil([UnittestRoot extensionRegistry]); +} + +- (void)testGPBMessageSize { + // See the note in GPBMessage_PackagePrivate.h about why we want to keep the + // base instance size pointer size aligned. + size_t messageSize = class_getInstanceSize([GPBMessage class]); + XCTAssertEqual((messageSize % sizeof(void *)), (size_t)0, + @"Base size isn't pointer size aligned"); + + // Since we add storage ourselves (see +allocWithZone: in GPBMessage), confirm + // that the size of some generated classes is still the same as the base for + // that logic to work as desired. + size_t testMessageSize = class_getInstanceSize([TestAllTypes class]); + XCTAssertEqual(testMessageSize, messageSize); +} + +- (void)testInit { + TestAllTypes *message = [TestAllTypes message]; + [self assertClear:message]; +} + +- (void)testAccessors { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testKVC_ValueForKey { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsKVCMatch:message]; +} + +- (void)testKVC_SetValue_ForKey { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFieldsViaKVC:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsKVCMatch:message]; + [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllFieldsKVCMatch:message]; +} + +- (void)testDescription { + // No real test, just exercise code + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + + GPBUnknownFieldSet *unknownFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + GPBField *field = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field addVarint:2]; + [unknownFields addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:4]; + [unknownFields addField:field]; + + [message setUnknownFields:unknownFields]; + + NSString *description = [message description]; + XCTAssertGreaterThan([description length], 0U); + + GPBMessage *message2 = [TestAllExtensions message]; + [message2 setExtension:[UnittestRoot optionalInt32Extension] value:@1]; + + [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@2]; + + description = [message2 description]; + XCTAssertGreaterThan([description length], 0U); +} + +- (void)testSetter { + // Test to make sure that if we set a value that has a default value + // with the default, that the has is set, and the value gets put into the + // message correctly. + TestAllTypes *message = [TestAllTypes message]; + GPBDescriptor *descriptor = [[message class] descriptor]; + XCTAssertNotNil(descriptor); + GPBFieldDescriptor *fieldDescriptor = + [descriptor fieldWithName:@"defaultInt32"]; + XCTAssertNotNil(fieldDescriptor); + GPBValue defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultInt32:defaultValue.valueInt32]; + XCTAssertTrue(message.hasDefaultInt32); + XCTAssertEqual(message.defaultInt32, defaultValue.valueInt32); + + // Do the same thing with an object type. + message = [TestAllTypes message]; + fieldDescriptor = [descriptor fieldWithName:@"defaultString"]; + XCTAssertNotNil(fieldDescriptor); + defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultString:defaultValue.valueString]; + XCTAssertTrue(message.hasDefaultString); + XCTAssertEqualObjects(message.defaultString, defaultValue.valueString); + + // Test default string type. + message = [TestAllTypes message]; + XCTAssertEqualObjects(message.defaultString, @"hello"); + XCTAssertFalse(message.hasDefaultString); + fieldDescriptor = [descriptor fieldWithName:@"defaultString"]; + XCTAssertNotNil(fieldDescriptor); + defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultString:defaultValue.valueString]; + XCTAssertEqualObjects(message.defaultString, @"hello"); + XCTAssertTrue(message.hasDefaultString); + [message setDefaultString:nil]; + XCTAssertEqualObjects(message.defaultString, @"hello"); + XCTAssertFalse(message.hasDefaultString); + message.hasDefaultString = NO; + XCTAssertFalse(message.hasDefaultString); + XCTAssertEqualObjects(message.defaultString, @"hello"); + + // Test default bytes type. + NSData *defaultBytes = [@"world" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + XCTAssertFalse(message.hasDefaultString); + fieldDescriptor = [descriptor fieldWithName:@"defaultBytes"]; + XCTAssertNotNil(fieldDescriptor); + defaultValue = [fieldDescriptor defaultValue]; + [message setDefaultBytes:defaultValue.valueData]; + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + XCTAssertTrue(message.hasDefaultBytes); + [message setDefaultBytes:nil]; + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + XCTAssertFalse(message.hasDefaultBytes); + message.hasDefaultBytes = NO; + XCTAssertFalse(message.hasDefaultBytes); + XCTAssertEqualObjects(message.defaultBytes, defaultBytes); + + // Test optional string. + XCTAssertFalse(message.hasOptionalString); + XCTAssertEqualObjects(message.optionalString, @""); + XCTAssertFalse(message.hasOptionalString); + message.optionalString = nil; + XCTAssertFalse(message.hasOptionalString); + XCTAssertEqualObjects(message.optionalString, @""); + NSString *string = @"string"; + message.optionalString = string; + XCTAssertEqualObjects(message.optionalString, string); + XCTAssertTrue(message.hasOptionalString); + message.optionalString = nil; + XCTAssertFalse(message.hasOptionalString); + XCTAssertEqualObjects(message.optionalString, @""); + + // Test optional data. + XCTAssertFalse(message.hasOptionalBytes); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + XCTAssertFalse(message.hasOptionalBytes); + message.optionalBytes = nil; + XCTAssertFalse(message.hasOptionalBytes); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + NSData *data = [@"bytes" dataUsingEncoding:NSUTF8StringEncoding]; + message.optionalBytes = data; + XCTAssertEqualObjects(message.optionalBytes, data); + XCTAssertTrue(message.hasOptionalBytes); + message.optionalBytes = nil; + XCTAssertFalse(message.hasOptionalBytes); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + + // Test lazy message setting + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertNotNil(message.optionalLazyMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + message.hasOptionalLazyMessage = NO; + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertNotNil(message.optionalLazyMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + message.optionalLazyMessage = nil; + XCTAssertFalse(message.hasOptionalLazyMessage); + + // Test nested messages + XCTAssertFalse(message.hasOptionalLazyMessage); + message.optionalLazyMessage.bb = 1; + XCTAssertTrue(message.hasOptionalLazyMessage); + XCTAssertEqual(message.optionalLazyMessage.bb, 1); + XCTAssertNotNil(message.optionalLazyMessage); + message.optionalLazyMessage = nil; + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertEqual(message.optionalLazyMessage.bb, 0); + XCTAssertFalse(message.hasOptionalLazyMessage); + XCTAssertNotNil(message.optionalLazyMessage); + + // -testDefaultSubMessages tests the "defaulting" handling of fields + // containing messages. +} + +- (void)testRepeatedSetters { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedFields:message]; + [self assertRepeatedFieldsModified:message + repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testClear { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self clearAllFields:message]; + [self assertClear:message]; + TestAllTypes *message2 = [TestAllTypes message]; + XCTAssertEqualObjects(message, message2); +} + +- (void)testClearKVC { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount]; + [self clearAllFields:message]; + [self assertClear:message]; + [self assertClearKVC:message]; +} + +- (void)testClearExtension { + // clearExtension() is not actually used in TestUtil, so try it manually. + GPBMessage *message1 = [TestAllExtensions message]; + [message1 setExtension:[UnittestRoot optionalInt32Extension] value:@1]; + + XCTAssertTrue([message1 hasExtension:[UnittestRoot optionalInt32Extension]]); + [message1 clearExtension:[UnittestRoot optionalInt32Extension]]; + XCTAssertFalse([message1 hasExtension:[UnittestRoot optionalInt32Extension]]); + + GPBMessage *message2 = [TestAllExtensions message]; + [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@1]; + + XCTAssertEqual( + [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count], + (NSUInteger)1); + [message2 clearExtension:[UnittestRoot repeatedInt32Extension]]; + XCTAssertEqual( + [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count], + (NSUInteger)0); + + // Clearing an unset extension field shouldn't make the target message + // visible. + GPBMessage *message3 = [TestAllExtensions message]; + GPBMessage *extension_msg = + [message3 getExtension:[UnittestObjcRoot recursiveExtension]]; + XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]); + [extension_msg clearExtension:[UnittestRoot optionalInt32Extension]]; + XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]); +} + +- (void)testDefaultingSubMessages { + TestAllTypes *message = [TestAllTypes message]; + + // Initially they should all not have values. + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + XCTAssertFalse(message.hasOptionalPublicImportMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + + // They should auto create something when fetched. + + TestAllTypes_OptionalGroup *optionalGroup = [message.optionalGroup retain]; + TestAllTypes_NestedMessage *optionalNestedMessage = + [message.optionalNestedMessage retain]; + ForeignMessage *optionalForeignMessage = + [message.optionalForeignMessage retain]; + ImportMessage *optionalImportMessage = [message.optionalImportMessage retain]; + PublicImportMessage *optionalPublicImportMessage = + [message.optionalPublicImportMessage retain]; + TestAllTypes_NestedMessage *optionalLazyMessage = + [message.optionalLazyMessage retain]; + + XCTAssertNotNil(optionalGroup); + XCTAssertNotNil(optionalNestedMessage); + XCTAssertNotNil(optionalForeignMessage); + XCTAssertNotNil(optionalImportMessage); + XCTAssertNotNil(optionalPublicImportMessage); + XCTAssertNotNil(optionalLazyMessage); + + // Although they were created, they should not respond to hasValue until that + // submessage is mutated. + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + XCTAssertFalse(message.hasOptionalPublicImportMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + + // And they set that value back in to the message since the value created was + // mutable (so a second fetch should give the same object). + + XCTAssertEqual(message.optionalGroup, optionalGroup); + XCTAssertEqual(message.optionalNestedMessage, optionalNestedMessage); + XCTAssertEqual(message.optionalForeignMessage, optionalForeignMessage); + XCTAssertEqual(message.optionalImportMessage, optionalImportMessage); + XCTAssertEqual(message.optionalPublicImportMessage, + optionalPublicImportMessage); + XCTAssertEqual(message.optionalLazyMessage, optionalLazyMessage); + + // And the default objects for a second message should be distinct (again, + // since they are mutable, each needs their own copy). + + TestAllTypes *message2 = [TestAllTypes message]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message2.optionalGroup, optionalGroup); + XCTAssertNotEqual(message2.optionalNestedMessage, optionalNestedMessage); + XCTAssertNotEqual(message2.optionalForeignMessage, optionalForeignMessage); + XCTAssertNotEqual(message2.optionalImportMessage, optionalImportMessage); + XCTAssertNotEqual(message2.optionalPublicImportMessage, + optionalPublicImportMessage); + XCTAssertNotEqual(message2.optionalLazyMessage, optionalLazyMessage); + + // Setting the values to nil will clear the has flag, and on next access you + // get back new submessages. + + message.optionalGroup = nil; + message.optionalNestedMessage = nil; + message.optionalForeignMessage = nil; + message.optionalImportMessage = nil; + message.optionalPublicImportMessage = nil; + message.optionalLazyMessage = nil; + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + XCTAssertFalse(message.hasOptionalPublicImportMessage); + XCTAssertFalse(message.hasOptionalLazyMessage); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.optionalGroup, optionalGroup); + XCTAssertNotEqual(message.optionalNestedMessage, optionalNestedMessage); + XCTAssertNotEqual(message.optionalForeignMessage, optionalForeignMessage); + XCTAssertNotEqual(message.optionalImportMessage, optionalImportMessage); + XCTAssertNotEqual(message.optionalPublicImportMessage, + optionalPublicImportMessage); + XCTAssertNotEqual(message.optionalLazyMessage, optionalLazyMessage); + + [optionalGroup release]; + [optionalNestedMessage release]; + [optionalForeignMessage release]; + [optionalImportMessage release]; + [optionalPublicImportMessage release]; + [optionalLazyMessage release]; +} + +- (void)testMultiplePointersToAutocreatedMessage { + // Multiple objects pointing to the same autocreated message. + TestAllTypes *message = [TestAllTypes message]; + TestAllTypes *message2 = [TestAllTypes message]; + message2.optionalGroup = message.optionalGroup; + XCTAssertTrue([message2 hasOptionalGroup]); + XCTAssertFalse([message hasOptionalGroup]); + message2.optionalGroup.a = 42; + XCTAssertTrue([message hasOptionalGroup]); + XCTAssertTrue([message2 hasOptionalGroup]); +} + +- (void)testCopyWithAutocreatedMessage { + // Mutable copy should not copy autocreated messages. + TestAllTypes *message = [TestAllTypes message]; + message.optionalGroup.a = 42; + XCTAssertNotNil(message.optionalNestedMessage); + TestAllTypes *message2 = [[message copy] autorelease]; + XCTAssertTrue([message2 hasOptionalGroup]); + XCTAssertFalse([message2 hasOptionalNestedMessage]); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.optionalNestedMessage, + message2.optionalNestedMessage); +} + +- (void)testClearAutocreatedSubmessage { + // Call clear on an intermediate submessage should cause it to get recreated + // on the next call. + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *message_inner = [message.a.a.a retain]; + XCTAssertNotNil(message_inner); + XCTAssertTrue(GPBWasMessageAutocreatedBy(message_inner, message.a.a)); + [message.a.a clear]; + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a.a)); + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.a.a.a, message_inner); + [message_inner release]; +} + +- (void)testRetainAutocreatedSubmessage { + // Should be able to retain autocreated submessage while the creator is + // dealloced. + TestAllTypes *message = [TestAllTypes message]; + + ForeignMessage *subMessage; + @autoreleasepool { + TestAllTypes *message2 = [TestAllTypes message]; + subMessage = message2.optionalForeignMessage; // Autocreated + message.optionalForeignMessage = subMessage; + XCTAssertTrue(GPBWasMessageAutocreatedBy(message.optionalForeignMessage, + message2)); + } + + // Should be the same object, and should still be live. + XCTAssertEqual(message.optionalForeignMessage, subMessage); + XCTAssertNotNil([subMessage description]); +} + +- (void)testSetNilAutocreatedSubmessage { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *message_inner = [message.a.a retain]; + XCTAssertFalse([message hasA]); + XCTAssertFalse([message.a hasA]); + message.a.a = nil; + + // |message.a| has to be made visible, but |message.a.a| was set to nil so + // shouldn't be. + XCTAssertTrue([message hasA]); + XCTAssertFalse([message.a hasA]); + + // Setting submessage to nil should cause it to lose its creator. + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a)); + + // After setting to nil, getting it again should create a new autocreated + // message. + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(message.a.a, message_inner); + + [message_inner release]; +} + +- (void)testSetDoesntHaveAutocreatedSubmessage { + // Clearing submessage (set has == NO) should NOT cause it to lose its + // creator. + TestAllTypes *message = [TestAllTypes message]; + TestAllTypes_NestedMessage *nestedMessage = message.optionalNestedMessage; + XCTAssertFalse([message hasOptionalNestedMessage]); + [message setHasOptionalNestedMessage:NO]; + XCTAssertFalse([message hasOptionalNestedMessage]); + XCTAssertEqual(message.optionalNestedMessage, nestedMessage); +} + +- (void)testSetAutocreatedMessageBecomesVisible { + // Setting a value should cause the submessage to appear to its creator. + // Test this several levels deep. + TestRecursiveMessage *message = [TestRecursiveMessage message]; + message.a.a.a.a.i = 42; + XCTAssertTrue([message hasA]); + XCTAssertTrue([message.a hasA]); + XCTAssertTrue([message.a.a hasA]); + XCTAssertTrue([message.a.a.a hasA]); + XCTAssertFalse([message.a.a.a.a hasA]); + XCTAssertEqual(message.a.a.a.a.i, 42); +} + +- (void)testClearUnsetFieldOfAutocreatedMessage { + // Clearing an unset field should not cause the submessage to appear to its + // creator. + TestRecursiveMessage *message = [TestRecursiveMessage message]; + message.a.a.a.a.hasI = NO; + XCTAssertFalse([message hasA]); + XCTAssertFalse([message.a hasA]); + XCTAssertFalse([message.a.a hasA]); + XCTAssertFalse([message.a.a.a hasA]); +} + +- (void)testAutocreatedSubmessageAssignSkip { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *messageLevel1 = [message.a retain]; + TestRecursiveMessage *messageLevel2 = [message.a.a retain]; + TestRecursiveMessage *messageLevel3 = [message.a.a.a retain]; + TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain]; + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3)); + + // Test skipping over an autocreated submessage and ensure it gets unset. + message.a = message.a.a; + XCTAssertEqual(message.a, messageLevel2); + XCTAssertTrue([message hasA]); + XCTAssertEqual(message.a.a, messageLevel3); + XCTAssertFalse([message.a hasA]); + XCTAssertEqual(message.a.a.a, messageLevel4); + XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1, + message)); // Because it was orphaned. + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2)); + + [messageLevel1 release]; + [messageLevel2 release]; + [messageLevel3 release]; + [messageLevel4 release]; +} + +- (void)testAutocreatedSubmessageAssignLoop { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + TestRecursiveMessage *messageLevel1 = [message.a retain]; + TestRecursiveMessage *messageLevel2 = [message.a.a retain]; + TestRecursiveMessage *messageLevel3 = [message.a.a.a retain]; + TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain]; + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2)); + XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3)); + + // Test a property with a loop. You'd never do this but at least ensure the + // autocreated submessages behave sanely. + message.a.a = message.a; + XCTAssertTrue([message hasA]); + XCTAssertEqual(message.a, messageLevel1); + XCTAssertTrue([message.a hasA]); + XCTAssertEqual(message.a.a, messageLevel1); + XCTAssertTrue([message.a.a hasA]); + XCTAssertEqual(message.a.a.a, messageLevel1); + XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1, + message)); // Because it was assigned. + XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel2, + messageLevel1)); // Because it was orphaned. + XCTAssertFalse([messageLevel2 hasA]); + + // Break the retain loop. + message.a.a = nil; + XCTAssertTrue([message hasA]); + XCTAssertFalse([message.a hasA]); + + [messageLevel1 release]; + [messageLevel2 release]; + [messageLevel3 release]; + [messageLevel4 release]; +} + +- (void)testSetAutocreatedSubmessage { + // Setting autocreated submessage to another value should cause the old one to + // lose its creator. + TestAllTypes *message = [TestAllTypes message]; + TestAllTypes_NestedMessage *nestedMessage = + [message.optionalNestedMessage retain]; + + message.optionalNestedMessage = [TestAllTypes_NestedMessage message]; + XCTAssertTrue([message hasOptionalNestedMessage]); + XCTAssertTrue(message.optionalNestedMessage != nestedMessage); + XCTAssertFalse(GPBWasMessageAutocreatedBy(nestedMessage, message)); + + [nestedMessage release]; +} + +- (void)testAutocreatedUnknownFields { + // Doing anything with (except reading) unknown fields should cause the + // submessage to become visible. + TestAllTypes *message = [TestAllTypes message]; + XCTAssertNotNil(message.optionalNestedMessage); + XCTAssertFalse([message hasOptionalNestedMessage]); + XCTAssertNil(message.optionalNestedMessage.unknownFields); + XCTAssertFalse([message hasOptionalNestedMessage]); + + GPBUnknownFieldSet *unknownFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + message.optionalNestedMessage.unknownFields = unknownFields; + XCTAssertTrue([message hasOptionalNestedMessage]); + + message.optionalNestedMessage = nil; + XCTAssertFalse([message hasOptionalNestedMessage]); + [message.optionalNestedMessage setUnknownFields:unknownFields]; + XCTAssertTrue([message hasOptionalNestedMessage]); +} + +- (void)testSetAutocreatedSubmessageToSelf { + // Setting submessage to itself should cause it to become visible. + TestAllTypes *message = [TestAllTypes message]; + XCTAssertNotNil(message.optionalNestedMessage); + XCTAssertFalse([message hasOptionalNestedMessage]); + message.optionalNestedMessage = message.optionalNestedMessage; + XCTAssertTrue([message hasOptionalNestedMessage]); +} + +- (void)testAutocreatedSubmessageMemoryLeaks { + // Test for memory leaks with autocreated submessages. + TestRecursiveMessage *message; + TestRecursiveMessage *messageLevel1; + TestRecursiveMessage *messageLevel2; + TestRecursiveMessage *messageLevel3; + TestRecursiveMessage *messageLevel4; + @autoreleasepool { + message = [[TestRecursiveMessage alloc] init]; + messageLevel1 = [message.a retain]; + messageLevel2 = [message.a.a retain]; + messageLevel3 = [message.a.a.a retain]; + messageLevel4 = [message.a.a.a.a retain]; + message.a.i = 1; + } + + XCTAssertEqual(message.retainCount, (NSUInteger)1); + [message release]; + XCTAssertEqual(messageLevel1.retainCount, (NSUInteger)1); + [messageLevel1 release]; + XCTAssertEqual(messageLevel2.retainCount, (NSUInteger)1); + [messageLevel2 release]; + XCTAssertEqual(messageLevel3.retainCount, (NSUInteger)1); + [messageLevel3 release]; + XCTAssertEqual(messageLevel4.retainCount, (NSUInteger)1); + [messageLevel4 release]; +} + +- (void)testDefaultingArrays { + // Basic tests for default creation of arrays in a message. + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + TestRecursiveMessageWithRepeatedField *message2 = + [TestRecursiveMessageWithRepeatedField message]; + + // Simply accessing the array should not make any fields visible. + XCTAssertNotNil(message.a.a.iArray); + XCTAssertFalse([message hasA]); + XCTAssertFalse([message.a hasA]); + XCTAssertNotNil(message2.a.a.strArray); + XCTAssertFalse([message2 hasA]); + XCTAssertFalse([message2.a hasA]); + + // But adding an element to the array should. + [message.a.a.iArray addValue:42]; + XCTAssertTrue([message hasA]); + XCTAssertTrue([message.a hasA]); + XCTAssertEqual([message.a.a.iArray count], (NSUInteger)1); + [message2.a.a.strArray addObject:@"foo"]; + XCTAssertTrue([message2 hasA]); + XCTAssertTrue([message2.a hasA]); + XCTAssertEqual([message2.a.a.strArray count], (NSUInteger)1); +} + +- (void)testAutocreatedArrayShared { + // Multiple objects pointing to the same array. + TestRecursiveMessageWithRepeatedField *message1a = + [TestRecursiveMessageWithRepeatedField message]; + TestRecursiveMessageWithRepeatedField *message1b = + [TestRecursiveMessageWithRepeatedField message]; + message1a.a.iArray = message1b.a.iArray; + XCTAssertTrue([message1a hasA]); + XCTAssertFalse([message1b hasA]); + [message1a.a.iArray addValue:1]; + XCTAssertTrue([message1a hasA]); + XCTAssertTrue([message1b hasA]); + XCTAssertEqual(message1a.a.iArray, message1b.a.iArray); + + TestRecursiveMessageWithRepeatedField *message2a = + [TestRecursiveMessageWithRepeatedField message]; + TestRecursiveMessageWithRepeatedField *message2b = + [TestRecursiveMessageWithRepeatedField message]; + message2a.a.strArray = message2b.a.strArray; + XCTAssertTrue([message2a hasA]); + XCTAssertFalse([message2b hasA]); + [message2a.a.strArray addObject:@"bar"]; + XCTAssertTrue([message2a hasA]); + XCTAssertTrue([message2b hasA]); + XCTAssertEqual(message2a.a.strArray, message2b.a.strArray); +} + +- (void)testAutocreatedArrayCopy { + // Copy should not copy autocreated arrays. + TestAllTypes *message = [TestAllTypes message]; + XCTAssertNotNil(message.repeatedStringArray); + XCTAssertNotNil(message.repeatedInt32Array); + TestAllTypes *message2 = [[message copy] autorelease]; + // Pointer conparisions. + XCTAssertNotEqual(message.repeatedStringArray, message2.repeatedStringArray); + XCTAssertNotEqual(message.repeatedInt32Array, message2.repeatedInt32Array); + + // Mutable copy should copy empty arrays that were explicitly set (end up + // with different objects that are equal). + TestAllTypes *message3 = [TestAllTypes message]; + message3.repeatedInt32Array = [GPBInt32Array arrayWithValue:42]; + message3.repeatedStringArray = [NSMutableArray arrayWithObject:@"wee"]; + XCTAssertNotNil(message.repeatedInt32Array); + XCTAssertNotNil(message.repeatedStringArray); + TestAllTypes *message4 = [message3 copy]; + XCTAssertNotEqual(message3.repeatedInt32Array, message4.repeatedInt32Array); + XCTAssertEqualObjects(message3.repeatedInt32Array, + message4.repeatedInt32Array); + XCTAssertNotEqual(message3.repeatedStringArray, message4.repeatedStringArray); + XCTAssertEqualObjects(message3.repeatedStringArray, + message4.repeatedStringArray); +} + +- (void)testAutocreatedArrayRetain { + // Should be able to retain autocreated array while the creator is dealloced. + TestAllTypes *message = [TestAllTypes message]; + + @autoreleasepool { + TestAllTypes *message2 = [TestAllTypes message]; + message.repeatedInt32Array = message2.repeatedInt32Array; + message.repeatedStringArray = message2.repeatedStringArray; + // Pointer conparision + XCTAssertEqual(message.repeatedInt32Array->_autocreator, message2); + XCTAssertTrue([message.repeatedStringArray + isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual( + ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator, + message2); + } + + XCTAssertNil(message.repeatedInt32Array->_autocreator); + XCTAssertTrue( + [message.repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertNil( + ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator); +} + +- (void)testSetNilAutocreatedArray { + // Setting array to nil should cause it to lose its delegate. + TestAllTypes *message = [TestAllTypes message]; + GPBInt32Array *repeatedInt32Array = [message.repeatedInt32Array retain]; + GPBAutocreatedArray *repeatedStringArray = + (GPBAutocreatedArray *)[message.repeatedStringArray retain]; + XCTAssertTrue([repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(repeatedInt32Array->_autocreator, message); + XCTAssertEqual(repeatedStringArray->_autocreator, message); + message.repeatedInt32Array = nil; + message.repeatedStringArray = nil; + XCTAssertNil(repeatedInt32Array->_autocreator); + XCTAssertNil(repeatedStringArray->_autocreator); + [repeatedInt32Array release]; + [repeatedStringArray release]; +} + +- (void)testReplaceAutocreatedArray { + // Replacing array should orphan the old one and cause its creator to become + // visible. + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.iArray); + XCTAssertFalse([message hasA]); + GPBInt32Array *iArray = [message.a.iArray retain]; + XCTAssertEqual(iArray->_autocreator, message.a); // Pointer comparision + message.a.iArray = [GPBInt32Array arrayWithValue:1]; + XCTAssertTrue([message hasA]); + XCTAssertNotEqual(message.a.iArray, iArray); // Pointer comparision + XCTAssertNil(iArray->_autocreator); + [iArray release]; + } + + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.strArray); + XCTAssertFalse([message hasA]); + GPBAutocreatedArray *strArray = + (GPBAutocreatedArray *)[message.a.strArray retain]; + XCTAssertTrue([strArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(strArray->_autocreator, message.a); // Pointer comparision + message.a.strArray = [NSMutableArray arrayWithObject:@"foo"]; + XCTAssertTrue([message hasA]); + XCTAssertNotEqual(message.a.strArray, strArray); // Pointer comparision + XCTAssertNil(strArray->_autocreator); + [strArray release]; + } +} + +- (void)testSetAutocreatedArrayToSelf { + // Setting array to itself should cause it to become visible. + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.iArray); + XCTAssertFalse([message hasA]); + message.a.iArray = message.a.iArray; + XCTAssertTrue([message hasA]); + XCTAssertNil(message.a.iArray->_autocreator); + } + + { + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.strArray); + XCTAssertFalse([message hasA]); + message.a.strArray = message.a.strArray; + XCTAssertTrue([message hasA]); + XCTAssertTrue([message.a.strArray isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertNil(((GPBAutocreatedArray *)message.a.strArray)->_autocreator); + } +} + +- (void)testAutocreatedArrayRemoveAllValues { + // Calling removeAllValues on autocreated array should not cause it to be + // visible. + TestRecursiveMessageWithRepeatedField *message = + [TestRecursiveMessageWithRepeatedField message]; + [message.a.iArray removeAll]; + XCTAssertFalse([message hasA]); + [message.a.strArray removeAllObjects]; + XCTAssertFalse([message hasA]); +} + +- (void)testExtensionAccessors { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self assertAllExtensionsSet:message repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testExtensionRepeatedSetters { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message]; + [self assertRepeatedExtensionsModified:message + repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testExtensionDefaults { + [self assertExtensionsClear:[TestAllExtensions message]]; +} + +- (void)testExtensionIsEquals { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message]; + TestAllExtensions *message2 = [TestAllExtensions message]; + [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount]; + XCTAssertFalse([message isEqual:message2]); + message2 = [TestAllExtensions message]; + [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message2]; + XCTAssertEqualObjects(message, message2); +} + +- (void)testExtensionsMergeFrom { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + [self modifyRepeatedExtensions:message]; + + message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount]; + TestAllExtensions *message2 = [TestAllExtensions message]; + [self modifyRepeatedExtensions:message2]; + [message2 mergeFrom:message]; + + XCTAssertEqualObjects(message, message2); +} + +- (void)testDefaultingExtensionMessages { + TestAllExtensions *message = [TestAllExtensions message]; + + // Initially they should all not have values. + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + XCTAssertFalse([message + hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]); + + // They should auto create something when fetched. + + TestAllTypes_OptionalGroup *optionalGroup = + [message getExtension:[UnittestRoot optionalGroupExtension]]; + TestAllTypes_NestedMessage *optionalNestedMessage = + [message getExtension:[UnittestRoot optionalNestedMessageExtension]]; + ForeignMessage *optionalForeignMessage = + [message getExtension:[UnittestRoot optionalForeignMessageExtension]]; + ImportMessage *optionalImportMessage = + [message getExtension:[UnittestRoot optionalImportMessageExtension]]; + PublicImportMessage *optionalPublicImportMessage = [message + getExtension:[UnittestRoot optionalPublicImportMessageExtension]]; + TestAllTypes_NestedMessage *optionalLazyMessage = + [message getExtension:[UnittestRoot optionalLazyMessageExtension]]; + + XCTAssertNotNil(optionalGroup); + XCTAssertNotNil(optionalNestedMessage); + XCTAssertNotNil(optionalForeignMessage); + XCTAssertNotNil(optionalImportMessage); + XCTAssertNotNil(optionalPublicImportMessage); + XCTAssertNotNil(optionalLazyMessage); + + // Although it auto-created empty messages, it should not show that it has + // them. + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalLazyMessageExtension]]); + + // And they set that value back in to the message since the value created was + // mutable (so a second fetch should give the same object). + + XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]], + optionalGroup); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalNestedMessageExtension]], + optionalNestedMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalForeignMessageExtension]], + optionalForeignMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalImportMessageExtension]], + optionalImportMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalPublicImportMessageExtension]], + optionalPublicImportMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalLazyMessageExtension]], + optionalLazyMessage); + + // And the default objects for a second message should be distinct (again, + // since they are mutable, each needs their own copy). + + TestAllExtensions *message2 = [TestAllExtensions message]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalGroupExtension]], + optionalGroup); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalNestedMessageExtension]], + optionalNestedMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalForeignMessageExtension]], + optionalForeignMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalImportMessageExtension]], + optionalImportMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalPublicImportMessageExtension]], + optionalPublicImportMessage); + XCTAssertNotEqual( + [message2 getExtension:[UnittestRoot optionalLazyMessageExtension]], + optionalLazyMessage); + + // Clear values, and on next access you get back new submessages. + + [message setExtension:[UnittestRoot optionalGroupExtension] value:nil]; + [message setExtension:[UnittestRoot optionalGroupExtension] value:nil]; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalImportMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalPublicImportMessageExtension] + value:nil]; + [message setExtension:[UnittestRoot optionalLazyMessageExtension] value:nil]; + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + XCTAssertFalse([message + hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]); + XCTAssertFalse( + [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]); + + XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]], + optionalGroup); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalNestedMessageExtension]], + optionalNestedMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalForeignMessageExtension]], + optionalForeignMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalImportMessageExtension]], + optionalImportMessage); + XCTAssertEqual( + [message + getExtension:[UnittestRoot optionalPublicImportMessageExtension]], + optionalPublicImportMessage); + XCTAssertEqual( + [message getExtension:[UnittestRoot optionalLazyMessageExtension]], + optionalLazyMessage); +} + +- (void)testMultiplePointersToAutocreatedExtension { + // 2 objects point to the same auto-created extension. One should "has" it. + // The other should not. + TestAllExtensions *message = [TestAllExtensions message]; + TestAllExtensions *message2 = [TestAllExtensions message]; + GPBExtensionField *extension = [UnittestRoot optionalGroupExtension]; + [message setExtension:extension value:[message2 getExtension:extension]]; + XCTAssertEqual([message getExtension:extension], + [message2 getExtension:extension]); + XCTAssertFalse([message2 hasExtension:extension]); + XCTAssertTrue([message hasExtension:extension]); + + TestAllTypes_OptionalGroup *extensionValue = + [message2 getExtension:extension]; + extensionValue.a = 1; + XCTAssertTrue([message2 hasExtension:extension]); + XCTAssertTrue([message hasExtension:extension]); +} + +- (void)testCopyWithAutocreatedExtension { + // Mutable copy shouldn't copy autocreated extensions. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + GPBExtensionField *optionalNestedMessageExtesion = + [UnittestRoot optionalNestedMessageExtension]; + TestAllTypes_OptionalGroup *optionalGroup = + [message getExtension:optionalGroupExtension]; + optionalGroup.a = 42; + XCTAssertNotNil(optionalGroup); + XCTAssertNotNil([message getExtension:optionalNestedMessageExtesion]); + XCTAssertTrue([message hasExtension:optionalGroupExtension]); + XCTAssertFalse([message hasExtension:optionalNestedMessageExtesion]); + + TestAllExtensions *message2 = [[message copy] autorelease]; + + // message2 should end up with its own copy of the optional group. + XCTAssertTrue([message2 hasExtension:optionalGroupExtension]); + XCTAssertEqualObjects([message getExtension:optionalGroupExtension], + [message2 getExtension:optionalGroupExtension]); + // Intentionally doing a pointer comparison. + XCTAssertNotEqual([message getExtension:optionalGroupExtension], + [message2 getExtension:optionalGroupExtension]); + + XCTAssertFalse([message2 hasExtension:optionalNestedMessageExtesion]); + // Intentionally doing a pointer comparison (auto creation should be + // different) + XCTAssertNotEqual([message getExtension:optionalNestedMessageExtesion], + [message2 getExtension:optionalNestedMessageExtesion]); +} + +- (void)testClearMessageAutocreatedExtension { + // Call clear should cause it to recreate its autocreated extensions. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + TestAllTypes_OptionalGroup *optionalGroup = + [[message getExtension:optionalGroupExtension] retain]; + [message clear]; + TestAllTypes_OptionalGroup *optionalGroupNew = + [message getExtension:optionalGroupExtension]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(optionalGroup, optionalGroupNew); + [optionalGroup release]; +} + +- (void)testRetainAutocreatedExtension { + // Should be able to retain autocreated extension while the creator is + // dealloced. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + + @autoreleasepool { + TestAllExtensions *message2 = [TestAllExtensions message]; + [message setExtension:optionalGroupExtension + value:[message2 getExtension:optionalGroupExtension]]; + XCTAssertTrue(GPBWasMessageAutocreatedBy( + [message getExtension:optionalGroupExtension], message2)); + } + + XCTAssertFalse(GPBWasMessageAutocreatedBy( + [message getExtension:optionalGroupExtension], message)); +} + +- (void)testClearAutocreatedExtension { + // Clearing autocreated extension should NOT cause it to lose its creator. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + TestAllTypes_OptionalGroup *optionalGroup = + [[message getExtension:optionalGroupExtension] retain]; + [message clearExtension:optionalGroupExtension]; + TestAllTypes_OptionalGroup *optionalGroupNew = + [message getExtension:optionalGroupExtension]; + XCTAssertEqual(optionalGroup, optionalGroupNew); + XCTAssertFalse([message hasExtension:optionalGroupExtension]); + [optionalGroup release]; + + // Clearing autocreated extension should not cause its creator to become + // visible + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension]; + TestAllExtensions *message_lvl3 = + [message_lvl2 getExtension:recursiveExtension]; + [message_lvl3 clearExtension:recursiveExtension]; + XCTAssertFalse([message hasExtension:recursiveExtension]); +} + +- (void)testSetAutocreatedExtensionBecomesVisible { + // Setting an extension should cause the extension to appear to its creator. + // Test this several levels deep. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension]; + TestAllExtensions *message_lvl3 = + [message_lvl2 getExtension:recursiveExtension]; + TestAllExtensions *message_lvl4 = + [message_lvl3 getExtension:recursiveExtension]; + XCTAssertFalse([message hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl2 hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl3 hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]); + [message_lvl4 setExtension:[UnittestRoot optionalInt32Extension] value:@(1)]; + XCTAssertTrue([message hasExtension:recursiveExtension]); + XCTAssertTrue([message_lvl2 hasExtension:recursiveExtension]); + XCTAssertTrue([message_lvl3 hasExtension:recursiveExtension]); + XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]); + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl4, message_lvl3)); + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl3, message_lvl2)); + XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl2, message)); +} + +- (void)testSetAutocreatedExtensionToSelf { + // Setting extension to itself should cause it to become visible. + TestAllExtensions *message = [TestAllExtensions message]; + GPBExtensionField *optionalGroupExtension = + [UnittestRoot optionalGroupExtension]; + XCTAssertNotNil([message getExtension:optionalGroupExtension]); + XCTAssertFalse([message hasExtension:optionalGroupExtension]); + [message setExtension:optionalGroupExtension + value:[message getExtension:optionalGroupExtension]]; + XCTAssertTrue([message hasExtension:optionalGroupExtension]); +} + +- (void)testAutocreatedExtensionMemoryLeaks { + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + + // Test for memory leaks with autocreated extensions. + TestAllExtensions *message; + TestAllExtensions *message_lvl2; + TestAllExtensions *message_lvl3; + TestAllExtensions *message_lvl4; + @autoreleasepool { + message = [[TestAllExtensions alloc] init]; + message_lvl2 = [[message getExtension:recursiveExtension] retain]; + message_lvl3 = [[message_lvl2 getExtension:recursiveExtension] retain]; + message_lvl4 = [[message_lvl3 getExtension:recursiveExtension] retain]; + [message_lvl2 setExtension:[UnittestRoot optionalInt32Extension] + value:@(1)]; + } + + XCTAssertEqual(message.retainCount, (NSUInteger)1); + @autoreleasepool { + [message release]; + } + XCTAssertEqual(message_lvl2.retainCount, (NSUInteger)1); + @autoreleasepool { + [message_lvl2 release]; + } + XCTAssertEqual(message_lvl3.retainCount, (NSUInteger)1); + @autoreleasepool { + [message_lvl3 release]; + } + XCTAssertEqual(message_lvl4.retainCount, (NSUInteger)1); + [message_lvl4 release]; +} + +- (void)testSetExtensionWithAutocreatedValue { + GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension]; + + TestAllExtensions *message; + @autoreleasepool { + message = [[TestAllExtensions alloc] init]; + [message getExtension:recursiveExtension]; + } + + // This statements checks that the extension value isn't accidentally + // dealloced when removing it from the autocreated map. + [message setExtension:recursiveExtension + value:[message getExtension:recursiveExtension]]; + XCTAssertTrue([message hasExtension:recursiveExtension]); + [message release]; +} + +- (void)testRecursion { + TestRecursiveMessage *message = [TestRecursiveMessage message]; + XCTAssertNotNil(message.a); + XCTAssertNotNil(message.a.a); + XCTAssertEqual(message.a.a.i, 0); +} + +- (void)testGenerateAndParseUnknownMessage { + GPBUnknownFieldSet *unknowns = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknowns mergeVarintField:123 value:456]; + GPBMessage *message = [GPBMessage message]; + [message setUnknownFields:unknowns]; + NSData *data = [message data]; + GPBMessage *message2 = [GPBMessage parseFromData:data extensionRegistry:nil]; + XCTAssertEqualObjects(message, message2); +} + +- (void)testDelimitedWriteAndParseMultipleMessages { + GPBUnknownFieldSet *unknowns1 = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknowns1 mergeVarintField:123 value:456]; + GPBMessage *message1 = [GPBMessage message]; + [message1 setUnknownFields:unknowns1]; + + GPBUnknownFieldSet *unknowns2 = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknowns2 mergeVarintField:789 value:987]; + [unknowns2 mergeVarintField:654 value:321]; + GPBMessage *message2 = [GPBMessage message]; + [message2 setUnknownFields:unknowns2]; + + NSMutableData *delimitedData = [NSMutableData data]; + [delimitedData appendData:[message1 delimitedData]]; + [delimitedData appendData:[message2 delimitedData]]; + GPBCodedInputStream *input = + [GPBCodedInputStream streamWithData:delimitedData]; + GPBMessage *message3 = [GPBMessage parseDelimitedFromCodedInputStream:input + extensionRegistry:nil]; + GPBMessage *message4 = [GPBMessage parseDelimitedFromCodedInputStream:input + extensionRegistry:nil]; + XCTAssertEqualObjects(message1, message3); + XCTAssertEqualObjects(message2, message4); +} + +- (void)testDuplicateEnums { + XCTAssertEqual(TestEnumWithDupValue_Foo1, TestEnumWithDupValue_Foo2); +} + +- (void)testWeirdDefaults { + ObjcWeirdDefaults *message = [ObjcWeirdDefaults message]; + GPBDescriptor *descriptor = [[message class] descriptor]; + GPBFieldDescriptor *fieldDesc = [descriptor fieldWithName:@"foo"]; + XCTAssertNotNil(fieldDesc); + XCTAssertTrue(fieldDesc.hasDefaultValue); + XCTAssertFalse(message.hasFoo); + XCTAssertEqualObjects(message.foo, @""); + + fieldDesc = [descriptor fieldWithName:@"bar"]; + XCTAssertNotNil(fieldDesc); + XCTAssertTrue(fieldDesc.hasDefaultValue); + XCTAssertFalse(message.hasBar); + XCTAssertEqualObjects(message.bar, GPBEmptyNSData()); +} + +- (void)testEnumDescriptorFromExtensionDescriptor { + GPBExtensionField *extField = [UnittestRoot optionalForeignEnumExtension]; + GPBExtensionDescriptor *extDescriptor = extField.descriptor; + XCTAssertEqual(extDescriptor.type, GPBTypeEnum); + GPBEnumDescriptor *enumDescriptor = extDescriptor.enumDescriptor; + GPBEnumDescriptor *expectedDescriptor = ForeignEnum_EnumDescriptor(); + XCTAssertEqualObjects(enumDescriptor, expectedDescriptor); +} + +- (void)testEnumNaming { + // objectivec_helpers.cc has some interesting cases to deal with in + // EnumValueName/EnumValueShortName. Confirm that things generated as + // expected. + + // This block just has to compile to confirm we got the expected types/names. + // The *_IsValidValue() calls are just there to keep the projects warnings + // flags happy by providing use of the variables/values. + + Foo aFoo = Foo_SerializedSize; + Foo_IsValidValue(aFoo); + aFoo = Foo_Size; + Foo_IsValidValue(aFoo); + + Category_Enum aCat = Category_Enum_Red; + Category_Enum_IsValidValue(aCat); + + Time aTime = Time_Base; + Time_IsValidValue(aTime); + aTime = Time_SomethingElse; + Time_IsValidValue(aTime); + + // This block confirms the names in the decriptors is what we wanted. + + GPBEnumDescriptor *descriptor; + NSString *valueName; + + descriptor = Foo_EnumDescriptor(); + XCTAssertNotNil(descriptor); + XCTAssertEqualObjects(@"Foo", descriptor.name); + valueName = [descriptor enumNameForValue:Foo_SerializedSize]; + XCTAssertEqualObjects(@"Foo_SerializedSize", valueName); + valueName = [descriptor enumNameForValue:Foo_Size]; + XCTAssertEqualObjects(@"Foo_Size", valueName); + + descriptor = Category_Enum_EnumDescriptor(); + XCTAssertNotNil(descriptor); + XCTAssertEqualObjects(@"Category_Enum", descriptor.name); + valueName = [descriptor enumNameForValue:Category_Enum_Red]; + XCTAssertEqualObjects(@"Category_Enum_Red", valueName); + + descriptor = Time_EnumDescriptor(); + XCTAssertNotNil(descriptor); + XCTAssertEqualObjects(@"Time", descriptor.name); + valueName = [descriptor enumNameForValue:Time_Base]; + XCTAssertEqualObjects(@"Time_Base", valueName); + valueName = [descriptor enumNameForValue:Time_SomethingElse]; + XCTAssertEqualObjects(@"Time_SomethingElse", valueName); +} + +- (void)testNegativeEnums { + EnumTestMsg *msg = [EnumTestMsg message]; + + // Defaults + XCTAssertEqual(msg.foo, EnumTestMsg_MyEnum_Zero); + XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_One); + XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegOne); + // Bounce to wire and back. + EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:[msg data]]; + XCTAssertEqualObjects(msgPrime, msg); + XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero); + XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_One); + XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegOne); + + // Other values + msg.bar = EnumTestMsg_MyEnum_Two; + msg.baz = EnumTestMsg_MyEnum_NegTwo; + XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_Two); + XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegTwo); + // Bounce to wire and back. + msgPrime = [EnumTestMsg parseFromData:[msg data]]; + XCTAssertEqualObjects(msgPrime, msg); + XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero); + XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_Two); + XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegTwo); + + // Repeated field (shouldn't ever be an issue since developer has to use the + // right GPBArray methods themselves). + msg.mumbleArray = [GPBEnumArray + arrayWithValidationFunction:EnumTestMsg_MyEnum_IsValidValue]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Zero]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_One]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Two]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegOne]; + [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegTwo]; + XCTAssertEqual([msg.mumbleArray valueAtIndex:0], EnumTestMsg_MyEnum_Zero); + XCTAssertEqual([msg.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One); + XCTAssertEqual([msg.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two); + XCTAssertEqual([msg.mumbleArray valueAtIndex:3], EnumTestMsg_MyEnum_NegOne); + XCTAssertEqual([msg.mumbleArray valueAtIndex:4], EnumTestMsg_MyEnum_NegTwo); + // Bounce to wire and back. + msgPrime = [EnumTestMsg parseFromData:[msg data]]; + XCTAssertEqualObjects(msgPrime, msg); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:0], + EnumTestMsg_MyEnum_Zero); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:3], + EnumTestMsg_MyEnum_NegOne); + XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:4], + EnumTestMsg_MyEnum_NegTwo); +} + +- (void)testMutableNameManagling { + // These basically confirm that all the expected name mangling happened by not + // having compile errors. + + // TODO(thomasvl): Write these, see unittest_name_mangling.proto. +} + +@end diff --git a/objectivec/Tests/GPBPerfTests.m b/objectivec/Tests/GPBPerfTests.m new file mode 100644 index 00000000..d09021af --- /dev/null +++ b/objectivec/Tests/GPBPerfTests.m @@ -0,0 +1,306 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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 "GPBTestUtilities.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" + +// +// This file really just uses the unittests framework as a testbed to +// run some simple performance tests. The data can then be used to help +// evaluate changes to the runtime. +// + +static const uint32_t kRepeatedCount = 100; + +@interface PerfTests : GPBTestCase +@end + +@implementation PerfTests + +- (void)setUp { + // A convenient place to put a break point if you want to connect instruments. + [super setUp]; +} + +- (void)testMessagePerformance { + [self measureBlock:^{ + for (int i = 0; i < 200; ++i) { + TestAllTypes* message = [[TestAllTypes alloc] init]; + [self setAllFields:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + message = [[TestAllTypes alloc] initWithData:rawBytes]; + [message release]; + } + }]; +} + +- (void)testExtensionsPerformance { + [self measureBlock:^{ + for (int i = 0; i < 200; ++i) { + TestAllExtensions* message = [[TestAllExtensions alloc] init]; + [self setAllExtensions:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + TestAllExtensions* message2 = + [[TestAllExtensions alloc] initWithData:rawBytes]; + [message2 release]; + } + }]; +} + +- (void)testPackedTypesPerformance { + [self measureBlock:^{ + for (int i = 0; i < 1000; ++i) { + TestPackedTypes* message = [[TestPackedTypes alloc] init]; + [self setPackedFields:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + message = [[TestPackedTypes alloc] initWithData:rawBytes]; + [message release]; + } + }]; +} + +- (void)testPackedExtensionsPerformance { + [self measureBlock:^{ + for (int i = 0; i < 1000; ++i) { + TestPackedExtensions* message = [[TestPackedExtensions alloc] init]; + [self setPackedExtensions:message repeatedCount:kRepeatedCount]; + NSData* rawBytes = [message data]; + [message release]; + TestPackedExtensions* message2 = + [[TestPackedExtensions alloc] initWithData:rawBytes]; + [message2 release]; + } + }]; +} + +- (void)testHas { + TestAllTypes* message = [self allSetRepeatedCount:1]; + [self measureBlock:^{ + for (int i = 0; i < 10000; ++i) { + [message hasOptionalInt32]; + message.hasOptionalInt32 = NO; + [message hasOptionalInt32]; + + [message hasOptionalInt64]; + message.hasOptionalInt64 = NO; + [message hasOptionalInt64]; + + [message hasOptionalUint32]; + message.hasOptionalUint32 = NO; + [message hasOptionalUint32]; + + [message hasOptionalUint64]; + message.hasOptionalUint64 = NO; + [message hasOptionalUint64]; + + [message hasOptionalSint32]; + message.hasOptionalSint32 = NO; + [message hasOptionalSint32]; + + [message hasOptionalSint64]; + message.hasOptionalSint64 = NO; + [message hasOptionalSint64]; + + [message hasOptionalFixed32]; + message.hasOptionalFixed32 = NO; + [message hasOptionalFixed32]; + + [message hasOptionalFixed64]; + message.hasOptionalFixed64 = NO; + [message hasOptionalFixed64]; + + [message hasOptionalSfixed32]; + message.hasOptionalSfixed32 = NO; + [message hasOptionalSfixed32]; + + [message hasOptionalSfixed64]; + message.hasOptionalSfixed64 = NO; + [message hasOptionalSfixed64]; + + [message hasOptionalFloat]; + message.hasOptionalFloat = NO; + [message hasOptionalFloat]; + + [message hasOptionalDouble]; + message.hasOptionalDouble = NO; + [message hasOptionalDouble]; + + [message hasOptionalBool]; + message.hasOptionalBool = NO; + [message hasOptionalBool]; + + [message hasOptionalString]; + message.hasOptionalString = NO; + [message hasOptionalString]; + + [message hasOptionalBytes]; + message.hasOptionalBytes = NO; + [message hasOptionalBytes]; + + [message hasOptionalGroup]; + message.hasOptionalGroup = NO; + [message hasOptionalGroup]; + + [message hasOptionalNestedMessage]; + message.hasOptionalNestedMessage = NO; + [message hasOptionalNestedMessage]; + + [message hasOptionalForeignMessage]; + message.hasOptionalForeignMessage = NO; + [message hasOptionalForeignMessage]; + + [message hasOptionalImportMessage]; + message.hasOptionalImportMessage = NO; + [message hasOptionalImportMessage]; + + [message.optionalGroup hasA]; + message.optionalGroup.hasA = NO; + [message.optionalGroup hasA]; + + [message.optionalNestedMessage hasBb]; + message.optionalNestedMessage.hasBb = NO; + [message.optionalNestedMessage hasBb]; + + [message.optionalForeignMessage hasC]; + message.optionalForeignMessage.hasC = NO; + [message.optionalForeignMessage hasC]; + + [message.optionalImportMessage hasD]; + message.optionalImportMessage.hasD = NO; + [message.optionalImportMessage hasD]; + + [message hasOptionalNestedEnum]; + message.hasOptionalNestedEnum = NO; + [message hasOptionalNestedEnum]; + + [message hasOptionalForeignEnum]; + message.hasOptionalForeignEnum = NO; + [message hasOptionalForeignEnum]; + + [message hasOptionalImportEnum]; + message.hasOptionalImportEnum = NO; + [message hasOptionalImportEnum]; + + [message hasOptionalStringPiece]; + message.hasOptionalStringPiece = NO; + [message hasOptionalStringPiece]; + + [message hasOptionalCord]; + message.hasOptionalCord = NO; + [message hasOptionalCord]; + + [message hasDefaultInt32]; + message.hasDefaultInt32 = NO; + [message hasDefaultInt32]; + + [message hasDefaultInt64]; + message.hasDefaultInt64 = NO; + [message hasDefaultInt64]; + + [message hasDefaultUint32]; + message.hasDefaultUint32 = NO; + [message hasDefaultUint32]; + + [message hasDefaultUint64]; + message.hasDefaultUint64 = NO; + [message hasDefaultUint64]; + + [message hasDefaultSint32]; + message.hasDefaultSint32 = NO; + [message hasDefaultSint32]; + + [message hasDefaultSint64]; + message.hasDefaultSint64 = NO; + [message hasDefaultSint64]; + + [message hasDefaultFixed32]; + message.hasDefaultFixed32 = NO; + [message hasDefaultFixed32]; + + [message hasDefaultFixed64]; + message.hasDefaultFixed64 = NO; + [message hasDefaultFixed64]; + + [message hasDefaultSfixed32]; + message.hasDefaultSfixed32 = NO; + [message hasDefaultSfixed32]; + + [message hasDefaultSfixed64]; + message.hasDefaultSfixed64 = NO; + [message hasDefaultSfixed64]; + + [message hasDefaultFloat]; + message.hasDefaultFloat = NO; + [message hasDefaultFloat]; + + [message hasDefaultDouble]; + message.hasDefaultDouble = NO; + [message hasDefaultDouble]; + + [message hasDefaultBool]; + message.hasDefaultBool = NO; + [message hasDefaultBool]; + + [message hasDefaultString]; + message.hasDefaultString = NO; + [message hasDefaultString]; + + [message hasDefaultBytes]; + message.hasDefaultBytes = NO; + [message hasDefaultBytes]; + + [message hasDefaultNestedEnum]; + message.hasDefaultNestedEnum = NO; + [message hasDefaultNestedEnum]; + + [message hasDefaultForeignEnum]; + message.hasDefaultForeignEnum = NO; + [message hasDefaultForeignEnum]; + + [message hasDefaultImportEnum]; + message.hasDefaultImportEnum = NO; + [message hasDefaultImportEnum]; + + [message hasDefaultStringPiece]; + message.hasDefaultStringPiece = NO; + [message hasDefaultStringPiece]; + + [message hasDefaultCord]; + message.hasDefaultCord = NO; + [message hasDefaultCord]; + } + }]; +} + +@end 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 + +#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! !Merhaba + "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 diff --git a/objectivec/Tests/GPBSwiftTests.swift b/objectivec/Tests/GPBSwiftTests.swift new file mode 100644 index 00000000..e7b6f94c --- /dev/null +++ b/objectivec/Tests/GPBSwiftTests.swift @@ -0,0 +1,405 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 Foundation +import XCTest + +// Test some usage of the ObjC library from Swift. + +class GPBBridgeTests: XCTestCase { + + func testProto2Basics() { + let msg = Message2() + let msg2 = Message2() + let msg3 = Message2_OptionalGroup() + + msg.optionalInt32 = 100 + msg.optionalString = "abc" + msg.optionalEnum = .Bar + msg2.optionalString = "other" + msg.optionalMessage = msg2 + msg3.a = 200 + msg.optionalGroup = msg3 + msg.repeatedInt32Array.addValue(300) + msg.repeatedInt32Array.addValue(301) + msg.repeatedStringArray.addObject("mno") + msg.repeatedStringArray.addObject("pqr") + msg.repeatedEnumArray.addValue(Message2_Enum.Bar.rawValue) + msg.repeatedEnumArray.addValue(Message2_Enum.Baz.rawValue) + + // Check has*. + XCTAssertTrue(msg.hasOptionalInt32) + XCTAssertTrue(msg.hasOptionalString) + XCTAssertTrue(msg.hasOptionalEnum) + XCTAssertTrue(msg2.hasOptionalString) + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertTrue(msg3.hasA) + XCTAssertTrue(msg.hasOptionalGroup) + XCTAssertFalse(msg.hasOptionalInt64) + XCTAssertFalse(msg.hasOptionalFloat) + + // Check values. + XCTAssertEqual(msg.optionalInt32, Int32(100)) + XCTAssertEqual(msg.optionalString, "abc") + XCTAssertEqual(msg2.optionalString, "other") + XCTAssertTrue(msg.optionalMessage === msg2) + XCTAssertEqual(msg.optionalEnum, Message2_Enum.Bar) + XCTAssertEqual(msg3.a, Int32(200)) + XCTAssertTrue(msg.optionalGroup === msg3) + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(2)) + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as! String, "mno") + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as! String, "pqr") + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2)) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message2_Enum.Bar.rawValue) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message2_Enum.Baz.rawValue) + XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0)) + + // Clearing a string with nil. + msg2.optionalString = nil + XCTAssertFalse(msg2.hasOptionalString) + XCTAssertEqual(msg2.optionalString, "") + + // Clearing a message with nil. + msg.optionalGroup = nil + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertTrue(msg.optionalGroup !== msg3) // New instance + + // Clear. + msg.clear() + XCTAssertFalse(msg.hasOptionalInt32) + XCTAssertFalse(msg.hasOptionalString) + XCTAssertFalse(msg.hasOptionalEnum) + XCTAssertFalse(msg.hasOptionalMessage) + XCTAssertFalse(msg.hasOptionalInt64) + XCTAssertFalse(msg.hasOptionalFloat) + XCTAssertEqual(msg.optionalInt32, Int32(0)) + XCTAssertEqual(msg.optionalString, "") + XCTAssertTrue(msg.optionalMessage !== msg2) // New instance + XCTAssertEqual(msg.optionalEnum, Message2_Enum.Foo) // Default + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(0)) + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0)) + } + + func testProto3Basics() { + let msg = Message3() + let msg2 = Message3() + + msg.optionalInt32 = 100 + msg.optionalString = "abc" + msg.optionalEnum = .Bar + msg2.optionalString = "other" + msg.optionalMessage = msg2 + msg.repeatedInt32Array.addValue(300) + msg.repeatedInt32Array.addValue(301) + msg.repeatedStringArray.addObject("mno") + msg.repeatedStringArray.addObject("pqr") + // "proto3" syntax lets enum get unknown values. + msg.repeatedEnumArray.addValue(Message3_Enum.Bar.rawValue) + msg.repeatedEnumArray.addRawValue(666) + SetMessage3_OptionalEnum_RawValue(msg2, 666) + + // Has only exists on for message fields. + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertFalse(msg2.hasOptionalMessage) + + // Check values. + XCTAssertEqual(msg.optionalInt32, Int32(100)) + XCTAssertEqual(msg.optionalString, "abc") + XCTAssertEqual(msg2.optionalString, "other") + XCTAssertTrue(msg.optionalMessage === msg2) + XCTAssertEqual(msg.optionalEnum, Message3_Enum.Bar) + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(2)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(0), Int32(300)) + XCTAssertEqual(msg.repeatedInt32Array.valueAtIndex(1), Int32(301)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(2)) + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(0) as! String, "mno") + XCTAssertEqual(msg.repeatedStringArray.objectAtIndex(1) as! String, "pqr") + XCTAssertEqual(msg.repeatedInt64Array.count, UInt(0)) + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(2)) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(0), Message3_Enum.Bar.rawValue) + XCTAssertEqual(msg.repeatedEnumArray.valueAtIndex(1), Message3_Enum.GPBUnrecognizedEnumeratorValue.rawValue) + XCTAssertEqual(msg.repeatedEnumArray.rawValueAtIndex(1), 666) + XCTAssertEqual(msg2.optionalEnum, Message3_Enum.GPBUnrecognizedEnumeratorValue) + XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Int32(666)) + + // Clearing a string with nil. + msg2.optionalString = nil + XCTAssertEqual(msg2.optionalString, "") + + // Clearing a message with nil. + msg.optionalMessage = nil + XCTAssertFalse(msg.hasOptionalMessage) + XCTAssertTrue(msg.optionalMessage !== msg2) // New instance + + // Clear. + msg.clear() + XCTAssertFalse(msg.hasOptionalMessage) + XCTAssertEqual(msg.optionalInt32, Int32(0)) + XCTAssertEqual(msg.optionalString, "") + XCTAssertTrue(msg.optionalMessage !== msg2) // New instance + XCTAssertEqual(msg.optionalEnum, Message3_Enum.Foo) // Default + XCTAssertEqual(msg.repeatedInt32Array.count, UInt(0)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(0)) + XCTAssertEqual(msg.repeatedEnumArray.count, UInt(0)) + msg2.clear() + XCTAssertEqual(msg2.optionalEnum, Message3_Enum.Foo) // Default + XCTAssertEqual(Message3_OptionalEnum_RawValue(msg2), Message3_Enum.Foo.rawValue) + } + + func testAutoCreation() { + let msg = Message2() + + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertFalse(msg.hasOptionalMessage) + + // Access shouldn't result in has* but should return objects. + let msg2 = msg.optionalGroup + let msg3 = msg.optionalMessage.optionalMessage + let msg4 = msg.optionalMessage + XCTAssertNotNil(msg2) + XCTAssertNotNil(msg3) + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertFalse(msg.optionalMessage.hasOptionalMessage) + XCTAssertFalse(msg.hasOptionalMessage) + + // Setting things should trigger has* getting set. + msg.optionalGroup.a = 10 + msg.optionalMessage.optionalMessage.optionalInt32 = 100 + XCTAssertTrue(msg.hasOptionalGroup) + XCTAssertTrue(msg.optionalMessage.hasOptionalMessage) + XCTAssertTrue(msg.hasOptionalMessage) + + // And they should be the same pointer as before. + XCTAssertTrue(msg2 === msg.optionalGroup) + XCTAssertTrue(msg3 === msg.optionalMessage.optionalMessage) + XCTAssertTrue(msg4 === msg.optionalMessage) + + // Clear gets us new objects next time around. + msg.clear() + XCTAssertFalse(msg.hasOptionalGroup) + XCTAssertFalse(msg.optionalMessage.hasOptionalMessage) + XCTAssertFalse(msg.hasOptionalMessage) + msg.optionalGroup.a = 20 + msg.optionalMessage.optionalMessage.optionalInt32 = 200 + XCTAssertTrue(msg.hasOptionalGroup) + XCTAssertTrue(msg.optionalMessage.hasOptionalMessage) + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertTrue(msg2 !== msg.optionalGroup) + XCTAssertTrue(msg3 !== msg.optionalMessage.optionalMessage) + XCTAssertTrue(msg4 !== msg.optionalMessage) + + // Explicit set of a message, means autocreated object doesn't bind. + msg.clear() + let autoCreated = msg.optionalMessage + XCTAssertFalse(msg.hasOptionalMessage) + let msg5 = Message2() + msg5.optionalInt32 = 123 + msg.optionalMessage = msg5 + XCTAssertTrue(msg.hasOptionalMessage) + // Modifing the autocreated doesn't replaced the explicit set one. + autoCreated.optionalInt32 = 456 + XCTAssertTrue(msg.hasOptionalMessage) + XCTAssertTrue(msg.optionalMessage === msg5) + XCTAssertEqual(msg.optionalMessage.optionalInt32, Int32(123)) + } + + func testProto2OneOfSupport() { + let msg = Message2() + + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + let autoCreated = msg.oneofMessage // Default create one. + XCTAssertNotNil(autoCreated) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32) + + msg.oneofFloat = 20.0 + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(20.0)) + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofFloat) + + msg.oneofEnum = .Bar + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Bar) + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofEnum) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 200 + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200)) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage) + + // Clear the oneof. + Message2_ClearOOneOfCase(msg) + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oneofFloat, Float(110.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message2_Enum.Baz) // Default + let autoCreated2 = msg.oneofMessage // Default create one + XCTAssertNotNil(autoCreated2) + XCTAssertTrue(autoCreated2 !== autoCreated) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofInt32) + + // Confirm Message.clear() handles the oneof correctly. + msg.clear() + XCTAssertEqual(msg.oneofInt32, Int32(100)) // Default + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 300 + XCTAssertTrue(msg.oneofMessage !== autoCreated) // New instance + XCTAssertTrue(msg.oneofMessage !== autoCreated2) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300)) + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.OneofMessage) + + // Set message to nil clears the oneof. + msg.oneofMessage = nil + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message2_O_OneOfCase.GPBUnsetOneOfCase) +} + + func testProto3OneOfSupport() { + let msg = Message3() + + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + let autoCreated = msg.oneofMessage // Default create one. + XCTAssertNotNil(autoCreated) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32) + + msg.oneofFloat = 20.0 + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(20.0)) + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofFloat) + + msg.oneofEnum = .Bar + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Bar) + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofEnum) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 200 + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + XCTAssertTrue(msg.oneofMessage === autoCreated) // Still the same + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(200)) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage) + + // Clear the oneof. + Message3_ClearOOneOfCase(msg) + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oneofFloat, Float(0.0)) // Default + XCTAssertEqual(msg.oneofEnum, Message3_Enum.Foo) // Default + let autoCreated2 = msg.oneofMessage // Default create one + XCTAssertNotNil(autoCreated2) + XCTAssertTrue(autoCreated2 !== autoCreated) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + + msg.oneofInt32 = 10 + XCTAssertEqual(msg.oneofInt32, Int32(10)) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofInt32) + + // Confirm Message.clear() handles the oneof correctly. + msg.clear() + XCTAssertEqual(msg.oneofInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + + // Sets via the autocreated instance. + msg.oneofMessage.optionalInt32 = 300 + XCTAssertTrue(msg.oneofMessage !== autoCreated) // New instance + XCTAssertTrue(msg.oneofMessage !== autoCreated2) // New instance + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(300)) + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.OneofMessage) + + // Set message to nil clears the oneof. + msg.oneofMessage = nil + XCTAssertEqual(msg.oneofMessage.optionalInt32, Int32(0)) // Default + XCTAssertEqual(msg.oOneOfCase, Message3_O_OneOfCase.GPBUnsetOneOfCase) + } + + func testSerialization() { + let msg = Message2() + + msg.optionalInt32 = 100 + msg.optionalInt64 = 101 + msg.optionalGroup.a = 102 + msg.repeatedStringArray.addObject("abc") + msg.repeatedStringArray.addObject("def") + + let data = msg.data() + + let msg2 = Message2(data: data) + XCTAssertTrue(msg2 !== msg) // New instance + XCTAssertEqual(msg.optionalInt32, Int32(100)) + XCTAssertEqual(msg.optionalInt64, Int64(101)) + XCTAssertEqual(msg.optionalGroup.a, Int32(102)) + XCTAssertEqual(msg.repeatedStringArray.count, Int(2)) + XCTAssertEqual(msg2, msg) + } + +} diff --git a/objectivec/Tests/GPBTestUtilities.h b/objectivec/Tests/GPBTestUtilities.h new file mode 100644 index 00000000..37e30f96 --- /dev/null +++ b/objectivec/Tests/GPBTestUtilities.h @@ -0,0 +1,87 @@ +// 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 + +@class TestAllExtensions; +@class TestAllTypes; +@class TestMap; +@class TestPackedTypes; +@class TestPackedExtensions; +@class GPBExtensionRegistry; + +// The number of repetitions of any repeated objects inside of test messages. +extern const uint32_t kGPBDefaultRepeatCount; + +@interface GPBTestCase : XCTestCase + +- (void)setAllFields:(TestAllTypes *)message repeatedCount:(uint32_t)count; +- (void)clearAllFields:(TestAllTypes *)message; +- (void)setAllExtensions:(TestAllExtensions *)message + repeatedCount:(uint32_t)count; +- (void)setPackedFields:(TestPackedTypes *)message + repeatedCount:(uint32_t)count; +- (void)setPackedExtensions:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count; +- (void)setAllMapFields:(TestMap *)message numEntries:(uint32_t)count; + +- (TestAllTypes *)allSetRepeatedCount:(uint32_t)count; +- (TestAllExtensions *)allExtensionsSetRepeatedCount:(uint32_t)count; +- (TestPackedTypes *)packedSetRepeatedCount:(uint32_t)count; +- (TestPackedExtensions *)packedExtensionsSetRepeatedCount:(uint32_t)count; + +- (void)assertAllFieldsSet:(TestAllTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertAllExtensionsSet:(TestAllExtensions *)message + repeatedCount:(uint32_t)count; +- (void)assertRepeatedFieldsModified:(TestAllTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertRepeatedExtensionsModified:(TestAllExtensions *)message + repeatedCount:(uint32_t)count; +- (void)assertExtensionsClear:(TestAllExtensions *)message; +- (void)assertClear:(TestAllTypes *)message; +- (void)assertPackedFieldsSet:(TestPackedTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertPackedExtensionsSet:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count; + +- (void)modifyRepeatedExtensions:(TestAllExtensions *)message; +- (void)modifyRepeatedFields:(TestAllTypes *)message; + +- (GPBExtensionRegistry *)extensionRegistry; + +- (NSData *)getDataFileNamed:(NSString *)name dataToWrite:(NSData *)dataToWrite; + +- (void)assertAllFieldsKVCMatch:(TestAllTypes *)message; +- (void)setAllFieldsViaKVC:(TestAllTypes *)message + repeatedCount:(uint32_t)count; +- (void)assertClearKVC:(TestAllTypes *)message; + +@end diff --git a/objectivec/Tests/GPBTestUtilities.m b/objectivec/Tests/GPBTestUtilities.m new file mode 100644 index 00000000..d664a88a --- /dev/null +++ b/objectivec/Tests/GPBTestUtilities.m @@ -0,0 +1,2350 @@ +// 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 "GPBTestUtilities.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/Unittest.pbobjc.h" + +const uint32_t kGPBDefaultRepeatCount = 2; + +// Small category to easily turn a CString into an NSData. +@interface NSData (GPBTestCase) ++ (NSData *)gpbtu_dataWithCString:(char *)buffer; ++ (instancetype)gpbtu_dataWithEmbeddedNulls; +@end + +@implementation NSData (GPBTestCase) ++ (NSData *)gpbtu_dataWithCString:(char *)buffer { + return [NSData dataWithBytes:buffer length:strlen(buffer)]; +} + ++ (instancetype)gpbtu_dataWithUint32:(uint32_t)value { + return [[[self alloc] initWithUint32_gpbtu:value] autorelease]; +} + +- (instancetype)initWithUint32_gpbtu:(uint32_t)value { + value = CFSwapInt32HostToLittle(value); + return [self initWithBytes:&value length:sizeof(value)]; +} + ++ (instancetype)gpbtu_dataWithEmbeddedNulls { + char bytes[6] = "\1\0\2\3\0\5"; + return [self dataWithBytes:bytes length:sizeof(bytes)]; +} +@end + +@implementation GPBTestCase + +// Return data for name. Optionally (based on #if setting) write out dataToWrite +// to replace that data. Useful for setting golden masters. +- (NSData *)getDataFileNamed:(NSString *)name + dataToWrite:(NSData *)dataToWrite { + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; + NSString *path = [bundle pathForResource:[name stringByDeletingPathExtension] + ofType:[name pathExtension]]; + XCTAssertNotNil(path, @"Unable to find %@", name); + NSData *data = [NSData dataWithContentsOfFile:path]; + XCTAssertNotNil(data, @"Unable to load from %@", path); +#if 0 + // Enable to write out golden master files. + if (!path) { + path = [[bundle resourcePath] stringByAppendingPathComponent:name]; + } + NSError *error = nil; + BOOL wrote = [dataToWrite writeToFile:path options:NSDataWritingAtomic error:&error]; + XCTAssertTrue(wrote, @"Unable to write %@ (%@)", path, error); + NSLog(@"Wrote data file to %@", path); +#else + // Kill off the unused variable warning. + dataToWrite = dataToWrite; +#endif + return data; +} + +// ------------------------------------------------------------------- + +- (void)modifyRepeatedExtensions:(TestAllExtensions *)message { + [message setExtension:[UnittestRoot repeatedInt32Extension] + index:1 + value:@501]; + [message setExtension:[UnittestRoot repeatedInt64Extension] + index:1 + value:@502]; + [message setExtension:[UnittestRoot repeatedUint32Extension] + index:1 + value:@503]; + [message setExtension:[UnittestRoot repeatedUint64Extension] + index:1 + value:@504]; + [message setExtension:[UnittestRoot repeatedSint32Extension] + index:1 + value:@505]; + [message setExtension:[UnittestRoot repeatedSint64Extension] + index:1 + value:@506]; + [message setExtension:[UnittestRoot repeatedFixed32Extension] + index:1 + value:@507]; + [message setExtension:[UnittestRoot repeatedFixed64Extension] + index:1 + value:@508]; + [message setExtension:[UnittestRoot repeatedSfixed32Extension] + index:1 + value:@509]; + [message setExtension:[UnittestRoot repeatedSfixed64Extension] + index:1 + value:@510]; + [message setExtension:[UnittestRoot repeatedFloatExtension] + index:1 + value:@511.0f]; + [message setExtension:[UnittestRoot repeatedDoubleExtension] + index:1 + value:@512.0]; + [message setExtension:[UnittestRoot repeatedBoolExtension] + index:1 + value:@YES]; + [message setExtension:[UnittestRoot repeatedStringExtension] + index:1 + value:@"515"]; + [message setExtension:[UnittestRoot repeatedBytesExtension] + index:1 + value:[NSData gpbtu_dataWithUint32:516]]; + + RepeatedGroup_extension *repeatedGroup = [RepeatedGroup_extension message]; + [repeatedGroup setA:517]; + [message setExtension:[UnittestRoot repeatedGroupExtension] + index:1 + value:repeatedGroup]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setBb:518]; + [message setExtension:[UnittestRoot repeatedNestedMessageExtension] + index:1 + value:nestedMessage]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:519]; + [message setExtension:[UnittestRoot repeatedForeignMessageExtension] + index:1 + value:foreignMessage]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setD:520]; + [message setExtension:[UnittestRoot repeatedImportMessageExtension] + index:1 + value:importMessage]; + + [message setExtension:[UnittestRoot repeatedNestedEnumExtension] + index:1 + value:@(TestAllTypes_NestedEnum_Foo)]; + [message setExtension:[UnittestRoot repeatedForeignEnumExtension] + index:1 + value:@(ForeignEnum_ForeignFoo)]; + [message setExtension:[UnittestRoot repeatedImportEnumExtension] + index:1 + value:@(ImportEnum_ImportFoo)]; + + [message setExtension:[UnittestRoot repeatedStringPieceExtension] + index:1 + value:@"524"]; + [message setExtension:[UnittestRoot repeatedCordExtension] + index:1 + value:@"525"]; +} + +- (void)assertAllExtensionsSet:(TestAllExtensions *)message + repeatedCount:(uint32_t)count { + XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalUint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalUint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalFixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalFixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSfixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalSfixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalFloatExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalDoubleExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalBoolExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalBytesExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + + XCTAssertTrue([[message getExtension:[UnittestRoot optionalGroupExtension]] hasA]); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalNestedMessageExtension]] hasBb]); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalForeignMessageExtension]] hasC]); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalImportMessageExtension]] hasD]); + + XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalForeignEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalImportEnumExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot optionalCordExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFloatExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultDoubleExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBoolExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultImportEnumExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultCordExtension]]); + + XCTAssertEqual(101, [[message getExtension:[UnittestRoot optionalInt32Extension]] intValue]); + XCTAssertEqual(102LL, [[message getExtension:[UnittestRoot optionalInt64Extension]] longLongValue]); + XCTAssertEqual(103U, [[message getExtension:[UnittestRoot optionalUint32Extension]] unsignedIntValue]); + XCTAssertEqual(104ULL, [[message getExtension:[UnittestRoot optionalUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(105, [[message getExtension:[UnittestRoot optionalSint32Extension]] intValue]); + XCTAssertEqual(106LL, [[message getExtension:[UnittestRoot optionalSint64Extension]] longLongValue]); + XCTAssertEqual(107U, [[message getExtension:[UnittestRoot optionalFixed32Extension]] unsignedIntValue]); + XCTAssertEqual(108ULL, [[message getExtension:[UnittestRoot optionalFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual(109, [[message getExtension:[UnittestRoot optionalSfixed32Extension]] intValue]); + XCTAssertEqual(110LL, [[message getExtension:[UnittestRoot optionalSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy(111.0f, [[message getExtension:[UnittestRoot optionalFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy(112.0, [[message getExtension:[UnittestRoot optionalDoubleExtension]] doubleValue], 0.01); + XCTAssertTrue([[message getExtension:[UnittestRoot optionalBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"115", [message getExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertEqualObjects([NSData gpbtu_dataWithEmbeddedNulls], [message getExtension:[UnittestRoot optionalBytesExtension]]); + + XCTAssertEqual(117, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot optionalGroupExtension]] a]); + XCTAssertEqual(118, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot optionalNestedMessageExtension]] bb]); + XCTAssertEqual(119, [[message getExtension:[UnittestRoot optionalForeignMessageExtension]] c]); + XCTAssertEqual(120, [[message getExtension:[UnittestRoot optionalImportMessageExtension]] d]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, [[message getExtension:[UnittestRoot optionalNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignBaz, [[message getExtension:[UnittestRoot optionalForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportBaz, [[message getExtension:[UnittestRoot optionalImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"124", [message getExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertEqualObjects(@"125", [message getExtension:[UnittestRoot optionalCordExtension]]); + + // ----------------------------------------------------------------- + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]); + + for (uint32_t i = 0; i < count; ++i) { + id extension = [message getExtension:[UnittestRoot repeatedInt32Extension]]; + XCTAssertEqual((int)(201 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedInt64Extension]]; + XCTAssertEqual(202 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot repeatedUint32Extension]]; + XCTAssertEqual(203 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot repeatedUint64Extension]]; + XCTAssertEqual(204 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot repeatedSint32Extension]]; + XCTAssertEqual((int)(205 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedSint64Extension]]; + XCTAssertEqual(206 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot repeatedFixed32Extension]]; + XCTAssertEqual(207 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot repeatedFixed64Extension]]; + XCTAssertEqual(208 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot repeatedSfixed32Extension]]; + XCTAssertEqual((int)(209 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedSfixed64Extension]]; + XCTAssertEqual(210 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot repeatedFloatExtension]]; + XCTAssertEqualWithAccuracy(211 + i * 100, [extension[i] floatValue], 0.01); + extension = [message getExtension:[UnittestRoot repeatedDoubleExtension]]; + XCTAssertEqualWithAccuracy(212 + i * 100, [extension[i] doubleValue], 0.01); + extension = [message getExtension:[UnittestRoot repeatedBoolExtension]]; + XCTAssertEqual((i % 2) ? YES : NO, [extension[i] boolValue]); + + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedStringExtension]]; + XCTAssertEqualObjects(string, extension[i]); + [string release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedBytesExtension]]; + XCTAssertEqualObjects(data, extension[i]); + [data release]; + + extension = [message getExtension:[UnittestRoot repeatedGroupExtension]]; + XCTAssertEqual((int)(217 + i * 100), [(TestAllTypes_OptionalGroup*)extension[i] a]); + extension = [message getExtension:[UnittestRoot repeatedNestedMessageExtension]]; + XCTAssertEqual((int)(218 + i * 100), [(TestAllTypes_NestedMessage*)extension[i] bb]); + extension = [message getExtension:[UnittestRoot repeatedForeignMessageExtension]]; + XCTAssertEqual((int)(219 + i * 100), [extension[i] c]); + extension = [message getExtension:[UnittestRoot repeatedImportMessageExtension]]; + XCTAssertEqual((int)(220 + i * 100), [extension[i] d]); + + extension = [message getExtension:[UnittestRoot repeatedNestedEnumExtension]]; + XCTAssertEqual((i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz, [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedForeignEnumExtension]]; + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot repeatedImportEnumExtension]]; + XCTAssertEqual((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz, [extension[i] intValue]); + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedStringPieceExtension]]; + XCTAssertEqualObjects(string, extension[i]); + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + extension = [message getExtension:[UnittestRoot repeatedCordExtension]]; + XCTAssertEqualObjects(string, extension[i]); + [string release]; + } + + // ----------------------------------------------------------------- + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultInt64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultUint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSint64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed32Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultSfixed64Extension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultFloatExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultDoubleExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBoolExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultImportEnumExtension]]); + + XCTAssertTrue([message hasExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertTrue([message hasExtension:[UnittestRoot defaultCordExtension]]); + + XCTAssertEqual(401, [[message getExtension:[UnittestRoot defaultInt32Extension]] intValue]); + XCTAssertEqual(402LL, [[message getExtension:[UnittestRoot defaultInt64Extension]] longLongValue]); + XCTAssertEqual(403U, [[message getExtension:[UnittestRoot defaultUint32Extension]] unsignedIntValue]); + XCTAssertEqual(404ULL, [[message getExtension:[UnittestRoot defaultUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(405, [[message getExtension:[UnittestRoot defaultSint32Extension]] intValue]); + XCTAssertEqual(406LL, [[message getExtension:[UnittestRoot defaultSint64Extension]] longLongValue]); + XCTAssertEqual(407U, [[message getExtension:[UnittestRoot defaultFixed32Extension]] unsignedIntValue]); + XCTAssertEqual(408ULL, [[message getExtension:[UnittestRoot defaultFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual(409, [[message getExtension:[UnittestRoot defaultSfixed32Extension]] intValue]); + XCTAssertEqual(410LL,[[message getExtension:[UnittestRoot defaultSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy(411.0f, [[message getExtension:[UnittestRoot defaultFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy(412.0, [[message getExtension:[UnittestRoot defaultDoubleExtension]] doubleValue], 0.01); + XCTAssertFalse([[message getExtension:[UnittestRoot defaultBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"415", [message getExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:416], [message getExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, [[message getExtension:[UnittestRoot defaultNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignFoo, [[message getExtension:[UnittestRoot defaultForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportFoo, [[message getExtension:[UnittestRoot defaultImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"424", [message getExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertEqualObjects(@"425", [message getExtension:[UnittestRoot defaultCordExtension]]); +} + +- (void)assertRepeatedExtensionsModified:(TestAllExtensions *)message + repeatedCount:(uint32_t)count { + // ModifyRepeatedFields only sets the second repeated element of each + // field. In addition to verifying this, we also verify that the first + // element and size were *not* modified. + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]); + + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]); + + XCTAssertEqual(201,[[message getExtension:[UnittestRoot repeatedInt32Extension]][0] intValue]); + XCTAssertEqual(202LL, [[message getExtension:[UnittestRoot repeatedInt64Extension]][0] longLongValue]); + XCTAssertEqual(203U, [[message getExtension:[UnittestRoot repeatedUint32Extension]][0] unsignedIntValue]); + XCTAssertEqual(204ULL, [[message getExtension:[UnittestRoot repeatedUint64Extension]][0] unsignedLongLongValue]); + XCTAssertEqual(205, [[message getExtension:[UnittestRoot repeatedSint32Extension]][0] intValue]); + XCTAssertEqual(206LL, [[message getExtension:[UnittestRoot repeatedSint64Extension]][0] longLongValue]); + XCTAssertEqual(207U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]][0] unsignedIntValue]); + XCTAssertEqual(208ULL, [[message getExtension:[UnittestRoot repeatedFixed64Extension]][0] unsignedLongLongValue]); + XCTAssertEqual(209, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]][0] intValue]); + XCTAssertEqual(210LL, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]][0] longLongValue]); + XCTAssertEqualWithAccuracy(211.0f, [[message getExtension:[UnittestRoot repeatedFloatExtension]][0] floatValue], 0.01); + XCTAssertEqualWithAccuracy(212.0, [[message getExtension:[UnittestRoot repeatedDoubleExtension]][0] doubleValue], 0.01); + XCTAssertFalse([[message getExtension:[UnittestRoot repeatedBoolExtension]][0] boolValue]); + XCTAssertEqualObjects(@"215", [message getExtension:[UnittestRoot repeatedStringExtension]][0]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:216], [message getExtension:[UnittestRoot repeatedBytesExtension]][0]); + + XCTAssertEqual(217, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot repeatedGroupExtension]][0] a]); + XCTAssertEqual(218, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot repeatedNestedMessageExtension]][0] bb]); + XCTAssertEqual(219, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]][0] c]); + XCTAssertEqual(220, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]][0] d]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, + [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]][0] intValue]); + XCTAssertEqual(ForeignEnum_ForeignBaz, + [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]][0] intValue]); + XCTAssertEqual(ImportEnum_ImportBaz, + [[message getExtension:[UnittestRoot repeatedImportEnumExtension]][0] intValue]); + + XCTAssertEqualObjects(@"224", [message getExtension:[UnittestRoot repeatedStringPieceExtension]][0]); + XCTAssertEqualObjects(@"225", [message getExtension:[UnittestRoot repeatedCordExtension]][0]); + + // Actually verify the second (modified) elements now. + XCTAssertEqual(501, [[message getExtension:[UnittestRoot repeatedInt32Extension]][1] intValue]); + XCTAssertEqual(502LL, [[message getExtension:[UnittestRoot repeatedInt64Extension]][1] longLongValue]); + XCTAssertEqual(503U, [[message getExtension:[UnittestRoot repeatedUint32Extension]][1] unsignedIntValue]); + XCTAssertEqual(504ULL, [[message getExtension:[UnittestRoot repeatedUint64Extension]][1] unsignedLongLongValue]); + XCTAssertEqual(505, [[message getExtension:[UnittestRoot repeatedSint32Extension]][1] intValue]); + XCTAssertEqual(506LL, [[message getExtension:[UnittestRoot repeatedSint64Extension]][1] longLongValue]); + XCTAssertEqual(507U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]][1] unsignedIntValue]); + XCTAssertEqual(508ULL, [[message getExtension:[UnittestRoot repeatedFixed64Extension]][1] unsignedLongLongValue]); + XCTAssertEqual(509, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]][1] intValue]); + XCTAssertEqual(510LL, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]][1] longLongValue]); + XCTAssertEqualWithAccuracy(511.0f, [[message getExtension:[UnittestRoot repeatedFloatExtension]][1] floatValue], 0.01); + XCTAssertEqualWithAccuracy(512.0, [[message getExtension:[UnittestRoot repeatedDoubleExtension]][1] doubleValue], 0.01); + XCTAssertTrue([[message getExtension:[UnittestRoot repeatedBoolExtension]][1] boolValue]); + XCTAssertEqualObjects(@"515", [message getExtension:[UnittestRoot repeatedStringExtension]][1]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:516], [message getExtension:[UnittestRoot repeatedBytesExtension]][1]); + + XCTAssertEqual(517, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot repeatedGroupExtension]][1] a]); + XCTAssertEqual(518, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot repeatedNestedMessageExtension]][1] bb]); + XCTAssertEqual(519, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]][1] c]); + XCTAssertEqual(520, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]][1] d]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, + [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]][1] intValue]); + XCTAssertEqual(ForeignEnum_ForeignFoo, + [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]][1] intValue]); + XCTAssertEqual(ImportEnum_ImportFoo, + [[message getExtension:[UnittestRoot repeatedImportEnumExtension]][1] intValue]); + + XCTAssertEqualObjects(@"524", [message getExtension:[UnittestRoot repeatedStringPieceExtension]][1]); + XCTAssertEqualObjects(@"525", [message getExtension:[UnittestRoot repeatedCordExtension]][1]); +} + +// ------------------------------------------------------------------- + +- (void)assertAllFieldsSet:(TestAllTypes *)message + repeatedCount:(uint32_t)count { + XCTAssertTrue(message.hasOptionalInt32); + XCTAssertTrue(message.hasOptionalInt64); + XCTAssertTrue(message.hasOptionalUint32); + XCTAssertTrue(message.hasOptionalUint64); + XCTAssertTrue(message.hasOptionalSint32); + XCTAssertTrue(message.hasOptionalSint64); + XCTAssertTrue(message.hasOptionalFixed32); + XCTAssertTrue(message.hasOptionalFixed64); + XCTAssertTrue(message.hasOptionalSfixed32); + XCTAssertTrue(message.hasOptionalSfixed64); + XCTAssertTrue(message.hasOptionalFloat); + XCTAssertTrue(message.hasOptionalDouble); + XCTAssertTrue(message.hasOptionalBool); + XCTAssertTrue(message.hasOptionalString); + XCTAssertTrue(message.hasOptionalBytes); + + XCTAssertTrue(message.hasOptionalGroup); + XCTAssertTrue(message.hasOptionalNestedMessage); + XCTAssertTrue(message.hasOptionalForeignMessage); + XCTAssertTrue(message.hasOptionalImportMessage); + + XCTAssertTrue(message.optionalGroup.hasA); + XCTAssertTrue(message.optionalNestedMessage.hasBb); + XCTAssertTrue(message.optionalForeignMessage.hasC); + XCTAssertTrue(message.optionalImportMessage.hasD); + + XCTAssertTrue(message.hasOptionalNestedEnum); + XCTAssertTrue(message.hasOptionalForeignEnum); + XCTAssertTrue(message.hasOptionalImportEnum); + + XCTAssertTrue(message.hasOptionalStringPiece); + XCTAssertTrue(message.hasOptionalCord); + + XCTAssertEqual(101, message.optionalInt32); + XCTAssertEqual(102LL, message.optionalInt64); + XCTAssertEqual(103U, message.optionalUint32); + XCTAssertEqual(104ULL, message.optionalUint64); + XCTAssertEqual(105, message.optionalSint32); + XCTAssertEqual(106LL, message.optionalSint64); + XCTAssertEqual(107U, message.optionalFixed32); + XCTAssertEqual(108ULL, message.optionalFixed64); + XCTAssertEqual(109, message.optionalSfixed32); + XCTAssertEqual(110LL, message.optionalSfixed64); + XCTAssertEqualWithAccuracy(111.0f, message.optionalFloat, 0.1); + XCTAssertEqualWithAccuracy(112.0, message.optionalDouble, 0.1); + XCTAssertTrue(message.optionalBool); + XCTAssertEqualObjects(@"115", message.optionalString); + XCTAssertEqualObjects([NSData gpbtu_dataWithEmbeddedNulls], + message.optionalBytes); + + XCTAssertEqual(117, message.optionalGroup.a); + XCTAssertEqual(118, message.optionalNestedMessage.bb); + XCTAssertEqual(119, message.optionalForeignMessage.c); + XCTAssertEqual(120, message.optionalImportMessage.d); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, message.optionalNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignBaz, message.optionalForeignEnum); + XCTAssertEqual(ImportEnum_ImportBaz, message.optionalImportEnum); + + XCTAssertEqualObjects(@"124", message.optionalStringPiece); + XCTAssertEqualObjects(@"125", message.optionalCord); + + // ----------------------------------------------------------------- + + XCTAssertEqual(count, message.repeatedInt32Array.count); + XCTAssertEqual(count, message.repeatedInt64Array.count); + XCTAssertEqual(count, message.repeatedUint32Array.count); + XCTAssertEqual(count, message.repeatedUint64Array.count); + XCTAssertEqual(count, message.repeatedSint32Array.count); + XCTAssertEqual(count, message.repeatedSint64Array.count); + XCTAssertEqual(count, message.repeatedFixed32Array.count); + XCTAssertEqual(count, message.repeatedFixed64Array.count); + XCTAssertEqual(count, message.repeatedSfixed32Array.count); + XCTAssertEqual(count, message.repeatedSfixed64Array.count); + XCTAssertEqual(count, message.repeatedFloatArray.count); + XCTAssertEqual(count, message.repeatedDoubleArray.count); + XCTAssertEqual(count, message.repeatedBoolArray.count); + XCTAssertEqual(count, message.repeatedStringArray.count); + XCTAssertEqual(count, message.repeatedBytesArray.count); + + XCTAssertEqual(count, message.repeatedGroupArray.count); + XCTAssertEqual(count, message.repeatedNestedMessageArray.count); + XCTAssertEqual(count, message.repeatedForeignMessageArray.count); + XCTAssertEqual(count, message.repeatedImportMessageArray.count); + XCTAssertEqual(count, message.repeatedNestedEnumArray.count); + XCTAssertEqual(count, message.repeatedForeignEnumArray.count); + XCTAssertEqual(count, message.repeatedImportEnumArray.count); + + XCTAssertEqual(count, message.repeatedStringPieceArray.count); + XCTAssertEqual(count, message.repeatedCordArray.count); + + for (uint32_t i = 0; i < count; ++i) { + XCTAssertEqual((int)(201 + i * 100), + [message.repeatedInt32Array valueAtIndex:i]); + XCTAssertEqual(202 + i * 100, [message.repeatedInt64Array valueAtIndex:i]); + XCTAssertEqual(203 + i * 100, [message.repeatedUint32Array valueAtIndex:i]); + XCTAssertEqual(204 + i * 100, [message.repeatedUint64Array valueAtIndex:i]); + XCTAssertEqual((int)(205 + i * 100), + [message.repeatedSint32Array valueAtIndex:i]); + XCTAssertEqual(206 + i * 100, [message.repeatedSint64Array valueAtIndex:i]); + XCTAssertEqual(207 + i * 100, + [message.repeatedFixed32Array valueAtIndex:i]); + XCTAssertEqual(208 + i * 100, + [message.repeatedFixed64Array valueAtIndex:i]); + XCTAssertEqual((int)(209 + i * 100), + [message.repeatedSfixed32Array valueAtIndex:i]); + XCTAssertEqual(210 + i * 100, + [message.repeatedSfixed64Array valueAtIndex:i]); + XCTAssertEqualWithAccuracy( + 211 + i * 100, [message.repeatedFloatArray valueAtIndex:i], 0.1); + XCTAssertEqualWithAccuracy( + 212 + i * 100, [message.repeatedDoubleArray valueAtIndex:i], 0.1); + XCTAssertEqual((i % 2) ? YES : NO, + [message.repeatedBoolArray valueAtIndex:i]); + + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + XCTAssertEqualObjects(string, message.repeatedStringArray[i]); + [string release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + XCTAssertEqualObjects(data, message.repeatedBytesArray[i]); + [data release]; + + XCTAssertEqual((int)(217 + i * 100), ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[i]).a); + XCTAssertEqual((int)(218 + i * 100), ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[i]).bb); + XCTAssertEqual((int)(219 + i * 100), ((ForeignMessage*)message.repeatedForeignMessageArray[i]).c); + XCTAssertEqual((int)(220 + i * 100), ((ImportMessage*)message.repeatedImportMessageArray[i]).d); + + XCTAssertEqual((i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz, [message.repeatedNestedEnumArray valueAtIndex:i]); + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, [message.repeatedForeignEnumArray valueAtIndex:i]); + XCTAssertEqual((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz, [message.repeatedImportEnumArray valueAtIndex:i]); + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + XCTAssertEqualObjects(string, message.repeatedStringPieceArray[i]); + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + XCTAssertEqualObjects(string, message.repeatedCordArray[i]); + [string release]; + } + + // ----------------------------------------------------------------- + + XCTAssertTrue(message.hasDefaultInt32); + XCTAssertTrue(message.hasDefaultInt64); + XCTAssertTrue(message.hasDefaultUint32); + XCTAssertTrue(message.hasDefaultUint64); + XCTAssertTrue(message.hasDefaultSint32); + XCTAssertTrue(message.hasDefaultSint64); + XCTAssertTrue(message.hasDefaultFixed32); + XCTAssertTrue(message.hasDefaultFixed64); + XCTAssertTrue(message.hasDefaultSfixed32); + XCTAssertTrue(message.hasDefaultSfixed64); + XCTAssertTrue(message.hasDefaultFloat); + XCTAssertTrue(message.hasDefaultDouble); + XCTAssertTrue(message.hasDefaultBool); + XCTAssertTrue(message.hasDefaultString); + XCTAssertTrue(message.hasDefaultBytes); + + XCTAssertTrue(message.hasDefaultNestedEnum); + XCTAssertTrue(message.hasDefaultForeignEnum); + XCTAssertTrue(message.hasDefaultImportEnum); + + XCTAssertTrue(message.hasDefaultStringPiece); + XCTAssertTrue(message.hasDefaultCord); + + XCTAssertEqual(401, message.defaultInt32); + XCTAssertEqual(402LL, message.defaultInt64); + XCTAssertEqual(403U, message.defaultUint32); + XCTAssertEqual(404ULL, message.defaultUint64); + XCTAssertEqual(405, message.defaultSint32); + XCTAssertEqual(406LL, message.defaultSint64); + XCTAssertEqual(407U, message.defaultFixed32); + XCTAssertEqual(408ULL, message.defaultFixed64); + XCTAssertEqual(409, message.defaultSfixed32); + XCTAssertEqual(410LL, message.defaultSfixed64); + XCTAssertEqualWithAccuracy(411.0f, message.defaultFloat, 0.1); + XCTAssertEqualWithAccuracy(412.0, message.defaultDouble, 0.1); + XCTAssertFalse(message.defaultBool); + XCTAssertEqualObjects(@"415", message.defaultString); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:416], + message.defaultBytes); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, message.defaultNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignFoo, message.defaultForeignEnum); + XCTAssertEqual(ImportEnum_ImportFoo, message.defaultImportEnum); + + XCTAssertEqualObjects(@"424", message.defaultStringPiece); + XCTAssertEqualObjects(@"425", message.defaultCord); +} + +- (void)setAllFields:(TestAllTypes *)message repeatedCount:(uint32_t)count { + [message setOptionalInt32:101]; + [message setOptionalInt64:102]; + [message setOptionalUint32:103]; + [message setOptionalUint64:104]; + [message setOptionalSint32:105]; + [message setOptionalSint64:106]; + [message setOptionalFixed32:107]; + [message setOptionalFixed64:108]; + [message setOptionalSfixed32:109]; + [message setOptionalSfixed64:110]; + [message setOptionalFloat:111]; + [message setOptionalDouble:112]; + [message setOptionalBool:YES]; + [message setOptionalString:@"115"]; + [message setOptionalBytes:[NSData gpbtu_dataWithEmbeddedNulls]]; + + TestAllTypes_OptionalGroup *allTypes = [TestAllTypes_OptionalGroup message]; + [allTypes setA:117]; + [message setOptionalGroup:allTypes]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setBb:118]; + [message setOptionalNestedMessage:nestedMessage]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:119]; + [message setOptionalForeignMessage:foreignMessage]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setD:120]; + [message setOptionalImportMessage:importMessage]; + + [message setOptionalNestedEnum:TestAllTypes_NestedEnum_Baz]; + [message setOptionalForeignEnum:ForeignEnum_ForeignBaz]; + [message setOptionalImportEnum:ImportEnum_ImportBaz]; + + [message setOptionalStringPiece:@"124"]; + [message setOptionalCord:@"125"]; + + // ----------------------------------------------------------------- + + for (uint32_t i = 0; i < count; i++) { + [message.repeatedInt32Array addValue:201 + i * 100]; + [message.repeatedInt64Array addValue:202 + i * 100]; + [message.repeatedUint32Array addValue:203 + i * 100]; + [message.repeatedUint64Array addValue:204 + i * 100]; + [message.repeatedSint32Array addValue:205 + i * 100]; + [message.repeatedSint64Array addValue:206 + i * 100]; + [message.repeatedFixed32Array addValue:207 + i * 100]; + [message.repeatedFixed64Array addValue:208 + i * 100]; + [message.repeatedSfixed32Array addValue:209 + i * 100]; + [message.repeatedSfixed64Array addValue:210 + i * 100]; + [message.repeatedFloatArray addValue:211 + i * 100]; + [message.repeatedDoubleArray addValue:212 + i * 100]; + [message.repeatedBoolArray addValue:(i % 2)]; + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + [message.repeatedStringArray addObject:string]; + [string release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + [message.repeatedBytesArray addObject:data]; + [data release]; + + TestAllTypes_RepeatedGroup *testAll = + [[TestAllTypes_RepeatedGroup alloc] init]; + [testAll setA:217 + i * 100]; + [message.repeatedGroupArray addObject:testAll]; + [testAll release]; + + nestedMessage = [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:218 + i * 100]; + [message.repeatedNestedMessageArray addObject:nestedMessage]; + [nestedMessage release]; + + foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:219 + i * 100]; + [message.repeatedForeignMessageArray addObject:foreignMessage]; + [foreignMessage release]; + + importMessage = [[ImportMessage alloc] init]; + [importMessage setD:220 + i * 100]; + [message.repeatedImportMessageArray addObject:importMessage]; + [importMessage release]; + + [message.repeatedNestedEnumArray addValue:(i % 2) ? TestAllTypes_NestedEnum_Bar : TestAllTypes_NestedEnum_Baz]; + + [message.repeatedForeignEnumArray addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz]; + [message.repeatedImportEnumArray addValue:(i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz]; + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + [message.repeatedStringPieceArray addObject:string]; + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + [message.repeatedCordArray addObject:string]; + [string release]; + } + // ----------------------------------------------------------------- + + message.defaultInt32 = 401; + message.defaultInt64 = 402; + message.defaultUint32 = 403; + message.defaultUint64 = 404; + message.defaultSint32 = 405; + message.defaultSint64 = 406; + message.defaultFixed32 = 407; + message.defaultFixed64 = 408; + message.defaultSfixed32 = 409; + message.defaultSfixed64 = 410; + message.defaultFloat = 411; + message.defaultDouble = 412; + message.defaultBool = NO; + message.defaultString = @"415"; + message.defaultBytes = [NSData gpbtu_dataWithUint32:416]; + + message.defaultNestedEnum = TestAllTypes_NestedEnum_Foo; + message.defaultForeignEnum = ForeignEnum_ForeignFoo; + message.defaultImportEnum = ImportEnum_ImportFoo; + + message.defaultStringPiece = @"424"; + message.defaultCord = @"425"; +} + +- (void)clearAllFields:(TestAllTypes *)message { + message.hasOptionalInt32 = NO; + message.hasOptionalInt64 = NO; + message.hasOptionalUint32 = NO; + message.hasOptionalUint64 = NO; + message.hasOptionalSint32 = NO; + message.hasOptionalSint64 = NO; + message.hasOptionalFixed32 = NO; + message.hasOptionalFixed64 = NO; + message.hasOptionalSfixed32 = NO; + message.hasOptionalSfixed64 = NO; + message.hasOptionalFloat = NO; + message.hasOptionalDouble = NO; + message.hasOptionalBool = NO; + message.hasOptionalString = NO; + message.hasOptionalBytes = NO; + + message.hasOptionalGroup = NO; + message.hasOptionalNestedMessage = NO; + message.hasOptionalForeignMessage = NO; + message.hasOptionalImportMessage = NO; + + message.hasOptionalNestedEnum = NO; + message.hasOptionalForeignEnum = NO; + message.hasOptionalImportEnum = NO; + + message.hasOptionalStringPiece = NO; + message.hasOptionalCord = NO; + + // ----------------------------------------------------------------- + + [message.repeatedInt32Array removeAll]; + [message.repeatedInt64Array removeAll]; + [message.repeatedUint32Array removeAll]; + [message.repeatedUint64Array removeAll]; + [message.repeatedSint32Array removeAll]; + [message.repeatedSint64Array removeAll]; + [message.repeatedFixed32Array removeAll]; + [message.repeatedFixed64Array removeAll]; + [message.repeatedSfixed32Array removeAll]; + [message.repeatedSfixed64Array removeAll]; + [message.repeatedFloatArray removeAll]; + [message.repeatedDoubleArray removeAll]; + [message.repeatedBoolArray removeAll]; + [message.repeatedStringArray removeAllObjects]; + [message.repeatedBytesArray removeAllObjects]; + + [message.repeatedGroupArray removeAllObjects]; + [message.repeatedNestedMessageArray removeAllObjects]; + [message.repeatedForeignMessageArray removeAllObjects]; + [message.repeatedImportMessageArray removeAllObjects]; + + [message.repeatedNestedEnumArray removeAll]; + [message.repeatedForeignEnumArray removeAll]; + [message.repeatedImportEnumArray removeAll]; + + [message.repeatedStringPieceArray removeAllObjects]; + [message.repeatedCordArray removeAllObjects]; + + // ----------------------------------------------------------------- + + message.hasDefaultInt32 = NO; + message.hasDefaultInt64 = NO; + message.hasDefaultUint32 = NO; + message.hasDefaultUint64 = NO; + message.hasDefaultSint32 = NO; + message.hasDefaultSint64 = NO; + message.hasDefaultFixed32 = NO; + message.hasDefaultFixed64 = NO; + message.hasDefaultSfixed32 = NO; + message.hasDefaultSfixed64 = NO; + message.hasDefaultFloat = NO; + message.hasDefaultDouble = NO; + message.hasDefaultBool = NO; + message.hasDefaultString = NO; + message.hasDefaultBytes = NO; + + message.hasDefaultNestedEnum = NO; + message.hasDefaultForeignEnum = NO; + message.hasDefaultImportEnum = NO; + + message.hasDefaultStringPiece = NO; + message.hasDefaultCord = NO; +} + +- (void)setAllExtensions:(TestAllExtensions *)message + repeatedCount:(uint32_t)count { + [message setExtension:[UnittestRoot optionalInt32Extension] value:@101]; + [message setExtension:[UnittestRoot optionalInt64Extension] value:@102L]; + [message setExtension:[UnittestRoot optionalUint32Extension] value:@103]; + [message setExtension:[UnittestRoot optionalUint64Extension] value:@104L]; + [message setExtension:[UnittestRoot optionalSint32Extension] value:@105]; + [message setExtension:[UnittestRoot optionalSint64Extension] value:@106L]; + [message setExtension:[UnittestRoot optionalFixed32Extension] value:@107]; + [message setExtension:[UnittestRoot optionalFixed64Extension] value:@108L]; + [message setExtension:[UnittestRoot optionalSfixed32Extension] value:@109]; + [message setExtension:[UnittestRoot optionalSfixed64Extension] value:@110L]; + [message setExtension:[UnittestRoot optionalFloatExtension] value:@111.0f]; + [message setExtension:[UnittestRoot optionalDoubleExtension] value:@112.0]; + [message setExtension:[UnittestRoot optionalBoolExtension] value:@YES]; + [message setExtension:[UnittestRoot optionalStringExtension] value:@"115"]; + [message setExtension:[UnittestRoot optionalBytesExtension] + value:[NSData gpbtu_dataWithEmbeddedNulls]]; + + OptionalGroup_extension *optionalGroup = [OptionalGroup_extension message]; + [optionalGroup setA:117]; + [message setExtension:[UnittestRoot optionalGroupExtension] + value:optionalGroup]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setBb:118]; + [message setExtension:[UnittestRoot optionalNestedMessageExtension] + value:nestedMessage]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setC:119]; + [message setExtension:[UnittestRoot optionalForeignMessageExtension] + value:foreignMessage]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setD:120]; + [message setExtension:[UnittestRoot optionalImportMessageExtension] + value:importMessage]; + + [message setExtension:[UnittestRoot optionalNestedEnumExtension] + value:@(TestAllTypes_NestedEnum_Baz)]; + [message setExtension:[UnittestRoot optionalForeignEnumExtension] + value:@(ForeignEnum_ForeignBaz)]; + [message setExtension:[UnittestRoot optionalImportEnumExtension] + value:@(ImportEnum_ImportBaz)]; + + [message setExtension:[UnittestRoot optionalStringPieceExtension] + value:@"124"]; + [message setExtension:[UnittestRoot optionalCordExtension] value:@"125"]; + + for (uint32_t i = 0; i < count; ++i) { + [message addExtension:[UnittestRoot repeatedInt32Extension] + value:@(201 + i * 100)]; + [message addExtension:[UnittestRoot repeatedInt64Extension] + value:@(202 + i * 100)]; + [message addExtension:[UnittestRoot repeatedUint32Extension] + value:@(203 + i * 100)]; + [message addExtension:[UnittestRoot repeatedUint64Extension] + value:@(204 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSint32Extension] + value:@(205 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSint64Extension] + value:@(206 + i * 100)]; + [message addExtension:[UnittestRoot repeatedFixed32Extension] + value:@(207 + i * 100)]; + [message addExtension:[UnittestRoot repeatedFixed64Extension] + value:@(208 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSfixed32Extension] + value:@(209 + i * 100)]; + [message addExtension:[UnittestRoot repeatedSfixed64Extension] + value:@(210 + i * 100)]; + [message addExtension:[UnittestRoot repeatedFloatExtension] + value:@(211 + i * 100)]; + [message addExtension:[UnittestRoot repeatedDoubleExtension] + value:@(212 + i * 100)]; + [message addExtension:[UnittestRoot repeatedBoolExtension] + value:@((i % 2) ? YES : NO)]; + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + [message addExtension:[UnittestRoot repeatedStringExtension] value:string]; + [string release]; + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + [message addExtension:[UnittestRoot repeatedBytesExtension] value:data]; + [data release]; + + RepeatedGroup_extension *repeatedGroup = + [[RepeatedGroup_extension alloc] init]; + [repeatedGroup setA:217 + i * 100]; + [message addExtension:[UnittestRoot repeatedGroupExtension] + value:repeatedGroup]; + [repeatedGroup release]; + nestedMessage = [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:218 + i * 100]; + [message addExtension:[UnittestRoot repeatedNestedMessageExtension] + value:nestedMessage]; + [nestedMessage release]; + foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:219 + i * 100]; + [message addExtension:[UnittestRoot repeatedForeignMessageExtension] + value:foreignMessage]; + [foreignMessage release]; + importMessage = [[ImportMessage alloc] init]; + [importMessage setD:220 + i * 100]; + [message addExtension:[UnittestRoot repeatedImportMessageExtension] + value:importMessage]; + [importMessage release]; + [message addExtension:[UnittestRoot repeatedNestedEnumExtension] + value:@((i % 2) ? TestAllTypes_NestedEnum_Bar + : TestAllTypes_NestedEnum_Baz)]; + [message addExtension:[UnittestRoot repeatedForeignEnumExtension] + value:@((i % 2) ? ForeignEnum_ForeignBar + : ForeignEnum_ForeignBaz)]; + [message + addExtension:[UnittestRoot repeatedImportEnumExtension] + value:@((i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz)]; + + string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + [message addExtension:[UnittestRoot repeatedStringPieceExtension] + value:string]; + [string release]; + + string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + [message addExtension:[UnittestRoot repeatedCordExtension] value:string]; + [string release]; + } + + // ----------------------------------------------------------------- + + [message setExtension:[UnittestRoot defaultInt32Extension] value:@401]; + [message setExtension:[UnittestRoot defaultInt64Extension] value:@402L]; + [message setExtension:[UnittestRoot defaultUint32Extension] value:@403]; + [message setExtension:[UnittestRoot defaultUint64Extension] value:@404L]; + [message setExtension:[UnittestRoot defaultSint32Extension] value:@405]; + [message setExtension:[UnittestRoot defaultSint64Extension] value:@406L]; + [message setExtension:[UnittestRoot defaultFixed32Extension] value:@407]; + [message setExtension:[UnittestRoot defaultFixed64Extension] value:@408L]; + [message setExtension:[UnittestRoot defaultSfixed32Extension] value:@409]; + [message setExtension:[UnittestRoot defaultSfixed64Extension] value:@410L]; + [message setExtension:[UnittestRoot defaultFloatExtension] value:@411.0f]; + [message setExtension:[UnittestRoot defaultDoubleExtension] value:@412.0]; + [message setExtension:[UnittestRoot defaultBoolExtension] value:@NO]; + [message setExtension:[UnittestRoot defaultStringExtension] value:@"415"]; + [message setExtension:[UnittestRoot defaultBytesExtension] + value:[NSData gpbtu_dataWithUint32:416]]; + + [message setExtension:[UnittestRoot defaultNestedEnumExtension] + value:@(TestAllTypes_NestedEnum_Foo)]; + [message setExtension:[UnittestRoot defaultForeignEnumExtension] + value:@(ForeignEnum_ForeignFoo)]; + [message setExtension:[UnittestRoot defaultImportEnumExtension] + value:@(ImportEnum_ImportFoo)]; + + [message setExtension:[UnittestRoot defaultStringPieceExtension] + value:@"424"]; + [message setExtension:[UnittestRoot defaultCordExtension] value:@"425"]; +} + +- (void)setAllMapFields:(TestMap *)message numEntries:(uint32_t)count { + message.mapInt32Int32 = [GPBInt32Int32Dictionary dictionary]; + message.mapInt64Int64 = [GPBInt64Int64Dictionary dictionary]; + message.mapUint32Uint32 = [GPBUInt32UInt32Dictionary dictionary]; + message.mapUint64Uint64 = [GPBUInt64UInt64Dictionary dictionary]; + message.mapSint32Sint32 = [GPBInt32Int32Dictionary dictionary]; + message.mapSint64Sint64 = [GPBInt64Int64Dictionary dictionary]; + message.mapFixed32Fixed32 = [GPBUInt32UInt32Dictionary dictionary]; + message.mapFixed64Fixed64 = [GPBUInt64UInt64Dictionary dictionary]; + message.mapSfixed32Sfixed32 = [GPBInt32Int32Dictionary dictionary]; + message.mapSfixed64Sfixed64 = [GPBInt64Int64Dictionary dictionary]; + message.mapInt32Float = [GPBInt32FloatDictionary dictionary]; + message.mapInt32Double = [GPBInt32DoubleDictionary dictionary]; + message.mapBoolBool = [GPBBoolBoolDictionary dictionary]; + message.mapStringString = [NSMutableDictionary dictionary]; + message.mapInt32Bytes = [GPBInt32ObjectDictionary dictionary]; + message.mapInt32Enum = [GPBInt32EnumDictionary + dictionaryWithValidationFunction:MapEnum_IsValidValue]; + message.mapInt32ForeignMessage = [GPBInt32ObjectDictionary dictionary]; + + for (uint32_t i = 0; i < count; i++) { + [message.mapInt32Int32 setValue:(i + 1) forKey:100 + i * 100]; + [message.mapInt64Int64 setValue:(i + 1) forKey:101 + i * 100]; + [message.mapUint32Uint32 setValue:(i + 1) forKey:102 + i * 100]; + [message.mapUint64Uint64 setValue:(i + 1) forKey:103 + i * 100]; + [message.mapSint32Sint32 setValue:(i + 1) forKey:104 + i * 100]; + [message.mapSint64Sint64 setValue:(i + 1) forKey:105 + i * 100]; + [message.mapFixed32Fixed32 setValue:(i + 1) forKey:106 + i * 100]; + [message.mapFixed64Fixed64 setValue:(i + 1) forKey:107 + i * 100]; + [message.mapSfixed32Sfixed32 setValue:(i + 1) forKey:108 + i * 100]; + [message.mapSfixed64Sfixed64 setValue:(i + 1) forKey:109 + i * 100]; + [message.mapInt32Float setValue:(i + 1) forKey:110 + i * 100]; + [message.mapInt32Double setValue:(i + 1) forKey:111 + i * 100]; + [message.mapBoolBool setValue:((i % 2) == 1) forKey:((i % 2) == 0)]; + + NSString *keyStr = [[NSString alloc] initWithFormat:@"%d", 112 + i * 100]; + NSString *dataStr = [[NSString alloc] initWithFormat:@"%d", i + 1]; + [message.mapStringString setObject:dataStr forKey:keyStr]; + [keyStr release]; + [dataStr release]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:i + 1]; + [message.mapInt32Bytes setValue:data forKey:113 + i * 100]; + [data release]; + + [message.mapInt32Enum + setValue:(i % 2) ? MapEnum_MapEnumBar : MapEnum_MapEnumBaz + forKey:114 + i * 100]; + + ForeignMessage *subMsg = [[ForeignMessage alloc] init]; + subMsg.c = i + 1; + [message.mapInt32ForeignMessage setValue:subMsg forKey:115 + i * 100]; + [subMsg release]; + } +} + +- (GPBExtensionRegistry *)extensionRegistry { + return [UnittestRoot extensionRegistry]; +} + +- (TestAllTypes *)allSetRepeatedCount:(uint32_t)count { + TestAllTypes *message = [TestAllTypes message]; + [self setAllFields:message repeatedCount:count]; + return message; +} + +- (TestAllExtensions *)allExtensionsSetRepeatedCount:(uint32_t)count { + TestAllExtensions *message = [TestAllExtensions message]; + [self setAllExtensions:message repeatedCount:count]; + return message; +} + +- (TestPackedTypes *)packedSetRepeatedCount:(uint32_t)count { + TestPackedTypes *message = [TestPackedTypes message]; + [self setPackedFields:message repeatedCount:count]; + return message; +} + +- (TestPackedExtensions *)packedExtensionsSetRepeatedCount:(uint32_t)count { + TestPackedExtensions *message = [TestPackedExtensions message]; + [self setPackedExtensions:message repeatedCount:count]; + return message; +} + +// ------------------------------------------------------------------- + +- (void)assertClear:(TestAllTypes *)message { + // hasBlah() should initially be NO for all optional fields. + XCTAssertFalse(message.hasOptionalInt32); + XCTAssertFalse(message.hasOptionalInt64); + XCTAssertFalse(message.hasOptionalUint32); + XCTAssertFalse(message.hasOptionalUint64); + XCTAssertFalse(message.hasOptionalSint32); + XCTAssertFalse(message.hasOptionalSint64); + XCTAssertFalse(message.hasOptionalFixed32); + XCTAssertFalse(message.hasOptionalFixed64); + XCTAssertFalse(message.hasOptionalSfixed32); + XCTAssertFalse(message.hasOptionalSfixed64); + XCTAssertFalse(message.hasOptionalFloat); + XCTAssertFalse(message.hasOptionalDouble); + XCTAssertFalse(message.hasOptionalBool); + XCTAssertFalse(message.hasOptionalString); + XCTAssertFalse(message.hasOptionalBytes); + + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + + XCTAssertFalse(message.hasOptionalNestedEnum); + XCTAssertFalse(message.hasOptionalForeignEnum); + XCTAssertFalse(message.hasOptionalImportEnum); + + XCTAssertFalse(message.hasOptionalStringPiece); + XCTAssertFalse(message.hasOptionalCord); + + // Optional fields without defaults are set to zero or something like it. + XCTAssertEqual(0, message.optionalInt32); + XCTAssertEqual(0LL, message.optionalInt64); + XCTAssertEqual(0U, message.optionalUint32); + XCTAssertEqual(0ULL, message.optionalUint64); + XCTAssertEqual(0, message.optionalSint32); + XCTAssertEqual(0LL, message.optionalSint64); + XCTAssertEqual(0U, message.optionalFixed32); + XCTAssertEqual(0ULL, message.optionalFixed64); + XCTAssertEqual(0, message.optionalSfixed32); + XCTAssertEqual(0LL, message.optionalSfixed64); + XCTAssertEqual(0.0f, message.optionalFloat); + XCTAssertEqual(0.0, message.optionalDouble); + XCTAssertFalse(message.optionalBool); + XCTAssertEqualObjects(message.optionalString, @""); + XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData()); + + // Embedded messages should also be clear. + XCTAssertFalse(message.hasOptionalGroup); + XCTAssertFalse(message.hasOptionalNestedMessage); + XCTAssertFalse(message.hasOptionalForeignMessage); + XCTAssertFalse(message.hasOptionalImportMessage); + + // Enums without defaults are set to the first value in the enum. + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, message.optionalNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignFoo, message.optionalForeignEnum); + XCTAssertEqual(ImportEnum_ImportFoo, message.optionalImportEnum); + + XCTAssertEqualObjects(message.optionalStringPiece, @""); + XCTAssertEqualObjects(message.optionalCord, @""); + + // Repeated fields are empty. + XCTAssertEqual(0U, message.repeatedInt32Array.count); + XCTAssertEqual(0U, message.repeatedInt64Array.count); + XCTAssertEqual(0U, message.repeatedUint32Array.count); + XCTAssertEqual(0U, message.repeatedUint64Array.count); + XCTAssertEqual(0U, message.repeatedSint32Array.count); + XCTAssertEqual(0U, message.repeatedSint64Array.count); + XCTAssertEqual(0U, message.repeatedFixed32Array.count); + XCTAssertEqual(0U, message.repeatedFixed64Array.count); + XCTAssertEqual(0U, message.repeatedSfixed32Array.count); + XCTAssertEqual(0U, message.repeatedSfixed64Array.count); + XCTAssertEqual(0U, message.repeatedFloatArray.count); + XCTAssertEqual(0U, message.repeatedDoubleArray.count); + XCTAssertEqual(0U, message.repeatedBoolArray.count); + XCTAssertEqual(0U, message.repeatedStringArray.count); + XCTAssertEqual(0U, message.repeatedBytesArray.count); + + XCTAssertEqual(0U, message.repeatedGroupArray.count); + XCTAssertEqual(0U, message.repeatedNestedMessageArray.count); + XCTAssertEqual(0U, message.repeatedForeignMessageArray.count); + XCTAssertEqual(0U, message.repeatedImportMessageArray.count); + XCTAssertEqual(0U, message.repeatedNestedEnumArray.count); + XCTAssertEqual(0U, message.repeatedForeignEnumArray.count); + XCTAssertEqual(0U, message.repeatedImportEnumArray.count); + + XCTAssertEqual(0U, message.repeatedStringPieceArray.count); + XCTAssertEqual(0U, message.repeatedCordArray.count); + + // hasBlah() should also be NO for all default fields. + XCTAssertFalse(message.hasDefaultInt32); + XCTAssertFalse(message.hasDefaultInt64); + XCTAssertFalse(message.hasDefaultUint32); + XCTAssertFalse(message.hasDefaultUint64); + XCTAssertFalse(message.hasDefaultSint32); + XCTAssertFalse(message.hasDefaultSint64); + XCTAssertFalse(message.hasDefaultFixed32); + XCTAssertFalse(message.hasDefaultFixed64); + XCTAssertFalse(message.hasDefaultSfixed32); + XCTAssertFalse(message.hasDefaultSfixed64); + XCTAssertFalse(message.hasDefaultFloat); + XCTAssertFalse(message.hasDefaultDouble); + XCTAssertFalse(message.hasDefaultBool); + XCTAssertFalse(message.hasDefaultString); + XCTAssertFalse(message.hasDefaultBytes); + + XCTAssertFalse(message.hasDefaultNestedEnum); + XCTAssertFalse(message.hasDefaultForeignEnum); + XCTAssertFalse(message.hasDefaultImportEnum); + + XCTAssertFalse(message.hasDefaultStringPiece); + XCTAssertFalse(message.hasDefaultCord); + + // Fields with defaults have their default values (duh). + XCTAssertEqual(41, message.defaultInt32); + XCTAssertEqual(42LL, message.defaultInt64); + XCTAssertEqual(43U, message.defaultUint32); + XCTAssertEqual(44ULL, message.defaultUint64); + XCTAssertEqual(-45, message.defaultSint32); + XCTAssertEqual(46LL, message.defaultSint64); + XCTAssertEqual(47U, message.defaultFixed32); + XCTAssertEqual(48ULL, message.defaultFixed64); + XCTAssertEqual(49, message.defaultSfixed32); + XCTAssertEqual(-50LL, message.defaultSfixed64); + XCTAssertEqualWithAccuracy(51.5f, message.defaultFloat, 0.1); + XCTAssertEqualWithAccuracy(52e3, message.defaultDouble, 0.1); + XCTAssertTrue(message.defaultBool); + XCTAssertEqualObjects(@"hello", message.defaultString); + XCTAssertEqualObjects([NSData gpbtu_dataWithCString:"world"], + message.defaultBytes); + + XCTAssertEqual(TestAllTypes_NestedEnum_Bar, message.defaultNestedEnum); + XCTAssertEqual(ForeignEnum_ForeignBar, message.defaultForeignEnum); + XCTAssertEqual(ImportEnum_ImportBar, message.defaultImportEnum); + + XCTAssertEqualObjects(@"abc", message.defaultStringPiece); + XCTAssertEqualObjects(@"123", message.defaultCord); +} + +- (void)assertExtensionsClear:(TestAllExtensions *)message { + // hasBlah() should initially be NO for all optional fields. + XCTAssertFalse([message hasExtension:[UnittestRoot optionalInt32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalInt64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalUint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalUint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalFixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalFixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSfixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalSfixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalFloatExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalDoubleExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalBoolExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalBytesExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportMessageExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportEnumExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot optionalCordExtension]]); + + // Optional fields without defaults are set to zero or something like it. + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalInt32Extension]] intValue]); + XCTAssertEqual(0LL,[[message getExtension:[UnittestRoot optionalInt64Extension]] longLongValue]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot optionalUint32Extension]] unsignedIntValue]); + XCTAssertEqual(0ULL, [[message getExtension:[UnittestRoot optionalUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalSint32Extension]] intValue]); + XCTAssertEqual(0LL, [[message getExtension:[UnittestRoot optionalSint64Extension]] longLongValue]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot optionalFixed32Extension]] unsignedIntValue]); + XCTAssertEqual(0ULL, [[message getExtension:[UnittestRoot optionalFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalSfixed32Extension]] intValue]); + XCTAssertEqual(0LL, [[message getExtension:[UnittestRoot optionalSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy(0.0f, [[message getExtension:[UnittestRoot optionalFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy(0.0, [[message getExtension:[UnittestRoot optionalDoubleExtension]] doubleValue], 0.01); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalStringExtension]]); + XCTAssertEqualObjects(GPBEmptyNSData(), [message getExtension:[UnittestRoot optionalBytesExtension]]); + + // Embedded messages should also be clear. + + XCTAssertFalse([[message getExtension:[UnittestRoot optionalGroupExtension]] hasA]); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalNestedMessageExtension]] hasBb]); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalForeignMessageExtension]] hasC]); + XCTAssertFalse([[message getExtension:[UnittestRoot optionalImportMessageExtension]] hasD]); + + XCTAssertEqual(0, [(TestAllTypes_OptionalGroup*)[message getExtension:[UnittestRoot optionalGroupExtension]] a]); + XCTAssertEqual(0, [(TestAllTypes_NestedMessage*)[message getExtension:[UnittestRoot optionalNestedMessageExtension]] bb]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalForeignMessageExtension]] c]); + XCTAssertEqual(0, [[message getExtension:[UnittestRoot optionalImportMessageExtension]] d]); + + // Enums without defaults are set to the first value in the enum. + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, + [[message getExtension:[UnittestRoot optionalNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignFoo, + [[message getExtension:[UnittestRoot optionalForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportFoo, + [[message getExtension:[UnittestRoot optionalImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalStringPieceExtension]]); + XCTAssertEqualObjects(@"", [message getExtension:[UnittestRoot optionalCordExtension]]); + + // Repeated fields are empty. + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedInt32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedInt64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedUint32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedUint64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSint32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSint64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFixed32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFixed64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSfixed32Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedSfixed64Extension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedFloatExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedDoubleExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedBoolExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedStringExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedBytesExtension]] count]); + + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedGroupExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedNestedMessageExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedForeignMessageExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedImportMessageExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedNestedEnumExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedForeignEnumExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedImportEnumExtension]] count]); + + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedStringPieceExtension]] count]); + XCTAssertEqual(0U, [[message getExtension:[UnittestRoot repeatedCordExtension]] count]); + + // hasBlah() should also be NO for all default fields. + XCTAssertFalse([message hasExtension:[UnittestRoot defaultInt32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultInt64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultUint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultUint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSint32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSint64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultFixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultFixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSfixed32Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultSfixed64Extension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultFloatExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultDoubleExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultBoolExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot defaultNestedEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultForeignEnumExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultImportEnumExtension]]); + + XCTAssertFalse([message hasExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertFalse([message hasExtension:[UnittestRoot defaultCordExtension]]); + + // Fields with defaults have their default values (duh). + XCTAssertEqual( 41, [[message getExtension:[UnittestRoot defaultInt32Extension]] intValue]); + XCTAssertEqual( 42LL, [[message getExtension:[UnittestRoot defaultInt64Extension]] longLongValue]); + XCTAssertEqual( 43U, [[message getExtension:[UnittestRoot defaultUint32Extension]] unsignedIntValue]); + XCTAssertEqual( 44ULL, [[message getExtension:[UnittestRoot defaultUint64Extension]] unsignedLongLongValue]); + XCTAssertEqual(-45, [[message getExtension:[UnittestRoot defaultSint32Extension]] intValue]); + XCTAssertEqual( 46LL, [[message getExtension:[UnittestRoot defaultSint64Extension]] longLongValue]); + XCTAssertEqual( 47, [[message getExtension:[UnittestRoot defaultFixed32Extension]] intValue]); + XCTAssertEqual( 48ULL, [[message getExtension:[UnittestRoot defaultFixed64Extension]] unsignedLongLongValue]); + XCTAssertEqual( 49, [[message getExtension:[UnittestRoot defaultSfixed32Extension]] intValue]); + XCTAssertEqual(-50LL, [[message getExtension:[UnittestRoot defaultSfixed64Extension]] longLongValue]); + XCTAssertEqualWithAccuracy( 51.5f, [[message getExtension:[UnittestRoot defaultFloatExtension]] floatValue], 0.01); + XCTAssertEqualWithAccuracy( 52e3, [[message getExtension:[UnittestRoot defaultDoubleExtension]] doubleValue], 0.01); + XCTAssertTrue([[message getExtension:[UnittestRoot defaultBoolExtension]] boolValue]); + XCTAssertEqualObjects(@"hello", [message getExtension:[UnittestRoot defaultStringExtension]]); + XCTAssertEqualObjects([NSData gpbtu_dataWithCString:"world"], [message getExtension:[UnittestRoot defaultBytesExtension]]); + + XCTAssertEqual(TestAllTypes_NestedEnum_Bar, + [[message getExtension:[UnittestRoot defaultNestedEnumExtension]] intValue]); + XCTAssertEqual(ForeignEnum_ForeignBar, + [[message getExtension:[UnittestRoot defaultForeignEnumExtension]] intValue]); + XCTAssertEqual(ImportEnum_ImportBar, + [[message getExtension:[UnittestRoot defaultImportEnumExtension]] intValue]); + + XCTAssertEqualObjects(@"abc", [message getExtension:[UnittestRoot defaultStringPieceExtension]]); + XCTAssertEqualObjects(@"123", [message getExtension:[UnittestRoot defaultCordExtension]]); +} + +- (void)modifyRepeatedFields:(TestAllTypes *)message { + [message.repeatedInt32Array replaceValueAtIndex:1 withValue:501]; + [message.repeatedInt64Array replaceValueAtIndex:1 withValue:502]; + [message.repeatedUint32Array replaceValueAtIndex:1 withValue:503]; + [message.repeatedUint64Array replaceValueAtIndex:1 withValue:504]; + [message.repeatedSint32Array replaceValueAtIndex:1 withValue:505]; + [message.repeatedSint64Array replaceValueAtIndex:1 withValue:506]; + [message.repeatedFixed32Array replaceValueAtIndex:1 withValue:507]; + [message.repeatedFixed64Array replaceValueAtIndex:1 withValue:508]; + [message.repeatedSfixed32Array replaceValueAtIndex:1 withValue:509]; + [message.repeatedSfixed64Array replaceValueAtIndex:1 withValue:510]; + [message.repeatedFloatArray replaceValueAtIndex:1 withValue:511]; + [message.repeatedDoubleArray replaceValueAtIndex:1 withValue:512]; + [message.repeatedBoolArray replaceValueAtIndex:1 withValue:YES]; + [message.repeatedStringArray replaceObjectAtIndex:1 withObject:@"515"]; + + NSData *data = [[NSData alloc] initWithUint32_gpbtu:516]; + [message.repeatedBytesArray replaceObjectAtIndex:1 withObject:data]; + [data release]; + + TestAllTypes_RepeatedGroup *testAll = + [[TestAllTypes_RepeatedGroup alloc] init]; + [testAll setA:517]; + [message.repeatedGroupArray replaceObjectAtIndex:1 withObject:testAll]; + [testAll release]; + + TestAllTypes_NestedMessage *nestedMessage = + [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:518]; + [message.repeatedNestedMessageArray replaceObjectAtIndex:1 + withObject:nestedMessage]; + [nestedMessage release]; + + ForeignMessage *foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:519]; + [message.repeatedForeignMessageArray replaceObjectAtIndex:1 + withObject:foreignMessage]; + [foreignMessage release]; + + ImportMessage *importMessage = [[ImportMessage alloc] init]; + [importMessage setD:520]; + [message.repeatedImportMessageArray replaceObjectAtIndex:1 + withObject:importMessage]; + [importMessage release]; + + [message.repeatedNestedEnumArray replaceValueAtIndex:1 withValue:TestAllTypes_NestedEnum_Foo]; + [message.repeatedForeignEnumArray replaceValueAtIndex:1 withValue:ForeignEnum_ForeignFoo]; + [message.repeatedImportEnumArray replaceValueAtIndex:1 withValue:ImportEnum_ImportFoo]; + + [message.repeatedStringPieceArray replaceObjectAtIndex:1 withObject:@"524"]; + [message.repeatedCordArray replaceObjectAtIndex:1 withObject:@"525"]; +} + +- (void)assertRepeatedFieldsModified:(TestAllTypes *)message + repeatedCount:(uint32_t)count { + // ModifyRepeatedFields only sets the second repeated element of each + // field. In addition to verifying this, we also verify that the first + // element and size were *not* modified. + XCTAssertEqual(count, message.repeatedInt32Array.count); + XCTAssertEqual(count, message.repeatedInt64Array.count); + XCTAssertEqual(count, message.repeatedUint32Array.count); + XCTAssertEqual(count, message.repeatedUint64Array.count); + XCTAssertEqual(count, message.repeatedSint32Array.count); + XCTAssertEqual(count, message.repeatedSint64Array.count); + XCTAssertEqual(count, message.repeatedFixed32Array.count); + XCTAssertEqual(count, message.repeatedFixed64Array.count); + XCTAssertEqual(count, message.repeatedSfixed32Array.count); + XCTAssertEqual(count, message.repeatedSfixed64Array.count); + XCTAssertEqual(count, message.repeatedFloatArray.count); + XCTAssertEqual(count, message.repeatedDoubleArray.count); + XCTAssertEqual(count, message.repeatedBoolArray.count); + XCTAssertEqual(count, message.repeatedStringArray.count); + XCTAssertEqual(count, message.repeatedBytesArray.count); + + XCTAssertEqual(count, message.repeatedGroupArray.count); + XCTAssertEqual(count, message.repeatedNestedMessageArray.count); + XCTAssertEqual(count, message.repeatedForeignMessageArray.count); + XCTAssertEqual(count, message.repeatedImportMessageArray.count); + XCTAssertEqual(count, message.repeatedNestedEnumArray.count); + XCTAssertEqual(count, message.repeatedForeignEnumArray.count); + XCTAssertEqual(count, message.repeatedImportEnumArray.count); + + XCTAssertEqual(count, message.repeatedStringPieceArray.count); + XCTAssertEqual(count, message.repeatedCordArray.count); + + XCTAssertEqual(201, [message.repeatedInt32Array valueAtIndex:0]); + XCTAssertEqual(202LL, [message.repeatedInt64Array valueAtIndex:0]); + XCTAssertEqual(203U, [message.repeatedUint32Array valueAtIndex:0]); + XCTAssertEqual(204ULL, [message.repeatedUint64Array valueAtIndex:0]); + XCTAssertEqual(205, [message.repeatedSint32Array valueAtIndex:0]); + XCTAssertEqual(206LL, [message.repeatedSint64Array valueAtIndex:0]); + XCTAssertEqual(207U, [message.repeatedFixed32Array valueAtIndex:0]); + XCTAssertEqual(208ULL, [message.repeatedFixed64Array valueAtIndex:0]); + XCTAssertEqual(209, [message.repeatedSfixed32Array valueAtIndex:0]); + XCTAssertEqual(210LL, [message.repeatedSfixed64Array valueAtIndex:0]); + XCTAssertEqualWithAccuracy(211.0f, [message.repeatedFloatArray valueAtIndex:0], 0.01); + XCTAssertEqualWithAccuracy(212.0, [message.repeatedDoubleArray valueAtIndex:0], 0.01); + XCTAssertFalse([message.repeatedBoolArray valueAtIndex:0]); + XCTAssertEqualObjects(@"215", message.repeatedStringArray[0]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:216], + message.repeatedBytesArray[0]); + + XCTAssertEqual(217, ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[0]).a); + XCTAssertEqual(218, ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[0]).bb); + XCTAssertEqual(219, ((ForeignMessage*)message.repeatedForeignMessageArray[0]).c); + XCTAssertEqual(220, ((ImportMessage*)message.repeatedImportMessageArray[0]).d); + + XCTAssertEqual(TestAllTypes_NestedEnum_Baz, [message.repeatedNestedEnumArray valueAtIndex:0]); + XCTAssertEqual(ForeignEnum_ForeignBaz, [message.repeatedForeignEnumArray valueAtIndex:0]); + XCTAssertEqual(ImportEnum_ImportBaz, [message.repeatedImportEnumArray valueAtIndex:0]); + + XCTAssertEqualObjects(@"224", message.repeatedStringPieceArray[0]); + XCTAssertEqualObjects(@"225", message.repeatedCordArray[0]); + + // Actually verify the second (modified) elements now. + XCTAssertEqual(501, [message.repeatedInt32Array valueAtIndex:1]); + XCTAssertEqual(502LL, [message.repeatedInt64Array valueAtIndex:1]); + XCTAssertEqual(503U, [message.repeatedUint32Array valueAtIndex:1]); + XCTAssertEqual(504ULL, [message.repeatedUint64Array valueAtIndex:1]); + XCTAssertEqual(505, [message.repeatedSint32Array valueAtIndex:1]); + XCTAssertEqual(506LL, [message.repeatedSint64Array valueAtIndex:1]); + XCTAssertEqual(507U, [message.repeatedFixed32Array valueAtIndex:1]); + XCTAssertEqual(508ULL, [message.repeatedFixed64Array valueAtIndex:1]); + XCTAssertEqual(509, [message.repeatedSfixed32Array valueAtIndex:1]); + XCTAssertEqual(510LL, [message.repeatedSfixed64Array valueAtIndex:1]); + XCTAssertEqualWithAccuracy(511.0f, [message.repeatedFloatArray valueAtIndex:1], 0.01); + XCTAssertEqualWithAccuracy(512.0, [message.repeatedDoubleArray valueAtIndex:1], 0.01); + XCTAssertTrue([message.repeatedBoolArray valueAtIndex:1]); + XCTAssertEqualObjects(@"515", message.repeatedStringArray[1]); + XCTAssertEqualObjects([NSData gpbtu_dataWithUint32:516], + message.repeatedBytesArray[1]); + + XCTAssertEqual(517, ((TestAllTypes_RepeatedGroup*)message.repeatedGroupArray[1]).a); + XCTAssertEqual(518, ((TestAllTypes_NestedMessage*)message.repeatedNestedMessageArray[1]).bb); + XCTAssertEqual(519, ((ForeignMessage*)message.repeatedForeignMessageArray[1]).c); + XCTAssertEqual(520, ((ImportMessage*)message.repeatedImportMessageArray[1]).d); + + XCTAssertEqual(TestAllTypes_NestedEnum_Foo, [message.repeatedNestedEnumArray valueAtIndex:1]); + XCTAssertEqual(ForeignEnum_ForeignFoo, [message.repeatedForeignEnumArray valueAtIndex:1]); + XCTAssertEqual(ImportEnum_ImportFoo, [message.repeatedImportEnumArray valueAtIndex:1]); + + XCTAssertEqualObjects(@"524", message.repeatedStringPieceArray[1]); + XCTAssertEqualObjects(@"525", message.repeatedCordArray[1]); +} + +- (void)setPackedFields:(TestPackedTypes *)message + repeatedCount:(uint32_t)count { + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:601 + i * 100]; + } + [message setPackedInt32Array:scratch]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:602 + i * 100]; + } + [message setPackedInt64Array:scratch]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:603 + i * 100]; + } + [message setPackedUint32Array:scratch]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:604 + i * 100]; + } + [message setPackedUint64Array:scratch]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:605 + i * 100]; + } + [message setPackedSint32Array:scratch]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:606 + i * 100]; + } + [message setPackedSint64Array:scratch]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:607 + i * 100]; + } + [message setPackedFixed32Array:scratch]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:608 + i * 100]; + } + [message setPackedFixed64Array:scratch]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:609 + i * 100]; + } + [message setPackedSfixed32Array:scratch]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:610 + i * 100]; + } + [message setPackedSfixed64Array:scratch]; + } + { + GPBFloatArray *scratch = [GPBFloatArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:611 + i * 100]; + } + [message setPackedFloatArray:scratch]; + } + { + GPBDoubleArray *scratch = [GPBDoubleArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:612 + i * 100]; + } + [message setPackedDoubleArray:scratch]; + } + { + GPBBoolArray *scratch = [GPBBoolArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? YES : NO]; + } + [message setPackedBoolArray:scratch]; + } + { + GPBEnumArray *scratch = + [GPBEnumArray arrayWithValidationFunction:ForeignEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch + addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz]; + } + [message setPackedEnumArray:scratch]; + } +} + +- (void)assertPackedFieldsSet:(TestPackedTypes *)message + repeatedCount:(uint32_t)count { + XCTAssertEqual(count, message.packedInt32Array.count); + XCTAssertEqual(count, message.packedInt64Array.count); + XCTAssertEqual(count, message.packedUint32Array.count); + XCTAssertEqual(count, message.packedUint64Array.count); + XCTAssertEqual(count, message.packedSint32Array.count); + XCTAssertEqual(count, message.packedSint64Array.count); + XCTAssertEqual(count, message.packedFixed32Array.count); + XCTAssertEqual(count, message.packedFixed64Array.count); + XCTAssertEqual(count, message.packedSfixed32Array.count); + XCTAssertEqual(count, message.packedSfixed64Array.count); + XCTAssertEqual(count, message.packedFloatArray.count); + XCTAssertEqual(count, message.packedDoubleArray.count); + XCTAssertEqual(count, message.packedBoolArray.count); + XCTAssertEqual(count, message.packedEnumArray.count); + for (uint32_t i = 0; i < count; ++i) { + XCTAssertEqual((int)(601 + i * 100), + [message.packedInt32Array valueAtIndex:i]); + XCTAssertEqual(602 + i * 100, [message.packedInt64Array valueAtIndex:i]); + XCTAssertEqual(603 + i * 100, [message.packedUint32Array valueAtIndex:i]); + XCTAssertEqual(604 + i * 100, [message.packedUint64Array valueAtIndex:i]); + XCTAssertEqual((int)(605 + i * 100), + [message.packedSint32Array valueAtIndex:i]); + XCTAssertEqual(606 + i * 100, [message.packedSint64Array valueAtIndex:i]); + XCTAssertEqual(607 + i * 100, [message.packedFixed32Array valueAtIndex:i]); + XCTAssertEqual(608 + i * 100, [message.packedFixed64Array valueAtIndex:i]); + XCTAssertEqual((int)(609 + i * 100), + [message.packedSfixed32Array valueAtIndex:i]); + XCTAssertEqual(610 + i * 100, [message.packedSfixed64Array valueAtIndex:i]); + XCTAssertEqualWithAccuracy(611 + i * 100, + [message.packedFloatArray valueAtIndex:i], 0.01); + XCTAssertEqualWithAccuracy( + 612 + i * 100, [message.packedDoubleArray valueAtIndex:i], 0.01); + XCTAssertEqual((i % 2) ? YES : NO, + [message.packedBoolArray valueAtIndex:i]); + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, + [message.packedEnumArray valueAtIndex:i]); + } +} + +- (void)setPackedExtensions:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count { + for (uint32_t i = 0; i < count; i++) { + [message addExtension:[UnittestRoot packedInt32Extension] + value:@(601 + i * 100)]; + [message addExtension:[UnittestRoot packedInt64Extension] + value:@(602 + i * 100)]; + [message addExtension:[UnittestRoot packedUint32Extension] + value:@(603 + i * 100)]; + [message addExtension:[UnittestRoot packedUint64Extension] + value:@(604 + i * 100)]; + [message addExtension:[UnittestRoot packedSint32Extension] + value:@(605 + i * 100)]; + [message addExtension:[UnittestRoot packedSint64Extension] + value:@(606 + i * 100)]; + [message addExtension:[UnittestRoot packedFixed32Extension] + value:@(607 + i * 100)]; + [message addExtension:[UnittestRoot packedFixed64Extension] + value:@(608 + i * 100)]; + [message addExtension:[UnittestRoot packedSfixed32Extension] + value:@(609 + i * 100)]; + [message addExtension:[UnittestRoot packedSfixed64Extension] + value:@(610 + i * 100)]; + [message addExtension:[UnittestRoot packedFloatExtension] + value:@(611 + i * 100)]; + [message addExtension:[UnittestRoot packedDoubleExtension] + value:@(612 + i * 100)]; + [message addExtension:[UnittestRoot packedBoolExtension] + value:@((i % 2) ? YES : NO)]; + [message addExtension:[UnittestRoot packedEnumExtension] + value:@((i % 2) ? ForeignEnum_ForeignBar + : ForeignEnum_ForeignBaz)]; + } +} + +- (void)assertPackedExtensionsSet:(TestPackedExtensions *)message + repeatedCount:(uint32_t)count{ + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedInt32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedInt64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedUint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedUint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSint32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSint64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSfixed32Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedSfixed64Extension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedFloatExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedDoubleExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedBoolExtension]] count]); + XCTAssertEqual(count, [[message getExtension:[UnittestRoot packedEnumExtension]] count]); + + for (uint32_t i = 0; i < count; ++i) { + id extension = [message getExtension:[UnittestRoot packedInt32Extension]]; + XCTAssertEqual((int)(601 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot packedInt64Extension]]; + XCTAssertEqual(602 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot packedUint32Extension]]; + XCTAssertEqual(603 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot packedUint64Extension]]; + XCTAssertEqual(604 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot packedSint32Extension]]; + XCTAssertEqual((int)(605 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot packedSint64Extension]]; + XCTAssertEqual(606 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot packedFixed32Extension]]; + XCTAssertEqual(607 + i * 100, [extension[i] unsignedIntValue]); + extension = [message getExtension:[UnittestRoot packedFixed64Extension]]; + XCTAssertEqual(608 + i * 100, [extension[i] unsignedLongLongValue]); + extension = [message getExtension:[UnittestRoot packedSfixed32Extension]]; + XCTAssertEqual((int)(609 + i * 100), [extension[i] intValue]); + extension = [message getExtension:[UnittestRoot packedSfixed64Extension]]; + XCTAssertEqual(610 + i * 100, [extension[i] longLongValue]); + extension = [message getExtension:[UnittestRoot packedFloatExtension]]; + XCTAssertEqualWithAccuracy(611 + i * 100, [extension[i] floatValue], 0.01); + extension = [message getExtension:[UnittestRoot packedDoubleExtension]]; + XCTAssertEqualWithAccuracy(612 + i * 100, [extension[i] doubleValue], 0.01); + extension = [message getExtension:[UnittestRoot packedBoolExtension]]; + XCTAssertEqual((i % 2) ? YES : NO, [extension[i] boolValue]); + extension = [message getExtension:[UnittestRoot packedEnumExtension]]; + XCTAssertEqual((i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz, + [extension[i] intValue]); + } +} + +- (void)assertAllFieldsKVCMatch:(TestAllTypes *)message { + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt32"], @YES); + XCTAssertEqualObjects(@(message.optionalInt32), [message valueForKey:@"optionalInt32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt64"], @YES); + XCTAssertEqualObjects(@(message.optionalInt64), [message valueForKey:@"optionalInt64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint32"], @YES); + XCTAssertEqualObjects(@(message.optionalUint32), [message valueForKey:@"optionalUint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint64"], @YES); + XCTAssertEqualObjects(@(message.optionalUint64), [message valueForKey:@"optionalUint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint32"], @YES); + XCTAssertEqualObjects(@(message.optionalSint32), [message valueForKey:@"optionalSint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint64"], @YES); + XCTAssertEqualObjects(@(message.optionalSint64), [message valueForKey:@"optionalSint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed32"], @YES); + XCTAssertEqualObjects(@(message.optionalFixed32), [message valueForKey:@"optionalFixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed64"], @YES); + XCTAssertEqualObjects(@(message.optionalFixed64), [message valueForKey:@"optionalFixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed32"], @YES); + XCTAssertEqualObjects(@(message.optionalSfixed32), [message valueForKey:@"optionalSfixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed64"], @YES); + XCTAssertEqualObjects(@(message.optionalSfixed64), [message valueForKey:@"optionalSfixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFloat"], @YES); + XCTAssertEqualObjects(@(message.optionalFloat), [message valueForKey:@"optionalFloat"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalDouble"], @YES); + XCTAssertEqualObjects(@(message.optionalDouble), [message valueForKey:@"optionalDouble"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBool"], @YES); + XCTAssertEqualObjects(@(message.optionalBool), [message valueForKey:@"optionalBool"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalString"], @YES); + XCTAssertEqualObjects(message.optionalString, [message valueForKey:@"optionalString"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBytes"], @YES); + XCTAssertEqualObjects(message.optionalBytes, [message valueForKey:@"optionalBytes"]); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalGroup"], @YES); + XCTAssertNotNil(message.optionalGroup); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.hasA"], @YES); + XCTAssertEqualObjects(@(message.optionalGroup.a), [message valueForKeyPath:@"optionalGroup.a"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedMessage"], @YES); + XCTAssertNotNil(message.optionalNestedMessage); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalNestedMessage.hasBb"], @YES); + XCTAssertEqualObjects(@(message.optionalNestedMessage.bb), [message valueForKeyPath:@"optionalNestedMessage.bb"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignMessage"], @YES); + XCTAssertNotNil(message.optionalForeignMessage); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalForeignMessage.hasC"], @YES); + XCTAssertEqualObjects(@(message.optionalForeignMessage.c), [message valueForKeyPath:@"optionalForeignMessage.c"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportMessage"], @YES); + XCTAssertNotNil(message.optionalForeignMessage); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.hasD"], @YES); + XCTAssertEqualObjects(@(message.optionalImportMessage.d), [message valueForKeyPath:@"optionalImportMessage.d"]); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedEnum"], @YES); + XCTAssertEqualObjects(@(message.optionalNestedEnum), [message valueForKey:@"optionalNestedEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignEnum"], @YES); + XCTAssertEqualObjects(@(message.optionalForeignEnum), [message valueForKey:@"optionalForeignEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportEnum"], @YES); + XCTAssertEqualObjects(@(message.optionalImportEnum), [message valueForKey:@"optionalImportEnum"]); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalStringPiece"], @YES); + XCTAssertEqualObjects(message.optionalStringPiece, [message valueForKey:@"optionalStringPiece"]); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalCord"], @YES); + XCTAssertEqualObjects(message.optionalCord, [message valueForKey:@"optionalCord"]); + + // ----------------------------------------------------------------- + + // GPBArray interface for repeated + + XCTAssertEqualObjects(message.repeatedInt32Array, [message valueForKey:@"repeatedInt32Array"]); + XCTAssertEqualObjects(message.repeatedInt64Array, [message valueForKey:@"repeatedInt64Array"]); + XCTAssertEqualObjects(message.repeatedUint32Array, [message valueForKey:@"repeatedUint32Array"]); + XCTAssertEqualObjects(message.repeatedUint64Array, [message valueForKey:@"repeatedUint64Array"]); + XCTAssertEqualObjects(message.repeatedSint32Array, [message valueForKey:@"repeatedSint32Array"]); + XCTAssertEqualObjects(message.repeatedSint64Array, [message valueForKey:@"repeatedSint64Array"]); + XCTAssertEqualObjects(message.repeatedFixed32Array, [message valueForKey:@"repeatedFixed32Array"]); + XCTAssertEqualObjects(message.repeatedFixed64Array, [message valueForKey:@"repeatedFixed64Array"]); + XCTAssertEqualObjects(message.repeatedSfixed32Array, [message valueForKey:@"repeatedSfixed32Array"]); + XCTAssertEqualObjects(message.repeatedSfixed64Array, [message valueForKey:@"repeatedSfixed64Array"]); + XCTAssertEqualObjects(message.repeatedFloatArray, [message valueForKey:@"repeatedFloatArray"]); + XCTAssertEqualObjects(message.repeatedDoubleArray, [message valueForKey:@"repeatedDoubleArray"]); + XCTAssertEqualObjects(message.repeatedBoolArray, [message valueForKey:@"repeatedBoolArray"]); + XCTAssertEqualObjects(message.repeatedStringArray, [message valueForKey:@"repeatedStringArray"]); + XCTAssertEqualObjects(message.repeatedBytesArray, [message valueForKey:@"repeatedBytesArray"]); + + XCTAssertEqualObjects(message.repeatedGroupArray, [message valueForKey:@"repeatedGroupArray"]); + XCTAssertEqualObjects(message.repeatedNestedMessageArray, [message valueForKey:@"repeatedNestedMessageArray"]); + XCTAssertEqualObjects(message.repeatedForeignMessageArray, [message valueForKey:@"repeatedForeignMessageArray"]); + XCTAssertEqualObjects(message.repeatedImportMessageArray, [message valueForKey:@"repeatedImportMessageArray"]); + + XCTAssertEqualObjects(message.repeatedNestedEnumArray, [message valueForKey:@"repeatedNestedEnumArray"]); + XCTAssertEqualObjects(message.repeatedForeignEnumArray, [message valueForKey:@"repeatedForeignEnumArray"]); + XCTAssertEqualObjects(message.repeatedImportEnumArray, [message valueForKey:@"repeatedImportEnumArray"]); + + XCTAssertEqualObjects(message.repeatedStringPieceArray, [message valueForKey:@"repeatedStringPieceArray"]); + XCTAssertEqualObjects(message.repeatedCordArray, [message valueForKey:@"repeatedCordArray"]); + + // ----------------------------------------------------------------- + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt32"], @YES); + XCTAssertEqualObjects(@(message.defaultInt32), [message valueForKey:@"defaultInt32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt64"], @YES); + XCTAssertEqualObjects(@(message.defaultInt64), [message valueForKey:@"defaultInt64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint32"], @YES); + XCTAssertEqualObjects(@(message.defaultUint32), [message valueForKey:@"defaultUint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint64"], @YES); + XCTAssertEqualObjects(@(message.defaultUint64), [message valueForKey:@"defaultUint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint32"], @YES); + XCTAssertEqualObjects(@(message.defaultSint32), [message valueForKey:@"defaultSint32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint64"], @YES); + XCTAssertEqualObjects(@(message.defaultSint64), [message valueForKey:@"defaultSint64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed32"], @YES); + XCTAssertEqualObjects(@(message.defaultFixed32), [message valueForKey:@"defaultFixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed64"], @YES); + XCTAssertEqualObjects(@(message.defaultFixed64), [message valueForKey:@"defaultFixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed32"], @YES); + XCTAssertEqualObjects(@(message.defaultSfixed32), [message valueForKey:@"defaultSfixed32"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed64"], @YES); + XCTAssertEqualObjects(@(message.defaultSfixed64), [message valueForKey:@"defaultSfixed64"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFloat"], @YES); + XCTAssertEqualObjects(@(message.defaultFloat), [message valueForKey:@"defaultFloat"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultDouble"], @YES); + XCTAssertEqualObjects(@(message.defaultDouble), [message valueForKey:@"defaultDouble"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBool"], @YES); + XCTAssertEqualObjects(@(message.defaultBool), [message valueForKey:@"defaultBool"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultString"], @YES); + XCTAssertEqualObjects(message.defaultString, [message valueForKey:@"defaultString"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBytes"], @YES); + XCTAssertEqualObjects(message.defaultBytes, [message valueForKey:@"defaultBytes"]); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultNestedEnum"], @YES); + XCTAssertEqualObjects(@(message.defaultNestedEnum), [message valueForKey:@"defaultNestedEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultForeignEnum"], @YES); + XCTAssertEqualObjects(@(message.defaultForeignEnum), [message valueForKey:@"defaultForeignEnum"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultImportEnum"], @YES); + XCTAssertEqualObjects(@(message.defaultImportEnum), [message valueForKey:@"defaultImportEnum"]); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultStringPiece"], @YES); + XCTAssertEqualObjects(message.defaultStringPiece, [message valueForKey:@"defaultStringPiece"]); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultCord"], @YES); + XCTAssertEqualObjects(message.defaultCord, [message valueForKey:@"defaultCord"]); +} + +- (void)setAllFieldsViaKVC:(TestAllTypes *)message + repeatedCount:(uint32_t)count { + [message setValue:@101 forKey:@"optionalInt32"]; + [message setValue:@102 forKey:@"optionalInt64"]; + [message setValue:@103 forKey:@"optionalUint32"]; + [message setValue:@104 forKey:@"optionalUint64"]; + [message setValue:@105 forKey:@"optionalSint32"]; + [message setValue:@106 forKey:@"optionalSint64"]; + [message setValue:@107 forKey:@"optionalFixed32"]; + [message setValue:@108 forKey:@"optionalFixed64"]; + [message setValue:@109 forKey:@"optionalSfixed32"]; + [message setValue:@110 forKey:@"optionalSfixed64"]; + [message setValue:@111 forKey:@"optionalFloat"]; + [message setValue:@112 forKey:@"optionalDouble"]; + [message setValue:@YES forKey:@"optionalBool"]; + [message setValue:@"115" forKey:@"optionalString"]; + [message setValue:[NSData gpbtu_dataWithEmbeddedNulls] + forKey:@"optionalBytes"]; + + TestAllTypes_OptionalGroup *allTypes = [TestAllTypes_OptionalGroup message]; + [allTypes setValue:@117 forKey:@"a"]; + [message setValue:allTypes forKey:@"optionalGroup"]; + TestAllTypes_NestedMessage *nestedMessage = + [TestAllTypes_NestedMessage message]; + [nestedMessage setValue:@118 forKey:@"bb"]; + [message setValue:nestedMessage forKey:@"optionalNestedMessage"]; + ForeignMessage *foreignMessage = [ForeignMessage message]; + [foreignMessage setValue:@119 forKey:@"c"]; + [message setValue:foreignMessage forKey:@"optionalForeignMessage"]; + ImportMessage *importMessage = [ImportMessage message]; + [importMessage setValue:@120 forKey:@"d"]; + [message setValue:importMessage forKey:@"optionalImportMessage"]; + + [message setValue:@(TestAllTypes_NestedEnum_Baz) + forKey:@"optionalNestedEnum"]; + [message setValue:@(ForeignEnum_ForeignBaz) forKey:@"optionalForeignEnum"]; + [message setValue:@(ImportEnum_ImportBaz) forKey:@"optionalImportEnum"]; + + [message setValue:@"124" forKey:@"optionalStringPiece"]; + [message setValue:@"125" forKey:@"optionalCord"]; + + // ----------------------------------------------------------------- + + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:201 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedInt32Array"]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:202 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedInt64Array"]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:203 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedUint32Array"]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:204 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedUint64Array"]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:205 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSint32Array"]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:206 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSint64Array"]; + } + { + GPBUInt32Array *scratch = [GPBUInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:207 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedFixed32Array"]; + } + { + GPBUInt64Array *scratch = [GPBUInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:208 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedFixed64Array"]; + } + { + GPBInt32Array *scratch = [GPBInt32Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:209 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSfixed32Array"]; + } + { + GPBInt64Array *scratch = [GPBInt64Array array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:210 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedSfixed64Array"]; + } + { + GPBFloatArray *scratch = [GPBFloatArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:211 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedFloatArray"]; + } + { + GPBDoubleArray *scratch = [GPBDoubleArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:212 + i * 100]; + } + [message setValue:scratch forKey:@"repeatedDoubleArray"]; + } + { + GPBBoolArray *scratch = [GPBBoolArray array]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? YES : NO]; + } + [message setValue:scratch forKey:@"repeatedBoolArray"]; + } + + NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSString *string = [[NSString alloc] initWithFormat:@"%d", 215 + i * 100]; + [array addObject:string]; + [string release]; + } + [message setValue:array forKey:@"repeatedStringArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSData *data = [[NSData alloc] initWithUint32_gpbtu:216 + i * 100]; + [array addObject:data]; + [data release]; + } + [message setValue:array forKey:@"repeatedBytesArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + TestAllTypes_RepeatedGroup *testAll = + [[TestAllTypes_RepeatedGroup alloc] init]; + [testAll setA:217 + i * 100]; + [array addObject:testAll]; + [testAll release]; + } + [message setValue:array forKey:@"repeatedGroupArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + nestedMessage = [[TestAllTypes_NestedMessage alloc] init]; + [nestedMessage setBb:218 + i * 100]; + [array addObject:nestedMessage]; + [nestedMessage release]; + } + [message setValue:array forKey:@"repeatedNestedMessageArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + foreignMessage = [[ForeignMessage alloc] init]; + [foreignMessage setC:219 + i * 100]; + [array addObject:foreignMessage]; + [foreignMessage release]; + } + [message setValue:array forKey:@"repeatedForeignMessageArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + importMessage = [[ImportMessage alloc] init]; + [importMessage setD:220 + i * 100]; + [array addObject:importMessage]; + [importMessage release]; + } + [message setValue:array forKey:@"repeatedImportMessageArray"]; + [array release]; + + { + GPBEnumArray *scratch = [GPBEnumArray + arrayWithValidationFunction:TestAllTypes_NestedEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? TestAllTypes_NestedEnum_Bar + : TestAllTypes_NestedEnum_Baz]; + } + [message setValue:scratch forKey:@"repeatedNestedEnumArray"]; + } + { + GPBEnumArray *scratch = + [GPBEnumArray arrayWithValidationFunction:ForeignEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch + addValue:(i % 2) ? ForeignEnum_ForeignBar : ForeignEnum_ForeignBaz]; + } + [message setValue:scratch forKey:@"repeatedForeignEnumArray"]; + } + { + GPBEnumArray *scratch = + [GPBEnumArray arrayWithValidationFunction:ImportEnum_IsValidValue]; + for (uint32_t i = 0; i < count; ++i) { + [scratch addValue:(i % 2) ? ImportEnum_ImportBar : ImportEnum_ImportBaz]; + } + [message setValue:scratch forKey:@"repeatedImportEnumArray"]; + } + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSString *string = [[NSString alloc] initWithFormat:@"%d", 224 + i * 100]; + [array addObject:string]; + [string release]; + } + [message setValue:array forKey:@"repeatedStringPieceArray"]; + [array release]; + + array = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0; i < count; ++i) { + NSString *string = [[NSString alloc] initWithFormat:@"%d", 225 + i * 100]; + [array addObject:string]; + [string release]; + } + [message setValue:array forKey:@"repeatedCordArray"]; + [array release]; + + // ----------------------------------------------------------------- + + [message setValue:@401 forKey:@"defaultInt32"]; + [message setValue:@402 forKey:@"defaultInt64"]; + [message setValue:@403 forKey:@"defaultUint32"]; + [message setValue:@404 forKey:@"defaultUint64"]; + [message setValue:@405 forKey:@"defaultSint32"]; + [message setValue:@406 forKey:@"defaultSint64"]; + [message setValue:@407 forKey:@"defaultFixed32"]; + [message setValue:@408 forKey:@"defaultFixed64"]; + [message setValue:@409 forKey:@"defaultSfixed32"]; + [message setValue:@410 forKey:@"defaultSfixed64"]; + [message setValue:@411 forKey:@"defaultFloat"]; + [message setValue:@412 forKey:@"defaultDouble"]; + [message setValue:@NO forKey:@"defaultBool"]; + [message setValue:@"415" forKey:@"defaultString"]; + [message setValue:[NSData gpbtu_dataWithUint32:416] forKey:@"defaultBytes"]; + + [message setValue:@(TestAllTypes_NestedEnum_Foo) forKey:@"defaultNestedEnum"]; + [message setValue:@(ForeignEnum_ForeignFoo) forKey:@"defaultForeignEnum"]; + [message setValue:@(ImportEnum_ImportFoo) forKey:@"defaultImportEnum"]; + + [message setValue:@"424" forKey:@"defaultStringPiece"]; + [message setValue:@"425" forKey:@"defaultCord"]; +} + +- (void)assertClearKVC:(TestAllTypes *)message { + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalInt64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalUint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalSfixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalFloat"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalDouble"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBool"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalString"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalBytes"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalGroup"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedMessage"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignMessage"], + @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportMessage"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalNestedEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalForeignEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalImportEnum"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasOptionalStringPiece"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasOptionalCord"], @NO); + + // Optional fields without defaults are set to zero or something like it. + XCTAssertEqualObjects([message valueForKey:@"optionalInt32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalInt64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalUint32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalUint64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSint32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSint64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalFixed32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalFixed64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSfixed32"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalSfixed64"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalFloat"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalDouble"], @0); + XCTAssertEqualObjects([message valueForKey:@"optionalBool"], @NO); + XCTAssertEqualObjects([message valueForKey:@"optionalString"], @""); + XCTAssertEqualObjects([message valueForKey:@"optionalBytes"], + GPBEmptyNSData()); + + // Embedded messages should also be exist, but be clear. + XCTAssertNotNil([message valueForKeyPath:@"optionalGroup"]); + XCTAssertNotNil([message valueForKeyPath:@"optionalNestedMessage"]); + XCTAssertNotNil([message valueForKeyPath:@"optionalForeignMessage"]); + XCTAssertNotNil([message valueForKeyPath:@"optionalImportMessage"]); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.hasA"], @NO); + XCTAssertEqualObjects( + [message valueForKeyPath:@"optionalNestedMessage.hasBb"], @NO); + XCTAssertEqualObjects( + [message valueForKeyPath:@"optionalForeignMessage.hasC"], @NO); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.hasD"], + @NO); + + XCTAssertEqualObjects([message valueForKeyPath:@"optionalGroup.a"], @0); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalNestedMessage.bb"], + @0); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalForeignMessage.c"], + @0); + XCTAssertEqualObjects([message valueForKeyPath:@"optionalImportMessage.d"], + @0); + + // Enums without defaults are set to the first value in the enum. + XCTAssertEqualObjects([message valueForKey:@"optionalNestedEnum"], + @(TestAllTypes_NestedEnum_Foo)); + XCTAssertEqualObjects([message valueForKey:@"optionalForeignEnum"], + @(ForeignEnum_ForeignFoo)); + XCTAssertEqualObjects([message valueForKey:@"optionalImportEnum"], + @(ImportEnum_ImportFoo)); + + XCTAssertEqualObjects([message valueForKey:@"optionalStringPiece"], @""); + XCTAssertEqualObjects([message valueForKey:@"optionalCord"], @""); + + // NSArray interface for repeated doesn't have has*, nil means no value. + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultInt64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultUint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSint64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed32"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultSfixed64"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultFloat"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultDouble"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBool"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultString"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultBytes"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultNestedEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultForeignEnum"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultImportEnum"], @NO); + + XCTAssertEqualObjects([message valueForKey:@"hasDefaultStringPiece"], @NO); + XCTAssertEqualObjects([message valueForKey:@"hasDefaultCord"], @NO); + + // Fields with defaults have their default values (duh). + XCTAssertEqualObjects([message valueForKey:@"defaultInt32"], @41); + XCTAssertEqualObjects([message valueForKey:@"defaultInt64"], @42); + XCTAssertEqualObjects([message valueForKey:@"defaultUint32"], @43); + XCTAssertEqualObjects([message valueForKey:@"defaultUint64"], @44); + XCTAssertEqualObjects([message valueForKey:@"defaultSint32"], @-45); + XCTAssertEqualObjects([message valueForKey:@"defaultSint64"], @46); + XCTAssertEqualObjects([message valueForKey:@"defaultFixed32"], @47); + XCTAssertEqualObjects([message valueForKey:@"defaultFixed64"], @48); + XCTAssertEqualObjects([message valueForKey:@"defaultSfixed32"], @49); + XCTAssertEqualObjects([message valueForKey:@"defaultSfixed64"], @-50); + XCTAssertEqualObjects([message valueForKey:@"defaultFloat"], @51.5); + XCTAssertEqualObjects([message valueForKey:@"defaultDouble"], @52e3); + XCTAssertEqualObjects([message valueForKey:@"defaultBool"], @YES); + XCTAssertEqualObjects([message valueForKey:@"defaultString"], @"hello"); + XCTAssertEqualObjects([message valueForKey:@"defaultBytes"], + [NSData gpbtu_dataWithCString:"world"]); + + XCTAssertEqualObjects([message valueForKey:@"defaultNestedEnum"], + @(TestAllTypes_NestedEnum_Bar)); + XCTAssertEqualObjects([message valueForKey:@"defaultForeignEnum"], + @(ForeignEnum_ForeignBar)); + XCTAssertEqualObjects([message valueForKey:@"defaultImportEnum"], + @(ImportEnum_ImportBar)); + + XCTAssertEqualObjects([message valueForKey:@"defaultStringPiece"], @"abc"); + XCTAssertEqualObjects([message valueForKey:@"defaultCord"], @"123"); +} + +@end diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m new file mode 100644 index 00000000..2c271bf7 --- /dev/null +++ b/objectivec/Tests/GPBUnittestProtos.m @@ -0,0 +1,56 @@ +// 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. + +// Collects all the compiled protos into one file and compiles them to make sure +// the compiler is generating valid code. + +#import "google/protobuf/MapProto2Unittest.pbobjc.m" +#import "google/protobuf/MapUnittest.pbobjc.m" +#import "google/protobuf/Unittest.pbobjc.m" +#import "google/protobuf/UnittestCustomOptions.pbobjc.m" +#import "google/protobuf/UnittestCycle.pbobjc.m" +#import "google/protobuf/UnittestDropUnknownFields.pbobjc.m" +#import "google/protobuf/UnittestEmbedOptimizeFor.pbobjc.m" +#import "google/protobuf/UnittestEmpty.pbobjc.m" +#import "google/protobuf/UnittestEnormousDescriptor.pbobjc.m" +#import "google/protobuf/UnittestFilter.pbobjc.m" +#import "google/protobuf/UnittestImport.pbobjc.m" +#import "google/protobuf/UnittestImportLite.pbobjc.m" +#import "google/protobuf/UnittestImportPublic.pbobjc.m" +#import "google/protobuf/UnittestImportPublicLite.pbobjc.m" +#import "google/protobuf/UnittestLite.pbobjc.m" +#import "google/protobuf/UnittestMset.pbobjc.m" +#import "google/protobuf/UnittestNameMangling.pbobjc.m" +#import "google/protobuf/UnittestNoGenericServices.pbobjc.m" +#import "google/protobuf/UnittestObjc.pbobjc.m" +#import "google/protobuf/UnittestOptimizeFor.pbobjc.m" +#import "google/protobuf/UnittestPreserveUnknownEnum.pbobjc.m" +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.m" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.m" diff --git a/objectivec/Tests/GPBUnknownFieldSetTest.m b/objectivec/Tests/GPBUnknownFieldSetTest.m new file mode 100644 index 00000000..80186088 --- /dev/null +++ b/objectivec/Tests/GPBUnknownFieldSetTest.m @@ -0,0 +1,255 @@ +// 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 "GPBTestUtilities.h" + +#import "GPBField_PackagePrivate.h" +#import "GPBUnknownFieldSet_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" + +@interface GPBUnknownFieldSet (GPBUnknownFieldSetTest) +- (void)getTags:(int32_t*)tags; +@end + +@interface UnknownFieldSetTest : GPBTestCase { + @private + TestAllTypes* allFields_; + NSData* allFieldsData_; + + // An empty message that has been parsed from allFieldsData. So, it has + // unknown fields of every type. + TestEmptyMessage* emptyMessage_; + GPBUnknownFieldSet* unknownFields_; +} + +@end + +@implementation UnknownFieldSetTest + +- (void)setUp { + allFields_ = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + allFieldsData_ = [allFields_ data]; + emptyMessage_ = [TestEmptyMessage parseFromData:allFieldsData_]; + unknownFields_ = emptyMessage_.unknownFields; +} + +- (GPBField*)getField:(int32_t)number { + return [unknownFields_ getField:number]; +} + +// Constructs a protocol buffer which contains fields with all the same +// numbers as allFieldsData except that each field is some other wire +// type. +- (NSData*)getBizarroData { + GPBUnknownFieldSet* bizarroFields = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + NSUInteger count = [unknownFields_ countOfFields]; + int32_t tags[count]; + [unknownFields_ getTags:tags]; + for (NSUInteger i = 0; i < count; ++i) { + int32_t tag = tags[i]; + GPBField* field = [unknownFields_ getField:tag]; + if (field.varintList.count == 0) { + // Original field is not a varint, so use a varint. + GPBField* varintField = + [[[GPBField alloc] initWithNumber:tag] autorelease]; + [varintField addVarint:1]; + [bizarroFields addField:varintField]; + } else { + // Original field *is* a varint, so use something else. + GPBField* fixed32Field = + [[[GPBField alloc] initWithNumber:tag] autorelease]; + [fixed32Field addFixed32:1]; + [bizarroFields addField:fixed32Field]; + } + } + + return [bizarroFields data]; +} + +- (void)testSerialize { + // Check that serializing the UnknownFieldSet produces the original data + // again. + NSData* data = [emptyMessage_ data]; + XCTAssertEqualObjects(allFieldsData_, data); +} + +- (void)testCopyFrom { + TestEmptyMessage* message = [TestEmptyMessage message]; + [message mergeFrom:emptyMessage_]; + + XCTAssertEqualObjects(emptyMessage_.data, message.data); +} + +- (void)testMergeFrom { + GPBUnknownFieldSet* set1 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + GPBField* field = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field addVarint:2]; + [set1 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:4]; + [set1 addField:field]; + + GPBUnknownFieldSet* set2 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + field = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field addVarint:1]; + [set2 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:3]; + [set2 addField:field]; + + GPBUnknownFieldSet* set3 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + field = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field addVarint:1]; + [set3 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:4]; + [set3 addField:field]; + + GPBUnknownFieldSet* set4 = [[[GPBUnknownFieldSet alloc] init] autorelease]; + field = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field addVarint:2]; + [set4 addField:field]; + field = [[[GPBField alloc] initWithNumber:3] autorelease]; + [field addVarint:3]; + [set4 addField:field]; + + TestEmptyMessage* source1 = [TestEmptyMessage message]; + [source1 setUnknownFields:set1]; + TestEmptyMessage* source2 = [TestEmptyMessage message]; + [source2 setUnknownFields:set2]; + TestEmptyMessage* source3 = [TestEmptyMessage message]; + [source3 setUnknownFields:set3]; + TestEmptyMessage* source4 = [TestEmptyMessage message]; + [source4 setUnknownFields:set4]; + + TestEmptyMessage* destination1 = [TestEmptyMessage message]; + [destination1 mergeFrom:source1]; + [destination1 mergeFrom:source2]; + + TestEmptyMessage* destination2 = [TestEmptyMessage message]; + [destination2 mergeFrom:source3]; + [destination2 mergeFrom:source4]; + + XCTAssertEqualObjects(destination1.data, destination2.data); +} + +- (void)testClearMessage { + TestEmptyMessage* message = [TestEmptyMessage message]; + [message mergeFrom:emptyMessage_]; + [message clear]; + XCTAssertEqual(message.serializedSize, (size_t)0); +} + +- (void)testParseKnownAndUnknown { + // Test mixing known and unknown fields when parsing. + GPBUnknownFieldSet* fields = [[unknownFields_ copy] autorelease]; + GPBField* field = [[[GPBField alloc] initWithNumber:123456] autorelease]; + [field addVarint:654321]; + [fields addField:field]; + + NSData* data = fields.data; + TestAllTypes* destination = [TestAllTypes parseFromData:data]; + + [self assertAllFieldsSet:destination repeatedCount:kGPBDefaultRepeatCount]; + XCTAssertEqual(destination.unknownFields.countOfFields, (NSUInteger)1); + + GPBField* field2 = [destination.unknownFields getField:123456]; + XCTAssertEqual(field2.varintList.count, (NSUInteger)1); + XCTAssertEqual(654321ULL, [field2.varintList valueAtIndex:0]); +} + +- (void)testWrongTypeTreatedAsUnknown { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing. + + NSData* bizarroData = [self getBizarroData]; + TestAllTypes* allTypesMessage = [TestAllTypes parseFromData:bizarroData]; + TestEmptyMessage* emptyMessage = [TestEmptyMessage parseFromData:bizarroData]; + + // All fields should have been interpreted as unknown, so the debug strings + // should be the same. + XCTAssertEqualObjects(emptyMessage.data, allTypesMessage.data); +} + +- (void)testUnknownExtensions { + // Make sure fields are properly parsed to the UnknownFieldSet even when + // they are declared as extension numbers. + + TestEmptyMessageWithExtensions* message = + [TestEmptyMessageWithExtensions parseFromData:allFieldsData_]; + + XCTAssertEqual(unknownFields_.countOfFields, + message.unknownFields.countOfFields); + XCTAssertEqualObjects(allFieldsData_, message.data); +} + +- (void)testWrongExtensionTypeTreatedAsUnknown { + // Test that fields of the wrong wire type are treated like unknown fields + // when parsing extensions. + + NSData* bizarroData = [self getBizarroData]; + TestAllExtensions* allExtensionsMessage = + [TestAllExtensions parseFromData:bizarroData]; + TestEmptyMessage* emptyMessage = [TestEmptyMessage parseFromData:bizarroData]; + + // All fields should have been interpreted as unknown, so the debug strings + // should be the same. + XCTAssertEqualObjects(emptyMessage.data, allExtensionsMessage.data); +} + +- (void)testLargeVarint { + GPBUnknownFieldSet* fields = [[unknownFields_ copy] autorelease]; + GPBField* field = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field addVarint:0x7FFFFFFFFFFFFFFFL]; + [fields addField:field]; + + NSData* data = [fields data]; + + GPBUnknownFieldSet* parsed = [[[GPBUnknownFieldSet alloc] init] autorelease]; + [parsed mergeFromData:data]; + GPBField* field2 = [parsed getField:1]; + XCTAssertEqual(field2.varintList.count, (NSUInteger)1); + XCTAssertEqual(0x7FFFFFFFFFFFFFFFULL, [field2.varintList valueAtIndex:0]); +} + +- (void)testMergingFields { + GPBField* field1 = [[[GPBField alloc] initWithNumber:1] autorelease]; + [field1 addVarint:1]; + [field1 addFixed32:2]; + [field1 addFixed64:3]; + [field1 addLengthDelimited:[NSData dataWithBytes:"hello" length:5]]; + [field1 addGroup:[[unknownFields_ copy] autorelease]]; + GPBField* field2 = [[[GPBField alloc] initWithNumber:2] autorelease]; + [field2 mergeFromField:field1]; + XCTAssertEqualObjects(field1, field2); +} + +@end diff --git a/objectivec/Tests/GPBUtilitiesTests.m b/objectivec/Tests/GPBUtilitiesTests.m new file mode 100644 index 00000000..02de0197 --- /dev/null +++ b/objectivec/Tests/GPBUtilitiesTests.m @@ -0,0 +1,363 @@ +// 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 + +#import "GPBUtilities_PackagePrivate.h" + +#import + +#import "GPBTestUtilities.h" + +#import "GPBDescriptor.h" +#import "GPBDescriptor_PackagePrivate.h" +#import "GPBMessage.h" + +#import "google/protobuf/MapUnittest.pbobjc.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestObjc.pbobjc.h" + +@interface UtilitiesTests : GPBTestCase +@end + +// Support code for testing +typedef struct { + uint32_t _has_storage_[1]; + BOOL aBool; + int32_t aInt32; + uint32_t aUInt32; + int64_t aInt64; + uint64_t aUInt64; + float aFloat; + double aDouble; + id aObject; + BOOL _hasTest; + BOOL stopper; + BOOL shouldNotBeCounted; + GPBInt32Array *anArray; +} ApplyFunctionsTest_Storage; + +@interface ApplyFunctionsTest : GPBMessage +@property(nonatomic, readwrite) BOOL aBool; +@property(nonatomic, readwrite) int32_t aInt32; +@property(nonatomic, readwrite) uint32_t aUInt32; +@property(nonatomic, readwrite) int64_t aInt64; +@property(nonatomic, readwrite) uint64_t aUInt64; +@property(nonatomic, readwrite) float aFloat; +@property(nonatomic, readwrite) double aDouble; +@property(nonatomic, readwrite, retain) id aObject; +@property(nonatomic, readwrite) BOOL _hasTest; +@property(nonatomic, readwrite) BOOL stopper; +@property(nonatomic, readwrite) BOOL shouldNotBeCounted; +@property(nonatomic, readwrite, retain) GPBInt32Array *anArray; +@end + +@implementation ApplyFunctionsTest + +@dynamic aBool, aInt32, aUInt32, aInt64, aUInt64, aFloat, aDouble, aObject; +@dynamic _hasTest, stopper, shouldNotBeCounted, anArray; + ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = NULL; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { +#define FIELD_ENTRY(NAME, INDEX) \ + { \ + .name = "a" #NAME, .hasIndex = INDEX, .type = GPBType##NAME, \ + .offset = offsetof(ApplyFunctionsTest_Storage, a##NAME), \ + } + FIELD_ENTRY(Bool, 1), + FIELD_ENTRY(Int32, 2), + FIELD_ENTRY(UInt32, 3), + FIELD_ENTRY(Int64, 4), + FIELD_ENTRY(UInt64, 5), + FIELD_ENTRY(Float, 6), + FIELD_ENTRY(Double, 7), +#undef FIELD_ENTRY + { + .name = "aObject", + .type = GPBTypeString, + .hasIndex = 8, + .offset = offsetof(ApplyFunctionsTest_Storage, aObject), + }, + { + .name = "stopper", + .type = GPBTypeBool, + .hasIndex = 9, + .offset = offsetof(ApplyFunctionsTest_Storage, stopper), + }, + { + .name = "shouldNotBeCounted", + .type = GPBTypeBool, + .hasIndex = 10, + .offset = offsetof(ApplyFunctionsTest_Storage, shouldNotBeCounted), + }, + { + .name = "anArray", + .type = GPBTypeInt32, + .hasIndex = 11, + .flags = GPBFieldRepeated, + .offset = offsetof(ApplyFunctionsTest_Storage, anArray), + }, + }; + descriptor = [GPBDescriptor + allocDescriptorForClass:[self class] + rootClass:Nil + file:nil + fields:fields + fieldCount:sizeof(fields) / + sizeof(GPBMessageFieldDescription) + oneofs:NULL + oneofCount:0 + enums:NULL + enumCount:0 + ranges:NULL + rangeCount:0 + storageSize:sizeof(ApplyFunctionsTest_Storage) + wireFormat:NO]; + } + return descriptor; +} + +@end + +typedef struct { + int calledBool; + int calledInt32; + int calledUInt32; + int calledInt64; + int calledUInt64; + int calledFloat; + int calledDouble; + int calledObject; + int hitCount; +} TestApplyFunctionsContext; + +// Really, who needs templates? +// Macro for testing apply functions. Declares a variety of different functions +// base on |NAME|. +#define TEST_APPLY_FUNCTIONS_FUNC(NAME) \ + static BOOL TestApplyFunction##NAME(GPBFieldDescriptor *field, \ + void *voidContext) { \ + TestApplyFunctionsContext *context = voidContext; \ + if (field->getSel_ == sel_getUid("stopper")) return NO; \ + context->called##NAME += 1; \ + context->hitCount += 1; \ + return YES; \ + } + +TEST_APPLY_FUNCTIONS_FUNC(Bool) +TEST_APPLY_FUNCTIONS_FUNC(Int32) +TEST_APPLY_FUNCTIONS_FUNC(UInt32) +TEST_APPLY_FUNCTIONS_FUNC(Int64) +TEST_APPLY_FUNCTIONS_FUNC(UInt64) +TEST_APPLY_FUNCTIONS_FUNC(Float) +TEST_APPLY_FUNCTIONS_FUNC(Double) +TEST_APPLY_FUNCTIONS_FUNC(Object) + +@implementation UtilitiesTests + +- (void)testRightShiftFunctions { + XCTAssertEqual((1UL << 31) >> 31, 1UL); + XCTAssertEqual((1 << 31) >> 31, -1); + XCTAssertEqual((1ULL << 63) >> 63, 1ULL); + XCTAssertEqual((1LL << 63) >> 63, -1LL); + + XCTAssertEqual(GPBLogicalRightShift32((1 << 31), 31), 1); + XCTAssertEqual(GPBLogicalRightShift64((1LL << 63), 63), 1LL); +} + +- (void)testMutability { + ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message]; + XCTAssertEqual(0, [foo_message aInt32]); + [foo_message setAInt32:100]; + XCTAssertEqual(100, [foo_message aInt32]); +} + +- (void)testSerializedSize { + ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message]; + [foo_message setAInt32:100]; + size_t size1 = [foo_message serializedSize]; + [foo_message setAInt64:100]; + size_t size2 = [foo_message serializedSize]; + + // Intentionally doing a pointer comparison. + XCTAssertNotEqual(size1, size2); +} + +- (void)testCopying { + ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message]; + [foo_message setAInt32:100]; + [foo_message setAObject:@"Happy"]; + ApplyFunctionsTest *foo = [[foo_message copy] autorelease]; + XCTAssertNotEqual(foo, foo_message); // Pointer comparision + XCTAssertEqualObjects(foo, foo_message); +} + +- (void)testApplyFunctions { + // Covers ApplyFunctionsToProtoVariables and + // ApplyFunctionsBasedOnEncodingType. + // This test depends on the layout of the ivars to be in the order + // declared in the interface. If this is not true, it will fail and will + // need to be rewritten to accomodate. + TestApplyFunctionsContext context; + memset(&context, 0, sizeof(context)); + GPBApplyFunctions foo = GPBAPPLY_FUNCTIONS_INIT(TestApplyFunction); + ApplyFunctionsTest *msg = [ApplyFunctionsTest message]; + GPBApplyFunctionsToMessageFields(&foo, msg, &context); + + // Only eight vars should be set. + // "stopper" should cause the loop to quit so it and shouldNotBeCounted should + // not be counted. + // "_hasTest" should be skipped over. + // Each of the vars should only be set once. + XCTAssertEqual(context.hitCount, 8); + XCTAssertEqual(context.calledBool, 1); + XCTAssertEqual(context.calledInt32, 1); + XCTAssertEqual(context.calledUInt32, 1); + XCTAssertEqual(context.calledInt64, 1); + XCTAssertEqual(context.calledUInt64, 1); + XCTAssertEqual(context.calledFloat, 1); + XCTAssertEqual(context.calledDouble, 1); + XCTAssertEqual(context.calledObject, 1); +} + +- (void)testGPBDecodeTextFormatName { + uint8_t decodeData[] = { + 0x6, + // An inlined string (first to make sure the leading null is handled + // correctly, and with a key of zero to check that). + 0x0, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0, + // All as is (00 op) + 0x1, 0x0A, 0x0, + // Underscore, upper + 9 (10 op) + 0x3, 0xCA, 0x0, + // Upper + 3 (10 op), underscore, upper + 5 (10 op) + 0x2, 0x44, 0xC6, 0x0, + // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op), + // underscore, lower + 0 (01 op) + 0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0, + // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op), + // underscore, lower + 3 (01 op), underscore, lower + 1 (01 op), + // underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 op), + // underscore, as is + 3 (00 op) + 0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0, + }; + NSString *inputStr = @"abcdefghIJ"; + + // Empty inputs + + XCTAssertNil(GPBDecodeTextFormatName(nil, 1, NULL)); + XCTAssertNil(GPBDecodeTextFormatName(decodeData, 1, NULL)); + XCTAssertNil(GPBDecodeTextFormatName(nil, 1, inputStr)); + + // Keys not found. + + XCTAssertNil(GPBDecodeTextFormatName(decodeData, 5, inputStr)); + XCTAssertNil(GPBDecodeTextFormatName(decodeData, -1, inputStr)); + + // Some name decodes. + + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1, inputStr), @"abcdefghIJ"); + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 2, inputStr), @"Abcd_EfghIJ"); + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 3, inputStr), @"_AbcdefghIJ"); + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 4, inputStr), @"ABCD__EfghI_j"); + + // An inlined string (and key of zero). + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 0, inputStr), @"zbcdefghIJ"); + + // Long name so multiple decode ops are needed. + inputStr = @"longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000"; + XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1000, inputStr), + @"long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000"); +} + +- (void)testTextFormat { + TestAllTypes *message = [TestAllTypes message]; + + // Not kGPBDefaultRepeatCount because we are comparing to golden master file + // which was generated with 2. + [self setAllFields:message repeatedCount:2]; + + NSString *result = GPBTextFormatForMessage(message, nil); + + NSString *fileName = @"text_format_unittest_data.txt"; + NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding]; + NSData *expectedData = + [self getDataFileNamed:fileName dataToWrite:resultData]; + NSString *expected = [[NSString alloc] initWithData:expectedData + encoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(expected, result); + [expected release]; +} + +- (void)testTextFormatExtra { + // -testTextFormat uses all protos with fields that don't require special + // handing for figuring out the names. The ObjC proto has a bunch of oddball + // field and enum names that require the decode info to get right, so this + // confirms they generated and decoded correctly. + + self_Class *message = [self_Class message]; + message.cmd = YES; + message.isProxy_p = YES; + message.subEnum = self_autorelease_RetainCount; + message.new_p.copy_p = @"foo"; + + NSString *expected = @"_cmd: true\n" + @"isProxy: true\n" + @"SubEnum: retainCount\n" + @"New {\n" + @" copy: \"foo\"\n" + @"}\n"; + NSString *result = GPBTextFormatForMessage(message, nil); + XCTAssertEqualObjects(expected, result); +} + +- (void)testTextFormatMaps { + TestMap *message = [TestMap message]; + + // Map iteration order doesn't have to be stable, so use only one entry. + [self setAllMapFields:message numEntries:1]; + + NSString *result = GPBTextFormatForMessage(message, nil); + + NSString *fileName = @"text_format_map_unittest_data.txt"; + NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding]; + NSData *expectedData = + [self getDataFileNamed:fileName dataToWrite:resultData]; + NSString *expected = [[NSString alloc] initWithData:expectedData + encoding:NSUTF8StringEncoding]; + XCTAssertEqualObjects(expected, result); + [expected release]; +} + +// TODO(thomasvl): add test with extensions once those format with correct names. + +@end diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m new file mode 100644 index 00000000..78f4e637 --- /dev/null +++ b/objectivec/Tests/GPBWellKnownTypesTest.m @@ -0,0 +1,102 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 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 "GPBWellKnownTypes.h" + +#import + +// A basically random interval into the future for testing with. +static const NSTimeInterval kFutureOffsetInterval = 15000; + +// Nanosecond time accuracy +static const NSTimeInterval kTimeAccuracy = 1e-9; + +@interface WellKnownTypesTest : XCTestCase +@end + +@implementation WellKnownTypesTest + +- (void)testTimeStamp { + // Test Creation. + NSDate *date = [NSDate date]; + GPBTimestamp *timeStamp = [[GPBTimestamp alloc] initWithDate:date]; + NSDate *timeStampDate = timeStamp.date; + + // Comparing timeIntervals instead of directly comparing dates because date + // equality requires the time intervals to be exactly the same, and the + // timeintervals go through a bit of floating point error as they are + // converted back and forth from the internal representation. + XCTAssertEqualWithAccuracy(date.timeIntervalSince1970, + timeStampDate.timeIntervalSince1970, + kTimeAccuracy); + + NSTimeInterval time = [date timeIntervalSince1970]; + GPBTimestamp *timeStamp2 = + [[GPBTimestamp alloc] initWithTimeIntervalSince1970:time]; + NSTimeInterval durationTime = timeStamp2.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [timeStamp release]; + + // Test Mutation. + date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval]; + timeStamp2.date = date; + timeStampDate = timeStamp2.date; + XCTAssertEqualWithAccuracy(date.timeIntervalSince1970, + timeStampDate.timeIntervalSince1970, + kTimeAccuracy); + + time = date.timeIntervalSince1970; + timeStamp2.timeIntervalSince1970 = time; + durationTime = timeStamp2.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [timeStamp2 release]; +} + +- (void)testDuration { + // Test Creation. + NSTimeInterval time = [[NSDate date] timeIntervalSince1970]; + GPBDuration *duration = + [[GPBDuration alloc] initWithTimeIntervalSince1970:time]; + NSTimeInterval durationTime = duration.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [duration release]; + + // Test Mutation. + GPBDuration *duration2 = + [[GPBDuration alloc] initWithTimeIntervalSince1970:time]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval]; + time = date.timeIntervalSince1970; + duration2.timeIntervalSince1970 = time; + durationTime = duration2.timeIntervalSince1970; + XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); + [duration2 release]; +} + +@end diff --git a/objectivec/Tests/GPBWireFormatTests.m b/objectivec/Tests/GPBWireFormatTests.m new file mode 100644 index 00000000..1344af08 --- /dev/null +++ b/objectivec/Tests/GPBWireFormatTests.m @@ -0,0 +1,246 @@ +// 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 "GPBTestUtilities.h" + +#import "GPBCodedInputStream.h" +#import "GPBMessage_PackagePrivate.h" +#import "GPBField_PackagePrivate.h" +#import "google/protobuf/Unittest.pbobjc.h" +#import "google/protobuf/UnittestMset.pbobjc.h" + +@interface WireFormatTests : GPBTestCase +@end + +@implementation WireFormatTests + +- (void)testSerialization { + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes]; + + [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSerializationPacked { + TestPackedTypes* message = + [self packedSetRepeatedCount:kGPBDefaultRepeatCount]; + + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestPackedTypes* message2 = [TestPackedTypes parseFromData:rawBytes]; + + [self assertPackedFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSerializeExtensions { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serealize a TestAllExtensions then parse it as TestAllTypes + // it should work. + + TestAllExtensions* message = + [self allExtensionsSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length); + + TestAllTypes* message2 = [TestAllTypes parseFromData:rawBytes]; + + [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + +- (void)testSerializePackedExtensions { + // TestPackedTypes and TestPackedExtensions should have compatible wire + // formats; check that they serialize to the same string. + TestPackedExtensions* message = + [self packedExtensionsSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + TestPackedTypes* message2 = + [self packedSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes2 = message2.data; + + XCTAssertEqualObjects(rawBytes, rawBytes2); +} + +- (void)testParseExtensions { + // TestAllTypes and TestAllExtensions should have compatible wire formats, + // so if we serialize a TestAllTypes then parse it as TestAllExtensions + // it should work. + + TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + GPBExtensionRegistry* registry = [self extensionRegistry]; + + TestAllExtensions* message2 = + [TestAllExtensions parseFromData:rawBytes extensionRegistry:registry]; + + [self assertAllExtensionsSet:message2 repeatedCount:kGPBDefaultRepeatCount]; +} + + +- (void) testExtensionsSerializedSize { + size_t allSet = [self allSetRepeatedCount:kGPBDefaultRepeatCount].serializedSize; + size_t extensionSet = [self allExtensionsSetRepeatedCount:kGPBDefaultRepeatCount].serializedSize; + XCTAssertEqual(allSet, extensionSet); +} + +- (void)testParsePackedExtensions { + // Ensure that packed extensions can be properly parsed. + TestPackedExtensions* message = + [self packedExtensionsSetRepeatedCount:kGPBDefaultRepeatCount]; + NSData* rawBytes = message.data; + + GPBExtensionRegistry* registry = [self extensionRegistry]; + + TestPackedExtensions* message2 = + [TestPackedExtensions parseFromData:rawBytes extensionRegistry:registry]; + + [self assertPackedExtensionsSet:message2 + repeatedCount:kGPBDefaultRepeatCount]; +} + +const int kUnknownTypeId = 1550055; + +- (void)testSerializeMessageSet { + // Set up a TestMessageSet with two known messages and an unknown one. + TestMessageSet* message_set = [TestMessageSet message]; + [[message_set getExtension:[TestMessageSetExtension1 messageSetExtension]] + setI:123]; + [[message_set getExtension:[TestMessageSetExtension2 messageSetExtension]] + setStr:@"foo"]; + GPBField* unknownField = + [[[GPBField alloc] initWithNumber:kUnknownTypeId] autorelease]; + [unknownField addLengthDelimited:[NSData dataWithBytes:"bar" length:3]]; + GPBUnknownFieldSet* unknownFieldSet = + [[[GPBUnknownFieldSet alloc] init] autorelease]; + [unknownFieldSet addField:unknownField]; + [message_set setUnknownFields:unknownFieldSet]; + + NSData* data = [message_set data]; + + // Parse back using RawMessageSet and check the contents. + RawMessageSet* raw = [RawMessageSet parseFromData:data]; + + XCTAssertEqual([raw.unknownFields countOfFields], (NSUInteger)0); + + XCTAssertEqual(raw.itemArray.count, (NSUInteger)3); + XCTAssertEqual([raw.itemArray[0] typeId], + [TestMessageSetExtension1 messageSetExtension].fieldNumber); + XCTAssertEqual([raw.itemArray[1] typeId], + [TestMessageSetExtension2 messageSetExtension].fieldNumber); + XCTAssertEqual([raw.itemArray[2] typeId], kUnknownTypeId); + + TestMessageSetExtension1* message1 = + [TestMessageSetExtension1 parseFromData:[raw.itemArray[0] message]]; + XCTAssertEqual(message1.i, 123); + + TestMessageSetExtension2* message2 = + [TestMessageSetExtension2 parseFromData:[raw.itemArray[1] message]]; + XCTAssertEqualObjects(message2.str, @"foo"); + + XCTAssertEqualObjects([raw.itemArray[2] message], + [NSData dataWithBytes:"bar" length:3]); +} + +- (void)testParseMessageSet { + // Set up a RawMessageSet with two known messages and an unknown one. + RawMessageSet* raw = [RawMessageSet message]; + + { + RawMessageSet_Item* item = [RawMessageSet_Item message]; + item.typeId = [TestMessageSetExtension1 messageSetExtension].fieldNumber; + TestMessageSetExtension1* message = [TestMessageSetExtension1 message]; + message.i = 123; + item.message = [message data]; + raw.itemArray = [NSMutableArray array]; + [raw.itemArray addObject:item]; + } + + { + RawMessageSet_Item* item = [RawMessageSet_Item message]; + item.typeId = [TestMessageSetExtension2 messageSetExtension].fieldNumber; + TestMessageSetExtension2* message = [TestMessageSetExtension2 message]; + message.str = @"foo"; + item.message = [message data]; + [raw.itemArray addObject:item]; + } + + { + RawMessageSet_Item* item = [RawMessageSet_Item message]; + item.typeId = kUnknownTypeId; + item.message = [NSData dataWithBytes:"bar" length:3]; + [raw.itemArray addObject:item]; + } + + NSData* data = [raw data]; + + // Parse as a TestMessageSet and check the contents. + TestMessageSet* messageSet = + [TestMessageSet parseFromData:data + extensionRegistry:[UnittestMsetRoot extensionRegistry]]; + + XCTAssertEqual( + [[messageSet + getExtension:[TestMessageSetExtension1 messageSetExtension]] i], + 123); + XCTAssertEqualObjects( + [[messageSet + getExtension:[TestMessageSetExtension2 messageSetExtension]] str], + @"foo"); + + XCTAssertEqual([messageSet.unknownFields countOfFields], (NSUInteger)1); + GPBField* unknownField = [messageSet.unknownFields getField:kUnknownTypeId]; + XCTAssertNotNil(unknownField); + XCTAssertEqual(unknownField.lengthDelimitedList.count, (NSUInteger)1); + XCTAssertEqualObjects(unknownField.lengthDelimitedList[0], + [NSData dataWithBytes:"bar" length:3]); +} + +- (void)assertFieldsInOrder:(NSData*)data { + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + int32_t previousTag = 0; + + while (YES) { + int32_t tag = [input readTag]; + if (tag == 0) { + break; + } + + XCTAssertGreaterThan(tag, previousTag); + [input skipField:tag]; + } +} + +@end diff --git a/objectivec/Tests/UnitTests-Bridging-Header.h b/objectivec/Tests/UnitTests-Bridging-Header.h new file mode 100644 index 00000000..46292fce --- /dev/null +++ b/objectivec/Tests/UnitTests-Bridging-Header.h @@ -0,0 +1,6 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h" +#import "google/protobuf/UnittestRuntimeProto3.pbobjc.h" diff --git a/objectivec/Tests/UnitTests-Info.plist b/objectivec/Tests/UnitTests-Info.plist new file mode 100644 index 00000000..65013556 --- /dev/null +++ b/objectivec/Tests/UnitTests-Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/objectivec/Tests/golden_message b/objectivec/Tests/golden_message new file mode 100644 index 00000000..7bceab41 Binary files /dev/null and b/objectivec/Tests/golden_message differ diff --git a/objectivec/Tests/golden_packed_fields_message b/objectivec/Tests/golden_packed_fields_message new file mode 100644 index 00000000..7bceab41 Binary files /dev/null and b/objectivec/Tests/golden_packed_fields_message differ diff --git a/objectivec/Tests/iOSTestHarness/AppDelegate.m b/objectivec/Tests/iOSTestHarness/AppDelegate.m new file mode 100644 index 00000000..8c4a586b --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/AppDelegate.m @@ -0,0 +1,35 @@ +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end + +@implementation AppDelegate + +@synthesize window; + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + #pragma unused (application, launchOptions) + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.backgroundColor = [UIColor whiteColor]; + [self.window makeKeyAndVisible]; + self.window.rootViewController = [[UIViewController alloc] init]; + + UILabel *label = + [[UILabel alloc] initWithFrame:CGRectMake(0, 200, CGRectGetWidth(self.window.frame), 40)]; + label.text = @"Protocol Buffer Test Harness"; + label.textAlignment = NSTextAlignmentCenter; + [self.window addSubview:label]; + + return YES; +} + +@end + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..ecd3584e --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "iPhone6.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "iPhone6@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "iPhone7@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "iPhone7@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "iPad6.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "iPad6@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "iPad7.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "iPad7@2x.png", + "scale" : "2x" + }, + { + "idiom" : "car", + "size" : "120x120", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png new file mode 100644 index 00000000..43da2ee4 Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png new file mode 100644 index 00000000..2ec93704 Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad6@2x.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png new file mode 100644 index 00000000..aec8bc1b Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png new file mode 100644 index 00000000..e39cc3e7 Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPad7@2x.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png new file mode 100644 index 00000000..5572d79f Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png new file mode 100644 index 00000000..2424997f Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone6@2x.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png new file mode 100644 index 00000000..10bfc3cf Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@2x.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png new file mode 100644 index 00000000..8d16f14d Binary files /dev/null and b/objectivec/Tests/iOSTestHarness/Images.xcassets/AppIcon.appiconset/iPhone7@3x.png differ diff --git a/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json b/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 00000000..5a296668 --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,49 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "minimum-system-version" : "7.0", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "minimum-system-version" : "7.0", + "extent" : "full-screen", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/objectivec/Tests/iOSTestHarness/Info.plist b/objectivec/Tests/iOSTestHarness/Info.plist new file mode 100644 index 00000000..31ab1578 --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.google.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + + diff --git a/objectivec/Tests/iOSTestHarness/LaunchScreen.xib b/objectivec/Tests/iOSTestHarness/LaunchScreen.xib new file mode 100644 index 00000000..22204bfe --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/LaunchScreen.xib @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings b/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..477b28ff --- /dev/null +++ b/objectivec/Tests/iOSTestHarness/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/objectivec/Tests/text_format_map_unittest_data.txt b/objectivec/Tests/text_format_map_unittest_data.txt new file mode 100644 index 00000000..ad1195e2 --- /dev/null +++ b/objectivec/Tests/text_format_map_unittest_data.txt @@ -0,0 +1,70 @@ +map_int32_int32 { + key: 100 + value: 1 +} +map_int64_int64 { + key: 101 + value: 1 +} +map_uint32_uint32 { + key: 102 + value: 1 +} +map_uint64_uint64 { + key: 103 + value: 1 +} +map_sint32_sint32 { + key: 104 + value: 1 +} +map_sint64_sint64 { + key: 105 + value: 1 +} +map_fixed32_fixed32 { + key: 106 + value: 1 +} +map_fixed64_fixed64 { + key: 107 + value: 1 +} +map_sfixed32_sfixed32 { + key: 108 + value: 1 +} +map_sfixed64_sfixed64 { + key: 109 + value: 1 +} +map_int32_float { + key: 110 + value: 1 +} +map_int32_double { + key: 111 + value: 1 +} +map_bool_bool { + key: true + value: false +} +map_string_string { + key: "112" + value: "1" +} +map_int32_bytes { + key: 113 + value: "\001\000\000\000" +} +map_int32_enum { + key: 114 + value: MAP_ENUM_BAZ +} +map_int32_foreign_message { + key: 115 + value { + c: 1 + } +} diff --git a/objectivec/Tests/text_format_unittest_data.txt b/objectivec/Tests/text_format_unittest_data.txt new file mode 100644 index 00000000..d10f1000 --- /dev/null +++ b/objectivec/Tests/text_format_unittest_data.txt @@ -0,0 +1,116 @@ +optional_int32: 101 +optional_int64: 102 +optional_uint32: 103 +optional_uint64: 104 +optional_sint32: 105 +optional_sint64: 106 +optional_fixed32: 107 +optional_fixed64: 108 +optional_sfixed32: 109 +optional_sfixed64: 110 +optional_float: 111 +optional_double: 112 +optional_bool: true +optional_string: "115" +optional_bytes: "\001\000\002\003\000\005" +OptionalGroup { + a: 117 +} +optional_nested_message { + bb: 118 +} +optional_foreign_message { + c: 119 +} +optional_import_message { + d: 120 +} +optional_nested_enum: BAZ +optional_foreign_enum: FOREIGN_BAZ +optional_import_enum: IMPORT_BAZ +optional_string_piece: "124" +optional_cord: "125" +repeated_int32: 201 +repeated_int32: 301 +repeated_int64: 202 +repeated_int64: 302 +repeated_uint32: 203 +repeated_uint32: 303 +repeated_uint64: 204 +repeated_uint64: 304 +repeated_sint32: 205 +repeated_sint32: 305 +repeated_sint64: 206 +repeated_sint64: 306 +repeated_fixed32: 207 +repeated_fixed32: 307 +repeated_fixed64: 208 +repeated_fixed64: 308 +repeated_sfixed32: 209 +repeated_sfixed32: 309 +repeated_sfixed64: 210 +repeated_sfixed64: 310 +repeated_float: 211 +repeated_float: 311 +repeated_double: 212 +repeated_double: 312 +repeated_bool: false +repeated_bool: true +repeated_string: "215" +repeated_string: "315" +repeated_bytes: "\330\000\000\000" +repeated_bytes: "<\001\000\000" +RepeatedGroup { + a: 217 +} +RepeatedGroup { + a: 317 +} +repeated_nested_message { + bb: 218 +} +repeated_nested_message { + bb: 318 +} +repeated_foreign_message { + c: 219 +} +repeated_foreign_message { + c: 319 +} +repeated_import_message { + d: 220 +} +repeated_import_message { + d: 320 +} +repeated_nested_enum: BAZ +repeated_nested_enum: BAR +repeated_foreign_enum: FOREIGN_BAZ +repeated_foreign_enum: FOREIGN_BAR +repeated_import_enum: IMPORT_BAZ +repeated_import_enum: IMPORT_BAR +repeated_string_piece: "224" +repeated_string_piece: "324" +repeated_cord: "225" +repeated_cord: "325" +default_int32: 401 +default_int64: 402 +default_uint32: 403 +default_uint64: 404 +default_sint32: 405 +default_sint64: 406 +default_fixed32: 407 +default_fixed64: 408 +default_sfixed32: 409 +default_sfixed64: 410 +default_float: 411 +default_double: 412 +default_bool: false +default_string: "415" +default_bytes: "\240\001\000\000" +default_nested_enum: FOO +default_foreign_enum: FOREIGN_FOO +default_import_enum: IMPORT_FOO +default_string_piece: "424" +default_cord: "425" diff --git a/objectivec/Tests/unittest_cycle.proto b/objectivec/Tests/unittest_cycle.proto new file mode 100644 index 00000000..5f6f56a1 --- /dev/null +++ b/objectivec/Tests/unittest_cycle.proto @@ -0,0 +1,58 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +syntax = "proto2"; + +package protobuf_unittest; + +// Cycles in the Message graph can cause problems for the mutable classes +// since the properties on the mutable class change types. This file just +// needs to generate source, and that source must compile, to ensure the +// generated source works for this sort of case. + +// You can't make a object graph that spans files, so this can only be done +// within a single proto file. + +message CycleFoo { + optional CycleFoo a_foo = 1; + optional CycleBar a_bar = 2; + optional CycleBaz a_baz = 3; +} + +message CycleBar { + optional CycleBar a_bar = 1; + optional CycleBaz a_baz = 2; + optional CycleFoo a_foo = 3; +} + +message CycleBaz { + optional CycleBaz a_baz = 1; + optional CycleFoo a_foo = 2; + optional CycleBar a_bar = 3; +} diff --git a/objectivec/Tests/unittest_filter.proto b/objectivec/Tests/unittest_filter.proto new file mode 100644 index 00000000..1398dfc8 --- /dev/null +++ b/objectivec/Tests/unittest_filter.proto @@ -0,0 +1,71 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 Google Inc. All rights reserved. +// +// 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. + +syntax = "proto2"; + +package protobuf_unittest; + + +message Keep { +} + +message Remove { +} + +message RemoveJustKidding { +} + +message Other { + optional Keep a = 1; + optional Remove b = 2; +} + +enum RemoveEnum { + RemoveValue = 1; +} + +enum KeepEnum { + KeepValue = 1; +} + +message RemoveEnumMessage { + enum KeepEnumInside { + KeepValue = 1; + } + + enum RemoveEnumInside { + RemoveValue = 1; + } + + message KeepNestedInside { + } + + message RemoveNestedInside { + } +} diff --git a/objectivec/Tests/unittest_name_mangling.proto b/objectivec/Tests/unittest_name_mangling.proto new file mode 100644 index 00000000..aadad6d6 --- /dev/null +++ b/objectivec/Tests/unittest_name_mangling.proto @@ -0,0 +1,37 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +syntax = "proto2"; + +option objc_class_prefix = "ABC"; + +package protobuf_unittest; + +// TODO(thomasvl): Add tests for the special cases in name mangling. + diff --git a/objectivec/Tests/unittest_objc.proto b/objectivec/Tests/unittest_objc.proto new file mode 100644 index 00000000..d288a30d --- /dev/null +++ b/objectivec/Tests/unittest_objc.proto @@ -0,0 +1,389 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2011 Google Inc. All rights reserved. +// +// 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. + +syntax = "proto2"; + +import "google/protobuf/unittest.proto"; + +package protobuf_unittest; + +// Using the messages in unittest.proto, setup for recursive cases for testing +// extensions at various depths. +extend TestAllExtensions { + optional TestAllExtensions recursive_extension = 86; +} + +// Recursive message to for testing autocreators at different depths. +message TestRecursiveMessageWithRepeatedField { + optional TestRecursiveMessageWithRepeatedField a = 1; + repeated int32 i = 2; + repeated string str = 3; +} + +// Recursive message and extension to for testing autocreators at different +// depths. +message TestRecursiveExtension { + optional TestRecursiveExtension recursive_sub_message = 1; + repeated int32 repeated_value = 2; + extensions 1000 to max; +} + +extend TestRecursiveExtension { + optional TestRecursiveExtension recursive_message_extension = 1000; +} + +message self { + message super { + optional int32 description = 1; + } + + enum autorelease { + retain = 1; + release = 2; + retainCount = 3; + } + + // Singular + optional bool id = 1; + optional bool _cmd = 2; + optional bool in = 3; + optional bool out = 4; + optional bool inout = 5; + optional bool bycopy = 6; + optional bool byref = 7; + optional bool oneway = 8; + optional bool dealloc = 9; + optional bool zone = 10; + optional bool isProxy = 11; + optional bool copy = 12; + optional bool readonly = 13; + optional bool default = 14; + optional bool assign = 15; + optional bool getter = 16; + optional bool setter = 17; + optional bool weak = 18; + optional bool public = 19; + optional bool case = 20; + + optional autorelease SubEnum = 25; + + optional group New = 50 { + optional string copy = 51; + } + optional group MutableCopy = 60 { + optional int32 extensionRegistry = 61; + } + + extensions 90 to 94; + +} + +enum retain { + count = 4; + initialized = 5; + serializedSize = 6; +} + +// EnumValueShortName: The short names shouldn't get suffixes/prefixes. +enum Foo { + SERIALIZED_SIZE = 1; + SIZE = 2; + OTHER = 3; +} + +// EnumValueShortName: The enum name gets a prefix. +enum Category { + RED = 1; + BLUE = 2; +} + +// EnumValueShortName: Twist case, full name gets PB, but the short names +// should still end up correct. +enum Time { + BASE = 1; + RECORD = 2; + SOMETHING_ELSE = 3; +} + +extend self { + repeated int32 debugDescription = 90 [packed = true]; + repeated int64 finalize = 91 [packed = true]; + repeated uint32 hash = 92 [packed = true]; + repeated uint64 classForCoder = 93 [packed = true]; + repeated sint32 byref = 94 [packed = true]; +} + +// Test handing of fields that start with init* since Xcode 5's ARC support +// doesn't like messages that look like initializers but aren't. +message ObjCInitFoo { + optional string init_val = 11; + optional int32 init_size = 12; + optional self init_self = 13; + + repeated string init_vals = 21; + repeated int32 init_sizes = 22; + repeated self init_selfs = 23; +} + +// Test handling of fields that start with retained names. +message ObjCRetainedFoo { + optional string new_val_lower_complex = 11; + optional string new_Val_upper_complex = 12; + optional string newvalue_lower_no_underscore_complex = 13; + optional string newValue_upper_no_underscore_complex = 14; + + optional int32 new_val_lower_primitive = 15; + optional int32 new_Val_upper_primitive = 16; + optional int32 newvalue_lower_no_underscore_primitive = 17; + optional int32 newValue_upper_no_underscore_primitive = 18; + + optional self new_val_lower_message = 19; + optional self new_Val_upper_message = 20; + optional self newvalue_lower_no_underscore_message = 21; + optional self newValue_upper_no_underscore_message = 22; + + optional Foo new_val_lower_enum = 23; + optional Foo new_Val_upper_enum = 24; + optional Foo newvalue_lower_no_underscore_enum = 25; + optional Foo newValue_upper_no_underscore_enum = 26; + + repeated string new_val_lower_complex_repeated = 111; + repeated string new_Val_upper_complex_repeated = 112; + repeated string newvalue_lower_no_underscore_complex_repeated = 113; + repeated string newValue_upper_no_underscore_complex_repeated = 114; + + repeated int32 new_val_lower_primitive_repeated = 115; + repeated int32 new_Val_upper_primitive_repeated = 116; + repeated int32 newvalue_lower_no_underscore_primitive_repeated = 117; + repeated int32 newValue_upper_no_underscore_primitive_repeated = 118; + + repeated self new_val_lower_message_repeated = 119; + repeated self new_Val_upper_message_repeated = 120; + repeated self newvalue_lower_no_underscore_message_repeated = 121; + repeated self newValue_upper_no_underscore_message_repeated = 122; + + repeated Foo new_val_lower_enum_repeated = 123; + repeated Foo new_Val_upper_enum_repeated = 124; + repeated Foo newvalue_lower_no_underscore_enum_repeated = 125; + repeated Foo newValue_upper_no_underscore_enum_repeated = 126; + + optional string alloc_val_lower_complex = 211; + optional string alloc_Val_upper_complex = 212; + optional string allocvalue_lower_no_underscore_complex = 213; + optional string allocValue_upper_no_underscore_complex = 214; + + optional int32 alloc_val_lower_primitive = 215; + optional int32 alloc_Val_upper_primitive = 216; + optional int32 allocvalue_lower_no_underscore_primitive = 217; + optional int32 allocValue_upper_no_underscore_primitive = 218; + + optional self alloc_val_lower_message = 219; + optional self alloc_Val_upper_message = 220; + optional self allocvalue_lower_no_underscore_message = 221; + optional self allocValue_upper_no_underscore_message = 222; + + optional Foo alloc_val_lower_enum = 223; + optional Foo alloc_Val_upper_enum = 224; + optional Foo allocvalue_lower_no_underscore_enum = 225; + optional Foo allocValue_upper_no_underscore_enum = 226; + + repeated string alloc_val_lower_complex_repeated = 311; + repeated string alloc_Val_upper_complex_repeated = 312; + repeated string allocvalue_lower_no_underscore_complex_repeated = 313; + repeated string allocValue_upper_no_underscore_complex_repeated = 314; + + repeated int32 alloc_val_lower_primitive_repeated = 315; + repeated int32 alloc_Val_upper_primitive_repeated = 316; + repeated int32 allocvalue_lower_no_underscore_primitive_repeated = 317; + repeated int32 allocValue_upper_no_underscore_primitive_repeated = 318; + + repeated self alloc_val_lower_message_repeated = 319; + repeated self alloc_Val_upper_message_repeated = 320; + repeated self allocvalue_lower_no_underscore_message_repeated = 321; + repeated self allocValue_upper_no_underscore_message_repeated = 322; + + repeated Foo alloc_val_lower_enum_repeated = 323; + repeated Foo alloc_Val_upper_enum_repeated = 324; + repeated Foo allocvalue_lower_no_underscore_enum_repeated = 325; + repeated Foo allocValue_upper_no_underscore_enum_repeated = 326; + + optional string copy_val_lower_complex = 411; + optional string copy_Val_upper_complex = 412; + optional string copyvalue_lower_no_underscore_complex = 413; + optional string copyValue_upper_no_underscore_complex = 414; + + optional int32 copy_val_lower_primitive = 415; + optional int32 copy_Val_upper_primitive = 416; + optional int32 copyvalue_lower_no_underscore_primitive = 417; + optional int32 copyValue_upper_no_underscore_primitive = 418; + + optional self copy_val_lower_message = 419; + optional self copy_Val_upper_message = 420; + optional self copyvalue_lower_no_underscore_message = 421; + optional self copyValue_upper_no_underscore_message = 422; + + optional Foo copy_val_lower_enum = 423; + optional Foo copy_Val_upper_enum = 424; + optional Foo copyvalue_lower_no_underscore_enum = 425; + optional Foo copyValue_upper_no_underscore_enum = 426; + + repeated string copy_val_lower_complex_repeated = 511; + repeated string copy_Val_upper_complex_repeated = 512; + repeated string copyvalue_lower_no_underscore_complex_repeated = 513; + repeated string copyValue_upper_no_underscore_complex_repeated = 514; + + repeated int32 copy_val_lower_primitive_repeated = 515; + repeated int32 copy_Val_upper_primitive_repeated = 516; + repeated int32 copyvalue_lower_no_underscore_primitive_repeated = 517; + repeated int32 copyValue_upper_no_underscore_primitive_repeated = 518; + + repeated self copy_val_lower_message_repeated = 519; + repeated self copy_Val_upper_message_repeated = 520; + repeated self copyvalue_lower_no_underscore_message_repeated = 521; + repeated self copyValue_upper_no_underscore_message_repeated = 522; + + repeated Foo copy_val_lower_enum_repeated = 523; + repeated Foo copy_Val_upper_enum_repeated = 524; + repeated Foo copyvalue_lower_no_underscore_enum_repeated = 525; + repeated Foo copyValue_upper_no_underscore_enum_repeated = 526; + + optional string mutableCopy_val_lower_complex = 611; + optional string mutableCopy_Val_upper_complex = 612; + optional string mutableCopyvalue_lower_no_underscore_complex = 613; + optional string mutableCopyValue_upper_no_underscore_complex = 614; + + optional int32 mutableCopy_val_lower_primitive = 615; + optional int32 mutableCopy_Val_upper_primitive = 616; + optional int32 mutableCopyvalue_lower_no_underscore_primitive = 617; + optional int32 mutableCopyValue_upper_no_underscore_primitive = 618; + + optional self mutableCopy_val_lower_message = 619; + optional self mutableCopy_Val_upper_message = 620; + optional self mutableCopyvalue_lower_no_underscore_message = 621; + optional self mutableCopyValue_upper_no_underscore_message = 622; + + optional Foo mutableCopy_val_lower_enum = 623; + optional Foo mutableCopy_Val_upper_enum = 624; + optional Foo mutableCopyvalue_lower_no_underscore_enum = 625; + optional Foo mutableCopyValue_upper_no_underscore_enum = 626; + + repeated string mutableCopy_val_lower_complex_repeated = 711; + repeated string mutableCopy_Val_upper_complex_repeated = 712; + repeated string mutableCopyvalue_lower_no_underscore_complex_repeated = 713; + repeated string mutableCopyValue_upper_no_underscore_complex_repeated = 714; + + repeated int32 mutableCopy_val_lower_primitive_repeated = 715; + repeated int32 mutableCopy_Val_upper_primitive_repeated = 716; + repeated int32 mutableCopyvalue_lower_no_underscore_primitive_repeated = 717; + repeated int32 mutableCopyValue_upper_no_underscore_primitive_repeated = 718; + + repeated self mutableCopy_val_lower_message_repeated = 719; + repeated self mutableCopy_Val_upper_message_repeated = 720; + repeated self mutableCopyvalue_lower_no_underscore_message_repeated = 721; + repeated self mutableCopyValue_upper_no_underscore_message_repeated = 722; + + repeated Foo mutableCopy_val_lower_enum_repeated = 723; + repeated Foo mutableCopy_Val_upper_enum_repeated = 724; + repeated Foo mutableCopyvalue_lower_no_underscore_enum_repeated = 725; + repeated Foo mutableCopyValue_upper_no_underscore_enum_repeated = 726; +} + +// Test handling of fields that are the retained names. +message ObjCRetainedComplex { + optional string new = 1; + optional string alloc = 2; + optional string copy = 3; + optional string mutableCopy = 4; +} + +message ObjCRetainedComplexRepeated { + repeated string new = 1; + repeated string alloc = 2; + repeated string copy = 3; + repeated string mutableCopy = 4; +} + +message ObjCRetainedPrimitive { + optional int32 new = 1; + optional int32 alloc = 2; + optional int32 copy = 3; + optional int32 mutableCopy = 4; +} + +message ObjCRetainedPrimitiveRepeated { + repeated int32 new = 1; + repeated int32 alloc = 2; + repeated int32 copy = 3; + repeated int32 mutableCopy = 4; +} + +message ObjCRetainedMessage { + optional self new = 1; + optional self alloc = 2; + optional self copy = 3; + optional self mutableCopy = 4; +} + +message ObjCRetainedMessageRepeated { + repeated self new = 1; + repeated self alloc = 2; + repeated self copy = 3; + repeated self mutableCopy = 4; +} + +// Test Handling some MacTypes +message Point { + message Rect { + optional int32 TimeValue = 1; + } +} + +// Test some weird defaults that we see in protos. +message ObjcWeirdDefaults { + // Set default values that match the protocol buffer defined defaults to + // confirm hasDefault and the default values are set correctly. + optional string foo = 1 [default = ""]; + optional bytes bar = 2 [default = ""]; +} + +// Used to confirm negative enum values work as expected. +message EnumTestMsg { + enum MyEnum { + ZERO = 0; + ONE = 1; + TWO = 2; + NEG_ONE = -1; + NEG_TWO = -2; + } + optional MyEnum foo = 1; + optional MyEnum bar = 2 [default = ONE]; + optional MyEnum baz = 3 [default = NEG_ONE]; + + repeated MyEnum mumble = 4; +} diff --git a/objectivec/Tests/unittest_runtime_proto2.proto b/objectivec/Tests/unittest_runtime_proto2.proto new file mode 100644 index 00000000..f9fd3c35 --- /dev/null +++ b/objectivec/Tests/unittest_runtime_proto2.proto @@ -0,0 +1,108 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +syntax = "proto2"; + +package protobuf_unittest; + +message Message2 { + enum Enum { + FOO = 0; + BAR = 1; + BAZ = 2; + EXTRA_2 = 20; + } + + optional int32 optional_int32 = 1; + optional int64 optional_int64 = 2; + optional uint32 optional_uint32 = 3; + optional uint64 optional_uint64 = 4; + optional sint32 optional_sint32 = 5; + optional sint64 optional_sint64 = 6; + optional fixed32 optional_fixed32 = 7; + optional fixed64 optional_fixed64 = 8; + optional sfixed32 optional_sfixed32 = 9; + optional sfixed64 optional_sfixed64 = 10; + optional float optional_float = 11; + optional double optional_double = 12; + optional bool optional_bool = 13; + optional string optional_string = 14; + optional bytes optional_bytes = 15; + optional group OptionalGroup = 16 { + optional int32 a = 17; + } + optional Message2 optional_message = 18; + optional Enum optional_enum = 19; + + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + repeated group RepeatedGroup = 46 { + optional int32 a = 47; + } + repeated Message2 repeated_message = 48; + repeated Enum repeated_enum = 49; + repeated Enum repeated_packed_enum = 50 [packed=true]; + + oneof o { + int32 oneof_int32 = 51 [default = 100]; + int64 oneof_int64 = 52 [default = 101]; + uint32 oneof_uint32 = 53 [default = 102]; + uint64 oneof_uint64 = 54 [default = 103]; + sint32 oneof_sint32 = 55 [default = 104]; + sint64 oneof_sint64 = 56 [default = 105]; + fixed32 oneof_fixed32 = 57 [default = 106]; + fixed64 oneof_fixed64 = 58 [default = 107]; + sfixed32 oneof_sfixed32 = 59 [default = 108]; + sfixed64 oneof_sfixed64 = 60 [default = 109]; + float oneof_float = 61 [default = 110]; + double oneof_double = 62 [default = 111]; + bool oneof_bool = 63 [default = true]; + string oneof_string = 64 [default = "string"]; + bytes oneof_bytes = 65 [default = "data"]; + group OneofGroup = 66 { + optional int32 a = 67; + optional int32 b = 167; + } + Message2 oneof_message = 68; + Enum oneof_enum = 69 [default = BAZ]; + } +} diff --git a/objectivec/Tests/unittest_runtime_proto3.proto b/objectivec/Tests/unittest_runtime_proto3.proto new file mode 100644 index 00000000..b6a2f4dc --- /dev/null +++ b/objectivec/Tests/unittest_runtime_proto3.proto @@ -0,0 +1,101 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +syntax = "proto3"; + +package protobuf_unittest; + +message Message3 { + enum Enum { + FOO = 0; + BAR = 1; + BAZ = 2; + EXTRA_3 = 30; + } + + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + // No 'group' in proto3. + Message3 optional_message = 18; + Enum optional_enum = 19; + + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + // No 'group' in proto3. + repeated Message3 repeated_message = 48; + repeated Enum repeated_enum = 49; + repeated Enum repeated_packed_enum = 50 [packed=true]; + + oneof o { + int32 oneof_int32 = 51; + int64 oneof_int64 = 52; + uint32 oneof_uint32 = 53; + uint64 oneof_uint64 = 54; + sint32 oneof_sint32 = 55; + sint64 oneof_sint64 = 56; + fixed32 oneof_fixed32 = 57; + fixed64 oneof_fixed64 = 58; + sfixed32 oneof_sfixed32 = 59; + sfixed64 oneof_sfixed64 = 60; + float oneof_float = 61; + double oneof_double = 62; + bool oneof_bool = 63; + string oneof_string = 64; + bytes oneof_bytes = 65; + // No 'group' in proto3. + Message3 oneof_message = 68; + Enum oneof_enum = 69; + } +} -- cgit v1.2.3