| // Copyright 2018 The Bazel Authors. All rights reserved. |
| // |
| // 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.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; |
| |
| /** Tests for {@link ImmutableMapCodec}. */ |
| @RunWith(JUnit4.class) |
| public class ImmutableMapCodecTest { |
| @Test |
| public void smoke() throws Exception { |
| new SerializationTester( |
| ImmutableMap.of(), |
| ImmutableMap.of("A", "//foo:A"), |
| ImmutableMap.of("B", "//foo:B"), |
| ImmutableSortedMap.of(), |
| ImmutableSortedMap.of("A", "//foo:A"), |
| ImmutableSortedMap.of("B", "//foo:B"), |
| ImmutableSortedMap.reverseOrder().put("a", "b").put("c", "d").build()) |
| // Check for order. |
| .setVerificationFunction( |
| (VerificationFunction<ImmutableMap<?, ?>>) |
| (deserialized, subject) -> { |
| assertThat(deserialized).isEqualTo(subject); |
| assertThat(deserialized).containsExactlyEntriesIn(subject).inOrder(); |
| }) |
| .runTests(); |
| } |
| |
| @Test |
| public void unnaturallySortedMapComesBackUnsortedInCorrectOrder() throws Exception { |
| ImmutableMap<?, ?> deserialized = |
| 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"); |
| } |
| } |
| } |