mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
[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:
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 |
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user