• 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 
12 import protobuf_unittest.UnittestMset.RawMessageSet;
13 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
14 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
15 import protobuf_unittest.UnittestMset.TestMessageSetExtension3;
16 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.junit.runner.RunWith;
20 import org.junit.runners.JUnit4;
21 
22 /** Tests related to handling of MessageSets with lazily parsed extensions. */
23 @RunWith(JUnit4.class)
24 public class LazilyParsedMessageSetTest {
25   private static final int TYPE_ID_1 =
26       TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
27   private static final int TYPE_ID_2 =
28       TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
29   private static final int TYPE_ID_3 =
30       TestMessageSetExtension3.getDescriptor().getExtensions().get(0).getNumber();
31   private static final ByteString CORRUPTED_MESSAGE_PAYLOAD =
32       ByteString.copyFrom(new byte[] {(byte) 0xff});
33 
34   @Before
setUp()35   public void setUp() {
36     ExtensionRegistryLite.setEagerlyParseMessageSets(false);
37   }
38 
39   @Test
testParseAndUpdateMessageSet_unaccessedLazyFieldsAreNotLoaded()40   public void testParseAndUpdateMessageSet_unaccessedLazyFieldsAreNotLoaded() throws Exception {
41     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
42     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
43     extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
44     extensionRegistry.add(TestMessageSetExtension3.messageSetExtension);
45 
46     // Set up a TestMessageSet with 2 extensions. The first extension has corrupted payload
47     // data. The test below makes sure that we never load this extension. If we ever do, then we
48     // will handle the exception and replace the value with the default empty message (this behavior
49     // is tested below in testLoadCorruptedLazyField_getsReplacedWithEmptyMessage). Later on we
50     // check that when we serialize the message set, we still have corrupted payload for the first
51     // extension.
52     RawMessageSet inputRaw =
53         RawMessageSet.newBuilder()
54             .addItem(
55                 RawMessageSet.Item.newBuilder()
56                     .setTypeId(TYPE_ID_1)
57                     .setMessage(CORRUPTED_MESSAGE_PAYLOAD))
58             .addItem(
59                 RawMessageSet.Item.newBuilder()
60                     .setTypeId(TYPE_ID_2)
61                     .setMessage(
62                         TestMessageSetExtension2.newBuilder().setStr("foo").build().toByteString()))
63             .build();
64 
65     ByteString inputData = inputRaw.toByteString();
66 
67     // Re-parse as a TestMessageSet, so that all extensions are lazy
68     TestMessageSet messageSet = TestMessageSet.parseFrom(inputData, extensionRegistry);
69 
70     // Update one extension and add a new one.
71     TestMessageSet.Builder builder = messageSet.toBuilder();
72     builder.setExtension(
73         TestMessageSetExtension2.messageSetExtension,
74         TestMessageSetExtension2.newBuilder().setStr("bar").build());
75 
76     // Call .build() in the middle of updating the builder. This triggers a codepath that we want to
77     // make sure preserves lazy fields.
78     TestMessageSet unusedIntermediateMessageSet = builder.build();
79 
80     builder.setExtension(
81         TestMessageSetExtension3.messageSetExtension,
82         TestMessageSetExtension3.newBuilder().setRequiredInt(666).build());
83 
84     TestMessageSet updatedMessageSet = builder.build();
85 
86     // Check that hasExtension call does not load lazy fields.
87     assertThat(updatedMessageSet.hasExtension(TestMessageSetExtension1.messageSetExtension))
88         .isTrue();
89 
90     // Serialize. The first extension should still be unloaded and will get serialized using the
91     // same corrupted byte array.
92     ByteString outputData = updatedMessageSet.toByteString();
93 
94     // Re-parse as RawMessageSet
95     RawMessageSet actualRaw =
96         RawMessageSet.parseFrom(outputData, ExtensionRegistry.getEmptyRegistry());
97 
98     RawMessageSet expectedRaw =
99         RawMessageSet.newBuilder()
100             .addItem(
101                 RawMessageSet.Item.newBuilder()
102                     .setTypeId(TYPE_ID_1)
103                     // This is the important part -- we want to make sure that the payload of the
104                     // 1st extensions is the same corrupted byte array. If we ever load the
105                     // extension during our manipulations above, then we would have replaced it with
106                     // the default empty message.
107                     .setMessage(CORRUPTED_MESSAGE_PAYLOAD))
108             .addItem(
109                 RawMessageSet.Item.newBuilder()
110                     .setTypeId(TYPE_ID_2)
111                     .setMessage(
112                         TestMessageSetExtension2.newBuilder().setStr("bar").build().toByteString()))
113             .addItem(
114                 RawMessageSet.Item.newBuilder()
115                     .setTypeId(TYPE_ID_3)
116                     .setMessage(
117                         TestMessageSetExtension3.newBuilder()
118                             .setRequiredInt(666)
119                             .build()
120                             .toByteString()))
121             .build();
122 
123     assertThat(actualRaw).isEqualTo(expectedRaw);
124   }
125 
126   @Test
testLoadCorruptedLazyField_getsReplacedWithEmptyMessage()127   public void testLoadCorruptedLazyField_getsReplacedWithEmptyMessage() throws Exception {
128     ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
129     extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
130 
131     RawMessageSet inputRaw =
132         RawMessageSet.newBuilder()
133             .addItem(
134                 RawMessageSet.Item.newBuilder()
135                     .setTypeId(TYPE_ID_1)
136                     .setMessage(CORRUPTED_MESSAGE_PAYLOAD))
137             .build();
138 
139     ByteString inputData = inputRaw.toByteString();
140 
141     // Re-parse as a TestMessageSet, so that all extensions are lazy
142     TestMessageSet messageSet = TestMessageSet.parseFrom(inputData, extensionRegistry);
143 
144     assertThat(messageSet.getExtension(TestMessageSetExtension1.messageSetExtension))
145         .isEqualTo(TestMessageSetExtension1.getDefaultInstance());
146 
147     // Serialize. The first extension should be serialized as an empty message.
148     ByteString outputData = messageSet.toByteString();
149 
150     // Re-parse as RawMessageSet
151     RawMessageSet actualRaw =
152         RawMessageSet.parseFrom(outputData, ExtensionRegistry.getEmptyRegistry());
153 
154     RawMessageSet expectedRaw =
155         RawMessageSet.newBuilder()
156             .addItem(
157                 RawMessageSet.Item.newBuilder().setTypeId(TYPE_ID_1).setMessage(ByteString.empty()))
158             .build();
159 
160     assertThat(actualRaw).isEqualTo(expectedRaw);
161   }
162 }
163