Merge "Remove Test Api annotation from ProtoInputStream" into qt-dev

This commit is contained in:
Michael Wachenschwanz
2019-04-10 21:30:49 +00:00
committed by Android (Google) Code Review
26 changed files with 10049 additions and 28 deletions

View File

@@ -2881,31 +2881,6 @@ package android.util.proto {
method public void writeRawZigZag64(long);
}
public final class ProtoInputStream extends android.util.proto.ProtoStream {
ctor public ProtoInputStream(java.io.InputStream, int);
ctor public ProtoInputStream(java.io.InputStream);
ctor public ProtoInputStream(byte[]);
method public int decodeZigZag32(int);
method public long decodeZigZag64(long);
method public String dumpDebugData();
method public void end(long);
method public int getFieldNumber();
method public int getOffset();
method public int getWireType();
method public boolean isNextField(long) throws java.io.IOException;
method public int nextField() throws java.io.IOException;
method public boolean readBoolean(long) throws java.io.IOException;
method public byte[] readBytes(long) throws java.io.IOException;
method public double readDouble(long) throws java.io.IOException;
method public float readFloat(long) throws java.io.IOException;
method public int readInt(long) throws java.io.IOException;
method public long readLong(long) throws java.io.IOException;
method public String readString(long) throws java.io.IOException;
method public void skip() throws java.io.IOException;
method public long start(long) throws java.io.IOException;
field public static final int NO_MORE_FIELDS = -1; // 0xffffffff
}
public final class ProtoOutputStream extends android.util.proto.ProtoStream {
ctor public ProtoOutputStream();
ctor public ProtoOutputStream(int);

View File

@@ -16,8 +16,6 @@
package android.util.proto;
import android.annotation.TestApi;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@@ -64,7 +62,6 @@ import java.util.ArrayList;
*
* @hide
*/
@TestApi
public final class ProtoInputStream extends ProtoStream {
public static final int NO_MORE_FIELDS = -1;

View File

@@ -0,0 +1,7 @@
{
"presubmit": [
{
"name": "ProtoInputStreamTests"
}
]
}

View File

@@ -0,0 +1,34 @@
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := ProtoInputStreamTests
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_MODULE_TAGS := tests optional
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-proto-files-under, src)
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_STATIC_JAVA_LIBRARIES := \
androidx.test.rules \
frameworks-base-testutils \
mockito-target-minus-junit4
include $(BUILD_PACKAGE)

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.protoinputstream">
<application>
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.test.protoinputstream"
android:label="ProtoInputStream Tests">
</instrumentation>
</manifest>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Configuration for ProtoInputStream Tests">
<option name="test-suite-tag" value="ProtoInputStreamTests" />
<option name="config-descriptor:metadata" key="component" value="metrics" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="ProtoInputStreamTests.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.test.protoinputstream" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>

View File

@@ -0,0 +1,7 @@
{
"presubmit": [
{
"name": "ProtoInputStreamTests"
}
]
}

View File

@@ -0,0 +1,500 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamBoolTest extends TestCase {
/**
* Test reading single bool field
*/
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
/**
* Implementation of testRead with a given chunkSize.
*/
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 3 -> 1
(byte) 0x18,
(byte) 0x01,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
boolean[] results = new boolean[2];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readBoolean(fieldId2);
break;
case (int) fieldId3:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(false, results[0]);
assertEquals(true, results[1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(false);
testReadCompat(true);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(boolean val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId = fieldFlags | ((long) 130 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.boolField = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
boolean result = false; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readBoolean(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.boolField, result);
}
/**
* Test reading repeated bool field
*/
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
/**
* Implementation of testRepeated with a given chunkSize.
*/
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 4 -> 0
(byte) 0x20,
(byte) 0x00,
// 4 -> 1
(byte) 0x20,
(byte) 0x01,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> 0
(byte) 0x18,
(byte) 0x00,
// 3 -> 1
(byte) 0x18,
(byte) 0x01,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
boolean[][] results = new boolean[3][2];
int[] indices = new int[3];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readBoolean(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readBoolean(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readBoolean(fieldId3);
break;
case (int) fieldId4:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(false, results[0][0]);
assertEquals(false, results[0][1]);
assertEquals(true, results[1][0]);
assertEquals(true, results[1][1]);
assertEquals(false, results[2][0]);
assertEquals(true, results[2][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new boolean[0]);
testRepeatedCompat(new boolean[]{false, true});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(boolean[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId = fieldFlags | ((long) 131 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.boolFieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
boolean[] result = new boolean[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readBoolean(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.boolFieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.boolFieldRepeated[i], result[i]);
}
}
/**
* Test reading packed bool field
*/
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
/**
* Implementation of testPacked with a given chunkSize.
*/
public void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 4 -> 0,1
(byte) 0x22,
(byte) 0x02,
(byte) 0x00,
(byte) 0x01,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 3 -> 0,1
(byte) 0x1a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x01,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
boolean[][] results = new boolean[3][2];
int[] indices = new int[3];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readBoolean(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readBoolean(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readBoolean(fieldId3);
break;
case (int) fieldId4:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(false, results[0][0]);
assertEquals(false, results[0][1]);
assertEquals(true, results[1][0]);
assertEquals(true, results[1][1]);
assertEquals(false, results[2][0]);
assertEquals(true, results[2][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new boolean[0]);
testPackedCompat(new boolean[]{false, true});
}
/**
* Implementation of testPackedCompat with a given value.
*/
private void testPackedCompat(boolean[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId = fieldFlags | ((long) 132 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.boolFieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
boolean[] result = new boolean[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readBoolean(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.boolFieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.boolFieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BOOL;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readBoolean(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readBoolean(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readBoolean(fieldId3);
// don't fail, length delimited is ok (represents packed booleans)
break;
case (int) fieldId6:
pi.readBoolean(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,423 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
public class ProtoInputStreamBytesTest extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> null - default value, written when repeated
(byte) 0x0a,
(byte) 0x00,
// 2 -> { } - default value, written when repeated
(byte) 0x12,
(byte) 0x00,
// 5 -> { 0, 1, 2, 3, 4 }
(byte) 0x2a,
(byte) 0x05,
(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
// 3 -> { 0, 1, 2, 3, 4, 5 }
(byte) 0x1a,
(byte) 0x06,
(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
// 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
(byte) 0x22,
(byte) 0x04,
(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
byte[][] results = new byte[4][];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0] = pi.readBytes(fieldId1);
break;
case (int) fieldId2:
results[1] = pi.readBytes(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readBytes(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readBytes(fieldId4);
break;
case (int) fieldId5:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertTrue("Expected: [] Actual: " + Arrays.toString(results[0]),
Arrays.equals(new byte[]{}, results[0]));
assertTrue("Expected: [] Actual: " + Arrays.toString(results[1]),
Arrays.equals(new byte[]{}, results[1]));
assertTrue("Expected: [0, 1, 2, 3, 4, 5] Actual: " + Arrays.toString(results[2]),
Arrays.equals(new byte[]{0, 1, 2, 3, 4, 5}, results[2]));
assertTrue("Expected: [-1, -2, -3, -4] Actual: " + Arrays.toString(results[3]),
Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
results[3]));
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(new byte[0]);
testReadCompat(new byte[]{1, 2, 3, 4});
testReadCompat(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc});
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(byte[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
final long fieldId = fieldFlags | ((long) 150 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.bytesField = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
byte[] result = new byte[val.length];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readBytes(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.bytesField.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.bytesField[i], result[i]);
}
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BYTES;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> null - default value, written when repeated
(byte) 0x0a,
(byte) 0x00,
// 2 -> { } - default value, written when repeated
(byte) 0x12,
(byte) 0x00,
// 3 -> { 0, 1, 2, 3, 4, 5 }
(byte) 0x1a,
(byte) 0x06,
(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
// 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
(byte) 0x22,
(byte) 0x04,
(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
// 5 -> { 0, 1, 2, 3, 4}
(byte) 0x2a,
(byte) 0x05,
(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
// 1 -> null - default value, written when repeated
(byte) 0x0a,
(byte) 0x00,
// 2 -> { } - default value, written when repeated
(byte) 0x12,
(byte) 0x00,
// 3 -> { 0, 1, 2, 3, 4, 5 }
(byte) 0x1a,
(byte) 0x06,
(byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
// 4 -> { (byte)0xff, (byte)0xfe, (byte)0xfd, (byte)0xfc }
(byte) 0x22,
(byte) 0x04,
(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
byte[][][] results = new byte[4][2][];
int[] indices = new int[4];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readBytes(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readBytes(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readBytes(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readBytes(fieldId4);
break;
case (int) fieldId5:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assert (Arrays.equals(new byte[]{}, results[0][0]));
assert (Arrays.equals(new byte[]{}, results[0][1]));
assert (Arrays.equals(new byte[]{}, results[1][0]));
assert (Arrays.equals(new byte[]{}, results[1][1]));
assert (Arrays.equals(new byte[]{1, 2, 3, 4}, results[2][0]));
assert (Arrays.equals(new byte[]{1, 2, 3, 4}, results[2][1]));
assert (Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
results[3][0]));
assert (Arrays.equals(new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc},
results[3][1]));
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new byte[0][]);
testRepeatedCompat(new byte[][]{
new byte[0],
new byte[]{1, 2, 3, 4},
new byte[]{(byte) 0xff, (byte) 0xfe, (byte) 0xfd, (byte) 0xfc}
});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(byte[][] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_BYTES;
final long fieldId = fieldFlags | ((long) 151 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.bytesFieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
byte[][] result = new byte[val.length][]; // start off with default value
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readBytes(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.bytesFieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.bytesFieldRepeated[i].length, result[i].length);
for (int j = 0; j < result[i].length; j++) {
assertEquals(readback.bytesFieldRepeated[i][j], result[i][j]);
}
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> {1}
(byte) 0x0a,
(byte) 0x01,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readBytes(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readBytes(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readBytes(fieldId3);
// don't fail, length delimited is ok
break;
case (int) fieldId6:
pi.readBytes(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,728 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamDoubleTest extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x11,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
// 10 -> 1
(byte) 0x51,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x19,
(byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
(byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
// 4 -> 42.42
(byte) 0x21,
(byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
(byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
// 5 -> Double.MIN_NORMAL
(byte) 0x29,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x31,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Double.NEGATIVE_INFINITY
(byte) 0x39,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
// 8 -> Double.NaN
(byte) 0x41,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
// 9 -> Double.POSITIVE_INFINITY
(byte) 0x49,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
double[] results = new double[9];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readDouble(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readDouble(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readDouble(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readDouble(fieldId5);
break;
case (int) fieldId6:
results[5] = pi.readDouble(fieldId6);
break;
case (int) fieldId7:
results[6] = pi.readDouble(fieldId7);
break;
case (int) fieldId8:
results[7] = pi.readDouble(fieldId8);
break;
case (int) fieldId9:
results[8] = pi.readDouble(fieldId9);
break;
case (int) fieldId10:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0.0, results[0]);
assertEquals(1.0, results[1]);
assertEquals(-1234.432, results[2]);
assertEquals(42.42, results[3]);
assertEquals(Double.MIN_NORMAL, results[4]);
assertEquals(Double.MIN_VALUE, results[5]);
assertEquals(Double.NEGATIVE_INFINITY, results[6]);
assertEquals(Double.NaN, results[7]);
assertEquals(Double.POSITIVE_INFINITY, results[8]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1234.432);
testReadCompat(42.42);
testReadCompat(Double.MIN_NORMAL);
testReadCompat(Double.MIN_VALUE);
testReadCompat(Double.NEGATIVE_INFINITY);
testReadCompat(Double.NaN);
testReadCompat(Double.POSITIVE_INFINITY);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(double val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId = fieldFlags | ((long) 10 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.doubleField = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
double result = 0.0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readDouble(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.doubleField, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x09,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x11,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x19,
(byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
(byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
// 4 -> 42.42
(byte) 0x21,
(byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
(byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
// 5 -> Double.MIN_NORMAL
(byte) 0x29,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x31,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Double.NEGATIVE_INFINITY
(byte) 0x39,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
// 8 -> Double.NaN
(byte) 0x41,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
// 9 -> Double.POSITIVE_INFINITY
(byte) 0x49,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
// 10 -> 1
(byte) 0x51,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
// 1 -> 0 - default value, written when repeated
(byte) 0x09,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x11,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x19,
(byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
(byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
// 4 -> 42.42
(byte) 0x21,
(byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
(byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
// 5 -> Double.MIN_NORMAL
(byte) 0x29,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x31,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Double.NEGATIVE_INFINITY
(byte) 0x39,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
// 8 -> Double.NaN
(byte) 0x41,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
// 9 -> Double.POSITIVE_INFINITY
(byte) 0x49,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
double[][] results = new double[9][2];
int[] indices = new int[9];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readDouble(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readDouble(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readDouble(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readDouble(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readDouble(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readDouble(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readDouble(fieldId7);
break;
case (int) fieldId8:
results[7][indices[7]++] = pi.readDouble(fieldId8);
break;
case (int) fieldId9:
results[8][indices[8]++] = pi.readDouble(fieldId9);
break;
case (int) fieldId10:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0.0, results[0][0]);
assertEquals(0.0, results[0][1]);
assertEquals(1.0, results[1][0]);
assertEquals(1.0, results[1][1]);
assertEquals(-1234.432, results[2][0]);
assertEquals(-1234.432, results[2][1]);
assertEquals(42.42, results[3][0]);
assertEquals(42.42, results[3][1]);
assertEquals(Double.MIN_NORMAL, results[4][0]);
assertEquals(Double.MIN_NORMAL, results[4][1]);
assertEquals(Double.MIN_VALUE, results[5][0]);
assertEquals(Double.MIN_VALUE, results[5][1]);
assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
assertEquals(Double.NaN, results[7][0]);
assertEquals(Double.NaN, results[7][1]);
assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new double[0]);
testRepeatedCompat(new double[]{0, 1, -1234.432, 42.42,
Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
Double.POSITIVE_INFINITY,
});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(double[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId = fieldFlags | ((long) 11 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.doubleFieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
double[] result = new double[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readDouble(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.doubleFieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.doubleFieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
// 10 -> 1
(byte) 0x52,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x1a,
(byte) 0x10,
(byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
(byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
(byte) 0x7d, (byte) 0x3f, (byte) 0x35, (byte) 0x5e,
(byte) 0xba, (byte) 0x49, (byte) 0x93, (byte) 0xc0,
// 4 -> 42.42
(byte) 0x22,
(byte) 0x10,
(byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
(byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
(byte) 0xf6, (byte) 0x28, (byte) 0x5c, (byte) 0x8f,
(byte) 0xc2, (byte) 0x35, (byte) 0x45, (byte) 0x40,
// 5 -> Double.MIN_NORMAL
(byte) 0x2a,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x32,
(byte) 0x10,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Double.NEGATIVE_INFINITY
(byte) 0x3a,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0xff,
// 8 -> Double.NaN
(byte) 0x42,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf8, (byte) 0x7f,
// 9 -> Double.POSITIVE_INFINITY
(byte) 0x4a,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0xf0, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
double[][] results = new double[9][2];
int[] indices = new int[9];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readDouble(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readDouble(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readDouble(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readDouble(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readDouble(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readDouble(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readDouble(fieldId7);
break;
case (int) fieldId8:
results[7][indices[7]++] = pi.readDouble(fieldId8);
break;
case (int) fieldId9:
results[8][indices[8]++] = pi.readDouble(fieldId9);
break;
case (int) fieldId10:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0.0, results[0][0]);
assertEquals(0.0, results[0][1]);
assertEquals(1.0, results[1][0]);
assertEquals(1.0, results[1][1]);
assertEquals(-1234.432, results[2][0]);
assertEquals(-1234.432, results[2][1]);
assertEquals(42.42, results[3][0]);
assertEquals(42.42, results[3][1]);
assertEquals(Double.MIN_NORMAL, results[4][0]);
assertEquals(Double.MIN_NORMAL, results[4][1]);
assertEquals(Double.MIN_VALUE, results[5][0]);
assertEquals(Double.MIN_VALUE, results[5][1]);
assertEquals(Double.NEGATIVE_INFINITY, results[6][0]);
assertEquals(Double.NEGATIVE_INFINITY, results[6][1]);
assertEquals(Double.NaN, results[7][0]);
assertEquals(Double.NaN, results[7][1]);
assertEquals(Double.POSITIVE_INFINITY, results[8][0]);
assertEquals(Double.POSITIVE_INFINITY, results[8][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new double[0]);
testPackedCompat(new double[]{0, 1, -1234.432, 42.42,
Double.MIN_NORMAL, Double.MIN_VALUE, Double.NEGATIVE_INFINITY, Double.NaN,
Double.POSITIVE_INFINITY,
});
}
/**
* Implementation of testPackedCompat with a given value.
*/
private void testPackedCompat(double[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId = fieldFlags | ((long) 12 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.doubleFieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
double[] result = new double[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readDouble(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.doubleFieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.doubleFieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x09,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_DOUBLE;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readDouble(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readDouble(fieldId2);
// don't fail, fixed64 is ok
break;
case (int) fieldId3:
pi.readDouble(fieldId3);
// don't fail, length delimited is ok (represents packed doubles)
break;
case (int) fieldId6:
pi.readDouble(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,570 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamEnumTest extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[] results = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(int val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId = fieldFlags | ((long) 160 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.outsideField = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
int result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
// Nano proto drops values that are outside the range, so compare against val
assertEquals(val, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new int[]{});
testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId = fieldFlags | ((long) 161 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.outsideFieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
// Nano proto drops values that are outside the range, so compare against val
assertEquals(val.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(val[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 6 -> MAX_VALUE
(byte) 0x32,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x1a,
(byte) 0x14,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x22,
(byte) 0x14,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x2a,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new int[]{});
testPackedCompat(new int[]{0, 1});
// Nano proto has a bug. It gets the size with computeInt32SizeNoTag (correctly)
// but incorrectly uses writeRawVarint32 to write the value for negative numbers.
//testPackedCompat(new int[] { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE });
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId = fieldFlags | ((long) 162 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.outsideFieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
// Nano proto drops values that are outside the range, so compare against val
assertEquals(val.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(val[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_ENUM;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readInt(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readInt(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readInt(fieldId3);
// don't fail, length delimited is ok (represents packed enums)
break;
case (int) fieldId6:
pi.readInt(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,547 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamFixed32Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x15,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> 1
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x25,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[] results = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(int val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId = fieldFlags | ((long) 90 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.fixed32Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.fixed32Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0d,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x15,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x25,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 6 -> 1
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 1 -> 0 - default value, written when repeated
(byte) 0x0d,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x15,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x25,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new int[0]);
testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId = fieldFlags | ((long) 91 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.fixed32FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.fixed32FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.fixed32FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> 1
(byte) 0x32,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1a,
(byte) 0x08,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x22,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2a,
(byte) 0x08,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new int[0]);
testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId = fieldFlags | ((long) 92 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.fixed32FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.fixed32FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.fixed32FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x0d,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x04,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readInt(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readInt(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readInt(fieldId3);
// don't fail, length delimited is ok (represents packed fixed32)
break;
case (int) fieldId6:
pi.readInt(fieldId6);
// don't fail, fixed32 is ok
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,649 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamFixed64Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> 1
(byte) 0x41,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x19,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x21,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x29,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x31,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x39,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[] results = new long[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
assertEquals(Long.MIN_VALUE, results[5]);
assertEquals(Long.MAX_VALUE, results[6]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
testReadCompat(Long.MIN_VALUE);
testReadCompat(Long.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(long val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId = fieldFlags | ((long) 100 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.fixed64Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.fixed64Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x09,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x19,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x21,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x29,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x31,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x39,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 8 -> 1
(byte) 0x41,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 1 -> 0 - default value, written when repeated
(byte) 0x09,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x19,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x21,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x29,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x31,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x39,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new long[0]);
testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId = fieldFlags | ((long) 101 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.fixed64FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.fixed64FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.fixed64FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x10,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 8 -> 1
(byte) 0x42,
(byte) 0x10,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1a,
(byte) 0x10,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x22,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x2a,
(byte) 0x10,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x32,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x3a,
(byte) 0x10,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new long[0]);
testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId = fieldFlags | ((long) 102 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.fixed64FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.fixed64FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.fixed64FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x09,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readLong(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readLong(fieldId2);
// don't fail, fixed64 is ok
break;
case (int) fieldId3:
pi.readLong(fieldId3);
// don't fail, length delimited is ok (represents packed fixed64)
break;
case (int) fieldId6:
pi.readLong(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,679 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamFloatTest extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x15,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
// 10 -> 1
(byte) 0x55,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x1d,
(byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
// 4 -> 42.42
(byte) 0x25,
(byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
// 5 -> Float.MIN_NORMAL
(byte) 0x2d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Float.NEGATIVE_INFINITY
(byte) 0x3d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
// 8 -> Float.NaN
(byte) 0x45,
(byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
// 9 -> Float.POSITIVE_INFINITY
(byte) 0x4d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
float[] results = new float[9];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readFloat(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readFloat(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readFloat(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readFloat(fieldId5);
break;
case (int) fieldId6:
results[5] = pi.readFloat(fieldId6);
break;
case (int) fieldId7:
results[6] = pi.readFloat(fieldId7);
break;
case (int) fieldId8:
results[7] = pi.readFloat(fieldId8);
break;
case (int) fieldId9:
results[8] = pi.readFloat(fieldId9);
break;
case (int) fieldId10:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0.0f, results[0]);
assertEquals(1.0f, results[1]);
assertEquals(-1234.432f, results[2]);
assertEquals(42.42f, results[3]);
assertEquals(Float.MIN_NORMAL, results[4]);
assertEquals(Float.MIN_VALUE, results[5]);
assertEquals(Float.NEGATIVE_INFINITY, results[6]);
assertEquals(Float.NaN, results[7]);
assertEquals(Float.POSITIVE_INFINITY, results[8]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1234.432f);
testReadCompat(42.42f);
testReadCompat(Float.MIN_NORMAL);
testReadCompat(Float.MIN_VALUE);
testReadCompat(Float.NEGATIVE_INFINITY);
testReadCompat(Float.NaN);
testReadCompat(Float.POSITIVE_INFINITY);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(float val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId = fieldFlags | ((long) 20 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.floatField = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
float result = 0.0f; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readFloat(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.floatField, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0d,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x15,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x1d,
(byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
// 4 -> 42.42
(byte) 0x25,
(byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
// 5 -> Float.MIN_NORMAL
(byte) 0x2d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Float.NEGATIVE_INFINITY
(byte) 0x3d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
// 8 -> Float.NaN
(byte) 0x45,
(byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
// 9 -> Float.POSITIVE_INFINITY
(byte) 0x4d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
// 10 -> 1
(byte) 0x55,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
// 1 -> 0 - default value, written when repeated
(byte) 0x0d,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x15,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x1d,
(byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
// 4 -> 42.42
(byte) 0x25,
(byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
// 5 -> Float.MIN_NORMAL
(byte) 0x2d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Float.NEGATIVE_INFINITY
(byte) 0x3d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
// 8 -> Float.NaN
(byte) 0x45,
(byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
// 9 -> Float.POSITIVE_INFINITY
(byte) 0x4d,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
float[][] results = new float[9][2];
int[] indices = new int[9];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readFloat(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readFloat(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readFloat(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readFloat(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readFloat(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readFloat(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readFloat(fieldId7);
break;
case (int) fieldId8:
results[7][indices[7]++] = pi.readFloat(fieldId8);
break;
case (int) fieldId9:
results[8][indices[8]++] = pi.readFloat(fieldId9);
break;
case (int) fieldId10:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0.0f, results[0][0]);
assertEquals(0.0f, results[0][1]);
assertEquals(1.0f, results[1][0]);
assertEquals(1.0f, results[1][1]);
assertEquals(-1234.432f, results[2][0]);
assertEquals(-1234.432f, results[2][1]);
assertEquals(42.42f, results[3][0]);
assertEquals(42.42f, results[3][1]);
assertEquals(Float.MIN_NORMAL, results[4][0]);
assertEquals(Float.MIN_NORMAL, results[4][1]);
assertEquals(Float.MIN_VALUE, results[5][0]);
assertEquals(Float.MIN_VALUE, results[5][1]);
assertEquals(Float.NEGATIVE_INFINITY, results[6][0]);
assertEquals(Float.NEGATIVE_INFINITY, results[6][1]);
assertEquals(Float.NaN, results[7][0]);
assertEquals(Float.NaN, results[7][1]);
assertEquals(Float.POSITIVE_INFINITY, results[8][0]);
assertEquals(Float.POSITIVE_INFINITY, results[8][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new float[0]);
testRepeatedCompat(new float[]{0, 1, -1234.432f, 42.42f,
Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
Float.POSITIVE_INFINITY,
});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(float[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId = fieldFlags | ((long) 21 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.floatFieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
float[] result = new float[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readFloat(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.floatFieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.floatFieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final long fieldId9 = fieldFlags | ((long) 9 & 0x0ffffffffL);
final long fieldId10 = fieldFlags | ((long) 10 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
// 10 -> 1
(byte) 0x52,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x3f,
// 3 -> -1234.432
(byte) 0x1a,
(byte) 0x08,
(byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
(byte) 0xd3, (byte) 0x4d, (byte) 0x9a, (byte) 0xc4,
// 4 -> 42.42
(byte) 0x22,
(byte) 0x08,
(byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
(byte) 0x14, (byte) 0xae, (byte) 0x29, (byte) 0x42,
// 5 -> Float.MIN_NORMAL
(byte) 0x2a,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x00,
// 6 -> DOUBLE.MIN_VALUE
(byte) 0x32,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 7 -> Float.NEGATIVE_INFINITY
(byte) 0x3a,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0xff,
// 8 -> Float.NaN
(byte) 0x42,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0xc0, (byte) 0x7f,
// 9 -> Float.POSITIVE_INFINITY
(byte) 0x4a,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x80, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
float[][] results = new float[9][2];
int[] indices = new int[9];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readFloat(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readFloat(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readFloat(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readFloat(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readFloat(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readFloat(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readFloat(fieldId7);
break;
case (int) fieldId8:
results[7][indices[7]++] = pi.readFloat(fieldId8);
break;
case (int) fieldId9:
results[8][indices[8]++] = pi.readFloat(fieldId9);
break;
case (int) fieldId10:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0.0f, results[0][0]);
assertEquals(0.0f, results[0][1]);
assertEquals(1.0f, results[1][0]);
assertEquals(1.0f, results[1][1]);
assertEquals(-1234.432f, results[2][0]);
assertEquals(-1234.432f, results[2][1]);
assertEquals(42.42f, results[3][0]);
assertEquals(42.42f, results[3][1]);
assertEquals(Float.MIN_NORMAL, results[4][0]);
assertEquals(Float.MIN_NORMAL, results[4][1]);
assertEquals(Float.MIN_VALUE, results[5][0]);
assertEquals(Float.MIN_VALUE, results[5][1]);
assertEquals(Float.NEGATIVE_INFINITY, results[6][0]);
assertEquals(Float.NEGATIVE_INFINITY, results[6][1]);
assertEquals(Float.NaN, results[7][0]);
assertEquals(Float.NaN, results[7][1]);
assertEquals(Float.POSITIVE_INFINITY, results[8][0]);
assertEquals(Float.POSITIVE_INFINITY, results[8][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new float[0]);
testPackedCompat(new float[]{0, 1, -1234.432f, 42.42f,
Float.MIN_NORMAL, Float.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.NaN,
Float.POSITIVE_INFINITY,
});
}
/**
* Implementation of testPackedCompat with a given value.
*/
private void testPackedCompat(float[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId = fieldFlags | ((long) 22 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.floatFieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
float[] result = new float[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readFloat(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.floatFieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.floatFieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x0d,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FLOAT;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x04,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readFloat(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readFloat(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readFloat(fieldId3);
// don't fail, length delimited is ok (represents packed floats)
break;
case (int) fieldId6:
pi.readFloat(fieldId6);
// don't fail, fixed32 is ok
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,565 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamInt32Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[] results = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(int val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
final long fieldId = fieldFlags | ((long) 30 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.int32Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.int32Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new int[0]);
testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
final long fieldId = fieldFlags | ((long) 31 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.int32FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.int32FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.int32FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_INT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 6 -> MAX_VALUE
(byte) 0x32,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x1a,
(byte) 0x14,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x22,
(byte) 0x14,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x2a,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new int[0]);
testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT32;
final long fieldId = fieldFlags | ((long) 32 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.int32FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.int32FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.int32FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readInt(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readInt(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readInt(fieldId3);
// don't fail, length delimited is ok (represents packed int32)
break;
case (int) fieldId6:
pi.readInt(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,645 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamInt64Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 8 -> Long.MAX_VALUE
(byte) 0x40,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[] results = new long[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
assertEquals(Long.MIN_VALUE, results[5]);
assertEquals(Long.MAX_VALUE, results[6]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
testReadCompat(Long.MIN_VALUE);
testReadCompat(Long.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(long val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
final long fieldId = fieldFlags | ((long) 40 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.int64Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.int64Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 8 -> Long.MAX_VALUE
(byte) 0x40,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new long[0]);
testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
final long fieldId = fieldFlags | ((long) 41 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.int64FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.int64FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.int64FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_INT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 8 -> Long.MAX_VALUE
(byte) 0x42,
(byte) 0x12,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 3 -> -1
(byte) 0x1a,
(byte) 0x14,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x22,
(byte) 0x14,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x2a,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x32,
(byte) 0x14,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x3a,
(byte) 0x12,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new long[0]);
testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_INT64;
final long fieldId = fieldFlags | ((long) 42 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.int64FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.int64FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.int64FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readLong(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readLong(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readLong(fieldId3);
// don't fail, length delimited is ok (represents packed int64)
break;
case (int) fieldId6:
pi.readLong(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,507 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamObjectTest extends TestCase {
class SimpleObject {
public char mChar;
public char mLargeChar;
public String mString;
public SimpleObject mNested;
void parseProto(ProtoInputStream pi) throws IOException {
final long uintFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
final long stringFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
final long messageFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long charId = uintFieldFlags | ((long) 2 & 0x0ffffffffL);
final long largeCharId = uintFieldFlags | ((long) 5000 & 0x0ffffffffL);
final long stringId = stringFieldFlags | ((long) 4 & 0x0ffffffffL);
final long nestedId = messageFieldFlags | ((long) 5 & 0x0ffffffffL);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) charId:
mChar = (char) pi.readInt(charId);
break;
case (int) largeCharId:
mLargeChar = (char) pi.readInt(largeCharId);
break;
case (int) stringId:
mString = pi.readString(stringId);
break;
case (int) nestedId:
long token = pi.start(nestedId);
mNested = new SimpleObject();
mNested.parseProto(pi);
pi.end(token);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
}
}
/**
* Test reading an object with one char in it.
*/
public void testObjectOneChar() throws IOException {
testObjectOneChar(0);
testObjectOneChar(1);
testObjectOneChar(5);
}
/**
* Implementation of testObjectOneChar for a given chunkSize.
*/
private void testObjectOneChar(int chunkSize) throws IOException {
final long messageFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long messageId1 = messageFieldFlags | ((long) 1 & 0x0ffffffffL);
final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// Message 2 : { char 2 : 'c' }
(byte) 0x12, (byte) 0x02, (byte) 0x10, (byte) 0x63,
// Message 1 : { char 2 : 'b' }
(byte) 0x0a, (byte) 0x02, (byte) 0x10, (byte) 0x62,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
SimpleObject result = null;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) messageId1:
final long token = pi.start(messageId1);
result = new SimpleObject();
result.parseProto(pi);
pi.end(token);
break;
case (int) messageId2:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertNotNull(result);
assertEquals('b', result.mChar);
}
/**
* Test reading an object with one multibyte unicode char in it.
*/
public void testObjectOneLargeChar() throws IOException {
testObjectOneLargeChar(0);
testObjectOneLargeChar(1);
testObjectOneLargeChar(5);
}
/**
* Implementation of testObjectOneLargeChar for a given chunkSize.
*/
private void testObjectOneLargeChar(int chunkSize) throws IOException {
final long messageFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long messageId1 = messageFieldFlags | ((long) 1 & 0x0ffffffffL);
final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// Message 2 : { char 5000 : '\u3110' }
(byte) 0x12, (byte) 0x05, (byte) 0xc0, (byte) 0xb8,
(byte) 0x02, (byte) 0x90, (byte) 0x62,
// Message 1 : { char 5000 : '\u3110' }
(byte) 0x0a, (byte) 0x05, (byte) 0xc0, (byte) 0xb8,
(byte) 0x02, (byte) 0x90, (byte) 0x62,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
SimpleObject result = null;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) messageId1:
final long token = pi.start(messageId1);
result = new SimpleObject();
result.parseProto(pi);
pi.end(token);
break;
case (int) messageId2:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertNotNull(result);
assertEquals('\u3110', result.mLargeChar);
}
/**
* Test reading a char, then an object, then a char.
*/
public void testObjectAndTwoChars() throws IOException {
testObjectAndTwoChars(0);
testObjectAndTwoChars(1);
testObjectAndTwoChars(5);
}
/**
* Implementation of testObjectAndTwoChars for a given chunkSize.
*/
private void testObjectAndTwoChars(int chunkSize) throws IOException {
final long uintFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
final long messageFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long charId1 = uintFieldFlags | ((long) 1 & 0x0ffffffffL);
final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
final long charId4 = uintFieldFlags | ((long) 4 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 'a'
(byte) 0x08, (byte) 0x61,
// Message 1 : { char 2 : 'b' }
(byte) 0x12, (byte) 0x02, (byte) 0x10, (byte) 0x62,
// 4 -> 'c'
(byte) 0x20, (byte) 0x63,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
SimpleObject obj = null;
char char1 = '\0';
char char4 = '\0';
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) charId1:
char1 = (char) pi.readInt(charId1);
break;
case (int) messageId2:
final long token = pi.start(messageId2);
obj = new SimpleObject();
obj.parseProto(pi);
pi.end(token);
break;
case (int) charId4:
char4 = (char) pi.readInt(charId4);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals('a', char1);
assertNotNull(obj);
assertEquals('b', obj.mChar);
assertEquals('c', char4);
}
/**
* Test reading a char, then an object with an int and a string in it, then a char.
*/
public void testComplexObject() throws IOException {
testComplexObject(0);
testComplexObject(1);
testComplexObject(5);
}
/**
* Implementation of testComplexObject for a given chunkSize.
*/
private void testComplexObject(int chunkSize) throws IOException {
final long uintFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
final long messageFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long charId1 = uintFieldFlags | ((long) 1 & 0x0ffffffffL);
final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
final long charId4 = uintFieldFlags | ((long) 4 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 'x'
(byte) 0x08, (byte) 0x78,
// begin object 2
(byte) 0x12, (byte) 0x10,
// 2 -> 'y'
(byte) 0x10, (byte) 0x79,
// 4 -> "abcdefghijkl"
(byte) 0x22, (byte) 0x0c,
(byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66,
(byte) 0x67, (byte) 0x68, (byte) 0x69, (byte) 0x6a, (byte) 0x6b, (byte) 0x6c,
// 4 -> 'z'
(byte) 0x20, (byte) 0x7a,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
SimpleObject obj = null;
char char1 = '\0';
char char4 = '\0';
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) charId1:
char1 = (char) pi.readInt(charId1);
break;
case (int) messageId2:
final long token = pi.start(messageId2);
obj = new SimpleObject();
obj.parseProto(pi);
pi.end(token);
break;
case (int) charId4:
char4 = (char) pi.readInt(charId4);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals('x', char1);
assertNotNull(obj);
assertEquals('y', obj.mChar);
assertEquals("abcdefghijkl", obj.mString);
assertEquals('z', char4);
}
/**
* Test reading 3 levels deep of objects.
*/
public void testDeepObjects() throws IOException {
testDeepObjects(0);
testDeepObjects(1);
testDeepObjects(5);
}
/**
* Implementation of testDeepObjects for a given chunkSize.
*/
private void testDeepObjects(int chunkSize) throws IOException {
final long messageFieldFlags =
ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long messageId2 = messageFieldFlags | ((long) 2 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// begin object id 2
(byte) 0x12, (byte) 0x1a,
// 2 -> 'a'
(byte) 0x10, (byte) 0x61,
// begin nested object id 5
(byte) 0x2a, (byte) 0x15,
// 5000 -> '\u3110'
(byte) 0xc0, (byte) 0xb8,
(byte) 0x02, (byte) 0x90, (byte) 0x62,
// begin nested object id 5
(byte) 0x2a, (byte) 0x0e,
// 4 -> "abcdefghijkl"
(byte) 0x22, (byte) 0x0c,
(byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66,
(byte) 0x67, (byte) 0x68, (byte) 0x69, (byte) 0x6a, (byte) 0x6b, (byte) 0x6c,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
SimpleObject obj = null;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) messageId2:
final long token = pi.start(messageId2);
obj = new SimpleObject();
obj.parseProto(pi);
pi.end(token);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertNotNull(obj);
assertEquals('a', obj.mChar);
assertNotNull(obj.mNested);
assertEquals('\u3110', obj.mNested.mLargeChar);
assertNotNull(obj.mNested.mNested);
assertEquals("abcdefghijkl", obj.mNested.mNested.mString);
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> {1}
(byte) 0x0a,
(byte) 0x01,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_MESSAGE;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readBytes(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readBytes(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readBytes(fieldId3);
// don't fail, length delimited is ok
break;
case (int) fieldId6:
pi.readBytes(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,547 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamSFixed32Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x15,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> 1
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x25,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[] results = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(int val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId = fieldFlags | ((long) 110 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sfixed32Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sfixed32Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0d,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x15,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x25,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 6 -> 1
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 1 -> 0 - default value, written when repeated
(byte) 0x0d,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x15,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x25,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2d,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new int[0]);
testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId = fieldFlags | ((long) 111 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sfixed32FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sfixed32FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sfixed32FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> 1
(byte) 0x32,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1a,
(byte) 0x08,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x22,
(byte) 0x08,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 5 -> Integer.MAX_VALUE
(byte) 0x2a,
(byte) 0x08,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new int[0]);
testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId = fieldFlags | ((long) 112 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sfixed32FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sfixed32FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sfixed32FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x04,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readInt(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readInt(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readInt(fieldId3);
// don't fail, length delimited is ok (represents packed sfixed32)
break;
case (int) fieldId6:
pi.readInt(fieldId6);
// don't fail, fixed32 is ok
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,648 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamSFixed64Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 8 -> 1
(byte) 0x41,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x19,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x21,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x29,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x31,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x39,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[] results = new long[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
assertEquals(Long.MIN_VALUE, results[5]);
assertEquals(Long.MAX_VALUE, results[6]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
testReadCompat(Long.MIN_VALUE);
testReadCompat(Long.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(long val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId = fieldFlags | ((long) 120 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sfixed64Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sfixed64Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x09,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x19,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x21,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x29,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x31,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x39,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 8 -> 1
(byte) 0x41,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 1 -> 0 - default value, written when repeated
(byte) 0x09,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x19,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x21,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x29,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x31,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x39,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new long[0]);
testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId = fieldFlags | ((long) 121 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sfixed64FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sfixed64FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sfixed64FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x10,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 8 -> 1
(byte) 0x42,
(byte) 0x10,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 -> -1
(byte) 0x1a,
(byte) 0x10,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 4 -> Integer.MIN_VALUE
(byte) 0x22,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
// 5 -> Integer.MAX_VALUE
(byte) 0x2a,
(byte) 0x10,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 -> Long.MIN_VALUE
(byte) 0x32,
(byte) 0x10,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x80,
// 7 -> Long.MAX_VALUE
(byte) 0x3a,
(byte) 0x10,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new long[0]);
testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId = fieldFlags | ((long) 122 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sfixed64FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sfixed64FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sfixed64FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SFIXED64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x08,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readLong(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readLong(fieldId2);
// don't fail, fixed32 is ok
break;
case (int) fieldId3:
pi.readLong(fieldId3);
// don't fail, length delimited is ok (represents packed sfixed64)
break;
case (int) fieldId6:
pi.readLong(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,547 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamSInt32Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x10,
(byte) 0x02,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 3 -> -1
(byte) 0x18,
(byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[] results = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(int val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId = fieldFlags | ((long) 70 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sint32Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sint32Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x02,
// 3 -> -1
(byte) 0x18,
(byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x02,
// 3 -> -1
(byte) 0x18,
(byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new int[0]);
testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId = fieldFlags | ((long) 71 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sint32FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sint32FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sint32FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x02,
(byte) 0x02,
// 6 -> MAX_VALUE
(byte) 0x32,
(byte) 0x0a,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 3 -> -1
(byte) 0x1a,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x22,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> MAX_VALUE
(byte) 0x2a,
(byte) 0x0a,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new int[0]);
testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId = fieldFlags | ((long) 72 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sint32FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sint32FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sint32FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readInt(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readInt(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readInt(fieldId3);
// don't fail, length delimited is ok (represents packed sint32)
break;
case (int) fieldId6:
pi.readInt(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,622 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamSInt64Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x10,
(byte) 0x02,
// 8 -> Integer.MAX_VALUE
(byte) 0x40,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 3 -> -1
(byte) 0x18,
(byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[] results = new long[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
assertEquals(Long.MIN_VALUE, results[5]);
assertEquals(Long.MAX_VALUE, results[6]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
testReadCompat(Long.MIN_VALUE);
testReadCompat(Long.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(long val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId = fieldFlags | ((long) 80 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sint64Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sint64Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x02,
// 3 -> -1
(byte) 0x18,
(byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 8 -> Integer.MAX_VALUE
(byte) 0x40,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x02,
// 3 -> -1
(byte) 0x18,
(byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new long[0]);
testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId = fieldFlags | ((long) 81 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sint64FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sint64FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sint64FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x02,
(byte) 0x02,
// 8 -> Integer.MAX_VALUE
(byte) 0x42,
(byte) 0x0a,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 3 -> -1
(byte) 0x1a,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x22,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 5 -> Integer.MAX_VALUE
(byte) 0x2a,
(byte) 0x0a,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x0f,
// 6 -> Long.MIN_VALUE
(byte) 0x32,
(byte) 0x14,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x3a,
(byte) 0x14,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new long[0]);
testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId = fieldFlags | ((long) 82 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.sint64FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.sint64FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.sint64FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_SINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readLong(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readLong(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readLong(fieldId3);
// don't fail, length delimited is ok (represents packed sint64)
break;
case (int) fieldId6:
pi.readLong(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,404 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamStringTest extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> null - default value, not written
// 2 -> "" - default value, not written
// 3 -> "abcd\u3110!"
(byte) 0x1a,
(byte) 0x08,
(byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
(byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
// 5 -> "Hi"
(byte) 0x2a,
(byte) 0x02,
(byte) 0x48, (byte) 0x69,
// 4 -> "Hi"
(byte) 0x22,
(byte) 0x02,
(byte) 0x48, (byte) 0x69,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
String[] results = new String[4];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0] = pi.readString(fieldId1);
break;
case (int) fieldId2:
results[1] = pi.readString(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readString(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readString(fieldId4);
break;
case (int) fieldId5:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertNull(results[0]);
assertNull(results[1]);
assertEquals("abcd\u3110!", results[2]);
assertEquals("Hi", results[3]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat("");
testReadCompat("abcd\u3110!");
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(String val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
final long fieldId = fieldFlags | ((long) 140 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.stringField = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
String result = "";
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readString(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.stringField, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_STRING;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> null - default value, written when repeated
(byte) 0x0a,
(byte) 0x00,
// 2 -> "" - default value, written when repeated
(byte) 0x12,
(byte) 0x00,
// 3 -> "abcd\u3110!"
(byte) 0x1a,
(byte) 0x08,
(byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
(byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
// 4 -> "Hi"
(byte) 0x22,
(byte) 0x02,
(byte) 0x48, (byte) 0x69,
// 5 -> "Hi"
(byte) 0x2a,
(byte) 0x02,
(byte) 0x48, (byte) 0x69,
// 1 -> null - default value, written when repeated
(byte) 0x0a,
(byte) 0x00,
// 2 -> "" - default value, written when repeated
(byte) 0x12,
(byte) 0x00,
// 3 -> "abcd\u3110!"
(byte) 0x1a,
(byte) 0x08,
(byte) 0x61, (byte) 0x62, (byte) 0x63, (byte) 0x64,
(byte) 0xe3, (byte) 0x84, (byte) 0x90, (byte) 0x21,
// 4 -> "Hi"
(byte) 0x22,
(byte) 0x02,
(byte) 0x48, (byte) 0x69,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
String[][] results = new String[4][2];
int[] indices = new int[4];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readString(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readString(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readString(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readString(fieldId4);
break;
case (int) fieldId5:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals("", results[0][0]);
assertEquals("", results[0][1]);
assertEquals("", results[1][0]);
assertEquals("", results[1][1]);
assertEquals("abcd\u3110!", results[2][0]);
assertEquals("abcd\u3110!", results[2][1]);
assertEquals("Hi", results[3][0]);
assertEquals("Hi", results[3][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new String[0]);
testRepeatedCompat(new String[]{"", "abcd\u3110!", "Hi"});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(String[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_STRING;
final long fieldId = fieldFlags | ((long) 141 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.stringFieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
String[] result = new String[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readString(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.stringFieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.stringFieldRepeated[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> {1}
(byte) 0x0a,
(byte) 0x01,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_STRING;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readString(fieldId1);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId2:
pi.readString(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readString(fieldId3);
// don't fail, length delimited is ok (represents packed booleans)
break;
case (int) fieldId6:
pi.readString(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,564 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamUInt32Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[] results = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(int val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId = fieldFlags | ((long) 50 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.uint32Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.uint32Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 6 -> MAX_VALUE
(byte) 0x30,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new int[0]);
testRepeatedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId = fieldFlags | ((long) 51 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.uint32FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.uint32FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.uint32FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 6 -> MAX_VALUE
(byte) 0x32,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x1a,
(byte) 0x14,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> MIN_VALUE
(byte) 0x22,
(byte) 0x14,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> MAX_VALUE
(byte) 0x2a,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
int[][] results = new int[5][2];
int[] indices = new int[5];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readInt(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readInt(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readInt(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readInt(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readInt(fieldId5);
break;
case (int) fieldId6:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new int[0]);
testPackedCompat(new int[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(int[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId = fieldFlags | ((long) 52 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.uint32FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
int[] result = new int[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readInt(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.uint32FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.uint32FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readLong(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT32;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readInt(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readInt(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readInt(fieldId3);
// don't fail, length delimited is ok (represents packed uint32)
break;
case (int) fieldId6:
pi.readInt(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,641 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoStream;
import android.util.proto.WireTypeMismatchException;
import com.android.test.protoinputstream.nano.Test;
import com.google.protobuf.nano.MessageNano;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ProtoInputStreamUInt64Test extends TestCase {
public void testRead() throws IOException {
testRead(0);
testRead(1);
testRead(5);
}
private void testRead(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, not written
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 8 -> Integer.MAX_VALUE
(byte) 0x40,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[] results = new long[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
fail("Should never reach this");
break;
case (int) fieldId2:
results[1] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0]);
assertEquals(1, results[1]);
assertEquals(-1, results[2]);
assertEquals(Integer.MIN_VALUE, results[3]);
assertEquals(Integer.MAX_VALUE, results[4]);
assertEquals(Long.MIN_VALUE, results[5]);
assertEquals(Long.MAX_VALUE, results[6]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testReadCompat() throws Exception {
testReadCompat(0);
testReadCompat(1);
testReadCompat(-1);
testReadCompat(Integer.MIN_VALUE);
testReadCompat(Integer.MAX_VALUE);
testReadCompat(Long.MIN_VALUE);
testReadCompat(Long.MAX_VALUE);
}
/**
* Implementation of testReadCompat with a given value.
*/
private void testReadCompat(long val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId = fieldFlags | ((long) 60 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.uint64Field = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long result = 0; // start off with default value
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.uint64Field, result);
}
public void testRepeated() throws IOException {
testRepeated(0);
testRepeated(1);
testRepeated(5);
}
private void testRepeated(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
// 8 -> Integer.MAX_VALUE
(byte) 0x40,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 1 -> 0 - default value, written when repeated
(byte) 0x08,
(byte) 0x00,
// 2 -> 1
(byte) 0x10,
(byte) 0x01,
// 3 -> -1
(byte) 0x18,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x20,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x28,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x30,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x38,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testRepeatedCompat() throws Exception {
testRepeatedCompat(new long[0]);
testRepeatedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testRepeatedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId = fieldFlags | ((long) 61 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.uint64FieldRepeated = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.uint64FieldRepeated.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.uint64FieldRepeated[i], result[i]);
}
}
public void testPacked() throws IOException {
testPacked(0);
testPacked(1);
testPacked(5);
}
private void testPacked(int chunkSize) throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_PACKED | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId4 = fieldFlags | ((long) 4 & 0x0ffffffffL);
final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final long fieldId7 = fieldFlags | ((long) 7 & 0x0ffffffffL);
final long fieldId8 = fieldFlags | ((long) 8 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 0 - default value, written when repeated
(byte) 0x0a,
(byte) 0x02,
(byte) 0x00,
(byte) 0x00,
// 2 -> 1
(byte) 0x12,
(byte) 0x02,
(byte) 0x01,
(byte) 0x01,
// 8 -> Integer.MAX_VALUE
(byte) 0x42,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 3 -> -1
(byte) 0x1a,
(byte) 0x14,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 4 -> Integer.MIN_VALUE
(byte) 0x22,
(byte) 0x14,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0xf8,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x01,
// 5 -> Integer.MAX_VALUE
(byte) 0x2a,
(byte) 0x0a,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x07,
// 6 -> Long.MIN_VALUE
(byte) 0x32,
(byte) 0x14,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x01,
// 7 -> Long.MAX_VALUE
(byte) 0x3a,
(byte) 0x12,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7f,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream, chunkSize);
long[][] results = new long[7][2];
int[] indices = new int[7];
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
results[0][indices[0]++] = pi.readLong(fieldId1);
break;
case (int) fieldId2:
results[1][indices[1]++] = pi.readLong(fieldId2);
break;
case (int) fieldId3:
results[2][indices[2]++] = pi.readLong(fieldId3);
break;
case (int) fieldId4:
results[3][indices[3]++] = pi.readLong(fieldId4);
break;
case (int) fieldId5:
results[4][indices[4]++] = pi.readLong(fieldId5);
break;
case (int) fieldId6:
results[5][indices[5]++] = pi.readLong(fieldId6);
break;
case (int) fieldId7:
results[6][indices[6]++] = pi.readLong(fieldId7);
break;
case (int) fieldId8:
// Intentionally don't read the data. Parse should continue normally
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
stream.close();
assertEquals(0, results[0][0]);
assertEquals(0, results[0][1]);
assertEquals(1, results[1][0]);
assertEquals(1, results[1][1]);
assertEquals(-1, results[2][0]);
assertEquals(-1, results[2][1]);
assertEquals(Integer.MIN_VALUE, results[3][0]);
assertEquals(Integer.MIN_VALUE, results[3][1]);
assertEquals(Integer.MAX_VALUE, results[4][0]);
assertEquals(Integer.MAX_VALUE, results[4][1]);
assertEquals(Long.MIN_VALUE, results[5][0]);
assertEquals(Long.MIN_VALUE, results[5][1]);
assertEquals(Long.MAX_VALUE, results[6][0]);
assertEquals(Long.MAX_VALUE, results[6][1]);
}
/**
* Test that reading with ProtoInputStream matches, and can read the output of standard proto.
*/
public void testPackedCompat() throws Exception {
testPackedCompat(new long[0]);
testPackedCompat(new long[]{0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE});
}
/**
* Implementation of testRepeatedCompat with a given value.
*/
private void testPackedCompat(long[] val) throws Exception {
final long fieldFlags = ProtoStream.FIELD_COUNT_REPEATED | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId = fieldFlags | ((long) 62 & 0x0ffffffffL);
final Test.All all = new Test.All();
all.uint64FieldPacked = val;
final byte[] proto = MessageNano.toByteArray(all);
final ProtoInputStream pi = new ProtoInputStream(proto);
final Test.All readback = Test.All.parseFrom(proto);
long[] result = new long[val.length];
int index = 0;
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (pi.getFieldNumber()) {
case (int) fieldId:
result[index++] = pi.readLong(fieldId);
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
}
assertEquals(readback.uint64FieldPacked.length, result.length);
for (int i = 0; i < result.length; i++) {
assertEquals(readback.uint64FieldPacked[i], result[i]);
}
}
/**
* Test that using the wrong read method throws an exception
*/
public void testBadReadType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 -> 1
(byte) 0x08,
(byte) 0x01,
};
ProtoInputStream pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readFloat(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readDouble(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readInt(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBoolean(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readBytes(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
pi = new ProtoInputStream(protobuf);
pi.isNextField(fieldId1);
try {
pi.readString(fieldId1);
fail("Should have throw IllegalArgumentException");
} catch (IllegalArgumentException iae) {
// good
}
}
/**
* Test that unexpected wrong wire types will throw an exception
*/
public void testBadWireType() throws IOException {
final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_UINT64;
final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL);
final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL);
final long fieldId3 = fieldFlags | ((long) 3 & 0x0ffffffffL);
final long fieldId6 = fieldFlags | ((long) 6 & 0x0ffffffffL);
final byte[] protobuf = new byte[]{
// 1 : varint -> 1
(byte) 0x08,
(byte) 0x01,
// 2 : fixed64 -> 0x1
(byte) 0x11,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
// 3 : length delimited -> { 1 }
(byte) 0x1a,
(byte) 0x01,
(byte) 0x01,
// 6 : fixed32
(byte) 0x35,
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
};
InputStream stream = new ByteArrayInputStream(protobuf);
final ProtoInputStream pi = new ProtoInputStream(stream);
while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
try {
switch (pi.getFieldNumber()) {
case (int) fieldId1:
pi.readLong(fieldId1);
// don't fail, varint is ok
break;
case (int) fieldId2:
pi.readLong(fieldId2);
fail("Should have thrown a WireTypeMismatchException");
break;
case (int) fieldId3:
pi.readLong(fieldId3);
// don't fail, length delimited is ok (represents packed uint64)
break;
case (int) fieldId6:
pi.readLong(fieldId6);
fail("Should have thrown a WireTypeMismatchException");
break;
default:
fail("Unexpected field id " + pi.getFieldNumber());
}
} catch (WireTypeMismatchException wtme) {
// good
}
}
stream.close();
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.test.protoinputstream;
import junit.framework.TestSuite;
public class ProtoTests {
public static TestSuite suite() {
TestSuite suite = new TestSuite(ProtoTests.class.getName());
suite.addTestSuite(ProtoInputStreamDoubleTest.class);
suite.addTestSuite(ProtoInputStreamFloatTest.class);
suite.addTestSuite(ProtoInputStreamInt32Test.class);
suite.addTestSuite(ProtoInputStreamInt64Test.class);
suite.addTestSuite(ProtoInputStreamUInt32Test.class);
suite.addTestSuite(ProtoInputStreamUInt64Test.class);
suite.addTestSuite(ProtoInputStreamSInt32Test.class);
suite.addTestSuite(ProtoInputStreamSInt64Test.class);
suite.addTestSuite(ProtoInputStreamFixed32Test.class);
suite.addTestSuite(ProtoInputStreamFixed64Test.class);
suite.addTestSuite(ProtoInputStreamSFixed32Test.class);
suite.addTestSuite(ProtoInputStreamSFixed64Test.class);
suite.addTestSuite(ProtoInputStreamBoolTest.class);
suite.addTestSuite(ProtoInputStreamStringTest.class);
suite.addTestSuite(ProtoInputStreamBytesTest.class);
suite.addTestSuite(ProtoInputStreamEnumTest.class);
suite.addTestSuite(ProtoInputStreamObjectTest.class);
return suite;
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
syntax = "proto2";
package com.android.test.protoinputstream;
/**
* Enum that outside the scope of any classes.
*/
enum Outside {
OUTSIDE_0 = 0;
OUTSIDE_1 = 1;
};
/**
* Message that is recursive.
*/
message Nested {
optional int32 data = 10001;
optional Nested nested = 10002;
};
/**
* Message with all of the field types.
*/
message All {
/**
* Enum that is inside the scope of a class.
*/
enum Inside {
option allow_alias = true;
INSIDE_0 = 0;
INSIDE_1 = 1;
INSIDE_1A = 1;
};
optional double double_field = 10;
repeated double double_field_repeated = 11;
repeated double double_field_packed = 12 [packed=true];
optional float float_field = 20;
repeated float float_field_repeated = 21;
repeated float float_field_packed = 22 [packed=true];
optional int32 int32_field = 30;
repeated int32 int32_field_repeated = 31;
repeated int32 int32_field_packed = 32 [packed=true];
optional int64 int64_field = 40;
repeated int64 int64_field_repeated = 41;
repeated int64 int64_field_packed = 42 [packed=true];
optional uint32 uint32_field = 50;
repeated uint32 uint32_field_repeated = 51;
repeated uint32 uint32_field_packed = 52 [packed=true];
optional uint64 uint64_field = 60;
repeated uint64 uint64_field_repeated = 61;
repeated uint64 uint64_field_packed = 62 [packed=true];
optional sint32 sint32_field = 70;
repeated sint32 sint32_field_repeated = 71;
repeated sint32 sint32_field_packed = 72 [packed=true];
optional sint64 sint64_field = 80;
repeated sint64 sint64_field_repeated = 81;
repeated sint64 sint64_field_packed = 82 [packed=true];
optional fixed32 fixed32_field = 90;
repeated fixed32 fixed32_field_repeated = 91;
repeated fixed32 fixed32_field_packed = 92 [packed=true];
optional fixed64 fixed64_field = 100;
repeated fixed64 fixed64_field_repeated = 101;
repeated fixed64 fixed64_field_packed = 102 [packed=true];
optional sfixed32 sfixed32_field = 110;
repeated sfixed32 sfixed32_field_repeated = 111;
repeated sfixed32 sfixed32_field_packed = 112 [packed=true];
optional sfixed64 sfixed64_field = 120;
repeated sfixed64 sfixed64_field_repeated = 121;
repeated sfixed64 sfixed64_field_packed = 122 [packed=true];
optional bool bool_field = 130;
repeated bool bool_field_repeated = 131;
repeated bool bool_field_packed = 132 [packed=true];
optional string string_field = 140;
repeated string string_field_repeated = 141;
optional bytes bytes_field = 150;
repeated bytes bytes_field_repeated = 151;
optional Outside outside_field = 160;
repeated Outside outside_field_repeated = 161;
repeated Outside outside_field_packed = 162 [packed=true];
optional Nested nested_field = 170;
repeated Nested nested_field_repeated = 171;
};