diff --git a/core/src/test/java/google/registry/model/ImmutableObjectSubject.java b/core/src/test/java/google/registry/model/ImmutableObjectSubject.java new file mode 100644 index 000000000..c3fc5bd03 --- /dev/null +++ b/core/src/test/java/google/registry/model/ImmutableObjectSubject.java @@ -0,0 +1,95 @@ +// Copyright 2020 The Nomulus 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 google.registry.model; + +import static com.google.common.truth.Truth.assertAbout; +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableSet; +import com.google.common.truth.Correspondence; +import com.google.common.truth.Correspondence.BinaryPredicate; +import com.google.common.truth.FailureMetadata; +import com.google.common.truth.SimpleSubjectBuilder; +import com.google.common.truth.Subject; +import java.lang.reflect.Field; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; +import javax.annotation.Nullable; + +/** Truth subject for asserting things about ImmutableObjects that are not built in. */ +public final class ImmutableObjectSubject extends Subject { + + private final ImmutableObject actual; + + protected ImmutableObjectSubject(FailureMetadata failureMetadata, ImmutableObject actual) { + super(failureMetadata, actual); + this.actual = actual; + } + + public void isEqualExceptFields(ImmutableObject expected, String... ignoredFields) { + Map actualFields = filterFields(actual, ignoredFields); + Map expectedFields = filterFields(expected, ignoredFields); + assertThat(actualFields).containsExactlyEntriesIn(expectedFields); + } + + public static Correspondence immutableObjectCorrespondence( + String... ignoredFields) { + return Correspondence.from( + new ImmutableObjectBinaryPredicate(ignoredFields), "has all relevant fields equal to"); + } + + public static SimpleSubjectBuilder + assertAboutImmutableObjects() { + return assertAbout(ImmutableObjectSubject::new); + } + + private static class ImmutableObjectBinaryPredicate + implements BinaryPredicate { + + private final String[] ignoredFields; + + private ImmutableObjectBinaryPredicate(String... ignoredFields) { + this.ignoredFields = ignoredFields; + } + + @Override + public boolean apply(@Nullable ImmutableObject actual, @Nullable ImmutableObject expected) { + if (actual == null && expected == null) { + return true; + } + if (actual == null || expected == null) { + return false; + } + Map actualFields = filterFields(actual, ignoredFields); + Map expectedFields = filterFields(expected, ignoredFields); + return Objects.equals(actualFields, expectedFields); + } + } + + private static Map filterFields( + ImmutableObject original, String... ignoredFields) { + ImmutableSet ignoredFieldSet = ImmutableSet.copyOf(ignoredFields); + Map originalFields = ModelUtils.getFieldValues(original); + // don't use ImmutableMap or a stream->collect model since we can have nulls + Map result = new LinkedHashMap<>(); + for (Map.Entry entry : originalFields.entrySet()) { + if (!ignoredFieldSet.contains(entry.getKey().getName())) { + result.put(entry.getKey(), entry.getValue()); + } + } + return result; + } +} diff --git a/core/src/test/java/google/registry/model/history/HostHistoryTest.java b/core/src/test/java/google/registry/model/history/HostHistoryTest.java index df6e268e5..3ded202a3 100644 --- a/core/src/test/java/google/registry/model/history/HostHistoryTest.java +++ b/core/src/test/java/google/registry/model/history/HostHistoryTest.java @@ -14,7 +14,7 @@ package google.registry.model.history; -import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects; import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; import static google.registry.testing.SqlHelper.saveRegistrar; import static java.nio.charset.StandardCharsets.UTF_8; @@ -74,14 +74,9 @@ public class HostHistoryTest extends EntityTestCase { } private void assertHostHistoriesEqual(HostHistory one, HostHistory two) { - // enough of the fields get changed during serialization that we can't depend on .equals() - assertThat(one.getClientId()).isEqualTo(two.getClientId()); - assertThat(one.getHostRepoId()).isEqualTo(two.getHostRepoId()); - assertThat(one.getBySuperuser()).isEqualTo(two.getBySuperuser()); - assertThat(one.getRequestedByRegistrar()).isEqualTo(two.getRequestedByRegistrar()); - assertThat(one.getReason()).isEqualTo(two.getReason()); - assertThat(one.getTrid()).isEqualTo(two.getTrid()); - assertThat(one.getType()).isEqualTo(two.getType()); - assertThat(one.getHostBase().getHostName()).isEqualTo(two.getHostBase().getHostName()); + assertAboutImmutableObjects().that(one).isEqualExceptFields(two, "hostBase"); + assertAboutImmutableObjects() + .that(one.getHostBase()) + .isEqualExceptFields(two.getHostBase(), "repoId"); } }