using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using UnitTestSharp;
namespace Vellum.Generator.UnitTests
{
public class SaveableChecksTests : TestFixture
{
///
/// Returns checks that differ from the default ones only in the arguments given.
///
public static SaveableChecks Variant(string name = "A", string convertedName = "Ns.A", bool generates = true,
SaveableProblem problem = SaveableProblem.None, SourcePlace problemPlace = null,
bool inheritsMark = false, MemberCheck[] members = null)
{
return new SaveableChecks(name, convertedName, generates, problem,
problemPlace ?? SourcePlaceTests.Variant(), inheritsMark,
new EquatableArray((members ?? new[] { MemberCheckTests.Variant() }).ToImmutableArray()));
}
public class CtorTests : TestFixture
{
public void KeepsEveryArgument()
{
SaveableChecks checks = Variant(generates: false, problem: SaveableProblem.PublicLoader,
inheritsMark: true);
CheckEqual("A", checks.Name);
CheckEqual("Ns.A", checks.ConvertedName);
CheckFalse(checks.Generates);
CheckEqual(SaveableProblem.PublicLoader, checks.Problem);
CheckEqual(SourcePlaceTests.Variant(), checks.ProblemPlace);
CheckTrue(checks.InheritsMark);
CheckEqual(MemberCheckTests.Variant(), checks.Members.Items.Single());
}
}
public class CheckTests : TestFixture
{
public static List CheckedDiagnostics(string metadataName, string source)
{
CSharpCompilation compilation = VellumRun.Compile(("Source.cs", source));
SaveableChecks checks = SaveableClass.Describe(compilation.GetTypeByMetadataName(metadataName)).Checks;
ConverterList converters = VellumRun.Converters(compilation);
return checks.Check(compilation, converters, converters.ConvertedNames());
}
public static List Checked(string metadataName, string source)
{
return CheckedDiagnostics(metadataName, source).Select(VellumRun.Describe).ToList();
}
public void ValidType_HasNothingToReport()
{
CheckEqual(0, Checked("Point", "[Saveable] public partial struct Point { public int X; }").Count);
}
public void UnsupportedShape_IsReportedAtTheTypesName()
{
CheckEqual(new[] { "VEL0005:Whole" }, Checked("Whole", "[Saveable] public struct Whole { }"));
}
public void NonPrivateOwnLoader_IsReportedAtTheLoader()
{
CheckEqual(new[] { "VEL0006:Open" }, Checked("Open",
"[Saveable] public partial struct Open { public Open(SaveReader reader) { } }"));
}
public void SubclassThatIsntPartial_IsReportedWithWhyItIsSaveable()
{
List found = CheckedDiagnostics("Dog",
"[Saveable] public partial class Animal { }\npublic class Dog : Animal { }");
CheckEqual(1, found.Count);
CheckEqual("VEL0005", found[0].Id);
CheckTrue(found[0].GetMessage().Contains("because a class it derives from, or an interface it " +
"implements, is"));
}
public void ImplementerWhoseBaseIsntSaveable_IsReportedWithWhyItIsSaveable()
{
List found = CheckedDiagnostics("Mission", "[Saveable] public interface IPet { }\n" +
"public class Framework { }\npublic partial class Mission : Framework, IPet { }");
CheckEqual(1, found.Count);
CheckEqual("VEL0005", found[0].Id);
CheckTrue(found[0].GetMessage().Contains("interface it implements"));
}
public void MarkedClassThatIsntPartial_IsReportedWithoutThatReason()
{
List found = CheckedDiagnostics("Open", "[Saveable] public class Open { }");
CheckFalse(found[0].GetMessage().Contains("because"));
}
public void MemberNamedForAKeyVellumUses_IsReportedWhereItIsDeclared()
{
CheckEqual(new[] { "VEL0008:__type", "VEL0008:__value" }, Checked("Tagged",
"[Saveable] public sealed partial class Tagged { public int __type; public int __value; }"));
}
public void MemberSavedUnderAKeyABaseClassUses_IsReportedWhereItIsDeclared()
{
CheckEqual(new[] { "VEL0009:Name" }, Checked("Dog",
"[Saveable] public partial class Animal { public string Name; }\n" +
"[Saveable] public sealed partial class Dog : Animal { public new string Name; }"));
}
public void MemberOfASubclass_ThatNoBaseSaves_IsNotReported()
{
CheckEqual(0, Checked("Dog",
"[Saveable] public partial class Animal { public string Name; }\n" +
"[Saveable] public sealed partial class Dog : Animal { public bool Barks; }").Count);
}
public void HandWrittenConverterOfAGeneratedType_IsReportedAtTheConverter()
{
CheckEqual(new[] { "VEL0002:PointConverter" }, Checked("Point",
"[Saveable] public partial struct Point { }\n" +
ConverterScanTests.Converter("PointConverter", "Point")));
}
public void HandWrittenConverterOfATypeThatAlreadyHasOne_IsNotReported()
{
CheckEqual(0, Checked("Point",
"[Saveable] public partial struct Point { public class __Converter { } }\n" +
ConverterScanTests.Converter("PointConverter", "Point")).Count);
}
public void MemberThatCantBeSaved_IsReportedWhereItsDeclared()
{
CheckEqual(new[] { "VEL0004:Stops" }, Checked("Route",
"[Saveable] public partial struct Route { public int Length; public object Stops; }"));
}
public void MemberWithAConverter_IsAllowed()
{
CheckEqual(0, Checked("Route", ConverterScanTests.Point +
ConverterScanTests.Converter("PointConverter", "Point") +
"[Saveable] public partial struct Route { public Point Start; public Point? End; }").Count);
}
public void MembersOfAnUnsupportedShape_AreStillChecked()
{
CheckEqual(new[] { "VEL0005:Whole", "VEL0004:Anything" }, Checked("Whole",
"[Saveable] public struct Whole { public object Anything; }"));
}
}
public class EqualsTests : TestFixture
{
public void SameValues_AreEqual()
{
CheckTrue(Variant().Equals(Variant()));
CheckTrue(Variant().Equals((object)Variant()));
}
public void Null_IsNotEqual()
{
CheckFalse(Variant().Equals((SaveableChecks)null));
CheckFalse(Variant().Equals((object)null));
}
public void OtherType_IsNotEqual()
{
CheckFalse(Variant().Equals("A"));
}
public void DifferentName_IsNotEqual()
{
CheckFalse(Variant().Equals(Variant(name: "B")));
}
public void DifferentConvertedName_IsNotEqual()
{
CheckFalse(Variant().Equals(Variant(convertedName: "Ns.B")));
}
public void DifferentGenerates_IsNotEqual()
{
CheckFalse(Variant().Equals(Variant(generates: false)));
}
public void DifferentProblem_IsNotEqual()
{
CheckFalse(Variant().Equals(Variant(problem: SaveableProblem.Unsupported)));
}
public void DifferentProblemPlace_IsNotEqual()
{
CheckFalse(Variant().Equals(Variant(problemPlace: SourcePlaceTests.Variant(start: 2))));
}
public void DifferentInheritsMark_IsNotEqual()
{
CheckFalse(Variant().Equals(Variant(inheritsMark: true)));
}
public void DifferentMembers_AreNotEqual()
{
CheckFalse(Variant().Equals(Variant(members: new[] { MemberCheckTests.Variant(key: "Total") })));
}
}
public class GetHashCodeTests : TestFixture
{
public void EqualChecks_HaveEqualHashCodes()
{
CheckEqual(Variant().GetHashCode(), Variant().GetHashCode());
}
}
}
}