1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static org.junit.Assert.assertEquals; 34 import static org.junit.Assert.assertFalse; 35 import static org.junit.Assert.assertNotEquals; 36 import static org.junit.Assert.fail; 37 38 import java.io.IOException; 39 import java.nio.ByteBuffer; 40 import java.util.Arrays; 41 import java.util.Collections; 42 import java.util.List; 43 import org.junit.Before; 44 import org.junit.Test; 45 46 public abstract class AbstractSchemaTest<T extends MessageLite> { 47 private Schema<T> schema; 48 49 @Before setup()50 public void setup() { 51 schema = schema(); 52 registerSchemas(); 53 } 54 55 // Subclass should override this method if it needs to register more than one schemas. registerSchemas()56 protected void registerSchemas() { 57 // Register this schema with the runtime to support processing of nested messages. 58 Protobuf.getInstance().registerSchemaOverride(schema.newInstance().getClass(), schema); 59 } 60 schema()61 protected abstract Schema<T> schema(); 62 messageFactory()63 protected abstract ExperimentalMessageFactory<? extends T> messageFactory(); 64 65 @SuppressWarnings("unused") serializedBytesWithInvalidUtf8()66 protected List<ByteBuffer> serializedBytesWithInvalidUtf8() throws IOException { 67 return Collections.emptyList(); 68 } 69 70 @Test randomMessageShouldRoundtrip()71 public void randomMessageShouldRoundtrip() throws IOException { 72 roundtrip("", messageFactory().newMessage()); 73 } 74 75 @Test invalidUtf8StringParsing()76 public void invalidUtf8StringParsing() throws IOException { 77 for (ByteBuffer invalidUtf8Bytes : serializedBytesWithInvalidUtf8()) { 78 Reader reader = BinaryReader.newInstance(invalidUtf8Bytes, /* bufferIsImmutable= */ true); 79 80 T newMsg = schema.newInstance(); 81 try { 82 schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry()); 83 fail("should throw invalid "); 84 } catch (InvalidProtocolBufferException expected) { 85 } 86 } 87 } 88 89 @Test mergeFromByteArrayFastPathMayThrowIndexOutOfBoundsException()90 public void mergeFromByteArrayFastPathMayThrowIndexOutOfBoundsException() throws IOException { 91 if (!Android.isOnAndroidDevice()) { 92 // Skip this test if not on Android. 93 return; 94 } 95 byte[] data = messageFactory().newMessage().toByteArray(); 96 int exceptionCount = 0; 97 for (int i = 0; i <= data.length; i++) { 98 byte[] truncatedData = Arrays.copyOf(data, i); 99 try { 100 T message = schema.newInstance(); 101 // Test that this method throws the expected exceptions. 102 schema.mergeFrom(message, truncatedData, 0, i, new ArrayDecoders.Registers()); 103 } catch (InvalidProtocolBufferException e) { 104 // Ignore expected exceptions. 105 } catch (IndexOutOfBoundsException e) { 106 exceptionCount += 1; 107 } 108 } 109 assertNotEquals(0, exceptionCount); 110 } 111 roundtrip( String failureMessage, M msg, Schema<M> schema)112 protected static final <M extends MessageLite> void roundtrip( 113 String failureMessage, M msg, Schema<M> schema) throws IOException { 114 byte[] serializedBytes = ExperimentalSerializationUtil.toByteArray(msg, schema); 115 assertEquals(failureMessage, msg.getSerializedSize(), serializedBytes.length); 116 117 // Now read it back in and verify it matches the original. 118 if (Android.isOnAndroidDevice()) { 119 // Test the fast path on Android. 120 M newMsg = schema.newInstance(); 121 schema.mergeFrom( 122 newMsg, serializedBytes, 0, serializedBytes.length, new ArrayDecoders.Registers()); 123 schema.makeImmutable(newMsg); 124 assertEquals(failureMessage, msg, newMsg); 125 } 126 M newMsg = schema.newInstance(); 127 Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(serializedBytes), true); 128 schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry()); 129 schema.makeImmutable(newMsg); 130 131 assertEquals(failureMessage, msg, newMsg); 132 } 133 roundtrip(String failureMessage, T msg)134 protected final void roundtrip(String failureMessage, T msg) throws IOException { 135 roundtrip(failureMessage, msg, schema); 136 } 137 data()138 protected final ExperimentalTestDataProvider data() { 139 return messageFactory().dataProvider(); 140 } 141 newMessagesMissingRequiredFields()142 protected List<T> newMessagesMissingRequiredFields() { 143 return Collections.emptyList(); 144 } 145 146 @SuppressWarnings("unchecked") 147 @Test testRequiredFields()148 public void testRequiredFields() throws Exception { 149 for (T msg : newMessagesMissingRequiredFields()) { 150 if (schema.isInitialized(msg)) { 151 assertEquals("", msg.toString()); 152 msg = (T) msg.toBuilder().build(); 153 } 154 assertFalse(schema.isInitialized(msg)); 155 } 156 } 157 } 158