using Azimuth; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnitTestSharp; using Glass; using System.Reflection; using System.Security.Cryptography.X509Certificates; namespace Glass.UnitTests { public class RenderCallbackRegistryTests : TestFixture { public class RenderAndRegisterCallbackTests : TestFixture { class GrandparentMaterial : Material { } class ParentMaterial : GrandparentMaterial { } class ChildMaterial : ParentMaterial { } class SiblingMaterial : GrandparentMaterial { } class CallbackInvocation { public int Context; public Material Material; public Rect Rect; public AffineMatrix Transform; public CallbackInvocation(int context, Material material, Rect rect, AffineMatrix transform) { Context = context; Material = material; Rect = rect; Transform = transform; } }; public void RegisteredCallbackIsInvokedOnRender() { var registry = new RenderCallbackRegistry(); var invocations = new List(); registry.RegisterCallback((_context, _material, _rect, _transform) => invocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); int context = 7; var material = new GrandparentMaterial(); var rect = Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)); var transform = AffineMatrix.Identity; registry.Render(context, material, rect, transform); CheckEqual(1, invocations.Count); CheckEqual(context, invocations[0].Context); CheckEqual(material, invocations[0].Material); CheckEqual(rect, invocations[0].Rect); CheckEqual(transform, invocations[0].Transform); } public void RenderReturnsTrueWhenCallbackIsRegistered() { var registry = new RenderCallbackRegistry(); registry.RegisterCallback((context, material, rect, transform) => { }); bool rendered = registry.Render( 7, new GrandparentMaterial(), Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckTrue(rendered); } public void RenderReturnsFalseWhenNoCallbackRegistered() { var registry = new RenderCallbackRegistry(); bool rendered = registry.Render( 7, new GrandparentMaterial(), Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckFalse(rendered); } public void DerivedTypeInheritsBaseCallback() { var registry = new RenderCallbackRegistry(); var invocations = new List(); registry.RegisterCallback((_context, _material, _rect, _transform) => invocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); var material = new ParentMaterial(); registry.Render( 7, material, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(1, invocations.Count); CheckEqual(material, invocations[0].Material); } public void GrandchildInheritsGrandparentCallbackWhenNothingCloserRegistered() { var registry = new RenderCallbackRegistry(); var invocations = new List(); registry.RegisterCallback((_context, _material, _rect, _transform) => invocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); var material = new ChildMaterial(); registry.Render( 7, material, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(1, invocations.Count); CheckEqual(material, invocations[0].Material); } public void ClosestAncestorCallbackWins() { var registry = new RenderCallbackRegistry(); var grandparentInvocations = new List(); var parentInvocations = new List(); registry.RegisterCallback((_context, _material, _rect, _transform) => grandparentInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); registry.RegisterCallback((_context, _material, _rect, _transform) => parentInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); var material = new ChildMaterial(); registry.Render( 7, material, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(0, grandparentInvocations.Count); CheckEqual(1, parentInvocations.Count); CheckEqual(material, parentInvocations[0].Material); } public void ClosestAncestorCallbackWinsRegardlessOfRegistrationOrder() { var registry = new RenderCallbackRegistry(); var grandparentInvocations = new List(); var parentInvocations = new List(); registry.RegisterCallback((_context, _material, _rect, _transform) => parentInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); registry.RegisterCallback((_context, _material, _rect, _transform) => grandparentInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); var material = new ChildMaterial(); registry.Render( 7, material, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(0, grandparentInvocations.Count); CheckEqual(1, parentInvocations.Count); CheckEqual(material, parentInvocations[0].Material); } public void ReRegistrationReplacesCallback() { var registry = new RenderCallbackRegistry(); var firstInvocations = new List(); var secondInvocations = new List(); registry.RegisterCallback((_context, _material, _rect, _transform) => firstInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); registry.RegisterCallback((_context, _material, _rect, _transform) => secondInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); registry.Render( 7, new GrandparentMaterial(), Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(0, firstInvocations.Count); CheckEqual(1, secondInvocations.Count); } public void ReRegistrationUpdatesCallbackForDerivedTypes() { var registry = new RenderCallbackRegistry(); var firstInvocations = new List(); var secondInvocations = new List(); registry.RegisterCallback((_context, _material, _rect, _transform) => firstInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); registry.RegisterCallback((_context, _material, _rect, _transform) => secondInvocations.Add(new CallbackInvocation(_context, _material, _rect, _transform))); registry.Render( 7, new ParentMaterial(), Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(0, firstInvocations.Count); CheckEqual(1, secondInvocations.Count); } } public class IsSystemAssemblyTests : TestFixture { public void SystemAssemblyReturnTrue() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("System.Collections")); } public void MicrosoftAssemblyReturnsTrue() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("Microsoft.CSharp")); } public void MscorlibReturnsTrue() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("mscorlib")); } public void NetstandardReturnsTrue() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("netstandard")); } public void UserAssemblyReturnsFalse() { CheckFalse(RenderCallbackRegistry.IsSystemAssembly("Glass")); } public void SystemAssemblyIsCaseInsensitive() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("system.Collections")); } public void MicrosoftAssemblyIsCaseInsensitive() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("microsoft.CSharp")); } public void MscorlibIsCaseInsensitive() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("Mscorlib")); } public void NetstandardIsCaseInsensitive() { CheckTrue(RenderCallbackRegistry.IsSystemAssembly("Netstandard")); } } public class MatchesRenderCallbackSignatureTests : TestFixture { class GrandparentMaterial : Material { } static void ValidCallback(int context, GrandparentMaterial material, Rect rect, AffineMatrix transform) { } static void TooFewParameters(int context, GrandparentMaterial material, Rect rect) { } static void TooManyParameters( int context, GrandparentMaterial material, Rect rect, AffineMatrix transform, int extra) { } static void WrongContextType( string context, GrandparentMaterial material, Rect rect, AffineMatrix transform) { } static void NonMaterialSecondParameter(int context, int material, Rect rect, AffineMatrix transform) { } static void WrongThirdParameter( int context, GrandparentMaterial material, int rect, AffineMatrix transform) { } static void WrongFourthParameter(int context, GrandparentMaterial material, Rect rect, int transform) { } static MethodInfo Method(string name) => typeof(MatchesRenderCallbackSignatureTests) .GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static); public void ValidSignatureReturnsTrue() { bool result = RenderCallbackRegistry.MatchesRenderCallbackSignature( Method(nameof(ValidCallback)), out Type materialType); CheckTrue(result); CheckEqual(typeof(GrandparentMaterial), materialType); } public void TooFewParametersReturnsFalse() { bool result = RenderCallbackRegistry.MatchesRenderCallbackSignature( Method(nameof(TooFewParameters)), out _); CheckFalse(result); } public void TooManyParametersReturnsFalse() { bool result = RenderCallbackRegistry.MatchesRenderCallbackSignature( Method(nameof(TooManyParameters)), out _); CheckFalse(result); } public void WrongContextTypeReturnsFalse() { bool result = RenderCallbackRegistry.MatchesRenderCallbackSignature( Method(nameof(WrongContextType)), out _); CheckFalse(result); } public void NonMaterialSecondParameterReturnsFalse() { bool result = RenderCallbackRegistry.MatchesRenderCallbackSignature( Method(nameof(NonMaterialSecondParameter)), out _); CheckFalse(result); } public void WrongThirdParameterReturnsFalse() { bool result = RenderCallbackRegistry.MatchesRenderCallbackSignature( Method(nameof(WrongThirdParameter)), out _); CheckFalse(result); } public void WrongFourthParameterReturnsFalse() { bool result = RenderCallbackRegistry.MatchesRenderCallbackSignature( Method(nameof(WrongFourthParameter)), out _); CheckFalse(result); } } public class GetConcreteTypesOfTests : TestFixture { class TestBase { } abstract class AbstractDerived : TestBase { } class ConcreteDerived : TestBase { } class ConcreteGrandchild : ConcreteDerived { } class Unrelated { } public void ConcreteSubclassIsReturned() { CheckTrue(RenderCallbackRegistry .GetConcreteTypesOf() .Contains(typeof(ConcreteDerived))); } public void ConcreteGrandchildIsReturned() { CheckTrue(RenderCallbackRegistry .GetConcreteTypesOf() .Contains(typeof(ConcreteGrandchild))); } public void AbstractSubclassIsNotReturned() { CheckFalse(RenderCallbackRegistry .GetConcreteTypesOf() .Contains(typeof(AbstractDerived))); } public void UnrelatedTypeIsNotReturned() { CheckFalse(RenderCallbackRegistry .GetConcreteTypesOf() .Contains(typeof(Unrelated))); } public void BaseTypeItselfIsReturnedWhenNotAbstract() { CheckTrue(RenderCallbackRegistry .GetConcreteTypesOf() .Contains(typeof(TestBase))); } } public class RegisterRenderCallbacksInInstanceTests : TestFixture { class GrandparentMaterial : Material { } class ParentMaterial : GrandparentMaterial { } class ChildMaterial : ParentMaterial { } class BaseOnlyMaterial : Material { } class TestRendererBase { public List BaseInvocations = new List(); public void BaseCallback( int context, BaseOnlyMaterial material, Rect rect, AffineMatrix transform) { BaseInvocations.Add(material); } } class TestRenderer : TestRendererBase { public List InstanceInvocations = new List(); public List AnotherInstanceInvocations = new List(); public static List StaticInvocations = new List(); public void ValidCallback( int context, GrandparentMaterial material, Rect rect, AffineMatrix transform) { InstanceInvocations.Add(material); } public void AnotherValidCallback( int context, ParentMaterial material, Rect rect, AffineMatrix transform) { AnotherInstanceInvocations.Add(material); } public static void StaticValidCallback( int context, ChildMaterial material, Rect rect, AffineMatrix transform) { StaticInvocations.Add(material); } } public override void TestSetup() { base.TestSetup(); TestRenderer.StaticInvocations.Clear(); } public void InstanceMethodIsRegistered() { var renderer = new TestRenderer(); var registry = new RenderCallbackRegistry(); registry.RegisterRenderCallbacksInInstance(renderer); var material = new GrandparentMaterial(); registry.Render( 7, material, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(new[] { material }, renderer.InstanceInvocations); } public void StaticMethodIsRegistered() { var registry = new RenderCallbackRegistry(); registry.RegisterRenderCallbacksInInstance(new TestRenderer()); var material = new ChildMaterial(); registry.Render( 7, material, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(new[] { material }, TestRenderer.StaticInvocations); } public void MultipleValidMethodsAreAllRegistered() { var renderer = new TestRenderer(); var registry = new RenderCallbackRegistry(); registry.RegisterRenderCallbacksInInstance(renderer); var grandparentMaterial = new GrandparentMaterial(); var parentMaterial = new ParentMaterial(); registry.Render( 7, grandparentMaterial, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); registry.Render( 7, parentMaterial, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(new[] { grandparentMaterial }, renderer.InstanceInvocations); CheckEqual(new[] { parentMaterial }, renderer.AnotherInstanceInvocations); } public void BaseClassMethodIsNotRegistered() { var renderer = new TestRenderer(); var registry = new RenderCallbackRegistry(); registry.RegisterRenderCallbacksInInstance(renderer); var material = new BaseOnlyMaterial(); registry.Render( 7, material, Rect.FromTwoPoints(new Vector(0, 0), new Vector(10, 10)), AffineMatrix.Identity); CheckEqual(new Material[] { }, renderer.BaseInvocations); } } } }