Home | History | Annotate | Download | only in Tests
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 #import "GPBTestUtilities.h"
     32 
     33 #import "GPBCodedInputStream.h"
     34 #import "GPBCodedOutputStream.h"
     35 #import "GPBUnknownFieldSet_PackagePrivate.h"
     36 #import "GPBUtilities_PackagePrivate.h"
     37 #import "google/protobuf/Unittest.pbobjc.h"
     38 
     39 @interface CodedInputStreamTests : GPBTestCase
     40 @end
     41 
     42 @implementation CodedInputStreamTests
     43 
     44 - (NSData*)bytes_with_sentinel:(int32_t)unused, ... {
     45   va_list list;
     46   va_start(list, unused);
     47 
     48   NSMutableData* values = [NSMutableData dataWithCapacity:0];
     49   int32_t i;
     50 
     51   while ((i = va_arg(list, int32_t)) != 256) {
     52     NSAssert(i >= 0 && i < 256, @"");
     53     uint8_t u = (uint8_t)i;
     54     [values appendBytes:&u length:1];
     55   }
     56 
     57   va_end(list);
     58 
     59   return values;
     60 }
     61 
     62 #define bytes(...) [self bytes_with_sentinel:0, __VA_ARGS__, 256]
     63 
     64 - (void)testDecodeZigZag {
     65   XCTAssertEqual(0, GPBDecodeZigZag32(0));
     66   XCTAssertEqual(-1, GPBDecodeZigZag32(1));
     67   XCTAssertEqual(1, GPBDecodeZigZag32(2));
     68   XCTAssertEqual(-2, GPBDecodeZigZag32(3));
     69   XCTAssertEqual((int32_t)0x3FFFFFFF, GPBDecodeZigZag32(0x7FFFFFFE));
     70   XCTAssertEqual((int32_t)0xC0000000, GPBDecodeZigZag32(0x7FFFFFFF));
     71   XCTAssertEqual((int32_t)0x7FFFFFFF, GPBDecodeZigZag32(0xFFFFFFFE));
     72   XCTAssertEqual((int32_t)0x80000000, GPBDecodeZigZag32(0xFFFFFFFF));
     73 
     74   XCTAssertEqual((int64_t)0, GPBDecodeZigZag64(0));
     75   XCTAssertEqual((int64_t)-1, GPBDecodeZigZag64(1));
     76   XCTAssertEqual((int64_t)1, GPBDecodeZigZag64(2));
     77   XCTAssertEqual((int64_t)-2, GPBDecodeZigZag64(3));
     78   XCTAssertEqual((int64_t)0x000000003FFFFFFFL,
     79                  GPBDecodeZigZag64(0x000000007FFFFFFEL));
     80   XCTAssertEqual((int64_t)0xFFFFFFFFC0000000L,
     81                  GPBDecodeZigZag64(0x000000007FFFFFFFL));
     82   XCTAssertEqual((int64_t)0x000000007FFFFFFFL,
     83                  GPBDecodeZigZag64(0x00000000FFFFFFFEL));
     84   XCTAssertEqual((int64_t)0xFFFFFFFF80000000L,
     85                  GPBDecodeZigZag64(0x00000000FFFFFFFFL));
     86   XCTAssertEqual((int64_t)0x7FFFFFFFFFFFFFFFL,
     87                  GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFEL));
     88   XCTAssertEqual((int64_t)0x8000000000000000L,
     89                  GPBDecodeZigZag64(0xFFFFFFFFFFFFFFFFL));
     90 }
     91 
     92 - (void)assertReadVarint:(NSData*)data value:(int64_t)value {
     93   {
     94     GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
     95     XCTAssertEqual((int32_t)value, [input readInt32]);
     96   }
     97   {
     98     GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
     99     XCTAssertEqual(value, [input readInt64]);
    100   }
    101 }
    102 
    103 - (void)assertReadLittleEndian32:(NSData*)data value:(int32_t)value {
    104   GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
    105   XCTAssertEqual(value, [input readSFixed32]);
    106 }
    107 
    108 - (void)assertReadLittleEndian64:(NSData*)data value:(int64_t)value {
    109   GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
    110   XCTAssertEqual(value, [input readSFixed64]);
    111 }
    112 
    113 - (void)assertReadVarintFailure:(NSData*)data {
    114   {
    115     GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
    116     XCTAssertThrows([input readInt32]);
    117   }
    118   {
    119     GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
    120     XCTAssertThrows([input readInt64]);
    121   }
    122 }
    123 
    124 - (void)testBytes {
    125   NSData* data = bytes(0xa2, 0x74);
    126   XCTAssertEqual(data.length, (NSUInteger)2);
    127   XCTAssertEqual(((uint8_t*)data.bytes)[0], (uint8_t)0xa2);
    128   XCTAssertEqual(((uint8_t*)data.bytes)[1], (uint8_t)0x74);
    129 }
    130 
    131 - (void)testReadVarint {
    132   [self assertReadVarint:bytes(0x00) value:0];
    133   [self assertReadVarint:bytes(0x01) value:1];
    134   [self assertReadVarint:bytes(0x7f) value:127];
    135   // 14882
    136   [self assertReadVarint:bytes(0xa2, 0x74) value:(0x22 << 0) | (0x74 << 7)];
    137   // 2961488830
    138   [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b)
    139                    value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) |
    140                          (0x04 << 21) | (0x0bLL << 28)];
    141 
    142   // 64-bit
    143   // 7256456126
    144   [self assertReadVarint:bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b)
    145                    value:(0x3e << 0) | (0x77 << 7) | (0x12 << 14) |
    146                          (0x04 << 21) | (0x1bLL << 28)];
    147   // 41256202580718336
    148   [self assertReadVarint:bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49)
    149                    value:(0x00 << 0) | (0x66 << 7) | (0x6b << 14) |
    150                          (0x1c << 21) | (0x43LL << 28) | (0x49LL << 35) |
    151                          (0x24LL << 42) | (0x49LL << 49)];
    152   // 11964378330978735131
    153   [self
    154       assertReadVarint:bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85,
    155                              0xa6, 0x01)
    156                  value:(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
    157                        (0x3bLL << 28) | (0x56LL << 35) | (0x00LL << 42) |
    158                        (0x05LL << 49) | (0x26LL << 56) | (0x01LL << 63)];
    159 
    160   // Failures
    161   [self assertReadVarintFailure:bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    162                                       0x80, 0x80, 0x80, 0x00)];
    163   [self assertReadVarintFailure:bytes(0x80)];
    164 }
    165 
    166 - (void)testReadLittleEndian {
    167   [self assertReadLittleEndian32:bytes(0x78, 0x56, 0x34, 0x12)
    168                            value:0x12345678];
    169   [self assertReadLittleEndian32:bytes(0xf0, 0xde, 0xbc, 0x9a)
    170                            value:0x9abcdef0];
    171 
    172   [self assertReadLittleEndian64:bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34,
    173                                        0x12)
    174                            value:0x123456789abcdef0LL];
    175   [self assertReadLittleEndian64:bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc,
    176                                        0x9a)
    177                            value:0x9abcdef012345678LL];
    178 }
    179 
    180 - (void)testReadWholeMessage {
    181   TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
    182 
    183   NSData* rawBytes = message.data;
    184   XCTAssertEqual(message.serializedSize, (size_t)rawBytes.length);
    185 
    186   TestAllTypes* message2 =
    187       [TestAllTypes parseFromData:rawBytes extensionRegistry:nil error:NULL];
    188   [self assertAllFieldsSet:message2 repeatedCount:kGPBDefaultRepeatCount];
    189 }
    190 
    191 - (void)testSkipWholeMessage {
    192   TestAllTypes* message = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
    193   NSData* rawBytes = message.data;
    194 
    195   // Create two parallel inputs.  Parse one as unknown fields while using
    196   // skipField() to skip each field on the other.  Expect the same tags.
    197   GPBCodedInputStream* input1 = [GPBCodedInputStream streamWithData:rawBytes];
    198   GPBCodedInputStream* input2 = [GPBCodedInputStream streamWithData:rawBytes];
    199   GPBUnknownFieldSet* unknownFields =
    200       [[[GPBUnknownFieldSet alloc] init] autorelease];
    201 
    202   while (YES) {
    203     int32_t tag = [input1 readTag];
    204     XCTAssertEqual(tag, [input2 readTag]);
    205     if (tag == 0) {
    206       break;
    207     }
    208     [unknownFields mergeFieldFrom:tag input:input1];
    209     [input2 skipField:tag];
    210   }
    211 }
    212 
    213 - (void)testReadHugeBlob {
    214   // Allocate and initialize a 1MB blob.
    215   NSMutableData* blob = [NSMutableData dataWithLength:1 << 20];
    216   for (NSUInteger i = 0; i < blob.length; i++) {
    217     ((uint8_t*)blob.mutableBytes)[i] = (uint8_t)i;
    218   }
    219 
    220   // Make a message containing it.
    221   TestAllTypes* message = [TestAllTypes message];
    222   [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
    223   [message setOptionalBytes:blob];
    224 
    225   // Serialize and parse it.  Make sure to parse from an InputStream, not
    226   // directly from a ByteString, so that CodedInputStream uses buffered
    227   // reading.
    228   NSData *messageData = message.data;
    229   XCTAssertNotNil(messageData);
    230   GPBCodedInputStream* stream =
    231       [GPBCodedInputStream streamWithData:messageData];
    232   TestAllTypes* message2 = [TestAllTypes parseFromCodedInputStream:stream
    233                                                  extensionRegistry:nil
    234                                                              error:NULL];
    235 
    236   XCTAssertEqualObjects(message.optionalBytes, message2.optionalBytes);
    237 
    238   // Make sure all the other fields were parsed correctly.
    239   TestAllTypes* message3 = [[message2 copy] autorelease];
    240   TestAllTypes* types = [self allSetRepeatedCount:kGPBDefaultRepeatCount];
    241   NSData* data = [types optionalBytes];
    242   [message3 setOptionalBytes:data];
    243 
    244   [self assertAllFieldsSet:message3 repeatedCount:kGPBDefaultRepeatCount];
    245 }
    246 
    247 - (void)testReadMaliciouslyLargeBlob {
    248   NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
    249   GPBCodedOutputStream* output =
    250       [GPBCodedOutputStream streamWithOutputStream:rawOutput];
    251 
    252   int32_t tag = GPBWireFormatMakeTag(1, GPBWireFormatLengthDelimited);
    253   [output writeRawVarint32:tag];
    254   [output writeRawVarint32:0x7FFFFFFF];
    255   uint8_t bytes[32] = {0};
    256   [output writeRawData:[NSData dataWithBytes:bytes length:32]];
    257   [output flush];
    258 
    259   NSData* data =
    260       [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
    261   GPBCodedInputStream* input =
    262       [GPBCodedInputStream streamWithData:[NSMutableData dataWithData:data]];
    263   XCTAssertEqual(tag, [input readTag]);
    264 
    265   XCTAssertThrows([input readBytes]);
    266 }
    267 
    268 // Verifies fix for b/10315336.
    269 // Note: Now that there isn't a custom string class under the hood, this test
    270 // isn't as critical, but it does cover bad input and if a custom class is added
    271 // again, it will help validate that class' handing of bad utf8.
    272 - (void)testReadMalformedString {
    273   NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
    274   GPBCodedOutputStream* output =
    275       [GPBCodedOutputStream streamWithOutputStream:rawOutput];
    276 
    277   int32_t tag = GPBWireFormatMakeTag(TestAllTypes_FieldNumber_DefaultString,
    278                                      GPBWireFormatLengthDelimited);
    279   [output writeRawVarint32:tag];
    280   [output writeRawVarint32:5];
    281   // Create an invalid utf-8 byte array.
    282   uint8_t bytes[] = {0xc2, 0xf2, 0x0, 0x0, 0x0};
    283   [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]];
    284   [output flush];
    285 
    286   NSData *data =
    287       [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
    288   GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
    289   NSError *error = nil;
    290   TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
    291                                                 extensionRegistry:nil
    292                                                             error:&error];
    293   XCTAssertNotNil(error);
    294   XCTAssertNil(message);
    295 }
    296 
    297 - (void)testBOMWithinStrings {
    298   // We've seen servers that end up with BOMs within strings (not always at the
    299   // start, and sometimes in multiple places), make sure they always parse
    300   // correctly. (Again, this is inpart incase a custom string class is ever
    301   // used again.)
    302   const char* strs[] = {
    303     "\xEF\xBB\xBF String with BOM",
    304     "String with \xEF\xBB\xBF in middle",
    305     "String with end bom \xEF\xBB\xBF",
    306     "\xEF\xBB\xBF\xe2\x99\xa1",  // BOM White Heart
    307     "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM",
    308   };
    309   for (size_t i = 0; i < GPBARRAYSIZE(strs); ++i) {
    310     NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
    311     GPBCodedOutputStream* output =
    312         [GPBCodedOutputStream streamWithOutputStream:rawOutput];
    313 
    314     int32_t tag = GPBWireFormatMakeTag(TestAllTypes_FieldNumber_DefaultString,
    315                                        GPBWireFormatLengthDelimited);
    316     [output writeRawVarint32:tag];
    317     size_t length = strlen(strs[i]);
    318     [output writeRawVarint32:(int32_t)length];
    319     [output writeRawData:[NSData dataWithBytes:strs[i] length:length]];
    320     [output flush];
    321 
    322     NSData* data =
    323         [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
    324     GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
    325     TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input
    326                                                   extensionRegistry:nil
    327                                                               error:NULL];
    328     XCTAssertNotNil(message, @"Loop %zd", i);
    329     // Ensure the string is there. NSString can consume the BOM in some
    330     // cases, so don't actually check the string for exact equality.
    331     XCTAssertTrue(message.defaultString.length > 0, @"Loop %zd", i);
    332   }
    333 }
    334 
    335 @end
    336