using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp; using UnitTestSharp; namespace Vellum.Generator.UnitTests { public class UnsavedSubtypeTests : TestFixture { public const string Animal = "public class Animal { }\n"; public static readonly string AnimalConverter = ConverterScanTests.Converter("AnimalConverter", "Animal"); public static UnsavedSubtype Variant(string name = "Dog", string convertedName = "Ns.Dog", string[] baseNames = null, SourcePlace place = null) { return new UnsavedSubtype(name, convertedName, new EquatableArray((baseNames ?? new[] { "Ns.Animal" }).ToImmutableArray()), place ?? SourcePlaceTests.Variant()); } public static UnsavedSubtype SubtypeOf(string metadataName, string source) { return UnsavedSubtype.Of(SaveableClassTests.TypeOf(metadataName, source)); } public class CtorTests : TestFixture { public void KeepsEveryArgument() { UnsavedSubtype subtype = Variant(); CheckEqual("Dog", subtype.Name); CheckEqual("Ns.Dog", subtype.ConvertedName); CheckEqual("Ns.Animal", subtype.BaseNames.Items.Single()); CheckEqual(SourcePlaceTests.Variant(), subtype.Place); } public void FamilyNames_AreKept() { UnsavedSubtype subtype = new UnsavedSubtype("Dog", "Ns.Dog", new EquatableArray(ImmutableArray.Create("Ns.Animal")), SourcePlaceTests.Variant(), new EquatableArray(ImmutableArray.Create("Ns.Dog", "Ns.Animal"))); CheckEqual(new[] { "Ns.Dog", "Ns.Animal" }, subtype.FamilyNames.Items.ToArray()); } } public class OfTests : TestFixture { public void Class_ListsTheClassesItDerivesFromNearestFirst() { UnsavedSubtype subtype = SubtypeOf("Game.Pup", @" namespace Game { public class Animal { } public class Dog : Animal { } public class Pup : Dog { } }"); CheckEqual("Pup", subtype.Name); CheckEqual("Game.Pup", subtype.ConvertedName); CheckEqual(new[] { "Game.Dog", "Game.Animal" }, subtype.BaseNames.Items.ToArray()); } public void GenericBase_IsListedAsMadeAndAsTheGenericTypeItIsMadeFrom() { UnsavedSubtype subtype = SubtypeOf("Crate", "public class Box { }\npublic class Crate : Box { }"); CheckEqual(new[] { "Box", "Box" }, subtype.BaseNames.Items.ToArray()); } public void Class_ListsItselfAndTheGenericClassesItDerivesFromByTheirGenericTypes() { UnsavedSubtype subtype = SubtypeOf("Crate", "public class Box { }\npublic class Crate : Box { }"); CheckEqual(new[] { "Crate", "Box" }, subtype.FamilyNames.Items.ToArray()); } public void Class_IsPlacedAtItsName() { var type = SaveableClassTests.TypeOf("Dog", Animal + "public class Dog : Animal { }"); UnsavedSubtype subtype = UnsavedSubtype.Of(type); CheckEqual("Dog", type.Locations[0].SourceTree.GetText().ToString(subtype.Place.Span)); } public void ClassDerivingFromObject_HasNothingToCheck() { CheckNull(SubtypeOf("Plain", "public class Plain { }")); } public void AbstractClass_HasNothingToCheck() { CheckNull(SubtypeOf("Dog", Animal + "public abstract class Dog : Animal { }")); } public void StructAndInterface_HaveNothingToCheck() { CheckNull(SubtypeOf("Point", "public struct Point { }")); CheckNull(SubtypeOf("IPet", "public interface IPet { }")); } } public class CheckTests : TestFixture { public static List Checked(string metadataName, string source) { CSharpCompilation compilation = VellumRun.Compile(("Source.cs", source)); UnsavedSubtype subtype = UnsavedSubtype.Of(compilation.GetTypeByMetadataName(metadataName)); ConverterList converters = VellumRun.Converters(compilation); return subtype.Check(compilation, converters.ConvertedNames(), converters.FamilyBaseNames()) .Select(VellumRun.Describe).ToList(); } public void SubtypeOfAConvertedClass_IsReportedAtItsName() { CheckEqual(new[] { "VEL0010:Dog" }, Checked("Dog", Animal + AnimalConverter + "public class Dog : Animal { }")); } public void SubtypeFurtherDown_IsReportedToo() { CheckEqual(new[] { "VEL0010:Pup" }, Checked("Pup", Animal + AnimalConverter + "public class Dog : Animal { }\npublic class Pup : Dog { }")); } public void SubtypeWithAConverterOfItsOwn_IsNotReported() { CheckEqual(0, Checked("Dog", Animal + AnimalConverter + "public class Dog : Animal { }\n" + ConverterScanTests.Converter("DogConverter", "Dog")).Count); } public void SubtypeOfAClassAFamilySaves_IsNotReported() { CheckEqual(0, Checked("Dog", Animal + AnimalConverter + "public class Dog : Animal { }\n" + ConverterScanTests.Family("DogConverter", "DogType", "Dog") + "public class Pup : Dog { }").Count); CheckEqual(0, Checked("Pup", Animal + AnimalConverter + "public class Dog : Animal { }\n" + ConverterScanTests.Family("DogConverter", "DogType", "Dog") + "public class Pup : Dog { }").Count); } public void SubtypeOfAClassAFamilySavesFurtherUp_IsNotReported() { CheckEqual(0, Checked("Dog", Animal + AnimalConverter + "public class Dog : Animal { }\n" + ConverterScanTests.Family("AnimalFamilyConverter", "AnimalType", "Animal")).Count); } public void SubtypeOfAClassNothingConverts_IsNotReported() { CheckEqual(0, Checked("Dog", Animal + "public class Dog : Animal { }").Count); } public void MessageNamesTheSubtypeAndTheClassThatIsConverted() { CSharpCompilation compilation = VellumRun.Compile(("Source.cs", Animal + AnimalConverter + "public class Dog : Animal { }")); UnsavedSubtype subtype = UnsavedSubtype.Of(compilation.GetTypeByMetadataName("Dog")); ConverterList converters = VellumRun.Converters(compilation); string message = subtype.Check(compilation, converters.ConvertedNames(), converters.FamilyBaseNames()) .Single().GetMessage(); CheckTrue(message.StartsWith("'Dog' derives from Animal, which a converter saves")); } } public class EqualsTests : TestFixture { public void SameValues_AreEqual() { CheckTrue(Variant().Equals(Variant())); CheckTrue(Variant().Equals((object)Variant())); } public void Null_IsNotEqual() { CheckFalse(Variant().Equals((UnsavedSubtype)null)); CheckFalse(Variant().Equals((object)null)); } public void OtherType_IsNotEqual() { CheckFalse(Variant().Equals("Dog")); } public void DifferentName_IsNotEqual() { CheckFalse(Variant().Equals(Variant(name: "Cat"))); } public void DifferentConvertedName_IsNotEqual() { CheckFalse(Variant().Equals(Variant(convertedName: "Ns.Cat"))); } public void DifferentBaseNames_AreNotEqual() { CheckFalse(Variant().Equals(Variant(baseNames: new[] { "Ns.Pet" }))); } public void DifferentFamilyNames_AreNotEqual() { UnsavedSubtype other = new UnsavedSubtype("Dog", "Ns.Dog", new EquatableArray(ImmutableArray.Create("Ns.Animal")), SourcePlaceTests.Variant(), new EquatableArray(ImmutableArray.Create("Ns.Dog"))); CheckFalse(Variant().Equals(other)); } public void DifferentPlace_IsNotEqual() { CheckFalse(Variant().Equals(Variant(place: SourcePlaceTests.Variant(start: 2)))); } } public class GetHashCodeTests : TestFixture { public void EqualSubtypes_HaveEqualHashCodes() { CheckEqual(Variant().GetHashCode(), Variant().GetHashCode()); } } } }