Merge "Remove Test Api annotation from ProtoInputStream" into qt-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9f7dba6155
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
7
core/java/android/util/proto/TEST_MAPPING
Normal file
7
core/java/android/util/proto/TEST_MAPPING
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "ProtoInputStreamTests"
|
||||
}
|
||||
]
|
||||
}
|
||||
34
tests/ProtoInputStreamTests/Android.mk
Normal file
34
tests/ProtoInputStreamTests/Android.mk
Normal 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)
|
||||
27
tests/ProtoInputStreamTests/AndroidManifest.xml
Normal file
27
tests/ProtoInputStreamTests/AndroidManifest.xml
Normal 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>
|
||||
28
tests/ProtoInputStreamTests/AndroidTest.xml
Normal file
28
tests/ProtoInputStreamTests/AndroidTest.xml
Normal 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>
|
||||
7
tests/ProtoInputStreamTests/TEST_MAPPING
Normal file
7
tests/ProtoInputStreamTests/TEST_MAPPING
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "ProtoInputStreamTests"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
Reference in New Issue
Block a user