| // 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.devtools.build.lib.skyframe.serialization.ObjectCodecRegistry.CodecDescriptor; |
| import com.google.devtools.build.lib.skyframe.serialization.SerializationException.NoCodecException; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for {@link ObjectCodecRegistry}. */ |
| @RunWith(JUnit4.class) |
| public class ObjectCodecRegistryTest { |
| |
| @Test |
| public void testDescriptorLookups() throws NoCodecException { |
| SingletonCodec<String> codec1 = SingletonCodec.of("value1", "mnemonic1"); |
| SingletonCodec<Integer> codec2 = SingletonCodec.of(1, "mnemonic2"); |
| |
| ObjectCodecRegistry underTest = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(false) |
| .add(codec1) |
| .add(codec2) |
| .build(); |
| |
| CodecDescriptor fooDescriptor = underTest.getCodecDescriptorForObject("hello"); |
| assertThat(fooDescriptor.getCodec()).isSameInstanceAs(codec1); |
| assertThat(underTest.getCodecDescriptorByTag(fooDescriptor.getTag())) |
| .isSameInstanceAs(fooDescriptor); |
| |
| CodecDescriptor barDescriptor = underTest.getCodecDescriptorForObject(1); |
| assertThat(barDescriptor.getCodec()).isSameInstanceAs(codec2); |
| assertThat(underTest.getCodecDescriptorByTag(barDescriptor.getTag())) |
| .isSameInstanceAs(barDescriptor); |
| |
| assertThat(barDescriptor.getTag()).isNotEqualTo(fooDescriptor.getTag()); |
| |
| assertThrows(NoCodecException.class, () -> underTest.getCodecDescriptorForObject((byte) 1)); |
| assertThrows(NoCodecException.class, () -> underTest.getCodecDescriptorByTag(42)); |
| } |
| |
| @Test |
| public void testDefaultCodecFallback() throws NoCodecException { |
| SingletonCodec<String> codec = SingletonCodec.of("value1", "mnemonic1"); |
| |
| ObjectCodecRegistry underTest = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(true) |
| .add(codec) |
| .addClassName(Byte.class.getName()) |
| .addClassName(Integer.class.getName()) |
| .build(); |
| |
| CodecDescriptor fooDescriptor = underTest.getCodecDescriptorForObject("value1"); |
| assertThat(fooDescriptor.getCodec()).isSameInstanceAs(codec); |
| |
| CodecDescriptor barDefaultDescriptor = underTest.getCodecDescriptorForObject(15); |
| assertThat(barDefaultDescriptor.getCodec()).isNotSameInstanceAs(codec); |
| assertThat(barDefaultDescriptor.getTag()).isNotEqualTo(fooDescriptor.getTag()); |
| assertThat(underTest.getCodecDescriptorByTag(barDefaultDescriptor.getTag())) |
| .isSameInstanceAs(barDefaultDescriptor); |
| |
| assertThat(underTest.getCodecDescriptorForObject((byte) 9).getCodec().getClass()) |
| .isSameInstanceAs(barDefaultDescriptor.getCodec().getClass()); |
| |
| // Bogus tags still throw. |
| assertThrows(NoCodecException.class, () -> underTest.getCodecDescriptorByTag(42)); |
| } |
| |
| @Test |
| public void testStableTagOrdering() throws NoCodecException { |
| SingletonCodec<String> codec1 = SingletonCodec.of("value1", "mnemonic1"); |
| SingletonCodec<Integer> codec2 = SingletonCodec.of(1, "mnemonic2"); |
| |
| ObjectCodecRegistry underTest1 = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(true) |
| .add(codec1) |
| .add(codec2) |
| .addClassName(Byte.class.getName()) |
| .build(); |
| |
| ObjectCodecRegistry underTest2 = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(true) |
| .add(codec2) |
| .add(codec1) |
| .addClassName(Byte.class.getName()) |
| .build(); |
| |
| assertThat(underTest1.getCodecDescriptorForObject("value1").getTag()) |
| .isEqualTo(underTest2.getCodecDescriptorForObject("value1").getTag()); |
| assertThat(underTest1.getCodecDescriptorForObject(5).getTag()) |
| .isEqualTo(underTest2.getCodecDescriptorForObject(5).getTag()); |
| // Default codec. |
| assertThat(underTest1.getCodecDescriptorForObject((byte) 10).getTag()) |
| .isEqualTo(underTest2.getCodecDescriptorForObject((byte) 10).getTag()); |
| } |
| |
| @Test |
| public void constantsOrderedByLastOccurrenceInIteration() { |
| Object constant1 = new Object(); |
| Object constant2 = new Object(); |
| ObjectCodecRegistry underTest1 = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(false) |
| .addReferenceConstant(constant1) |
| .addReferenceConstant(constant2) |
| .addReferenceConstant(constant1) |
| .build(); |
| ObjectCodecRegistry underTest2 = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(false) |
| .addReferenceConstant(constant1) |
| .addReferenceConstant(constant2) |
| .build(); |
| assertThat(underTest1.maybeGetTagForConstant(constant1)).isEqualTo(3); |
| assertThat(underTest1.maybeGetTagForConstant(constant2)).isEqualTo(2); |
| assertThat(underTest2.maybeGetTagForConstant(constant1)).isEqualTo(1); |
| assertThat(underTest2.maybeGetTagForConstant(constant2)).isEqualTo(2); |
| } |
| |
| private static ObjectCodecRegistry.Builder builderWithThisClass() { |
| return ObjectCodecRegistry.newBuilder().addClassName(ObjectCodecRegistryTest.class.getName()); |
| } |
| |
| @Test |
| public void blacklistingPrefix() throws NoCodecException { |
| ObjectCodecRegistry underTest = builderWithThisClass().build(); |
| CodecDescriptor descriptor = underTest.getCodecDescriptorForObject(this); |
| assertThat(descriptor).isNotNull(); |
| assertThat(descriptor.getCodec()).isInstanceOf(DynamicCodec.class); |
| ObjectCodecRegistry underTestWithBlacklist = |
| builderWithThisClass() |
| .blacklistClassNamePrefix(this.getClass().getPackage().getName()) |
| .build(); |
| assertThrows( |
| NoCodecException.class, () -> underTestWithBlacklist.getCodecDescriptorForObject(this)); |
| ObjectCodecRegistry underTestWithWideBlacklist = |
| builderWithThisClass().blacklistClassNamePrefix("com").build(); |
| assertThrows( |
| NoCodecException.class, () -> underTestWithWideBlacklist.getCodecDescriptorForObject(this)); |
| } |
| |
| @Test |
| public void testGetBuilder() throws NoCodecException { |
| SingletonCodec<String> codec1 = SingletonCodec.of("value1", "mnemonic1"); |
| SingletonCodec<Integer> codec2 = SingletonCodec.of(1, "mnemonic2"); |
| Object constant = new Object(); |
| |
| ObjectCodecRegistry underTest = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(false) |
| .add(codec1) |
| .add(codec2) |
| .addReferenceConstant(constant) |
| .build(); |
| |
| ObjectCodecRegistry copy = underTest.getBuilder().build(); |
| assertThat(copy.getCodecDescriptorForObject(12).getTag()).isEqualTo(1); |
| assertThat(copy.getCodecDescriptorForObject("value1").getTag()).isEqualTo(2); |
| assertThat(copy.maybeGetTagForConstant(constant)).isNotNull(); |
| assertThrows(NoCodecException.class, () -> copy.getCodecDescriptorForObject((byte) 5)); |
| } |
| |
| private enum TestEnum { |
| ONE { |
| @Override |
| public int val() { |
| return 1; |
| } |
| }, |
| TWO { |
| @Override |
| public int val() { |
| return 2; |
| } |
| }, |
| THREE { |
| @Override |
| public int val() { |
| return 3; |
| } |
| }; |
| |
| public abstract int val(); |
| } |
| |
| @SuppressWarnings("GetClassOnEnum") |
| @Test |
| public void testDefaultEnum() throws NoCodecException { |
| assertThat(TestEnum.ONE.getClass()).isNotEqualTo(TestEnum.class); |
| assertThat(TestEnum.ONE.getDeclaringClass()).isEqualTo(TestEnum.class); |
| assertThat(TestEnum.ONE.getClass()).isNotEqualTo(TestEnum.TWO.getClass()); |
| |
| ObjectCodecRegistry underTest = |
| ObjectCodecRegistry.newBuilder() |
| .setAllowDefaultCodec(true) |
| .addClassName(TestEnum.class.getName()) |
| .addClassName(TestEnum.ONE.getClass().getName()) |
| .addClassName(TestEnum.TWO.getClass().getName()) |
| .addClassName(TestEnum.THREE.getClass().getName()) |
| .build(); |
| |
| CodecDescriptor oneDescriptor = underTest.getCodecDescriptorForObject(TestEnum.ONE); |
| CodecDescriptor twoDescriptor = underTest.getCodecDescriptorForObject(TestEnum.TWO); |
| assertThat(oneDescriptor).isEqualTo(twoDescriptor); |
| |
| assertThat(oneDescriptor.getCodec().getEncodedClass()).isEqualTo(TestEnum.class); |
| } |
| } |