1// Protocol Buffers - Google's data interchange format 2// Copyright 2015 Google Inc. All rights reserved. 3// 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file or at 6// https://developers.google.com/open-source/licenses/bsd 7 8//%PDDM-DEFINE TEST_FOR_POD_KEY(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4) 9//%TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4) 10//%TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, Object, NSString*, @"abc", @"def", @"ghi", @"jkl") 11 12//%PDDM-DEFINE TESTS_FOR_POD_VALUES(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) 13//%TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP) 14//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt32, uint32_t, , 100U, 101U, 102U, 103U) 15//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int32, int32_t, , 200, 201, 202, 203) 16//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, UInt64, uint64_t, , 300U, 301U, 302U, 303U) 17//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Int64, int64_t, , 400, 401, 402, 403) 18//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Bool, BOOL, , YES, YES, NO, NO) 19//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Float, float, , 500.f, 501.f, 502.f, 503.f) 20//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Double, double, , 600., 601., 602., 603.) 21//%TESTS_FOR_POD_VALUE(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, Raw, 700, 701, 702, 703) 22//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) 23 24//%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) 25//%TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, , value, POD, VACCESSOR, VAL1, VAL2, VAL3, VAL4) 26 27//%PDDM-DEFINE TESTS_FOR_POD_KEY_OBJECT_VALUE(KEY_NAME, KEY_TYPE, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VAL1, VAL2, VAL3, VAL4) 28//%TESTS_COMMON(KEY_NAME, KEY_TYPE, , , KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, Objects, object, OBJECT, , VAL1, VAL2, VAL3, VAL4) 29 30//%PDDM-DEFINE DICTIONARY_CLASS_DECLPOD(KEY_NAME, VALUE_NAME, VALUE_TYPE) 31//%GPB##KEY_NAME##VALUE_NAME##Dictionary 32//%PDDM-DEFINE DICTIONARY_CLASS_DECLEnum(KEY_NAME, VALUE_NAME, VALUE_TYPE) 33//%GPB##KEY_NAME##VALUE_NAME##Dictionary 34//%PDDM-DEFINE DICTIONARY_CLASS_DECLOBJECT(KEY_NAME, VALUE_NAME, VALUE_TYPE) 35//%GPB##KEY_NAME##VALUE_NAME##Dictionary<VALUE_TYPE> 36 37//%PDDM-DEFINE TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, VALUE_NAME, VALUE_TYPE, VSUFFIX, VNAME, VHELPER, VACCESSOR, VAL1, VAL2, VAL3, VAL4) 38//%#pragma mark - KEY_NAME -> VALUE_NAME 39//% 40//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase 41//%@end 42//% 43//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests 44//% 45//%- (void)testEmpty { 46//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; 47//% XCTAssertNotNil(dict); 48//% XCTAssertEqual(dict.count, 0U); 49//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY1) 50//% [dict enumerateKeysAnd##VALUE_NAME$u##sUsingBlock:^(__unused KEY_TYPE KisP##aKey, __unused VALUE_TYPE a##VNAME$u, __unused BOOL *stop) { 51//% XCTFail(@"Shouldn't get here!"); 52//% }]; 53//% [dict release]; 54//%} 55//% 56//%- (void)testOne { 57//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; 58//% [dict set##VALUE_NAME$u##:VAL1 forKey:KEY1]; 59//% XCTAssertNotNil(dict); 60//% XCTAssertEqual(dict.count, 1U); 61//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 62//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 63//% [dict enumerateKeysAnd##VALUE_NAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) { 64//% XCTAssertEqual##KSUFFIX(aKey, KEY1); 65//% XCTAssertEqual##VSUFFIX(a##VNAME$u, VAL1); 66//% XCTAssertNotEqual(stop, NULL); 67//% }]; 68//% [dict release]; 69//%} 70//% 71//%- (void)testBasics { 72//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 }; 73//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3 }; 74//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 75//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME$u##s:k##VNAME$u##s 76//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 77//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 78//% XCTAssertNotNil(dict); 79//% XCTAssertEqual(dict.count, 3U); 80//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 81//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 82//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 83//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY4) 84//% 85//% __block NSUInteger idx = 0; 86//% KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP)); 87//% VALUE_TYPE *seen##VNAME$u##s = malloc(3 * sizeof(VALUE_TYPE)); 88//% [dict enumerateKeysAnd##VALUE_NAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) { 89//% XCTAssertLessThan(idx, 3U); 90//% seenKeys[idx] = aKey; 91//% seen##VNAME$u##s[idx] = a##VNAME$u##; 92//% XCTAssertNotEqual(stop, NULL); 93//% ++idx; 94//% }]; 95//% for (int i = 0; i < 3; ++i) { 96//% BOOL foundKey = NO; 97//% for (int j = 0; (j < 3) && !foundKey; ++j) { 98//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { 99//% foundKey = YES; 100//% XCTAssertEqual##VSUFFIX(k##VNAME$u##s[i], seen##VNAME$u##s[j], @"i = %d, j = %d", i, j); 101//% } 102//% } 103//% XCTAssertTrue(foundKey, @"i = %d", i); 104//% } 105//% free(seenKeys); 106//% free(seen##VNAME$u##s); 107//% 108//% // Stopping the enumeration. 109//% idx = 0; 110//% [dict enumerateKeysAnd##VALUE_NAME$u##sUsingBlock:^(__unused KEY_TYPE KisP##aKey, __unused VALUE_TYPE a##VNAME$u, BOOL *stop) { 111//% if (idx == 1) *stop = YES; 112//% XCTAssertNotEqual(idx, 2U); 113//% ++idx; 114//% }]; 115//% [dict release]; 116//%} 117//% 118//%- (void)testEquality { 119//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 }; 120//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 }; 121//% const VALUE_TYPE k##VNAME$u##s1[] = { VAL1, VAL2, VAL3 }; 122//% const VALUE_TYPE k##VNAME$u##s2[] = { VAL1, VAL4, VAL3 }; 123//% const VALUE_TYPE k##VNAME$u##s3[] = { VAL1, VAL2, VAL3, VAL4 }; 124//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 = 125//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s1 126//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 127//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s1)]; 128//% XCTAssertNotNil(dict1); 129//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime = 130//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s1 131//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 132//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s1)]; 133//% XCTAssertNotNil(dict1prime); 134//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 135//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s2 136//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 137//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s2)]; 138//% XCTAssertNotNil(dict2); 139//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 = 140//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s1 141//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys2 142//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s1)]; 143//% XCTAssertNotNil(dict3); 144//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 = 145//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s3 146//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 147//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s3)]; 148//% XCTAssertNotNil(dict4); 149//% 150//% // 1/1Prime should be different objects, but equal. 151//% XCTAssertNotEqual(dict1, dict1prime); 152//% XCTAssertEqualObjects(dict1, dict1prime); 153//% // Equal, so they must have same hash. 154//% XCTAssertEqual([dict1 hash], [dict1prime hash]); 155//% 156//% // 2 is same keys, different ##VNAME##s; not equal. 157//% XCTAssertNotEqualObjects(dict1, dict2); 158//% 159//% // 3 is different keys, same ##VNAME##s; not equal. 160//% XCTAssertNotEqualObjects(dict1, dict3); 161//% 162//% // 4 extra pair; not equal 163//% XCTAssertNotEqualObjects(dict1, dict4); 164//% 165//% [dict1 release]; 166//% [dict1prime release]; 167//% [dict2 release]; 168//% [dict3 release]; 169//% [dict4 release]; 170//%} 171//% 172//%- (void)testCopy { 173//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 174//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 }; 175//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 176//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 177//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 178//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 179//% XCTAssertNotNil(dict); 180//% 181//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy]; 182//% XCTAssertNotNil(dict2); 183//% 184//% // Should be new object but equal. 185//% XCTAssertNotEqual(dict, dict2); 186//% XCTAssertEqualObjects(dict, dict2); 187//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); 188//% 189//% [dict2 release]; 190//% [dict release]; 191//%} 192//% 193//%- (void)testDictionaryFromDictionary { 194//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 195//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 }; 196//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 197//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 198//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 199//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 200//% XCTAssertNotNil(dict); 201//% 202//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 203//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithDictionary:dict]; 204//% XCTAssertNotNil(dict2); 205//% 206//% // Should be new pointer, but equal objects. 207//% XCTAssertNotEqual(dict, dict2); 208//% XCTAssertEqualObjects(dict, dict2); 209//% [dict2 release]; 210//% [dict release]; 211//%} 212//% 213//%- (void)testAdds { 214//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; 215//% XCTAssertNotNil(dict); 216//% 217//% XCTAssertEqual(dict.count, 0U); 218//% [dict set##VALUE_NAME##:VAL1 forKey:KEY1]; 219//% XCTAssertEqual(dict.count, 1U); 220//% 221//% const KEY_TYPE KisP##kKeys[] = { KEY2, KEY3, KEY4 }; 222//% const VALUE_TYPE k##VNAME$u##s[] = { VAL2, VAL3, VAL4 }; 223//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 224//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 225//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 226//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 227//% XCTAssertNotNil(dict2); 228//% [dict add##VACCESSOR##EntriesFromDictionary:dict2]; 229//% XCTAssertEqual(dict.count, 4U); 230//% 231//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 232//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 233//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 234//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY4, VAL4) 235//% [dict2 release]; 236//% [dict release]; 237//%} 238//% 239//%- (void)testRemove { 240//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 241//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 }; 242//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 243//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 244//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 245//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 246//% XCTAssertNotNil(dict); 247//% XCTAssertEqual(dict.count, 4U); 248//% 249//% [dict remove##VALUE_NAME##ForKey:KEY2]; 250//% XCTAssertEqual(dict.count, 3U); 251//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 252//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 253//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 254//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY4, VAL4) 255//% 256//% // Remove again does nothing. 257//% [dict remove##VALUE_NAME##ForKey:KEY2]; 258//% XCTAssertEqual(dict.count, 3U); 259//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 260//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 261//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 262//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY4, VAL4) 263//% 264//% [dict remove##VALUE_NAME##ForKey:KEY4]; 265//% XCTAssertEqual(dict.count, 2U); 266//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 267//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 268//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 269//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY4) 270//% 271//% [dict removeAll]; 272//% XCTAssertEqual(dict.count, 0U); 273//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY1) 274//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 275//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY3) 276//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY4) 277//% [dict release]; 278//%} 279//% 280//%- (void)testInplaceMutation { 281//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 282//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2, VAL3, VAL4 }; 283//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 284//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 285//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 286//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 287//% XCTAssertNotNil(dict); 288//% XCTAssertEqual(dict.count, 4U); 289//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 290//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 291//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 292//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY4, VAL4) 293//% 294//% [dict set##VALUE_NAME##:VAL4 forKey:KEY1]; 295//% XCTAssertEqual(dict.count, 4U); 296//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL4) 297//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 298//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 299//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY4, VAL4) 300//% 301//% [dict set##VALUE_NAME##:VAL2 forKey:KEY4]; 302//% XCTAssertEqual(dict.count, 4U); 303//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL4) 304//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 305//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL3) 306//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY4, VAL2) 307//% 308//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 }; 309//% const VALUE_TYPE k##VNAME$u##s2[] = { VAL3, VAL1 }; 310//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 311//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s2 312//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys2 313//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s2)]; 314//% XCTAssertNotNil(dict2); 315//% [dict add##VACCESSOR##EntriesFromDictionary:dict2]; 316//% XCTAssertEqual(dict.count, 4U); 317//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL4) 318//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL3) 319//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY3, VAL1) 320//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY4, VAL2) 321//% 322//% [dict2 release]; 323//% [dict release]; 324//%} 325//% 326//%@end 327//% 328 329//%PDDM-DEFINE TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4) 330//%TESTS_FOR_ENUM_VALUE_RAW_ADDITIONS2(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, KEY3, KEY4, Enum, int32_t, , POD, 700, 801, 702, 803) 331//%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) 332//%#pragma mark - KEY_NAME -> VALUE_NAME (Unknown Enums) 333//% 334//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests : XCTestCase 335//%@end 336//% 337//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryUnknownEnumTests 338//% 339//%- (void)testRawBasics { 340//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3 }; 341//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3 }; 342//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 343//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 344//% KEY_NAME$S VALUE_NAME$S rawValues:kValues 345//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys 346//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; 347//% XCTAssertNotNil(dict); 348//% XCTAssertEqual(dict.count, 3U); 349//% XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue); // Pointer comparison 350//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL1) 351//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY2, kGPBUnrecognizedEnumeratorValue) 352//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) 353//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL3) 354//%RAW_VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY4) 355//% 356//% __block NSUInteger idx = 0; 357//% KEY_TYPE KisP##*seenKeys = malloc(3 * sizeof(KEY_TYPE##KisP)); 358//% VALUE_TYPE *seenValues = malloc(3 * sizeof(VALUE_TYPE)); 359//% [dict enumerateKeysAndEnumsUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { 360//% XCTAssertLessThan(idx, 3U); 361//% seenKeys[idx] = aKey; 362//% seenValues[idx] = aValue; 363//% XCTAssertNotEqual(stop, NULL); 364//% ++idx; 365//% }]; 366//% for (int i = 0; i < 3; ++i) { 367//% BOOL foundKey = NO; 368//% for (int j = 0; (j < 3) && !foundKey; ++j) { 369//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { 370//% foundKey = YES; 371//% if (i == 1) { 372//% XCTAssertEqual##VSUFFIX(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j); 373//% } else { 374//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); 375//% } 376//% } 377//% } 378//% XCTAssertTrue(foundKey, @"i = %d", i); 379//% } 380//% idx = 0; 381//% [dict enumerateKeysAndRawValuesUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE aValue, BOOL *stop) { 382//% XCTAssertLessThan(idx, 3U); 383//% seenKeys[idx] = aKey; 384//% seenValues[idx] = aValue; 385//% XCTAssertNotEqual(stop, NULL); 386//% ++idx; 387//% }]; 388//% for (int i = 0; i < 3; ++i) { 389//% BOOL foundKey = NO; 390//% for (int j = 0; (j < 3) && !foundKey; ++j) { 391//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { 392//% foundKey = YES; 393//% XCTAssertEqual##VSUFFIX(kValues[i], seenValues[j], @"i = %d, j = %d", i, j); 394//% } 395//% } 396//% XCTAssertTrue(foundKey, @"i = %d", i); 397//% } 398//% free(seenKeys); 399//% free(seenValues); 400//% 401//% // Stopping the enumeration. 402//% idx = 0; 403//% [dict enumerateKeysAndRawValuesUsingBlock:^(__unused KEY_TYPE KisP##aKey, __unused VALUE_TYPE aValue, BOOL *stop) { 404//% if (idx == 1) *stop = YES; 405//% XCTAssertNotEqual(idx, 2U); 406//% ++idx; 407//% }]; 408//% [dict release]; 409//%} 410//% 411//%- (void)testEqualityWithUnknowns { 412//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2, KEY3, KEY4 }; 413//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1, KEY4 }; 414//% const VALUE_TYPE kValues1[] = { VAL1, VAL2, VAL3 }; // Unknown 415//% const VALUE_TYPE kValues2[] = { VAL1, VAL4, VAL3 }; // Unknown 416//% const VALUE_TYPE kValues3[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns 417//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 = 418//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 419//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 420//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 421//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; 422//% XCTAssertNotNil(dict1); 423//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime = 424//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 425//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 426//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 427//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; 428//% XCTAssertNotNil(dict1prime); 429//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 430//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 431//% KEY_NAME$S VALUE_NAME$S rawValues:kValues2 432//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 433//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; 434//% XCTAssertNotNil(dict2); 435//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 = 436//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 437//% KEY_NAME$S VALUE_NAME$S rawValues:kValues1 438//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 439//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues1)]; 440//% XCTAssertNotNil(dict3); 441//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 = 442//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 443//% KEY_NAME$S VALUE_NAME$S rawValues:kValues3 444//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys1 445//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues3)]; 446//% XCTAssertNotNil(dict4); 447//% 448//% // 1/1Prime should be different objects, but equal. 449//% XCTAssertNotEqual(dict1, dict1prime); 450//% XCTAssertEqualObjects(dict1, dict1prime); 451//% // Equal, so they must have same hash. 452//% XCTAssertEqual([dict1 hash], [dict1prime hash]); 453//% 454//% // 2 is same keys, different values; not equal. 455//% XCTAssertNotEqualObjects(dict1, dict2); 456//% 457//% // 3 is different keys, same values; not equal. 458//% XCTAssertNotEqualObjects(dict1, dict3); 459//% 460//% // 4 extra pair; not equal 461//% XCTAssertNotEqualObjects(dict1, dict4); 462//% 463//% [dict1 release]; 464//% [dict1prime release]; 465//% [dict2 release]; 466//% [dict3 release]; 467//% [dict4 release]; 468//%} 469//% 470//%- (void)testCopyWithUnknowns { 471//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 472//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknown 473//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 474//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 475//% KEY_NAME$S VALUE_NAME$S rawValues:kValues 476//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys 477//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; 478//% XCTAssertNotNil(dict); 479//% 480//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy]; 481//% XCTAssertNotNil(dict2); 482//% 483//% // Should be new pointer, but equal objects. 484//% XCTAssertNotEqual(dict, dict2); 485//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison 486//% XCTAssertEqualObjects(dict, dict2); 487//% 488//% [dict2 release]; 489//% [dict release]; 490//%} 491//% 492//%- (void)testDictionaryFromDictionary { 493//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 494//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns 495//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 496//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 497//% KEY_NAME$S VALUE_NAME$S rawValues:kValues 498//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys 499//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; 500//% XCTAssertNotNil(dict); 501//% 502//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 503//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithDictionary:dict]; 504//% XCTAssertNotNil(dict2); 505//% 506//% // Should be new pointer, but equal objects. 507//% XCTAssertNotEqual(dict, dict2); 508//% XCTAssertEqualObjects(dict, dict2); 509//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison 510//% [dict2 release]; 511//% [dict release]; 512//%} 513//% 514//%- (void)testUnknownAdds { 515//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 516//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue]; 517//% XCTAssertNotNil(dict); 518//% 519//% XCTAssertEqual(dict.count, 0U); 520//% XCTAssertThrowsSpecificNamed([dict setEnum:VAL2 forKey:KEY2], // Unknown 521//% NSException, NSInvalidArgumentException); 522//% XCTAssertEqual(dict.count, 0U); 523//% [dict setRawValue:VAL2 forKey:KEY2]; // Unknown 524//% XCTAssertEqual(dict.count, 1U); 525//% 526//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY3, KEY4 }; 527//% const VALUE_TYPE kValues[] = { VAL1, VAL3, VAL4 }; // Unknown 528//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 529//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithEnums:kValues 530//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys 531//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; 532//% XCTAssertNotNil(dict2); 533//% [dict addRawEntriesFromDictionary:dict2]; 534//% XCTAssertEqual(dict.count, 4U); 535//% 536//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY1, VAL1) 537//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY2, kGPBUnrecognizedEnumeratorValue) 538//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) 539//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 540//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY4, kGPBUnrecognizedEnumeratorValue) 541//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) 542//% [dict2 release]; 543//% [dict release]; 544//%} 545//% 546//%- (void)testUnknownRemove { 547//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 548//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns 549//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 550//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 551//% KEY_NAME$S VALUE_NAME$S rawValues:kValues 552//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys 553//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; 554//% XCTAssertNotNil(dict); 555//% XCTAssertEqual(dict.count, 4U); 556//% 557//% [dict removeEnumForKey:KEY2]; 558//% XCTAssertEqual(dict.count, 3U); 559//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY1, VAL1) 560//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 561//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 562//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) 563//% 564//% // Remove again does nothing. 565//% [dict removeEnumForKey:KEY2]; 566//% XCTAssertEqual(dict.count, 3U); 567//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY1, VAL1) 568//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 569//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 570//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) 571//% 572//% [dict removeEnumForKey:KEY4]; 573//% XCTAssertEqual(dict.count, 2U); 574//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY1, VAL1) 575//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 576//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 577//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY4) 578//% 579//% [dict removeAll]; 580//% XCTAssertEqual(dict.count, 0U); 581//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY1) 582//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 583//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY3) 584//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY4) 585//% [dict release]; 586//%} 587//% 588//%- (void)testInplaceMutationUnknowns { 589//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 590//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; // Unknowns 591//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 592//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 593//% KEY_NAME$S VALUE_NAME$S rawValues:kValues 594//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys 595//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; 596//% XCTAssertNotNil(dict); 597//% XCTAssertEqual(dict.count, 4U); 598//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, value)TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY1, VAL1) 599//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) 600//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 601//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) 602//% 603//% XCTAssertThrowsSpecificNamed([dict setEnum:VAL4 forKey:KEY1], // Unknown 604//% NSException, NSInvalidArgumentException); 605//% XCTAssertEqual(dict.count, 4U); 606//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY1, VAL1) 607//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) 608//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 609//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) 610//% 611//% [dict setRawValue:VAL4 forKey:KEY1]; // Unknown 612//% XCTAssertEqual(dict.count, 4U); 613//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) 614//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) 615//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 616//%TEST_RAW_VALUE##VHELPER(dict, value, KEY4, VAL4) 617//% 618//% [dict setRawValue:VAL1 forKey:KEY4]; 619//% XCTAssertEqual(dict.count, 4U); 620//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) 621//%TEST_RAW_VALUE##VHELPER(dict, value, KEY2, VAL2) 622//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY3, VAL3) 623//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY4, VAL1) 624//% 625//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY3 }; 626//% const VALUE_TYPE kValues2[] = { VAL3, VAL2 }; // Unknown 627//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 628//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 629//% KEY_NAME$S VALUE_NAME$S rawValues:kValues2 630//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys2 631//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues2)]; 632//% XCTAssertNotNil(dict2); 633//% [dict addRawEntriesFromDictionary:dict2]; 634//% XCTAssertEqual(dict.count, 4U); 635//%TEST_RAW_VALUE##VHELPER(dict, value, KEY1, VAL4) 636//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY2, VAL3) 637//%TEST_RAW_VALUE##VHELPER(dict, value, KEY3, VAL2) 638//%TEST_VALUE##VHELPER(VALUE_NAME, dict, value, KEY4, VAL1) 639//% 640//% [dict2 release]; 641//% [dict release]; 642//%} 643//% 644//%- (void)testCopyUnknowns { 645//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2, KEY3, KEY4 }; 646//% const VALUE_TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; 647//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 648//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue 649//% KEY_NAME$S VALUE_NAME$S rawValues:kValues 650//% KEY_NAME$S VALUE_NAME$S forKeys:kKeys 651//% KEY_NAME$S VALUE_NAME$S count:GPBARRAYSIZE(kValues)]; 652//% XCTAssertNotNil(dict); 653//% 654//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy]; 655//% XCTAssertNotNil(dict2); 656//% 657//% // Should be new pointer, but equal objects. 658//% XCTAssertNotEqual(dict, dict2); 659//% XCTAssertEqualObjects(dict, dict2); 660//% XCTAssertEqual(dict.validationFunc, dict2.validationFunc); // Pointer comparison 661//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); 662//% 663//% [dict2 release]; 664//% [dict release]; 665//%} 666//% 667//%@end 668//% 669 670// 671// Helpers for PODs 672// 673 674//%PDDM-DEFINE DECLARE_VALUE_STORAGEPOD(VALUE_TYPE, NAME) 675//% VALUE_TYPE NAME; 676//% 677//%PDDM-DEFINE VALUE_NOT_FOUNDPOD(VALUE_NAME, DICT, KEY) 678//% XCTAssertFalse([DICT get##VALUE_NAME##:NULL forKey:KEY]); 679//%PDDM-DEFINE TEST_VALUEPOD(VALUE_NAME, DICT, STORAGE, KEY, VALUE) 680//% XCTAssertTrue([DICT get##VALUE_NAME##:NULL forKey:KEY]); 681//% XCTAssertTrue([DICT get##VALUE_NAME##:&STORAGE forKey:KEY]); 682//% XCTAssertEqual(STORAGE, VALUE); 683//%PDDM-DEFINE COMPARE_KEYS(KEY1, KEY2) 684//%KEY1 == KEY2 685//%PDDM-DEFINE RAW_VALUE_NOT_FOUNDPOD(VALUE_NAME, DICT, KEY) 686//% XCTAssertFalse([DICT getRawValue:NULL forKey:KEY]); 687//%PDDM-DEFINE TEST_RAW_VALUEPOD(DICT, STORAGE, KEY, VALUE) 688//% XCTAssertTrue([DICT getRawValue:NULL forKey:KEY]); 689//% XCTAssertTrue([DICT getRawValue:&STORAGE forKey:KEY]); 690//% XCTAssertEqual(STORAGE, VALUE); 691 692// 693// Helpers for Objects 694// 695 696//%PDDM-DEFINE DECLARE_VALUE_STORAGEOBJECT(VALUE_TYPE, NAME) 697// Empty 698//%PDDM-DEFINE VALUE_NOT_FOUNDOBJECT(VALUE_NAME, DICT, KEY) 699//% XCTAssertNil([DICT objectForKey:KEY]); 700//%PDDM-DEFINE TEST_VALUEOBJECT(VALUE_NAME, DICT, STORAGE, KEY, VALUE) 701//% XCTAssertEqualObjects([DICT objectForKey:KEY], VALUE); 702//%PDDM-DEFINE COMPARE_KEYSObjects(KEY1, KEY2) 703//%[KEY1 isEqual:KEY2] 704 705// 706// Helpers for tests. 707// 708 709//%PDDM-DEFINE TEST_HELPERS(KEY_NAME, KEY_TYPE, KisP) 710//%// To let the testing macros work, add some extra methods to simplify things. 711//%@interface GPB##KEY_NAME##EnumDictionary (TestingTweak) 712//%- (instancetype)initWithEnums:(const int32_t [])values 713//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys 714//% count:(NSUInteger)count; 715//%@end 716//% 717//%static BOOL TestingEnum_IsValidValue(int32_t value) { 718//% switch (value) { 719//% case 700: 720//% case 701: 721//% case 702: 722//% case 703: 723//% return YES; 724//% default: 725//% return NO; 726//% } 727//%} 728//% 729//%@implementation GPB##KEY_NAME##EnumDictionary (TestingTweak) 730//%- (instancetype)initWithEnums:(const int32_t [])values 731//% forKeys:(const KEY_TYPE##KisP$S##KisP [])keys 732//% count:(NSUInteger)count { 733//% return [self initWithValidationFunction:TestingEnum_IsValidValue 734//% rawValues:values 735//% forKeys:keys 736//% count:count]; 737//%} 738//%@end 739//% 740//% 741 742 743// 744// BOOL test macros 745// 746//TODO: enum tests 747 748//%PDDM-DEFINE BOOL_TESTS_FOR_POD_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2) 749//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, , value, POD, VAL1, VAL2) 750 751//%PDDM-DEFINE TESTS_FOR_BOOL_KEY_OBJECT_VALUE(VALUE_NAME, VALUE_TYPE, VAL1, VAL2) 752//%BOOL_TESTS_COMMON(Bool, BOOL, , , YES, NO, VALUE_NAME, VALUE_TYPE, Objects, object, OBJECT, VAL1, VAL2) 753 754//%PDDM-DEFINE BOOL_TESTS_COMMON(KEY_NAME, KEY_TYPE, KisP, KSUFFIX, KEY1, KEY2, VALUE_NAME, VALUE_TYPE, VSUFFIX, VNAME, VHELPER, VAL1, VAL2) 755//%#pragma mark - KEY_NAME -> VALUE_NAME 756//% 757//%@interface GPB##KEY_NAME##VALUE_NAME##DictionaryTests : XCTestCase 758//%@end 759//% 760//%@implementation GPB##KEY_NAME##VALUE_NAME##DictionaryTests 761//% 762//%- (void)testEmpty { 763//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; 764//% XCTAssertNotNil(dict); 765//% XCTAssertEqual(dict.count, 0U); 766//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY1) 767//% [dict enumerateKeysAnd##VALUE_NAME##sUsingBlock:^(__unused KEY_TYPE KisP##aKey, __unused VALUE_TYPE a##VNAME$u##, __unused BOOL *stop) { 768//% XCTFail(@"Shouldn't get here!"); 769//% }]; 770//% [dict release]; 771//%} 772//% 773//%- (void)testOne { 774//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; 775//% [dict set##VALUE_NAME$u##:VAL1 forKey:KEY1]; 776//% XCTAssertNotNil(dict); 777//% XCTAssertEqual(dict.count, 1U); 778//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 779//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 780//% [dict enumerateKeysAnd##VALUE_NAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u, BOOL *stop) { 781//% XCTAssertEqual##KSUFFIX(aKey, KEY1); 782//% XCTAssertEqual##VSUFFIX(a##VNAME$u, VAL1); 783//% XCTAssertNotEqual(stop, NULL); 784//% }]; 785//% [dict release]; 786//%} 787//% 788//%- (void)testBasics { 789//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; 790//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 }; 791//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 792//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 793//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 794//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 795//% XCTAssertNotNil(dict); 796//% XCTAssertEqual(dict.count, 2U); 797//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 798//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 799//% 800//% __block NSUInteger idx = 0; 801//% KEY_TYPE KisP##*seenKeys = malloc(2 * sizeof(KEY_TYPE##KisP)); 802//% VALUE_TYPE *seen##VNAME$u##s = malloc(2 * sizeof(VALUE_TYPE)); 803//% [dict enumerateKeysAnd##VALUE_NAME$u##sUsingBlock:^(KEY_TYPE KisP##aKey, VALUE_TYPE a##VNAME$u##, BOOL *stop) { 804//% XCTAssertLessThan(idx, 2U); 805//% seenKeys[idx] = aKey; 806//% seen##VNAME$u##s[idx] = a##VNAME$u; 807//% XCTAssertNotEqual(stop, NULL); 808//% ++idx; 809//% }]; 810//% for (int i = 0; i < 2; ++i) { 811//% BOOL foundKey = NO; 812//% for (int j = 0; (j < 2) && !foundKey; ++j) { 813//% if (COMPARE_KEYS##KSUFFIX(kKeys[i], seenKeys[j])) { 814//% foundKey = YES; 815//% XCTAssertEqual##VSUFFIX(k##VNAME$u##s[i], seen##VNAME$u##s[j], @"i = %d, j = %d", i, j); 816//% } 817//% } 818//% XCTAssertTrue(foundKey, @"i = %d", i); 819//% } 820//% free(seenKeys); 821//% free(seen##VNAME$u##s); 822//% 823//% // Stopping the enumeration. 824//% idx = 0; 825//% [dict enumerateKeysAnd##VALUE_NAME$u##sUsingBlock:^(__unused KEY_TYPE KisP##aKey, __unused VALUE_TYPE a##VNAME$u##, BOOL *stop) { 826//% if (idx == 0) *stop = YES; 827//% XCTAssertNotEqual(idx, 2U); 828//% ++idx; 829//% }]; 830//% [dict release]; 831//%} 832//% 833//%- (void)testEquality { 834//% const KEY_TYPE KisP##kKeys1[] = { KEY1, KEY2 }; 835//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 }; 836//% const VALUE_TYPE k##VNAME$u##s1[] = { VAL1, VAL2 }; 837//% const VALUE_TYPE k##VNAME$u##s2[] = { VAL2, VAL1 }; 838//% const VALUE_TYPE k##VNAME$u##s3[] = { VAL2 }; 839//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1 = 840//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s1 841//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 842//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s1)]; 843//% XCTAssertNotNil(dict1); 844//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict1prime = 845//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s1 846//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 847//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s1)]; 848//% XCTAssertNotNil(dict1prime); 849//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 850//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s2 851//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 852//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s2)]; 853//% XCTAssertNotNil(dict2); 854//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict3 = 855//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s1 856//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys2 857//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s1)]; 858//% XCTAssertNotNil(dict3); 859//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict4 = 860//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s3 861//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys1 862//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s3)]; 863//% XCTAssertNotNil(dict4); 864//% 865//% // 1/1Prime should be different objects, but equal. 866//% XCTAssertNotEqual(dict1, dict1prime); 867//% XCTAssertEqualObjects(dict1, dict1prime); 868//% // Equal, so they must have same hash. 869//% XCTAssertEqual([dict1 hash], [dict1prime hash]); 870//% 871//% // 2 is same keys, different ##VNAME##s; not equal. 872//% XCTAssertNotEqualObjects(dict1, dict2); 873//% 874//% // 3 is different keys, same ##VNAME##s; not equal. 875//% XCTAssertNotEqualObjects(dict1, dict3); 876//% 877//% // 4 Fewer pairs; not equal 878//% XCTAssertNotEqualObjects(dict1, dict4); 879//% 880//% [dict1 release]; 881//% [dict1prime release]; 882//% [dict2 release]; 883//% [dict3 release]; 884//% [dict4 release]; 885//%} 886//% 887//%- (void)testCopy { 888//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; 889//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 }; 890//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 891//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 892//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 893//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 894//% XCTAssertNotNil(dict); 895//% 896//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = [dict copy]; 897//% XCTAssertNotNil(dict2); 898//% 899//% // Should be new object but equal. 900//% XCTAssertNotEqual(dict, dict2); 901//% XCTAssertEqualObjects(dict, dict2); 902//% XCTAssertTrue([dict2 isKindOfClass:[GPB##KEY_NAME##VALUE_NAME##Dictionary class]]); 903//% 904//% [dict2 release]; 905//% [dict release]; 906//%} 907//% 908//%- (void)testDictionaryFromDictionary { 909//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; 910//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 }; 911//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 912//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 913//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 914//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 915//% XCTAssertNotNil(dict); 916//% 917//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 918//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWithDictionary:dict]; 919//% XCTAssertNotNil(dict2); 920//% 921//% // Should be new pointer, but equal objects. 922//% XCTAssertNotEqual(dict, dict2); 923//% XCTAssertEqualObjects(dict, dict2); 924//% [dict2 release]; 925//% [dict release]; 926//%} 927//% 928//%- (void)testAdds { 929//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] init]; 930//% XCTAssertNotNil(dict); 931//% 932//% XCTAssertEqual(dict.count, 0U); 933//% [dict set##VALUE_NAME:VAL1 forKey:KEY1]; 934//% XCTAssertEqual(dict.count, 1U); 935//% 936//% const KEY_TYPE KisP##kKeys[] = { KEY2 }; 937//% const VALUE_TYPE k##VNAME$u##s[] = { VAL2 }; 938//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 939//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 940//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 941//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 942//% XCTAssertNotNil(dict2); 943//% [dict addEntriesFromDictionary:dict2]; 944//% XCTAssertEqual(dict.count, 2U); 945//% 946//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 947//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 948//% [dict2 release]; 949//% [dict release]; 950//%} 951//% 952//%- (void)testRemove { 953//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2}; 954//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 }; 955//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 956//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 957//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 958//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 959//% XCTAssertNotNil(dict); 960//% XCTAssertEqual(dict.count, 2U); 961//% 962//% [dict remove##VALUE_NAME##ForKey:KEY2]; 963//% XCTAssertEqual(dict.count, 1U); 964//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 965//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 966//% 967//% // Remove again does nothing. 968//% [dict remove##VALUE_NAME##ForKey:KEY2]; 969//% XCTAssertEqual(dict.count, 1U); 970//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 971//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 972//% 973//% [dict removeAll]; 974//% XCTAssertEqual(dict.count, 0U); 975//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY1) 976//%VALUE_NOT_FOUND##VHELPER(VALUE_NAME, dict, KEY2) 977//% [dict release]; 978//%} 979//% 980//%- (void)testInplaceMutation { 981//% const KEY_TYPE KisP##kKeys[] = { KEY1, KEY2 }; 982//% const VALUE_TYPE k##VNAME$u##s[] = { VAL1, VAL2 }; 983//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict = 984//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s 985//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys 986//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s)]; 987//% XCTAssertNotNil(dict); 988//% XCTAssertEqual(dict.count, 2U); 989//%DECLARE_VALUE_STORAGE##VHELPER(VALUE_TYPE, VNAME)TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 990//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 991//% 992//% [dict set##VALUE_NAME##:VAL2 forKey:KEY1]; 993//% XCTAssertEqual(dict.count, 2U); 994//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL2) 995//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 996//% 997//% [dict set##VALUE_NAME##:VAL1 forKey:KEY2]; 998//% XCTAssertEqual(dict.count, 2U); 999//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL2) 1000//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL1) 1001//% 1002//% const KEY_TYPE KisP##kKeys2[] = { KEY2, KEY1 }; 1003//% const VALUE_TYPE k##VNAME$u##s2[] = { VAL2, VAL1 }; 1004//% DICTIONARY_CLASS_DECL##VHELPER(KEY_NAME, VALUE_NAME, VALUE_TYPE) *dict2 = 1005//% [[GPB##KEY_NAME##VALUE_NAME##Dictionary alloc] initWith##VALUE_NAME##s:k##VNAME$u##s2 1006//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## forKeys:kKeys2 1007//% KEY_NAME$S VALUE_NAME$S ##VALUE_NAME$S## count:GPBARRAYSIZE(k##VNAME$u##s2)]; 1008//% XCTAssertNotNil(dict2); 1009//% [dict addEntriesFromDictionary:dict2]; 1010//% XCTAssertEqual(dict.count, 2U); 1011//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY1, VAL1) 1012//%TEST_VALUE##VHELPER(VALUE_NAME, dict, VNAME, KEY2, VAL2) 1013//% 1014//% [dict2 release]; 1015//% [dict release]; 1016//%} 1017//% 1018//%@end 1019//% 1020 1021