From 3e5a9bb7a258de77e5ca5dc46e3c730317f8b894 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Fri, 17 Feb 2023 17:39:12 +0100 Subject: feat: type inference for class hierarchies --- .../translator/typehierarchy/InferredTypeTest.java | 32 ++++ .../TypeAnalyzerExampleHierarchyTest.java | 203 +++++++++++++++++++++ .../translator/typehierarchy/TypeAnalyzerTest.java | 200 ++++++++++++++++++++ .../typehierarchy/TypeAnalyzerTester.java | 51 ++++++ 4 files changed, 486 insertions(+) create mode 100644 subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/InferredTypeTest.java create mode 100644 subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java create mode 100644 subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java create mode 100644 subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTester.java (limited to 'subprojects/store/src/test') diff --git a/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/InferredTypeTest.java b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/InferredTypeTest.java new file mode 100644 index 00000000..9efa76ef --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/InferredTypeTest.java @@ -0,0 +1,32 @@ +package tools.refinery.store.partial.translator.typehierarchy; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.partial.representation.PartialRelation; + +import java.util.Set; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +class InferredTypeTest { + private final PartialRelation c1 = new PartialRelation("C1", 1); + private final PartialRelation c2 = new PartialRelation("C2", 1); + + @Test + void untypedIsConsistentTest() { + var sut = new InferredType(Set.of(), Set.of(c1, c2), null); + assertThat(sut.isConsistent(), is(true)); + } + + @Test + void typedIsConsistentTest() { + var sut = new InferredType(Set.of(c1), Set.of(c1, c2), c1); + assertThat(sut.isConsistent(), is(true)); + } + + @Test + void typedIsInconsistentTest() { + var sut = new InferredType(Set.of(c1), Set.of(), null); + assertThat(sut.isConsistent(), is(false)); + } +} diff --git a/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java new file mode 100644 index 00000000..5f528328 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java @@ -0,0 +1,203 @@ +package tools.refinery.store.partial.translator.typehierarchy; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tools.refinery.store.partial.representation.PartialRelation; +import tools.refinery.store.representation.TruthValue; + +import java.util.LinkedHashMap; +import java.util.Set; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertAll; + +class TypeAnalyzerExampleHierarchyTest { + private final PartialRelation a1 = new PartialRelation("A1", 1); + private final PartialRelation a2 = new PartialRelation("A2", 1); + private final PartialRelation a3 = new PartialRelation("A3", 1); + private final PartialRelation a4 = new PartialRelation("A4", 1); + private final PartialRelation a5 = new PartialRelation("A5", 1); + private final PartialRelation c1 = new PartialRelation("C1", 1); + private final PartialRelation c2 = new PartialRelation("C2", 1); + private final PartialRelation c3 = new PartialRelation("C3", 1); + private final PartialRelation c4 = new PartialRelation("C4", 1); + + private TypeAnalyzer sut; + private TypeAnalyzerTester tester; + + @BeforeEach + void beforeEach() { + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(a1, TypeInfo.builder().abstractType().build()); + typeInfoMap.put(a2, TypeInfo.builder().abstractType().build()); + typeInfoMap.put(a3, TypeInfo.builder().abstractType().build()); + typeInfoMap.put(a4, TypeInfo.builder().abstractType().build()); + typeInfoMap.put(a5, TypeInfo.builder().abstractType().build()); + typeInfoMap.put(c1, TypeInfo.builder().supertypes(a1, a4).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertypes(a1, a2, a3, a4).build()); + typeInfoMap.put(c3, TypeInfo.builder().supertype(a3).build()); + typeInfoMap.put(c4, TypeInfo.builder().supertype(a4).build()); + sut = new TypeAnalyzer(typeInfoMap); + tester = new TypeAnalyzerTester(sut); + } + + @Test + void analysisResultsTest() { + assertAll( + () -> tester.assertAbstractType(a1, c1, c2), + () -> tester.assertEliminatedType(a2, c2), + () -> tester.assertAbstractType(a3, c2, c3), + () -> tester.assertAbstractType(a4, c1, c2, c4), + () -> tester.assertVacuousType(a5), + () -> tester.assertConcreteType(c1), + () -> tester.assertConcreteType(c2), + () -> tester.assertConcreteType(c3), + () -> tester.assertConcreteType(c4) + ); + } + + @Test + void inferredTypesTest() { + assertAll( + () -> assertThat(sut.getUnknownType(), is(new InferredType(Set.of(), Set.of(c1, c2, c3, c4), null))), + () -> assertThat(tester.getInferredType(a1), is(new InferredType(Set.of(a1, a4), Set.of(c1, c2), c1))), + () -> assertThat(tester.getInferredType(a3), is(new InferredType(Set.of(a3), Set.of(c2, c3), c2))), + () -> assertThat(tester.getInferredType(a4), is(new InferredType(Set.of(a4), Set.of(c1, c2, c4), c1))), + () -> assertThat(tester.getInferredType(a5), is(new InferredType(Set.of(a5), Set.of(), null))), + () -> assertThat(tester.getInferredType(c1), is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), + () -> assertThat(tester.getInferredType(c2), + is(new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2))), + () -> assertThat(tester.getInferredType(c3), is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), + () -> assertThat(tester.getInferredType(c4), is(new InferredType(Set.of(a4, c4), Set.of(c4), c4))) + ); + } + + @Test + void consistentMustTest() { + var a1Result = tester.getPreservedType(a1); + var a3Result = tester.getPreservedType(a3); + var expected = new InferredType(Set.of(a1, a3, a4, c2), Set.of(c2), c2); + assertAll( + () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.TRUE), is(expected)), + () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), is(expected)), + () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a1Result.asInferredType())), + () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(a3Result.asInferredType())), + () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.TRUE), + is(a1Result.asInferredType())) + ); + } + + @Test + void consistentMayNotTest() { + var a1Result = tester.getPreservedType(a1); + var a3Result = tester.getPreservedType(a3); + var a4Result = tester.getPreservedType(a4); + assertAll( + () -> assertThat(a1Result.merge(a3Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), + () -> assertThat(a3Result.merge(a1Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a1, a4, c1), Set.of(c1), c1))), + () -> assertThat(a4Result.merge(a3Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a3, c3), Set.of(c3), c3))), + () -> assertThat(a3Result.merge(a4Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a4), Set.of(c1, c4), c1))), + () -> assertThat(a1Result.merge(sut.getUnknownType(), TruthValue.FALSE), + is(new InferredType(Set.of(), Set.of(c3, c4), null))), + () -> assertThat(a3Result.merge(sut.getUnknownType(), TruthValue.FALSE), + is(new InferredType(Set.of(), Set.of(c1, c4), null))), + () -> assertThat(a4Result.merge(sut.getUnknownType(), TruthValue.FALSE), + is(new InferredType(Set.of(), Set.of(c3), null))) + ); + } + + @Test + void consistentErrorTest() { + var c1Result = tester.getPreservedType(c1); + var a4Result = tester.getPreservedType(a4); + var expected = new InferredType(Set.of(c1, a1, a4), Set.of(), null); + assertAll( + () -> assertThat(c1Result.merge(a4Result.asInferredType(), TruthValue.ERROR), is(expected)), + () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.ERROR), is(expected)) + ); + } + + @Test + void consistentUnknownTest() { + var c1Result = tester.getPreservedType(c1); + var a4Result = tester.getPreservedType(a4); + assertAll( + () -> assertThat(c1Result.merge(a4Result.asInferredType(), TruthValue.UNKNOWN), + is(a4Result.asInferredType())), + () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.UNKNOWN), + is(c1Result.asInferredType())) + ); + } + + @Test + void inconsistentMustTest() { + var a1Result = tester.getPreservedType(a1); + var c3Result = tester.getPreservedType(c3); + assertAll( + () -> assertThat(a1Result.merge(c3Result.asInferredType(), TruthValue.TRUE), + is(new InferredType(Set.of(a1, a3, c3), Set.of(), null))), + () -> assertThat(c3Result.merge(a1Result.asInferredType(), TruthValue.TRUE), + is(new InferredType(Set.of(a1, a3, a4, c3), Set.of(), null))) + ); + } + + @Test + void inconsistentMayNotTest() { + var a1Result = tester.getPreservedType(a1); + var a4Result = tester.getPreservedType(a4); + var c1Result = tester.getPreservedType(c1); + assertAll( + () -> assertThat(a4Result.merge(a1Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a1, a4), Set.of(), null))), + () -> assertThat(a1Result.merge(c1Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), + () -> assertThat(a4Result.merge(c1Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a1, a4, c1), Set.of(), null))), + () -> assertThat(a1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a1, a4), Set.of(), null))) + ); + } + + @Test + void vacuousMustTest() { + var c1Result = tester.getPreservedType(c1); + var a5Result = tester.getPreservedType(a5); + assertAll( + () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.TRUE), + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), + () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.TRUE), + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))) + ); + } + + @Test + void vacuousMayNotTest() { + var c1Result = tester.getPreservedType(c1); + var a5Result = tester.getPreservedType(a5); + assertAll( + () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.FALSE), + is(a5Result.asInferredType())), + () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.FALSE), + is(c1Result.asInferredType())) + ); + } + + @Test + void vacuousErrorTest() { + var c1Result = tester.getPreservedType(c1); + var a5Result = tester.getPreservedType(a5); + assertAll( + () -> assertThat(c1Result.merge(a5Result.asInferredType(), TruthValue.ERROR), + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), + () -> assertThat(a5Result.merge(c1Result.asInferredType(), TruthValue.ERROR), + is(new InferredType(Set.of(a1, a4, a5, c1), Set.of(), null))), + () -> assertThat(a5Result.merge(a5Result.asInferredType(), TruthValue.ERROR), + is(a5Result.asInferredType())) + ); + } +} diff --git a/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java new file mode 100644 index 00000000..02903026 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTest.java @@ -0,0 +1,200 @@ +package tools.refinery.store.partial.translator.typehierarchy; + +import org.junit.jupiter.api.Test; +import tools.refinery.store.partial.representation.PartialRelation; +import tools.refinery.store.representation.TruthValue; + +import java.util.LinkedHashMap; +import java.util.Set; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class TypeAnalyzerTest { + @Test + void directSupertypesTest() { + var c1 = new PartialRelation("C1", 1); + var c2 = new PartialRelation("C2", 1); + var c3 = new PartialRelation("C3", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(c1, TypeInfo.builder().supertypes(c2, c3).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(c3).build()); + typeInfoMap.put(c3, TypeInfo.builder().build()); + + var sut = new TypeAnalyzer(typeInfoMap); + var tester = new TypeAnalyzerTester(sut); + + assertAll( + () -> tester.assertConcreteType(c1), + () -> tester.assertConcreteType(c2, c1), + () -> tester.assertConcreteType(c3, c2) + ); + } + + @Test + void typeEliminationAbstractToConcreteTest() { + var c1 = new PartialRelation("C1", 1); + var c2 = new PartialRelation("C2", 1); + var a11 = new PartialRelation("A11", 1); + var a12 = new PartialRelation("A12", 1); + var a21 = new PartialRelation("A21", 1); + var a22 = new PartialRelation("A22", 1); + var a3 = new PartialRelation("A3", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(a3, TypeInfo.builder().abstractType().build()); + typeInfoMap.put(a21, TypeInfo.builder().abstractType().supertype(a3).build()); + typeInfoMap.put(a22, TypeInfo.builder().abstractType().supertype(a3).build()); + typeInfoMap.put(a11, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); + typeInfoMap.put(a12, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); + typeInfoMap.put(c1, TypeInfo.builder().supertypes(a11, a12).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(a3).build()); + + var sut = new TypeAnalyzer(typeInfoMap); + var tester = new TypeAnalyzerTester(sut); + + assertAll( + () -> tester.assertConcreteType(c1), + () -> tester.assertConcreteType(c2), + () -> tester.assertEliminatedType(a11, c1), + () -> tester.assertEliminatedType(a12, c1), + () -> tester.assertEliminatedType(a21, c1), + () -> tester.assertEliminatedType(a22, c1), + () -> tester.assertAbstractType(a3, c1, c2) + ); + } + + @Test + void typeEliminationConcreteToAbstractTest() { + var c1 = new PartialRelation("C1", 1); + var c2 = new PartialRelation("C2", 1); + var a11 = new PartialRelation("A11", 1); + var a12 = new PartialRelation("A12", 1); + var a21 = new PartialRelation("A21", 1); + var a22 = new PartialRelation("A22", 1); + var a3 = new PartialRelation("A3", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(c1, TypeInfo.builder().supertypes(a11, a12).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(a3).build()); + typeInfoMap.put(a11, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); + typeInfoMap.put(a12, TypeInfo.builder().abstractType().supertypes(a21, a22).build()); + typeInfoMap.put(a21, TypeInfo.builder().abstractType().supertype(a3).build()); + typeInfoMap.put(a22, TypeInfo.builder().abstractType().supertype(a3).build()); + typeInfoMap.put(a3, TypeInfo.builder().abstractType().build()); + + var sut = new TypeAnalyzer(typeInfoMap); + var tester = new TypeAnalyzerTester(sut); + + assertAll( + () -> tester.assertConcreteType(c1), + () -> tester.assertConcreteType(c2), + () -> tester.assertEliminatedType(a11, c1), + () -> tester.assertEliminatedType(a12, c1), + () -> tester.assertEliminatedType(a21, c1), + () -> tester.assertEliminatedType(a22, c1), + () -> tester.assertAbstractType(a3, c1, c2) + ); + } + + @Test + void preserveConcreteTypeTest() { + var c1 = new PartialRelation("C1", 1); + var a1 = new PartialRelation("A1", 1); + var c2 = new PartialRelation("C2", 1); + var a2 = new PartialRelation("A2", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(c1, TypeInfo.builder().supertype(a1).build()); + typeInfoMap.put(a1, TypeInfo.builder().abstractType().supertype(c2).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(a2).build()); + typeInfoMap.put(a2, TypeInfo.builder().abstractType().build()); + + var sut = new TypeAnalyzer(typeInfoMap); + var tester = new TypeAnalyzerTester(sut); + + assertAll( + () -> tester.assertConcreteType(c1), + () -> tester.assertEliminatedType(a1, c1), + () -> tester.assertConcreteType(c2, c1), + () -> tester.assertEliminatedType(a2, c2) + ); + } + + @Test + void mostGeneralCurrentTypeTest() { + var c1 = new PartialRelation("C1", 1); + var c2 = new PartialRelation("C2", 1); + var c3 = new PartialRelation("C3", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(c1, TypeInfo.builder().supertype(c3).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(c3).build()); + typeInfoMap.put(c3, TypeInfo.builder().build()); + + var sut = new TypeAnalyzer(typeInfoMap); + var tester = new TypeAnalyzerTester(sut); + var c3Result = tester.getPreservedType(c3); + + var expected = new InferredType(Set.of(c3), Set.of(c1, c2, c3), c3); + assertAll( + () -> assertThat(tester.getInferredType(c3), is(expected)), + () -> assertThat(c3Result.merge(sut.getUnknownType(), TruthValue.TRUE), is(expected)) + ); + } + + @Test + void preferFirstConcreteTypeTest() { + var a1 = new PartialRelation("A1", 1); + var c1 = new PartialRelation("C1", 1); + var c2 = new PartialRelation("C2", 1); + var c3 = new PartialRelation("C3", 1); + var c4 = new PartialRelation("C4", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(c1, TypeInfo.builder().supertype(a1).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(a1).build()); + typeInfoMap.put(c3, TypeInfo.builder().supertype(a1).build()); + typeInfoMap.put(c4, TypeInfo.builder().supertype(c3).build()); + typeInfoMap.put(a1, TypeInfo.builder().abstractType().build()); + + var sut = new TypeAnalyzer(typeInfoMap); + var tester = new TypeAnalyzerTester(sut); + var c1Result = tester.getPreservedType(c1); + var a1Result = tester.getPreservedType(a1); + + assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c2))); + } + + @Test + void preferFirstMostGeneralConcreteTypeTest() { + var a1 = new PartialRelation("A1", 1); + var c1 = new PartialRelation("C1", 1); + var c2 = new PartialRelation("C2", 1); + var c3 = new PartialRelation("C3", 1); + var c4 = new PartialRelation("C4", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(c4, TypeInfo.builder().supertype(c3).build()); + typeInfoMap.put(c3, TypeInfo.builder().supertype(a1).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(a1).build()); + typeInfoMap.put(c1, TypeInfo.builder().supertype(a1).build()); + typeInfoMap.put(a1, TypeInfo.builder().abstractType().build()); + + var sut = new TypeAnalyzer(typeInfoMap); + var tester = new TypeAnalyzerTester(sut); + var c1Result = tester.getPreservedType(c1); + var a1Result = tester.getPreservedType(a1); + + assertThat(c1Result.merge(a1Result.asInferredType(), TruthValue.FALSE), + is(new InferredType(Set.of(a1), Set.of(c2, c3, c4), c3))); + } + + @Test + void circularTypeHierarchyTest() { + var c1 = new PartialRelation("C1", 1); + var c2 = new PartialRelation("C2", 1); + var typeInfoMap = new LinkedHashMap(); + typeInfoMap.put(c1, TypeInfo.builder().supertype(c2).build()); + typeInfoMap.put(c2, TypeInfo.builder().supertype(c1).build()); + + assertThrows(IllegalArgumentException.class, () -> new TypeAnalyzer(typeInfoMap)); + } +} diff --git a/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTester.java b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTester.java new file mode 100644 index 00000000..ce600ea6 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/partial/translator/typehierarchy/TypeAnalyzerTester.java @@ -0,0 +1,51 @@ +package tools.refinery.store.partial.translator.typehierarchy; + +import tools.refinery.store.partial.representation.PartialRelation; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; + +class TypeAnalyzerTester { + private final TypeAnalyzer sut; + + public TypeAnalyzerTester(TypeAnalyzer sut) { + this.sut = sut; + } + + public void assertAbstractType(PartialRelation partialRelation, PartialRelation... directSubtypes) { + assertPreservedType(partialRelation, true, false, directSubtypes); + } + + public void assertVacuousType(PartialRelation partialRelation) { + assertPreservedType(partialRelation, true, true); + } + + public void assertConcreteType(PartialRelation partialRelation, PartialRelation... directSubtypes) { + assertPreservedType(partialRelation, false, false, directSubtypes); + } + + private void assertPreservedType(PartialRelation partialRelation, boolean isAbstract, boolean isVacuous, + PartialRelation... directSubtypes) { + var result = sut.getAnalysisResults().get(partialRelation); + assertThat(result, is(instanceOf(PreservedType.class))); + var preservedResult = (PreservedType) result; + assertThat(preservedResult.isAbstractType(), is(isAbstract)); + assertThat(preservedResult.isVacuous(), is(isVacuous)); + assertThat(preservedResult.getDirectSubtypes(), hasItems(directSubtypes)); + } + + public void assertEliminatedType(PartialRelation partialRelation, PartialRelation replacement) { + var result = sut.getAnalysisResults().get(partialRelation); + assertThat(result, is(instanceOf(EliminatedType.class))); + assertThat(((EliminatedType) result).replacement(), is(replacement)); + } + + public PreservedType getPreservedType(PartialRelation partialRelation) { + return (PreservedType) sut.getAnalysisResults().get(partialRelation); + } + + public InferredType getInferredType(PartialRelation partialRelation) { + return getPreservedType(partialRelation).asInferredType(); + } +} -- cgit v1.2.3-70-g09d2