diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/gtest/type-builder.cpp | 151 |
1 files changed, 142 insertions, 9 deletions
diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp index 9cbd04298..8f922380d 100644 --- a/test/gtest/type-builder.cpp +++ b/test/gtest/type-builder.cpp @@ -16,6 +16,17 @@ protected: destroyAllTypesForTestingPurposesOnly(); setTypeSystem(originalSystem); } + + // Utilities + Struct makeStruct(TypeBuilder& builder, + std::initializer_list<size_t> indices) { + FieldList fields; + for (auto index : indices) { + Type ref = builder.getTempRefType(builder[index], Nullable); + fields.emplace_back(ref, Mutable); + } + return Struct(std::move(fields)); + } }; using TypeTest = TypeSystemTest<TypeSystem::Equirecursive>; @@ -214,15 +225,6 @@ static void testInvalidSupertype() { TEST_F(NominalTest, InvalidSupertype) { testInvalidSupertype(); } TEST_F(IsorecursiveTest, InvalidSupertype) { testInvalidSupertype(); } -TEST_F(IsorecursiveTest, SelfReferencedChild) { - // A self-referential type should be ok even without an explicit rec group. - TypeBuilder builder(1); - Type selfRef = builder.getTempRefType(builder[0], Nullable); - builder[0] = Struct({Field(selfRef, Immutable)}); - auto result = builder.build(); - EXPECT_TRUE(result); -} - TEST_F(IsorecursiveTest, ForwardReferencedChild) { TypeBuilder builder(3); builder.createRecGroup(0, 2); @@ -269,3 +271,134 @@ TEST_F(IsorecursiveTest, RecGroupIndices) { EXPECT_EQ(built[3].getRecGroupIndex(), 1u); EXPECT_EQ(built[4].getRecGroupIndex(), 2u); } + +TEST_F(IsorecursiveTest, CanonicalizeGroups) { + // Trivial types in the same group are not equivalent. + TypeBuilder builderA(2); + builderA.createRecGroup(0, 2); + builderA[0] = Struct{}; + builderA[1] = Struct{}; + auto resultA = builderA.build(); + ASSERT_TRUE(resultA); + auto builtA = *resultA; + + EXPECT_NE(builtA[0], builtA[1]); + + // But if they are in their own separate groups, they are equivalent. + TypeBuilder builderB(2); + builderB[0] = Struct{}; + builderB[1] = Struct{}; + auto resultB = builderB.build(); + ASSERT_TRUE(resultB); + auto builtB = *resultB; + + EXPECT_EQ(builtB[0], builtB[1]); + EXPECT_NE(builtB[0], builtA[0]); + EXPECT_NE(builtB[0], builtA[1]); + + // If we build the same groups again, we should get the same results. + TypeBuilder builderA2(4); + builderA2.createRecGroup(0, 2); + builderA2.createRecGroup(2, 2); + builderA2[0] = Struct{}; + builderA2[1] = Struct{}; + builderA2[2] = Struct{}; + builderA2[3] = Struct{}; + auto resultA2 = builderA2.build(); + ASSERT_TRUE(resultA2); + auto builtA2 = *resultA2; + + EXPECT_EQ(builtA2[0], builtA[0]); + EXPECT_EQ(builtA2[1], builtA[1]); + EXPECT_EQ(builtA2[2], builtA[0]); + EXPECT_EQ(builtA2[3], builtA[1]); + + TypeBuilder builderB2(1); + builderB2[0] = Struct{}; + auto resultB2 = builderB2.build(); + ASSERT_TRUE(resultB2); + auto builtB2 = *resultB2; + + EXPECT_EQ(builtB2[0], builtB[0]); +} + +TEST_F(IsorecursiveTest, CanonicalizeUses) { + TypeBuilder builder(8); + builder[0] = makeStruct(builder, {}); + builder[1] = makeStruct(builder, {}); + builder[2] = makeStruct(builder, {0}); + builder[3] = makeStruct(builder, {1}); + builder[4] = makeStruct(builder, {0, 2}); + builder[5] = makeStruct(builder, {1, 3}); + builder[6] = makeStruct(builder, {2, 4}); + builder[7] = makeStruct(builder, {3, 5}); + + auto result = builder.build(); + ASSERT_TRUE(result); + auto built = *result; + + EXPECT_EQ(built[0], built[1]); + EXPECT_EQ(built[2], built[3]); + EXPECT_EQ(built[4], built[5]); + EXPECT_EQ(built[6], built[7]); + + EXPECT_NE(built[0], built[2]); + EXPECT_NE(built[0], built[4]); + EXPECT_NE(built[0], built[6]); + EXPECT_NE(built[2], built[4]); + EXPECT_NE(built[2], built[6]); + EXPECT_NE(built[4], built[6]); +} + +TEST_F(IsorecursiveTest, CanonicalizeSelfReferences) { + TypeBuilder builder(5); + // Single self-reference + builder[0] = makeStruct(builder, {0}); + builder[1] = makeStruct(builder, {1}); + // Single other reference + builder[2] = makeStruct(builder, {0}); + // Other reference followed by self-reference + builder[3] = makeStruct(builder, {2, 3}); + // Self-reference followed by other reference + builder[4] = makeStruct(builder, {4, 2}); + + auto result = builder.build(); + ASSERT_TRUE(result); + auto built = *result; + + EXPECT_EQ(built[0], built[1]); + + EXPECT_NE(built[0], built[2]); + EXPECT_NE(built[0], built[3]); + EXPECT_NE(built[0], built[4]); + EXPECT_NE(built[2], built[3]); + EXPECT_NE(built[2], built[4]); + EXPECT_NE(built[3], built[4]); +} + +TEST_F(IsorecursiveTest, CanonicalizeSupertypes) { + TypeBuilder builder(6); + builder[0] = Struct{}; + builder[1] = Struct{}; + // Type with a supertype + builder[2] = Struct{}; + builder[2].subTypeOf(builder[0]); + // Type with the same supertype after canonicalization. + builder[3] = Struct{}; + builder[3].subTypeOf(builder[1]); + // Type with a different supertype + builder[4] = Struct{}; + builder[4].subTypeOf(builder[2]); + // Type with no supertype + builder[5] = Struct{}; + + auto result = builder.build(); + ASSERT_TRUE(result); + auto built = *result; + + EXPECT_EQ(built[2], built[3]); + + EXPECT_NE(built[3], built[4]); + EXPECT_NE(built[3], built[5]); + EXPECT_NE(built[4], built[5]); +} |