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