Home | History | Annotate | Download | only in protoinputstream
      1 /*
      2  * Copyright (C) 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.test.protoinputstream;
     18 
     19 import android.util.proto.ProtoInputStream;
     20 import android.util.proto.ProtoStream;
     21 import android.util.proto.WireTypeMismatchException;
     22 
     23 import com.android.test.protoinputstream.nano.Test;
     24 
     25 import com.google.protobuf.nano.MessageNano;
     26 
     27 import junit.framework.TestCase;
     28 
     29 import java.io.ByteArrayInputStream;
     30 import java.io.IOException;
     31 import java.io.InputStream;
     32 
     33 public class ProtoInputStreamFixed64Test extends TestCase {
     34 
     35     public void testRead() throws IOException {
     36         testRead(0);
     37         testRead(1);
     38         testRead(5);
     39     }
     40 
     41     private void testRead(int chunkSize) throws IOException {
     42         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
     43 
     44         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
     45         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
     46         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
     47         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
     48         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
     49         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
     50         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
     51         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
     52 
     53         final byte[] protobuf = new byte[]{
     54                 // 1 -> 0 - default value, not written
     55                 // 2 -> 1
     56                 (byte) 0x11,
     57                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     58                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     59                 // 6 -> 1
     60                 (byte) 0x41,
     61                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     62                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     63                 // 3 -> -1
     64                 (byte) 0x19,
     65                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
     66                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
     67                 // 4 -> Integer.MIN_VALUE
     68                 (byte) 0x21,
     69                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
     70                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
     71                 // 5 -> Integer.MAX_VALUE
     72                 (byte) 0x29,
     73                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
     74                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     75                 // 6 -> Long.MIN_VALUE
     76                 (byte) 0x31,
     77                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     78                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
     79                 // 7 -> Long.MAX_VALUE
     80                 (byte) 0x39,
     81                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
     82                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
     83         };
     84 
     85         InputStream stream = new ByteArrayInputStream(protobuf);
     86         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
     87         long[] results = new long[7];
     88         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
     89             switch (pi.getFieldNumber()) {
     90                 case (int) fieldId1:
     91                     fail("Should never reach this");
     92                     break;
     93                 case (int) fieldId2:
     94                     results[1] = pi.readLong(fieldId2);
     95                     break;
     96                 case (int) fieldId3:
     97                     results[2] = pi.readLong(fieldId3);
     98                     break;
     99                 case (int) fieldId4:
    100                     results[3] = pi.readLong(fieldId4);
    101                     break;
    102                 case (int) fieldId5:
    103                     results[4] = pi.readLong(fieldId5);
    104                     break;
    105                 case (int) fieldId6:
    106                     results[5] = pi.readLong(fieldId6);
    107                     break;
    108                 case (int) fieldId7:
    109                     results[6] = pi.readLong(fieldId7);
    110                     break;
    111                 case (int) fieldId8:
    112                     // Intentionally don't read the data. Parse should continue normally
    113                     break;
    114                 default:
    115                     fail("Unexpected field id " + pi.getFieldNumber());
    116             }
    117         }
    118         stream.close();
    119 
    120         assertEquals(0, results[0]);
    121         assertEquals(1, results[1]);
    122         assertEquals(-1, results[2]);
    123         assertEquals(Integer.MIN_VALUE, results[3]);
    124         assertEquals(Integer.MAX_VALUE, results[4]);
    125         assertEquals(Long.MIN_VALUE, results[5]);
    126         assertEquals(Long.MAX_VALUE, results[6]);
    127     }
    128 
    129     /**
    130      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    131      */
    132     public void testReadCompat() throws Exception {
    133         testReadCompat(0);
    134         testReadCompat(1);
    135         testReadCompat(-1);
    136         testReadCompat(Integer.MIN_VALUE);
    137         testReadCompat(Integer.MAX_VALUE);
    138         testReadCompat(Long.MIN_VALUE);
    139         testReadCompat(Long.MAX_VALUE);
    140     }
    141 
    142     /**
    143      * Implementation of testReadCompat with a given value.
    144      */
    145     private void testReadCompat(long val) throws Exception {
    146         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
    147         final long fieldId = fieldFlags | ((long) 100 & 0x0ffffffffL);
    148 
    149         final Test.All all = new Test.All();
    150         all.fixed64Field = val;
    151 
    152         final byte[] proto = MessageNano.toByteArray(all);
    153 
    154         final ProtoInputStream pi = new ProtoInputStream(proto);
    155         final Test.All readback = Test.All.parseFrom(proto);
    156 
    157         long result = 0; // start off with default value
    158         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    159             switch (pi.getFieldNumber()) {
    160                 case (int) fieldId:
    161                     result = pi.readLong(fieldId);
    162                     break;
    163                 default:
    164                     fail("Unexpected field id " + pi.getFieldNumber());
    165             }
    166         }
    167 
    168         assertEquals(readback.fixed64Field, result);
    169     }
    170 
    171     public void testRepeated() throws IOException {
    172         testRepeated(0);
    173         testRepeated(1);
    174         testRepeated(5);
    175     }
    176 
    177     private void testRepeated(int chunkSize) throws IOException {
    178         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
    179 
    180         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    181         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    182         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    183         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
    184         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
    185         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    186         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
    187         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
    188 
    189         final byte[] protobuf = new byte[]{
    190                 // 1 -> 0 - default value, written when repeated
    191                 (byte) 0x09,
    192                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    193                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    194                 // 2 -> 1
    195                 (byte) 0x11,
    196                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    197                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    198                 // 3 -> -1
    199                 (byte) 0x19,
    200                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    201                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    202                 // 4 -> Integer.MIN_VALUE
    203                 (byte) 0x21,
    204                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    205                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    206                 // 5 -> Integer.MAX_VALUE
    207                 (byte) 0x29,
    208                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    209                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    210                 // 6 -> Long.MIN_VALUE
    211                 (byte) 0x31,
    212                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    213                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    214                 // 7 -> Long.MAX_VALUE
    215                 (byte) 0x39,
    216                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    217                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    218 
    219                 // 8 -> 1
    220                 (byte) 0x41,
    221                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    222                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    223 
    224                 // 1 -> 0 - default value, written when repeated
    225                 (byte) 0x09,
    226                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    227                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    228                 // 2 -> 1
    229                 (byte) 0x11,
    230                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    231                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    232                 // 3 -> -1
    233                 (byte) 0x19,
    234                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    235                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    236                 // 4 -> Integer.MIN_VALUE
    237                 (byte) 0x21,
    238                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    239                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    240                 // 5 -> Integer.MAX_VALUE
    241                 (byte) 0x29,
    242                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    243                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    244                 // 6 -> Long.MIN_VALUE
    245                 (byte) 0x31,
    246                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    247                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    248                 // 7 -> Long.MAX_VALUE
    249                 (byte) 0x39,
    250                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    251                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    252         };
    253 
    254         InputStream stream = new ByteArrayInputStream(protobuf);
    255         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
    256         long[][] results = new long[7][2];
    257         int[] indices = new int[7];
    258         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    259 
    260             switch (pi.getFieldNumber()) {
    261                 case (int) fieldId1:
    262                     results[0][indices[0]++] = pi.readLong(fieldId1);
    263                     break;
    264                 case (int) fieldId2:
    265                     results[1][indices[1]++] = pi.readLong(fieldId2);
    266                     break;
    267                 case (int) fieldId3:
    268                     results[2][indices[2]++] = pi.readLong(fieldId3);
    269                     break;
    270                 case (int) fieldId4:
    271                     results[3][indices[3]++] = pi.readLong(fieldId4);
    272                     break;
    273                 case (int) fieldId5:
    274                     results[4][indices[4]++] = pi.readLong(fieldId5);
    275                     break;
    276                 case (int) fieldId6:
    277                     results[5][indices[5]++] = pi.readLong(fieldId6);
    278                     break;
    279                 case (int) fieldId7:
    280                     results[6][indices[6]++] = pi.readLong(fieldId7);
    281                     break;
    282                 case (int) fieldId8:
    283                     // Intentionally don't read the data. Parse should continue normally
    284                     break;
    285                 default:
    286                     fail("Unexpected field id " + pi.getFieldNumber());
    287             }
    288         }
    289         stream.close();
    290 
    291         assertEquals(0, results[0][0]);
    292         assertEquals(0, results[0][1]);
    293         assertEquals(1, results[1][0]);
    294         assertEquals(1, results[1][1]);
    295         assertEquals(-1, results[2][0]);
    296         assertEquals(-1, results[2][1]);
    297         assertEquals(Integer.MIN_VALUE, results[3][0]);
    298         assertEquals(Integer.MIN_VALUE, results[3][1]);
    299         assertEquals(Integer.MAX_VALUE, results[4][0]);
    300         assertEquals(Integer.MAX_VALUE, results[4][1]);
    301         assertEquals(Long.MIN_VALUE, results[5][0]);
    302         assertEquals(Long.MIN_VALUE, results[5][1]);
    303         assertEquals(Long.MAX_VALUE, results[6][0]);
    304         assertEquals(Long.MAX_VALUE, results[6][1]);
    305     }
    306 
    307     /**
    308      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    309      */
    310     public void testRepeatedCompat() throws Exception {
    311         testRepeatedCompat(new long[0]);
    312         testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
    313     }
    314 
    315     /**
    316      * Implementation of testRepeatedCompat with a given value.
    317      */
    318     private void testRepeatedCompat(long[] val) throws Exception {
    319         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
    320         final long fieldId = fieldFlags | ((long) 101 & 0x0ffffffffL);
    321 
    322         final Test.All all = new Test.All();
    323         all.fixed64FieldRepeated = val;
    324 
    325         final byte[] proto = MessageNano.toByteArray(all);
    326 
    327         final ProtoInputStream pi = new ProtoInputStream(proto);
    328         final Test.All readback = Test.All.parseFrom(proto);
    329 
    330         long[] result = new long[val.length];
    331         int index = 0;
    332         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    333             switch (pi.getFieldNumber()) {
    334                 case (int) fieldId:
    335                     result[index++] = pi.readLong(fieldId);
    336                     break;
    337                 default:
    338                     fail("Unexpected field id " + pi.getFieldNumber());
    339             }
    340         }
    341 
    342         assertEquals(readback.fixed64FieldRepeated.length, result.length);
    343         for (int i = 0; i < result.length; i++) {
    344             assertEquals(readback.fixed64FieldRepeated[i], result[i]);
    345         }
    346     }
    347 
    348     public void testPacked() throws IOException {
    349         testPacked(0);
    350         testPacked(1);
    351         testPacked(5);
    352     }
    353 
    354     private void testPacked(int chunkSize) throws IOException {
    355         final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FIXED64;
    356 
    357         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    358         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    359         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    360         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
    361         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
    362         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    363         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
    364         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
    365 
    366         final byte[] protobuf = new byte[]{
    367                 // 1 -> 0 - default value, written when repeated
    368                 (byte) 0x0a,
    369                 (byte) 0x10,
    370                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    371                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    372                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    373                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    374                 // 2 -> 1
    375                 (byte) 0x12,
    376                 (byte) 0x10,
    377                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    378                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    379                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    380                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    381                 // 8 -> 1
    382                 (byte) 0x42,
    383                 (byte) 0x10,
    384                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    385                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    386                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    387                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    388                 // 3 -> -1
    389                 (byte) 0x1a,
    390                 (byte) 0x10,
    391                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    392                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    393                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    394                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    395                 // 4 -> Integer.MIN_VALUE
    396                 (byte) 0x22,
    397                 (byte) 0x10,
    398                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    399                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    400                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    401                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    402                 // 5 -> Integer.MAX_VALUE
    403                 (byte) 0x2a,
    404                 (byte) 0x10,
    405                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    406                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    407                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    408                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    409                 // 6 -> Long.MIN_VALUE
    410                 (byte) 0x32,
    411                 (byte) 0x10,
    412                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    413                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    414                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    415                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
    416                 // 7 -> Long.MAX_VALUE
    417                 (byte) 0x3a,
    418                 (byte) 0x10,
    419                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    420                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    421                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    422                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
    423         };
    424 
    425         InputStream stream = new ByteArrayInputStream(protobuf);
    426         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
    427         long[][] results = new long[7][2];
    428         int[] indices = new int[7];
    429         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    430 
    431             switch (pi.getFieldNumber()) {
    432                 case (int) fieldId1:
    433                     results[0][indices[0]++] = pi.readLong(fieldId1);
    434                     break;
    435                 case (int) fieldId2:
    436                     results[1][indices[1]++] = pi.readLong(fieldId2);
    437                     break;
    438                 case (int) fieldId3:
    439                     results[2][indices[2]++] = pi.readLong(fieldId3);
    440                     break;
    441                 case (int) fieldId4:
    442                     results[3][indices[3]++] = pi.readLong(fieldId4);
    443                     break;
    444                 case (int) fieldId5:
    445                     results[4][indices[4]++] = pi.readLong(fieldId5);
    446                     break;
    447                 case (int) fieldId6:
    448                     results[5][indices[5]++] = pi.readLong(fieldId6);
    449                     break;
    450                 case (int) fieldId7:
    451                     results[6][indices[6]++] = pi.readLong(fieldId7);
    452                     break;
    453                 case (int) fieldId8:
    454                     // Intentionally don't read the data. Parse should continue normally
    455                     break;
    456                 default:
    457                     fail("Unexpected field id " + pi.getFieldNumber());
    458             }
    459         }
    460         stream.close();
    461 
    462         assertEquals(0, results[0][0]);
    463         assertEquals(0, results[0][1]);
    464         assertEquals(1, results[1][0]);
    465         assertEquals(1, results[1][1]);
    466         assertEquals(-1, results[2][0]);
    467         assertEquals(-1, results[2][1]);
    468         assertEquals(Integer.MIN_VALUE, results[3][0]);
    469         assertEquals(Integer.MIN_VALUE, results[3][1]);
    470         assertEquals(Integer.MAX_VALUE, results[4][0]);
    471         assertEquals(Integer.MAX_VALUE, results[4][1]);
    472         assertEquals(Long.MIN_VALUE, results[5][0]);
    473         assertEquals(Long.MIN_VALUE, results[5][1]);
    474         assertEquals(Long.MAX_VALUE, results[6][0]);
    475         assertEquals(Long.MAX_VALUE, results[6][1]);
    476     }
    477 
    478     /**
    479      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    480      */
    481     public void testPackedCompat() throws Exception {
    482         testPackedCompat(new long[0]);
    483         testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
    484     }
    485 
    486     /**
    487      * Implementation of testRepeatedCompat with a given value.
    488      */
    489     private void testPackedCompat(long[] val) throws Exception {
    490         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
    491         final long fieldId = fieldFlags | ((long) 102 & 0x0ffffffffL);
    492 
    493         final Test.All all = new Test.All();
    494         all.fixed64FieldPacked = val;
    495 
    496         final byte[] proto = MessageNano.toByteArray(all);
    497 
    498         final ProtoInputStream pi = new ProtoInputStream(proto);
    499         final Test.All readback = Test.All.parseFrom(proto);
    500 
    501         long[] result = new long[val.length];
    502         int index = 0;
    503         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    504             switch (pi.getFieldNumber()) {
    505                 case (int) fieldId:
    506                     result[index++] = pi.readLong(fieldId);
    507                     break;
    508                 default:
    509                     fail("Unexpected field id " + pi.getFieldNumber());
    510             }
    511         }
    512 
    513         assertEquals(readback.fixed64FieldPacked.length, result.length);
    514         for (int i = 0; i < result.length; i++) {
    515             assertEquals(readback.fixed64FieldPacked[i], result[i]);
    516         }
    517     }
    518 
    519     /**
    520      * Test that using the wrong read method throws an exception
    521      */
    522     public void testBadReadType() throws IOException {
    523         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
    524 
    525         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    526 
    527         final byte[] protobuf = new byte[]{
    528                 // 1 -> 1
    529                 (byte) 0x09,
    530                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    531                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    532         };
    533 
    534         ProtoInputStream pi = new ProtoInputStream(protobuf);
    535         pi.isNextField(fieldId1);
    536         try {
    537             pi.readFloat(fieldId1);
    538             fail("Should have throw IllegalArgumentException");
    539         } catch (IllegalArgumentException iae) {
    540             // good
    541         }
    542 
    543         pi = new ProtoInputStream(protobuf);
    544         pi.isNextField(fieldId1);
    545         try {
    546             pi.readDouble(fieldId1);
    547             fail("Should have throw IllegalArgumentException");
    548         } catch (IllegalArgumentException iae) {
    549             // good
    550         }
    551 
    552         pi = new ProtoInputStream(protobuf);
    553         pi.isNextField(fieldId1);
    554         try {
    555             pi.readInt(fieldId1);
    556             fail("Should have throw IllegalArgumentException");
    557         } catch (IllegalArgumentException iae) {
    558             // good
    559         }
    560 
    561         pi = new ProtoInputStream(protobuf);
    562         pi.isNextField(fieldId1);
    563         try {
    564             pi.readBoolean(fieldId1);
    565             fail("Should have throw IllegalArgumentException");
    566         } catch (IllegalArgumentException iae) {
    567             // good
    568         }
    569 
    570         pi = new ProtoInputStream(protobuf);
    571         pi.isNextField(fieldId1);
    572         try {
    573             pi.readBytes(fieldId1);
    574             fail("Should have throw IllegalArgumentException");
    575         } catch (IllegalArgumentException iae) {
    576             // good
    577         }
    578 
    579         pi = new ProtoInputStream(protobuf);
    580         pi.isNextField(fieldId1);
    581         try {
    582             pi.readString(fieldId1);
    583             fail("Should have throw IllegalArgumentException");
    584         } catch (IllegalArgumentException iae) {
    585             // good
    586         }
    587     }
    588 
    589     /**
    590      * Test that unexpected wrong wire types will throw an exception
    591      */
    592     public void testBadWireType() throws IOException {
    593         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
    594 
    595         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    596         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    597         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    598         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    599 
    600         final byte[] protobuf = new byte[]{
    601                 // 1 : varint -> 1
    602                 (byte) 0x08,
    603                 (byte) 0x01,
    604                 // 2 : fixed64 -> 0x1
    605                 (byte) 0x11,
    606                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    607                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    608                 // 3 : length delimited -> { 1 }
    609                 (byte) 0x1a,
    610                 (byte) 0x08,
    611                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    612                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    613                 // 6 : fixed32
    614                 (byte) 0x35,
    615                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    616         };
    617 
    618         InputStream stream = new ByteArrayInputStream(protobuf);
    619         final ProtoInputStream pi = new ProtoInputStream(stream);
    620 
    621         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    622             try {
    623                 switch (pi.getFieldNumber()) {
    624                     case (int) fieldId1:
    625                         pi.readLong(fieldId1);
    626                         fail("Should have thrown a WireTypeMismatchException");
    627                         break;
    628                     case (int) fieldId2:
    629                         pi.readLong(fieldId2);
    630                         // don't fail, fixed64 is ok
    631                         break;
    632                     case (int) fieldId3:
    633                         pi.readLong(fieldId3);
    634                         // don't fail, length delimited is ok (represents packed fixed64)
    635                         break;
    636                     case (int) fieldId6:
    637                         pi.readLong(fieldId6);
    638                         fail("Should have thrown a WireTypeMismatchException");
    639                         break;
    640                     default:
    641                         fail("Unexpected field id " + pi.getFieldNumber());
    642                 }
    643             } catch (WireTypeMismatchException wtme) {
    644                 // good
    645             }
    646         }
    647         stream.close();
    648     }
    649 }
    650