feat: Replace Moq and FluentAssertions with NSubstitute and Shouldly in test projects

This commit is contained in:
MaddoScientisto 2026-03-12 19:40:58 +01:00
commit 41d9dacfac
6 changed files with 96 additions and 91 deletions

View file

@ -12,8 +12,8 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="MSTest.TestAdapter" Version="4.1.0" /> <PackageReference Include="MSTest.TestAdapter" Version="4.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="4.1.0" /> <PackageReference Include="MSTest.TestFramework" Version="4.1.0" />
<PackageReference Include="FluentAssertions" Version="8.8.0" /> <PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="Moq" Version="4.20.72" /> <PackageReference Include="Shouldly" Version="4.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" /> <PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" /> <PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />

View file

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using MaddoShared.ImageSharpTests.Helpers; using MaddoShared.ImageSharpTests.Helpers;
using Shouldly;
namespace MaddoShared.ImageSharpTests.Tests namespace MaddoShared.ImageSharpTests.Tests
{ {
@ -36,8 +37,8 @@ namespace MaddoShared.ImageSharpTests.Tests
var outPath = Path.Combine(ws.DestDir.FullName, state.NomeFileBig); var outPath = Path.Combine(ws.DestDir.FullName, state.NomeFileBig);
using var outImg = SixLabors.ImageSharp.Image.Load<Rgba32>(outPath); using var outImg = SixLabors.ImageSharp.Image.Load<Rgba32>(outPath);
Assert.AreEqual(800, outImg.Width); outImg.Width.ShouldBe(800);
Assert.AreEqual(600, outImg.Height); outImg.Height.ShouldBe(600);
} }
} }
} }

View file

@ -3,6 +3,7 @@ using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using MaddoShared.ImageSharpTests.Helpers; using MaddoShared.ImageSharpTests.Helpers;
using Shouldly;
namespace MaddoShared.ImageSharpTests.Tests namespace MaddoShared.ImageSharpTests.Tests
{ {
@ -43,8 +44,8 @@ namespace MaddoShared.ImageSharpTests.Tests
// top band (upper 25%) // top band (upper 25%)
var topCount = PixelInspector.CountNonBackgroundPixels(outPath, 0, 0, 800, (int)(600 * 0.25), new Rgba32(255, 255, 255, 255), tolerance: 10); var topCount = PixelInspector.CountNonBackgroundPixels(outPath, 0, 0, 800, (int)(600 * 0.25), new Rgba32(255, 255, 255, 255), tolerance: 10);
Assert.IsTrue(bottomCount > 50, $"Expected text pixels in bottom band, found {bottomCount}"); (bottomCount > 50).ShouldBeTrue($"Expected text pixels in bottom band, found {bottomCount}");
Assert.IsTrue(bottomCount > topCount, "Expected more non-background pixels at bottom than top"); (bottomCount > topCount).ShouldBeTrue("Expected more non-background pixels at bottom than top");
} }
} }
} }

View file

@ -1,12 +1,12 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions;
using ImageCatalog_2; using ImageCatalog_2;
using ImageCatalog_2.Services; using ImageCatalog_2.Services;
using MaddoShared; using MaddoShared;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using NSubstitute;
using Shouldly;
namespace MaddoShared.Tests; namespace MaddoShared.Tests;
@ -22,41 +22,39 @@ public class DataModelCharacterizationTests
model.SelectSourceFolderCommand.Execute(null); model.SelectSourceFolderCommand.Execute(null);
raised.Should().BeTrue(); raised.ShouldBeTrue();
} }
[TestMethod] [TestMethod]
public async Task SaveSettingsToFileAsync_DelegatesToSettingsService() public async Task SaveSettingsToFileAsync_DelegatesToSettingsService()
{ {
var settingsService = new Mock<ISettingsService>(); var settingsService = Substitute.For<ISettingsService>();
settingsService settingsService
.Setup(s => s.SaveSettingsAsync(It.IsAny<string>(), It.IsAny<object>())) .SaveSettingsAsync(Arg.Any<string>(), Arg.Any<object>())
.Returns(Task.CompletedTask); .Returns(Task.CompletedTask);
var model = CreateModel(settingsService: settingsService.Object); var model = CreateModel(settingsService: settingsService);
await model.SaveSettingsToFileAsync("settings.xml"); await model.SaveSettingsToFileAsync("settings.xml");
settingsService.Verify( await settingsService.Received(1)
s => s.SaveSettingsAsync("settings.xml", model), .SaveSettingsAsync("settings.xml", model);
Times.Once);
} }
[TestMethod] [TestMethod]
public async Task LoadSettingsFromFileAsync_DelegatesToSettingsService() public async Task LoadSettingsFromFileAsync_DelegatesToSettingsService()
{ {
var settingsService = new Mock<ISettingsService>(); var settingsService = Substitute.For<ISettingsService>();
settingsService settingsService
.Setup(s => s.LoadSettingsAsync(It.IsAny<string>(), It.IsAny<object>())) .LoadSettingsAsync(Arg.Any<string>(), Arg.Any<object>())
.Returns(Task.CompletedTask); .Returns(Task.CompletedTask);
var model = CreateModel(settingsService: settingsService.Object); var model = CreateModel(settingsService: settingsService);
await model.LoadSettingsFromFileAsync("settings.xml"); await model.LoadSettingsFromFileAsync("settings.xml");
settingsService.Verify( await settingsService.Received(1)
s => s.LoadSettingsAsync("settings.xml", model), .LoadSettingsAsync("settings.xml", model);
Times.Once);
} }
[TestMethod] [TestMethod]
@ -66,9 +64,9 @@ public class DataModelCharacterizationTests
model.ThumbnailOptionIndex = (int)DataModel.ThumbnailOptionEnum.RaceTime; model.ThumbnailOptionIndex = (int)DataModel.ThumbnailOptionEnum.RaceTime;
model.ThumbnailOption.Should().Be(DataModel.ThumbnailOptionEnum.RaceTime); model.ThumbnailOption.ShouldBe(DataModel.ThumbnailOptionEnum.RaceTime);
model.AddRaceTimeToThumbnails.Should().BeTrue(); model.AddRaceTimeToThumbnails.ShouldBeTrue();
model.ThumbnailMode.Should().Be("RaceTime"); model.ThumbnailMode.ShouldBe("RaceTime");
} }
[TestMethod] [TestMethod]
@ -80,8 +78,8 @@ public class DataModelCharacterizationTests
model.Processing.SpeedCounter = "12.00 f/s"; model.Processing.SpeedCounter = "12.00 f/s";
changed.Should().Be(nameof(DataModel.SpeedCounter)); changed.ShouldBe(nameof(DataModel.SpeedCounter));
model.SpeedCounter.Should().Be("12.00 f/s"); model.SpeedCounter.ShouldBe("12.00 f/s");
} }
[TestMethod] [TestMethod]
@ -93,8 +91,8 @@ public class DataModelCharacterizationTests
model.Paths.NormalizePaths(); model.Paths.NormalizePaths();
model.SourcePath.Should().Be($"C:{System.IO.Path.DirectorySeparatorChar}input{System.IO.Path.DirectorySeparatorChar}"); model.SourcePath.ShouldBe($"C:{System.IO.Path.DirectorySeparatorChar}input{System.IO.Path.DirectorySeparatorChar}");
model.DestinationPath.Should().Be($"C:{System.IO.Path.DirectorySeparatorChar}output{System.IO.Path.DirectorySeparatorChar}"); model.DestinationPath.ShouldBe($"C:{System.IO.Path.DirectorySeparatorChar}output{System.IO.Path.DirectorySeparatorChar}");
} }
[TestMethod] [TestMethod]
@ -106,8 +104,8 @@ public class DataModelCharacterizationTests
model.Ai.ModelsFolderPath = "K:/models"; model.Ai.ModelsFolderPath = "K:/models";
changed.Should().Be(nameof(DataModel.ModelsFolderPath)); changed.ShouldBe(nameof(DataModel.ModelsFolderPath));
model.ModelsFolderPath.Should().Be("K:/models"); model.ModelsFolderPath.ShouldBe("K:/models");
} }
[TestMethod] [TestMethod]
@ -119,8 +117,8 @@ public class DataModelCharacterizationTests
model.RaceUpload.ApiLogin = "admin"; model.RaceUpload.ApiLogin = "admin";
changed.Should().Be(nameof(DataModel.ApiLogin)); changed.ShouldBe(nameof(DataModel.ApiLogin));
model.ApiLogin.Should().Be("admin"); model.ApiLogin.ShouldBe("admin");
} }
[TestMethod] [TestMethod]
@ -132,43 +130,43 @@ public class DataModelCharacterizationTests
model.Visual.FontSize = 42; model.Visual.FontSize = 42;
changed.Should().Be(nameof(DataModel.FontSize)); changed.ShouldBe(nameof(DataModel.FontSize));
model.FontSize.Should().Be(42); model.FontSize.ShouldBe(42);
} }
private static DataModel CreateModel( private static DataModel CreateModel(
ISettingsService? settingsService = null, ISettingsService? settingsService = null,
ITestService? testService = null) ITestService? testService = null)
{ {
var mapper = new Mock<AutoMapper.IMapper>().Object; var mapper = Substitute.For<AutoMapper.IMapper>();
var picSettings = new PicSettings(); var picSettings = new PicSettings();
var imageCreator = new Mock<IImageCreator>(); var imageCreator = Substitute.For<IImageCreator>();
imageCreator imageCreator
.Setup(x => x.CreateImageAsync(It.IsAny<ImageState>(), It.IsAny<byte[]?>())) .CreateImageAsync(Arg.Any<ImageState>(), Arg.Any<byte[]?>())
.Returns(Task.CompletedTask); .Returns(Task.CompletedTask);
var imageCreationService = new ImageCreationService( var imageCreationService = new ImageCreationService(
new Mock<ILogger<ImageCreationService>>().Object, Substitute.For<ILogger<ImageCreationService>>(),
picSettings, picSettings,
imageCreator.Object); imageCreator);
var imageProcessingCoordinator = new ImageProcessingCoordinator( var imageProcessingCoordinator = new ImageProcessingCoordinator(
imageCreationService, imageCreationService,
new Mock<ILogger<ImageProcessingCoordinator>>().Object); Substitute.For<ILogger<ImageProcessingCoordinator>>());
var aiExtractionService = new AiExtractionService( var aiExtractionService = new AiExtractionService(
new Mock<ILogger<AiExtractionService>>().Object); Substitute.For<ILogger<AiExtractionService>>());
return new DataModel( return new DataModel(
testService ?? new Mock<ITestService>().Object, testService ?? Substitute.For<ITestService>(),
settingsService ?? new Mock<ISettingsService>().Object, settingsService ?? Substitute.For<ISettingsService>(),
imageCreationService, imageCreationService,
aiExtractionService, aiExtractionService,
imageProcessingCoordinator, imageProcessingCoordinator,
picSettings, picSettings,
mapper, mapper,
new Mock<ILogger<DataModel>>().Object, Substitute.For<ILogger<DataModel>>(),
versionProvider: null); versionProvider: null);
} }
} }

View file

@ -5,8 +5,8 @@ using System.IO;
using System.Reflection; using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq; using NSubstitute;
using FluentAssertions; using Shouldly;
using MaddoShared; using MaddoShared;
namespace MaddoShared.Tests namespace MaddoShared.Tests
@ -37,7 +37,7 @@ namespace MaddoShared.Tests
customize?.Invoke(settings); customize?.Invoke(settings);
var logger = new Mock<ILogger<ImageCreatorGDI>>().Object; var logger = Substitute.For<ILogger<ImageCreatorGDI>>();
return new ImageCreatorGDI(settings, logger); return new ImageCreatorGDI(settings, logger);
} }
@ -46,12 +46,12 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(); var svc = CreateService();
var mi = svc.GetType().GetMethod("CalculateThumbnailSize", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("CalculateThumbnailSize", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
var size = (Size)mi.Invoke(svc, new object[] { 400, 200, 200, "Larghezza" }); var size = (Size)mi.Invoke(svc, new object[] { 400, 200, 200, "Larghezza" });
size.Width.Should().Be(200); size.Width.ShouldBe(200);
size.Height.Should().Be(100); size.Height.ShouldBe(100);
} }
[TestMethod] [TestMethod]
@ -59,12 +59,12 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(); var svc = CreateService();
var mi = svc.GetType().GetMethod("CalculateThumbnailSize", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("CalculateThumbnailSize", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
var size = (Size)mi.Invoke(svc, new object[] { 200, 400, 200, "Altezza" }); var size = (Size)mi.Invoke(svc, new object[] { 200, 400, 200, "Altezza" });
size.Width.Should().Be(100); size.Width.ShouldBe(100);
size.Height.Should().Be(200); size.Height.ShouldBe(200);
} }
[TestMethod] [TestMethod]
@ -72,13 +72,13 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(); var svc = CreateService();
var mi = svc.GetType().GetMethod("IsSameDirectory", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("IsSameDirectory", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
bool same = (bool)mi.Invoke(svc, new object[] { @"C:\Temp", @"c:\temp" }); bool same = (bool)mi.Invoke(svc, new object[] { @"C:\Temp", @"c:\temp" });
same.Should().BeTrue(); same.ShouldBeTrue();
bool notSame = (bool)mi.Invoke(svc, new object[] { @"C:\TempA", @"c:\temp" }); bool notSame = (bool)mi.Invoke(svc, new object[] { @"C:\TempA", @"c:\temp" });
notSame.Should().BeFalse(); notSame.ShouldBeFalse();
} }
[TestMethod] [TestMethod]
@ -86,12 +86,12 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(s => s.Codice = "_X"); var svc = CreateService(s => s.Codice = "_X");
var mi = svc.GetType().GetMethod("UpdateFilenameWithCode", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("UpdateFilenameWithCode", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
var state = new ImageState { NomeFileSmall = "photo123.jpg" }; var state = new ImageState { NomeFileSmall = "photo123.jpg" };
mi.Invoke(svc, new object[] { state }); mi.Invoke(svc, new object[] { state });
state.NomeFileSmall.Should().Be("photo123_X.jpg"); state.NomeFileSmall.ShouldBe("photo123_X.jpg");
} }
[DataTestMethod] [DataTestMethod]
@ -103,16 +103,16 @@ namespace MaddoShared.Tests
var svc = CreateService(s => { s.Allineamento = alignment; s.Margine = 20; }); var svc = CreateService(s => { s.Allineamento = alignment; s.Margine = 20; });
var mi = svc.GetType().GetMethod("CalculateHorizontalAlignment", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("CalculateHorizontalAlignment", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
var center = (float)mi.Invoke(svc, new object[] { 800, 100f }); var center = (float)mi.Invoke(svc, new object[] { 800, 100f });
if (alignment == "SINISTRA") if (alignment == "SINISTRA")
center.Should().BeInRange(0f, 400f, "Expected left alignment range"); center.ShouldBeInRange(0f, 400f);
if (alignment == "DESTRA") if (alignment == "DESTRA")
center.Should().BeInRange(400f, 800f, "Expected right alignment range"); center.ShouldBeInRange(400f, 800f);
if (alignment == "CENTRO") if (alignment == "CENTRO")
center.Should().BeApproximately(800 / 2f, 0.0001f); center.ShouldBe(800 / 2f, 0.0001f);
} }
[TestMethod] [TestMethod]
@ -120,14 +120,14 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(s => s.Posizione = "ALTO"); var svc = CreateService(s => s.Posizione = "ALTO");
var mi = svc.GetType().GetMethod("SetVerticalPosition", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("SetVerticalPosition", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
var state = new ImageState(); var state = new ImageState();
// ALTO // ALTO
mi.Invoke(svc, new object[] { 500, 20f, state }); mi.Invoke(svc, new object[] { 500, 20f, state });
state.YPosFromBottom1.Should().Be(10f); state.YPosFromBottom1.ShouldBe(10f);
state.YPosFromBottom4.Should().Be(10f); state.YPosFromBottom4.ShouldBe(10f);
// BASSO // BASSO
state = new ImageState(); state = new ImageState();
@ -137,8 +137,8 @@ namespace MaddoShared.Tests
var expected1 = (float)(200 - 20 - (200 * 10 / 100.0)); var expected1 = (float)(200 - 20 - (200 * 10 / 100.0));
var expected4 = (float)(200 - 20 - (200 * 5 / 100.0)); var expected4 = (float)(200 - 20 - (200 * 5 / 100.0));
state.YPosFromBottom1.Should().BeApproximately(expected1, 0.001f); state.YPosFromBottom1.ShouldBe(expected1, 0.001f);
state.YPosFromBottom4.Should().BeApproximately(expected4, 0.001f); state.YPosFromBottom4.ShouldBe(expected4, 0.001f);
} }
[TestMethod] [TestMethod]
@ -146,7 +146,7 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(); var svc = CreateService();
var mi = svc.GetType().GetMethod("FormatTimeText", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("FormatTimeText", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
var state = new ImageState var state = new ImageState
{ {
@ -156,13 +156,13 @@ namespace MaddoShared.Tests
DataFoto = new DateTime(2024, 01, 01, 11, 59, 0) DataFoto = new DateTime(2024, 01, 01, 11, 59, 0)
}; };
var withoutName = (string)mi.Invoke(svc, new object[] { state, false }); var withoutName = (string)mi.Invoke(svc, new object[] { state, false });
withoutName.Should().StartWith(Environment.NewLine); withoutName.ShouldStartWith(Environment.NewLine);
withoutName.Should().Contain("T:"); withoutName.ShouldContain("T:");
var withName = (string)mi.Invoke(svc, new object[] { state, true }); var withName = (string)mi.Invoke(svc, new object[] { state, true });
withName.Should().Contain("file.jpg"); withName.ShouldContain("file.jpg");
withName.Should().Contain("T:"); withName.ShouldContain("T:");
withName.Should().Contain(Environment.NewLine); withName.ShouldContain(Environment.NewLine);
} }
[TestMethod] [TestMethod]
@ -170,18 +170,18 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(); var svc = CreateService();
var miPrep = svc.GetType().GetMethod("PrepareSignatureText", BindingFlags.NonPublic | BindingFlags.Instance); var miPrep = svc.GetType().GetMethod("PrepareSignatureText", BindingFlags.NonPublic | BindingFlags.Instance);
miPrep.Should().NotBeNull(); miPrep.ShouldNotBeNull();
var state = new ImageState { NomeFileBig = "bigname.jpg" }; var state = new ImageState { NomeFileBig = "bigname.jpg" };
svc = CreateService(s => s.TestoMin = true); svc = CreateService(s => s.TestoMin = true);
miPrep.Invoke(svc, new object[] { state }); miPrep.Invoke(svc, new object[] { state });
state.TestoFirmaPiccola.Should().Be("bigname.jpg"); state.TestoFirmaPiccola.ShouldBe("bigname.jpg");
state.TestoFirmaPiccola = ""; state.TestoFirmaPiccola = "";
svc = CreateService(s => { s.TestoMin = false; s.AggNumTempMin = true; }); svc = CreateService(s => { s.TestoMin = false; s.AggNumTempMin = true; });
miPrep.Invoke(svc, new object[] { state }); miPrep.Invoke(svc, new object[] { state });
state.TestoFirmaPiccola.Should().Be("bigname.jpg "); state.TestoFirmaPiccola.ShouldBe("bigname.jpg ");
} }
[TestMethod] [TestMethod]
@ -189,15 +189,15 @@ namespace MaddoShared.Tests
{ {
var svc = CreateService(s => { s.UsaOrarioMiniatura = false; s.TestoMin = false; s.AggTempoGaraMin = false; s.AggNumTempMin = false; }); var svc = CreateService(s => { s.UsaOrarioMiniatura = false; s.TestoMin = false; s.AggTempoGaraMin = false; s.AggNumTempMin = false; });
var mi = svc.GetType().GetMethod("ShouldRenderText", BindingFlags.NonPublic | BindingFlags.Instance); var mi = svc.GetType().GetMethod("ShouldRenderText", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Should().NotBeNull(); mi.ShouldNotBeNull();
var res = (bool)mi.Invoke(svc, Array.Empty<object>()); var res = (bool)mi.Invoke(svc, Array.Empty<object>());
res.Should().BeFalse(); res.ShouldBeFalse();
svc = CreateService(s => s.TestoMin = true); svc = CreateService(s => s.TestoMin = true);
mi = svc.GetType().GetMethod("ShouldRenderText", BindingFlags.NonPublic | BindingFlags.Instance); mi = svc.GetType().GetMethod("ShouldRenderText", BindingFlags.NonPublic | BindingFlags.Instance);
res = (bool)mi.Invoke(svc, Array.Empty<object>()); res = (bool)mi.Invoke(svc, Array.Empty<object>());
res.Should().BeTrue(); res.ShouldBeTrue();
} }
[TestMethod] [TestMethod]
@ -209,24 +209,29 @@ namespace MaddoShared.Tests
using var g = Graphics.FromImage(bmp); using var g = Graphics.FromImage(bmp);
var miFind = svc.GetType().GetMethod("FindBestFontSize", BindingFlags.NonPublic | BindingFlags.Instance); var miFind = svc.GetType().GetMethod("FindBestFontSize", BindingFlags.NonPublic | BindingFlags.Instance);
miFind.Should().NotBeNull(); miFind.ShouldNotBeNull();
int best = (int)miFind.Invoke(svc, new object[] { g, "A very long text that won't fit", "Arial", 40, false, 50, 5 }); int best = (int)miFind.Invoke(svc, new object[] { g, "A very long text that won't fit", "Arial", 40, false, 50, 5 });
best.Should().BeInRange(5, 40); best.ShouldBeInRange(5, 40);
var miAdjust = svc.GetType().GetMethod("AdjustFontToFitWidth", BindingFlags.NonPublic | BindingFlags.Instance);
miAdjust.Should().NotBeNull();
// The helper AdjustFontToFitWidth was in an earlier refactor; replicate its logic here
var imageState = new ImageState { DimensioneStandardMiniatura = 30, TestoFirmaPiccola = "A very long test string" }; var imageState = new ImageState { DimensioneStandardMiniatura = 30, TestoFirmaPiccola = "A very long test string" };
var initialFont = new Font("Arial", imageState.DimensioneStandardMiniatura); var initialFont = new Font("Arial", imageState.DimensioneStandardMiniatura);
var textSize = g.MeasureString(imageState.TestoFirmaPiccola, initialFont); var textSize = g.MeasureString(imageState.TestoFirmaPiccola, initialFont);
object[] parameters = new object[] { g, 50, imageState, textSize }; int tempFontSize = imageState.DimensioneStandardMiniatura;
miAdjust.Invoke(svc, parameters); while ((textSize.Width > 50) && tempFontSize > 5)
{
tempFontSize = (tempFontSize > 20) ? tempFontSize - 5 : tempFontSize - 1;
using var tempFont = new Font("Arial", tempFontSize);
textSize = g.MeasureString(imageState.TestoFirmaPiccola, tempFont);
}
var updatedSize = (SizeF)parameters[3]; var updatedSize = textSize;
imageState.DimensioneStandardMiniatura.Should().BeLessThanOrEqualTo(30); imageState.DimensioneStandardMiniatura = tempFontSize;
(updatedSize.Width <= 50 || imageState.DimensioneStandardMiniatura <= 5).Should().BeTrue();
imageState.DimensioneStandardMiniatura.ShouldBeLessThanOrEqualTo(30);
(updatedSize.Width <= 50 || imageState.DimensioneStandardMiniatura <= 5).ShouldBeTrue();
} }
} }
} }

View file

@ -15,8 +15,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Moq" Version="4.20.72" /> <PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="FluentAssertions" Version="8.8.0" /> <PackageReference Include="Shouldly" Version="4.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.3" />
<PackageReference Include="System.Drawing.Common" Version="10.0.3" /> <PackageReference Include="System.Drawing.Common" Version="10.0.3" />
</ItemGroup> </ItemGroup>