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