[MouseJump][CQ]Refactor "common" classes into a separate project (#34333)

* [Mouse Jump] - moving common code to MouseJump.Common project - #25482

* [Mouse Jump] - fixing warnings in MouseJump.Common - #25482

* [MouseJump] - cherrypick 5653b4 - Exclude MouseJump Common tests from the checks

# Conflicts:
#	src/modules/MouseUtils/MouseJump.Common.UnitTests/MouseJump.Common.UnitTests.csproj

* [mOuSEjUMP] - cherry pick 61aab9 - Fix ci build issues

# Conflicts:
#	src/modules/MouseUtils/MouseJump.Common.UnitTests/MouseJump.Common.UnitTests.csproj

* [Mouse Jump] - remove project type guids - #25482

* [Mouse Jump] - simplify mousejump *.csproj files - #25482

* [Mouse Jump] - fixing broken tests - #25482

* [Mouse Jump] - fixing broken build - #25482

* [Mouse Jump] - editing MouseJump.Common.UnitTests.csproj - #25482

* [Mouse Jump] - editing MouseJump.Common.csproj (UseWindowsForms=true) - #25482

* [Mouse Jump] - fixing spellcheck - #25482

* [MouseJump] - enabled implicit usings - #25482

* [Mouse Jump] - re-add csproj attributes - #27511

* ci: Fix signing of Common dll

---------

Co-authored-by: Clayton <mike.clayton@delinian.com>
This commit is contained in:
Michael Clayton
2024-10-21 17:38:07 +01:00
committed by GitHub
parent db3c8e621e
commit dc7c7ef2b7
87 changed files with 281 additions and 308 deletions

View File

@@ -0,0 +1,154 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MouseJump.Common.Helpers;
using MouseJump.Common.Imaging;
using MouseJump.Common.Models.Drawing;
using MouseJump.Common.Models.Styles;
namespace MouseJump.Common.UnitTests.Helpers;
[TestClass]
public static class DrawingHelperTests
{
[TestClass]
public sealed class GetPreviewLayoutTests
{
public sealed class TestCase
{
public TestCase(PreviewStyle previewStyle, List<RectangleInfo> screens, PointInfo activatedLocation, string desktopImageFilename, string expectedImageFilename)
{
this.PreviewStyle = previewStyle;
this.Screens = screens;
this.ActivatedLocation = activatedLocation;
this.DesktopImageFilename = desktopImageFilename;
this.ExpectedImageFilename = expectedImageFilename;
}
public PreviewStyle PreviewStyle { get; }
public List<RectangleInfo> Screens { get; }
public PointInfo ActivatedLocation { get; }
public string DesktopImageFilename { get; }
public string ExpectedImageFilename { get; }
}
public static IEnumerable<object[]> GetTestCases()
{
/* 4-grid */
yield return new object[]
{
new TestCase(
previewStyle: StyleHelper.DefaultPreviewStyle,
screens: new List<RectangleInfo>()
{
new(0, 0, 500, 500),
new(500, 0, 500, 500),
new(500, 500, 500, 500),
new(0, 500, 500, 500),
},
activatedLocation: new(x: 50, y: 50),
desktopImageFilename: "_test-4grid-desktop.png",
expectedImageFilename: "_test-4grid-expected.png"),
};
/* win 11 */
yield return new object[]
{
new TestCase(
previewStyle: StyleHelper.DefaultPreviewStyle,
screens: new List<RectangleInfo>()
{
new(5120, 349, 1920, 1080),
new(0, 0, 5120, 1440),
},
activatedLocation: new(x: 50, y: 50),
desktopImageFilename: "_test-win11-desktop.png",
expectedImageFilename: "_test-win11-expected.png"),
};
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
// load the fake desktop image
using var desktopImage = GetPreviewLayoutTests.LoadImageResource(data.DesktopImageFilename);
// draw the preview image
var previewLayout = LayoutHelper.GetPreviewLayout(
previewStyle: data.PreviewStyle,
screens: data.Screens,
activatedLocation: data.ActivatedLocation);
var imageCopyService = new StaticImageRegionCopyService(desktopImage);
using var actual = DrawingHelper.RenderPreview(previewLayout, imageCopyService);
// load the expected image
var expected = GetPreviewLayoutTests.LoadImageResource(data.ExpectedImageFilename);
// compare the images
var screens = System.Windows.Forms.Screen.AllScreens;
AssertImagesEqual(expected, actual);
}
private static Bitmap LoadImageResource(string filename)
{
// assume embedded resources are in the same source folder as this
// class, and the namespace hierarchy matches the folder structure.
// that way we can build resource names from the current namespace
var resourcePrefix = typeof(DrawingHelperTests).Namespace;
var resourceName = $"{resourcePrefix}.{filename}";
var assembly = Assembly.GetExecutingAssembly();
var resourceNames = assembly.GetManifestResourceNames();
if (!resourceNames.Contains(resourceName))
{
var message = $"Embedded resource '{resourceName}' does not exist. " +
"Valid resource names are: \r\n" + string.Join("\r\n", resourceNames);
throw new InvalidOperationException(message);
}
var stream = assembly.GetManifestResourceStream(resourceName)
?? throw new InvalidOperationException();
var image = (Bitmap)Image.FromStream(stream);
return image;
}
/// <summary>
/// Naive / brute force image comparison - we can optimise this later :-)
/// </summary>
private static void AssertImagesEqual(Bitmap expected, Bitmap actual)
{
Assert.AreEqual(
expected.Width,
actual.Width,
$"expected width: {expected.Width}, actual width: {actual.Width}");
Assert.AreEqual(
expected.Height,
actual.Height,
$"expected height: {expected.Height}, actual height: {actual.Height}");
for (var y = 0; y < expected.Height; y++)
{
for (var x = 0; x < expected.Width; x++)
{
var expectedPixel = expected.GetPixel(x, y);
var actualPixel = actual.GetPixel(x, y);
// allow a small tolerance for rounding differences in gdi
Assert.IsTrue(
(Math.Abs(expectedPixel.A - actualPixel.A) <= 1) &&
(Math.Abs(expectedPixel.R - actualPixel.R) <= 1) &&
(Math.Abs(expectedPixel.G - actualPixel.G) <= 1) &&
(Math.Abs(expectedPixel.B - actualPixel.B) <= 1),
$"images differ at pixel ({x}, {y}) - expected: {expectedPixel}, actual: {actualPixel}");
}
}
}
}
}

View File

@@ -0,0 +1,451 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MouseJump.Common.Helpers;
using MouseJump.Common.Models.Drawing;
using MouseJump.Common.Models.Layout;
using MouseJump.Common.Models.Styles;
namespace MouseJump.Common.UnitTests.Helpers;
[TestClass]
public static class LayoutHelperTests
{
/*
[TestClass]
public sealed class OldLayoutTests
{
public static IEnumerable<object[]> GetTestCases()
{
// check we handle rounding errors in scaling the preview form
// that might make the form *larger* than the current screen -
// e.g. a desktop 7168 x 1440 scaled to a screen 1024 x 768
// with a 5px form padding border:
//
// ((decimal)1014 / 7168) * 7168 = 1014.0000000000000000000000002
//
// +----------------+
// | |
// | 1 +-------+
// | | 0 |
// +----------------+-------+
layoutConfig = new LayoutConfig(
virtualScreenBounds: new(0, 0, 7168, 1440),
screens: new List<ScreenInfo>
{
new(HMONITOR.Null, false, new(6144, 0, 1024, 768), new(6144, 0, 1024, 768)),
new(HMONITOR.Null, false, new(0, 0, 6144, 1440), new(0, 0, 6144, 1440)),
},
activatedLocation: new(6656, 384),
activatedScreenIndex: 0,
activatedScreenNumber: 1,
maximumFormSize: new(1600, 1200),
formPadding: new(5, 5, 5, 5),
previewPadding: new(0, 0, 0, 0));
layoutInfo = new LayoutInfo(
layoutConfig: layoutConfig,
formBounds: new(6144, 277.14732M, 1024, 213.70535M),
previewBounds: new(0, 0, 1014, 203.70535M),
screenBounds: new List<RectangleInfo>
{
new(869.14285M, 0, 144.85714M, 108.642857M),
new(0, 0, 869.142857M, 203.705357M),
},
activatedScreenBounds: new(6144, 0, 1024, 768));
yield return new object[] { new TestCase(layoutConfig, layoutInfo) };
// check we handle rounding errors in scaling the preview form
// that might make the form a pixel *smaller* than the current screen -
// e.g. a desktop 7168 x 1440 scaled to a screen 1024 x 768
// with a 5px form padding border:
//
// ((decimal)1280 / 7424) * 7424 = 1279.9999999999999999999999999
//
// +----------------+
// | |
// | 1 +-------+
// | | 0 |
// +----------------+-------+
layoutConfig = new LayoutConfig(
virtualScreenBounds: new(0, 0, 7424, 1440),
screens: new List<ScreenInfo>
{
new(HMONITOR.Null, false, new(6144, 0, 1280, 768), new(6144, 0, 1280, 768)),
new(HMONITOR.Null, false, new(0, 0, 6144, 1440), new(0, 0, 6144, 1440)),
},
activatedLocation: new(6784, 384),
activatedScreenIndex: 0,
activatedScreenNumber: 1,
maximumFormSize: new(1600, 1200),
formPadding: new(5, 5, 5, 5),
previewPadding: new(0, 0, 0, 0));
layoutInfo = new LayoutInfo(
layoutConfig: layoutConfig,
formBounds: new(
6144,
255.83189M, // (768 - (((decimal)(1280-10) / 7424 * 1440) + 10)) / 2
1280,
256.33620M // ((decimal)(1280 - 10) / 7424 * 1440) + 10
),
previewBounds: new(0, 0, 1270, 246.33620M),
screenBounds: new List<RectangleInfo>
{
new(1051.03448M, 0, 218.96551M, 131.37931M),
new(0, 0M, 1051.03448M, 246.33620M),
},
activatedScreenBounds: new(6144, 0, 1280, 768));
yield return new object[] { new TestCase(layoutConfig, layoutInfo) };
}
}
*/
[TestClass]
public sealed class GetPreviewLayoutTests
{
public sealed class TestCase
{
public TestCase(PreviewStyle previewStyle, List<RectangleInfo> screens, PointInfo activatedLocation, PreviewLayout expectedResult)
{
this.PreviewStyle = previewStyle;
this.Screens = screens;
this.ActivatedLocation = activatedLocation;
this.ExpectedResult = expectedResult;
}
public PreviewStyle PreviewStyle { get; }
public List<RectangleInfo> Screens { get; }
public PointInfo ActivatedLocation { get; }
public PreviewLayout ExpectedResult { get; }
}
public static IEnumerable<object[]> GetTestCases()
{
// happy path - single screen with 50% scaling,
// *has* a preview borders but *no* screenshot borders
//
// +----------------+
// | |
// | 0 |
// | |
// +----------------+
var previewStyle = new PreviewStyle(
canvasSize: new(
width: 524,
height: 396
),
canvasStyle: new(
marginStyle: MarginStyle.Empty,
borderStyle: new(
color: SystemColors.Highlight,
all: 5,
depth: 3),
paddingStyle: new(
all: 1),
backgroundStyle: new(
color1: Color.FromArgb(13, 87, 210), // light blue
color2: Color.FromArgb(3, 68, 192) // darker blue
)
),
screenStyle: BoxStyle.Empty);
var screens = new List<RectangleInfo>
{
new(0, 0, 1024, 768),
};
var activatedLocation = new PointInfo(512, 384);
var previewLayout = new PreviewLayout(
virtualScreen: new(0, 0, 1024, 768),
screens: screens,
activatedScreenIndex: 0,
formBounds: new(250, 186, 524, 396),
previewStyle: previewStyle,
previewBounds: new(
outerBounds: new(0, 0, 524, 396),
marginBounds: new(0, 0, 524, 396),
borderBounds: new(0, 0, 524, 396),
paddingBounds: new(5, 5, 514, 386),
contentBounds: new(6, 6, 512, 384)
),
screenshotBounds: new()
{
new(
outerBounds: new(6, 6, 512, 384),
marginBounds: new(6, 6, 512, 384),
borderBounds: new(6, 6, 512, 384),
paddingBounds: new(6, 6, 512, 384),
contentBounds: new(6, 6, 512, 384)
),
});
yield return new object[] { new TestCase(previewStyle, screens, activatedLocation, previewLayout) };
// happy path - single screen with 50% scaling,
// *no* preview borders but *has* screenshot borders
//
// +----------------+
// | |
// | 0 |
// | |
// +----------------+
previewStyle = new PreviewStyle(
canvasSize: new(
width: 512,
height: 384
),
canvasStyle: BoxStyle.Empty,
screenStyle: new(
marginStyle: new(
all: 1),
borderStyle: new(
color: SystemColors.Highlight,
all: 5,
depth: 3),
paddingStyle: PaddingStyle.Empty,
backgroundStyle: new(
color1: Color.FromArgb(13, 87, 210), // light blue
color2: Color.FromArgb(3, 68, 192) // darker blue
)
));
screens = new List<RectangleInfo>
{
new(0, 0, 1024, 768),
};
activatedLocation = new PointInfo(512, 384);
previewLayout = new PreviewLayout(
virtualScreen: new(0, 0, 1024, 768),
screens: screens,
activatedScreenIndex: 0,
formBounds: new(256, 192, 512, 384),
previewStyle: previewStyle,
previewBounds: new(
outerBounds: new(0, 0, 512, 384),
marginBounds: new(0, 0, 512, 384),
borderBounds: new(0, 0, 512, 384),
paddingBounds: new(0, 0, 512, 384),
contentBounds: new(0, 0, 512, 384)
),
screenshotBounds: new()
{
new(
outerBounds: new(0, 0, 512, 384),
marginBounds: new(0, 0, 512, 384),
borderBounds: new(1, 1, 510, 382),
paddingBounds: new(6, 6, 500, 372),
contentBounds: new(6, 6, 500, 372)
),
});
yield return new object[] { new TestCase(previewStyle, screens, activatedLocation, previewLayout) };
// primary monitor not topmost / leftmost - if there are screens
// that are further left or higher up than the primary monitor
// they'll have negative coordinates which has caused some
// issues with calculations in the past. this test will make
// sure we handle screens with negative coordinates gracefully
//
// +-------+
// | 0 +----------------+
// +-------+ |
// | 1 |
// | |
// +----------------+
previewStyle = new PreviewStyle(
canvasSize: new(
width: 716,
height: 204
),
canvasStyle: new(
marginStyle: MarginStyle.Empty,
borderStyle: new(
color: SystemColors.Highlight,
all: 5,
depth: 3),
paddingStyle: new(
all: 1),
backgroundStyle: new(
color1: Color.FromArgb(13, 87, 210), // light blue
color2: Color.FromArgb(3, 68, 192) // darker blue
)
),
screenStyle: new(
marginStyle: new(
all: 1),
borderStyle: new(
color: SystemColors.Highlight,
all: 5,
depth: 3),
paddingStyle: PaddingStyle.Empty,
backgroundStyle: new(
color1: Color.FromArgb(13, 87, 210), // light blue
color2: Color.FromArgb(3, 68, 192) // darker blue
)
));
screens = new List<RectangleInfo>
{
new(-1920, -480, 1920, 1080),
new(0, 0, 5120, 1440),
};
activatedLocation = new(-960, 60);
previewLayout = new PreviewLayout(
virtualScreen: new(-1920, -480, 7040, 1920),
screens: screens,
activatedScreenIndex: 0,
formBounds: new(-1318, -42, 716, 204),
previewStyle: previewStyle,
previewBounds: new(
outerBounds: new(0, 0, 716, 204),
marginBounds: new(0, 0, 716, 204),
borderBounds: new(0, 0, 716, 204),
paddingBounds: new(5, 5, 706, 194),
contentBounds: new(6, 6, 704, 192)
),
screenshotBounds: new()
{
new(
outerBounds: new(6, 6, 192, 108),
marginBounds: new(6, 6, 192, 108),
borderBounds: new(7, 7, 190, 106),
paddingBounds: new(12, 12, 180, 96),
contentBounds: new(12, 12, 180, 96)
),
new(
outerBounds: new(198, 54, 512, 144),
marginBounds: new(198, 54, 512, 144),
borderBounds: new(199, 55, 510, 142),
paddingBounds: new(204, 60, 500, 132),
contentBounds: new(204, 60, 500, 132)
),
});
yield return new object[] { new TestCase(previewStyle, screens, activatedLocation, previewLayout) };
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
// note - even if values are within 0.0001M of each other they could
// still round to different values - e.g.
// (int)1279.999999999999 -> 1279
// vs
// (int)1280.000000000000 -> 1280
// so we'll compare the raw values, *and* convert to an int-based
// Rectangle to compare rounded values
var actual = LayoutHelper.GetPreviewLayout(data.PreviewStyle, data.Screens, data.ActivatedLocation);
var expected = data.ExpectedResult;
var options = new JsonSerializerOptions
{
WriteIndented = true,
};
Assert.AreEqual(
JsonSerializer.Serialize(expected, options),
JsonSerializer.Serialize(actual, options));
}
}
[TestClass]
public sealed class GetBoxBoundsFromContentBoundsTests
{
public sealed class TestCase
{
public TestCase(RectangleInfo contentBounds, BoxStyle boxStyle, BoxBounds expectedResult)
{
this.ContentBounds = contentBounds;
this.BoxStyle = boxStyle;
this.ExpectedResult = expectedResult;
}
public RectangleInfo ContentBounds { get; set; }
public BoxStyle BoxStyle { get; set; }
public BoxBounds ExpectedResult { get; set; }
}
public static IEnumerable<object[]> GetTestCases()
{
yield return new[]
{
new TestCase(
contentBounds: new(100, 100, 800, 600),
boxStyle: new(
marginStyle: new(3),
borderStyle: new(Color.Red, 5, 0),
paddingStyle: new(7),
backgroundStyle: BackgroundStyle.Empty),
expectedResult: new(
outerBounds: new(85, 85, 830, 630),
marginBounds: new(85, 85, 830, 630),
borderBounds: new(88, 88, 824, 624),
paddingBounds: new(93, 93, 814, 614),
contentBounds: new(100, 100, 800, 600))),
};
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
var actual = LayoutHelper.GetBoxBoundsFromContentBounds(data.ContentBounds, data.BoxStyle);
var expected = data.ExpectedResult;
Assert.AreEqual(
JsonSerializer.Serialize(expected),
JsonSerializer.Serialize(actual));
}
}
[TestClass]
public sealed class GetBoxBoundsFromOuterBoundsTests
{
public sealed class TestCase
{
public TestCase(RectangleInfo outerBounds, BoxStyle boxStyle, BoxBounds expectedResult)
{
this.OuterBounds = outerBounds;
this.BoxStyle = boxStyle;
this.ExpectedResult = expectedResult;
}
public RectangleInfo OuterBounds { get; set; }
public BoxStyle BoxStyle { get; set; }
public BoxBounds ExpectedResult { get; set; }
}
public static IEnumerable<object[]> GetTestCases()
{
yield return new[]
{
new TestCase(
outerBounds: new(85, 85, 830, 630),
boxStyle: new(
marginStyle: new(3),
borderStyle: new(Color.Red, 5, 0),
paddingStyle: new(7),
backgroundStyle: BackgroundStyle.Empty),
expectedResult: new(
outerBounds: new(85, 85, 830, 630),
marginBounds: new(85, 85, 830, 630),
borderBounds: new(88, 88, 824, 624),
paddingBounds: new(93, 93, 814, 614),
contentBounds: new(100, 100, 800, 600))),
};
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
var actual = LayoutHelper.GetBoxBoundsFromOuterBounds(data.OuterBounds, data.BoxStyle);
var expected = data.ExpectedResult;
Assert.AreEqual(
JsonSerializer.Serialize(expected),
JsonSerializer.Serialize(actual));
}
}
}

View File

@@ -0,0 +1,73 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MouseJump.Common.Helpers;
using MouseJump.Common.Models.Drawing;
namespace MouseJump.Common.UnitTests.Helpers;
[TestClass]
public static class MouseHelperTests
{
[TestClass]
public sealed class GetJumpLocationTests
{
public sealed class TestCase
{
public TestCase(PointInfo previewLocation, SizeInfo previewSize, RectangleInfo desktopBounds, PointInfo expectedResult)
{
this.PreviewLocation = previewLocation;
this.PreviewSize = previewSize;
this.DesktopBounds = desktopBounds;
this.ExpectedResult = expectedResult;
}
public PointInfo PreviewLocation { get; }
public SizeInfo PreviewSize { get; }
public RectangleInfo DesktopBounds { get; }
public PointInfo ExpectedResult { get; }
}
public static IEnumerable<object[]> GetTestCases()
{
// screen corners and midpoint with a zero origin
yield return new object[] { new TestCase(new(0, 0), new(160, 120), new(0, 0, 1600, 1200), new(0, 0)) };
yield return new object[] { new TestCase(new(160, 0), new(160, 120), new(0, 0, 1600, 1200), new(1600, 0)) };
yield return new object[] { new TestCase(new(0, 120), new(160, 120), new(0, 0, 1600, 1200), new(0, 1200)) };
yield return new object[] { new TestCase(new(160, 120), new(160, 120), new(0, 0, 1600, 1200), new(1600, 1200)) };
yield return new object[] { new TestCase(new(80, 60), new(160, 120), new(0, 0, 1600, 1200), new(800, 600)) };
// screen corners and midpoint with a positive origin
yield return new object[] { new TestCase(new(0, 0), new(160, 120), new(1000, 1000, 1600, 1200), new(1000, 1000)) };
yield return new object[] { new TestCase(new(160, 0), new(160, 120), new(1000, 1000, 1600, 1200), new(2600, 1000)) };
yield return new object[] { new TestCase(new(0, 120), new(160, 120), new(1000, 1000, 1600, 1200), new(1000, 2200)) };
yield return new object[] { new TestCase(new(160, 120), new(160, 120), new(1000, 1000, 1600, 1200), new(2600, 2200)) };
yield return new object[] { new TestCase(new(80, 60), new(160, 120), new(1000, 1000, 1600, 1200), new(1800, 1600)) };
// screen corners and midpoint with a negative origin
yield return new object[] { new TestCase(new(0, 0), new(160, 120), new(-1000, -1000, 1600, 1200), new(-1000, -1000)) };
yield return new object[] { new TestCase(new(160, 0), new(160, 120), new(-1000, -1000, 1600, 1200), new(600, -1000)) };
yield return new object[] { new TestCase(new(0, 120), new(160, 120), new(-1000, -1000, 1600, 1200), new(-1000, 200)) };
yield return new object[] { new TestCase(new(160, 120), new(160, 120), new(-1000, -1000, 1600, 1200), new(600, 200)) };
yield return new object[] { new TestCase(new(80, 60), new(160, 120), new(-1000, -1000, 1600, 1200), new(-200, -400)) };
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
var actual = MouseHelper.GetJumpLocation(
data.PreviewLocation,
data.PreviewSize,
data.DesktopBounds);
var expected = data.ExpectedResult;
Assert.AreEqual(expected.X, actual.X);
Assert.AreEqual(expected.Y, actual.Y);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

View File

@@ -0,0 +1,140 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MouseJump.Common.Models.Drawing;
namespace MouseJump.Common.UnitTests.Models.Drawing;
[TestClass]
public static class RectangleInfoTests
{
[TestClass]
public sealed class CenterTests
{
public sealed class TestCase
{
public TestCase(RectangleInfo rectangle, PointInfo point, RectangleInfo expectedResult)
{
this.Rectangle = rectangle;
this.Point = point;
this.ExpectedResult = expectedResult;
}
public RectangleInfo Rectangle { get; }
public PointInfo Point { get; }
public RectangleInfo ExpectedResult { get; }
}
public static IEnumerable<object[]> GetTestCases()
{
// zero-sized
yield return new object[] { new TestCase(new(0, 0, 0, 0), new(0, 0), new(0, 0, 0, 0)), };
// zero-origin
yield return new object[] { new TestCase(new(0, 0, 200, 200), new(100, 100), new(0, 0, 200, 200)), };
yield return new object[] { new TestCase(new(0, 0, 200, 200), new(500, 500), new(400, 400, 200, 200)), };
yield return new object[] { new TestCase(new(0, 0, 800, 600), new(1000, 1000), new(600, 700, 800, 600)), };
// non-zero origin
yield return new object[] { new TestCase(new(1000, 2000, 200, 200), new(100, 100), new(0, 0, 200, 200)), };
yield return new object[] { new TestCase(new(1000, 2000, 200, 200), new(500, 500), new(400, 400, 200, 200)), };
yield return new object[] { new TestCase(new(1000, 2000, 800, 600), new(1000, 1000), new(600, 700, 800, 600)), };
// negative result
yield return new object[] { new TestCase(new(0, 0, 1000, 1200), new(300, 300), new(-200, -300, 1000, 1200)), };
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
var actual = data.Rectangle.Center(data.Point);
var expected = data.ExpectedResult;
Assert.AreEqual(expected.X, actual.X);
Assert.AreEqual(expected.Y, actual.Y);
Assert.AreEqual(expected.Width, actual.Width);
Assert.AreEqual(expected.Height, actual.Height);
}
}
[TestClass]
public sealed class ClampTests
{
public sealed class TestCase
{
public TestCase(RectangleInfo inner, RectangleInfo outer, RectangleInfo expectedResult)
{
this.Inner = inner;
this.Outer = outer;
this.ExpectedResult = expectedResult;
}
public RectangleInfo Inner { get; }
public RectangleInfo Outer { get; }
public RectangleInfo ExpectedResult { get; }
}
public static IEnumerable<object[]> GetTestCases()
{
// already inside - obj fills bounds exactly
yield return new object[]
{
new TestCase(new(0, 0, 100, 100), new(0, 0, 100, 100), new(0, 0, 100, 100)),
};
// already inside - obj exactly in each corner
yield return new object[]
{
new TestCase(new(0, 0, 100, 100), new(0, 0, 200, 200), new(0, 0, 100, 100)),
};
yield return new object[]
{
new TestCase(new(100, 0, 100, 100), new(0, 0, 200, 200), new(100, 0, 100, 100)),
};
yield return new object[]
{
new TestCase(new(0, 100, 100, 100), new(0, 0, 200, 200), new(0, 100, 100, 100)),
};
yield return new object[]
{
new TestCase(new(100, 100, 100, 100), new(0, 0, 200, 200), new(100, 100, 100, 100)),
};
// move inside - obj outside each corner
yield return new object[]
{
new TestCase(new(-50, -50, 100, 100), new(0, 0, 200, 200), new(0, 0, 100, 100)),
};
yield return new object[]
{
new TestCase(new(250, -50, 100, 100), new(0, 0, 200, 200), new(100, 0, 100, 100)),
};
yield return new object[]
{
new TestCase(new(-50, 250, 100, 100), new(0, 0, 200, 200), new(0, 100, 100, 100)),
};
yield return new object[]
{
new TestCase(new(150, 150, 100, 100), new(0, 0, 200, 200), new(100, 100, 100, 100)),
};
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
var actual = data.Inner.Clamp(data.Outer);
var expected = data.ExpectedResult;
Assert.AreEqual(expected.X, actual.X);
Assert.AreEqual(expected.Y, actual.Y);
Assert.AreEqual(expected.Width, actual.Width);
Assert.AreEqual(expected.Height, actual.Height);
}
}
}

View File

@@ -0,0 +1,105 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MouseJump.Common.Models.Drawing;
namespace MouseJump.Common.UnitTests.Models.Drawing;
[TestClass]
public static class SizeInfoTests
{
[TestClass]
public sealed class ScaleToFitTests
{
public sealed class TestCase
{
public TestCase(SizeInfo obj, SizeInfo bounds, SizeInfo expectedResult)
{
this.Obj = obj;
this.Bounds = bounds;
this.ExpectedResult = expectedResult;
}
public SizeInfo Obj { get; }
public SizeInfo Bounds { get; }
public SizeInfo ExpectedResult { get; }
}
public static IEnumerable<object[]> GetTestCases()
{
// identity tests
yield return new object[] { new TestCase(new(512, 384), new(512, 384), new(512, 384)), };
yield return new object[] { new TestCase(new(1024, 768), new(1024, 768), new(1024, 768)), };
// general tests
yield return new object[] { new TestCase(new(512, 384), new(2048, 1536), new(2048, 1536)), };
yield return new object[] { new TestCase(new(2048, 1536), new(1024, 768), new(1024, 768)), };
// scale to fit width
yield return new object[] { new TestCase(new(512, 384), new(2048, 3072), new(2048, 1536)), };
// scale to fit height
yield return new object[] { new TestCase(new(512, 384), new(4096, 1536), new(2048, 1536)), };
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
var actual = data.Obj.ScaleToFit(data.Bounds);
var expected = data.ExpectedResult;
Assert.AreEqual(expected.Width, actual.Width);
Assert.AreEqual(expected.Height, actual.Height);
}
}
[TestClass]
public sealed class ScaleToFitRatioTests
{
public sealed class TestCase
{
public TestCase(SizeInfo obj, SizeInfo bounds, decimal expectedResult)
{
this.Obj = obj;
this.Bounds = bounds;
this.ExpectedResult = expectedResult;
}
public SizeInfo Obj { get; }
public SizeInfo Bounds { get; }
public decimal ExpectedResult { get; }
}
public static IEnumerable<object[]> GetTestCases()
{
// identity tests
yield return new object[] { new TestCase(new(512, 384), new(512, 384), 1), };
yield return new object[] { new TestCase(new(1024, 768), new(1024, 768), 1), };
// general tests
yield return new object[] { new TestCase(new(512, 384), new(2048, 1536), 4), };
yield return new object[] { new TestCase(new(2048, 1536), new(1024, 768), 0.5M), };
// scale to fit width
yield return new object[] { new TestCase(new(512, 384), new(2048, 3072), 4), };
// scale to fit height
yield return new object[] { new TestCase(new(512, 384), new(4096, 1536), 4), };
}
[TestMethod]
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
public void RunTestCases(TestCase data)
{
var actual = data.Obj.ScaleToFitRatio(data.Bounds);
var expected = data.ExpectedResult;
Assert.AreEqual(expected, actual);
}
}
}

View File

@@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- Look at Directory.Build.props in root for common stuff as well -->
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
<PropertyGroup>
<ProjectGuid>{D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}</ProjectGuid>
<AssemblyName>PowerToys.MouseJump.Common.UnitTests</AssemblyName>
<AssemblyTitle>PowerToys.MouseJump.Common.UnitTests</AssemblyTitle>
<AssemblyDescription>PowerToys MouseJump.Common.UnitTests</AssemblyDescription>
<OutputType>Library</OutputType>
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\MouseJump.Common.UnitTests\</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<None Remove="Helpers\_test-4grid-desktop.png" />
<None Remove="Helpers\_test-4grid-expected.png" />
<None Remove="Helpers\_test-win11-desktop.png" />
<None Remove="Helpers\_test-win11-expected.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Helpers\_test-4grid-desktop.png" />
<EmbeddedResource Include="Helpers\_test-4grid-expected.png" />
<EmbeddedResource Include="Helpers\_test-win11-desktop.png" />
<EmbeddedResource Include="Helpers\_test-win11-expected.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MSTest" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MouseJump.Common\MouseJump.Common.csproj" />
</ItemGroup>
</Project>