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