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