GPBDictionaryTests+String.m 127 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
// Protocol Buffers - Google's data interchange format
// Copyright 2015 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>

#import "GPBDictionary.h"

36
#import "GPBTestUtilities.h"
37 38 39 40 41 42 43 44 45 46 47
#import "google/protobuf/UnittestRuntimeProto2.pbobjc.h"

// Pull in the macros (using an external file because expanding all tests
// in a single file makes a file that is failing to work with within Xcode.
//%PDDM-IMPORT-DEFINES GPBDictionaryTests.pddm

//%PDDM-EXPAND TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble")
// This block of code is generated, do not edit it directly.

// To let the testing macros work, add some extra methods to simplify things.
@interface GPBStringEnumDictionary (TestingTweak)
48 49 50
- (instancetype)initWithEnums:(const int32_t [])values
                      forKeys:(const NSString * [])keys
                        count:(NSUInteger)count;
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
@end

static BOOL TestingEnum_IsValidValue(int32_t value) {
  switch (value) {
    case 700:
    case 701:
    case 702:
    case 703:
      return YES;
    default:
      return NO;
  }
}

@implementation GPBStringEnumDictionary (TestingTweak)
66 67 68
- (instancetype)initWithEnums:(const int32_t [])values
                      forKeys:(const NSString * [])keys
                        count:(NSUInteger)count {
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
  return [self initWithValidationFunction:TestingEnum_IsValidValue
                                rawValues:values
                                  forKeys:keys
                                    count:count];
}
@end


#pragma mark - String -> UInt32

@interface GPBStringUInt32DictionaryTests : XCTestCase
@end

@implementation GPBStringUInt32DictionaryTests

- (void)testEmpty {
  GPBStringUInt32Dictionary *dict = [[GPBStringUInt32Dictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
88 89
  XCTAssertFalse([dict getUInt32:NULL forKey:@"foo"]);
  [dict enumerateKeysAndUInt32sUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
90 91 92 93 94 95 96
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
97 98
  GPBStringUInt32Dictionary *dict = [[GPBStringUInt32Dictionary alloc] init];
  [dict setUInt32:100U forKey:@"foo"];
99 100 101
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  uint32_t value;
102 103
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
104
  XCTAssertEqual(value, 100U);
105 106
  XCTAssertFalse([dict getUInt32:NULL forKey:@"bar"]);
  [dict enumerateKeysAndUInt32sUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
107 108 109 110
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, 100U);
    XCTAssertNotEqual(stop, NULL);
  }];
111
  [dict release];
112 113 114 115 116 117
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const uint32_t kValues[] = { 100U, 101U, 102U };
  GPBStringUInt32Dictionary *dict =
118 119 120
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
121 122 123
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  uint32_t value;
124 125
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
126
  XCTAssertEqual(value, 100U);
127 128
  XCTAssertTrue([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"bar"]);
129
  XCTAssertEqual(value, 101U);
130 131
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
132
  XCTAssertEqual(value, 102U);
133
  XCTAssertFalse([dict getUInt32:NULL forKey:@"mumble"]);
134 135 136 137

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  uint32_t *seenValues = malloc(3 * sizeof(uint32_t));
138
  [dict enumerateKeysAndUInt32sUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
160
  [dict enumerateKeysAndUInt32sUsingBlock:^(NSString *aKey, uint32_t aValue, BOOL *stop) {
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const uint32_t kValues1[] = { 100U, 101U, 102U };
  const uint32_t kValues2[] = { 100U, 103U, 102U };
  const uint32_t kValues3[] = { 100U, 101U, 102U, 103U };
  GPBStringUInt32Dictionary *dict1 =
176 177 178
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues1
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues1)];
179 180
  XCTAssertNotNil(dict1);
  GPBStringUInt32Dictionary *dict1prime =
181 182 183
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues1
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues1)];
184 185
  XCTAssertNotNil(dict1prime);
  GPBStringUInt32Dictionary *dict2 =
186 187 188
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues2
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues2)];
189 190
  XCTAssertNotNil(dict2);
  GPBStringUInt32Dictionary *dict3 =
191 192 193
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues1
                                                 forKeys:kKeys2
                                                   count:GPBARRAYSIZE(kValues1)];
194 195
  XCTAssertNotNil(dict3);
  GPBStringUInt32Dictionary *dict4 =
196 197 198
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues3
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues3)];
199 200 201 202 203 204 205 206
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

207
  // 2 is same keys, different values; not equal.
208 209
  XCTAssertNotEqualObjects(dict1, dict2);

210
  // 3 is different keys, same values; not equal.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
  GPBStringUInt32Dictionary *dict =
227 228 229
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
  XCTAssertNotNil(dict);

  GPBStringUInt32Dictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt32Dictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
  GPBStringUInt32Dictionary *dict =
248 249 250
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
251 252 253
  XCTAssertNotNil(dict);

  GPBStringUInt32Dictionary *dict2 =
254
      [[GPBStringUInt32Dictionary alloc] initWithDictionary:dict];
255 256 257 258 259
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
260
  [dict2 release];
261 262 263 264
  [dict release];
}

- (void)testAdds {
265
  GPBStringUInt32Dictionary *dict = [[GPBStringUInt32Dictionary alloc] init];
266 267 268
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
269
  [dict setUInt32:100U forKey:@"foo"];
270 271 272 273 274
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const uint32_t kValues[] = { 101U, 102U, 103U };
  GPBStringUInt32Dictionary *dict2 =
275 276 277
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
278 279 280 281 282
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  uint32_t value;
283 284
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
285
  XCTAssertEqual(value, 100U);
286 287
  XCTAssertTrue([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"bar"]);
288
  XCTAssertEqual(value, 101U);
289 290
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
291
  XCTAssertEqual(value, 102U);
292 293
  XCTAssertTrue([dict getUInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"mumble"]);
294 295
  XCTAssertEqual(value, 103U);
  [dict2 release];
296
  [dict release];
297 298 299 300 301 302
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
  GPBStringUInt32Dictionary *dict =
303 304 305
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
306 307 308
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

309
  [dict removeUInt32ForKey:@"bar"];
310 311
  XCTAssertEqual(dict.count, 3U);
  uint32_t value;
312 313
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
314
  XCTAssertEqual(value, 100U);
315 316 317
  XCTAssertFalse([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
318
  XCTAssertEqual(value, 102U);
319 320
  XCTAssertTrue([dict getUInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"mumble"]);
321 322 323
  XCTAssertEqual(value, 103U);

  // Remove again does nothing.
324
  [dict removeUInt32ForKey:@"bar"];
325
  XCTAssertEqual(dict.count, 3U);
326 327
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
328
  XCTAssertEqual(value, 100U);
329 330 331
  XCTAssertFalse([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
332
  XCTAssertEqual(value, 102U);
333 334
  XCTAssertTrue([dict getUInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"mumble"]);
335 336
  XCTAssertEqual(value, 103U);

337
  [dict removeUInt32ForKey:@"mumble"];
338
  XCTAssertEqual(dict.count, 2U);
339 340
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
341
  XCTAssertEqual(value, 100U);
342 343 344
  XCTAssertFalse([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
345
  XCTAssertEqual(value, 102U);
346
  XCTAssertFalse([dict getUInt32:NULL forKey:@"mumble"]);
347 348 349

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
350 351 352 353
  XCTAssertFalse([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getUInt32:NULL forKey:@"mumble"]);
354 355 356 357 358 359 360
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint32_t kValues[] = { 100U, 101U, 102U, 103U };
  GPBStringUInt32Dictionary *dict =
361 362 363
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
364 365 366
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  uint32_t value;
367 368
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
369
  XCTAssertEqual(value, 100U);
370 371
  XCTAssertTrue([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"bar"]);
372
  XCTAssertEqual(value, 101U);
373 374
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
375
  XCTAssertEqual(value, 102U);
376 377
  XCTAssertTrue([dict getUInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"mumble"]);
378 379
  XCTAssertEqual(value, 103U);

380
  [dict setUInt32:103U forKey:@"foo"];
381
  XCTAssertEqual(dict.count, 4U);
382 383
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
384
  XCTAssertEqual(value, 103U);
385 386
  XCTAssertTrue([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"bar"]);
387
  XCTAssertEqual(value, 101U);
388 389
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
390
  XCTAssertEqual(value, 102U);
391 392
  XCTAssertTrue([dict getUInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"mumble"]);
393 394
  XCTAssertEqual(value, 103U);

395
  [dict setUInt32:101U forKey:@"mumble"];
396
  XCTAssertEqual(dict.count, 4U);
397 398
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
399
  XCTAssertEqual(value, 103U);
400 401
  XCTAssertTrue([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"bar"]);
402
  XCTAssertEqual(value, 101U);
403 404
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
405
  XCTAssertEqual(value, 102U);
406 407
  XCTAssertTrue([dict getUInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"mumble"]);
408 409 410 411 412
  XCTAssertEqual(value, 101U);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const uint32_t kValues2[] = { 102U, 100U };
  GPBStringUInt32Dictionary *dict2 =
413 414 415
      [[GPBStringUInt32Dictionary alloc] initWithUInt32s:kValues2
                                                 forKeys:kKeys2
                                                   count:GPBARRAYSIZE(kValues2)];
416 417 418
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
419 420
  XCTAssertTrue([dict getUInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"foo"]);
421
  XCTAssertEqual(value, 103U);
422 423
  XCTAssertTrue([dict getUInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"bar"]);
424
  XCTAssertEqual(value, 102U);
425 426
  XCTAssertTrue([dict getUInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"baz"]);
427
  XCTAssertEqual(value, 100U);
428 429
  XCTAssertTrue([dict getUInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt32:&value forKey:@"mumble"]);
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
  XCTAssertEqual(value, 101U);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> Int32

@interface GPBStringInt32DictionaryTests : XCTestCase
@end

@implementation GPBStringInt32DictionaryTests

- (void)testEmpty {
  GPBStringInt32Dictionary *dict = [[GPBStringInt32Dictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
449 450
  XCTAssertFalse([dict getInt32:NULL forKey:@"foo"]);
  [dict enumerateKeysAndInt32sUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
451 452 453 454 455 456 457
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
458 459
  GPBStringInt32Dictionary *dict = [[GPBStringInt32Dictionary alloc] init];
  [dict setInt32:200 forKey:@"foo"];
460 461 462
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  int32_t value;
463 464
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
465
  XCTAssertEqual(value, 200);
466 467
  XCTAssertFalse([dict getInt32:NULL forKey:@"bar"]);
  [dict enumerateKeysAndInt32sUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
468 469 470 471
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, 200);
    XCTAssertNotEqual(stop, NULL);
  }];
472
  [dict release];
473 474 475 476 477 478
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const int32_t kValues[] = { 200, 201, 202 };
  GPBStringInt32Dictionary *dict =
479
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues
480 481 482 483 484
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  int32_t value;
485 486
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
487
  XCTAssertEqual(value, 200);
488 489
  XCTAssertTrue([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"bar"]);
490
  XCTAssertEqual(value, 201);
491 492
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
493
  XCTAssertEqual(value, 202);
494
  XCTAssertFalse([dict getInt32:NULL forKey:@"mumble"]);
495 496 497 498

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  int32_t *seenValues = malloc(3 * sizeof(int32_t));
499
  [dict enumerateKeysAndInt32sUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
521
  [dict enumerateKeysAndInt32sUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const int32_t kValues1[] = { 200, 201, 202 };
  const int32_t kValues2[] = { 200, 203, 202 };
  const int32_t kValues3[] = { 200, 201, 202, 203 };
  GPBStringInt32Dictionary *dict1 =
537
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues1
538 539 540 541
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1);
  GPBStringInt32Dictionary *dict1prime =
542
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues1
543 544 545 546
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1prime);
  GPBStringInt32Dictionary *dict2 =
547
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues2
548 549 550 551
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  GPBStringInt32Dictionary *dict3 =
552
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues1
553 554 555 556
                                               forKeys:kKeys2
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict3);
  GPBStringInt32Dictionary *dict4 =
557
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues3
558 559 560 561 562 563 564 565 566 567
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues3)];
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

568
  // 2 is same keys, different values; not equal.
569 570
  XCTAssertNotEqualObjects(dict1, dict2);

571
  // 3 is different keys, same values; not equal.
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 200, 201, 202, 203 };
  GPBStringInt32Dictionary *dict =
588
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringInt32Dictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt32Dictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 200, 201, 202, 203 };
  GPBStringInt32Dictionary *dict =
609
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues
610 611 612 613 614
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringInt32Dictionary *dict2 =
615
      [[GPBStringInt32Dictionary alloc] initWithDictionary:dict];
616 617 618 619 620
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
621
  [dict2 release];
622 623 624 625
  [dict release];
}

- (void)testAdds {
626
  GPBStringInt32Dictionary *dict = [[GPBStringInt32Dictionary alloc] init];
627 628 629
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
630
  [dict setInt32:200 forKey:@"foo"];
631 632 633 634 635
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 201, 202, 203 };
  GPBStringInt32Dictionary *dict2 =
636
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues
637 638 639 640 641 642 643
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  int32_t value;
644 645
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
646
  XCTAssertEqual(value, 200);
647 648
  XCTAssertTrue([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"bar"]);
649
  XCTAssertEqual(value, 201);
650 651
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
652
  XCTAssertEqual(value, 202);
653 654
  XCTAssertTrue([dict getInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"mumble"]);
655 656
  XCTAssertEqual(value, 203);
  [dict2 release];
657
  [dict release];
658 659 660 661 662 663
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 200, 201, 202, 203 };
  GPBStringInt32Dictionary *dict =
664 665 666
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
667 668 669
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

670
  [dict removeInt32ForKey:@"bar"];
671 672
  XCTAssertEqual(dict.count, 3U);
  int32_t value;
673 674
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
675
  XCTAssertEqual(value, 200);
676 677 678
  XCTAssertFalse([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
679
  XCTAssertEqual(value, 202);
680 681
  XCTAssertTrue([dict getInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"mumble"]);
682 683 684
  XCTAssertEqual(value, 203);

  // Remove again does nothing.
685
  [dict removeInt32ForKey:@"bar"];
686
  XCTAssertEqual(dict.count, 3U);
687 688
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
689
  XCTAssertEqual(value, 200);
690 691 692
  XCTAssertFalse([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
693
  XCTAssertEqual(value, 202);
694 695
  XCTAssertTrue([dict getInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"mumble"]);
696 697
  XCTAssertEqual(value, 203);

698
  [dict removeInt32ForKey:@"mumble"];
699
  XCTAssertEqual(dict.count, 2U);
700 701
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
702
  XCTAssertEqual(value, 200);
703 704 705
  XCTAssertFalse([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
706
  XCTAssertEqual(value, 202);
707
  XCTAssertFalse([dict getInt32:NULL forKey:@"mumble"]);
708 709 710

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
711 712 713 714
  XCTAssertFalse([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getInt32:NULL forKey:@"mumble"]);
715 716 717 718 719 720 721
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 200, 201, 202, 203 };
  GPBStringInt32Dictionary *dict =
722 723 724
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
725 726 727
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  int32_t value;
728 729
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
730
  XCTAssertEqual(value, 200);
731 732
  XCTAssertTrue([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"bar"]);
733
  XCTAssertEqual(value, 201);
734 735
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
736
  XCTAssertEqual(value, 202);
737 738
  XCTAssertTrue([dict getInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"mumble"]);
739 740
  XCTAssertEqual(value, 203);

741
  [dict setInt32:203 forKey:@"foo"];
742
  XCTAssertEqual(dict.count, 4U);
743 744
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
745
  XCTAssertEqual(value, 203);
746 747
  XCTAssertTrue([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"bar"]);
748
  XCTAssertEqual(value, 201);
749 750
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
751
  XCTAssertEqual(value, 202);
752 753
  XCTAssertTrue([dict getInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"mumble"]);
754 755
  XCTAssertEqual(value, 203);

756
  [dict setInt32:201 forKey:@"mumble"];
757
  XCTAssertEqual(dict.count, 4U);
758 759
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
760
  XCTAssertEqual(value, 203);
761 762
  XCTAssertTrue([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"bar"]);
763
  XCTAssertEqual(value, 201);
764 765
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
766
  XCTAssertEqual(value, 202);
767 768
  XCTAssertTrue([dict getInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"mumble"]);
769 770 771 772 773
  XCTAssertEqual(value, 201);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const int32_t kValues2[] = { 202, 200 };
  GPBStringInt32Dictionary *dict2 =
774
      [[GPBStringInt32Dictionary alloc] initWithInt32s:kValues2
775 776 777 778 779
                                               forKeys:kKeys2
                                                 count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
780 781
  XCTAssertTrue([dict getInt32:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"foo"]);
782
  XCTAssertEqual(value, 203);
783 784
  XCTAssertTrue([dict getInt32:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"bar"]);
785
  XCTAssertEqual(value, 202);
786 787
  XCTAssertTrue([dict getInt32:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"baz"]);
788
  XCTAssertEqual(value, 200);
789 790
  XCTAssertTrue([dict getInt32:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt32:&value forKey:@"mumble"]);
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
  XCTAssertEqual(value, 201);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> UInt64

@interface GPBStringUInt64DictionaryTests : XCTestCase
@end

@implementation GPBStringUInt64DictionaryTests

- (void)testEmpty {
  GPBStringUInt64Dictionary *dict = [[GPBStringUInt64Dictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
810 811
  XCTAssertFalse([dict getUInt64:NULL forKey:@"foo"]);
  [dict enumerateKeysAndUInt64sUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
812 813 814 815 816 817 818
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
819 820
  GPBStringUInt64Dictionary *dict = [[GPBStringUInt64Dictionary alloc] init];
  [dict setUInt64:300U forKey:@"foo"];
821 822 823
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  uint64_t value;
824 825
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
826
  XCTAssertEqual(value, 300U);
827 828
  XCTAssertFalse([dict getUInt64:NULL forKey:@"bar"]);
  [dict enumerateKeysAndUInt64sUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
829 830 831 832
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, 300U);
    XCTAssertNotEqual(stop, NULL);
  }];
833
  [dict release];
834 835 836 837 838 839
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const uint64_t kValues[] = { 300U, 301U, 302U };
  GPBStringUInt64Dictionary *dict =
840 841 842
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
843 844 845
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  uint64_t value;
846 847
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
848
  XCTAssertEqual(value, 300U);
849 850
  XCTAssertTrue([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"bar"]);
851
  XCTAssertEqual(value, 301U);
852 853
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
854
  XCTAssertEqual(value, 302U);
855
  XCTAssertFalse([dict getUInt64:NULL forKey:@"mumble"]);
856 857 858 859

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  uint64_t *seenValues = malloc(3 * sizeof(uint64_t));
860
  [dict enumerateKeysAndUInt64sUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
882
  [dict enumerateKeysAndUInt64sUsingBlock:^(NSString *aKey, uint64_t aValue, BOOL *stop) {
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const uint64_t kValues1[] = { 300U, 301U, 302U };
  const uint64_t kValues2[] = { 300U, 303U, 302U };
  const uint64_t kValues3[] = { 300U, 301U, 302U, 303U };
  GPBStringUInt64Dictionary *dict1 =
898 899 900
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues1
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues1)];
901 902
  XCTAssertNotNil(dict1);
  GPBStringUInt64Dictionary *dict1prime =
903 904 905
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues1
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues1)];
906 907
  XCTAssertNotNil(dict1prime);
  GPBStringUInt64Dictionary *dict2 =
908 909 910
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues2
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues2)];
911 912
  XCTAssertNotNil(dict2);
  GPBStringUInt64Dictionary *dict3 =
913 914 915
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues1
                                                 forKeys:kKeys2
                                                   count:GPBARRAYSIZE(kValues1)];
916 917
  XCTAssertNotNil(dict3);
  GPBStringUInt64Dictionary *dict4 =
918 919 920
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues3
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues3)];
921 922 923 924 925 926 927 928
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

929
  // 2 is same keys, different values; not equal.
930 931
  XCTAssertNotEqualObjects(dict1, dict2);

932
  // 3 is different keys, same values; not equal.
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
  GPBStringUInt64Dictionary *dict =
949 950 951
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
  XCTAssertNotNil(dict);

  GPBStringUInt64Dictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringUInt64Dictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
  GPBStringUInt64Dictionary *dict =
970 971 972
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
973 974 975
  XCTAssertNotNil(dict);

  GPBStringUInt64Dictionary *dict2 =
976
      [[GPBStringUInt64Dictionary alloc] initWithDictionary:dict];
977 978 979 980 981
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
982
  [dict2 release];
983 984 985 986
  [dict release];
}

- (void)testAdds {
987
  GPBStringUInt64Dictionary *dict = [[GPBStringUInt64Dictionary alloc] init];
988 989 990
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
991
  [dict setUInt64:300U forKey:@"foo"];
992 993 994 995 996
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const uint64_t kValues[] = { 301U, 302U, 303U };
  GPBStringUInt64Dictionary *dict2 =
997 998 999
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
1000 1001 1002 1003 1004
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  uint64_t value;
1005 1006
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1007
  XCTAssertEqual(value, 300U);
1008 1009
  XCTAssertTrue([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"bar"]);
1010
  XCTAssertEqual(value, 301U);
1011 1012
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1013
  XCTAssertEqual(value, 302U);
1014 1015
  XCTAssertTrue([dict getUInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"mumble"]);
1016 1017
  XCTAssertEqual(value, 303U);
  [dict2 release];
1018
  [dict release];
1019 1020 1021 1022 1023 1024
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
  GPBStringUInt64Dictionary *dict =
1025 1026 1027
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
1028 1029 1030
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

1031
  [dict removeUInt64ForKey:@"bar"];
1032 1033
  XCTAssertEqual(dict.count, 3U);
  uint64_t value;
1034 1035
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1036
  XCTAssertEqual(value, 300U);
1037 1038 1039
  XCTAssertFalse([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1040
  XCTAssertEqual(value, 302U);
1041 1042
  XCTAssertTrue([dict getUInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"mumble"]);
1043 1044 1045
  XCTAssertEqual(value, 303U);

  // Remove again does nothing.
1046
  [dict removeUInt64ForKey:@"bar"];
1047
  XCTAssertEqual(dict.count, 3U);
1048 1049
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1050
  XCTAssertEqual(value, 300U);
1051 1052 1053
  XCTAssertFalse([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1054
  XCTAssertEqual(value, 302U);
1055 1056
  XCTAssertTrue([dict getUInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"mumble"]);
1057 1058
  XCTAssertEqual(value, 303U);

1059
  [dict removeUInt64ForKey:@"mumble"];
1060
  XCTAssertEqual(dict.count, 2U);
1061 1062
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1063
  XCTAssertEqual(value, 300U);
1064 1065 1066
  XCTAssertFalse([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1067
  XCTAssertEqual(value, 302U);
1068
  XCTAssertFalse([dict getUInt64:NULL forKey:@"mumble"]);
1069 1070 1071

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
1072 1073 1074 1075
  XCTAssertFalse([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getUInt64:NULL forKey:@"mumble"]);
1076 1077 1078 1079 1080 1081 1082
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const uint64_t kValues[] = { 300U, 301U, 302U, 303U };
  GPBStringUInt64Dictionary *dict =
1083 1084 1085
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
1086 1087 1088
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  uint64_t value;
1089 1090
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1091
  XCTAssertEqual(value, 300U);
1092 1093
  XCTAssertTrue([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"bar"]);
1094
  XCTAssertEqual(value, 301U);
1095 1096
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1097
  XCTAssertEqual(value, 302U);
1098 1099
  XCTAssertTrue([dict getUInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"mumble"]);
1100 1101
  XCTAssertEqual(value, 303U);

1102
  [dict setUInt64:303U forKey:@"foo"];
1103
  XCTAssertEqual(dict.count, 4U);
1104 1105
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1106
  XCTAssertEqual(value, 303U);
1107 1108
  XCTAssertTrue([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"bar"]);
1109
  XCTAssertEqual(value, 301U);
1110 1111
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1112
  XCTAssertEqual(value, 302U);
1113 1114
  XCTAssertTrue([dict getUInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"mumble"]);
1115 1116
  XCTAssertEqual(value, 303U);

1117
  [dict setUInt64:301U forKey:@"mumble"];
1118
  XCTAssertEqual(dict.count, 4U);
1119 1120
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1121
  XCTAssertEqual(value, 303U);
1122 1123
  XCTAssertTrue([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"bar"]);
1124
  XCTAssertEqual(value, 301U);
1125 1126
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1127
  XCTAssertEqual(value, 302U);
1128 1129
  XCTAssertTrue([dict getUInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"mumble"]);
1130 1131 1132 1133 1134
  XCTAssertEqual(value, 301U);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const uint64_t kValues2[] = { 302U, 300U };
  GPBStringUInt64Dictionary *dict2 =
1135 1136 1137
      [[GPBStringUInt64Dictionary alloc] initWithUInt64s:kValues2
                                                 forKeys:kKeys2
                                                   count:GPBARRAYSIZE(kValues2)];
1138 1139 1140
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
1141 1142
  XCTAssertTrue([dict getUInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"foo"]);
1143
  XCTAssertEqual(value, 303U);
1144 1145
  XCTAssertTrue([dict getUInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"bar"]);
1146
  XCTAssertEqual(value, 302U);
1147 1148
  XCTAssertTrue([dict getUInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"baz"]);
1149
  XCTAssertEqual(value, 300U);
1150 1151
  XCTAssertTrue([dict getUInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getUInt64:&value forKey:@"mumble"]);
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
  XCTAssertEqual(value, 301U);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> Int64

@interface GPBStringInt64DictionaryTests : XCTestCase
@end

@implementation GPBStringInt64DictionaryTests

- (void)testEmpty {
  GPBStringInt64Dictionary *dict = [[GPBStringInt64Dictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
1171 1172
  XCTAssertFalse([dict getInt64:NULL forKey:@"foo"]);
  [dict enumerateKeysAndInt64sUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
1173 1174 1175 1176 1177 1178 1179
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
1180 1181
  GPBStringInt64Dictionary *dict = [[GPBStringInt64Dictionary alloc] init];
  [dict setInt64:400 forKey:@"foo"];
1182 1183 1184
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  int64_t value;
1185 1186
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1187
  XCTAssertEqual(value, 400);
1188 1189
  XCTAssertFalse([dict getInt64:NULL forKey:@"bar"]);
  [dict enumerateKeysAndInt64sUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
1190 1191 1192 1193
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, 400);
    XCTAssertNotEqual(stop, NULL);
  }];
1194
  [dict release];
1195 1196 1197 1198 1199 1200
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const int64_t kValues[] = { 400, 401, 402 };
  GPBStringInt64Dictionary *dict =
1201
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues
1202 1203 1204 1205 1206
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  int64_t value;
1207 1208
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1209
  XCTAssertEqual(value, 400);
1210 1211
  XCTAssertTrue([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"bar"]);
1212
  XCTAssertEqual(value, 401);
1213 1214
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1215
  XCTAssertEqual(value, 402);
1216
  XCTAssertFalse([dict getInt64:NULL forKey:@"mumble"]);
1217 1218 1219 1220

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  int64_t *seenValues = malloc(3 * sizeof(int64_t));
1221
  [dict enumerateKeysAndInt64sUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
1243
  [dict enumerateKeysAndInt64sUsingBlock:^(NSString *aKey, int64_t aValue, BOOL *stop) {
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const int64_t kValues1[] = { 400, 401, 402 };
  const int64_t kValues2[] = { 400, 403, 402 };
  const int64_t kValues3[] = { 400, 401, 402, 403 };
  GPBStringInt64Dictionary *dict1 =
1259
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues1
1260 1261 1262 1263
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1);
  GPBStringInt64Dictionary *dict1prime =
1264
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues1
1265 1266 1267 1268
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1prime);
  GPBStringInt64Dictionary *dict2 =
1269
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues2
1270 1271 1272 1273
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  GPBStringInt64Dictionary *dict3 =
1274
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues1
1275 1276 1277 1278
                                               forKeys:kKeys2
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict3);
  GPBStringInt64Dictionary *dict4 =
1279
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues3
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues3)];
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

1290
  // 2 is same keys, different values; not equal.
1291 1292
  XCTAssertNotEqualObjects(dict1, dict2);

1293
  // 3 is different keys, same values; not equal.
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int64_t kValues[] = { 400, 401, 402, 403 };
  GPBStringInt64Dictionary *dict =
1310
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringInt64Dictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringInt64Dictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int64_t kValues[] = { 400, 401, 402, 403 };
  GPBStringInt64Dictionary *dict =
1331
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues
1332 1333 1334 1335 1336
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringInt64Dictionary *dict2 =
1337
      [[GPBStringInt64Dictionary alloc] initWithDictionary:dict];
1338 1339 1340 1341 1342
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
1343
  [dict2 release];
1344 1345 1346 1347
  [dict release];
}

- (void)testAdds {
1348
  GPBStringInt64Dictionary *dict = [[GPBStringInt64Dictionary alloc] init];
1349 1350 1351
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
1352
  [dict setInt64:400 forKey:@"foo"];
1353 1354 1355 1356 1357
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const int64_t kValues[] = { 401, 402, 403 };
  GPBStringInt64Dictionary *dict2 =
1358
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues
1359 1360 1361 1362 1363 1364 1365
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  int64_t value;
1366 1367
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1368
  XCTAssertEqual(value, 400);
1369 1370
  XCTAssertTrue([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"bar"]);
1371
  XCTAssertEqual(value, 401);
1372 1373
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1374
  XCTAssertEqual(value, 402);
1375 1376
  XCTAssertTrue([dict getInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"mumble"]);
1377 1378
  XCTAssertEqual(value, 403);
  [dict2 release];
1379
  [dict release];
1380 1381 1382 1383 1384 1385
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int64_t kValues[] = { 400, 401, 402, 403 };
  GPBStringInt64Dictionary *dict =
1386 1387 1388
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
1389 1390 1391
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

1392
  [dict removeInt64ForKey:@"bar"];
1393 1394
  XCTAssertEqual(dict.count, 3U);
  int64_t value;
1395 1396
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1397
  XCTAssertEqual(value, 400);
1398 1399 1400
  XCTAssertFalse([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1401
  XCTAssertEqual(value, 402);
1402 1403
  XCTAssertTrue([dict getInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"mumble"]);
1404 1405 1406
  XCTAssertEqual(value, 403);

  // Remove again does nothing.
1407
  [dict removeInt64ForKey:@"bar"];
1408
  XCTAssertEqual(dict.count, 3U);
1409 1410
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1411
  XCTAssertEqual(value, 400);
1412 1413 1414
  XCTAssertFalse([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1415
  XCTAssertEqual(value, 402);
1416 1417
  XCTAssertTrue([dict getInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"mumble"]);
1418 1419
  XCTAssertEqual(value, 403);

1420
  [dict removeInt64ForKey:@"mumble"];
1421
  XCTAssertEqual(dict.count, 2U);
1422 1423
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1424
  XCTAssertEqual(value, 400);
1425 1426 1427
  XCTAssertFalse([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1428
  XCTAssertEqual(value, 402);
1429
  XCTAssertFalse([dict getInt64:NULL forKey:@"mumble"]);
1430 1431 1432

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
1433 1434 1435 1436
  XCTAssertFalse([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getInt64:NULL forKey:@"mumble"]);
1437 1438 1439 1440 1441 1442 1443
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int64_t kValues[] = { 400, 401, 402, 403 };
  GPBStringInt64Dictionary *dict =
1444 1445 1446
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
1447 1448 1449
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  int64_t value;
1450 1451
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1452
  XCTAssertEqual(value, 400);
1453 1454
  XCTAssertTrue([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"bar"]);
1455
  XCTAssertEqual(value, 401);
1456 1457
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1458
  XCTAssertEqual(value, 402);
1459 1460
  XCTAssertTrue([dict getInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"mumble"]);
1461 1462
  XCTAssertEqual(value, 403);

1463
  [dict setInt64:403 forKey:@"foo"];
1464
  XCTAssertEqual(dict.count, 4U);
1465 1466
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1467
  XCTAssertEqual(value, 403);
1468 1469
  XCTAssertTrue([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"bar"]);
1470
  XCTAssertEqual(value, 401);
1471 1472
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1473
  XCTAssertEqual(value, 402);
1474 1475
  XCTAssertTrue([dict getInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"mumble"]);
1476 1477
  XCTAssertEqual(value, 403);

1478
  [dict setInt64:401 forKey:@"mumble"];
1479
  XCTAssertEqual(dict.count, 4U);
1480 1481
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1482
  XCTAssertEqual(value, 403);
1483 1484
  XCTAssertTrue([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"bar"]);
1485
  XCTAssertEqual(value, 401);
1486 1487
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1488
  XCTAssertEqual(value, 402);
1489 1490
  XCTAssertTrue([dict getInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"mumble"]);
1491 1492 1493 1494 1495
  XCTAssertEqual(value, 401);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const int64_t kValues2[] = { 402, 400 };
  GPBStringInt64Dictionary *dict2 =
1496
      [[GPBStringInt64Dictionary alloc] initWithInt64s:kValues2
1497 1498 1499 1500 1501
                                               forKeys:kKeys2
                                                 count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
1502 1503
  XCTAssertTrue([dict getInt64:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"foo"]);
1504
  XCTAssertEqual(value, 403);
1505 1506
  XCTAssertTrue([dict getInt64:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"bar"]);
1507
  XCTAssertEqual(value, 402);
1508 1509
  XCTAssertTrue([dict getInt64:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"baz"]);
1510
  XCTAssertEqual(value, 400);
1511 1512
  XCTAssertTrue([dict getInt64:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getInt64:&value forKey:@"mumble"]);
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
  XCTAssertEqual(value, 401);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> Bool

@interface GPBStringBoolDictionaryTests : XCTestCase
@end

@implementation GPBStringBoolDictionaryTests

- (void)testEmpty {
  GPBStringBoolDictionary *dict = [[GPBStringBoolDictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
1532 1533
  XCTAssertFalse([dict getBool:NULL forKey:@"foo"]);
  [dict enumerateKeysAndBoolsUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
1534 1535 1536 1537 1538 1539 1540
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
1541 1542
  GPBStringBoolDictionary *dict = [[GPBStringBoolDictionary alloc] init];
  [dict setBool:YES forKey:@"foo"];
1543 1544 1545
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  BOOL value;
1546 1547
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1548
  XCTAssertEqual(value, YES);
1549 1550
  XCTAssertFalse([dict getBool:NULL forKey:@"bar"]);
  [dict enumerateKeysAndBoolsUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
1551 1552 1553 1554
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, YES);
    XCTAssertNotEqual(stop, NULL);
  }];
1555
  [dict release];
1556 1557 1558 1559 1560 1561
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const BOOL kValues[] = { YES, YES, NO };
  GPBStringBoolDictionary *dict =
1562 1563 1564
      [[GPBStringBoolDictionary alloc] initWithBools:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
1565 1566 1567
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  BOOL value;
1568 1569
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1570
  XCTAssertEqual(value, YES);
1571 1572
  XCTAssertTrue([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:&value forKey:@"bar"]);
1573
  XCTAssertEqual(value, YES);
1574 1575
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1576
  XCTAssertEqual(value, NO);
1577
  XCTAssertFalse([dict getBool:NULL forKey:@"mumble"]);
1578 1579 1580 1581

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  BOOL *seenValues = malloc(3 * sizeof(BOOL));
1582
  [dict enumerateKeysAndBoolsUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
1604
  [dict enumerateKeysAndBoolsUsingBlock:^(NSString *aKey, BOOL aValue, BOOL *stop) {
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const BOOL kValues1[] = { YES, YES, NO };
  const BOOL kValues2[] = { YES, NO, NO };
  const BOOL kValues3[] = { YES, YES, NO, NO };
  GPBStringBoolDictionary *dict1 =
1620 1621 1622
      [[GPBStringBoolDictionary alloc] initWithBools:kValues1
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues1)];
1623 1624
  XCTAssertNotNil(dict1);
  GPBStringBoolDictionary *dict1prime =
1625 1626 1627
      [[GPBStringBoolDictionary alloc] initWithBools:kValues1
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues1)];
1628 1629
  XCTAssertNotNil(dict1prime);
  GPBStringBoolDictionary *dict2 =
1630 1631 1632
      [[GPBStringBoolDictionary alloc] initWithBools:kValues2
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues2)];
1633 1634
  XCTAssertNotNil(dict2);
  GPBStringBoolDictionary *dict3 =
1635 1636 1637
      [[GPBStringBoolDictionary alloc] initWithBools:kValues1
                                             forKeys:kKeys2
                                               count:GPBARRAYSIZE(kValues1)];
1638 1639
  XCTAssertNotNil(dict3);
  GPBStringBoolDictionary *dict4 =
1640 1641 1642
      [[GPBStringBoolDictionary alloc] initWithBools:kValues3
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues3)];
1643 1644 1645 1646 1647 1648 1649 1650
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

1651
  // 2 is same keys, different values; not equal.
1652 1653
  XCTAssertNotEqualObjects(dict1, dict2);

1654
  // 3 is different keys, same values; not equal.
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const BOOL kValues[] = { YES, YES, NO, NO };
  GPBStringBoolDictionary *dict =
1671 1672 1673
      [[GPBStringBoolDictionary alloc] initWithBools:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
  XCTAssertNotNil(dict);

  GPBStringBoolDictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringBoolDictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const BOOL kValues[] = { YES, YES, NO, NO };
  GPBStringBoolDictionary *dict =
1692 1693 1694
      [[GPBStringBoolDictionary alloc] initWithBools:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
1695 1696 1697
  XCTAssertNotNil(dict);

  GPBStringBoolDictionary *dict2 =
1698
      [[GPBStringBoolDictionary alloc] initWithDictionary:dict];
1699 1700 1701 1702 1703
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
1704
  [dict2 release];
1705 1706 1707 1708
  [dict release];
}

- (void)testAdds {
1709
  GPBStringBoolDictionary *dict = [[GPBStringBoolDictionary alloc] init];
1710 1711 1712
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
1713
  [dict setBool:YES forKey:@"foo"];
1714 1715 1716 1717 1718
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const BOOL kValues[] = { YES, NO, NO };
  GPBStringBoolDictionary *dict2 =
1719 1720 1721
      [[GPBStringBoolDictionary alloc] initWithBools:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
1722 1723 1724 1725 1726
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  BOOL value;
1727 1728
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1729
  XCTAssertEqual(value, YES);
1730 1731
  XCTAssertTrue([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:&value forKey:@"bar"]);
1732
  XCTAssertEqual(value, YES);
1733 1734
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1735
  XCTAssertEqual(value, NO);
1736 1737
  XCTAssertTrue([dict getBool:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getBool:&value forKey:@"mumble"]);
1738 1739
  XCTAssertEqual(value, NO);
  [dict2 release];
1740
  [dict release];
1741 1742 1743 1744 1745 1746
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const BOOL kValues[] = { YES, YES, NO, NO };
  GPBStringBoolDictionary *dict =
1747 1748 1749
      [[GPBStringBoolDictionary alloc] initWithBools:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
1750 1751 1752
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

1753
  [dict removeBoolForKey:@"bar"];
1754 1755
  XCTAssertEqual(dict.count, 3U);
  BOOL value;
1756 1757
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1758
  XCTAssertEqual(value, YES);
1759 1760 1761
  XCTAssertFalse([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1762
  XCTAssertEqual(value, NO);
1763 1764
  XCTAssertTrue([dict getBool:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getBool:&value forKey:@"mumble"]);
1765 1766 1767
  XCTAssertEqual(value, NO);

  // Remove again does nothing.
1768
  [dict removeBoolForKey:@"bar"];
1769
  XCTAssertEqual(dict.count, 3U);
1770 1771
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1772
  XCTAssertEqual(value, YES);
1773 1774 1775
  XCTAssertFalse([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1776
  XCTAssertEqual(value, NO);
1777 1778
  XCTAssertTrue([dict getBool:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getBool:&value forKey:@"mumble"]);
1779 1780
  XCTAssertEqual(value, NO);

1781
  [dict removeBoolForKey:@"mumble"];
1782
  XCTAssertEqual(dict.count, 2U);
1783 1784
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1785
  XCTAssertEqual(value, YES);
1786 1787 1788
  XCTAssertFalse([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1789
  XCTAssertEqual(value, NO);
1790
  XCTAssertFalse([dict getBool:NULL forKey:@"mumble"]);
1791 1792 1793

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
1794 1795 1796 1797
  XCTAssertFalse([dict getBool:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getBool:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getBool:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getBool:NULL forKey:@"mumble"]);
1798 1799 1800 1801 1802 1803 1804
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const BOOL kValues[] = { YES, YES, NO, NO };
  GPBStringBoolDictionary *dict =
1805 1806 1807
      [[GPBStringBoolDictionary alloc] initWithBools:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
1808 1809 1810
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  BOOL value;
1811 1812
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1813
  XCTAssertEqual(value, YES);
1814 1815
  XCTAssertTrue([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:&value forKey:@"bar"]);
1816
  XCTAssertEqual(value, YES);
1817 1818
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1819
  XCTAssertEqual(value, NO);
1820 1821
  XCTAssertTrue([dict getBool:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getBool:&value forKey:@"mumble"]);
1822 1823
  XCTAssertEqual(value, NO);

1824
  [dict setBool:NO forKey:@"foo"];
1825
  XCTAssertEqual(dict.count, 4U);
1826 1827
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1828
  XCTAssertEqual(value, NO);
1829 1830
  XCTAssertTrue([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:&value forKey:@"bar"]);
1831
  XCTAssertEqual(value, YES);
1832 1833
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1834
  XCTAssertEqual(value, NO);
1835 1836
  XCTAssertTrue([dict getBool:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getBool:&value forKey:@"mumble"]);
1837 1838
  XCTAssertEqual(value, NO);

1839
  [dict setBool:YES forKey:@"mumble"];
1840
  XCTAssertEqual(dict.count, 4U);
1841 1842
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1843
  XCTAssertEqual(value, NO);
1844 1845
  XCTAssertTrue([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:&value forKey:@"bar"]);
1846
  XCTAssertEqual(value, YES);
1847 1848
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1849
  XCTAssertEqual(value, NO);
1850 1851
  XCTAssertTrue([dict getBool:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getBool:&value forKey:@"mumble"]);
1852 1853 1854 1855 1856
  XCTAssertEqual(value, YES);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const BOOL kValues2[] = { NO, YES };
  GPBStringBoolDictionary *dict2 =
1857 1858 1859
      [[GPBStringBoolDictionary alloc] initWithBools:kValues2
                                             forKeys:kKeys2
                                               count:GPBARRAYSIZE(kValues2)];
1860 1861 1862
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
1863 1864
  XCTAssertTrue([dict getBool:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getBool:&value forKey:@"foo"]);
1865
  XCTAssertEqual(value, NO);
1866 1867
  XCTAssertTrue([dict getBool:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getBool:&value forKey:@"bar"]);
1868
  XCTAssertEqual(value, NO);
1869 1870
  XCTAssertTrue([dict getBool:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getBool:&value forKey:@"baz"]);
1871
  XCTAssertEqual(value, YES);
1872 1873
  XCTAssertTrue([dict getBool:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getBool:&value forKey:@"mumble"]);
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892
  XCTAssertEqual(value, YES);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> Float

@interface GPBStringFloatDictionaryTests : XCTestCase
@end

@implementation GPBStringFloatDictionaryTests

- (void)testEmpty {
  GPBStringFloatDictionary *dict = [[GPBStringFloatDictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
1893 1894
  XCTAssertFalse([dict getFloat:NULL forKey:@"foo"]);
  [dict enumerateKeysAndFloatsUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
1895 1896 1897 1898 1899 1900 1901
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
1902 1903
  GPBStringFloatDictionary *dict = [[GPBStringFloatDictionary alloc] init];
  [dict setFloat:500.f forKey:@"foo"];
1904 1905 1906
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  float value;
1907 1908
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
1909
  XCTAssertEqual(value, 500.f);
1910 1911
  XCTAssertFalse([dict getFloat:NULL forKey:@"bar"]);
  [dict enumerateKeysAndFloatsUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
1912 1913 1914 1915
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, 500.f);
    XCTAssertNotEqual(stop, NULL);
  }];
1916
  [dict release];
1917 1918 1919 1920 1921 1922
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const float kValues[] = { 500.f, 501.f, 502.f };
  GPBStringFloatDictionary *dict =
1923
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues
1924 1925 1926 1927 1928
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  float value;
1929 1930
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
1931
  XCTAssertEqual(value, 500.f);
1932 1933
  XCTAssertTrue([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"bar"]);
1934
  XCTAssertEqual(value, 501.f);
1935 1936
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
1937
  XCTAssertEqual(value, 502.f);
1938
  XCTAssertFalse([dict getFloat:NULL forKey:@"mumble"]);
1939 1940 1941 1942

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  float *seenValues = malloc(3 * sizeof(float));
1943
  [dict enumerateKeysAndFloatsUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
1965
  [dict enumerateKeysAndFloatsUsingBlock:^(NSString *aKey, float aValue, BOOL *stop) {
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const float kValues1[] = { 500.f, 501.f, 502.f };
  const float kValues2[] = { 500.f, 503.f, 502.f };
  const float kValues3[] = { 500.f, 501.f, 502.f, 503.f };
  GPBStringFloatDictionary *dict1 =
1981
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues1
1982 1983 1984 1985
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1);
  GPBStringFloatDictionary *dict1prime =
1986
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues1
1987 1988 1989 1990
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1prime);
  GPBStringFloatDictionary *dict2 =
1991
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues2
1992 1993 1994 1995
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  GPBStringFloatDictionary *dict3 =
1996
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues1
1997 1998 1999 2000
                                               forKeys:kKeys2
                                                 count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict3);
  GPBStringFloatDictionary *dict4 =
2001
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues3
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011
                                               forKeys:kKeys1
                                                 count:GPBARRAYSIZE(kValues3)];
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

2012
  // 2 is same keys, different values; not equal.
2013 2014
  XCTAssertNotEqualObjects(dict1, dict2);

2015
  // 3 is different keys, same values; not equal.
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
  GPBStringFloatDictionary *dict =
2032
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringFloatDictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringFloatDictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
  GPBStringFloatDictionary *dict =
2053
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues
2054 2055 2056 2057 2058
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringFloatDictionary *dict2 =
2059
      [[GPBStringFloatDictionary alloc] initWithDictionary:dict];
2060 2061 2062 2063 2064
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
2065
  [dict2 release];
2066 2067 2068 2069
  [dict release];
}

- (void)testAdds {
2070
  GPBStringFloatDictionary *dict = [[GPBStringFloatDictionary alloc] init];
2071 2072 2073
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
2074
  [dict setFloat:500.f forKey:@"foo"];
2075 2076 2077 2078 2079
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const float kValues[] = { 501.f, 502.f, 503.f };
  GPBStringFloatDictionary *dict2 =
2080
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues
2081 2082 2083 2084 2085 2086 2087
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  float value;
2088 2089
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2090
  XCTAssertEqual(value, 500.f);
2091 2092
  XCTAssertTrue([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"bar"]);
2093
  XCTAssertEqual(value, 501.f);
2094 2095
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2096
  XCTAssertEqual(value, 502.f);
2097 2098
  XCTAssertTrue([dict getFloat:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"mumble"]);
2099 2100
  XCTAssertEqual(value, 503.f);
  [dict2 release];
2101
  [dict release];
2102 2103 2104 2105 2106 2107
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
  GPBStringFloatDictionary *dict =
2108 2109 2110
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
2111 2112 2113
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

2114
  [dict removeFloatForKey:@"bar"];
2115 2116
  XCTAssertEqual(dict.count, 3U);
  float value;
2117 2118
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2119
  XCTAssertEqual(value, 500.f);
2120 2121 2122
  XCTAssertFalse([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2123
  XCTAssertEqual(value, 502.f);
2124 2125
  XCTAssertTrue([dict getFloat:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"mumble"]);
2126 2127 2128
  XCTAssertEqual(value, 503.f);

  // Remove again does nothing.
2129
  [dict removeFloatForKey:@"bar"];
2130
  XCTAssertEqual(dict.count, 3U);
2131 2132
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2133
  XCTAssertEqual(value, 500.f);
2134 2135 2136
  XCTAssertFalse([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2137
  XCTAssertEqual(value, 502.f);
2138 2139
  XCTAssertTrue([dict getFloat:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"mumble"]);
2140 2141
  XCTAssertEqual(value, 503.f);

2142
  [dict removeFloatForKey:@"mumble"];
2143
  XCTAssertEqual(dict.count, 2U);
2144 2145
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2146
  XCTAssertEqual(value, 500.f);
2147 2148 2149
  XCTAssertFalse([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2150
  XCTAssertEqual(value, 502.f);
2151
  XCTAssertFalse([dict getFloat:NULL forKey:@"mumble"]);
2152 2153 2154

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
2155 2156 2157 2158
  XCTAssertFalse([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getFloat:NULL forKey:@"mumble"]);
2159 2160 2161 2162 2163 2164 2165
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const float kValues[] = { 500.f, 501.f, 502.f, 503.f };
  GPBStringFloatDictionary *dict =
2166 2167 2168
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
2169 2170 2171
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  float value;
2172 2173
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2174
  XCTAssertEqual(value, 500.f);
2175 2176
  XCTAssertTrue([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"bar"]);
2177
  XCTAssertEqual(value, 501.f);
2178 2179
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2180
  XCTAssertEqual(value, 502.f);
2181 2182
  XCTAssertTrue([dict getFloat:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"mumble"]);
2183 2184
  XCTAssertEqual(value, 503.f);

2185
  [dict setFloat:503.f forKey:@"foo"];
2186
  XCTAssertEqual(dict.count, 4U);
2187 2188
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2189
  XCTAssertEqual(value, 503.f);
2190 2191
  XCTAssertTrue([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"bar"]);
2192
  XCTAssertEqual(value, 501.f);
2193 2194
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2195
  XCTAssertEqual(value, 502.f);
2196 2197
  XCTAssertTrue([dict getFloat:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"mumble"]);
2198 2199
  XCTAssertEqual(value, 503.f);

2200
  [dict setFloat:501.f forKey:@"mumble"];
2201
  XCTAssertEqual(dict.count, 4U);
2202 2203
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2204
  XCTAssertEqual(value, 503.f);
2205 2206
  XCTAssertTrue([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"bar"]);
2207
  XCTAssertEqual(value, 501.f);
2208 2209
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2210
  XCTAssertEqual(value, 502.f);
2211 2212
  XCTAssertTrue([dict getFloat:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"mumble"]);
2213 2214 2215 2216 2217
  XCTAssertEqual(value, 501.f);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const float kValues2[] = { 502.f, 500.f };
  GPBStringFloatDictionary *dict2 =
2218
      [[GPBStringFloatDictionary alloc] initWithFloats:kValues2
2219 2220 2221 2222 2223
                                               forKeys:kKeys2
                                                 count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
2224 2225
  XCTAssertTrue([dict getFloat:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"foo"]);
2226
  XCTAssertEqual(value, 503.f);
2227 2228
  XCTAssertTrue([dict getFloat:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"bar"]);
2229
  XCTAssertEqual(value, 502.f);
2230 2231
  XCTAssertTrue([dict getFloat:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"baz"]);
2232
  XCTAssertEqual(value, 500.f);
2233 2234
  XCTAssertTrue([dict getFloat:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getFloat:&value forKey:@"mumble"]);
2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253
  XCTAssertEqual(value, 501.f);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> Double

@interface GPBStringDoubleDictionaryTests : XCTestCase
@end

@implementation GPBStringDoubleDictionaryTests

- (void)testEmpty {
  GPBStringDoubleDictionary *dict = [[GPBStringDoubleDictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
2254 2255
  XCTAssertFalse([dict getDouble:NULL forKey:@"foo"]);
  [dict enumerateKeysAndDoublesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
2256 2257 2258 2259 2260 2261 2262
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
2263 2264
  GPBStringDoubleDictionary *dict = [[GPBStringDoubleDictionary alloc] init];
  [dict setDouble:600. forKey:@"foo"];
2265 2266 2267
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  double value;
2268 2269
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2270
  XCTAssertEqual(value, 600.);
2271 2272
  XCTAssertFalse([dict getDouble:NULL forKey:@"bar"]);
  [dict enumerateKeysAndDoublesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
2273 2274 2275 2276
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, 600.);
    XCTAssertNotEqual(stop, NULL);
  }];
2277
  [dict release];
2278 2279 2280 2281 2282 2283
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const double kValues[] = { 600., 601., 602. };
  GPBStringDoubleDictionary *dict =
2284 2285 2286
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
2287 2288 2289
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  double value;
2290 2291
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2292
  XCTAssertEqual(value, 600.);
2293 2294
  XCTAssertTrue([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"bar"]);
2295
  XCTAssertEqual(value, 601.);
2296 2297
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2298
  XCTAssertEqual(value, 602.);
2299
  XCTAssertFalse([dict getDouble:NULL forKey:@"mumble"]);
2300 2301 2302 2303

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  double *seenValues = malloc(3 * sizeof(double));
2304
  [dict enumerateKeysAndDoublesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
2326
  [dict enumerateKeysAndDoublesUsingBlock:^(NSString *aKey, double aValue, BOOL *stop) {
2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const double kValues1[] = { 600., 601., 602. };
  const double kValues2[] = { 600., 603., 602. };
  const double kValues3[] = { 600., 601., 602., 603. };
  GPBStringDoubleDictionary *dict1 =
2342 2343 2344
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues1
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues1)];
2345 2346
  XCTAssertNotNil(dict1);
  GPBStringDoubleDictionary *dict1prime =
2347 2348 2349
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues1
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues1)];
2350 2351
  XCTAssertNotNil(dict1prime);
  GPBStringDoubleDictionary *dict2 =
2352 2353 2354
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues2
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues2)];
2355 2356
  XCTAssertNotNil(dict2);
  GPBStringDoubleDictionary *dict3 =
2357 2358 2359
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues1
                                                 forKeys:kKeys2
                                                   count:GPBARRAYSIZE(kValues1)];
2360 2361
  XCTAssertNotNil(dict3);
  GPBStringDoubleDictionary *dict4 =
2362 2363 2364
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues3
                                                 forKeys:kKeys1
                                                   count:GPBARRAYSIZE(kValues3)];
2365 2366 2367 2368 2369 2370 2371 2372
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

2373
  // 2 is same keys, different values; not equal.
2374 2375
  XCTAssertNotEqualObjects(dict1, dict2);

2376
  // 3 is different keys, same values; not equal.
2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const double kValues[] = { 600., 601., 602., 603. };
  GPBStringDoubleDictionary *dict =
2393 2394 2395
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
  XCTAssertNotNil(dict);

  GPBStringDoubleDictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringDoubleDictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const double kValues[] = { 600., 601., 602., 603. };
  GPBStringDoubleDictionary *dict =
2414 2415 2416
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
2417 2418 2419
  XCTAssertNotNil(dict);

  GPBStringDoubleDictionary *dict2 =
2420
      [[GPBStringDoubleDictionary alloc] initWithDictionary:dict];
2421 2422 2423 2424 2425
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
2426
  [dict2 release];
2427 2428 2429 2430
  [dict release];
}

- (void)testAdds {
2431
  GPBStringDoubleDictionary *dict = [[GPBStringDoubleDictionary alloc] init];
2432 2433 2434
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
2435
  [dict setDouble:600. forKey:@"foo"];
2436 2437 2438 2439 2440
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const double kValues[] = { 601., 602., 603. };
  GPBStringDoubleDictionary *dict2 =
2441 2442 2443
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
2444 2445 2446 2447 2448
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  double value;
2449 2450
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2451
  XCTAssertEqual(value, 600.);
2452 2453
  XCTAssertTrue([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"bar"]);
2454
  XCTAssertEqual(value, 601.);
2455 2456
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2457
  XCTAssertEqual(value, 602.);
2458 2459
  XCTAssertTrue([dict getDouble:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"mumble"]);
2460 2461
  XCTAssertEqual(value, 603.);
  [dict2 release];
2462
  [dict release];
2463 2464 2465 2466 2467 2468
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const double kValues[] = { 600., 601., 602., 603. };
  GPBStringDoubleDictionary *dict =
2469 2470 2471
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
2472 2473 2474
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

2475
  [dict removeDoubleForKey:@"bar"];
2476 2477
  XCTAssertEqual(dict.count, 3U);
  double value;
2478 2479
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2480
  XCTAssertEqual(value, 600.);
2481 2482 2483
  XCTAssertFalse([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2484
  XCTAssertEqual(value, 602.);
2485 2486
  XCTAssertTrue([dict getDouble:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"mumble"]);
2487 2488 2489
  XCTAssertEqual(value, 603.);

  // Remove again does nothing.
2490
  [dict removeDoubleForKey:@"bar"];
2491
  XCTAssertEqual(dict.count, 3U);
2492 2493
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2494
  XCTAssertEqual(value, 600.);
2495 2496 2497
  XCTAssertFalse([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2498
  XCTAssertEqual(value, 602.);
2499 2500
  XCTAssertTrue([dict getDouble:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"mumble"]);
2501 2502
  XCTAssertEqual(value, 603.);

2503
  [dict removeDoubleForKey:@"mumble"];
2504
  XCTAssertEqual(dict.count, 2U);
2505 2506
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2507
  XCTAssertEqual(value, 600.);
2508 2509 2510
  XCTAssertFalse([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2511
  XCTAssertEqual(value, 602.);
2512
  XCTAssertFalse([dict getDouble:NULL forKey:@"mumble"]);
2513 2514 2515

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
2516 2517 2518 2519
  XCTAssertFalse([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getDouble:NULL forKey:@"mumble"]);
2520 2521 2522 2523 2524 2525 2526
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const double kValues[] = { 600., 601., 602., 603. };
  GPBStringDoubleDictionary *dict =
2527 2528 2529
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues
                                                 forKeys:kKeys
                                                   count:GPBARRAYSIZE(kValues)];
2530 2531 2532
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  double value;
2533 2534
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2535
  XCTAssertEqual(value, 600.);
2536 2537
  XCTAssertTrue([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"bar"]);
2538
  XCTAssertEqual(value, 601.);
2539 2540
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2541
  XCTAssertEqual(value, 602.);
2542 2543
  XCTAssertTrue([dict getDouble:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"mumble"]);
2544 2545
  XCTAssertEqual(value, 603.);

2546
  [dict setDouble:603. forKey:@"foo"];
2547
  XCTAssertEqual(dict.count, 4U);
2548 2549
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2550
  XCTAssertEqual(value, 603.);
2551 2552
  XCTAssertTrue([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"bar"]);
2553
  XCTAssertEqual(value, 601.);
2554 2555
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2556
  XCTAssertEqual(value, 602.);
2557 2558
  XCTAssertTrue([dict getDouble:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"mumble"]);
2559 2560
  XCTAssertEqual(value, 603.);

2561
  [dict setDouble:601. forKey:@"mumble"];
2562
  XCTAssertEqual(dict.count, 4U);
2563 2564
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2565
  XCTAssertEqual(value, 603.);
2566 2567
  XCTAssertTrue([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"bar"]);
2568
  XCTAssertEqual(value, 601.);
2569 2570
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2571
  XCTAssertEqual(value, 602.);
2572 2573
  XCTAssertTrue([dict getDouble:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"mumble"]);
2574 2575 2576 2577 2578
  XCTAssertEqual(value, 601.);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const double kValues2[] = { 602., 600. };
  GPBStringDoubleDictionary *dict2 =
2579 2580 2581
      [[GPBStringDoubleDictionary alloc] initWithDoubles:kValues2
                                                 forKeys:kKeys2
                                                   count:GPBARRAYSIZE(kValues2)];
2582 2583 2584
  XCTAssertNotNil(dict2);
  [dict addEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
2585 2586
  XCTAssertTrue([dict getDouble:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"foo"]);
2587
  XCTAssertEqual(value, 603.);
2588 2589
  XCTAssertTrue([dict getDouble:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"bar"]);
2590
  XCTAssertEqual(value, 602.);
2591 2592
  XCTAssertTrue([dict getDouble:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"baz"]);
2593
  XCTAssertEqual(value, 600.);
2594 2595
  XCTAssertTrue([dict getDouble:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getDouble:&value forKey:@"mumble"]);
2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614
  XCTAssertEqual(value, 601.);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> Enum

@interface GPBStringEnumDictionaryTests : XCTestCase
@end

@implementation GPBStringEnumDictionaryTests

- (void)testEmpty {
  GPBStringEnumDictionary *dict = [[GPBStringEnumDictionary alloc] init];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 0U);
2615 2616
  XCTAssertFalse([dict getEnum:NULL forKey:@"foo"]);
  [dict enumerateKeysAndEnumsUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
2617 2618 2619 2620 2621 2622 2623
    #pragma unused(aKey, aValue, stop)
    XCTFail(@"Shouldn't get here!");
  }];
  [dict release];
}

- (void)testOne {
2624 2625
  GPBStringEnumDictionary *dict = [[GPBStringEnumDictionary alloc] init];
  [dict setEnum:700 forKey:@"foo"];
2626 2627 2628
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 1U);
  int32_t value;
2629 2630
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2631
  XCTAssertEqual(value, 700);
2632 2633
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  [dict enumerateKeysAndEnumsUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
2634 2635 2636 2637
    XCTAssertEqualObjects(aKey, @"foo");
    XCTAssertEqual(aValue, 700);
    XCTAssertNotEqual(stop, NULL);
  }];
2638
  [dict release];
2639 2640 2641 2642 2643 2644
}

- (void)testBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const int32_t kValues[] = { 700, 701, 702 };
  GPBStringEnumDictionary *dict =
2645 2646 2647
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
2648 2649 2650
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  int32_t value;
2651 2652
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2653
  XCTAssertEqual(value, 700);
2654 2655
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
2656
  XCTAssertEqual(value, 701);
2657 2658
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2659
  XCTAssertEqual(value, 702);
2660
  XCTAssertFalse([dict getEnum:NULL forKey:@"mumble"]);
2661 2662 2663 2664

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  int32_t *seenValues = malloc(3 * sizeof(int32_t));
2665
  [dict enumerateKeysAndEnumsUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
2687
  [dict enumerateKeysAndEnumsUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEquality {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const int32_t kValues1[] = { 700, 701, 702 };
  const int32_t kValues2[] = { 700, 703, 702 };
  const int32_t kValues3[] = { 700, 701, 702, 703 };
  GPBStringEnumDictionary *dict1 =
2703 2704 2705
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues1
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues1)];
2706 2707
  XCTAssertNotNil(dict1);
  GPBStringEnumDictionary *dict1prime =
2708 2709 2710
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues1
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues1)];
2711 2712
  XCTAssertNotNil(dict1prime);
  GPBStringEnumDictionary *dict2 =
2713 2714 2715
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues2
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues2)];
2716 2717
  XCTAssertNotNil(dict2);
  GPBStringEnumDictionary *dict3 =
2718 2719 2720
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues1
                                             forKeys:kKeys2
                                               count:GPBARRAYSIZE(kValues1)];
2721 2722
  XCTAssertNotNil(dict3);
  GPBStringEnumDictionary *dict4 =
2723 2724 2725
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues3
                                             forKeys:kKeys1
                                               count:GPBARRAYSIZE(kValues3)];
2726 2727 2728 2729 2730 2731 2732 2733
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

2734
  // 2 is same keys, different values; not equal.
2735 2736
  XCTAssertNotEqualObjects(dict1, dict2);

2737
  // 3 is different keys, same values; not equal.
2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopy {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 701, 702, 703 };
  GPBStringEnumDictionary *dict =
2754 2755 2756
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774
  XCTAssertNotNil(dict);

  GPBStringEnumDictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new object but equal.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 701, 702, 703 };
  GPBStringEnumDictionary *dict =
2775 2776 2777
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
2778 2779 2780
  XCTAssertNotNil(dict);

  GPBStringEnumDictionary *dict2 =
2781
      [[GPBStringEnumDictionary alloc] initWithDictionary:dict];
2782 2783 2784 2785 2786
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
2787
  [dict2 release];
2788 2789 2790 2791
  [dict release];
}

- (void)testAdds {
2792
  GPBStringEnumDictionary *dict = [[GPBStringEnumDictionary alloc] init];
2793 2794 2795
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
2796
  [dict setEnum:700 forKey:@"foo"];
2797 2798 2799 2800 2801
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 701, 702, 703 };
  GPBStringEnumDictionary *dict2 =
2802 2803 2804
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
2805 2806 2807 2808 2809
  XCTAssertNotNil(dict2);
  [dict addRawEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  int32_t value;
2810 2811
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2812
  XCTAssertEqual(value, 700);
2813 2814
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
2815
  XCTAssertEqual(value, 701);
2816 2817
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2818
  XCTAssertEqual(value, 702);
2819 2820
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
2821 2822
  XCTAssertEqual(value, 703);
  [dict2 release];
2823
  [dict release];
2824 2825 2826 2827 2828 2829
}

- (void)testRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 701, 702, 703 };
  GPBStringEnumDictionary *dict =
2830 2831 2832
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
2833 2834 2835
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

2836
  [dict removeEnumForKey:@"bar"];
2837 2838
  XCTAssertEqual(dict.count, 3U);
  int32_t value;
2839 2840
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2841
  XCTAssertEqual(value, 700);
2842 2843 2844
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2845
  XCTAssertEqual(value, 702);
2846 2847
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
2848 2849 2850
  XCTAssertEqual(value, 703);

  // Remove again does nothing.
2851
  [dict removeEnumForKey:@"bar"];
2852
  XCTAssertEqual(dict.count, 3U);
2853 2854
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2855
  XCTAssertEqual(value, 700);
2856 2857 2858
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2859
  XCTAssertEqual(value, 702);
2860 2861
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
2862 2863
  XCTAssertEqual(value, 703);

2864
  [dict removeEnumForKey:@"mumble"];
2865
  XCTAssertEqual(dict.count, 2U);
2866 2867
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2868
  XCTAssertEqual(value, 700);
2869 2870 2871
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2872
  XCTAssertEqual(value, 702);
2873
  XCTAssertFalse([dict getEnum:NULL forKey:@"mumble"]);
2874 2875 2876

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
2877 2878 2879 2880
  XCTAssertFalse([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getEnum:NULL forKey:@"mumble"]);
2881 2882 2883 2884 2885 2886 2887
  [dict release];
}

- (void)testInplaceMutation {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 701, 702, 703 };
  GPBStringEnumDictionary *dict =
2888 2889 2890
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues
                                             forKeys:kKeys
                                               count:GPBARRAYSIZE(kValues)];
2891 2892 2893
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  int32_t value;
2894 2895
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2896
  XCTAssertEqual(value, 700);
2897 2898
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
2899
  XCTAssertEqual(value, 701);
2900 2901
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2902
  XCTAssertEqual(value, 702);
2903 2904
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
2905 2906
  XCTAssertEqual(value, 703);

2907
  [dict setEnum:703 forKey:@"foo"];
2908
  XCTAssertEqual(dict.count, 4U);
2909 2910
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2911
  XCTAssertEqual(value, 703);
2912 2913
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
2914
  XCTAssertEqual(value, 701);
2915 2916
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2917
  XCTAssertEqual(value, 702);
2918 2919
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
2920 2921
  XCTAssertEqual(value, 703);

2922
  [dict setEnum:701 forKey:@"mumble"];
2923
  XCTAssertEqual(dict.count, 4U);
2924 2925
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2926
  XCTAssertEqual(value, 703);
2927 2928
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
2929
  XCTAssertEqual(value, 701);
2930 2931
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2932
  XCTAssertEqual(value, 702);
2933 2934
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
2935 2936 2937 2938 2939
  XCTAssertEqual(value, 701);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const int32_t kValues2[] = { 702, 700 };
  GPBStringEnumDictionary *dict2 =
2940 2941 2942
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues2
                                             forKeys:kKeys2
                                               count:GPBARRAYSIZE(kValues2)];
2943 2944 2945
  XCTAssertNotNil(dict2);
  [dict addRawEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
2946 2947
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
2948
  XCTAssertEqual(value, 703);
2949 2950
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
2951
  XCTAssertEqual(value, 702);
2952 2953
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
2954
  XCTAssertEqual(value, 700);
2955 2956
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983
  XCTAssertEqual(value, 701);

  [dict2 release];
  [dict release];
}

@end

#pragma mark - String -> Enum (Unknown Enums)

@interface GPBStringEnumDictionaryUnknownEnumTests : XCTestCase
@end

@implementation GPBStringEnumDictionaryUnknownEnumTests

- (void)testRawBasics {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz" };
  const int32_t kValues[] = { 700, 801, 702 };
  GPBStringEnumDictionary *dict =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues
                                                          forKeys:kKeys
                                                            count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 3U);
  XCTAssertTrue(dict.validationFunc == TestingEnum_IsValidValue);  // Pointer comparison
  int32_t value;
2984 2985
  XCTAssertTrue([dict getRawValue:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"foo"]);
2986
  XCTAssertEqual(value, 700);
2987 2988
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
2989
  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
2990 2991
  XCTAssertTrue([dict getRawValue:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"bar"]);
2992
  XCTAssertEqual(value, 801);
2993 2994
  XCTAssertTrue([dict getRawValue:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"baz"]);
2995
  XCTAssertEqual(value, 702);
2996
  XCTAssertFalse([dict getRawValue:NULL forKey:@"mumble"]);
2997 2998 2999 3000

  __block NSUInteger idx = 0;
  NSString **seenKeys = malloc(3 * sizeof(NSString*));
  int32_t *seenValues = malloc(3 * sizeof(int32_t));
3001
  [dict enumerateKeysAndEnumsUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        if (i == 1) {
          XCTAssertEqual(kGPBUnrecognizedEnumeratorValue, seenValues[j], @"i = %d, j = %d", i, j);
        } else {
          XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
        }
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  idx = 0;
  [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
    XCTAssertLessThan(idx, 3U);
    seenKeys[idx] = aKey;
    seenValues[idx] = aValue;
    XCTAssertNotEqual(stop, NULL);
    ++idx;
  }];
  for (int i = 0; i < 3; ++i) {
    BOOL foundKey = NO;
    for (int j = 0; (j < 3) && !foundKey; ++j) {
      if ([kKeys[i] isEqual:seenKeys[j]]) {
        foundKey = YES;
        XCTAssertEqual(kValues[i], seenValues[j], @"i = %d, j = %d", i, j);
      }
    }
    XCTAssertTrue(foundKey, @"i = %d", i);
  }
  free(seenKeys);
  free(seenValues);

  // Stopping the enumeration.
  idx = 0;
  [dict enumerateKeysAndRawValuesUsingBlock:^(NSString *aKey, int32_t aValue, BOOL *stop) {
    #pragma unused(aKey, aValue)
    if (idx == 1) *stop = YES;
    XCTAssertNotEqual(idx, 2U);
    ++idx;
  }];
  [dict release];
}

- (void)testEqualityWithUnknowns {
  const NSString *kKeys1[] = { @"foo", @"bar", @"baz", @"mumble" };
  const NSString *kKeys2[] = { @"bar", @"foo", @"mumble" };
  const int32_t kValues1[] = { 700, 801, 702 };  // Unknown
  const int32_t kValues2[] = { 700, 803, 702 };  // Unknown
  const int32_t kValues3[] = { 700, 801, 702, 803 };  // Unknowns
  GPBStringEnumDictionary *dict1 =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues1
                                                          forKeys:kKeys1
                                                            count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1);
  GPBStringEnumDictionary *dict1prime =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues1
                                                          forKeys:kKeys1
                                                            count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict1prime);
  GPBStringEnumDictionary *dict2 =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues2
                                                          forKeys:kKeys1
                                                            count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  GPBStringEnumDictionary *dict3 =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues1
                                                          forKeys:kKeys2
                                                            count:GPBARRAYSIZE(kValues1)];
  XCTAssertNotNil(dict3);
  GPBStringEnumDictionary *dict4 =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues3
                                                          forKeys:kKeys1
                                                            count:GPBARRAYSIZE(kValues3)];
  XCTAssertNotNil(dict4);

  // 1/1Prime should be different objects, but equal.
  XCTAssertNotEqual(dict1, dict1prime);
  XCTAssertEqualObjects(dict1, dict1prime);
  // Equal, so they must have same hash.
  XCTAssertEqual([dict1 hash], [dict1prime hash]);

3097
  // 2 is same keys, different values; not equal.
3098 3099
  XCTAssertNotEqualObjects(dict1, dict2);

3100
  // 3 is different keys, same values; not equal.
3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145
  XCTAssertNotEqualObjects(dict1, dict3);

  // 4 extra pair; not equal
  XCTAssertNotEqualObjects(dict1, dict4);

  [dict1 release];
  [dict1prime release];
  [dict2 release];
  [dict3 release];
  [dict4 release];
}

- (void)testCopyWithUnknowns {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknown
  GPBStringEnumDictionary *dict =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues
                                                          forKeys:kKeys
                                                            count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringEnumDictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
  XCTAssertEqualObjects(dict, dict2);

  [dict2 release];
  [dict release];
}

- (void)testDictionaryFromDictionary {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
  GPBStringEnumDictionary *dict =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues
                                                          forKeys:kKeys
                                                            count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringEnumDictionary *dict2 =
3146
      [[GPBStringEnumDictionary alloc] initWithDictionary:dict];
3147 3148 3149 3150 3151 3152
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
3153
  [dict2 release];
3154 3155 3156 3157 3158
  [dict release];
}

- (void)testUnknownAdds {
  GPBStringEnumDictionary *dict =
3159
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue];
3160 3161 3162
  XCTAssertNotNil(dict);

  XCTAssertEqual(dict.count, 0U);
3163
  XCTAssertThrowsSpecificNamed([dict setEnum:801 forKey:@"bar"],  // Unknown
3164 3165 3166 3167 3168 3169 3170 3171
                               NSException, NSInvalidArgumentException);
  XCTAssertEqual(dict.count, 0U);
  [dict setRawValue:801 forKey:@"bar"];  // Unknown
  XCTAssertEqual(dict.count, 1U);

  const NSString *kKeys[] = { @"foo", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 702, 803 };  // Unknown
  GPBStringEnumDictionary *dict2 =
3172 3173 3174
      [[GPBStringEnumDictionary alloc] initWithEnums:kValues
                                               forKeys:kKeys
                                                 count:GPBARRAYSIZE(kValues)];
3175 3176 3177 3178 3179
  XCTAssertNotNil(dict2);
  [dict addRawEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);

  int32_t value;
3180 3181
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
3182
  XCTAssertEqual(value, 700);
3183 3184
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
3185
  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
3186 3187
  XCTAssertTrue([dict getRawValue:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"bar"]);
3188
  XCTAssertEqual(value, 801);
3189 3190
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3191
  XCTAssertEqual(value, 702);
3192 3193
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
3194
  XCTAssertEqual(value, kGPBUnrecognizedEnumeratorValue);
3195 3196
  XCTAssertTrue([dict getRawValue:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"mumble"]);
3197 3198
  XCTAssertEqual(value, 803);
  [dict2 release];
3199
  [dict release];
3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212
}

- (void)testUnknownRemove {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
  GPBStringEnumDictionary *dict =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues
                                                          forKeys:kKeys
                                                            count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);

3213
  [dict removeEnumForKey:@"bar"];
3214 3215
  XCTAssertEqual(dict.count, 3U);
  int32_t value;
3216 3217
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
3218
  XCTAssertEqual(value, 700);
3219 3220 3221
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3222
  XCTAssertEqual(value, 702);
3223 3224
  XCTAssertTrue([dict getRawValue:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"mumble"]);
3225 3226 3227
  XCTAssertEqual(value, 803);

  // Remove again does nothing.
3228
  [dict removeEnumForKey:@"bar"];
3229
  XCTAssertEqual(dict.count, 3U);
3230 3231
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
3232
  XCTAssertEqual(value, 700);
3233 3234 3235
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3236
  XCTAssertEqual(value, 702);
3237 3238
  XCTAssertTrue([dict getRawValue:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"mumble"]);
3239 3240
  XCTAssertEqual(value, 803);

3241
  [dict removeEnumForKey:@"mumble"];
3242
  XCTAssertEqual(dict.count, 2U);
3243 3244
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
3245
  XCTAssertEqual(value, 700);
3246 3247 3248
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3249
  XCTAssertEqual(value, 702);
3250
  XCTAssertFalse([dict getEnum:NULL forKey:@"mumble"]);
3251 3252 3253

  [dict removeAll];
  XCTAssertEqual(dict.count, 0U);
3254 3255 3256 3257
  XCTAssertFalse([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertFalse([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertFalse([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertFalse([dict getEnum:NULL forKey:@"mumble"]);
3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271
  [dict release];
}

- (void)testInplaceMutationUnknowns {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 801, 702, 803 };  // Unknowns
  GPBStringEnumDictionary *dict =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues
                                                          forKeys:kKeys
                                                            count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);
  XCTAssertEqual(dict.count, 4U);
  int32_t value;
3272 3273
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
3274
  XCTAssertEqual(value, 700);
3275 3276
  XCTAssertTrue([dict getRawValue:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"bar"]);
3277
  XCTAssertEqual(value, 801);
3278 3279
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3280
  XCTAssertEqual(value, 702);
3281 3282
  XCTAssertTrue([dict getRawValue:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"mumble"]);
3283 3284
  XCTAssertEqual(value, 803);

3285
  XCTAssertThrowsSpecificNamed([dict setEnum:803 forKey:@"foo"],  // Unknown
3286 3287
                               NSException, NSInvalidArgumentException);
  XCTAssertEqual(dict.count, 4U);
3288 3289
  XCTAssertTrue([dict getEnum:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"foo"]);
3290
  XCTAssertEqual(value, 700);
3291 3292
  XCTAssertTrue([dict getRawValue:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"bar"]);
3293
  XCTAssertEqual(value, 801);
3294 3295
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3296
  XCTAssertEqual(value, 702);
3297 3298
  XCTAssertTrue([dict getRawValue:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"mumble"]);
3299 3300 3301 3302
  XCTAssertEqual(value, 803);

  [dict setRawValue:803 forKey:@"foo"];  // Unknown
  XCTAssertEqual(dict.count, 4U);
3303 3304
  XCTAssertTrue([dict getRawValue:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"foo"]);
3305
  XCTAssertEqual(value, 803);
3306 3307
  XCTAssertTrue([dict getRawValue:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"bar"]);
3308
  XCTAssertEqual(value, 801);
3309 3310
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3311
  XCTAssertEqual(value, 702);
3312 3313
  XCTAssertTrue([dict getRawValue:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"mumble"]);
3314 3315 3316 3317
  XCTAssertEqual(value, 803);

  [dict setRawValue:700 forKey:@"mumble"];
  XCTAssertEqual(dict.count, 4U);
3318 3319
  XCTAssertTrue([dict getRawValue:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"foo"]);
3320
  XCTAssertEqual(value, 803);
3321 3322
  XCTAssertTrue([dict getRawValue:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"bar"]);
3323
  XCTAssertEqual(value, 801);
3324 3325
  XCTAssertTrue([dict getEnum:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"baz"]);
3326
  XCTAssertEqual(value, 702);
3327 3328
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340
  XCTAssertEqual(value, 700);

  const NSString *kKeys2[] = { @"bar", @"baz" };
  const int32_t kValues2[] = { 702, 801 };  // Unknown
  GPBStringEnumDictionary *dict2 =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues2
                                                          forKeys:kKeys2
                                                            count:GPBARRAYSIZE(kValues2)];
  XCTAssertNotNil(dict2);
  [dict addRawEntriesFromDictionary:dict2];
  XCTAssertEqual(dict.count, 4U);
3341 3342
  XCTAssertTrue([dict getRawValue:NULL forKey:@"foo"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"foo"]);
3343
  XCTAssertEqual(value, 803);
3344 3345
  XCTAssertTrue([dict getEnum:NULL forKey:@"bar"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"bar"]);
3346
  XCTAssertEqual(value, 702);
3347 3348
  XCTAssertTrue([dict getRawValue:NULL forKey:@"baz"]);
  XCTAssertTrue([dict getRawValue:&value forKey:@"baz"]);
3349
  XCTAssertEqual(value, 801);
3350 3351
  XCTAssertTrue([dict getEnum:NULL forKey:@"mumble"]);
  XCTAssertTrue([dict getEnum:&value forKey:@"mumble"]);
3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384
  XCTAssertEqual(value, 700);

  [dict2 release];
  [dict release];
}

- (void)testCopyUnknowns {
  const NSString *kKeys[] = { @"foo", @"bar", @"baz", @"mumble" };
  const int32_t kValues[] = { 700, 801, 702, 803 };
  GPBStringEnumDictionary *dict =
      [[GPBStringEnumDictionary alloc] initWithValidationFunction:TestingEnum_IsValidValue
                                                        rawValues:kValues
                                                          forKeys:kKeys
                                                            count:GPBARRAYSIZE(kValues)];
  XCTAssertNotNil(dict);

  GPBStringEnumDictionary *dict2 = [dict copy];
  XCTAssertNotNil(dict2);

  // Should be new pointer, but equal objects.
  XCTAssertNotEqual(dict, dict2);
  XCTAssertEqualObjects(dict, dict2);
  XCTAssertEqual(dict.validationFunc, dict2.validationFunc);  // Pointer comparison
  XCTAssertTrue([dict2 isKindOfClass:[GPBStringEnumDictionary class]]);

  [dict2 release];
  [dict release];
}

@end

//%PDDM-EXPAND-END TESTS_FOR_POD_VALUES(String, NSString, *, Objects, @"foo", @"bar", @"baz", @"mumble")