diff --git a/Testing/VelaptorTests/Content/TextureFactoryTests.cs b/Testing/VelaptorTests/Content/TextureFactoryTests.cs index 4c5acc670..bb305ba8b 100644 --- a/Testing/VelaptorTests/Content/TextureFactoryTests.cs +++ b/Testing/VelaptorTests/Content/TextureFactoryTests.cs @@ -8,7 +8,7 @@ namespace VelaptorTests.Content; using System.Drawing; using Carbonate.OneWay; using FluentAssertions; -using Moq; +using NSubstitute; using Velaptor.Content.Factories; using Velaptor.Factories; using Velaptor.Graphics; @@ -22,22 +22,22 @@ namespace VelaptorTests.Content; /// public class TextureFactoryTests { - private readonly Mock mockGL; - private readonly Mock mockGLService; - private readonly Mock mockReactableFactory; + private readonly IGLInvoker mockGL; + private readonly IOpenGLService mockGLService; + private readonly IReactableFactory mockReactableFactory; /// /// Initializes a new instance of the class. /// public TextureFactoryTests() { - this.mockGL = new Mock(); - this.mockGLService = new Mock(); + this.mockGL = Substitute.For(); + this.mockGLService = Substitute.For(); - var mockDisposeReactable = new Mock>(); + var mockDisposeReactable = Substitute.For>(); - this.mockReactableFactory = new Mock(); - this.mockReactableFactory.Setup(m => m.CreateDisposeTextureReactable()).Returns(mockDisposeReactable.Object); + this.mockReactableFactory = Substitute.For(); + this.mockReactableFactory.CreateDisposeTextureReactable().Returns(mockDisposeReactable); } #region Constructor Tests @@ -49,8 +49,8 @@ public void Ctor_WithNullGLInvoker_ThrowsException() { _ = new TextureFactory( null, - this.mockGLService.Object, - this.mockReactableFactory.Object); + this.mockGLService, + this.mockReactableFactory); }; // Assert @@ -66,9 +66,9 @@ public void Ctor_WithNullOpenGLService_ThrowsException() var act = () => { _ = new TextureFactory( - this.mockGL.Object, + this.mockGL, null, - this.mockReactableFactory.Object); + this.mockReactableFactory); }; // Assert @@ -84,8 +84,8 @@ public void Ctor_WithNullReactableFactoryParam_ThrowsException() var act = () => { _ = new TextureFactory( - this.mockGL.Object, - this.mockGLService.Object, + this.mockGL, + this.mockGLService, null); }; @@ -164,8 +164,8 @@ public void Create_WhenInvoked_WorksCorrectly() // Assert // NOTE: These are only here to prove that the same injected objects are the ones being used. - this.mockGL.Verify(m => m.GenTexture(), Times.Once); - this.mockGLService.Verify(m => m.LabelTexture(It.IsAny(), It.IsAny()), Times.Once); + this.mockGL.Received(1).GenTexture(); + this.mockGLService.Received(1).LabelTexture(Arg.Any(), Arg.Any()); } #endregion @@ -174,7 +174,7 @@ public void Create_WhenInvoked_WorksCorrectly() /// /// The instance to test. private TextureFactory CreateSystemUnderTest() => new ( - this.mockGL.Object, - this.mockGLService.Object, - this.mockReactableFactory.Object); + this.mockGL, + this.mockGLService, + this.mockReactableFactory); } diff --git a/Testing/VelaptorTests/Content/TextureTests.cs b/Testing/VelaptorTests/Content/TextureTests.cs index 915a456a7..963311a25 100644 --- a/Testing/VelaptorTests/Content/TextureTests.cs +++ b/Testing/VelaptorTests/Content/TextureTests.cs @@ -7,10 +7,11 @@ namespace VelaptorTests.Content; using System; using System.Collections.Generic; using System.Drawing; +using System.Linq; using Carbonate.Core.OneWay; using Carbonate.OneWay; using FluentAssertions; -using Moq; +using NSubstitute; using Velaptor.Content; using Velaptor.Factories; using Velaptor.Graphics; @@ -28,10 +29,10 @@ public class TextureTests private const string TextureName = "test-texture"; private const string TexturePath = @"C:\temp\test-texture.png"; private const uint TextureId = 1234; - private readonly Mock mockGL; - private readonly Mock mockGLService; - private readonly Mock mockDisposeUnsubscriber; - private readonly Mock mockReactableFactory; + private readonly IGLInvoker mockGL; + private readonly IOpenGLService mockGLService; + private readonly IDisposable mockDisposeUnsubscriber; + private readonly IReactableFactory mockReactableFactory; private readonly ImageData imageData; private IReceiveSubscription? disposeReactor; @@ -75,34 +76,36 @@ public TextureTests() } } - this.mockGL = new Mock(); - this.mockGL.Setup(m => m.GenTexture()).Returns(TextureId); + this.mockGL = Substitute.For(); + this.mockGL.GenTexture().Returns(TextureId); - this.mockGLService = new Mock(); - this.mockDisposeUnsubscriber = new Mock(); + this.mockGLService = Substitute.For(); + this.mockDisposeUnsubscriber = Substitute.For(); - var mockDisposeReactable = new Mock>(); - mockDisposeReactable.Setup(m => m.Subscribe(It.IsAny>())) - .Returns(this.mockDisposeUnsubscriber.Object) - .Callback>(reactor => + var mockDisposeReactable = Substitute.For>(); + mockDisposeReactable.Subscribe(Arg.Any>()) + .Returns(this.mockDisposeUnsubscriber) + .AndDoes(callInfo => { + var reactor = callInfo.Arg>(); reactor.Should().NotBeNull("It is required for unit testing."); this.disposeReactor = reactor; }); - this.mockReactableFactory = new Mock(); - this.mockReactableFactory.Setup(m => m.CreateDisposeTextureReactable()).Returns(mockDisposeReactable.Object); + this.mockReactableFactory = Substitute.For(); + this.mockReactableFactory.CreateDisposeTextureReactable().Returns(mockDisposeReactable); } #region Constructor Tests + [Fact] public void InternalCtor_WithNullGLParam_ThrowsException() { // Arrange & Act var act = () => new Texture( null, - this.mockGLService.Object, - this.mockReactableFactory.Object, + this.mockGLService, + this.mockReactableFactory, TextureName, TexturePath, this.imageData); @@ -117,9 +120,9 @@ public void InternalCtor_WithNullOpenGLServiceParam_ThrowsException() { // Arrange & Act var act = () => new Texture( - this.mockGL.Object, + this.mockGL, null, - this.mockReactableFactory.Object, + this.mockReactableFactory, TextureName, TexturePath, this.imageData); @@ -134,8 +137,8 @@ public void InternalCtor_WithNullReactableFactoryParam_ThrowsException() { // Arrange & Act var act = () => new Texture( - this.mockGL.Object, - this.mockGLService.Object, + this.mockGL, + this.mockGLService, null, TextureName, TexturePath, @@ -151,9 +154,9 @@ public void InternalCtor_WithNullName_ThrowsException() { // Arrange & Act var act = () => new Texture( - this.mockGL.Object, - this.mockGLService.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockGLService, + this.mockReactableFactory, null, TexturePath, this.imageData); @@ -168,9 +171,9 @@ public void InternalCtor_WithEmptyName_ThrowsException() { // Arrange & Act var act = () => new Texture( - this.mockGL.Object, - this.mockGLService.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockGLService, + this.mockReactableFactory, string.Empty, TexturePath, this.imageData); @@ -185,9 +188,9 @@ public void InternalCtor_WithNullFilePath_ThrowsException() { // Act & Assert var act = () => new Texture( - this.mockGL.Object, - this.mockGLService.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockGLService, + this.mockReactableFactory, TextureName, null, this.imageData); @@ -202,9 +205,9 @@ public void InternalCtor_WithEmptyFilePath_ThrowsException() { // Act & Assert var act = () => new Texture( - this.mockGL.Object, - this.mockGLService.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockGLService, + this.mockReactableFactory, TextureName, string.Empty, this.imageData); @@ -250,39 +253,38 @@ public void InternalCtor_WhenInvoked_UploadsTextureDataToGpu() // Act _ = new Texture( - this.mockGL.Object, - this.mockGLService.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockGLService, + this.mockReactableFactory, "test-texture.png", @"C:\temp\test-texture.png", this.imageData); // Assert - this.mockGLService.Verify(m => m.LabelTexture(TextureId, "test-texture.png"), - Times.Once()); - this.mockGL.Verify(m => m.TexParameter( + this.mockGLService.Received(1).LabelTexture(TextureId, "test-texture.png"); + this.mockGL.Received(1).TexParameter( GLTextureTarget.Texture2D, GLTextureParameterName.TextureMinFilter, - GLTextureMinFilter.Linear), Times.Once()); + GLTextureMinFilter.Linear); - this.mockGL.Verify(m => m.TexParameter( + this.mockGL.Received(1).TexParameter( GLTextureTarget.Texture2D, GLTextureParameterName.TextureMagFilter, - GLTextureMagFilter.Linear), Times.Once()); + GLTextureMagFilter.Linear); - this.mockGL.Verify(m => m.TexParameter( + this.mockGL.Received(1).TexParameter( GLTextureTarget.Texture2D, GLTextureParameterName.TextureWrapS, - GLTextureWrapMode.ClampToEdge), Times.Once()); + GLTextureWrapMode.ClampToEdge); - this.mockGL.Verify(m => m.TexParameter( + this.mockGL.Received(1).TexParameter( GLTextureTarget.Texture2D, GLTextureParameterName.TextureWrapT, - GLTextureWrapMode.ClampToEdge), Times.Once()); + GLTextureWrapMode.ClampToEdge); var expectedPixelArray = expectedPixelData.ToArray(); - this.mockGL.Verify(m => m.TexImage2D( + this.mockGL.Received(1).TexImage2D( GLTextureTarget.Texture2D, 0, GLInternalFormat.Rgba, @@ -291,14 +293,16 @@ public void InternalCtor_WhenInvoked_UploadsTextureDataToGpu() 0, GLPixelFormat.Rgba, GLPixelType.UnsignedByte, - expectedPixelArray), Times.Once()); + Arg.Is(actualPixelArray => actualPixelArray.SequenceEqual(expectedPixelArray))); - this.mockGLService.Verify(m => m.BindTexture2D(TextureId), Times.Once); - this.mockGLService.Verify(m => m.UnbindTexture2D(), Times.Once); + this.mockGLService.Received(1).BindTexture2D(TextureId); + this.mockGLService.Received(1).UnbindTexture2D(); } + #endregion #region Prop Tests + [Fact] public void Id_WhenCreatingTexture_ReturnsCorrectResult() { @@ -363,9 +367,11 @@ public void Height_WhenCreatingTexture_ReturnsCorrectResult() // Assert actual.Should().Be(3u); } + #endregion #region Method Tests + [Fact] public void ReactableNotifications_WithDifferentTextureID_DoesNotDisposeOfTexture() { @@ -378,8 +384,8 @@ public void ReactableNotifications_WithDifferentTextureID_DoesNotDisposeOfTextur this.disposeReactor?.OnReceive(disposeTextureData); // Assert - this.mockGL.Verify(m => m.DeleteTexture(It.IsAny()), Times.Never); - this.mockDisposeUnsubscriber.Verify(m => m.Dispose(), Times.Never); + this.mockGL.DidNotReceive().DeleteTexture(Arg.Any()); + this.mockDisposeUnsubscriber.DidNotReceive().Dispose(); } [Fact] @@ -394,8 +400,10 @@ public void ReactableNotifications_WhenPushingDisposeTextureNotification_Dispose this.disposeReactor?.OnReceive(disposeTextureData); // Assert - this.mockGL.Verify(m => m.DeleteTexture(TextureId), Times.Once()); + // this.mockGL.Verify(m => m.DeleteTexture(TextureId), Times.Once()); + this.mockGL.Received(1).DeleteTexture(TextureId); } + #endregion /// @@ -404,9 +412,9 @@ public void ReactableNotifications_WhenPushingDisposeTextureNotification_Dispose /// The texture instance to test. private Texture CreateSystemUnderTest(bool useEmptyData = false) => new ( - this.mockGL.Object, - this.mockGLService.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockGLService, + this.mockReactableFactory, TextureName, TexturePath, useEmptyData ? default : this.imageData); diff --git a/Testing/VelaptorTests/ExtensionMethods/GpuDataTypeExtensionsTests.cs b/Testing/VelaptorTests/ExtensionMethods/GpuDataTypeExtensionsTests.cs index bbac44977..5c4cf3422 100644 --- a/Testing/VelaptorTests/ExtensionMethods/GpuDataTypeExtensionsTests.cs +++ b/Testing/VelaptorTests/ExtensionMethods/GpuDataTypeExtensionsTests.cs @@ -10,7 +10,6 @@ namespace VelaptorTests.ExtensionMethods; using System.Drawing; using System.Numerics; using FluentAssertions; -using Moq; using Velaptor.ExtensionMethods; using Velaptor.OpenGL; using Velaptor.OpenGL.GpuData; @@ -32,7 +31,7 @@ public void SetVertexPos_WithRectGpuDataAndInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetVertexPos(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetVertexPos(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -111,7 +110,7 @@ public void SetRectangle_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetRectangle(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetRectangle(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -185,7 +184,7 @@ public void SetAsSolid_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetAsSolid(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetAsSolid(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -258,7 +257,7 @@ public void SetBorderThickness_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetBorderThickness(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetBorderThickness(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -332,7 +331,7 @@ public void SetTopLeftCornerRadius_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetTopLeftCornerRadius(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetTopLeftCornerRadius(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -406,7 +405,7 @@ public void SetBottomLeftCornerRadius_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetBottomLeftCornerRadius(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetBottomLeftCornerRadius(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -480,7 +479,7 @@ public void SetBottomRightCornerRadius_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetBottomRightCornerRadius(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetBottomRightCornerRadius(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -554,7 +553,7 @@ public void SetTopRightCornerRadius_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetTopRightCornerRadius(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetTopRightCornerRadius(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() @@ -628,7 +627,7 @@ public void SetColor_WithInvalidVertexValue_ThrowsException() var gpuData = GenerateGpuDataInSequence(0); // Act - var act = () => gpuData.SetColor(It.IsAny(), (VertexNumber)invalidValue); + var act = () => gpuData.SetColor(default, (VertexNumber)invalidValue); // Assert act.Should().Throw() diff --git a/Testing/VelaptorTests/Factories/NativeInputFactoryTests.cs b/Testing/VelaptorTests/Factories/NativeInputFactoryTests.cs index be81f1a13..bf51be96a 100644 --- a/Testing/VelaptorTests/Factories/NativeInputFactoryTests.cs +++ b/Testing/VelaptorTests/Factories/NativeInputFactoryTests.cs @@ -6,7 +6,7 @@ namespace VelaptorTests.Factories; using System; using FluentAssertions; -using Moq; +using NSubstitute; using Velaptor.Factories; using Xunit; @@ -35,7 +35,7 @@ public void Ctor_WithNullWindowFactoryParam_ThrowsException() public void Ctor_WithNonNullWindowFactoryParam_DoesNotThrowException() { // Arrange & Act - var act = () => _ = new NativeInputFactory(new Mock().Object); + var act = () => _ = new NativeInputFactory(Substitute.For()); // Assert act.Should().NotThrow(); diff --git a/Testing/VelaptorTests/Graphics/ImageLoaderTests.cs b/Testing/VelaptorTests/Graphics/ImageLoaderTests.cs index 3291649e9..9e64627ea 100644 --- a/Testing/VelaptorTests/Graphics/ImageLoaderTests.cs +++ b/Testing/VelaptorTests/Graphics/ImageLoaderTests.cs @@ -8,8 +8,7 @@ namespace VelaptorTests.Graphics; using System.Drawing; using System.IO.Abstractions; using FluentAssertions; -using Helpers; -using Moq; +using NSubstitute; using Velaptor.Content; using Velaptor.Graphics; using Velaptor.Services; @@ -20,28 +19,29 @@ namespace VelaptorTests.Graphics; /// public class ImageLoaderTests { - private readonly Mock mockPath; - private readonly Mock mockImageService; - private readonly Mock mockTexturePathResolver; + private readonly IPath mockPath; + private readonly IImageService mockImageService; + private readonly IContentPathResolver mockTexturePathResolver; /// /// Initializes a new instance of the class. /// public ImageLoaderTests() { - this.mockPath = new Mock(); - this.mockImageService = new Mock(); - this.mockTexturePathResolver = new Mock(); + this.mockPath = Substitute.For(); + this.mockImageService = Substitute.For(); + this.mockTexturePathResolver = Substitute.For(); } #region Constructor Tests + [Fact] public void Ctor_WithNullPathParam_ThrowsException() { // Arrange & Act var act = () => { - _ = new ImageLoader(null, this.mockImageService.Object, this.mockTexturePathResolver.Object); + _ = new ImageLoader(null, this.mockImageService, this.mockTexturePathResolver); }; // Assert @@ -56,7 +56,7 @@ public void Ctor_WithNullImageServiceParam_ThrowsException() // Arrange & Act var act = () => { - _ = new ImageLoader(this.mockPath.Object, null, this.mockTexturePathResolver.Object); + _ = new ImageLoader(this.mockPath, null, this.mockTexturePathResolver); }; // Assert @@ -71,7 +71,7 @@ public void Ctor_WithNullTexturePathResolverParam_ThrowsException() // Arrange & Act var act = () => { - _ = new ImageLoader(this.mockPath.Object, this.mockImageService.Object, null); + _ = new ImageLoader(this.mockPath, this.mockImageService, null); }; // Assert @@ -79,9 +79,11 @@ public void Ctor_WithNullTexturePathResolverParam_ThrowsException() .Throw() .WithMessage("Value cannot be null. (Parameter 'texturePathResolver')"); } + #endregion #region Method Tests + [Fact] public void LoadImage_WithAbsoluteFilePath_LoadsImageData() { @@ -89,9 +91,9 @@ public void LoadImage_WithAbsoluteFilePath_LoadsImageData() const string filePath = "test-file-path"; var expected = new ImageData(new Color[2, 4], filePath); - this.mockPath.Setup(m => m.IsPathRooted(It.IsAny())).Returns(true); - this.mockImageService.Setup(m => m.Load(filePath)) - .Returns(_ => new ImageData(new Color[2, 4], filePath)); + this.mockPath.IsPathRooted(Arg.Any()).Returns(true); + this.mockImageService.Load(filePath) + .Returns(_ => new ImageData(new Color[2, 4], filePath)); var sut = CreateSystemUnderTest(); // Act @@ -99,7 +101,7 @@ public void LoadImage_WithAbsoluteFilePath_LoadsImageData() // Assert actual.Should().Be(expected); - this.mockImageService.VerifyOnce(m => m.Load(filePath)); + this.mockImageService.Received(1).Load(filePath); } [Fact] @@ -109,11 +111,11 @@ public void LoadImage_WithRelativeFilePath_LoadsImageData() const string filePath = "test-file-path"; var expected = new ImageData(new Color[2, 4], filePath); - this.mockTexturePathResolver.Setup(m => m.ResolveFilePath(It.IsAny())) + this.mockTexturePathResolver.ResolveFilePath(Arg.Any()) .Returns(filePath); - this.mockPath.Setup(m => m.IsPathRooted(It.IsAny())).Returns(false); - this.mockImageService.Setup(m => m.Load(filePath)) - .Returns(_ => new ImageData(new Color[2, 4], filePath)); + this.mockPath.IsPathRooted(Arg.Any()).Returns(false); + this.mockImageService.Load(filePath) + .Returns(_ => new ImageData(new Color[2, 4], filePath)); var sut = CreateSystemUnderTest(); // Act @@ -121,8 +123,9 @@ public void LoadImage_WithRelativeFilePath_LoadsImageData() // Assert actual.Should().Be(expected); - this.mockImageService.VerifyOnce(m => m.Load(filePath)); + this.mockImageService.Received(1).Load(filePath); } + #endregion /// @@ -130,5 +133,5 @@ public void LoadImage_WithRelativeFilePath_LoadsImageData() /// /// The instance to test. private ImageLoader CreateSystemUnderTest() - => new (this.mockPath.Object, this.mockImageService.Object, this.mockTexturePathResolver.Object); + => new (this.mockPath, this.mockImageService, this.mockTexturePathResolver); } diff --git a/Testing/VelaptorTests/Graphics/RenderMediatorTests.cs b/Testing/VelaptorTests/Graphics/RenderMediatorTests.cs index 987e4b601..8364bafe1 100644 --- a/Testing/VelaptorTests/Graphics/RenderMediatorTests.cs +++ b/Testing/VelaptorTests/Graphics/RenderMediatorTests.cs @@ -10,7 +10,7 @@ namespace VelaptorTests.Graphics; using Carbonate.NonDirectional; using FluentAssertions; using Helpers; -using Moq; +using NSubstitute; using Velaptor; using Velaptor.Batching; using Velaptor.Factories; @@ -23,20 +23,20 @@ namespace VelaptorTests.Graphics; /// public class RenderMediatorTests : TestsBase { - private readonly Mock mockReactableFactory; - private readonly Mock mockPushReactable; - private readonly Mock>> mockTextureComparer; - private readonly Mock>> mockFontComparer; - private readonly Mock>> mockShapeComparer; - private readonly Mock>> mockLineComparer; - private readonly Mock> mockTextureRenderBatchReactable; - private readonly Mock> mockFontRenderBatchReactable; - private readonly Mock> mockShapeRenderBatchReactable; - private readonly Mock> mockLineRenderBatchReactable; - private readonly Mock> mockTexturePullReactable; - private readonly Mock> mockFontPullReactable; - private readonly Mock> mockShapePullReactable; - private readonly Mock> mockLinePullReactable; + private readonly IReactableFactory mockReactableFactory; + private readonly IPushReactable mockPushReactable; + private readonly IComparer> mockTextureComparer; + private readonly IComparer> mockFontComparer; + private readonly IComparer> mockShapeComparer; + private readonly IComparer> mockLineComparer; + private readonly IRenderBatchReactable mockTextureRenderBatchReactable; + private readonly IRenderBatchReactable mockFontRenderBatchReactable; + private readonly IRenderBatchReactable mockShapeRenderBatchReactable; + private readonly IRenderBatchReactable mockLineRenderBatchReactable; + private readonly IBatchPullReactable mockTexturePullReactable; + private readonly IBatchPullReactable mockFontPullReactable; + private readonly IBatchPullReactable mockShapePullReactable; + private readonly IBatchPullReactable mockLinePullReactable; private IReceiveSubscription? endBatchReactor; @@ -45,51 +45,54 @@ public class RenderMediatorTests : TestsBase /// public RenderMediatorTests() { - var mockEndBatchUnsubscriber = new Mock(); - - this.mockPushReactable = new Mock(); - this.mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.endBatchReactor = reactor) - .Returns(_ => mockEndBatchUnsubscriber.Object); - - this.mockTexturePullReactable = new Mock>(); - this.mockFontPullReactable = new Mock>(); - this.mockShapePullReactable = new Mock>(); - this.mockLinePullReactable = new Mock>(); - - this.mockTextureRenderBatchReactable = new Mock>(); - this.mockFontRenderBatchReactable = new Mock>(); - this.mockShapeRenderBatchReactable = new Mock>(); - this.mockLineRenderBatchReactable = new Mock>(); - - this.mockReactableFactory = new Mock(); - this.mockReactableFactory.Setup(m => m.CreateNoDataPushReactable()).Returns(this.mockPushReactable.Object); - - this.mockReactableFactory.Setup(m => m.CreateTexturePullBatchReactable()) - .Returns(this.mockTexturePullReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateFontPullBatchReactable()). - Returns(this.mockFontPullReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateShapePullBatchReactable()). - Returns(this.mockShapePullReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateLinePullBatchReactable()). - Returns(this.mockLinePullReactable.Object); - - this.mockReactableFactory.Setup(m => m.CreateRenderTextureReactable()) - .Returns(this.mockTextureRenderBatchReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateRenderFontReactable()) - .Returns(this.mockFontRenderBatchReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateRenderShapeReactable()) - .Returns(this.mockShapeRenderBatchReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateRenderLineReactable()) - .Returns(this.mockLineRenderBatchReactable.Object); - - this.mockTextureComparer = new Mock>>(); - this.mockFontComparer = new Mock>>(); - this.mockShapeComparer = new Mock>>(); - this.mockLineComparer = new Mock>>(); + var mockEndBatchUnsubscriber = Substitute.For(); + this.mockPushReactable = Substitute.For(); + this.mockPushReactable + .Subscribe(Arg.Any()) + .Returns(_ => mockEndBatchUnsubscriber) + .AndDoes(ci => + { + this.endBatchReactor = ci.Arg(); + }); + + this.mockTexturePullReactable = Substitute.For>(); + this.mockFontPullReactable = Substitute.For>(); + this.mockShapePullReactable = Substitute.For>(); + this.mockLinePullReactable = Substitute.For>(); + + this.mockTextureRenderBatchReactable = Substitute.For>(); + this.mockFontRenderBatchReactable = Substitute.For>(); + this.mockShapeRenderBatchReactable = Substitute.For>(); + this.mockLineRenderBatchReactable = Substitute.For>(); + + this.mockReactableFactory = Substitute.For(); + this.mockReactableFactory.CreateNoDataPushReactable().Returns(this.mockPushReactable); + + this.mockReactableFactory.CreateTexturePullBatchReactable() + .Returns(this.mockTexturePullReactable); + this.mockReactableFactory.CreateFontPullBatchReactable() + .Returns(this.mockFontPullReactable); + this.mockReactableFactory.CreateShapePullBatchReactable() + .Returns(this.mockShapePullReactable); + this.mockReactableFactory.CreateLinePullBatchReactable() + .Returns(this.mockLinePullReactable); + this.mockReactableFactory.CreateRenderTextureReactable() + .Returns(this.mockTextureRenderBatchReactable); + this.mockReactableFactory.CreateRenderFontReactable() + .Returns(this.mockFontRenderBatchReactable); + this.mockReactableFactory.CreateRenderShapeReactable() + .Returns(this.mockShapeRenderBatchReactable); + this.mockReactableFactory.CreateRenderLineReactable() + .Returns(this.mockLineRenderBatchReactable); + + this.mockTextureComparer = Substitute.For>>(); + this.mockFontComparer = Substitute.For>>(); + this.mockShapeComparer = Substitute.For>>(); + this.mockLineComparer = Substitute.For>>(); } #region Constructor Tests + [Fact] public void Ctor_WithNullReactableFactoryParam_ThrowsException() { @@ -98,10 +101,10 @@ public void Ctor_WithNullReactableFactoryParam_ThrowsException() { _ = new RenderMediator( null, - this.mockTextureComparer.Object, - this.mockFontComparer.Object, - this.mockShapeComparer.Object, - this.mockLineComparer.Object); + this.mockTextureComparer, + this.mockFontComparer, + this.mockShapeComparer, + this.mockLineComparer); }; // Assert @@ -117,11 +120,11 @@ public void Ctor_WithNullTextureItemComparerParam_ThrowsException() var act = () => { _ = new RenderMediator( - this.mockReactableFactory.Object, + this.mockReactableFactory, null, - this.mockFontComparer.Object, - this.mockShapeComparer.Object, - this.mockLineComparer.Object); + this.mockFontComparer, + this.mockShapeComparer, + this.mockLineComparer); }; // Assert @@ -137,11 +140,11 @@ public void Ctor_WithNullFontItemComparerParam_ThrowsException() var act = () => { _ = new RenderMediator( - this.mockReactableFactory.Object, - this.mockTextureComparer.Object, + this.mockReactableFactory, + this.mockTextureComparer, null, - this.mockShapeComparer.Object, - this.mockLineComparer.Object); + this.mockShapeComparer, + this.mockLineComparer); }; // Assert @@ -157,11 +160,11 @@ public void Ctor_WithNullShapeItemComparerParam_ThrowsException() var act = () => { _ = new RenderMediator( - this.mockReactableFactory.Object, - this.mockTextureComparer.Object, - this.mockFontComparer.Object, + this.mockReactableFactory, + this.mockTextureComparer, + this.mockFontComparer, null, - this.mockLineComparer.Object); + this.mockLineComparer); }; // Assert @@ -177,10 +180,10 @@ public void Ctor_WithNullNullItemComparerParam_ThrowsException() var act = () => { _ = new RenderMediator( - this.mockReactableFactory.Object, - this.mockTextureComparer.Object, - this.mockFontComparer.Object, - this.mockShapeComparer.Object, + this.mockReactableFactory, + this.mockTextureComparer, + this.mockFontComparer, + this.mockShapeComparer, null); }; @@ -189,9 +192,11 @@ public void Ctor_WithNullNullItemComparerParam_ThrowsException() .Throw() .WithMessage("Value cannot be null. (Parameter 'lineItemComparer')"); } + #endregion #region Indirect Tests + [Fact] public void PushReactable_WithBatchEndNotification_CoordinatesRenderCalls() { @@ -211,33 +216,37 @@ public void PushReactable_WithBatchEndNotification_CoordinatesRenderCalls() var shapeItems = new[] { shapeItemA, shapeItemB }; var lineItems = new[] { lineItemA, lineItemB }; - this.mockTexturePullReactable.Setup(m => m.Pull(It.IsAny())) - .Returns(_ => new Memory>(textureItems)); + this.mockTexturePullReactable + .Pull(Arg.Any()) + .Returns(_ => new Memory>(textureItems)); - this.mockFontPullReactable.Setup(m => m.Pull(It.IsAny())) - .Returns(_ => new Memory>(fontItems)); + this.mockFontPullReactable + .Pull(Arg.Any()) + .Returns(_ => new Memory>(fontItems)); - this.mockShapePullReactable.Setup(m => m.Pull(It.IsAny())) - .Returns(_ => new Memory>(shapeItems)); + this.mockShapePullReactable + .Pull(Arg.Any()) + .Returns(_ => new Memory>(shapeItems)); - this.mockLinePullReactable.Setup(m => m.Pull(It.IsAny())) - .Returns(_ => new Memory>(lineItems)); + this.mockLinePullReactable + .Pull(Arg.Any()) + .Returns(_ => new Memory>(lineItems)); this.mockTextureRenderBatchReactable - .Setup(m => m.Push(It.IsAny(), It.Ref>>.IsAny)) - .Callback(AssertTextureItems); + .When(x => x.Push(Arg.Any(), Arg.Any>>())) + .Do(ci => AssertTextureItems(ci.Arg(), ci.Arg>>())); this.mockFontRenderBatchReactable - .Setup(m => m.Push(It.IsAny(), It.Ref>>.IsAny)) - .Callback(AssertFontItems); + .When(x => x.Push(Arg.Any(), Arg.Any>>())) + .Do(ci => AssertFontItems(ci.Arg(), ci.Arg>>())); this.mockShapeRenderBatchReactable - .Setup(m => m.Push(It.IsAny(), It.Ref>>.IsAny)) - .Callback(AssertShapeItems); + .When(x => x.Push(Arg.Any(), Arg.Any>>())) + .Do(ci => AssertShapeItems(ci.Arg(), ci.Arg>>())); this.mockLineRenderBatchReactable - .Setup(m => m.Push(It.IsAny(), It.Ref>>.IsAny)) - .Callback(AssertLineItems); + .When(x => x.Push(Arg.Any(), Arg.Any>>())) + .Do(ci => AssertLineItems(ci.Arg(), ci.Arg>>())); _ = CreateSystemUnderTest(); @@ -245,10 +254,10 @@ public void PushReactable_WithBatchEndNotification_CoordinatesRenderCalls() this.endBatchReactor.OnReceive(); // Assert - this.mockTexturePullReactable.VerifyOnce(m => m.Pull(PullResponses.GetTextureItemsId)); - this.mockFontPullReactable.VerifyOnce(m => m.Pull(PullResponses.GetFontItemsId)); - this.mockShapePullReactable.VerifyOnce(m => m.Pull(PullResponses.GetShapeItemsId)); - this.mockLinePullReactable.VerifyOnce(m => m.Pull(PullResponses.GetLineItemsId)); + this.mockTexturePullReactable.Received(1).Pull(PullResponses.GetTextureItemsId); + this.mockFontPullReactable.Received(1).Pull(PullResponses.GetFontItemsId); + this.mockShapePullReactable.Received(1).Pull(PullResponses.GetShapeItemsId); + this.mockLinePullReactable.Received(1).Pull(PullResponses.GetLineItemsId); void AssertTextureItems(Guid eventId, in Memory> data) { @@ -274,19 +283,23 @@ void AssertLineItems(Guid eventId, in Memory> data) data.Span.ToArray().Should().HaveCount(2); } - this.mockPushReactable.VerifyOnce(m => m.Push(PushNotifications.EmptyBatchId)); + this.mockPushReactable.Received(1).Push(PushNotifications.EmptyBatchId); } + #endregion #region Reacteable Tests + [Fact] [Trait("Category", Subscription)] public void EndBatchReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly() { // Arrange & Assert - this.mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => + this.mockPushReactable + .When(x => x.Subscribe(Arg.Any())) + .Do(ci => { + var reactor = ci.Arg(); reactor.Should().NotBeNull("It is required for unit testing."); reactor.Name.Should().Be($"RenderMediator.ctor() - {PushNotifications.BatchHasEndedId}"); }); @@ -294,6 +307,7 @@ public void EndBatchReactable_WhenCreatingSubscription_CreatesSubscriptionCorrec // Act _ = CreateSystemUnderTest(); } + #endregion private static RenderItem CreateRenderItem(T item, int layer) => new () { Layer = layer, Item = item }; @@ -303,9 +317,9 @@ public void EndBatchReactable_WhenCreatingSubscription_CreatesSubscriptionCorrec /// /// The instance to test. private RenderMediator CreateSystemUnderTest() - => new (this.mockReactableFactory.Object, - this.mockTextureComparer.Object, - this.mockFontComparer.Object, - this.mockShapeComparer.Object, - this.mockLineComparer.Object); + => new (this.mockReactableFactory, + this.mockTextureComparer, + this.mockFontComparer, + this.mockShapeComparer, + this.mockLineComparer); } diff --git a/Testing/VelaptorTests/Graphics/Renderers/FontRendererTests.cs b/Testing/VelaptorTests/Graphics/Renderers/FontRendererTests.cs index 5adf198b0..af858e34e 100644 --- a/Testing/VelaptorTests/Graphics/Renderers/FontRendererTests.cs +++ b/Testing/VelaptorTests/Graphics/Renderers/FontRendererTests.cs @@ -13,7 +13,7 @@ namespace VelaptorTests.Graphics.Renderers; using Carbonate.NonDirectional; using FluentAssertions; using Helpers; -using Moq; +using NSubstitute; using Velaptor; using Velaptor.Batching; using Velaptor.Content; @@ -44,13 +44,13 @@ public class FontRendererTests : TestsBase private const uint AtlasTextureId = 1234u; private const uint FontShaderId = 2222u; private const char InvalidCharacter = '□'; - private readonly Mock mockGL; - private readonly Mock mockGLService; - private readonly Mock> mockGpuBuffer; - private readonly Mock mockShader; - private readonly Mock mockFont; - private readonly Mock mockBatchingManager; - private readonly Mock mockReactableFactory; + private readonly IGLInvoker mockGL; + private readonly IOpenGLService mockGLService; + private readonly IGpuBuffer mockGpuBuffer; + private readonly IShaderProgram mockShader; + private readonly IFont mockFont; + private readonly IBatchingManager mockBatchingManager; + private readonly IReactableFactory mockReactableFactory; private readonly char[] glyphChars = [ @@ -59,6 +59,7 @@ public class FontRendererTests : TestsBase '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '=', '~', '_', '+', '[', ']', '\\', ';', '\'', ',', '.', '/', '{', '}', '|', ':', '"', '<', '>', '?', ' ', ]; + private IReceiveSubscription? batchHasBegunReactor; private FontRenderItem? renderReactor; @@ -69,45 +70,53 @@ public class FontRendererTests : TestsBase /// public FontRendererTests() { - this.mockGL = new Mock(); + this.mockGL = Substitute.For(); - this.mockGLService = new Mock(); - this.mockGLService.Setup(m => m.ProgramLinkedSuccessfully(It.IsAny())).Returns(true); - this.mockGLService.Setup(m => m.ShaderCompiledSuccessfully(It.IsAny())).Returns(true); - this.mockGLService.Setup(m => m.GetViewPortSize()).Returns(new Size(800, 600)); + this.mockGLService = Substitute.For(); + this.mockGLService.ProgramLinkedSuccessfully(Arg.Any()).Returns(true); + this.mockGLService.ShaderCompiledSuccessfully(Arg.Any()).Returns(true); + this.mockGLService.GetViewPortSize().Returns(new Size(800, 600)); - this.mockShader = new Mock(); - this.mockShader.SetupGet(p => p.ShaderId).Returns(FontShaderId); + this.mockShader = Substitute.For(); + this.mockShader.ShaderId.Returns(FontShaderId); - this.mockGpuBuffer = new Mock>(); + this.mockGpuBuffer = Substitute.For>(); - this.mockBatchingManager = new Mock(); + this.mockBatchingManager = Substitute.For(); - var mockPushReactable = new Mock(); - mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.batchHasBegunReactor = reactor); + var mockPushReactable = Substitute.For(); + mockPushReactable + .When(x => x.Subscribe(Arg.Any())) + .Do(ci => + { + var reactor = ci.Arg(); + this.batchHasBegunReactor = reactor; + }); - var mockFontRenderBatchReactable = new Mock>(); + var mockFontRenderBatchReactable = Substitute.For>(); mockFontRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.renderReactor = reactor); - - this.mockReactableFactory = new Mock(); - this.mockReactableFactory.Setup(m => m.CreateNoDataPushReactable()) - .Returns(mockPushReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateRenderFontReactable()) - .Returns(mockFontRenderBatchReactable.Object); - - var mockFontTextureAtlas = new Mock(); - mockFontTextureAtlas.SetupGet(p => p.Width).Returns(200); - mockFontTextureAtlas.SetupGet(p => p.Height).Returns(100); - - this.mockFont = new Mock(); - this.mockFont.SetupGet(p => p.Atlas).Returns(mockFontTextureAtlas.Object); - this.mockFont.SetupGet(p => p.Size).Returns(12u); + .When(x => x.Subscribe(Arg.Any())) + .Do(ci => + { + var reactor = ci.Arg(); + this.renderReactor = reactor; + }); + + this.mockReactableFactory = Substitute.For(); + this.mockReactableFactory.CreateNoDataPushReactable().Returns(mockPushReactable); + this.mockReactableFactory.CreateRenderFontReactable().Returns(mockFontRenderBatchReactable); + + var mockFontTextureAtlas = Substitute.For(); + mockFontTextureAtlas.Width.Returns(200u); + mockFontTextureAtlas.Height.Returns(100u); + + this.mockFont = Substitute.For(); + this.mockFont.Atlas.Returns(mockFontTextureAtlas); + this.mockFont.Size.Returns(12u); } #region Constructor Tests + [Fact] [Trait("Category", Ctor)] public void Ctor_WithNullOpenGLServiceParam_ThrowsException() @@ -116,12 +125,12 @@ public void Ctor_WithNullOpenGLServiceParam_ThrowsException() var act = () => { _ = new FontRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockReactableFactory, null, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -138,12 +147,12 @@ public void Ctor_WithNullBufferParam_ThrowsException() var act = () => { _ = new FontRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, null, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -160,12 +169,12 @@ public void Ctor_WithNullShaderParam_ThrowsException() var act = () => { _ = new FontRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, null, - this.mockBatchingManager.Object); + this.mockBatchingManager); }; // Assert @@ -182,11 +191,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() var act = () => { _ = new FontRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, null); }; @@ -195,9 +204,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() .Throw() .WithMessage("Value cannot be null. (Parameter 'batchManager')"); } + #endregion #region Method Tests + [Fact] [Trait("Category", Method)] public void Render_WithNullFont_ThrowsException() @@ -219,30 +230,37 @@ public void Render_WithNoFontItemsToRender_SetsUpCorrectDebugGroupAndExits() { // Arrange const string shaderName = "TestFontShader"; - this.mockShader.Setup(m => m.Name).Returns(shaderName); + this.mockShader.Name.Returns(shaderName); _ = CreateSystemUnderTest(); // Act this.renderReactor.OnReceive(default); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render Text Process - Nothing To Render")); - this.mockGLService.VerifyOnce(m => m.EndGroup()); - this.mockGLService.VerifyNever(m => m.BeginGroup($"Render Text Process With {shaderName} Shader")); - this.mockShader.VerifyNever(m => m.Use()); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Update Character Data - TextureID")))); - this.mockGL.VerifyNever(m => m.ActiveTexture(It.IsAny())); - this.mockGLService.VerifyNever(m => m.BindTexture2D(It.IsAny())); - this.mockGpuBuffer.VerifyNever(m => - m.UploadData(It.IsAny(), It.IsAny())); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Render ") && value.EndsWith(" Font Elements")))); - this.mockGL.VerifyNever(m => m.DrawElements( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())); + this.mockGLService.Received(1).BeginGroup("Render Text Process - Nothing To Render"); + this.mockGLService.Received(1).EndGroup(); + this.mockGLService.DidNotReceive().BeginGroup($"Render Text Process With {shaderName} Shader"); + this.mockShader.DidNotReceive().Use(); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Update Character Data - TextureID"))); + this.mockGL.DidNotReceive().ActiveTexture(Arg.Any()); + this.mockGLService + .DidNotReceive() + .BindTexture2D(Arg.Any()); + this.mockGpuBuffer + .DidNotReceive() + .UploadData(Arg.Any(), Arg.Any()); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Render ") && value.EndsWith(" Font Elements"))); + this.mockGL + .DidNotReceive() + .DrawElements( + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any()); } [Theory] @@ -257,19 +275,20 @@ public void Render_WithNullOrEmptyText_DoesNotRenderText(string? renderText) // Act sut.Render( - new Mock().Object, - renderText, - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + font: Substitute.For(), + text: renderText, + x: default, + y: default, + renderSize: default, + angle: default, + color: default); // Assert - this.mockFont.VerifyNever(m => m.Measure(It.IsAny())); - this.mockFont.VerifyNever(m => m.ToGlyphMetrics(It.IsAny())); + this.mockFont.DidNotReceive().Measure(Arg.Any()); + this.mockFont.DidNotReceive().ToGlyphMetrics(Arg.Any()); this.mockBatchingManager - .VerifyNever(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())); + .DidNotReceive() + .AddFontItem(Arg.Any(), Arg.Any(), Arg.Any()); } [Fact] @@ -277,26 +296,27 @@ public void Render_WithNullOrEmptyText_DoesNotRenderText(string? renderText) public void Render_WithFontSizeSetToZero_DoesNotRenderText() { // Arrange - this.mockFont.SetupGet(p => p.Size).Returns(0); + this.mockFont.Size.Returns(0u); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act sut.Render( - this.mockFont.Object, - "test-text", - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + font: this.mockFont, + text: "test-text", + x: default, + y: default, + renderSize: default, + angle: default, + color: default); // Assert - this.mockFont.VerifyNever(m => m.Measure(It.IsAny())); - this.mockFont.VerifyNever(m => m.ToGlyphMetrics(It.IsAny())); + this.mockFont.DidNotReceive().Measure(Arg.Any()); + this.mockFont.DidNotReceive().ToGlyphMetrics(Arg.Any()); this.mockBatchingManager - .VerifyNever(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())); + .DidNotReceive() + .AddFontItem(Arg.Any(), Arg.Any(), Arg.Any()); } [Fact] @@ -310,13 +330,14 @@ public void Render_WhenNotCallingBeginFirst_ThrowsException() var sut = CreateSystemUnderTest(); // Act - var act = () => sut.Render(this.mockFont.Object, - renderText, - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + var act = () => sut.Render( + font: this.mockFont, + text: renderText, + x: default, + y: default, + renderSize: default, + angle: default, + color: default); // Assert act.Should().Throw() @@ -339,20 +360,20 @@ public void Render_WhenTextIsOnlyNewLineCharacters_DoesNotRenderText() // Act sut.Render( - this.mockFont.Object, - renderText, - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + font: this.mockFont, + text: renderText, + x: default, + y: default, + renderSize: default, + angle: default, + color: default); // Assert - this.mockFont.VerifyNever(m => m.ToGlyphMetrics(It.IsAny())); - this.mockFont.VerifyNever(m => m.GetKerning(It.IsAny(), It.IsAny())); + this.mockFont.DidNotReceive().ToGlyphMetrics(Arg.Any()); + this.mockFont.DidNotReceive().GetKerning(Arg.Any(), Arg.Any()); this.mockBatchingManager - .VerifyNever(m => - m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())); + .DidNotReceive() + .AddFontItem(Arg.Any(), Arg.Any(), Arg.Any()); } [Fact] @@ -368,16 +389,16 @@ public void Render_WhenInvoked_MeasuresText() // Act sut.Render( - this.mockFont.Object, - renderText, - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + font: this.mockFont, + text: renderText, + x: default, + y: default, + renderSize: default, + angle: default, + color: default); // Assert - this.mockFont.VerifyOnce(m => m.Measure(renderText)); + this.mockFont.Received(1).Measure(renderText); } [Fact] @@ -396,17 +417,17 @@ public void Render_WhenRenderingMultilineText_ConvertsEachLineToGlyphMetrics() // Act sut.Render( - this.mockFont.Object, - renderText, - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + font: this.mockFont, + text: renderText, + x: default, + y: default, + renderSize: default, + angle: default, + color: default); // Assert - this.mockFont.VerifyOnce(m => m.ToGlyphMetrics("hello")); - this.mockFont.VerifyOnce(m => m.ToGlyphMetrics("world")); + this.mockFont.Received(1).ToGlyphMetrics("hello"); + this.mockFont.Received(1).ToGlyphMetrics("world"); } [Fact] @@ -424,9 +445,10 @@ public void Render_WhenInvoked_AddsCorrectBatchItems() MockToGlyphMetrics(renderText); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(call => { + var item = call.Arg(); actualBatchResultData.Add(item); }); @@ -435,7 +457,7 @@ public void Render_WhenInvoked_AddsCorrectBatchItems() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, 400, 300, @@ -446,8 +468,8 @@ public void Render_WhenInvoked_AddsCorrectBatchItems() // Assert this.mockBatchingManager - .VerifyExactly(m => - m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny()), renderText.Length); + .Received(renderText.Length) + .AddFontItem(Arg.Any(), Arg.Any(), Arg.Any()); actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -471,9 +493,10 @@ public void Render_WhenInvoking4ParamsWithXAndYOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -482,15 +505,14 @@ public void Render_WhenInvoking4ParamsWithXAndYOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, 11, 22, 123); // Assert - this.mockBatchingManager - .VerifyExactly(m => m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + this.mockBatchingManager.Received(totalGlyphs).AddFontItem(Arg.Any(), 123, Arg.Any()); actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -514,9 +536,10 @@ public void Render_WhenInvoking3ParamsWithPositionOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -525,14 +548,15 @@ public void Render_WhenInvoking3ParamsWithPositionOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, new Vector2(33, 44), 123); // Assert this.mockBatchingManager - .VerifyExactly(m => m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + .Received(totalGlyphs) + .AddFontItem(Arg.Any(), 123, Arg.Any()); actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -556,9 +580,10 @@ public void Render_WhenInvoking6ParamsWithXAndYOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -567,7 +592,7 @@ public void Render_WhenInvoking6ParamsWithXAndYOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, 321, 202, @@ -577,8 +602,8 @@ public void Render_WhenInvoking6ParamsWithXAndYOverload_RendersFont() // Assert this.mockBatchingManager - .VerifyExactly(m => - m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + .Received(totalGlyphs) + .AddFontItem(Arg.Any(), 123, Arg.Any()); actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -602,9 +627,10 @@ public void Render_WhenInvoking5ParamsWithPositionOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -613,7 +639,7 @@ public void Render_WhenInvoking5ParamsWithPositionOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, new Vector2(66, 77), 1.25f, @@ -622,8 +648,8 @@ public void Render_WhenInvoking5ParamsWithPositionOverload_RendersFont() // Assert this.mockBatchingManager - .VerifyExactly(m => - m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + .Received(totalGlyphs) + .AddFontItem(Arg.Any(), 123, Arg.Any()); actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -647,9 +673,10 @@ public void Render_WhenInvoking5ParamsWithColorOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -658,7 +685,7 @@ public void Render_WhenInvoking5ParamsWithColorOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, 456, 635, @@ -667,8 +694,8 @@ public void Render_WhenInvoking5ParamsWithColorOverload_RendersFont() // Assert this.mockBatchingManager - .VerifyExactly(m => - m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + .Received(totalGlyphs) + .AddFontItem(Arg.Is(x => true), 123, Arg.Any()); actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -692,9 +719,10 @@ public void Render_WhenInvoking4ParamsWithPositionAndColorOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -703,7 +731,7 @@ public void Render_WhenInvoking4ParamsWithPositionAndColorOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, new Vector2(758, 137), Color.MediumPurple, @@ -711,8 +739,9 @@ public void Render_WhenInvoking4ParamsWithPositionAndColorOverload_RendersFont() // Assert this.mockBatchingManager - .VerifyExactly(m => - m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + .Received(totalGlyphs) + .AddFontItem(Arg.Is(x => true), 123, Arg.Any()); + actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -736,9 +765,10 @@ public void Render_WhenInvoking6ParamsWithColorOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -747,7 +777,7 @@ public void Render_WhenInvoking6ParamsWithColorOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, 147, 185, @@ -756,8 +786,10 @@ public void Render_WhenInvoking6ParamsWithColorOverload_RendersFont() 123); // Assert - this.mockBatchingManager.VerifyExactly(m => - m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + this.mockBatchingManager + .Received(totalGlyphs) + .AddFontItem(Arg.Is(x => true), 123, Arg.Any()); + actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -781,9 +813,10 @@ public void Render_WhenInvoking5ParamsWithPositionAndColorOverload_RendersFont() MockToGlyphMetrics("hello"); MockToGlyphMetrics("world"); this.mockBatchingManager - .Setup(m => m.AddFontItem(It.IsAny(), It.IsAny(), It.IsAny())) - .Callback((item, _, _) => + .When(m => m.AddFontItem(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(ci => { + var item = ci.Arg(); actualBatchResultData.Add(item); }); @@ -792,7 +825,7 @@ public void Render_WhenInvoking5ParamsWithPositionAndColorOverload_RendersFont() // Act sut.Render( - this.mockFont.Object, + this.mockFont, renderText, new Vector2(1255, 79), 88f, @@ -800,8 +833,10 @@ public void Render_WhenInvoking5ParamsWithPositionAndColorOverload_RendersFont() 123); // Assert - this.mockBatchingManager.VerifyExactly(m => - m.AddFontItem(It.IsAny(), 123, It.IsAny()), totalGlyphs); + this.mockBatchingManager + .Received(totalGlyphs) + .AddFontItem(Arg.Is(x => true), 123, Arg.Any()); + actualBatchResultData.Should().BeEquivalentTo(expectedBatchResultData); } @@ -817,8 +852,8 @@ public void Render_WhenInvoked_RendersFont() var renderItems = CreateFontRenderItems(renderText); - var mockFontTextureAtlas = new Mock(); - mockFontTextureAtlas.SetupGet(p => p.Id).Returns(AtlasTextureId); + var mockFontTextureAtlas = Substitute.For(); + mockFontTextureAtlas.Id.Returns(AtlasTextureId); var sut = CreateSystemUnderTest(); @@ -828,33 +863,38 @@ public void Render_WhenInvoked_RendersFont() this.batchHasBegunReactor.OnReceive(); sut.Render( - this.mockFont.Object, + this.mockFont, renderText, 11, 22); // Assert - this.mockGL.VerifyOnce(m => m.DrawElements(GLPrimitiveType.Triangles, + this.mockGL + .Received(1) + .DrawElements(GLPrimitiveType.Triangles, 6u * (uint)renderText.Length, GLDrawElementsType.UnsignedInt, - nint.Zero)); - this.mockGLService.VerifyOnce(m => m.BindTexture2D(AtlasTextureId)); - this.mockGpuBuffer - .VerifyExactly(m => - m.UploadData(It.IsAny(), It.IsAny()), renderText.Length); + nint.Zero); + + this.mockGLService.Received(1).BindTexture2D(AtlasTextureId); + this.mockGpuBuffer.Received(renderText.Length).UploadData(Arg.Any(), Arg.Any()); } + #endregion #region Reactable Tests + [Fact] [Trait("Category", Subscription)] public void PushReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly() { // Arrange & Act & Assert - var mockPushReactable = new Mock(); - mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => + var mockPushReactable = Substitute.For(); + mockPushReactable + .When(x => x.Subscribe(Arg.Any())) + .Do(ci => { + var reactor = ci.Arg(); reactor.Should().NotBeNull("It is required for unit testing."); reactor.Name.Should().Be($"FontRenderer.ctor() - {PushNotifications.BatchHasBegunId}"); }); @@ -865,15 +905,17 @@ public void PushReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly( public void FontRenderBatchReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly() { // Arrange & Act & Assert - var mockFontRenderBatchReactable = new Mock>(); + var mockFontRenderBatchReactable = Substitute.For>(); mockFontRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => + .When(x => x.Subscribe(Arg.Any())) + .Do(ci => { + var reactor = ci.Arg(); reactor.Should().NotBeNull("It is required for unit testing."); reactor.Name.Should().Be($"FontRenderer.ctor() - {PushNotifications.RenderFontsId}"); }); } + #endregion /// @@ -896,11 +938,7 @@ private static Memory> CreateFontRenderItems(stri RenderEffects.None, AtlasTextureId); - renderItems.Add(new RenderItem - { - Layer = 0, - Item = batchItem, - }); + renderItems.Add(new RenderItem { Layer = 0, Item = batchItem, }); } return new Memory>(renderItems.ToArray()); @@ -911,20 +949,20 @@ private static Memory> CreateFontRenderItems(stri /// /// The instance to test. private FontRenderer CreateSystemUnderTest() - => new (this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); - - /// + => new (this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); + + /// /// Mocks the font metrics for testing. /// private void MockFontMetrics() { this.allGlyphMetrics = TestDataLoader.LoadTestData(string.Empty, GlyphTestDataFileName).ToList(); - this.mockFont.SetupGet(p => p.Metrics).Returns(() => this.allGlyphMetrics.ToArray().AsReadOnly()); + this.mockFont.Metrics.Returns(this.allGlyphMetrics.ToArray().AsReadOnly()); } /// @@ -933,16 +971,14 @@ private void MockFontMetrics() /// The text of glyphs to mock. private void MockToGlyphMetrics(string text) { - this.mockFont.Setup(m => m.ToGlyphMetrics(text)).Returns(() => + this.mockFont.ToGlyphMetrics(text).Returns(ci => { var textGlyphs = this.allGlyphMetrics.Where(m => text.Contains(m.Glyph)).ToList(); - return text.Select(character - => (from m in textGlyphs - where m.Glyph == (this.glyphChars.Contains(character) + => textGlyphs.FirstOrDefault(m => m.Glyph == (this.glyphChars.Contains(character) ? character - : InvalidCharacter) - select m).FirstOrDefault()).ToArray(); + : InvalidCharacter))) + .ToArray(); }); } } diff --git a/Testing/VelaptorTests/Graphics/Renderers/LineRendererTests.cs b/Testing/VelaptorTests/Graphics/Renderers/LineRendererTests.cs index 75f8891f7..911f4b0b3 100644 --- a/Testing/VelaptorTests/Graphics/Renderers/LineRendererTests.cs +++ b/Testing/VelaptorTests/Graphics/Renderers/LineRendererTests.cs @@ -11,7 +11,6 @@ namespace VelaptorTests.Graphics.Renderers; using Carbonate.NonDirectional; using FluentAssertions; using Helpers; -using Moq; using NSubstitute; using Velaptor; using Velaptor.Batching; @@ -38,12 +37,12 @@ namespace VelaptorTests.Graphics.Renderers; public class LineRendererTests : TestsBase { private const uint LineShaderId = 3333u; - private readonly Mock mockGL; - private readonly Mock mockGLService; - private readonly Mock mockShader; - private readonly Mock> mockGpuBuffer; - private readonly Mock mockBatchingManager; - private readonly Mock mockReactableFactory; + private readonly IGLInvoker mockGL; + private readonly IOpenGLService mockGLService; + private readonly IShaderProgram mockShader; + private readonly IGpuBuffer mockGpuBuffer; + private readonly IBatchingManager mockBatchingManager; + private readonly IReactableFactory mockReactableFactory; private LineRenderItem? renderReactor; private IReceiveSubscription? batchHasBegunReactor; @@ -52,45 +51,54 @@ public class LineRendererTests : TestsBase /// public LineRendererTests() { - this.mockGL = new Mock(); + this.mockGL = Substitute.For(); - this.mockGLService = new Mock(); - this.mockGLService.Setup(m => m.ProgramLinkedSuccessfully(It.IsAny())).Returns(true); - this.mockGLService.Setup(m => m.ShaderCompiledSuccessfully(It.IsAny())).Returns(true); - this.mockGLService.Setup(m => m.GetViewPortSize()).Returns(new Size(800, 600)); + this.mockGLService = Substitute.For(); + this.mockGLService.ProgramLinkedSuccessfully(Arg.Any()).Returns(true); + this.mockGLService.ShaderCompiledSuccessfully(Arg.Any()).Returns(true); + this.mockGLService.GetViewPortSize().Returns(new Size(800, 600)); - this.mockShader = new Mock(); - this.mockShader.Setup(m => m.ShaderId).Returns(LineShaderId); + this.mockShader = Substitute.For(); + this.mockShader.ShaderId.Returns(LineShaderId); - this.mockGpuBuffer = new Mock>(); + this.mockGpuBuffer = Substitute.For>(); + this.mockBatchingManager = Substitute.For(); - this.mockBatchingManager = new Mock(); - - var mockRenderUnsubscriber = new Mock(); - - var mockPushReactable = new Mock(); - mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.batchHasBegunReactor = reactor) - .Returns(_ => Substitute.For()); + var mockPushReactable = Substitute.For(); + mockPushReactable + .Subscribe(Arg.Any()) + .Returns(Substitute.For()) + .AndDoes(ci => + { + var reactor = ci.Arg(); + this.batchHasBegunReactor = reactor; + }); - var mockLineRenderBatchReactable = new Mock>(); + var mockLineRenderBatchReactable = Substitute.For>(); mockLineRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.renderReactor = reactor) - .Returns(_ => mockRenderUnsubscriber.Object); - - this.mockReactableFactory = new Mock(); - this.mockReactableFactory.Setup(m => m.CreateNoDataPushReactable()) - .Returns(mockPushReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateRenderLineReactable()) - .Returns(mockLineRenderBatchReactable.Object); - - var mockFontTextureAtlas = new Mock(); - mockFontTextureAtlas.SetupGet(p => p.Width).Returns(200); - mockFontTextureAtlas.SetupGet(p => p.Height).Returns(100); + .Subscribe(Arg.Any()) + .Returns(Substitute.For()) + .AndDoes(ci => + { + var reactor = ci.Arg(); + this.renderReactor = reactor; + }); + + this.mockReactableFactory = Substitute.For(); + this.mockReactableFactory + .CreateNoDataPushReactable() + .Returns(mockPushReactable); + this.mockReactableFactory + .CreateRenderLineReactable() + .Returns(mockLineRenderBatchReactable); + + var mockFontTextureAtlas = Substitute.For(); + mockFontTextureAtlas.Width.Returns(200u); + mockFontTextureAtlas.Height.Returns(100u); } #region Constructor Tests + [Fact] [Trait("Category", Ctor)] public void Ctor_WithNullOpenGLServiceParam_ThrowsException() @@ -99,12 +107,12 @@ public void Ctor_WithNullOpenGLServiceParam_ThrowsException() var act = () => { _ = new LineRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockReactableFactory, null, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -121,12 +129,12 @@ public void Ctor_WithNullBufferParam_ThrowsException() var act = () => { _ = new LineRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, null, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -143,12 +151,12 @@ public void Ctor_WithNullShaderParam_ThrowsException() var act = () => { _ = new LineRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, null, - this.mockBatchingManager.Object); + this.mockBatchingManager); }; // Assert @@ -165,11 +173,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() var act = () => { _ = new LineRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, null); }; @@ -178,9 +186,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() .Throw() .WithMessage("Value cannot be null. (Parameter 'batchManager')"); } + #endregion #region Method Tests + [Fact] [Trait("Category", Method)] public void Render_WhenBegunHasNotBeenInvoked_ThrowsException() @@ -220,7 +230,7 @@ public void Render_WhenInvoking2ParamMethodOverload_AddsToBatch() sut.Render(line, 10); // Assert - this.mockBatchingManager.VerifyOnce(m => m.AddLineItem(expected, 10, It.IsAny())); + this.mockBatchingManager.Received(1).AddLineItem(expected, 10, Arg.Any()); } [Fact] @@ -241,8 +251,8 @@ public void Render_WhenInvoking3ParamMethodOverload_AddsToBatch() sut.RenderLine(new Vector2(1, 2), new Vector2(3, 4), 10); // Assert - this.mockBatchingManager.VerifyOnce(m => m.AddLineItem(expected, 10, It.IsAny())); - } + this.mockBatchingManager.Received(1).AddLineItem(expected, 10, Arg.Any()); + } [Fact] [Trait("Category", Method)] @@ -266,7 +276,7 @@ public void Render_WhenInvoking4ParamWithColorMethodOverload_AddsToBatch() 10); // Assert - this.mockBatchingManager.VerifyOnce(m => m.AddLineItem(expected, 10, It.IsAny())); + this.mockBatchingManager.Received(1).AddLineItem(expected, 10, Arg.Any()); } [Fact] @@ -291,7 +301,7 @@ public void Render_WhenInvoking4ParamWithThicknessMethodOverload_AddsToBatch() 10); // Assert - this.mockBatchingManager.VerifyOnce(m => m.AddLineItem(expected, 10, It.IsAny())); + this.mockBatchingManager.Received(1).AddLineItem(expected, 10, Arg.Any()); } [Fact] @@ -317,7 +327,7 @@ public void Render_WhenInvokingOverloadWithAllParams_AddsToBatch() 10); // Assert - this.mockBatchingManager.VerifyOnce(m => m.AddLineItem(expected, 10, It.IsAny())); + this.mockBatchingManager.Received(1).AddLineItem(expected, 10, Arg.Any()); } [Fact] @@ -326,30 +336,33 @@ public void Render_WithNoLineItemsToRender_SetsUpCorrectDebugGroupAndExits() { // Arrange const string shaderName = "TestLineShader"; - this.mockShader.SetupGet(p => p.Name).Returns(shaderName); + this.mockShader.Name.Returns(shaderName); _ = CreateSystemUnderTest(); // Act this.renderReactor.OnReceive(default); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render Line Process - Nothing To Render")); - this.mockGLService.VerifyOnce(m => m.EndGroup()); - this.mockGLService.VerifyNever(m => m.BeginGroup($"Render Line Process With {shaderName} Shader")); - this.mockShader.VerifyNever(m => m.Use()); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Update Line Data - TextureID")))); - this.mockGL.VerifyNever(m => m.ActiveTexture(It.IsAny())); - this.mockGLService.VerifyNever(m => m.BindTexture2D(It.IsAny())); - this.mockGpuBuffer.VerifyNever(m => - m.UploadData(It.IsAny(), It.IsAny())); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Render ") && value.EndsWith(" Texture Elements")))); - this.mockGL.VerifyNever(m => m.DrawElements( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())); + this.mockGLService.Received(1).BeginGroup("Render Line Process - Nothing To Render"); + this.mockGLService.Received(1).EndGroup(); + this.mockGLService.DidNotReceive().BeginGroup($"Render Line Process With {shaderName} Shader"); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Update Line Data - TextureID"))); + this.mockGLService.DidNotReceive().BindTexture2D(Arg.Any()); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Render ") && value.EndsWith(" Texture Elements"))); + this.mockGL.DidNotReceive().ActiveTexture(Arg.Any()); + this.mockGL.DidNotReceive().DrawElements( + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any()); + this.mockShader.DidNotReceive().Use(); + this.mockGpuBuffer + .DidNotReceive() + .UploadData(Arg.Any(), Arg.Any()); } [Fact] @@ -383,23 +396,33 @@ public void Render_WhenInvoked_RendersLine() this.renderReactor.OnReceive(renderItems); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render 6 Line Elements")); - this.mockGLService.VerifyExactly(m => m.EndGroup(), 3); - this.mockGL.VerifyOnce(m => m.DrawElements(GLPrimitiveType.Triangles, 6, GLDrawElementsType.UnsignedInt, nint.Zero)); - this.mockGpuBuffer.VerifyOnce(m => m.UploadData(batchItem, batchIndex)); + this.mockGLService.Received(1).BeginGroup("Render 6 Line Elements"); + this.mockGLService.Received(3).EndGroup(); + this.mockGL + .Received(1) + .DrawElements( + GLPrimitiveType.Triangles, + 6, + GLDrawElementsType.UnsignedInt, + nint.Zero); + this.mockGpuBuffer.Received(1).UploadData(batchItem, batchIndex); } + #endregion #region Reactable Tests + [Fact] [Trait("Category", Subscription)] public void PushReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly() { // Arrange & Act & Assert - var mockPushReactable = new Mock(); - mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => + var mockPushReactable = Substitute.For(); + mockPushReactable + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => { + var reactor = ci.Arg(); reactor.Should().NotBeNull("It is required for unit testing."); }); } @@ -409,15 +432,17 @@ public void PushReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly( public void LineRenderReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly() { // Arrange & Act & Assert - var mockLineRenderBatchReactable = new Mock>(); + var mockLineRenderBatchReactable = Substitute.For>(); mockLineRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => { + var reactor = ci.Arg(); reactor.Should().NotBeNull("It is required for unit testing."); reactor.Name.Should().Be($"LineRenderer.ctor() - {PushNotifications.RenderLinesId}"); }); } + #endregion /// @@ -425,10 +450,10 @@ public void LineRenderReactable_WhenCreatingSubscription_CreatesSubscriptionCorr /// /// The instance to test. private LineRenderer CreateSystemUnderTest() - => new (this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); + => new (this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); } diff --git a/Testing/VelaptorTests/Graphics/Renderers/ShapeRendererTests.cs b/Testing/VelaptorTests/Graphics/Renderers/ShapeRendererTests.cs index ba29fa436..8cbd13eb1 100644 --- a/Testing/VelaptorTests/Graphics/Renderers/ShapeRendererTests.cs +++ b/Testing/VelaptorTests/Graphics/Renderers/ShapeRendererTests.cs @@ -11,7 +11,7 @@ namespace VelaptorTests.Graphics.Renderers; using Carbonate.NonDirectional; using FluentAssertions; using Helpers; -using Moq; +using NSubstitute; using Velaptor; using Velaptor.Batching; using Velaptor.Content; @@ -42,12 +42,12 @@ namespace VelaptorTests.Graphics.Renderers; public class ShapeRendererTests : TestsBase { private const uint ShapeShaderId = 3333u; - private readonly Mock mockGL; - private readonly Mock mockGLService; - private readonly Mock mockShader; - private readonly Mock> mockGpuBuffer; - private readonly Mock mockBatchingManager; - private readonly Mock mockReactableFactory; + private readonly IGLInvoker mockGL; + private readonly IOpenGLService mockGLService; + private readonly IShaderProgram mockShader; + private readonly IGpuBuffer mockGpuBuffer; + private readonly IBatchingManager mockBatchingManager; + private readonly IReactableFactory mockReactableFactory; private IReceiveSubscription? batchHasBegunReactor; private RectRenderItem? renderReactor; @@ -56,42 +56,53 @@ public class ShapeRendererTests : TestsBase /// public ShapeRendererTests() { - this.mockGL = new Mock(); + this.mockGL = Substitute.For(); - this.mockGLService = new Mock(); - this.mockGLService.Setup(m => m.ProgramLinkedSuccessfully(It.IsAny())).Returns(true); - this.mockGLService.Setup(m => m.ShaderCompiledSuccessfully(It.IsAny())).Returns(true); - this.mockGLService.Setup(m => m.GetViewPortSize()).Returns(new Size(800, 600)); + this.mockGLService = Substitute.For(); + this.mockGLService.ProgramLinkedSuccessfully(Arg.Any()).Returns(true); + this.mockGLService.ShaderCompiledSuccessfully(Arg.Any()).Returns(true); + this.mockGLService.GetViewPortSize().Returns(new Size(800, 600)); - this.mockShader = new Mock(); - this.mockShader.SetupGet(p => p.ShaderId).Returns(ShapeShaderId); + this.mockShader = Substitute.For(); + this.mockShader.ShaderId.Returns(ShapeShaderId); - this.mockGpuBuffer = new Mock>(); + this.mockGpuBuffer = Substitute.For>(); - this.mockBatchingManager = new Mock(); - this.mockBatchingManager.Name = nameof(this.mockBatchingManager); + this.mockBatchingManager = Substitute.For(); - var mockPushReactable = new Mock(); - mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.batchHasBegunReactor = reactor); + var mockPushReactable = Substitute.For(); + mockPushReactable + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => + { + var reactor = ci.Arg(); + this.batchHasBegunReactor = reactor; + }); - var mockShapeRenderBatchReactable = new Mock>(); + var mockShapeRenderBatchReactable = Substitute.For>(); mockShapeRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.renderReactor = reactor); - - this.mockReactableFactory = new Mock(); - this.mockReactableFactory.Setup(m => m.CreateNoDataPushReactable()) - .Returns(mockPushReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateRenderShapeReactable()) - .Returns(mockShapeRenderBatchReactable.Object); - - var mockFontTextureAtlas = new Mock(); - mockFontTextureAtlas.SetupGet(p => p.Width).Returns(200); - mockFontTextureAtlas.SetupGet(p => p.Height).Returns(100); + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => + { + var reactor = ci.Arg(); + this.renderReactor = reactor; + }); + + this.mockReactableFactory = Substitute.For(); + this.mockReactableFactory + .CreateNoDataPushReactable() + .Returns(mockPushReactable); + this.mockReactableFactory + .CreateRenderShapeReactable() + .Returns(mockShapeRenderBatchReactable); + + var mockFontTextureAtlas = Substitute.For(); + mockFontTextureAtlas.Width.Returns(200u); + mockFontTextureAtlas.Height.Returns(100u); } #region Constructor Tests + [Fact] [Trait("Category", Ctor)] public void Ctor_WithNullOpenGLServiceParam_ThrowsException() @@ -100,12 +111,12 @@ public void Ctor_WithNullOpenGLServiceParam_ThrowsException() var act = () => { _ = new ShapeRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockReactableFactory, null, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -122,12 +133,12 @@ public void Ctor_WithNullBufferParam_ThrowsException() var act = () => { _ = new ShapeRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, null, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -144,12 +155,12 @@ public void Ctor_WithNullShaderParam_ThrowsException() var act = () => { _ = new ShapeRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, null, - this.mockBatchingManager.Object); + this.mockBatchingManager); }; // Assert @@ -166,11 +177,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() var act = () => { _ = new ShapeRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, null); }; @@ -179,9 +190,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() .Throw() .WithMessage("Value cannot be null. (Parameter 'batchManager')"); } + #endregion #region Method Tests + [Fact] [Trait("Category", Method)] public void Render_WhenRenderingShape_AddsShapeToBatch() @@ -220,7 +233,7 @@ public void Render_WhenRenderingShape_AddsShapeToBatch() sut.Render(rectShape, 123); // Assert - this.mockBatchingManager.VerifyOnce(m => m.AddShapeItem(expected, 123, It.IsAny())); + this.mockBatchingManager.Received(1).AddShapeItem(expected, 123, Arg.Any()); } [Fact] @@ -265,10 +278,13 @@ public void Render_WhenRenderingRect_RendersRectangle() this.renderReactor.OnReceive(renderItems); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render 6 Shape Elements")); - this.mockGLService.VerifyExactly(m => m.EndGroup(), 3); - this.mockGL.VerifyOnce(m => m.DrawElements(GLPrimitiveType.Triangles, 6, GLDrawElementsType.UnsignedInt, nint.Zero)); - this.mockGpuBuffer.VerifyOnce(m => m.UploadData(batchItem, batchIndex)); + this.mockGLService.Received(1).BeginGroup("Render 6 Shape Elements"); + this.mockGLService.Received(3).EndGroup(); + + this.mockGL + .Received(1) + .DrawElements(GLPrimitiveType.Triangles, 6, GLDrawElementsType.UnsignedInt, nint.Zero); + this.mockGpuBuffer.Received(1).UploadData(batchItem, batchIndex); } [Fact] @@ -324,7 +340,7 @@ public void Render_WhenRenderingCircle_AddsCircleToBatch() sut.Render(circle, 123); // Assert - this.mockBatchingManager.VerifyOnce(m => m.AddShapeItem(expected, 123, It.IsAny())); + this.mockBatchingManager.Received(1).AddShapeItem(expected, 123, Arg.Any()); } [Fact] @@ -367,10 +383,12 @@ public void Render_WhenRenderingCircle_RendersCircle() this.renderReactor.OnReceive(renderItems); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render 6 Shape Elements")); - this.mockGLService.VerifyExactly(m => m.EndGroup(), 3); - this.mockGL.VerifyOnce(m => m.DrawElements(GLPrimitiveType.Triangles, 6, GLDrawElementsType.UnsignedInt, nint.Zero)); - this.mockGpuBuffer.VerifyOnce(m => m.UploadData(batchItem, batchIndex)); + this.mockGLService.Received(1).BeginGroup("Render 6 Shape Elements"); + this.mockGLService.Received(3).EndGroup(); + this.mockGL + .Received(1) + .DrawElements(GLPrimitiveType.Triangles, 6, GLDrawElementsType.UnsignedInt, nint.Zero); + this.mockGpuBuffer.Received(1).UploadData(batchItem, batchIndex); } [Fact] @@ -389,39 +407,46 @@ public void Render_WhenRenderingCircleAndBegunHasNotBeenInvoked_ThrowsException( act.Should().Throw() .WithMessage(expected); } + #endregion #region Reactable Tests + [Fact] [Trait("Category", Ctor)] public void Render_WithNoRectItemsToRender_SetsUpCorrectDebugGroupAndExits() { // Arrange const string shaderName = "TestShapeShader"; - this.mockShader.SetupGet(p => p.Name).Returns(shaderName); + this.mockShader.Name.Returns(shaderName); _ = CreateSystemUnderTest(); // Act this.renderReactor.OnReceive(default); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render Shape Process - Nothing To Render")); - this.mockGLService.VerifyOnce(m => m.EndGroup()); - this.mockGLService.VerifyNever(m => m.BeginGroup($"Render Shape Process With {shaderName} Shader")); - this.mockShader.VerifyNever(m => m.Use()); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Update Rectangle Data - TextureID")))); - this.mockGL.VerifyNever(m => m.ActiveTexture(It.IsAny())); - this.mockGLService.VerifyNever(m => m.BindTexture2D(It.IsAny())); - this.mockGpuBuffer.VerifyNever(m => - m.UploadData(It.IsAny(), It.IsAny())); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Render ") && value.EndsWith(" Texture Elements")))); - this.mockGL.VerifyNever(m => m.DrawElements( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())); + this.mockGLService.Received(1).BeginGroup("Render Shape Process - Nothing To Render"); + this.mockGLService.Received(1).EndGroup(); + this.mockGLService.DidNotReceive().BeginGroup($"Render Shape Process With {shaderName} Shader"); + this.mockShader.DidNotReceive().Use(); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Update Rectangle Data - TextureID"))); + this.mockGL.DidNotReceive().ActiveTexture(Arg.Any()); + this.mockGLService.DidNotReceive().BindTexture2D(Arg.Any()); + this.mockGpuBuffer + .DidNotReceive() + .UploadData(Arg.Any(), Arg.Any()); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Render ") && value.EndsWith(" Texture Elements"))); + this.mockGL + .DidNotReceive() + .DrawElements( + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any()); } [Fact] @@ -429,10 +454,12 @@ public void Render_WithNoRectItemsToRender_SetsUpCorrectDebugGroupAndExits() public void PushReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly() { // Arrange & Act & Assert - var mockPushReactable = new Mock(); - mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => + var mockPushReactable = Substitute.For(); + mockPushReactable + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => { + var reactor = ci.Arg(); reactor.Should().NotBeNull("It is required for unit testing."); reactor.Name.Should().Be($"ShapeRenderer.ctor() - {PushNotifications.BatchHasBegunId}"); }); @@ -443,15 +470,17 @@ public void PushReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly( public void ShapeRenderBatchReactable_WhenCreatingSubscription_CreatesSubscriptionCorrectly() { // Arrange & Act & Assert - var mockShapeRenderBatchReactable = new Mock>(); + var mockShapeRenderBatchReactable = Substitute.For>(); mockShapeRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => { + var reactor = ci.Arg(); reactor.Should().NotBeNull("It is required for unit testing."); reactor.Name.Should().Be($"ShapeRenderer.ctor() - {PushNotifications.RenderShapesId}"); }); } + #endregion /// @@ -459,10 +488,10 @@ public void ShapeRenderBatchReactable_WhenCreatingSubscription_CreatesSubscripti /// /// The instance to test. private ShapeRenderer CreateSystemUnderTest() - => new (this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); + => new (this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); } diff --git a/Testing/VelaptorTests/Graphics/Renderers/TextureRendererTests.cs b/Testing/VelaptorTests/Graphics/Renderers/TextureRendererTests.cs index 2fa5d9461..18f2a4332 100644 --- a/Testing/VelaptorTests/Graphics/Renderers/TextureRendererTests.cs +++ b/Testing/VelaptorTests/Graphics/Renderers/TextureRendererTests.cs @@ -12,8 +12,8 @@ namespace VelaptorTests.Graphics.Renderers; using Carbonate.NonDirectional; using FluentAssertions; using Helpers; -using Moq; -using Moq.Language.Flow; +using NSubstitute; +using NSubstitute.Core; using Velaptor.Batching; using Velaptor.Content; using Velaptor.Factories; @@ -39,14 +39,14 @@ namespace VelaptorTests.Graphics.Renderers; public class TextureRendererTests : TestsBase { private const uint TextureId = 456u; - private readonly Mock mockGL; - private readonly Mock mockGLService; - private readonly Mock> mockGpuBuffer; - private readonly Mock mockShader; - private readonly Mock mockBatchingManager; - private readonly Mock mockReactableFactory; - private readonly Mock mockPushReactable; - private readonly Mock> mockTextureRenderBatchReactable; + private readonly IGLInvoker mockGL; + private readonly IOpenGLService mockGLService; + private readonly IGpuBuffer mockGpuBuffer; + private readonly IShaderProgram mockShader; + private readonly IBatchingManager mockBatchingManager; + private readonly IReactableFactory mockReactableFactory; + private readonly IPushReactable mockPushReactable; + private readonly IRenderBatchReactable mockTextureRenderBatchReactable; private IReceiveSubscription? batchHasBegunReactor; private TextureRenderItem? renderReactor; @@ -55,32 +55,34 @@ public class TextureRendererTests : TestsBase /// public TextureRendererTests() { - this.mockGL = new Mock(); - this.mockGLService = new Mock(); - this.mockShader = new Mock(); - this.mockGpuBuffer = new Mock>(); - - this.mockBatchingManager = new Mock(); - this.mockBatchingManager.Name = nameof(this.mockBatchingManager); + this.mockGL = Substitute.For(); + this.mockGLService = Substitute.For(); + this.mockShader = Substitute.For(); + this.mockGpuBuffer = Substitute.For>(); + this.mockBatchingManager = Substitute.For(); + + this.mockPushReactable = Substitute.For(); + this.mockPushReactable + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => this.batchHasBegunReactor = ci.Arg()); + + this.mockTextureRenderBatchReactable = Substitute.For>(); + this.mockTextureRenderBatchReactable + .When(m => m.Subscribe(Arg.Any())) + .Do(ci => this.renderReactor = ci.Arg()); - this.mockPushReactable = new Mock(); - this.mockPushReactable.Name = "NoADataPushReactable"; - this.mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.batchHasBegunReactor = reactor); - this.mockTextureRenderBatchReactable = new Mock>(); - this.mockTextureRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactor => this.renderReactor = reactor); - - this.mockReactableFactory = new Mock(); - this.mockReactableFactory.Setup(m => m.CreateNoDataPushReactable()) - .Returns(this.mockPushReactable.Object); - this.mockReactableFactory.Setup(m => m.CreateRenderTextureReactable()) - .Returns(this.mockTextureRenderBatchReactable.Object); + this.mockReactableFactory = Substitute.For(); + this.mockReactableFactory + .CreateNoDataPushReactable() + .Returns(this.mockPushReactable); + this.mockReactableFactory + .CreateRenderTextureReactable() + .Returns(this.mockTextureRenderBatchReactable); } #region Constructor Tests + [Fact] [Trait("Category", Ctor)] public void Ctor_WithNullOpenGLServiceParam_ThrowsException() @@ -89,12 +91,12 @@ public void Ctor_WithNullOpenGLServiceParam_ThrowsException() var act = () => { _ = new TextureRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, + this.mockGL, + this.mockReactableFactory, null, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -111,12 +113,12 @@ public void Ctor_WithNullBufferParam_ThrowsException() var act = () => { _ = new TextureRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, null, - this.mockShader.Object, - this.mockBatchingManager.Object); + this.mockShader, + this.mockBatchingManager); }; // Assert @@ -133,12 +135,12 @@ public void Ctor_WithNullShaderParam_ThrowsException() var act = () => { _ = new TextureRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, null, - this.mockBatchingManager.Object); + this.mockBatchingManager); }; // Assert @@ -155,11 +157,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() var act = () => { _ = new TextureRenderer( - this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, + this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, null); }; @@ -168,9 +170,11 @@ public void Ctor_WithNullBatchManagerParam_ThrowsException() .Throw() .WithMessage("Value cannot be null. (Parameter 'batchManager')"); } + #endregion #region Method Tests + [Fact] [Trait("Category", Method)] public void Render_WhenNotCallingBeginFirst_ThrowsException() @@ -182,13 +186,13 @@ public void Render_WhenNotCallingBeginFirst_ThrowsException() AssertExtensions.ThrowsWithMessage(() => { sut.Render( - new Mock().Object, + Substitute.For(), new Rectangle(10, 20, 30, 40), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + default, + default, + default, + default, + default); }, "The 'Begin()' method must be invoked first before any 'Render()' methods."); } @@ -208,13 +212,13 @@ public void Render_WithSourceRectWithNoWidthOrHeight_ThrowsException(int width, AssertExtensions.ThrowsWithMessage(() => { sut.Render( - new Mock().Object, + Substitute.For(), new Rectangle(1, 2, width, height), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + default, + default, + default, + default, + default); }, "The source rectangle must have a width and height greater than zero. (Parameter 'srcRect')"); } @@ -228,25 +232,25 @@ public void Render_WithNullTexture_ThrowsException() // Act & Assert AssertExtensions.ThrowsWithMessage(() => - { - sut.Render( - null, - new Rectangle(10, 20, 30, 40), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); - }, $"Cannot render a null '{nameof(ITexture)}'. (Parameter 'texture')"); + { + sut.Render( + null, + new Rectangle(10, 20, 30, 40), + default, + default, + default, + default, + default); + }, $"Cannot render a null '{nameof(ITexture)}'. (Parameter 'texture')"); } [Fact] public void Render_WithZeroWidthOrHeightTexture_ThrowsException() { // Arrange - var mockTexture = new Mock(); - mockTexture.SetupGet(p => p.Width).Returns(0); - mockTexture.SetupGet(p => p.Height).Returns(0); + var mockTexture = Substitute.For(); + mockTexture.Width.Returns(0u); + mockTexture.Height.Returns(0u); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); @@ -255,11 +259,11 @@ public void Render_WithZeroWidthOrHeightTexture_ThrowsException() AssertExtensions.ThrowsWithMessage(() => { sut.Render( - mockTexture.Object, - 10, - 20, - It.IsAny(), - It.IsAny()); + texture: mockTexture, + x: 10, + y: 20, + color: default, + effects: default); }, "The source rectangle must have a width and height greater than zero. (Parameter 'rects')"); } @@ -269,30 +273,35 @@ public void Render_WithNoTextureItemsToRender_SetsUpCorrectDebugGroupAndExits() { // Arrange const string shaderName = "TestTextureShader"; - this.mockShader.SetupGet(p => p.Name).Returns(shaderName); + this.mockShader.Name.Returns(shaderName); _ = CreateSystemUnderTest(); // Act this.renderReactor.OnReceive(default); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render Texture Process - Nothing To Render")); - this.mockGLService.VerifyOnce(m => m.EndGroup()); - this.mockGLService.VerifyNever(m => m.BeginGroup($"Render Texture Process With {shaderName} Shader")); - this.mockShader.VerifyNever(m => m.Use()); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Update Texture Data - TextureID")))); - this.mockGL.VerifyNever(m => m.ActiveTexture(It.IsAny())); - this.mockGLService.VerifyNever(m => m.BindTexture2D(It.IsAny())); - this.mockGpuBuffer.VerifyNever(m => - m.UploadData(It.IsAny(), It.IsAny())); - this.mockGLService.VerifyNever(m => - m.BeginGroup(It.Is(value => value.StartsWith("Render ") && value.EndsWith(" Texture Elements")))); - this.mockGL.VerifyNever(m => m.DrawElements( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())); + this.mockGLService.Received(1).BeginGroup("Render Texture Process - Nothing To Render"); + this.mockGLService.Received(1).EndGroup(); + this.mockGLService.DidNotReceive().BeginGroup($"Render Texture Process With {shaderName} Shader"); + this.mockShader.DidNotReceive().Use(); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Update Texture Data - TextureID"))); + this.mockGL.DidNotReceive().ActiveTexture(Arg.Any()); + this.mockGLService.DidNotReceive().BindTexture2D(Arg.Any()); + this.mockGpuBuffer + .DidNotReceive() + .UploadData(Arg.Any(), Arg.Any()); + this.mockGLService + .DidNotReceive() + .BeginGroup(Arg.Is(value => value.StartsWith("Render ") && value.EndsWith(" Texture Elements"))); + this.mockGL + .DidNotReceive() + .DrawElements( + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any()); } [Fact] @@ -317,20 +326,18 @@ public void Render_With4ParamAndIntPosOverload_AddsCorrectItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, 10, 20, 123); + sut.Render(mockTexture, 10, 20, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -356,20 +363,18 @@ public void Render_With5ParamAndIntPosOverloadWithAngle_AddsCorrectItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, 10, 20, 180, 123); + sut.Render(mockTexture, 10, 20, 180, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -395,20 +400,18 @@ public void Render_With6ParamAndIntPosOverloadWithSize_AddsCorrectItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, 10, 20, 180, 1.5f, 123); + sut.Render(mockTexture, 10, 20, 180, 1.5f, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -434,20 +437,18 @@ public void Render_With7ParamAndVectorPosOverloadWithSizeAndColor_AddsCorrectIte TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, 10, 20, 180, 1.5f, Color.FromArgb(11, 22, 33, 44), 123); + sut.Render(mockTexture, 10, 20, 180, 1.5f, Color.FromArgb(11, 22, 33, 44), 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -474,20 +475,18 @@ public void Render_With5ParamAndIntPosOverloadWithEffects_AddsCorrectItemToBatch TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, 10, 20, expectedRenderEffects, 123); + sut.Render(mockTexture, 10, 20, expectedRenderEffects, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); AssertExtensions.EqualWithMessage(expectedBatchItem, actualBatchItem, "The texture batch item being added is incorrect."); } @@ -514,20 +513,18 @@ public void Render_With5ParamAndIntPosOverloadWithColor_AddsCorrectItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, 10, 20, expectedClr, 123); + sut.Render(mockTexture, 10, 20, expectedClr, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); AssertExtensions.EqualWithMessage(expectedBatchItem, actualBatchItem, "The texture batch item being added is incorrect."); } @@ -555,20 +552,18 @@ public void Render_With6ParamAndIntPosOverload_AddsCorrectItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, 10, 20, expectedClr, expectedRenderEffects, 123); + sut.Render(mockTexture, 10, 20, expectedClr, expectedRenderEffects, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); AssertExtensions.EqualWithMessage(expectedBatchItem, actualBatchItem, "The texture batch item being added is incorrect."); } @@ -594,20 +589,18 @@ public void Render_With4ParamAndVectorPosOverload_AddsCorrectItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, new Vector2(10, 20), 123); + sut.Render(mockTexture, new Vector2(10, 20), 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -633,20 +626,18 @@ public void Render_With5ParamAndVectorPosOverloadWithAngle_AddsCorrectItemToBatc TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, new Vector2(10, 20), 180, 123); + sut.Render(mockTexture, new Vector2(10, 20), 180, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -672,20 +663,18 @@ public void Render_With5ParamAndVectorPosOverloadWithAngleAndSize_AddsCorrectIte TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, new Vector2(10, 20), 180, 1.5f, 123); + sut.Render(mockTexture, new Vector2(10, 20), 180, 1.5f, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -711,20 +700,18 @@ public void Render_With6ParamAndVectorPosOverloadWithAngleAndSizeAndColor_AddsCo TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, new Vector2(10, 20), 180, 1.5f, Color.FromArgb(30, 40, 50, 60), 123); + sut.Render(mockTexture, new Vector2(10, 20), 180, 1.5f, Color.FromArgb(30, 40, 50, 60), 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -751,20 +738,18 @@ public void Render_With5ParamAndVectorPosOverloadWithEffects_AddsCorrectItemToBa TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, new Vector2(10, 20), expectedRenderEffects, 123); + sut.Render(mockTexture, new Vector2(10, 20), expectedRenderEffects, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); AssertExtensions.EqualWithMessage(expectedBatchItem, actualBatchItem, "The texture batch item being added is incorrect."); } @@ -791,20 +776,18 @@ public void Render_With5ParamAndVectorPosOverloadWithColor_AddsCorrectItemToBatc TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, new Vector2(10, 20), expectedClr, 123); + sut.Render(mockTexture, new Vector2(10, 20), expectedClr, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); AssertExtensions.EqualWithMessage(expectedBatchItem, actualBatchItem, "The texture batch item being added is incorrect."); } @@ -832,20 +815,18 @@ public void Render_With6ParamAndVectorPosOverload_AddsCorrectItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockTexture.Object, new Vector2(10, 20), expectedClr, expectedRenderEffects, 123); + sut.Render(mockTexture, new Vector2(10, 20), expectedClr, expectedRenderEffects, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); AssertExtensions.EqualWithMessage(expectedBatchItem, actualBatchItem, "The texture batch item being added is incorrect."); } @@ -865,11 +846,11 @@ public void Render_With8ParamOverloadAndSrcRectWidthOrHeightIsZero_ThrowsExcepti var act = () => sut.Render( MockTexture(TextureId), new Rectangle(10, 20, srcRectWidth, srcRectHeight), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + default, + default, + default, + default, + default); // Assert act.Should().Throw() @@ -914,22 +895,23 @@ public void Render_With8ParamOverload_RendersTexture() sut.Render( MockTexture(TextureId), new Rectangle(0, 0, 1, 2), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny()); + default, + default, + default, + default, + default); // Act this.renderReactor.OnReceive(items); // Assert - this.mockGLService.VerifyOnce(m => m.BeginGroup("Render 12 Texture Elements")); - this.mockGL.VerifyOnce(m - => m.DrawElements(GLPrimitiveType.Triangles, expectedTotalElements, GLDrawElementsType.UnsignedInt, nint.Zero)); - this.mockGLService.VerifyOnce(m => m.BindTexture2D(TextureId)); - this.mockGpuBuffer.VerifyOnce(m => m.UploadData(batchItemA, itemABatchIndex)); - this.mockGpuBuffer.VerifyOnce(m => m.UploadData(batchItemB, itemBBatchIndex)); + this.mockGLService.Received(1).BeginGroup("Render 12 Texture Elements"); + this.mockGL + .Received(1) + .DrawElements(GLPrimitiveType.Triangles, expectedTotalElements, GLDrawElementsType.UnsignedInt, nint.Zero); + this.mockGLService.Received(1).BindTexture2D(TextureId); + this.mockGpuBuffer.Received(1).UploadData(batchItemA, itemABatchIndex); + this.mockGpuBuffer.Received(1).UploadData(batchItemB, itemBBatchIndex); } [Fact] @@ -1055,7 +1037,7 @@ public void Render_With5ParamOverloadWithInvalidFrameNumber_ThrowsException() var mockAtlas = CreateAtlasDataMock(10, 20); // Act - var act = () => sut.Render(mockAtlas.Object, "test-sub-texture", new Vector2(10, 20), 1234); + var act = () => sut.Render(mockAtlas, "test-sub-texture", new Vector2(10, 20), 1234); // Assert act.Should().Throw().WithMessage(expectedMsg); @@ -1073,7 +1055,7 @@ public void Render_With6ParamOverloadWithInvalidFrameNumber_ThrowsException() // Act var act = () => - sut.Render(mockAtlas.Object, "test-sub-texture", new Vector2(10, 20), Color.CornflowerBlue, 1234); + sut.Render(mockAtlas, "test-sub-texture", new Vector2(10, 20), Color.CornflowerBlue, 1234); // Assert act.Should().Throw().WithMessage(expectedMsg); @@ -1090,7 +1072,7 @@ public void Render_With6ParamOverloadWithInvalidFrameNumberAndAngle_ThrowsExcept var mockAtlas = CreateAtlasDataMock(10, 20); // Act - var act = () => sut.Render(mockAtlas.Object, "test-sub-texture", new Vector2(10, 20), 25f, 1234); + var act = () => sut.Render(mockAtlas, "test-sub-texture", new Vector2(10, 20), 25f, 1234); // Assert act.Should().Throw().WithMessage(expectedMsg); @@ -1108,7 +1090,7 @@ public void Render_With7ParamOverloadWithInvalidFrameNumberAndAngleAndSize_Throw // Act var act = () => - sut.Render(mockAtlas.Object, "test-sub-texture", new Vector2(10, 20), 35f, 1.4f, 1234); + sut.Render(mockAtlas, "test-sub-texture", new Vector2(10, 20), 35f, 1.4f, 1234); // Assert act.Should().Throw().WithMessage(expectedMsg); @@ -1126,7 +1108,7 @@ public void Render_With7ParamOverloadWithInvalidFrameNumberAndAngleAndColor_Thro // Act var act = () => - sut.Render(mockAtlas.Object, "test-sub-texture", new Vector2(10, 20), 45f, Color.IndianRed, 1234); + sut.Render(mockAtlas, "test-sub-texture", new Vector2(10, 20), 45f, Color.IndianRed, 1234); // Assert act.Should().Throw().WithMessage(expectedMsg); @@ -1145,7 +1127,7 @@ public void Render_With9ParamOverloadWithInvalidFrameNumberAndAngleAndSizeAndCol // Act var act = () => sut.Render( - mockAtlas.Object, + mockAtlas, "test-sub-texture", new Vector2(10, 20), 15f, @@ -1170,7 +1152,7 @@ public void Render_With9ParamOverloadWithInvalidFrameNumberAndAngleAndSizeAndCol // Act var act = () => sut.Render( - mockAtlas.Object, + mockAtlas, "test-sub-texture", new Vector2(10, 20), 15f, @@ -1206,20 +1188,18 @@ public void Render_With5ParamOverloadWithPos_AddsItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockAtlasData.Object, "test-texture", pos, 0, 123); + sut.Render(mockAtlasData, "test-texture", pos, 0, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -1247,20 +1227,18 @@ public void Render_With6ParamOverloadWithPosAndColor_AddsItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockAtlasData.Object, "test-texture", pos, color, 0, 123); + sut.Render(mockAtlasData, "test-texture", pos, color, 0, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -1288,20 +1266,18 @@ public void Render_With6ParamOverloadWithPosAndAngle_AddsItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockAtlasData.Object, "test-texture", pos, angle, 0, 123); + sut.Render(mockAtlasData, "test-texture", pos, angle, 0, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -1330,20 +1306,18 @@ public void Render_With7ParamOverloadWithPosAndAngleAndSize_AddsItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockAtlasData.Object, "test-texture", pos, angle, size, 0, 123); + sut.Render(mockAtlasData, "test-texture", pos, angle, size, 0, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -1372,20 +1346,18 @@ public void Render_With7ParamOverloadWithPosAndAngleAndColor_AddsItemToBatch() TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockAtlasData.Object, "test-texture", pos, angle, color, 0, 123); + sut.Render(mockAtlasData, "test-texture", pos, angle, color, 0, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -1415,20 +1387,18 @@ public void Render_With8ParamOverloadWithPosAndAngleAndSizeAndColor_AddsItemToBa TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockAtlasData.Object, "test-texture", pos, angle, size, color, 0, 123); + sut.Render(mockAtlasData, "test-texture", pos, angle, size, color, 0, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } @@ -1459,40 +1429,43 @@ public void Render_With8ParamOverloadWithPosAndAngleAndSizeAndColorAndEffects_Ad TextureBatchItem actualBatchItem = default; - MockAddTextureItem().Callback((item, _, _) => - { - actualBatchItem = item; - }); + MockAddTextureItem().Do(ci => actualBatchItem = ci.Arg()); var sut = CreateSystemUnderTest(); this.batchHasBegunReactor.OnReceive(); // Act - sut.Render(mockAtlasData.Object, "test-texture", pos, angle, size, color, effects, 0, 123); + sut.Render(mockAtlasData, "test-texture", pos, angle, size, color, effects, 0, 123); // Assert this.mockBatchingManager - .VerifyOnce(m => m.AddTextureItem(It.IsAny(), 123, It.IsAny())); + .Received(1) + .AddTextureItem(Arg.Any(), 123, Arg.Any()); actualBatchItem.Should().BeEquivalentTo(expectedBatchItem); } + #endregion #region Reactable Tests + [Fact] [Trait("Category", Subscription)] public void PushReactable_WhenCreatingAndDisposingOfSubscription_CreatesAndDisposesOfSubscriptionCorrectly() { // Arrange IReceiveSubscription? reactor = null; - Mock mockUnsubscriber = new Mock(); + IDisposable mockUnsubscriber = Substitute.For(); - this.mockPushReactable.Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactorParam => + this.mockPushReactable + .Subscribe(Arg.Any()) + .Returns(mockUnsubscriber) + .AndDoes(ci => { + var reactorParam = ci.Arg(); reactorParam.Should().NotBeNull("It is required for unit testing."); - reactor = reactorParam; - }).Returns(mockUnsubscriber.Object); + }); + _ = CreateSystemUnderTest(); @@ -1500,7 +1473,7 @@ public void PushReactable_WhenCreatingAndDisposingOfSubscription_CreatesAndDispo reactor.OnUnsubscribe(); // Assert - mockUnsubscriber.VerifyOnce(m => m.Dispose()); + mockUnsubscriber.Received(1).Dispose(); } [Fact] @@ -1509,15 +1482,17 @@ public void TextureRenderBatchReactable_WhenCreatingSubscription_CreatesSubscrip { // Arrange TextureRenderItem? reactor = null; - Mock mockUnsubscriber = new Mock(); + IDisposable mockUnsubscriber = Substitute.For(); this.mockTextureRenderBatchReactable - .Setup(m => m.Subscribe(It.IsAny())) - .Callback(reactorParam => + .Subscribe(Arg.Any()) + .Returns(mockUnsubscriber) + .AndDoes(ci => { + var reactorParam = ci.Arg(); reactorParam.Should().NotBeNull("It is required for unit testing."); reactor = reactorParam; - }).Returns(mockUnsubscriber.Object); + }); _ = CreateSystemUnderTest(); @@ -1525,8 +1500,9 @@ public void TextureRenderBatchReactable_WhenCreatingSubscription_CreatesSubscrip reactor.OnUnsubscribe(); // Assert - mockUnsubscriber.VerifyOnce(m => m.Dispose()); + mockUnsubscriber.Received(1).Dispose(); } + #endregion /// @@ -1536,10 +1512,10 @@ public void TextureRenderBatchReactable_WhenCreatingSubscription_CreatesSubscrip /// The instance to use for testing. private static ITexture MockTexture(uint textureId) { - var mockResult = new Mock(); - mockResult.SetupGet(p => p.Id).Returns(textureId); + var mockResult = Substitute.For(); + mockResult.Id.Returns(textureId); - return mockResult.Object; + return mockResult; } /// @@ -1549,15 +1525,15 @@ private static ITexture MockTexture(uint textureId) /// The texture width to mock. /// The texture height to mock. /// The mocked texture. - private static Mock CreateTextureMock( + private static ITexture CreateTextureMock( uint textureId, uint expectedWidth, uint expectedHeight) { - var mockTexture = new Mock(); - mockTexture.SetupGet(p => p.Id).Returns(textureId); - mockTexture.SetupGet(p => p.Width).Returns(expectedWidth); - mockTexture.SetupGet(p => p.Height).Returns(expectedHeight); + var mockTexture = Substitute.For(); + mockTexture.Id.Returns(textureId); + mockTexture.Width.Returns(expectedWidth); + mockTexture.Height.Returns(expectedHeight); return mockTexture; } @@ -1595,27 +1571,22 @@ private static (RectangleF, RectangleF) CreateExpectedRects(Vector2 pos, int wid /// The width of the bounds. /// The height of the bounds. /// The mocked object. - private static Mock CreateAtlasDataMock(int width, int height) + private static IAtlasData CreateAtlasDataMock(int width, int height) { - var mockTexture = new Mock(); - mockTexture.SetupGet(p => p.Id).Returns(TextureId); - var mockPath = new Mock(); - mockPath.Setup(m => m.GetFileNameWithoutExtension(It.IsAny())).Returns("test-atlas"); + var mockTexture = Substitute.For(); + mockTexture.Id.Returns(TextureId); + var mockPath = Substitute.For(); + mockPath.GetFileNameWithoutExtension(Arg.Any()).Returns("test-atlas"); - var subTextureData = new AtlasSubTextureData - { - Name = "test-sub-texture", - Bounds = new Rectangle(0, 0, width, height), - FrameIndex = 0, - }; - var subTextureDataItems = new[] { subTextureData }; + var subTextureData = new AtlasSubTextureData { Name = "test-sub-texture", Bounds = new Rectangle(0, 0, width, height), FrameIndex = 0, }; + var subTextureDataItems = new[] { subTextureData }; - var mock = new Mock(); - mock.SetupGet(p => p.Name).Returns("test-atlas-texture"); - mock.SetupGet(p => p.Width).Returns((uint)width); - mock.SetupGet(p => p.Height).Returns((uint)height); - mock.SetupGet(p => p.Texture).Returns(mockTexture.Object); - mock.Setup(m => m.GetFrames(It.IsAny())).Returns(subTextureDataItems); + var mock = Substitute.For(); + mock.Name.Returns("test-atlas-texture"); + mock.Width.Returns((uint)width); + mock.Height.Returns((uint)height); + mock.Texture.Returns(mockTexture); + mock.GetFrames(Arg.Any()).Returns(subTextureDataItems); return mock; } @@ -1624,10 +1595,9 @@ private static Mock CreateAtlasDataMock(int width, int height) /// Mocks the method. /// /// The mock setup. - private ISetup MockAddTextureItem() + private WhenCalled MockAddTextureItem() { - return this.mockBatchingManager - .Setup(m => m.AddTextureItem(It.IsAny(), It.IsAny(), It.IsAny())); + return this.mockBatchingManager.When(m => m.AddTextureItem(Arg.Any(), Arg.Any(), Arg.Any())); } /// @@ -1635,10 +1605,10 @@ private ISetup MockAddTextureItem() /// /// The instance to test. private TextureRenderer CreateSystemUnderTest() - => new (this.mockGL.Object, - this.mockReactableFactory.Object, - this.mockGLService.Object, - this.mockGpuBuffer.Object, - this.mockShader.Object, - this.mockBatchingManager.Object); + => new (this.mockGL, + this.mockReactableFactory, + this.mockGLService, + this.mockGpuBuffer, + this.mockShader, + this.mockBatchingManager); } diff --git a/Testing/VelaptorTests/Services/SystemDisplayServiceTests.cs b/Testing/VelaptorTests/Services/SystemDisplayServiceTests.cs index 836c6bcfa..1899a1626 100644 --- a/Testing/VelaptorTests/Services/SystemDisplayServiceTests.cs +++ b/Testing/VelaptorTests/Services/SystemDisplayServiceTests.cs @@ -1,4 +1,4 @@ - // +// // Copyright (c) KinsonDigital. All rights reserved. // @@ -7,7 +7,7 @@ namespace VelaptorTests.Services; using System; using System.Linq; using FluentAssertions; -using Moq; +using NSubstitute; using Velaptor; using Velaptor.Hardware; using Velaptor.NativeInterop.GLFW; @@ -20,6 +20,7 @@ namespace VelaptorTests.Services; public class SystemDisplayServiceTests { #region Constructor Tests + [Fact] public void Ctor_WithNullDisplaysParam_ThrowsException() { @@ -34,18 +35,19 @@ public void Ctor_WithNullDisplaysParam_ThrowsException() .Throw() .WithMessage("Value cannot be null. (Parameter 'displays')"); } + #endregion #region Prop Tests + [Fact] public void Displays_WithNoDisplaysInSystem_ReturnsEmptyResult() { // Arrange - var mockDisplays = new Mock(); - mockDisplays.SetupGet(m => m.SystemDisplays) - .Returns([]); + var mockDisplays = Substitute.For(); + mockDisplays.SystemDisplays.Returns([]); - var service = new SystemDisplayService(mockDisplays.Object); + var service = new SystemDisplayService(mockDisplays); // Act var actual = service.Displays; @@ -58,13 +60,12 @@ public void Displays_WithNoDisplaysInSystem_ReturnsEmptyResult() public void Displays_WhenGettingValue_ReturnsCorrectResult() { // Arrange - var mockPlatform = new Mock(); - var mockDisplays = new Mock(); - var display = new SystemDisplay(mockPlatform.Object); - mockDisplays.SetupGet(m => m.SystemDisplays) - .Returns(new[] { display }); + var mockPlatform = Substitute.For(); + var mockDisplays = Substitute.For(); + var display = new SystemDisplay(mockPlatform); + mockDisplays.SystemDisplays.Returns([display]); - var service = new SystemDisplayService(mockDisplays.Object); + var service = new SystemDisplayService(mockDisplays); // Act var actual = service.Displays.ToArray(); @@ -78,16 +79,12 @@ public void Displays_WhenGettingValue_ReturnsCorrectResult() public void MainDisplay_WhenGettingValue_ReturnsCorrectResult() { // Arrange - var mockPlatform = new Mock(); - var mockDisplays = new Mock(); - var display = new SystemDisplay(mockPlatform.Object) - { - IsMain = true, - }; - mockDisplays.SetupGet(m => m.SystemDisplays) - .Returns(new[] { display }); + var mockPlatform = Substitute.For(); + var mockDisplays = Substitute.For(); + var display = new SystemDisplay(mockPlatform) { IsMain = true, }; + mockDisplays.SystemDisplays.Returns([display]); - var service = new SystemDisplayService(mockDisplays.Object); + var service = new SystemDisplayService(mockDisplays); // Act var actual = service.MainDisplay; @@ -95,26 +92,28 @@ public void MainDisplay_WhenGettingValue_ReturnsCorrectResult() // Assert actual.Should().NotBeNull(); } + #endregion #region Method Tests + [Fact] public void Refresh_WhenInvoked_RefreshesDisplay() { // Arrange - var mockPlatform = new Mock(); - var mockDisplays = new Mock(); - var display = new SystemDisplay(mockPlatform.Object); - mockDisplays.SetupGet(m => m.SystemDisplays) - .Returns(new[] { display }); + var mockPlatform = Substitute.For(); + var mockDisplays = Substitute.For(); + var display = new SystemDisplay(mockPlatform); + mockDisplays.SystemDisplays.Returns([display]); - var service = new SystemDisplayService(mockDisplays.Object); + var service = new SystemDisplayService(mockDisplays); // Act service.Refresh(); // Assert - mockDisplays.Verify(m => m.Refresh(), Times.Once); + mockDisplays.Received(1).Refresh(); } + #endregion }