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 ProtoInputStreamDoubleTest extends TestCase {
     34 
     35 
     36     public void testRead() throws IOException {
     37         testRead(0);
     38         testRead(1);
     39         testRead(5);
     40     }
     41 
     42     private void testRead(int chunkSize) throws IOException {
     43         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
     44 
     45         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
     46         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
     47         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
     48         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
     49         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
     50         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
     51         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
     52         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
     53         final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
     54         final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
     55 
     56         final byte[] protobuf = new byte[]{
     57                 // 1 -> 0 - default value, not written
     58                 // 2 -> 1
     59                 (byte) 0x11,
     60                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     61                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
     62                 // 10 -> 1
     63                 (byte) 0x51,
     64                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     65                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
     66                 // 3 -> -1234.432
     67                 (byte) 0x19,
     68                 (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
     69                 (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
     70                 // 4 -> 42.42
     71                 (byte) 0x21,
     72                 (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
     73                 (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
     74                 // 5 -> Double.MIN_NORMAL
     75                 (byte) 0x29,
     76                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     77                 (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
     78                 // 6 -> DOUBLE.MIN_VALUE
     79                 (byte) 0x31,
     80                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     81                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     82                 // 7 -> Double.NEGATIVE_INFINITY
     83                 (byte) 0x39,
     84                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     85                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
     86                 // 8 -> Double.NaN
     87                 (byte) 0x41,
     88                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     89                 (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
     90                 // 9 -> Double.POSITIVE_INFINITY
     91                 (byte) 0x49,
     92                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
     93                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
     94         };
     95 
     96         InputStream stream = new ByteArrayInputStream(protobuf);
     97         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
     98         double[] results = new double[9];
     99         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    100             switch (pi.getFieldNumber()) {
    101                 case (int) fieldId1:
    102                     fail("Should never reach this");
    103                     break;
    104                 case (int) fieldId2:
    105                     results[1] = pi.readDouble(fieldId2);
    106                     break;
    107                 case (int) fieldId3:
    108                     results[2] = pi.readDouble(fieldId3);
    109                     break;
    110                 case (int) fieldId4:
    111                     results[3] = pi.readDouble(fieldId4);
    112                     break;
    113                 case (int) fieldId5:
    114                     results[4] = pi.readDouble(fieldId5);
    115                     break;
    116                 case (int) fieldId6:
    117                     results[5] = pi.readDouble(fieldId6);
    118                     break;
    119                 case (int) fieldId7:
    120                     results[6] = pi.readDouble(fieldId7);
    121                     break;
    122                 case (int) fieldId8:
    123                     results[7] = pi.readDouble(fieldId8);
    124                     break;
    125                 case (int) fieldId9:
    126                     results[8] = pi.readDouble(fieldId9);
    127                     break;
    128                 case (int) fieldId10:
    129                     // Intentionally don't read the data. Parse should continue normally
    130                     break;
    131                 default:
    132                     fail("Unexpected field id " + pi.getFieldNumber());
    133             }
    134         }
    135         stream.close();
    136         assertEquals(0.0, results[0]);
    137         assertEquals(1.0, results[1]);
    138         assertEquals(-1234.432, results[2]);
    139         assertEquals(42.42, results[3]);
    140         assertEquals(Double.MIN_NORMAL, results[4]);
    141         assertEquals(Double.MIN_VALUE, results[5]);
    142         assertEquals(Double.NEGATIVE_INFINITY, results[6]);
    143         assertEquals(Double.NaN, results[7]);
    144         assertEquals(Double.POSITIVE_INFINITY, results[8]);
    145     }
    146 
    147     /**
    148      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    149      */
    150     public void testReadCompat() throws Exception {
    151         testReadCompat(0);
    152         testReadCompat(1);
    153         testReadCompat(-1234.432);
    154         testReadCompat(42.42);
    155         testReadCompat(Double.MIN_NORMAL);
    156         testReadCompat(Double.MIN_VALUE);
    157         testReadCompat(Double.NEGATIVE_INFINITY);
    158         testReadCompat(Double.NaN);
    159         testReadCompat(Double.POSITIVE_INFINITY);
    160     }
    161 
    162     /**
    163      * Implementation of testReadCompat with a given value.
    164      */
    165     private void testReadCompat(double val) throws Exception {
    166         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
    167         final long fieldId = fieldFlags | ((long) 10 & 0x0ffffffffL);
    168 
    169         final Test.All all = new Test.All();
    170         all.doubleField = val;
    171 
    172         final byte[] proto = MessageNano.toByteArray(all);
    173 
    174         final ProtoInputStream pi = new ProtoInputStream(proto);
    175         final Test.All readback = Test.All.parseFrom(proto);
    176 
    177         double result = 0.0; // start off with default value
    178         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    179             switch (pi.getFieldNumber()) {
    180                 case (int) fieldId:
    181                     result = pi.readDouble(fieldId);
    182                     break;
    183                 default:
    184                     fail("Unexpected field id " + pi.getFieldNumber());
    185             }
    186         }
    187 
    188         assertEquals(readback.doubleField, result);
    189     }
    190 
    191 
    192     public void testRepeated() throws IOException {
    193         testRepeated(0);
    194         testRepeated(1);
    195         testRepeated(5);
    196     }
    197 
    198     private void testRepeated(int chunkSize) throws IOException {
    199         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
    200 
    201         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    202         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    203         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    204         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
    205         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
    206         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    207         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
    208         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
    209         final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
    210         final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
    211 
    212         final byte[] protobuf = new byte[]{
    213                 // 1 -> 0 - default value, written when repeated
    214                 (byte) 0x09,
    215                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    216                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    217                 // 2 -> 1
    218                 (byte) 0x11,
    219                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    220                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
    221                 // 3 -> -1234.432
    222                 (byte) 0x19,
    223                 (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
    224                 (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
    225                 // 4 -> 42.42
    226                 (byte) 0x21,
    227                 (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
    228                 (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
    229                 // 5 -> Double.MIN_NORMAL
    230                 (byte) 0x29,
    231                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    232                 (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
    233                 // 6 -> DOUBLE.MIN_VALUE
    234                 (byte) 0x31,
    235                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    236                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    237                 // 7 -> Double.NEGATIVE_INFINITY
    238                 (byte) 0x39,
    239                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    240                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
    241                 // 8 -> Double.NaN
    242                 (byte) 0x41,
    243                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    244                 (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
    245                 // 9 -> Double.POSITIVE_INFINITY
    246                 (byte) 0x49,
    247                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    248                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
    249                 // 10 -> 1
    250                 (byte) 0x51,
    251                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    252                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
    253 
    254                 // 1 -> 0 - default value, written when repeated
    255                 (byte) 0x09,
    256                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    257                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    258                 // 2 -> 1
    259                 (byte) 0x11,
    260                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    261                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
    262                 // 3 -> -1234.432
    263                 (byte) 0x19,
    264                 (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
    265                 (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
    266                 // 4 -> 42.42
    267                 (byte) 0x21,
    268                 (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
    269                 (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
    270                 // 5 -> Double.MIN_NORMAL
    271                 (byte) 0x29,
    272                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    273                 (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
    274                 // 6 -> DOUBLE.MIN_VALUE
    275                 (byte) 0x31,
    276                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    277                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    278                 // 7 -> Double.NEGATIVE_INFINITY
    279                 (byte) 0x39,
    280                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    281                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
    282                 // 8 -> Double.NaN
    283                 (byte) 0x41,
    284                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    285                 (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
    286                 // 9 -> Double.POSITIVE_INFINITY
    287                 (byte) 0x49,
    288                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    289                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
    290         };
    291 
    292         InputStream stream = new ByteArrayInputStream(protobuf);
    293         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
    294         double[][] results = new double[9][2];
    295         int[] indices = new int[9];
    296         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    297 
    298             switch (pi.getFieldNumber()) {
    299                 case (int) fieldId1:
    300                     results[0][indices[0]++] = pi.readDouble(fieldId1);
    301                     break;
    302                 case (int) fieldId2:
    303                     results[1][indices[1]++] = pi.readDouble(fieldId2);
    304                     break;
    305                 case (int) fieldId3:
    306                     results[2][indices[2]++] = pi.readDouble(fieldId3);
    307                     break;
    308                 case (int) fieldId4:
    309                     results[3][indices[3]++] = pi.readDouble(fieldId4);
    310                     break;
    311                 case (int) fieldId5:
    312                     results[4][indices[4]++] = pi.readDouble(fieldId5);
    313                     break;
    314                 case (int) fieldId6:
    315                     results[5][indices[5]++] = pi.readDouble(fieldId6);
    316                     break;
    317                 case (int) fieldId7:
    318                     results[6][indices[6]++] = pi.readDouble(fieldId7);
    319                     break;
    320                 case (int) fieldId8:
    321                     results[7][indices[7]++] = pi.readDouble(fieldId8);
    322                     break;
    323                 case (int) fieldId9:
    324                     results[8][indices[8]++] = pi.readDouble(fieldId9);
    325                     break;
    326                 case (int) fieldId10:
    327                     // Intentionally don't read the data. Parse should continue normally
    328                     break;
    329                 default:
    330                     fail("Unexpected field id " + pi.getFieldNumber());
    331             }
    332         }
    333         stream.close();
    334         assertEquals(0.0, results[0][0]);
    335         assertEquals(0.0, results[0][1]);
    336         assertEquals(1.0, results[1][0]);
    337         assertEquals(1.0, results[1][1]);
    338         assertEquals(-1234.432, results[2][0]);
    339         assertEquals(-1234.432, results[2][1]);
    340         assertEquals(42.42, results[3][0]);
    341         assertEquals(42.42, results[3][1]);
    342         assertEquals(Double.MIN_NORMAL, results[4][0]);
    343         assertEquals(Double.MIN_NORMAL, results[4][1]);
    344         assertEquals(Double.MIN_VALUE, results[5][0]);
    345         assertEquals(Double.MIN_VALUE, results[5][1]);
    346         assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
    347         assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
    348         assertEquals(Double.NaN, results[7][0]);
    349         assertEquals(Double.NaN, results[7][1]);
    350         assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
    351         assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
    352     }
    353 
    354     /**
    355      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    356      */
    357     public void testRepeatedCompat() throws Exception {
    358         testRepeatedCompat(new double[0]);
    359         testRepeatedCompat(new double[]{0, 1, -1234.432, 42.42,
    360                 Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
    361                 Double.POSITIVE_INFINITY,
    362         });
    363     }
    364 
    365     /**
    366      * Implementation of testRepeatedCompat with a given value.
    367      */
    368     private void testRepeatedCompat(double[] val) throws Exception {
    369         final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
    370         final long fieldId = fieldFlags | ((long) 11 & 0x0ffffffffL);
    371 
    372         final Test.All all = new Test.All();
    373         all.doubleFieldRepeated = val;
    374 
    375         final byte[] proto = MessageNano.toByteArray(all);
    376 
    377         final ProtoInputStream pi = new ProtoInputStream(proto);
    378         final Test.All readback = Test.All.parseFrom(proto);
    379 
    380         double[] result = new double[val.length];
    381         int index = 0;
    382         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    383             switch (pi.getFieldNumber()) {
    384                 case (int) fieldId:
    385                     result[index++] = pi.readDouble(fieldId);
    386                     break;
    387                 default:
    388                     fail("Unexpected field id " + pi.getFieldNumber());
    389             }
    390         }
    391 
    392         assertEquals(readback.doubleFieldRepeated.length, result.length);
    393         for (int i = 0; i < result.length; i++) {
    394             assertEquals(readback.doubleFieldRepeated[i], result[i]);
    395         }
    396     }
    397 
    398 
    399     public void testPacked() throws IOException {
    400         testPacked(0);
    401         testPacked(1);
    402         testPacked(5);
    403     }
    404 
    405     private void testPacked(int chunkSize) throws IOException {
    406         final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
    407 
    408         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    409         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    410         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    411         final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
    412         final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
    413         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    414         final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
    415         final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
    416         final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
    417         final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
    418 
    419         final byte[] protobuf = new byte[]{
    420                 // 1 -> 0 - default value, written when repeated
    421                 (byte) 0x0a,
    422                 (byte) 0x10,
    423                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    424                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    425                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    426                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    427                 // 2 -> 1
    428                 (byte) 0x12,
    429                 (byte) 0x10,
    430                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    431                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
    432                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    433                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
    434                 // 10 -> 1
    435                 (byte) 0x52,
    436                 (byte) 0x10,
    437                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    438                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
    439                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    440                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
    441                 // 3 -> -1234.432
    442                 (byte) 0x1a,
    443                 (byte) 0x10,
    444                 (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
    445                 (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
    446                 (byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
    447                 (byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
    448                 // 4 -> 42.42
    449                 (byte) 0x22,
    450                 (byte) 0x10,
    451                 (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
    452                 (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
    453                 (byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
    454                 (byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
    455                 // 5 -> Double.MIN_NORMAL
    456                 (byte) 0x2a,
    457                 (byte) 0x10,
    458                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    459                 (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
    460                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    461                 (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
    462                 // 6 -> DOUBLE.MIN_VALUE
    463                 (byte) 0x32,
    464                 (byte) 0x10,
    465                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    466                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    467                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    468                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    469                 // 7 -> Double.NEGATIVE_INFINITY
    470                 (byte) 0x3a,
    471                 (byte) 0x10,
    472                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    473                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
    474                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    475                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
    476                 // 8 -> Double.NaN
    477                 (byte) 0x42,
    478                 (byte) 0x10,
    479                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    480                 (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
    481                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    482                 (byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
    483                 // 9 -> Double.POSITIVE_INFINITY
    484                 (byte) 0x4a,
    485                 (byte) 0x10,
    486                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    487                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
    488                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    489                 (byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
    490         };
    491 
    492         InputStream stream = new ByteArrayInputStream(protobuf);
    493         final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
    494         double[][] results = new double[9][2];
    495         int[] indices = new int[9];
    496         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    497 
    498             switch (pi.getFieldNumber()) {
    499                 case (int) fieldId1:
    500                     results[0][indices[0]++] = pi.readDouble(fieldId1);
    501                     break;
    502                 case (int) fieldId2:
    503                     results[1][indices[1]++] = pi.readDouble(fieldId2);
    504                     break;
    505                 case (int) fieldId3:
    506                     results[2][indices[2]++] = pi.readDouble(fieldId3);
    507                     break;
    508                 case (int) fieldId4:
    509                     results[3][indices[3]++] = pi.readDouble(fieldId4);
    510                     break;
    511                 case (int) fieldId5:
    512                     results[4][indices[4]++] = pi.readDouble(fieldId5);
    513                     break;
    514                 case (int) fieldId6:
    515                     results[5][indices[5]++] = pi.readDouble(fieldId6);
    516                     break;
    517                 case (int) fieldId7:
    518                     results[6][indices[6]++] = pi.readDouble(fieldId7);
    519                     break;
    520                 case (int) fieldId8:
    521                     results[7][indices[7]++] = pi.readDouble(fieldId8);
    522                     break;
    523                 case (int) fieldId9:
    524                     results[8][indices[8]++] = pi.readDouble(fieldId9);
    525                     break;
    526                 case (int) fieldId10:
    527                     // Intentionally don't read the data. Parse should continue normally
    528                     break;
    529                 default:
    530                     fail("Unexpected field id " + pi.getFieldNumber());
    531             }
    532         }
    533         stream.close();
    534         assertEquals(0.0, results[0][0]);
    535         assertEquals(0.0, results[0][1]);
    536         assertEquals(1.0, results[1][0]);
    537         assertEquals(1.0, results[1][1]);
    538         assertEquals(-1234.432, results[2][0]);
    539         assertEquals(-1234.432, results[2][1]);
    540         assertEquals(42.42, results[3][0]);
    541         assertEquals(42.42, results[3][1]);
    542         assertEquals(Double.MIN_NORMAL, results[4][0]);
    543         assertEquals(Double.MIN_NORMAL, results[4][1]);
    544         assertEquals(Double.MIN_VALUE, results[5][0]);
    545         assertEquals(Double.MIN_VALUE, results[5][1]);
    546         assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
    547         assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
    548         assertEquals(Double.NaN, results[7][0]);
    549         assertEquals(Double.NaN, results[7][1]);
    550         assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
    551         assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
    552     }
    553 
    554     /**
    555      * Test that reading with ProtoInputStream matches, and can read the output of standard proto.
    556      */
    557     public void testPackedCompat() throws Exception {
    558         testPackedCompat(new double[0]);
    559         testPackedCompat(new double[]{0, 1, -1234.432, 42.42,
    560                 Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
    561                 Double.POSITIVE_INFINITY,
    562         });
    563     }
    564 
    565     /**
    566      * Implementation of testPackedCompat with a given value.
    567      */
    568     private void testPackedCompat(double[] val) throws Exception {
    569         final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
    570         final long fieldId = fieldFlags | ((long) 12 & 0x0ffffffffL);
    571 
    572         final Test.All all = new Test.All();
    573         all.doubleFieldPacked = val;
    574 
    575         final byte[] proto = MessageNano.toByteArray(all);
    576 
    577         final ProtoInputStream pi = new ProtoInputStream(proto);
    578         final Test.All readback = Test.All.parseFrom(proto);
    579 
    580         double[] result = new double[val.length];
    581         int index = 0;
    582         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    583             switch (pi.getFieldNumber()) {
    584                 case (int) fieldId:
    585                     result[index++] = pi.readDouble(fieldId);
    586                     break;
    587                 default:
    588                     fail("Unexpected field id " + pi.getFieldNumber());
    589             }
    590         }
    591 
    592         assertEquals(readback.doubleFieldPacked.length, result.length);
    593         for (int i = 0; i < result.length; i++) {
    594             assertEquals(readback.doubleFieldPacked[i], result[i]);
    595         }
    596     }
    597 
    598     /**
    599      * Test that using the wrong read method throws an exception
    600      */
    601     public void testBadReadType() throws IOException {
    602         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
    603 
    604         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    605 
    606         final byte[] protobuf = new byte[]{
    607                 // 1 -> 1
    608                 (byte) 0x09,
    609                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    610                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    611         };
    612 
    613         ProtoInputStream pi = new ProtoInputStream(protobuf);
    614         pi.isNextField(fieldId1);
    615         try {
    616             pi.readFloat(fieldId1);
    617             fail("Should have throw IllegalArgumentException");
    618         } catch (IllegalArgumentException iae) {
    619             // good
    620         }
    621 
    622         pi = new ProtoInputStream(protobuf);
    623         pi.isNextField(fieldId1);
    624         try {
    625             pi.readBoolean(fieldId1);
    626             fail("Should have throw IllegalArgumentException");
    627         } catch (IllegalArgumentException iae) {
    628             // good
    629         }
    630 
    631         pi = new ProtoInputStream(protobuf);
    632         pi.isNextField(fieldId1);
    633         try {
    634             pi.readInt(fieldId1);
    635             fail("Should have throw IllegalArgumentException");
    636         } catch (IllegalArgumentException iae) {
    637             // good
    638         }
    639 
    640         pi = new ProtoInputStream(protobuf);
    641         pi.isNextField(fieldId1);
    642         try {
    643             pi.readLong(fieldId1);
    644             fail("Should have throw IllegalArgumentException");
    645         } catch (IllegalArgumentException iae) {
    646             // good
    647         }
    648 
    649         pi = new ProtoInputStream(protobuf);
    650         pi.isNextField(fieldId1);
    651         try {
    652             pi.readBytes(fieldId1);
    653             fail("Should have throw IllegalArgumentException");
    654         } catch (IllegalArgumentException iae) {
    655             // good
    656         }
    657 
    658         pi = new ProtoInputStream(protobuf);
    659         pi.isNextField(fieldId1);
    660         try {
    661             pi.readString(fieldId1);
    662             fail("Should have throw IllegalArgumentException");
    663         } catch (IllegalArgumentException iae) {
    664             // good
    665         }
    666     }
    667 
    668     /**
    669      * Test that unexpected wrong wire types will throw an exception
    670      */
    671     public void testBadWireType() throws IOException {
    672         final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
    673 
    674         final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
    675         final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
    676         final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
    677         final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
    678 
    679         final byte[] protobuf = new byte[]{
    680                 // 1 : varint -> 1
    681                 (byte) 0x08,
    682                 (byte) 0x01,
    683                 // 2 : fixed64 -> 0x1
    684                 (byte) 0x11,
    685                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    686                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    687                 // 3 : length delimited -> { 1 }
    688                 (byte) 0x1a,
    689                 (byte) 0x08,
    690                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    691                 (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    692                 // 6 : fixed32
    693                 (byte) 0x35,
    694                 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
    695         };
    696 
    697         InputStream stream = new ByteArrayInputStream(protobuf);
    698         final ProtoInputStream pi = new ProtoInputStream(stream);
    699 
    700         while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
    701             try {
    702                 switch (pi.getFieldNumber()) {
    703                     case (int) fieldId1:
    704                         pi.readDouble(fieldId1);
    705                         fail("Should have thrown a WireTypeMismatchException");
    706                         break;
    707                     case (int) fieldId2:
    708                         pi.readDouble(fieldId2);
    709                         // don't fail, fixed64 is ok
    710                         break;
    711                     case (int) fieldId3:
    712                         pi.readDouble(fieldId3);
    713                         // don't fail, length delimited is ok (represents packed doubles)
    714                         break;
    715                     case (int) fieldId6:
    716                         pi.readDouble(fieldId6);
    717                         fail("Should have thrown a WireTypeMismatchException");
    718                         break;
    719                     default:
    720                         fail("Unexpected field id " + pi.getFieldNumber());
    721                 }
    722             } catch (WireTypeMismatchException wtme) {
    723                 // good
    724             }
    725         }
    726         stream.close();
    727     }
    728 }
    729