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