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 ProtoInputStreamSInt64Test 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_SINT64;
     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) 0x10,
     57                 (byte) 0x02,
     58                 // 8 -> Integer.MAX_VALUE
     59                 (byte) 0x40,
     60                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
     61                 // 3 -> -1
     62                 (byte) 0x18,
     63                 (byte) 0x01,
     64                 // 4 -> Integer.MIN_VALUE
     65                 (byte) 0x20,
     66                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
     67                 // 5 -> Integer.MAX_VALUE
     68                 (byte) 0x28,
     69                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
     70                 // 6 -> Long.MIN_VALUE
     71                 (byte) 0x30,
     72                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
     73                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
     74                 // 7 -> Long.MAX_VALUE
     75                 (byte) 0x38,
     76                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
     77                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
     78         };
     79 
     80         InputStream stream = new ByteArrayInputStream(protobuf);
     81         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
     82         long[] results = new long[7];
     83         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
     84             switch (pi.getFieldNumber()) {
     85                 case (int) fieldId1:
     86                     fail("Should never reach this");
     87                     break;
     88                 case (int) fieldId2:
     89                     results[1] = pi.readLong(fieldId2);
     90                     break;
     91                 case (int) fieldId3:
     92                     results[2] = pi.readLong(fieldId3);
     93                     break;
     94                 case (int) fieldId4:
     95                     results[3] = pi.readLong(fieldId4);
     96                     break;
     97                 case (int) fieldId5:
     98                     results[4] = pi.readLong(fieldId5);
     99                     break;
    100                 case (int) fieldId6:
    101                     results[5] = pi.readLong(fieldId6);
    102                     break;
    103                 case (int) fieldId7:
    104                     results[6] = pi.readLong(fieldId7);
    105                     break;
    106                 case (int) fieldId8:
    107                     // Intentionally don't read the data. Parse should continue normally
    108                     break;
    109                 default:
    110                     fail("Unexpected field id " + pi.getFieldNumber());
    111             }
    112         }
    113         stream.close();
    114 
    115         assertEquals(0, results[0]);
    116         assertEquals(1, results[1]);
    117         assertEquals(-1, results[2]);
    118         assertEquals(Integer.MIN_VALUE, results[3]);
    119         assertEquals(Integer.MAX_VALUE, results[4]);
    120         assertEquals(Long.MIN_VALUE, results[5]);
    121         assertEquals(Long.MAX_VALUE, results[6]);
    122     }
    123 
    124     /**
    125      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    126      */
    127     public void testReadCompat() throws Exception {
    128         testReadCompat(0);
    129         testReadCompat(1);
    130         testReadCompat(-1);
    131         testReadCompat(Integer.MIN_VALUE);
    132         testReadCompat(Integer.MAX_VALUE);
    133         testReadCompat(Long.MIN_VALUE);
    134         testReadCompat(Long.MAX_VALUE);
    135     }
    136 
    137     /**
    138      * Implementation of testReadCompat with a given value.
    139      */
    140     private void testReadCompat(long val) throws Exception {
    141         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
    142         final long fieldId = fieldFlags | ((long) 80 & 0x0ffffffffL);
    143 
    144         final Test.All all = new Test.All();
    145         all.sint64Field = val;
    146 
    147         final byte[] proto = MessageNano.toByteArray(all);
    148 
    149         final ProtoInputStream pi = new ProtoInputStream(proto);
    150         final Test.All readback = Test.All.parseFrom(proto);
    151 
    152         long result = 0; // start off with default value
    153         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    154             switch (pi.getFieldNumber()) {
    155                 case (int) fieldId:
    156                     result = pi.readLong(fieldId);
    157                     break;
    158                 default:
    159                     fail("Unexpected field id " + pi.getFieldNumber());
    160             }
    161         }
    162 
    163         assertEquals(readback.sint64Field, result);
    164     }
    165 
    166     public void testRepeated() throws IOException {
    167         testRepeated(0);
    168         testRepeated(1);
    169         testRepeated(5);
    170     }
    171 
    172     private void testRepeated(int chunkSize) throws IOException {
    173         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
    174 
    175         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    176         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    177         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    178         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
    179         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
    180         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    181         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
    182         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
    183 
    184         final byte[] protobuf = new byte[]{
    185                 // 1 -> 0 - default value, written when repeated
    186                 (byte) 0x08,
    187                 (byte) 0x00,
    188                 // 2 -> 1
    189                 (byte) 0x10,
    190                 (byte) 0x02,
    191                 // 3 -> -1
    192                 (byte) 0x18,
    193                 (byte) 0x01,
    194                 // 4 -> Integer.MIN_VALUE
    195                 (byte) 0x20,
    196                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    197                 // 5 -> Integer.MAX_VALUE
    198                 (byte) 0x28,
    199                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    200                 // 6 -> Long.MIN_VALUE
    201                 (byte) 0x30,
    202                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    203                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
    204                 // 7 -> Long.MAX_VALUE
    205                 (byte) 0x38,
    206                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    207                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
    208 
    209                 // 8 -> Integer.MAX_VALUE
    210                 (byte) 0x40,
    211                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    212 
    213 
    214                 // 1 -> 0 - default value, written when repeated
    215                 (byte) 0x08,
    216                 (byte) 0x00,
    217                 // 2 -> 1
    218                 (byte) 0x10,
    219                 (byte) 0x02,
    220                 // 3 -> -1
    221                 (byte) 0x18,
    222                 (byte) 0x01,
    223                 // 4 -> Integer.MIN_VALUE
    224                 (byte) 0x20,
    225                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    226                 // 5 -> Integer.MAX_VALUE
    227                 (byte) 0x28,
    228                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    229                 // 6 -> Long.MIN_VALUE
    230                 (byte) 0x30,
    231                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    232                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
    233                 // 7 -> Long.MAX_VALUE
    234                 (byte) 0x38,
    235                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    236                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
    237         };
    238 
    239         InputStream stream = new ByteArrayInputStream(protobuf);
    240         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
    241         long[][] results = new long[7][2];
    242         int[] indices = new int[7];
    243         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    244 
    245             switch (pi.getFieldNumber()) {
    246                 case (int) fieldId1:
    247                     results[0][indices[0]++] = pi.readLong(fieldId1);
    248                     break;
    249                 case (int) fieldId2:
    250                     results[1][indices[1]++] = pi.readLong(fieldId2);
    251                     break;
    252                 case (int) fieldId3:
    253                     results[2][indices[2]++] = pi.readLong(fieldId3);
    254                     break;
    255                 case (int) fieldId4:
    256                     results[3][indices[3]++] = pi.readLong(fieldId4);
    257                     break;
    258                 case (int) fieldId5:
    259                     results[4][indices[4]++] = pi.readLong(fieldId5);
    260                     break;
    261                 case (int) fieldId6:
    262                     results[5][indices[5]++] = pi.readLong(fieldId6);
    263                     break;
    264                 case (int) fieldId7:
    265                     results[6][indices[6]++] = pi.readLong(fieldId7);
    266                     break;
    267                 case (int) fieldId8:
    268                     // Intentionally don't read the data. Parse should continue normally
    269                     break;
    270                 default:
    271                     fail("Unexpected field id " + pi.getFieldNumber());
    272             }
    273         }
    274         stream.close();
    275 
    276         assertEquals(0, results[0][0]);
    277         assertEquals(0, results[0][1]);
    278         assertEquals(1, results[1][0]);
    279         assertEquals(1, results[1][1]);
    280         assertEquals(-1, results[2][0]);
    281         assertEquals(-1, results[2][1]);
    282         assertEquals(Integer.MIN_VALUE, results[3][0]);
    283         assertEquals(Integer.MIN_VALUE, results[3][1]);
    284         assertEquals(Integer.MAX_VALUE, results[4][0]);
    285         assertEquals(Integer.MAX_VALUE, results[4][1]);
    286         assertEquals(Long.MIN_VALUE, results[5][0]);
    287         assertEquals(Long.MIN_VALUE, results[5][1]);
    288         assertEquals(Long.MAX_VALUE, results[6][0]);
    289         assertEquals(Long.MAX_VALUE, results[6][1]);
    290     }
    291 
    292     /**
    293      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    294      */
    295     public void testRepeatedCompat() throws Exception {
    296         testRepeatedCompat(new long[0]);
    297         testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
    298     }
    299 
    300     /**
    301      * Implementation of testRepeatedCompat with a given value.
    302      */
    303     private void testRepeatedCompat(long[] val) throws Exception {
    304         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
    305         final long fieldId = fieldFlags | ((long) 81 & 0x0ffffffffL);
    306 
    307         final Test.All all = new Test.All();
    308         all.sint64FieldRepeated = val;
    309 
    310         final byte[] proto = MessageNano.toByteArray(all);
    311 
    312         final ProtoInputStream pi = new ProtoInputStream(proto);
    313         final Test.All readback = Test.All.parseFrom(proto);
    314 
    315         long[] result = new long[val.length];
    316         int index = 0;
    317         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    318             switch (pi.getFieldNumber()) {
    319                 case (int) fieldId:
    320                     result[index++] = pi.readLong(fieldId);
    321                     break;
    322                 default:
    323                     fail("Unexpected field id " + pi.getFieldNumber());
    324             }
    325         }
    326 
    327         assertEquals(readback.sint64FieldRepeated.length, result.length);
    328         for (int i = 0; i < result.length; i++) {
    329             assertEquals(readback.sint64FieldRepeated[i], result[i]);
    330         }
    331     }
    332 
    333     public void testPacked() throws IOException {
    334         testPacked(0);
    335         testPacked(1);
    336         testPacked(5);
    337     }
    338 
    339     private void testPacked(int chunkSize) throws IOException {
    340         final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SINT64;
    341 
    342         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    343         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    344         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    345         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
    346         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
    347         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    348         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
    349         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
    350 
    351         final byte[] protobuf = new byte[]{
    352                 // 1 -> 0 - default value, written when repeated
    353                 (byte) 0x0a,
    354                 (byte) 0x02,
    355                 (byte) 0x00,
    356                 (byte) 0x00,
    357                 // 2 -> 1
    358                 (byte) 0x12,
    359                 (byte) 0x02,
    360                 (byte) 0x02,
    361                 (byte) 0x02,
    362                 // 8 -> Integer.MAX_VALUE
    363                 (byte) 0x42,
    364                 (byte) 0x0a,
    365                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    366                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    367                 // 3 -> -1
    368                 (byte) 0x1a,
    369                 (byte) 0x02,
    370                 (byte) 0x01,
    371                 (byte) 0x01,
    372                 // 4 -> Integer.MIN_VALUE
    373                 (byte) 0x22,
    374                 (byte) 0x0a,
    375                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    376                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    377                 // 5 -> Integer.MAX_VALUE
    378                 (byte) 0x2a,
    379                 (byte) 0x0a,
    380                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    381                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
    382                 // 6 -> Long.MIN_VALUE
    383                 (byte) 0x32,
    384                 (byte) 0x14,
    385                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    386                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
    387 
    388                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    389                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
    390                 // 7 -> Long.MAX_VALUE
    391                 (byte) 0x3a,
    392                 (byte) 0x14,
    393                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    394                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
    395 
    396                 (byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
    397                 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01
    398         };
    399 
    400         InputStream stream = new ByteArrayInputStream(protobuf);
    401         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
    402         long[][] results = new long[7][2];
    403         int[] indices = new int[7];
    404         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    405 
    406             switch (pi.getFieldNumber()) {
    407                 case (int) fieldId1:
    408                     results[0][indices[0]++] = pi.readLong(fieldId1);
    409                     break;
    410                 case (int) fieldId2:
    411                     results[1][indices[1]++] = pi.readLong(fieldId2);
    412                     break;
    413                 case (int) fieldId3:
    414                     results[2][indices[2]++] = pi.readLong(fieldId3);
    415                     break;
    416                 case (int) fieldId4:
    417                     results[3][indices[3]++] = pi.readLong(fieldId4);
    418                     break;
    419                 case (int) fieldId5:
    420                     results[4][indices[4]++] = pi.readLong(fieldId5);
    421                     break;
    422                 case (int) fieldId6:
    423                     results[5][indices[5]++] = pi.readLong(fieldId6);
    424                     break;
    425                 case (int) fieldId7:
    426                     results[6][indices[6]++] = pi.readLong(fieldId7);
    427                     break;
    428                 case (int) fieldId8:
    429                     // Intentionally don't read the data. Parse should continue normally
    430                     break;
    431                 default:
    432                     fail("Unexpected field id " + pi.getFieldNumber());
    433             }
    434         }
    435         stream.close();
    436 
    437         assertEquals(0, results[0][0]);
    438         assertEquals(0, results[0][1]);
    439         assertEquals(1, results[1][0]);
    440         assertEquals(1, results[1][1]);
    441         assertEquals(-1, results[2][0]);
    442         assertEquals(-1, results[2][1]);
    443         assertEquals(Integer.MIN_VALUE, results[3][0]);
    444         assertEquals(Integer.MIN_VALUE, results[3][1]);
    445         assertEquals(Integer.MAX_VALUE, results[4][0]);
    446         assertEquals(Integer.MAX_VALUE, results[4][1]);
    447         assertEquals(Long.MIN_VALUE, results[5][0]);
    448         assertEquals(Long.MIN_VALUE, results[5][1]);
    449         assertEquals(Long.MAX_VALUE, results[6][0]);
    450         assertEquals(Long.MAX_VALUE, results[6][1]);
    451     }
    452 
    453     /**
    454      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    455      */
    456     public void testPackedCompat() throws Exception {
    457         testPackedCompat(new long[0]);
    458         testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
    459     }
    460 
    461     /**
    462      * Implementation of testRepeatedCompat with a given value.
    463      */
    464     private void testPackedCompat(long[] val) throws Exception {
    465         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
    466         final long fieldId = fieldFlags | ((long) 82 & 0x0ffffffffL);
    467 
    468         final Test.All all = new Test.All();
    469         all.sint64FieldPacked = val;
    470 
    471         final byte[] proto = MessageNano.toByteArray(all);
    472 
    473         final ProtoInputStream pi = new ProtoInputStream(proto);
    474         final Test.All readback = Test.All.parseFrom(proto);
    475 
    476         long[] result = new long[val.length];
    477         int index = 0;
    478         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    479             switch (pi.getFieldNumber()) {
    480                 case (int) fieldId:
    481                     result[index++] = pi.readLong(fieldId);
    482                     break;
    483                 default:
    484                     fail("Unexpected field id " + pi.getFieldNumber());
    485             }
    486         }
    487 
    488         assertEquals(readback.sint64FieldPacked.length, result.length);
    489         for (int i = 0; i < result.length; i++) {
    490             assertEquals(readback.sint64FieldPacked[i], result[i]);
    491         }
    492     }
    493 
    494     /**
    495      * Test that using the wrong read method throws an exception
    496      */
    497     public void testBadReadType() throws IOException {
    498         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
    499 
    500         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    501 
    502         final byte[] protobuf = new byte[]{
    503                 // 1 -> 1
    504                 (byte) 0x08,
    505                 (byte) 0x01,
    506         };
    507 
    508         ProtoInputStream pi = new ProtoInputStream(protobuf);
    509         pi.isNextField(fieldId1);
    510         try {
    511             pi.readFloat(fieldId1);
    512             fail("Should have throw IllegalArgumentException");
    513         } catch (IllegalArgumentException iae) {
    514             // good
    515         }
    516 
    517         pi = new ProtoInputStream(protobuf);
    518         pi.isNextField(fieldId1);
    519         try {
    520             pi.readDouble(fieldId1);
    521             fail("Should have throw IllegalArgumentException");
    522         } catch (IllegalArgumentException iae) {
    523             // good
    524         }
    525 
    526         pi = new ProtoInputStream(protobuf);
    527         pi.isNextField(fieldId1);
    528         try {
    529             pi.readInt(fieldId1);
    530             fail("Should have throw IllegalArgumentException");
    531         } catch (IllegalArgumentException iae) {
    532             // good
    533         }
    534 
    535         pi = new ProtoInputStream(protobuf);
    536         pi.isNextField(fieldId1);
    537         try {
    538             pi.readBoolean(fieldId1);
    539             fail("Should have throw IllegalArgumentException");
    540         } catch (IllegalArgumentException iae) {
    541             // good
    542         }
    543 
    544         pi = new ProtoInputStream(protobuf);
    545         pi.isNextField(fieldId1);
    546         try {
    547             pi.readBytes(fieldId1);
    548             fail("Should have throw IllegalArgumentException");
    549         } catch (IllegalArgumentException iae) {
    550             // good
    551         }
    552 
    553         pi = new ProtoInputStream(protobuf);
    554         pi.isNextField(fieldId1);
    555         try {
    556             pi.readString(fieldId1);
    557             fail("Should have throw IllegalArgumentException");
    558         } catch (IllegalArgumentException iae) {
    559             // good
    560         }
    561     }
    562 
    563     /**
    564      * Test that unexpected wrong wire types will throw an exception
    565      */
    566     public void testBadWireType() throws IOException {
    567         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
    568 
    569         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    570         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    571         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    572         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    573 
    574         final byte[] protobuf = new byte[]{
    575                 // 1 : varint -> 1
    576                 (byte) 0x08,
    577                 (byte) 0x01,
    578                 // 2 : fixed64 -> 0x1
    579                 (byte) 0x11,
    580                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    581                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    582                 // 3 : length delimited -> { 1 }
    583                 (byte) 0x1a,
    584                 (byte) 0x01,
    585                 (byte) 0x01,
    586                 // 6 : fixed32
    587                 (byte) 0x35,
    588                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    589         };
    590 
    591         InputStream stream = new ByteArrayInputStream(protobuf);
    592         final ProtoInputStream pi = new ProtoInputStream(stream);
    593 
    594         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    595             try {
    596                 switch (pi.getFieldNumber()) {
    597                     case (int) fieldId1:
    598                         pi.readLong(fieldId1);
    599                         // don't fail, varint is ok
    600                         break;
    601                     case (int) fieldId2:
    602                         pi.readLong(fieldId2);
    603                         fail("Should have thrown a WireTypeMismatchException");
    604                         break;
    605                     case (int) fieldId3:
    606                         pi.readLong(fieldId3);
    607                         // don't fail, length delimited is ok (represents packed sint64)
    608                         break;
    609                     case (int) fieldId6:
    610                         pi.readLong(fieldId6);
    611                         fail("Should have thrown a WireTypeMismatchException");
    612                         break;
    613                     default:
    614                         fail("Unexpected field id " + pi.getFieldNumber());
    615                 }
    616             } catch (WireTypeMismatchException wtme) {
    617                 // good
    618             }
    619         }
    620         stream.close();
    621     }
    622 }
    623