aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
authorGravatar janakr <janakr@google.com>2018-03-13 13:07:52 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-03-13 13:09:37 -0700
commit9ba46f8f3c2f62a37914e7bfb199c65a71b64b9f (patch)
treea37d6665ae4c4f156e0ff27616bfe8ea01791846 /src/test/java/com/google/devtools/build/lib
parent25f37123a0b33484acedaab2ef7c78d50365c43a (diff)
Integrate memoization into standard serialization. This involves a number of large changes:
1. SerializationContext and DeserializationContext become the owners of the Memoizer if requested. They produce new versions of themselves on demand that are memoization-aware. Because of intricacies of Skylark that I do not fully understand, we inject a Mutability object when starting memoization, and so to be conservative, that injection starts up a new memoization frame, nested if we were already memoizing, just like before. It would be nice to decouple this injection from memoization in the future. 2. MemoizingCodec is deleted, but really ObjectCodec becomes MemoizingCodec, so it lives on. BaseCodec is deleted since it now has only one implementation. 3. The simplified model of registering MemoizingCodecs is adopted for ObjectCodecs: all codecs are registered based on their #getEncodedClass and #additionalEncodedSubclasses. This also allows us to register codecs that are defined using tricky parameter types, since we're no longer trying to reflectively examine them. This required a clean-up of such codecs, and the addition of ArrayListCodec to stop NullableListCodec from making lists unmodifiable when they shouldn't be. 4. @AutoCodec is extended to allow users to specify that memoization should start with this codec. To ensure bit-equivalence, SkyKeySerializer disables memoization. PiperOrigin-RevId: 188918251
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib')
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContextTest.java57
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodecTest.java77
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecRegistryTest.java50
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecsTest.java12
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContextTest.java94
5 files changed, 167 insertions, 123 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContextTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContextTest.java
index 764284a2ea..ba99518e6f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContextTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/DeserializationContextTest.java
@@ -18,7 +18,9 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec.MemoizationStrategy;
import com.google.protobuf.CodedInputStream;
import java.io.IOException;
import org.junit.Test;
@@ -82,13 +84,10 @@ public class DeserializationContextTest {
new DeserializationContext(registry, ImmutableMap.of());
when(codedInputStream.readSInt32()).thenReturn(0);
assertThat(
- deserializationContext
- .getMemoizingCodecRecordedInInput(codedInputStream)
- .deserializePayload(
- deserializationContext,
- /*initial=*/ null,
- codedInputStream,
- new Memoizer.Deserializer()))
+ (Object)
+ deserializationContext
+ .newMemoizingContext(new Object())
+ .deserialize(codedInputStream))
.isEqualTo(null);
Mockito.verify(codedInputStream).readSInt32();
Mockito.verifyZeroInteractions(registry);
@@ -104,40 +103,23 @@ public class DeserializationContextTest {
new DeserializationContext(registry, ImmutableMap.of());
when(codedInputStream.readSInt32()).thenReturn(1);
assertThat(
- deserializationContext
- .getMemoizingCodecRecordedInInput(codedInputStream)
- .deserializePayload(
- deserializationContext,
- /*initial=*/ null,
- codedInputStream,
- new Memoizer.Deserializer()))
+ (Object)
+ deserializationContext
+ .newMemoizingContext(new Object())
+ .deserialize(codedInputStream))
.isEqualTo(constant);
Mockito.verify(codedInputStream).readSInt32();
Mockito.verify(registry).maybeGetConstantByTag(1);
}
@Test
- public void memoizingDeserialize_memoize() throws SerializationException, IOException {
- @SuppressWarnings("unchecked")
- Memoizer.MemoizingCodec<?> memoizingCodec = Mockito.mock(Memoizer.MemoizingCodec.class);
- ObjectCodecRegistry registry = Mockito.mock(ObjectCodecRegistry.class);
- doReturn(memoizingCodec).when(registry).maybeGetMemoizingCodecByTag(1);
- CodedInputStream codedInputStream = Mockito.mock(CodedInputStream.class);
- DeserializationContext deserializationContext =
- new DeserializationContext(registry, ImmutableMap.of());
- when(codedInputStream.readSInt32()).thenReturn(1);
- assertThat(deserializationContext.getMemoizingCodecRecordedInInput(codedInputStream))
- .isSameAs(memoizingCodec);
- Mockito.verify(codedInputStream).readSInt32();
- Mockito.verify(registry).maybeGetConstantByTag(1);
- Mockito.verify(registry).maybeGetMemoizingCodecByTag(1);
- }
-
- @Test
public void memoizingDeserialize_codec() throws SerializationException, IOException {
Object returned = new Object();
@SuppressWarnings("unchecked")
ObjectCodec<Object> codec = Mockito.mock(ObjectCodec.class);
+ when(codec.getStrategy()).thenReturn(MemoizationStrategy.MEMOIZE_AFTER);
+ when(codec.getEncodedClass()).thenReturn(Object.class);
+ when(codec.additionalEncodedClasses()).thenReturn(ImmutableList.of());
ObjectCodecRegistry.CodecDescriptor codecDescriptor =
Mockito.mock(ObjectCodecRegistry.CodecDescriptor.class);
doReturn(codec).when(codecDescriptor).getCodec();
@@ -145,21 +127,12 @@ public class DeserializationContextTest {
when(registry.getCodecDescriptorByTag(1)).thenReturn(codecDescriptor);
CodedInputStream codedInputStream = Mockito.mock(CodedInputStream.class);
DeserializationContext deserializationContext =
- new DeserializationContext(registry, ImmutableMap.of());
+ new DeserializationContext(registry, ImmutableMap.of()).newMemoizingContext(new Object());
when(codec.deserialize(deserializationContext, codedInputStream)).thenReturn(returned);
when(codedInputStream.readSInt32()).thenReturn(1);
- assertThat(
- deserializationContext
- .getMemoizingCodecRecordedInInput(codedInputStream)
- .deserializePayload(
- deserializationContext,
- /*initial=*/ null,
- codedInputStream,
- new Memoizer.Deserializer()))
- .isEqualTo(returned);
+ assertThat((Object) deserializationContext.deserialize(codedInputStream)).isEqualTo(returned);
Mockito.verify(codedInputStream).readSInt32();
Mockito.verify(registry).maybeGetConstantByTag(1);
- Mockito.verify(registry).maybeGetMemoizingCodecByTag(1);
Mockito.verify(registry).getCodecDescriptorByTag(1);
Mockito.verify(codecDescriptor).getCodec();
Mockito.verify(codec).deserialize(deserializationContext, codedInputStream);
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodecTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodecTest.java
index 2791f0adcc..d4042fe107 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodecTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodecTest.java
@@ -15,12 +15,17 @@
package com.google.devtools.build.lib.skyframe.serialization;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester.VerificationFunction;
import com.google.devtools.build.lib.skyframe.serialization.testutils.TestUtils;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.CodedOutputStream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -51,11 +56,77 @@ public class ImmutableMapCodecTest {
@Test
public void unnaturallySortedMapComesBackUnsortedInCorrectOrder() throws Exception {
ImmutableMap<?, ?> deserialized =
- TestUtils.roundTrip(
- ImmutableSortedMap.reverseOrder().put("a", "b").put("c", "d").build(),
- ImmutableMap.of());
+ TestUtils.roundTrip(ImmutableSortedMap.reverseOrder().put("a", "b").put("c", "d").build());
assertThat(deserialized).isInstanceOf(ImmutableMap.class);
assertThat(deserialized).isNotInstanceOf(ImmutableSortedMap.class);
assertThat(deserialized).containsExactly("c", "d", "a", "b").inOrder();
}
+
+ @Test
+ public void serializingErrorIncludesKeyStringAndValueClass() {
+ SerializationException expected =
+ assertThrows(
+ SerializationException.class,
+ () ->
+ TestUtils.toBytesMemoized(
+ ImmutableMap.of("a", new Dummy()),
+ AutoRegistry.get()
+ .getBuilder()
+ .add(new DummyThrowingCodec(/*throwsOnSerialization=*/ true))
+ .build()));
+ assertThat(expected)
+ .hasMessageThat()
+ .containsMatch("Exception while serializing value of type .*\\$Dummy for key 'a'");
+ }
+
+ @Test
+ public void deserializingErrorIncludesKeyString() throws Exception {
+ ObjectCodecRegistry registry =
+ AutoRegistry.get()
+ .getBuilder()
+ .add(new DummyThrowingCodec(/*throwsOnSerialization=*/ false))
+ .build();
+ ByteString data =
+ TestUtils.toBytes(
+ new SerializationContext(registry, ImmutableMap.of()),
+ ImmutableMap.of("a", new Dummy()));
+ SerializationException expected =
+ assertThrows(
+ SerializationException.class,
+ () ->
+ TestUtils.fromBytes(new DeserializationContext(registry, ImmutableMap.of()), data));
+ assertThat(expected)
+ .hasMessageThat()
+ .contains("Exception while deserializing value for key 'a'");
+ }
+
+ private static class Dummy {}
+
+ private static class DummyThrowingCodec implements ObjectCodec<Dummy> {
+ private final boolean throwsOnSerialization;
+
+ private DummyThrowingCodec(boolean throwsOnSerialization) {
+ this.throwsOnSerialization = throwsOnSerialization;
+ }
+
+ @Override
+ public Class<Dummy> getEncodedClass() {
+ return Dummy.class;
+ }
+
+ @Override
+ public void serialize(SerializationContext context, Dummy value, CodedOutputStream codedOut)
+ throws SerializationException {
+ if (throwsOnSerialization) {
+ throw new SerializationException("Expected failure");
+ }
+ }
+
+ @Override
+ public Dummy deserialize(DeserializationContext context, CodedInputStream codedIn)
+ throws SerializationException {
+ Preconditions.checkState(!throwsOnSerialization);
+ throw new SerializationException("Expected failure");
+ }
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecRegistryTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecRegistryTest.java
index efcb760d44..71efbd714b 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecRegistryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecRegistryTest.java
@@ -35,8 +35,8 @@ public class ObjectCodecRegistryTest {
ObjectCodecRegistry underTest =
ObjectCodecRegistry.newBuilder()
.setAllowDefaultCodec(false)
- .add(String.class, codec1)
- .add(Integer.class, codec2)
+ .add(codec1)
+ .add(codec2)
.build();
CodecDescriptor fooDescriptor = underTest.getCodecDescriptor(String.class);
@@ -58,10 +58,7 @@ public class ObjectCodecRegistryTest {
SingletonCodec<String> codec = SingletonCodec.of("value1", "mnemonic1");
ObjectCodecRegistry underTest =
- ObjectCodecRegistry.newBuilder()
- .setAllowDefaultCodec(true)
- .add(String.class, codec)
- .build();
+ ObjectCodecRegistry.newBuilder().setAllowDefaultCodec(true).add(codec).build();
CodecDescriptor fooDescriptor = underTest.getCodecDescriptor(String.class);
assertThat(fooDescriptor.getCodec()).isSameAs(codec);
@@ -84,18 +81,10 @@ public class ObjectCodecRegistryTest {
SingletonCodec<Integer> codec2 = SingletonCodec.of(1, "mnemonic2");
ObjectCodecRegistry underTest1 =
- ObjectCodecRegistry.newBuilder()
- .setAllowDefaultCodec(true)
- .add(String.class, codec1)
- .add(Integer.class, codec2)
- .build();
+ ObjectCodecRegistry.newBuilder().setAllowDefaultCodec(true).add(codec1).add(codec2).build();
ObjectCodecRegistry underTest2 =
- ObjectCodecRegistry.newBuilder()
- .setAllowDefaultCodec(true)
- .add(Integer.class, codec2)
- .add(String.class, codec1)
- .build();
+ ObjectCodecRegistry.newBuilder().setAllowDefaultCodec(true).add(codec2).add(codec1).build();
assertThat(underTest1.getCodecDescriptor(String.class).getTag())
.isEqualTo(underTest2.getCodecDescriptor(String.class).getTag());
@@ -130,47 +119,22 @@ public class ObjectCodecRegistryTest {
}
@Test
- public void memoizingOrderedByClassName() {
- Memoizer.MemoizingCodec<String> memoizingCodec1 =
- new Memoizer.ObjectCodecAdaptor<>(SingletonCodec.of("value1", "mnemonic1"));
- Memoizer.MemoizingCodec<Object> memoizingCodec2 =
- new Memoizer.ObjectCodecAdaptor<>(SingletonCodec.of(new Object(), "mnemonic2"));
- ObjectCodecRegistry underTest =
- ObjectCodecRegistry.newBuilder()
- .setAllowDefaultCodec(false)
- .addMemoizing(memoizingCodec1)
- .addMemoizing(memoizingCodec2)
- .build();
-
- assertThat(underTest.getMemoizingCodecDescriptor(Object.class).getMemoizingCodec())
- .isEqualTo(memoizingCodec2);
- assertThat(underTest.getMemoizingCodecDescriptor(String.class).getMemoizingCodec())
- .isEqualTo(memoizingCodec1);
- assertThat(underTest.maybeGetMemoizingCodecByTag(1)).isEqualTo(memoizingCodec2);
- assertThat(underTest.maybeGetMemoizingCodecByTag(2)).isEqualTo(memoizingCodec1);
- }
-
- @Test
public void testGetBuilder() throws NoCodecException {
SingletonCodec<String> codec1 = SingletonCodec.of("value1", "mnemonic1");
SingletonCodec<Integer> codec2 = SingletonCodec.of(1, "mnemonic2");
Object constant = new Object();
- Memoizer.MemoizingCodec<String> memoizingCodec = new Memoizer.ObjectCodecAdaptor<>(codec1);
ObjectCodecRegistry underTest =
ObjectCodecRegistry.newBuilder()
.setAllowDefaultCodec(false)
- .add(String.class, codec1)
- .add(Integer.class, codec2)
+ .add(codec1)
+ .add(codec2)
.addConstant(constant)
- .addMemoizing(memoizingCodec)
.build();
ObjectCodecRegistry copy = underTest.getBuilder().build();
assertThat(copy.getCodecDescriptor(Integer.class).getTag()).isEqualTo(1);
assertThat(copy.getCodecDescriptor(String.class).getTag()).isEqualTo(2);
- assertThat(copy.getMemoizingCodecDescriptor(String.class).getMemoizingCodec())
- .isEqualTo(memoizingCodec);
assertThat(copy.maybeGetTagForConstant(constant)).isNotNull();
assertThrows(NoCodecException.class, () -> copy.getCodecDescriptor(Byte.class));
}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecsTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecsTest.java
index 5577087b37..66ad1db474 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/ObjectCodecsTest.java
@@ -24,12 +24,14 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.protobuf.ByteString;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
import java.io.NotSerializableException;
+import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,6 +51,13 @@ public class ObjectCodecsTest {
return Integer.class;
}
+ // We have to override the default explicitly here because Mockito can't delegate to default
+ // methods on interfaces.
+ @Override
+ public List<Class<? extends Integer>> additionalEncodedClasses() {
+ return ImmutableList.of();
+ }
+
@Override
public void serialize(SerializationContext context, Integer obj, CodedOutputStream codedOut)
throws SerializationException, IOException {
@@ -74,8 +83,7 @@ public class ObjectCodecsTest {
spyObjectCodec = spy(new IntegerCodec());
this.underTest =
new ObjectCodecs(
- ObjectCodecRegistry.newBuilder().add(Integer.class, spyObjectCodec).build(),
- ImmutableMap.of());
+ ObjectCodecRegistry.newBuilder().add(spyObjectCodec).build(), ImmutableMap.of());
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContextTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContextTest.java
index bd05444e21..bd8ed19a1d 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContextTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/SerializationContextTest.java
@@ -14,13 +14,17 @@
package com.google.devtools.build.lib.skyframe.serialization;
-import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec.MemoizationStrategy;
+import com.google.devtools.build.lib.skyframe.serialization.testutils.TestUtils;
+import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -77,8 +81,7 @@ public class SerializationContextTest {
CodedOutputStream codedOutputStream = Mockito.mock(CodedOutputStream.class);
SerializationContext serializationContext =
new SerializationContext(registry, ImmutableMap.of());
- assertThat(serializationContext.recordAndMaybeGetMemoizingCodec(null, codedOutputStream))
- .isNull();
+ serializationContext.newMemoizingContext().serialize(null, codedOutputStream);
Mockito.verify(codedOutputStream).writeSInt32NoTag(0);
Mockito.verifyZeroInteractions(registry);
}
@@ -91,57 +94,82 @@ public class SerializationContextTest {
SerializationContext serializationContext =
new SerializationContext(registry, ImmutableMap.of());
Object constant = new Object();
- assertThat(serializationContext.recordAndMaybeGetMemoizingCodec(constant, codedOutputStream))
- .isNull();
+ serializationContext.newMemoizingContext().serialize(constant, codedOutputStream);
Mockito.verify(codedOutputStream).writeSInt32NoTag(1);
Mockito.verify(registry).maybeGetTagForConstant(constant);
}
@Test
- public void memoizingSerialize_memoize() throws SerializationException, IOException {
- @SuppressWarnings("unchecked")
- Memoizer.MemoizingCodec<Object> memoizingCodec = Mockito.mock(Memoizer.MemoizingCodec.class);
- @SuppressWarnings("unchecked")
- ObjectCodecRegistry.MemoizingCodecDescriptor<Object> memoizingCodecDescriptor =
- Mockito.mock(ObjectCodecRegistry.MemoizingCodecDescriptor.class);
- when(memoizingCodecDescriptor.getTag()).thenReturn(1);
- doReturn(memoizingCodec).when(memoizingCodecDescriptor).getMemoizingCodec();
- ObjectCodecRegistry registry = Mockito.mock(ObjectCodecRegistry.class);
- when(registry.maybeGetTagForConstant(Mockito.anyObject())).thenReturn(null);
- doReturn(memoizingCodecDescriptor).when(registry).getMemoizingCodecDescriptor(String.class);
- CodedOutputStream codedOutputStream = Mockito.mock(CodedOutputStream.class);
- SerializationContext underTest = new SerializationContext(registry, ImmutableMap.of());
- assertThat(underTest.recordAndMaybeGetMemoizingCodec("string", codedOutputStream))
- .isSameAs(memoizingCodec);
- Mockito.verify(codedOutputStream).writeSInt32NoTag(1);
- Mockito.verify(registry).maybeGetTagForConstant("string");
- Mockito.verify(registry).getMemoizingCodecDescriptor(String.class);
- Mockito.verifyNoMoreInteractions(registry);
- }
-
- @Test
public void memoizingSerialize_descriptor() throws SerializationException, IOException {
@SuppressWarnings("unchecked")
ObjectCodec<Object> codec = Mockito.mock(ObjectCodec.class);
+ when(codec.getStrategy()).thenReturn(MemoizationStrategy.MEMOIZE_AFTER);
ObjectCodecRegistry.CodecDescriptor codecDescriptor =
Mockito.mock(ObjectCodecRegistry.CodecDescriptor.class);
when(codecDescriptor.getTag()).thenReturn(1);
doReturn(codec).when(codecDescriptor).getCodec();
ObjectCodecRegistry registry = Mockito.mock(ObjectCodecRegistry.class);
when(registry.maybeGetTagForConstant(Mockito.anyObject())).thenReturn(null);
- when(registry.getMemoizingCodecDescriptor(Mockito.anyObject())).thenReturn(null);
when(registry.getCodecDescriptor(String.class)).thenReturn(codecDescriptor);
CodedOutputStream codedOutputStream = Mockito.mock(CodedOutputStream.class);
- SerializationContext underTest = new SerializationContext(registry, ImmutableMap.of());
- underTest
- .recordAndMaybeGetMemoizingCodec("string", codedOutputStream)
- .serializePayload(underTest, "string", codedOutputStream, null);
+ SerializationContext underTest =
+ new SerializationContext(registry, ImmutableMap.of()).newMemoizingContext();
+ underTest.serialize("string", codedOutputStream);
Mockito.verify(codedOutputStream).writeSInt32NoTag(1);
Mockito.verify(registry).maybeGetTagForConstant("string");
- Mockito.verify(registry).getMemoizingCodecDescriptor(String.class);
Mockito.verify(registry).getCodecDescriptor(String.class);
Mockito.verify(codecDescriptor).getTag();
Mockito.verify(codecDescriptor).getCodec();
Mockito.verify(codec).serialize(underTest, "string", codedOutputStream);
}
+
+ @Test
+ public void mismatchMemoizingRoundtrip() {
+ ArrayList<Object> repeatedObject = new ArrayList<>();
+ repeatedObject.add(null);
+ repeatedObject.add(null);
+ ArrayList<Object> container = new ArrayList<>();
+ container.add(repeatedObject);
+ ArrayList<Object> toSerialize = new ArrayList<>();
+ toSerialize.add(repeatedObject);
+ toSerialize.add(container);
+ assertThrows(
+ SerializationException.class,
+ () ->
+ TestUtils.roundTripMemoized(
+ toSerialize,
+ ObjectCodecRegistry.newBuilder()
+ .add(new BadCodecOnlyMemoizesWhenDeserializing())
+ .build()));
+ }
+
+ private static class BadCodecOnlyMemoizesWhenDeserializing implements ObjectCodec<ArrayList<?>> {
+ @SuppressWarnings("unchecked")
+ @Override
+ public Class<ArrayList<?>> getEncodedClass() {
+ return (Class<ArrayList<?>>) (Class<?>) ArrayList.class;
+ }
+
+ @Override
+ public void serialize(
+ SerializationContext context, ArrayList<?> obj, CodedOutputStream codedOut)
+ throws SerializationException, IOException {
+ codedOut.writeInt32NoTag(obj.size());
+ for (Object item : obj) {
+ context.serialize(item, codedOut);
+ }
+ }
+
+ @Override
+ public ArrayList<?> deserialize(DeserializationContext context, CodedInputStream codedIn)
+ throws SerializationException, IOException {
+ context = context.newMemoizingContext(new Object());
+ int size = codedIn.readInt32();
+ ArrayList<?> result = new ArrayList<>();
+ for (int i = 0; i < size; i++) {
+ result.add(context.deserialize(codedIn));
+ }
+ return result;
+ }
+ }
}