• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3//
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file or at
6// https://developers.google.com/open-source/licenses/bsd
7
8#import <XCTest/XCTest.h>
9#import <objc/runtime.h>
10
11#import "GPBDescriptor.h"
12#import "GPBDescriptor_PackagePrivate.h"
13#import "GPBMessage.h"
14#import "GPBTestUtilities.h"
15#import "GPBUnknownField.h"
16#import "GPBUnknownField_PackagePrivate.h"
17#import "GPBUtilities.h"
18#import "GPBUtilities_PackagePrivate.h"
19#import "objectivec/Tests/MapUnittest.pbobjc.h"
20#import "objectivec/Tests/Unittest.pbobjc.h"
21#import "objectivec/Tests/UnittestObjc.pbobjc.h"
22
23@interface UtilitiesTests : GPBTestCase
24@end
25
26@implementation UtilitiesTests
27
28- (void)testRightShiftFunctions {
29  XCTAssertEqual((1UL << 31) >> 31, 1UL);
30  XCTAssertEqual((int32_t)(1U << 31) >> 31, -1);
31  XCTAssertEqual((1ULL << 63) >> 63, 1ULL);
32  XCTAssertEqual((int64_t)(1ULL << 63) >> 63, -1LL);
33
34  XCTAssertEqual(GPBLogicalRightShift32((1U << 31), 31), 1);
35  XCTAssertEqual(GPBLogicalRightShift64((1ULL << 63), 63), 1LL);
36}
37
38- (void)testGPBDecodeTextFormatName {
39  uint8_t decodeData[] = {
40      // clang-format off
41    0x6,
42    // An inlined string (first to make sure the leading null is handled
43    // correctly, and with a key of zero to check that).
44    0x0, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0,
45    // All as is (00 op)
46    0x1, 0x0A, 0x0,
47    // Underscore, upper + 9 (10 op)
48    0x3, 0xCA, 0x0,
49    //  Upper + 3 (10 op), underscore, upper + 5 (10 op)
50    0x2, 0x44, 0xC6, 0x0,
51    // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op),
52    // underscore, lower + 0 (01 op)
53    0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0,
54    // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op),
55    //   underscore, lower + 3 (01 op), underscore, lower + 1 (01 op),
56    //   underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 op),
57    //   underscore, as is + 3 (00 op)
58    0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0,
59      // clang-format on
60  };
61  NSString *inputStr = @"abcdefghIJ";
62
63  // Empty inputs
64
65  XCTAssertNil(GPBDecodeTextFormatName(nil, 1, NULL));
66  XCTAssertNil(GPBDecodeTextFormatName(decodeData, 1, NULL));
67  XCTAssertNil(GPBDecodeTextFormatName(nil, 1, inputStr));
68
69  // Keys not found.
70
71  XCTAssertNil(GPBDecodeTextFormatName(decodeData, 5, inputStr));
72  XCTAssertNil(GPBDecodeTextFormatName(decodeData, -1, inputStr));
73
74  // Some name decodes.
75
76  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1, inputStr), @"abcdefghIJ");
77  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 2, inputStr), @"Abcd_EfghIJ");
78  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 3, inputStr), @"_AbcdefghIJ");
79  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 4, inputStr), @"ABCD__EfghI_j");
80
81  // An inlined string (and key of zero).
82  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 0, inputStr), @"zbcdefghIJ");
83
84  // clang-format off
85  // Long name so multiple decode ops are needed.
86  inputStr = @"longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000";
87  XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1000, inputStr),
88                        @"long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000");
89  // clang-format on
90}
91
92- (void)testTextFormat {
93  TestAllTypes *message = [TestAllTypes message];
94
95  // Not kGPBDefaultRepeatCount because we are comparing to golden master file
96  // which was generated with 2.
97  [self setAllFields:message repeatedCount:2];
98
99  NSString *result = GPBTextFormatForMessage(message, nil);
100
101  NSString *fileName = @"text_format_unittest_data.txt";
102  NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding];
103  NSData *expectedData = [self getDataFileNamed:fileName dataToWrite:resultData];
104  NSString *expected = [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding];
105  XCTAssertEqualObjects(expected, result);
106  [expected release];
107}
108
109- (void)testTextFormatExtra {
110  // -testTextFormat uses all protos with fields that don't require special
111  // handing for figuring out the names.  The ObjC proto has a bunch of oddball
112  // field and enum names that require the decode info to get right, so this
113  // confirms they generated and decoded correctly.
114
115  self_Class *message = [self_Class message];
116  message.cmd = YES;
117  message.isProxy_p = YES;
118  message.subEnum = self_autorelease_RetainCount;
119  message.new_p.copy_p = @"foo";
120
121  // clang-format off
122  NSString *expected = @"_cmd: true\n"
123                       @"isProxy: true\n"
124                       @"SubEnum: retainCount\n"
125                       @"New {\n"
126                       @"  copy: \"foo\"\n"
127                       @"}\n";
128  // clang-format on
129  NSString *result = GPBTextFormatForMessage(message, nil);
130  XCTAssertEqualObjects(expected, result);
131}
132
133- (void)testTextFormatMaps {
134  TestMap *message = [TestMap message];
135
136  // Map iteration order doesn't have to be stable, so use only one entry.
137  [self setAllMapFields:message numEntries:1];
138
139  NSString *result = GPBTextFormatForMessage(message, nil);
140
141  NSString *fileName = @"text_format_map_unittest_data.txt";
142  NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding];
143  NSData *expectedData = [self getDataFileNamed:fileName dataToWrite:resultData];
144  NSString *expected = [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding];
145  XCTAssertEqualObjects(expected, result);
146  [expected release];
147}
148
149- (void)testTextFormatExtensions {
150  TestAllExtensions *message = [TestAllExtensions message];
151
152  // Not kGPBDefaultRepeatCount because we are comparing to golden master file
153  // which was generated with 2.
154  [self setAllExtensions:message repeatedCount:2];
155
156  NSString *result = GPBTextFormatForMessage(message, nil);
157
158  // NOTE: ObjC TextFormat doesn't have the proper extension names so it
159  // uses comments for the ObjC name and raw numbers for the fields instead
160  // of the bracketed extension name.
161  NSString *fileName = @"text_format_extensions_unittest_data.txt";
162  NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding];
163  NSData *expectedData = [self getDataFileNamed:fileName dataToWrite:resultData];
164  NSString *expected = [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding];
165  XCTAssertEqualObjects(expected, result);
166  [expected release];
167}
168
169- (void)testTextFormatUnknownFields {
170  GPBUnknownFields *ufs = [[[GPBUnknownFields alloc] init] autorelease];
171  [ufs addFieldNumber:100 varint:5];
172  [ufs addFieldNumber:100 varint:4];
173  [ufs addFieldNumber:10 varint:1];
174  [ufs addFieldNumber:300 fixed32:0x50];
175  [ufs addFieldNumber:300 fixed32:0x40];
176  [ufs addFieldNumber:10 fixed32:0x10];
177  [ufs addFieldNumber:200 fixed64:0x5000];
178  [ufs addFieldNumber:200 fixed64:0x4000];
179  [ufs addFieldNumber:10 fixed64:0x1000];
180  [ufs addFieldNumber:10 lengthDelimited:DataFromCStr("foo")];
181  [ufs addFieldNumber:10 lengthDelimited:DataFromCStr("bar")];
182  GPBUnknownFields *group = [ufs addGroupWithFieldNumber:150];
183  [group addFieldNumber:2 varint:2];
184  [group addFieldNumber:1 varint:1];
185  group = [ufs addGroupWithFieldNumber:150];
186  [group addFieldNumber:1 varint:1];
187  [group addFieldNumber:3 fixed32:0x3];
188  [group addFieldNumber:2 fixed64:0x2];
189  TestEmptyMessage *message = [TestEmptyMessage message];
190  XCTAssertTrue([message mergeUnknownFields:ufs extensionRegistry:nil error:NULL]);
191
192  NSString *expected = @"# --- Unknown fields ---\n"
193                       @"10: 1\n"
194                       @"10: 0x10\n"
195                       @"10: 0x1000\n"
196                       @"10: \"foo\"\n"
197                       @"10: \"bar\"\n"
198                       @"100: 5\n"
199                       @"100: 4\n"
200                       @"150: {\n"
201                       @"  1: 1\n"
202                       @"  2: 2\n"
203                       @"}\n"
204                       @"150: {\n"
205                       @"  1: 1\n"
206                       @"  2: 0x2\n"
207                       @"  3: 0x3\n"
208                       @"}\n"
209                       @"200: 0x5000\n"
210                       @"200: 0x4000\n"
211                       @"300: 0x50\n"
212                       @"300: 0x40\n";
213  NSString *result = GPBTextFormatForMessage(message, nil);
214  XCTAssertEqualObjects(expected, result);
215}
216
217- (void)testSetRepeatedFields {
218  TestAllTypes *message = [TestAllTypes message];
219
220  NSDictionary *repeatedFieldValues = @{
221    @"repeatedStringArray" : [@[ @"foo", @"bar" ] mutableCopy],
222    @"repeatedBoolArray" : [GPBBoolArray arrayWithValue:YES],
223    @"repeatedInt32Array" : [GPBInt32Array arrayWithValue:14],
224    @"repeatedInt64Array" : [GPBInt64Array arrayWithValue:15],
225    @"repeatedUint32Array" : [GPBUInt32Array arrayWithValue:16],
226    @"repeatedUint64Array" : [GPBUInt64Array arrayWithValue:16],
227    @"repeatedFloatArray" : [GPBFloatArray arrayWithValue:16],
228    @"repeatedDoubleArray" : [GPBDoubleArray arrayWithValue:16],
229    @"repeatedNestedEnumArray" :
230        [GPBEnumArray arrayWithValidationFunction:TestAllTypes_NestedEnum_IsValidValue
231                                         rawValue:TestAllTypes_NestedEnum_Foo],
232  };
233  for (NSString *fieldName in repeatedFieldValues) {
234    GPBFieldDescriptor *field = [message.descriptor fieldWithName:fieldName];
235    XCTAssertNotNil(field, @"No field with name: %@", fieldName);
236    id expectedValues = repeatedFieldValues[fieldName];
237    GPBSetMessageRepeatedField(message, field, expectedValues);
238    XCTAssertEqualObjects(expectedValues, [message valueForKeyPath:fieldName]);
239  }
240}
241
242#pragma clang diagnostic push
243#pragma clang diagnostic ignored "-Wdeprecated-declarations"
244// Helper to make an unknown field set with something in it.
245static GPBUnknownFieldSet *UnknownFieldsSetHelper(int num) {
246  GPBUnknownFieldSet *result = [[[GPBUnknownFieldSet alloc] init] autorelease];
247
248  GPBUnknownField *field = [[[GPBUnknownField alloc] initWithNumber:num] autorelease];
249  [field addVarint:num];
250  [result addField:field];
251
252  return result;
253}
254#pragma clang diagnostic pop
255
256// Helper to add an unknown field data to messages.
257static void AddUnknownFields(GPBMessage *message, int num) {
258  GPBUnknownFields *ufs = [[GPBUnknownFields alloc] init];
259  [ufs addFieldNumber:num varint:num];
260  // Can't fail since it is a varint.
261  [message mergeUnknownFields:ufs extensionRegistry:nil error:NULL];
262  [ufs release];
263}
264
265static BOOL HasUnknownFields(GPBMessage *message) {
266  GPBUnknownFields *ufs = [[GPBUnknownFields alloc] initFromMessage:message];
267  BOOL result = !ufs.empty;
268  [ufs release];
269  return result;
270}
271
272- (void)testDropMessageUnknownFieldsRecursively {
273  TestAllExtensions *message = [TestAllExtensions message];
274
275#pragma clang diagnostic push
276#pragma clang diagnostic ignored "-Wdeprecated-declarations"
277
278  // Give it unknownFields.
279  message.unknownFields = UnknownFieldsSetHelper(777);
280  AddUnknownFields(message, 1777);
281
282  // Given it extensions that include a message with unknown fields of its own.
283  {
284    // Int
285    [message setExtension:[UnittestRoot optionalInt32Extension] value:@5];
286
287    // Group
288    OptionalGroup_extension *optionalGroup = [OptionalGroup_extension message];
289    optionalGroup.a = 123;
290    optionalGroup.unknownFields = UnknownFieldsSetHelper(779);
291    AddUnknownFields(optionalGroup, 1779);
292    [message setExtension:[UnittestRoot optionalGroupExtension] value:optionalGroup];
293
294    // Message
295    TestAllTypes_NestedMessage *nestedMessage = [TestAllTypes_NestedMessage message];
296    nestedMessage.bb = 456;
297    nestedMessage.unknownFields = UnknownFieldsSetHelper(778);
298    AddUnknownFields(nestedMessage, 1778);
299    [message setExtension:[UnittestRoot optionalNestedMessageExtension] value:nestedMessage];
300
301    // Repeated Group
302    RepeatedGroup_extension *repeatedGroup = [[RepeatedGroup_extension alloc] init];
303    repeatedGroup.a = 567;
304    repeatedGroup.unknownFields = UnknownFieldsSetHelper(780);
305    AddUnknownFields(repeatedGroup, 1780);
306    [message addExtension:[UnittestRoot repeatedGroupExtension] value:repeatedGroup];
307    [repeatedGroup release];
308
309    // Repeated Message
310    nestedMessage = [[TestAllTypes_NestedMessage alloc] init];
311    nestedMessage.bb = 678;
312    nestedMessage.unknownFields = UnknownFieldsSetHelper(781);
313    AddUnknownFields(nestedMessage, 1781);
314    [message addExtension:[UnittestRoot repeatedNestedMessageExtension] value:nestedMessage];
315    [nestedMessage release];
316  }
317
318  // Confirm everything is there.
319
320  XCTAssertNotNil(message);
321  XCTAssertTrue(HasUnknownFields(message));
322  XCTAssertNotNil(message.unknownFields);
323  XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]);
324
325  {
326    XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]);
327    OptionalGroup_extension *optionalGroup =
328        [message getExtension:[UnittestRoot optionalGroupExtension]];
329    XCTAssertNotNil(optionalGroup);
330    XCTAssertEqual(optionalGroup.a, 123);
331    XCTAssertTrue(HasUnknownFields(optionalGroup));
332    XCTAssertNotNil(optionalGroup.unknownFields);
333  }
334
335  {
336    XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
337    TestAllTypes_NestedMessage *nestedMessage =
338        [message getExtension:[UnittestRoot optionalNestedMessageExtension]];
339    XCTAssertNotNil(nestedMessage);
340    XCTAssertEqual(nestedMessage.bb, 456);
341    XCTAssertTrue(HasUnknownFields(nestedMessage));
342    XCTAssertNotNil(nestedMessage.unknownFields);
343  }
344
345  {
346    XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]);
347    NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]];
348    XCTAssertEqual(repeatedGroups.count, (NSUInteger)1);
349    RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject;
350    XCTAssertNotNil(repeatedGroup);
351    XCTAssertEqual(repeatedGroup.a, 567);
352    XCTAssertTrue(HasUnknownFields(repeatedGroup));
353    XCTAssertNotNil(repeatedGroup.unknownFields);
354  }
355
356  {
357    XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]);
358    NSArray *repeatedNestedMessages =
359        [message getExtension:[UnittestRoot repeatedNestedMessageExtension]];
360    XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1);
361    TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject;
362    XCTAssertNotNil(repeatedNestedMessage);
363    XCTAssertEqual(repeatedNestedMessage.bb, 678);
364    XCTAssertTrue(HasUnknownFields(repeatedNestedMessage));
365    XCTAssertNotNil(repeatedNestedMessage.unknownFields);
366  }
367
368  // Drop them.
369  GPBMessageDropUnknownFieldsRecursively(message);
370
371  // Confirm unknowns are gone from within the messages.
372
373  XCTAssertNotNil(message);
374  XCTAssertFalse(HasUnknownFields(message));
375  XCTAssertNil(message.unknownFields);
376  XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]);
377
378  {
379    XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]);
380    OptionalGroup_extension *optionalGroup =
381        [message getExtension:[UnittestRoot optionalGroupExtension]];
382    XCTAssertNotNil(optionalGroup);
383    XCTAssertEqual(optionalGroup.a, 123);
384    XCTAssertFalse(HasUnknownFields(optionalGroup));
385    XCTAssertNil(optionalGroup.unknownFields);
386  }
387
388  {
389    XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
390    TestAllTypes_NestedMessage *nestedMessage =
391        [message getExtension:[UnittestRoot optionalNestedMessageExtension]];
392    XCTAssertNotNil(nestedMessage);
393    XCTAssertEqual(nestedMessage.bb, 456);
394    XCTAssertFalse(HasUnknownFields(nestedMessage));
395    XCTAssertNil(nestedMessage.unknownFields);
396  }
397
398  {
399    XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]);
400    NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]];
401    XCTAssertEqual(repeatedGroups.count, (NSUInteger)1);
402    RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject;
403    XCTAssertNotNil(repeatedGroup);
404    XCTAssertEqual(repeatedGroup.a, 567);
405    XCTAssertFalse(HasUnknownFields(repeatedGroup));
406    XCTAssertNil(repeatedGroup.unknownFields);
407  }
408
409  {
410    XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]);
411    NSArray *repeatedNestedMessages =
412        [message getExtension:[UnittestRoot repeatedNestedMessageExtension]];
413    XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1);
414    TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject;
415    XCTAssertNotNil(repeatedNestedMessage);
416    XCTAssertEqual(repeatedNestedMessage.bb, 678);
417    XCTAssertFalse(HasUnknownFields(repeatedNestedMessage));
418    XCTAssertNil(repeatedNestedMessage.unknownFields);
419  }
420
421#pragma clang diagnostic pop
422}
423
424- (void)testDropMessageUnknownFieldsRecursively_Maps {
425  TestMap *message = [TestMap message];
426
427#pragma clang diagnostic push
428#pragma clang diagnostic ignored "-Wdeprecated-declarations"
429
430  {
431    ForeignMessage *foreignMessage = [ForeignMessage message];
432    foreignMessage.unknownFields = UnknownFieldsSetHelper(100);
433    AddUnknownFields(foreignMessage, 1000);
434    [message.mapInt32ForeignMessage setObject:foreignMessage forKey:100];
435
436    foreignMessage = [ForeignMessage message];
437    foreignMessage.unknownFields = UnknownFieldsSetHelper(101);
438    AddUnknownFields(foreignMessage, 1001);
439    [message.mapStringForeignMessage setObject:foreignMessage forKey:@"101"];
440  }
441
442  // Confirm everything is there.
443
444  XCTAssertNotNil(message);
445
446  {
447    ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100];
448    XCTAssertNotNil(foreignMessage);
449    XCTAssertTrue(HasUnknownFields(foreignMessage));
450    XCTAssertNotNil(foreignMessage.unknownFields);
451  }
452
453  {
454    ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"];
455    XCTAssertNotNil(foreignMessage);
456    XCTAssertTrue(HasUnknownFields(foreignMessage));
457    XCTAssertNotNil(foreignMessage.unknownFields);
458  }
459
460  GPBMessageDropUnknownFieldsRecursively(message);
461
462  // Confirm unknowns are gone from within the messages.
463
464  XCTAssertNotNil(message);
465
466  {
467    ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100];
468    XCTAssertNotNil(foreignMessage);
469    XCTAssertFalse(HasUnknownFields(foreignMessage));
470    XCTAssertNil(foreignMessage.unknownFields);
471  }
472
473  {
474    ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"];
475    XCTAssertNotNil(foreignMessage);
476    XCTAssertFalse(HasUnknownFields(foreignMessage));
477    XCTAssertNil(foreignMessage.unknownFields);
478  }
479
480#pragma clang diagnostic pop
481}
482
483@end
484