• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 import static com.google.common.truth.Truth.assertThat;
11 import static com.google.common.truth.Truth.assertWithMessage;
12 
13 import java.io.IOException;
14 import java.nio.ByteBuffer;
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.List;
18 import org.junit.Before;
19 import org.junit.Test;
20 
21 public abstract class AbstractSchemaTest<T extends MessageLite> {
22   private Schema<T> schema;
23 
24   @Before
setup()25   public void setup() {
26     schema = schema();
27     registerSchemas();
28   }
29 
30   // Subclass should override this method if it needs to register more than one schemas.
registerSchemas()31   protected void registerSchemas() {
32     // Register this schema with the runtime to support processing of nested messages.
33     Protobuf.getInstance().registerSchemaOverride(schema.newInstance().getClass(), schema);
34   }
35 
schema()36   protected abstract Schema<T> schema();
37 
messageFactory()38   protected abstract ExperimentalMessageFactory<? extends T> messageFactory();
39 
40   @SuppressWarnings("unused")
serializedBytesWithInvalidUtf8()41   protected List<ByteBuffer> serializedBytesWithInvalidUtf8() throws IOException {
42     return Collections.emptyList();
43   }
44 
45   @Test
randomMessageShouldRoundtrip()46   public void randomMessageShouldRoundtrip() throws IOException {
47     roundtrip("", messageFactory().newMessage());
48   }
49 
50   @Test
invalidUtf8StringParsing()51   public void invalidUtf8StringParsing() throws IOException {
52     for (ByteBuffer invalidUtf8Bytes : serializedBytesWithInvalidUtf8()) {
53       Reader reader = BinaryReader.newInstance(invalidUtf8Bytes, /* bufferIsImmutable= */ true);
54 
55       T newMsg = schema.newInstance();
56       try {
57         schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry());
58         assertWithMessage("should throw invalid").fail();
59       } catch (InvalidProtocolBufferException expected) {
60       }
61     }
62   }
63 
64   @Test
mergeFromByteArrayFastPathMayThrowIndexOutOfBoundsException()65   public void mergeFromByteArrayFastPathMayThrowIndexOutOfBoundsException() throws IOException {
66     if (!Android.isOnAndroidDevice()) {
67       // Skip this test if not on Android.
68       return;
69     }
70     byte[] data = messageFactory().newMessage().toByteArray();
71     int exceptionCount = 0;
72     for (int i = 0; i <= data.length; i++) {
73       byte[] truncatedData = Arrays.copyOf(data, i);
74       try {
75         T message = schema.newInstance();
76         // Test that this method throws the expected exceptions.
77         schema.mergeFrom(message, truncatedData, 0, i, new ArrayDecoders.Registers());
78       } catch (InvalidProtocolBufferException e) {
79         // Ignore expected exceptions.
80       } catch (IndexOutOfBoundsException e) {
81         exceptionCount += 1;
82       }
83     }
84     assertThat(exceptionCount).isNotEqualTo(0);
85   }
86 
roundtrip( String failureMessage, M msg, Schema<M> schema)87   protected static final <M extends MessageLite> void roundtrip(
88       String failureMessage, M msg, Schema<M> schema) throws IOException {
89     byte[] serializedBytes = ExperimentalSerializationUtil.toByteArray(msg, schema);
90     assertWithMessage(failureMessage)
91         .that(serializedBytes.length)
92         .isEqualTo(msg.getSerializedSize());
93 
94     // Now read it back in and verify it matches the original.
95     if (Android.isOnAndroidDevice()) {
96       // Test the fast path on Android.
97       M newMsg = schema.newInstance();
98       schema.mergeFrom(
99           newMsg, serializedBytes, 0, serializedBytes.length, new ArrayDecoders.Registers());
100       schema.makeImmutable(newMsg);
101       assertWithMessage(failureMessage).that(newMsg).isEqualTo(msg);
102     }
103     M newMsg = schema.newInstance();
104     Reader reader = BinaryReader.newInstance(ByteBuffer.wrap(serializedBytes), true);
105     schema.mergeFrom(newMsg, reader, ExtensionRegistryLite.getEmptyRegistry());
106     schema.makeImmutable(newMsg);
107 
108     assertWithMessage(failureMessage).that(newMsg).isEqualTo(msg);
109   }
110 
roundtrip(String failureMessage, T msg)111   protected final void roundtrip(String failureMessage, T msg) throws IOException {
112     roundtrip(failureMessage, msg, schema);
113   }
114 
data()115   protected final ExperimentalTestDataProvider data() {
116     return messageFactory().dataProvider();
117   }
118 
newMessagesMissingRequiredFields()119   protected List<T> newMessagesMissingRequiredFields() {
120     return Collections.emptyList();
121   }
122 
123   @SuppressWarnings("unchecked")
124   @Test
testRequiredFields()125   public void testRequiredFields() throws Exception {
126     for (T msg : newMessagesMissingRequiredFields()) {
127       if (schema.isInitialized(msg)) {
128         assertThat(msg.toString()).isEmpty();
129         msg = (T) msg.toBuilder().build();
130       }
131       assertThat(schema.isInitialized(msg)).isFalse();
132     }
133   }
134 }
135