using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.Extensions.Logging; using NSubstitute; using Shouldly; using MaddoShared; namespace MaddoShared.Tests { [TestClass] public class ImageCreatorSharpTests { private ImageCreatorGDI CreateService(Action customize = null) { var settings = new PicSettings { DimStandard = 20, DimStandardMiniatura = 10, LarghezzaSmall = 100, AltezzaSmall = 100, LarghezzaBig = 800, AltezzaBig = 600, Trasparenza = 50, IlFont = "Arial", Grassetto = false, Posizione = "CENTRO", Allineamento = "CENTRO", Margine = 10, MargVert = 10, TestoMin = false, AggNumTempMin = false }; customize?.Invoke(settings); var logger = Substitute.For>(); return new ImageCreatorGDI(settings, logger); } [TestMethod] public void CalculateThumbnailSize_Larghezza_UsesWidthScaling() { var svc = CreateService(); var mi = svc.GetType().GetMethod("CalculateThumbnailSize", BindingFlags.NonPublic | BindingFlags.Instance); mi.ShouldNotBeNull(); var size = (Size)mi.Invoke(svc, new object[] { 400, 200, 200, "Larghezza" }); size.Width.ShouldBe(200); size.Height.ShouldBe(100); } [TestMethod] public void CalculateThumbnailSize_Altezza_UsesHeightScaling() { var svc = CreateService(); var mi = svc.GetType().GetMethod("CalculateThumbnailSize", BindingFlags.NonPublic | BindingFlags.Instance); mi.ShouldNotBeNull(); var size = (Size)mi.Invoke(svc, new object[] { 200, 400, 200, "Altezza" }); size.Width.ShouldBe(100); size.Height.ShouldBe(200); } [TestMethod] public void IsSameDirectory_IsCaseInsensitive() { var svc = CreateService(); var mi = svc.GetType().GetMethod("IsSameDirectory", BindingFlags.NonPublic | BindingFlags.Instance); mi.ShouldNotBeNull(); bool same = (bool)mi.Invoke(svc, new object[] { @"C:\Temp", @"c:\temp" }); same.ShouldBeTrue(); bool notSame = (bool)mi.Invoke(svc, new object[] { @"C:\TempA", @"c:\temp" }); notSame.ShouldBeFalse(); } [TestMethod] public void UpdateFilenameWithCode_InsertsCodeBeforeExtension() { var svc = CreateService(s => s.Codice = "_X"); var mi = svc.GetType().GetMethod("UpdateFilenameWithCode", BindingFlags.NonPublic | BindingFlags.Instance); mi.ShouldNotBeNull(); var state = new ImageState { NomeFileSmall = "photo123.jpg" }; mi.Invoke(svc, new object[] { state }); state.NomeFileSmall.ShouldBe("photo123_X.jpg"); } [DataTestMethod] [DataRow("SINISTRA")] [DataRow("CENTRO")] [DataRow("DESTRA")] public void CalculateHorizontalAlignment_RespectsAlignment(string alignment) { var svc = CreateService(s => { s.Allineamento = alignment; s.Margine = 20; }); var mi = svc.GetType().GetMethod("CalculateHorizontalAlignment", BindingFlags.NonPublic | BindingFlags.Instance); mi.ShouldNotBeNull(); var center = (float)mi.Invoke(svc, new object[] { 800, 100f }); if (alignment == "SINISTRA") center.ShouldBeInRange(0f, 400f); if (alignment == "DESTRA") center.ShouldBeInRange(400f, 800f); if (alignment == "CENTRO") center.ShouldBe(800 / 2f, 0.0001f); } [TestMethod] public void SetVerticalPosition_AltoAndBasso_SetExpectedValues() { var svc = CreateService(s => s.Posizione = "ALTO"); var mi = svc.GetType().GetMethod("SetVerticalPosition", BindingFlags.NonPublic | BindingFlags.Instance); mi.ShouldNotBeNull(); var state = new ImageState(); // ALTO mi.Invoke(svc, new object[] { 500, 20f, state }); state.YPosFromBottom1.ShouldBe(10f); state.YPosFromBottom4.ShouldBe(10f); // BASSO state = new ImageState(); svc = CreateService(s => { s.Posizione = "BASSO"; s.Margine = 10; s.MargVert = 5; }); mi = svc.GetType().GetMethod("SetVerticalPosition", BindingFlags.NonPublic | BindingFlags.Instance); mi.Invoke(svc, new object[] { 200, 20f, state }); var expected1 = (float)(200 - 20 - (200 * 10 / 100.0)); var expected4 = (float)(200 - 20 - (200 * 5 / 100.0)); state.YPosFromBottom1.ShouldBe(expected1, 0.001f); state.YPosFromBottom4.ShouldBe(expected4, 0.001f); } [TestMethod] public void FormatTimeText_WithAndWithoutFileName_ProducesExpectedStrings() { var svc = CreateService(); var mi = svc.GetType().GetMethod("FormatTimeText", BindingFlags.NonPublic | BindingFlags.Instance); mi.ShouldNotBeNull(); var state = new ImageState { NomeFileBig = "file.jpg", TestoOrario = "T:", DataPartenzaI = new DateTime(2024, 01, 01, 12, 0, 0), DataFoto = new DateTime(2024, 01, 01, 11, 59, 0) }; var withoutName = (string)mi.Invoke(svc, new object[] { state, false }); withoutName.ShouldStartWith(Environment.NewLine); withoutName.ShouldContain("T:"); var withName = (string)mi.Invoke(svc, new object[] { state, true }); withName.ShouldContain("file.jpg"); withName.ShouldContain("T:"); withName.ShouldContain(Environment.NewLine); } [TestMethod] public void PrepareSignatureText_SetsSmallSignature_AccordingFlags() { var svc = CreateService(); var miPrep = svc.GetType().GetMethod("PrepareSignatureText", BindingFlags.NonPublic | BindingFlags.Instance); miPrep.ShouldNotBeNull(); var state = new ImageState { NomeFileBig = "bigname.jpg" }; svc = CreateService(s => s.TestoMin = true); miPrep.Invoke(svc, new object[] { state }); state.TestoFirmaPiccola.ShouldBe("bigname.jpg"); state.TestoFirmaPiccola = ""; svc = CreateService(s => { s.TestoMin = false; s.AggNumTempMin = true; }); miPrep.Invoke(svc, new object[] { state }); state.TestoFirmaPiccola.ShouldBe("bigname.jpg "); } [TestMethod] public void ShouldRenderText_ReturnsCorrectFlag() { 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); mi.ShouldNotBeNull(); var res = (bool)mi.Invoke(svc, Array.Empty()); res.ShouldBeFalse(); svc = CreateService(s => s.TestoMin = true); mi = svc.GetType().GetMethod("ShouldRenderText", BindingFlags.NonPublic | BindingFlags.Instance); res = (bool)mi.Invoke(svc, Array.Empty()); res.ShouldBeTrue(); } [TestMethod] public void FindBestFontSize_And_AdjustFontToFitWidth_ModifySizes() { var svc = CreateService(s => { s.IlFont = "Arial"; s.DimStandardMiniatura = 30; }); using var bmp = new Bitmap(400, 100); using var g = Graphics.FromImage(bmp); var miFind = svc.GetType().GetMethod("FindBestFontSize", BindingFlags.NonPublic | BindingFlags.Instance); miFind.ShouldNotBeNull(); int best = (int)miFind.Invoke(svc, new object[] { g, "A very long text that won't fit", "Arial", 40, false, 50, 5 }); best.ShouldBeInRange(5, 40); // 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 initialFont = new Font("Arial", imageState.DimensioneStandardMiniatura); var textSize = g.MeasureString(imageState.TestoFirmaPiccola, initialFont); int tempFontSize = imageState.DimensioneStandardMiniatura; 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 = textSize; imageState.DimensioneStandardMiniatura = tempFontSize; imageState.DimensioneStandardMiniatura.ShouldBeLessThanOrEqualTo(30); (updatedSize.Width <= 50 || imageState.DimensioneStandardMiniatura <= 5).ShouldBeTrue(); } } }