aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/AbstractObjectCodecTest.java45
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/ObjectCodecTester.java172
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/FastStringCodecTest.java52
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/StringCodecTest.java12
4 files changed, 219 insertions, 62 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/AbstractObjectCodecTest.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/AbstractObjectCodecTest.java
index 117f4d8bac..08f675c5dd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/AbstractObjectCodecTest.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/AbstractObjectCodecTest.java
@@ -15,30 +15,25 @@
package com.google.devtools.build.lib.skyframe.serialization.testutils;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
-import com.google.protobuf.CodedInputStream;
import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
-/** Common ObjectCodec tests. */
+/**
+ * Base class for {@link ObjectCodec} tests. This is a slim wrapper around {@link ObjectCodecTester}
+ * and exists mostly to support existing tests.
+ */
public abstract class AbstractObjectCodecTest<T> {
@Nullable protected ObjectCodec<T> underTest;
@Nullable protected ImmutableList<T> subjects;
-
- /**
- * Override to false to skip testDeserializeBadDataThrowsSerializationException(). Codecs that
- * cannot distinguish good and bad data should do this.
- */
- protected boolean shouldTestDeserializeBadData = true;
+ private ObjectCodecTester<T> objectCodecTester;
/** Construct with the given codec and subjects. */
protected AbstractObjectCodecTest(
@@ -57,41 +52,29 @@ public abstract class AbstractObjectCodecTest<T> {
protected AbstractObjectCodecTest() {}
@Before
- public void checkInitialized() {
+ public void initialize() {
Preconditions.checkNotNull(underTest);
Preconditions.checkNotNull(subjects);
+ objectCodecTester = ObjectCodecTester.newBuilder(underTest)
+ .verificationFunction(
+ (original, deserialized) -> this.verifyDeserialization(deserialized, original))
+ .addSubjects(subjects)
+ .build();
}
@Test
public void testSuccessfulSerializationDeserialization() throws Exception {
- for (T subject : subjects) {
- byte[] serialized = toBytes(subject);
- Object deserialized = fromBytes(serialized);
- verifyDeserialization(deserialized, subject);
- }
+ objectCodecTester.testSerializeDeserialize();
}
@Test
public void testSerializationRoundTripBytes() throws Exception {
- for (T subject : subjects) {
- byte[] serialized = toBytes(subject);
- T deserialized = fromBytes(serialized);
- byte[] reserialized = toBytes(deserialized);
- assertThat(reserialized).isEqualTo(serialized);
- }
+ objectCodecTester.testStableSerialization();
}
@Test
public void testDeserializeBadDataThrowsSerializationException() {
- if (!shouldTestDeserializeBadData) {
- return;
- }
- try {
- underTest.deserialize(CodedInputStream.newInstance("junk".getBytes(StandardCharsets.UTF_8)));
- fail("Expected exception");
- } catch (SerializationException | IOException e) {
- // Expected.
- }
+ objectCodecTester.testDeserializeJunkData();
}
protected T fromBytes(byte[] bytes) throws SerializationException, IOException {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/ObjectCodecTester.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/ObjectCodecTester.java
new file mode 100644
index 0000000000..1f370f68de
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils/ObjectCodecTester.java
@@ -0,0 +1,172 @@
+// Copyright 2017 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.testutils;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.skyframe.serialization.ObjectCodec;
+import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
+import com.google.protobuf.CodedInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/** Utility for testing {@link ObjectCodec} instances. */
+public class ObjectCodecTester<T> {
+
+ /** Interface for testing successful deserialization of an object. */
+ @FunctionalInterface
+ public interface VerificationFunction<T> {
+ /**
+ * Verify whether or not the original object was sufficiently serialized/deserialized. Typically
+ * this will be some sort of assertion.
+ *
+ * @throws Exception on verification failure
+ */
+ void verifyDeserialized(T original, Object deserialized) throws Exception;
+ }
+
+ /**
+ * Create an {@link ObjectCodecTester.Builder} for the supplied instance. See
+ * {@link ObjectCodecTester.Builder} for details.
+ */
+ public static <T> ObjectCodecTester.Builder<T> newBuilder(ObjectCodec<T> toTest) {
+ return new ObjectCodecTester.Builder<>(toTest);
+ }
+
+ private final ObjectCodec<T> underTest;
+ private final ImmutableList<T> subjects;
+ private final boolean skipBadDataTest;
+ private final VerificationFunction<T> verificationFunction;
+
+ private ObjectCodecTester(
+ ObjectCodec<T> underTest,
+ ImmutableList<T> subjects,
+ boolean skipBadDataTest,
+ VerificationFunction<T> verificationFunction) {
+ this.underTest = underTest;
+ Preconditions.checkState(!subjects.isEmpty(), "No subjects provided");
+ this.subjects = subjects;
+ this.skipBadDataTest = skipBadDataTest;
+ this.verificationFunction = verificationFunction;
+ }
+
+ private void runTests() throws Exception {
+ testSerializeDeserialize();
+ testStableSerialization();
+ if (!skipBadDataTest) {
+ testDeserializeJunkData();
+ }
+ }
+
+ /** Runs serialization/deserialization tests. */
+ void testSerializeDeserialize() throws Exception {
+ for (T subject : subjects) {
+ byte[] serialized = toBytes(subject);
+ Object deserialized = fromBytes(serialized);
+ verificationFunction.verifyDeserialized(subject, deserialized);
+ }
+ }
+
+ /** Runs serialized bytes stability tests. */
+ void testStableSerialization() throws Exception {
+ for (T subject : subjects) {
+ byte[] serialized = toBytes(subject);
+ T deserialized = fromBytes(serialized);
+ byte[] reserialized = toBytes(deserialized);
+ assertThat(reserialized).isEqualTo(serialized);
+ }
+ }
+
+ /** Runs junk-data recognition tests. */
+ void testDeserializeJunkData() {
+ try {
+ underTest.deserialize(CodedInputStream.newInstance("junk".getBytes(StandardCharsets.UTF_8)));
+ fail("Expected exception");
+ } catch (SerializationException | IOException e) {
+ // Expected.
+ }
+ }
+
+ private T fromBytes(byte[] bytes) throws SerializationException, IOException {
+ return TestUtils.fromBytes(underTest, bytes);
+ }
+
+ private byte[] toBytes(T subject) throws IOException, SerializationException {
+ return TestUtils.toBytes(underTest, subject);
+ }
+
+ /** Builder for {@link ObjectCodecTester}. */
+ public static class Builder<T> {
+ private final ObjectCodec<T> underTest;
+ private final ImmutableList.Builder<T> subjectsBuilder = ImmutableList.builder();
+ private boolean skipBadDataTest = false;
+ private VerificationFunction<T> verificationFunction =
+ (original, deserialized) -> assertThat(deserialized).isEqualTo(original);
+
+ private Builder(ObjectCodec<T> underTest) {
+ this.underTest = underTest;
+ }
+
+ /** Add subjects to be tested for serialization/deserialization. */
+ public Builder<T> addSubjects(@SuppressWarnings("unchecked") T... subjects) {
+ return addSubjects(ImmutableList.copyOf(subjects));
+ }
+
+ /** Add subjects to be tested for serialization/deserialization. */
+ Builder<T> addSubjects(ImmutableList<T> subjects) {
+ subjectsBuilder.addAll(subjects);
+ return this;
+ }
+
+ /**
+ * Skip tests that check for the ability to detect bad data. This may be useful for simpler
+ * codecs which don't do any error verification.
+ */
+ public Builder<T> skipBadDataTest() {
+ this.skipBadDataTest = true;
+ return this;
+ }
+
+ /**
+ * Sets {@link ObjectCodecTester.VerificationFunction} for verifying deserialization. Default
+ * is simple equality assertion, a custom version may be provided for more, or less, detailed
+ * checks.
+ */
+ public Builder<T> verificationFunction(VerificationFunction<T> verificationFunction) {
+ this.verificationFunction = Preconditions.checkNotNull(verificationFunction);
+ return this;
+ }
+
+ /** Captures the state of this builder and run all associated tests. */
+ public void buildAndRunTests() throws Exception {
+ build().runTests();
+ }
+
+ /**
+ * Creates a new {@link ObjectCodecTester} from this builder. Exposed to allow running tests
+ * individually.
+ */
+ ObjectCodecTester<T> build() {
+ return new ObjectCodecTester<>(
+ underTest,
+ subjectsBuilder.build(),
+ skipBadDataTest,
+ verificationFunction);
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/FastStringCodecTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/FastStringCodecTest.java
index 30b9a1ded2..c0ae7d02ee 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/FastStringCodecTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/FastStringCodecTest.java
@@ -15,41 +15,39 @@
package com.google.devtools.build.lib.skyframe.serialization.strings;
import com.google.common.testing.EqualsTester;
-import com.google.devtools.build.lib.skyframe.serialization.testutils.AbstractObjectCodecTest;
+import com.google.devtools.build.lib.skyframe.serialization.testutils.ObjectCodecTester;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link FastStringCodec}. */
@RunWith(JUnit4.class)
-public class FastStringCodecTest extends AbstractObjectCodecTest<String> {
+public class FastStringCodecTest {
- public FastStringCodecTest() {
- super(
- // TODO(michajlo): Don't bother running this test if FastStringCodec isn't available.
- FastStringCodec.isAvailable() ? new FastStringCodec() : new StringCodec(),
- "ow now brown cow. ow now brown cow",
- "(╯°□°)╯︵┻━┻ string with utf8/ascii",
- "string with ascii/utf8 (╯°□°)╯︵┻━┻",
- "last character utf8 ╯",
- "last char only non-ascii ƒ",
- "ƒ",
- "╯",
- "",
- Character.toString((char) 0xc3));;
- }
-
- // hashCode is stored in String. Because we're using Unsafe to bypass standard String
- // constructors, make sure it still works.
@Test
- public void testEqualsAndHashCodePreserved() throws Exception {
- String original1 = "hello world";
- String original2 = "dlrow olleh";
+ public void testCodec() throws Exception {
+ if (!FastStringCodec.isAvailable()) {
+ // Not available on this platform, skip test.
+ return;
+ }
- // Equals tester tests equals and hash code.
- new EqualsTester()
- .addEqualityGroup(original1, fromBytes(toBytes(original1)))
- .addEqualityGroup(original2, fromBytes(toBytes(original2)))
- .testEquals();
+ ObjectCodecTester.newBuilder(new FastStringCodec())
+ .verificationFunction(
+ (original, deserialized) -> {
+ // hashCode is stored in String. Because we're using Unsafe to bypass standard String
+ // constructors, make sure it still works.
+ new EqualsTester().addEqualityGroup(original, deserialized).testEquals();
+ })
+ .addSubjects(
+ "ow now brown cow. ow now brown cow",
+ "(╯°□°)╯︵┻━┻ string with utf8/ascii",
+ "string with ascii/utf8 (╯°□°)╯︵┻━┻",
+ "last character utf8 ╯",
+ "last char only non-ascii ƒ",
+ "ƒ",
+ "╯",
+ "",
+ Character.toString((char) 0xc3))
+ .buildAndRunTests();
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/StringCodecTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/StringCodecTest.java
index c1b6f5dbe3..8e8b80ea0b 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/StringCodecTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/serialization/strings/StringCodecTest.java
@@ -14,15 +14,19 @@
package com.google.devtools.build.lib.skyframe.serialization.strings;
-import com.google.devtools.build.lib.skyframe.serialization.testutils.AbstractObjectCodecTest;
+import com.google.devtools.build.lib.skyframe.serialization.testutils.ObjectCodecTester;
+import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Basic tests for {@link StringCodec}. */
@RunWith(JUnit4.class)
-public class StringCodecTest extends AbstractObjectCodecTest<String> {
+public class StringCodecTest {
- public StringCodecTest() {
- super(new StringCodec(), "usually precomputed and supports weird unicodes: (╯°□°)╯︵┻━┻ ");
+ @Test
+ public void testCodec() throws Exception {
+ ObjectCodecTester.newBuilder(new StringCodec())
+ .addSubjects("usually precomputed and supports weird unicodes: (╯°□°)╯︵┻━┻ ")
+ .buildAndRunTests();
}
}