GPBUnknownFieldSetTest.m 18.3 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
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#import "GPBTestUtilities.h"

33
#import "GPBUnknownField_PackagePrivate.h"
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
#import "GPBUnknownFieldSet_PackagePrivate.h"
#import "google/protobuf/Unittest.pbobjc.h"

@interface GPBUnknownFieldSet (GPBUnknownFieldSetTest)
- (void)getTags:(int32_t*)tags;
@end

@interface UnknownFieldSetTest : GPBTestCase {
 @private
  TestAllTypes* allFields_;
  NSData* allFieldsData_;

  // An empty message that has been parsed from allFieldsData.  So, it has
  // unknown fields of every type.
  TestEmptyMessage* emptyMessage_;
  GPBUnknownFieldSet* unknownFields_;
}

@end

@implementation UnknownFieldSetTest

- (void)setUp {
  allFields_ = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
  allFieldsData_ = [allFields_ data];
59
  emptyMessage_ = [TestEmptyMessage parseFromData:allFieldsData_ error:NULL];
60 61 62
  unknownFields_ = emptyMessage_.unknownFields;
}

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
- (void)testInvalidFieldNumber {
  GPBUnknownFieldSet *set = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* field = [[[GPBUnknownField alloc] initWithNumber:0] autorelease];
  XCTAssertThrowsSpecificNamed([set addField:field], NSException, NSInvalidArgumentException);
}

- (void)testEqualityAndHash {
  // Empty

  GPBUnknownFieldSet *set1 = [[[GPBUnknownFieldSet alloc] init] autorelease];
  XCTAssertTrue([set1 isEqual:set1]);
  XCTAssertFalse([set1 isEqual:@"foo"]);
  GPBUnknownFieldSet *set2 = [[[GPBUnknownFieldSet alloc] init] autorelease];
  XCTAssertEqualObjects(set1, set2);
  XCTAssertEqual([set1 hash], [set2 hash]);

  // Varint

  GPBUnknownField* field1 = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
  [field1 addVarint:1];
  [set1 addField:field1];
  XCTAssertNotEqualObjects(set1, set2);
  GPBUnknownField* field2 = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
  [field2 addVarint:1];
  [set2 addField:field2];
  XCTAssertEqualObjects(set1, set2);
  XCTAssertEqual([set1 hash], [set2 hash]);

  // Fixed32

  field1 = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
  [field1 addFixed32:2];
  [set1 addField:field1];
  XCTAssertNotEqualObjects(set1, set2);
  field2 = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
  [field2 addFixed32:2];
  [set2 addField:field2];
  XCTAssertEqualObjects(set1, set2);
  XCTAssertEqual([set1 hash], [set2 hash]);

  // Fixed64

  field1 = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
  [field1 addFixed64:3];
  [set1 addField:field1];
  XCTAssertNotEqualObjects(set1, set2);
  field2 = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
  [field2 addFixed64:3];
  [set2 addField:field2];
  XCTAssertEqualObjects(set1, set2);
  XCTAssertEqual([set1 hash], [set2 hash]);

  // LengthDelimited

  field1 = [[[GPBUnknownField alloc] initWithNumber:4] autorelease];
  [field1 addLengthDelimited:DataFromCStr("foo")];
  [set1 addField:field1];
  XCTAssertNotEqualObjects(set1, set2);
  field2 = [[[GPBUnknownField alloc] initWithNumber:4] autorelease];
  [field2 addLengthDelimited:DataFromCStr("foo")];
  [set2 addField:field2];
  XCTAssertEqualObjects(set1, set2);
  XCTAssertEqual([set1 hash], [set2 hash]);

  // Group

  GPBUnknownFieldSet *group1 = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* fieldGroup1 = [[[GPBUnknownField alloc] initWithNumber:10] autorelease];
  [fieldGroup1 addVarint:1];
  [group1 addField:fieldGroup1];
  GPBUnknownFieldSet *group2 = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* fieldGroup2 = [[[GPBUnknownField alloc] initWithNumber:10] autorelease];
  [fieldGroup2 addVarint:1];
  [group2 addField:fieldGroup2];

  field1 = [[[GPBUnknownField alloc] initWithNumber:5] autorelease];
  [field1 addGroup:group1];
  [set1 addField:field1];
  XCTAssertNotEqualObjects(set1, set2);
  field2 = [[[GPBUnknownField alloc] initWithNumber:5] autorelease];
  [field2 addGroup:group2];
  [set2 addField:field2];
  XCTAssertEqualObjects(set1, set2);
  XCTAssertEqual([set1 hash], [set2 hash]);

  // Exercise description for completeness.
  XCTAssertTrue(set1.description.length > 10);
}

152 153 154 155 156 157 158 159 160 161 162
// Constructs a protocol buffer which contains fields with all the same
// numbers as allFieldsData except that each field is some other wire
// type.
- (NSData*)getBizarroData {
  GPBUnknownFieldSet* bizarroFields =
      [[[GPBUnknownFieldSet alloc] init] autorelease];
  NSUInteger count = [unknownFields_ countOfFields];
  int32_t tags[count];
  [unknownFields_ getTags:tags];
  for (NSUInteger i = 0; i < count; ++i) {
    int32_t tag = tags[i];
163
    GPBUnknownField* field = [unknownFields_ getField:tag];
164 165
    if (field.varintList.count == 0) {
      // Original field is not a varint, so use a varint.
166 167
      GPBUnknownField* varintField =
          [[[GPBUnknownField alloc] initWithNumber:tag] autorelease];
168 169 170 171
      [varintField addVarint:1];
      [bizarroFields addField:varintField];
    } else {
      // Original field *is* a varint, so use something else.
172 173
      GPBUnknownField* fixed32Field =
          [[[GPBUnknownField alloc] initWithNumber:tag] autorelease];
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
      [fixed32Field addFixed32:1];
      [bizarroFields addField:fixed32Field];
    }
  }

  return [bizarroFields data];
}

- (void)testSerialize {
  // Check that serializing the UnknownFieldSet produces the original data
  // again.
  NSData* data = [emptyMessage_ data];
  XCTAssertEqualObjects(allFieldsData_, data);
}

- (void)testCopyFrom {
  TestEmptyMessage* message = [TestEmptyMessage message];
  [message mergeFrom:emptyMessage_];

  XCTAssertEqualObjects(emptyMessage_.data, message.data);
}

- (void)testMergeFrom {
  GPBUnknownFieldSet* set1 = [[[GPBUnknownFieldSet alloc] init] autorelease];
198
  GPBUnknownField* field = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
199 200
  [field addVarint:2];
  [set1 addField:field];
201
  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
202 203
  [field addVarint:4];
  [set1 addField:field];
204 205 206 207 208 209
  field = [[[GPBUnknownField alloc] initWithNumber:4] autorelease];
  [field addFixed32:6];
  [set1 addField:field];
  field = [[[GPBUnknownField alloc] initWithNumber:5] autorelease];
  [field addFixed64:20];
  [set1 addField:field];
210 211 212
  field = [[[GPBUnknownField alloc] initWithNumber:10] autorelease];
  [field addLengthDelimited:DataFromCStr("data1")];
  [set1 addField:field];
213

214 215 216 217 218 219 220 221 222
  GPBUnknownFieldSet *group1 = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* fieldGroup1 = [[[GPBUnknownField alloc] initWithNumber:200] autorelease];
  [fieldGroup1 addVarint:100];
  [group1 addField:fieldGroup1];

  field = [[[GPBUnknownField alloc] initWithNumber:11] autorelease];
  [field addGroup:group1];
  [set1 addField:field];

223
  GPBUnknownFieldSet* set2 = [[[GPBUnknownFieldSet alloc] init] autorelease];
224
  field = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
225 226
  [field addVarint:1];
  [set2 addField:field];
227
  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
228 229
  [field addVarint:3];
  [set2 addField:field];
230 231 232 233 234 235
  field = [[[GPBUnknownField alloc] initWithNumber:4] autorelease];
  [field addFixed32:7];
  [set2 addField:field];
  field = [[[GPBUnknownField alloc] initWithNumber:5] autorelease];
  [field addFixed64:30];
  [set2 addField:field];
236 237 238
  field = [[[GPBUnknownField alloc] initWithNumber:10] autorelease];
  [field addLengthDelimited:DataFromCStr("data2")];
  [set2 addField:field];
239

240 241 242 243 244 245 246 247 248
  GPBUnknownFieldSet *group2 = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* fieldGroup2 = [[[GPBUnknownField alloc] initWithNumber:201] autorelease];
  [fieldGroup2 addVarint:99];
  [group2 addField:fieldGroup2];

  field = [[[GPBUnknownField alloc] initWithNumber:11] autorelease];
  [field addGroup:group2];
  [set2 addField:field];

249
  GPBUnknownFieldSet* set3 = [[[GPBUnknownFieldSet alloc] init] autorelease];
250
  field = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
251 252
  [field addVarint:1];
  [set3 addField:field];
253
  field = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
254
  [field addVarint:2];
255
  [set3 addField:field];
256
  field = [[[GPBUnknownField alloc] initWithNumber:3] autorelease];
257 258
  [field addVarint:4];
  [set3 addField:field];
259
  [field addVarint:3];
260
  [set3 addField:field];
261 262 263 264 265 266 267 268
  field = [[[GPBUnknownField alloc] initWithNumber:4] autorelease];
  [field addFixed32:6];
  [field addFixed32:7];
  [set3 addField:field];
  field = [[[GPBUnknownField alloc] initWithNumber:5] autorelease];
  [field addFixed64:20];
  [field addFixed64:30];
  [set3 addField:field];
269 270 271 272
  field = [[[GPBUnknownField alloc] initWithNumber:10] autorelease];
  [field addLengthDelimited:DataFromCStr("data1")];
  [field addLengthDelimited:DataFromCStr("data2")];
  [set3 addField:field];
273

274 275 276 277 278 279 280 281 282 283 284 285 286 287
  GPBUnknownFieldSet *group3a = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* fieldGroup3a1 = [[[GPBUnknownField alloc] initWithNumber:200] autorelease];
  [fieldGroup3a1 addVarint:100];
  [group3a addField:fieldGroup3a1];
  GPBUnknownFieldSet *group3b = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* fieldGroup3b2 = [[[GPBUnknownField alloc] initWithNumber:201] autorelease];
  [fieldGroup3b2 addVarint:99];
  [group3b addField:fieldGroup3b2];

  field = [[[GPBUnknownField alloc] initWithNumber:11] autorelease];
  [field addGroup:group1];
  [field addGroup:group3b];
  [set3 addField:field];

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
  TestEmptyMessage* source1 = [TestEmptyMessage message];
  [source1 setUnknownFields:set1];
  TestEmptyMessage* source2 = [TestEmptyMessage message];
  [source2 setUnknownFields:set2];
  TestEmptyMessage* source3 = [TestEmptyMessage message];
  [source3 setUnknownFields:set3];

  TestEmptyMessage* destination1 = [TestEmptyMessage message];
  [destination1 mergeFrom:source1];
  [destination1 mergeFrom:source2];

  TestEmptyMessage* destination2 = [TestEmptyMessage message];
  [destination2 mergeFrom:source3];

  XCTAssertEqualObjects(destination1.data, destination2.data);
303 304
  XCTAssertEqualObjects(destination1.data, source3.data);
  XCTAssertEqualObjects(destination2.data, source3.data);
305 306 307
}

- (void)testClearMessage {
308
  TestEmptyMessage *message = [TestEmptyMessage message];
309 310 311 312 313 314 315
  [message mergeFrom:emptyMessage_];
  [message clear];
  XCTAssertEqual(message.serializedSize, (size_t)0);
}

- (void)testParseKnownAndUnknown {
  // Test mixing known and unknown fields when parsing.
316 317 318
  GPBUnknownFieldSet *fields = [[unknownFields_ copy] autorelease];
  GPBUnknownField *field =
    [[[GPBUnknownField alloc] initWithNumber:123456] autorelease];
319 320 321 322
  [field addVarint:654321];
  [fields addField:field];

  NSData* data = fields.data;
323
  TestAllTypes* destination = [TestAllTypes parseFromData:data error:NULL];
324 325 326 327

  [self assertAllFieldsSet:destination repeatedCount:kGPBDefaultRepeatCount];
  XCTAssertEqual(destination.unknownFields.countOfFields, (NSUInteger)1);

328
  GPBUnknownField* field2 = [destination.unknownFields getField:123456];
329 330 331 332 333 334 335 336 337
  XCTAssertEqual(field2.varintList.count, (NSUInteger)1);
  XCTAssertEqual(654321ULL, [field2.varintList valueAtIndex:0]);
}

- (void)testWrongTypeTreatedAsUnknown {
  // Test that fields of the wrong wire type are treated like unknown fields
  // when parsing.

  NSData* bizarroData = [self getBizarroData];
338 339 340 341
  TestAllTypes* allTypesMessage =
      [TestAllTypes parseFromData:bizarroData error:NULL];
  TestEmptyMessage* emptyMessage =
      [TestEmptyMessage parseFromData:bizarroData error:NULL];
342 343 344 345 346 347 348 349 350 351 352

  // All fields should have been interpreted as unknown, so the debug strings
  // should be the same.
  XCTAssertEqualObjects(emptyMessage.data, allTypesMessage.data);
}

- (void)testUnknownExtensions {
  // Make sure fields are properly parsed to the UnknownFieldSet even when
  // they are declared as extension numbers.

  TestEmptyMessageWithExtensions* message =
353
      [TestEmptyMessageWithExtensions parseFromData:allFieldsData_ error:NULL];
354 355 356 357 358 359 360 361 362 363 364 365

  XCTAssertEqual(unknownFields_.countOfFields,
                 message.unknownFields.countOfFields);
  XCTAssertEqualObjects(allFieldsData_, message.data);
}

- (void)testWrongExtensionTypeTreatedAsUnknown {
  // Test that fields of the wrong wire type are treated like unknown fields
  // when parsing extensions.

  NSData* bizarroData = [self getBizarroData];
  TestAllExtensions* allExtensionsMessage =
366 367 368
      [TestAllExtensions parseFromData:bizarroData error:NULL];
  TestEmptyMessage* emptyMessage =
      [TestEmptyMessage parseFromData:bizarroData error:NULL];
369 370 371 372 373 374 375 376

  // All fields should have been interpreted as unknown, so the debug strings
  // should be the same.
  XCTAssertEqualObjects(emptyMessage.data, allExtensionsMessage.data);
}

- (void)testLargeVarint {
  GPBUnknownFieldSet* fields = [[unknownFields_ copy] autorelease];
377
  GPBUnknownField* field = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
378 379 380 381 382 383 384
  [field addVarint:0x7FFFFFFFFFFFFFFFL];
  [fields addField:field];

  NSData* data = [fields data];

  GPBUnknownFieldSet* parsed = [[[GPBUnknownFieldSet alloc] init] autorelease];
  [parsed mergeFromData:data];
385
  GPBUnknownField* field2 = [parsed getField:1];
386 387 388 389
  XCTAssertEqual(field2.varintList.count, (NSUInteger)1);
  XCTAssertEqual(0x7FFFFFFFFFFFFFFFULL, [field2.varintList valueAtIndex:0]);
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
#pragma mark - Field tests
// Some tests directly on fields since the dictionary in FieldSet can gate
// testing some of these.

- (void)testFieldEqualityAndHash {
  GPBUnknownField* field1 = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
  XCTAssertTrue([field1 isEqual:field1]);
  XCTAssertFalse([field1 isEqual:@"foo"]);
  GPBUnknownField* field2 = [[[GPBUnknownField alloc] initWithNumber:2] autorelease];
  XCTAssertNotEqualObjects(field1, field2);

  field2 = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);

  // Varint

  [field1 addVarint:10];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addVarint:10];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);
  [field1 addVarint:11];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addVarint:11];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);

  // Fixed32

  [field1 addFixed32:20];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addFixed32:20];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);
  [field1 addFixed32:21];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addFixed32:21];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);

  // Fixed64

  [field1 addFixed64:30];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addFixed64:30];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);
  [field1 addFixed64:31];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addFixed64:31];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);

  // LengthDelimited

  [field1 addLengthDelimited:DataFromCStr("foo")];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addLengthDelimited:DataFromCStr("foo")];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);
  [field1 addLengthDelimited:DataFromCStr("bar")];
  XCTAssertNotEqualObjects(field1, field2);
  [field2 addLengthDelimited:DataFromCStr("bar")];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);

  // Group

  GPBUnknownFieldSet *group = [[[GPBUnknownFieldSet alloc] init] autorelease];
  GPBUnknownField* fieldGroup = [[[GPBUnknownField alloc] initWithNumber:100] autorelease];
  [fieldGroup addVarint:100];
  [group addField:fieldGroup];
  [field1 addGroup:group];
  XCTAssertNotEqualObjects(field1, field2);
  group = [[[GPBUnknownFieldSet alloc] init] autorelease];
  fieldGroup = [[[GPBUnknownField alloc] initWithNumber:100] autorelease];
  [fieldGroup addVarint:100];
  [group addField:fieldGroup];
  [field2 addGroup:group];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);

  group = [[[GPBUnknownFieldSet alloc] init] autorelease];
  fieldGroup = [[[GPBUnknownField alloc] initWithNumber:101] autorelease];
  [fieldGroup addVarint:101];
  [group addField:fieldGroup];
  [field1 addGroup:group];
  XCTAssertNotEqualObjects(field1, field2);
  group = [[[GPBUnknownFieldSet alloc] init] autorelease];
  fieldGroup = [[[GPBUnknownField alloc] initWithNumber:101] autorelease];
  [fieldGroup addVarint:101];
  [group addField:fieldGroup];
  [field2 addGroup:group];
  XCTAssertEqualObjects(field1, field2);
  XCTAssertEqual([field1 hash], [field2 hash]);

  // Exercise description for completeness.
  XCTAssertTrue(field1.description.length > 10);
}

491
- (void)testMergingFields {
492
  GPBUnknownField* field1 = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
493 494 495 496 497
  [field1 addVarint:1];
  [field1 addFixed32:2];
  [field1 addFixed64:3];
  [field1 addLengthDelimited:[NSData dataWithBytes:"hello" length:5]];
  [field1 addGroup:[[unknownFields_ copy] autorelease]];
498
  GPBUnknownField* field2 = [[[GPBUnknownField alloc] initWithNumber:1] autorelease];
499 500 501 502
  [field2 mergeFromField:field1];
}

@end