mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 18:26:39 +02:00
* [Mouse Jump] - screenshot performance (#24607) * [Mouse Jump] - add words to spellchecker (#24607) * [Mouse Jump] - progressive activation (#24607) * [Mouse Jump] - fixing build (#24607) * [Mouse Jump] - fixing jump location, add unit tests, refactor (#24607) * [Mouse Jump] - removed testing code (#24607) * [Mouse Jump] added failing tests for * [Mouse Jump] - fix problem with some monitor layouts (#24607) * [Mouse Jump] - cleaning up some comments and namepsaces * [Mouse Jump] - added another screen layout test (#24607)
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
// 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.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MouseJumpUI.Drawing.Models;
|
||||
|
||||
namespace MouseJumpUI.UnitTests.Drawing;
|
||||
|
||||
[TestClass]
|
||||
public static class RectangleInfoTests
|
||||
{
|
||||
[TestClass]
|
||||
public class CenterTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(RectangleInfo rectangle, PointInfo point, RectangleInfo expectedResult)
|
||||
{
|
||||
this.Rectangle = rectangle;
|
||||
this.Point = point;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public RectangleInfo Rectangle { get; set; }
|
||||
|
||||
public PointInfo Point { get; set; }
|
||||
|
||||
public RectangleInfo ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// zero-sized
|
||||
yield return new[] { new TestCase(new(0, 0, 0, 0), new(0, 0), new(0, 0, 0, 0)), };
|
||||
|
||||
// zero-origin
|
||||
yield return new[] { new TestCase(new(0, 0, 200, 200), new(100, 100), new(0, 0, 200, 200)), };
|
||||
yield return new[] { new TestCase(new(0, 0, 200, 200), new(500, 500), new(400, 400, 200, 200)), };
|
||||
yield return new[] { new TestCase(new(0, 0, 800, 600), new(1000, 1000), new(600, 700, 800, 600)), };
|
||||
|
||||
// non-zero origin
|
||||
yield return new[] { new TestCase(new(1000, 2000, 200, 200), new(100, 100), new(0, 0, 200, 200)), };
|
||||
yield return new[] { new TestCase(new(1000, 2000, 200, 200), new(500, 500), new(400, 400, 200, 200)), };
|
||||
yield return new[] { new TestCase(new(1000, 2000, 800, 600), new(1000, 1000), new(600, 700, 800, 600)), };
|
||||
|
||||
// negative result
|
||||
yield return new[] { 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 class ClampTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(RectangleInfo inner, RectangleInfo outer, RectangleInfo expectedResult)
|
||||
{
|
||||
this.Inner = inner;
|
||||
this.Outer = outer;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public RectangleInfo Inner { get; set; }
|
||||
|
||||
public RectangleInfo Outer { get; set; }
|
||||
|
||||
public RectangleInfo ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// already inside - obj fills bounds exactly
|
||||
yield return new[]
|
||||
{
|
||||
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[]
|
||||
{
|
||||
new TestCase(new(0, 0, 100, 100), new(0, 0, 200, 200), new(0, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(100, 0, 100, 100), new(0, 0, 200, 200), new(100, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(0, 100, 100, 100), new(0, 0, 200, 200), new(0, 100, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
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[]
|
||||
{
|
||||
new TestCase(new(-50, -50, 100, 100), new(0, 0, 200, 200), new(0, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(250, -50, 100, 100), new(0, 0, 200, 200), new(100, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(-50, 250, 100, 100), new(0, 0, 200, 200), new(0, 100, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
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 System.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MouseJumpUI.Drawing.Models;
|
||||
|
||||
namespace MouseJumpUI.UnitTests.Drawing;
|
||||
|
||||
public sealed class SizeInfoTests
|
||||
{
|
||||
[TestClass]
|
||||
public class ScaleToFitTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(SizeInfo obj, SizeInfo bounds, SizeInfo expectedResult)
|
||||
{
|
||||
this.Obj = obj;
|
||||
this.Bounds = bounds;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public SizeInfo Obj { get; set; }
|
||||
|
||||
public SizeInfo Bounds { get; set; }
|
||||
|
||||
public SizeInfo ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// identity tests
|
||||
yield return new[] { new TestCase(new(512, 384), new(512, 384), new(512, 384)), };
|
||||
yield return new[] { new TestCase(new(1024, 768), new(1024, 768), new(1024, 768)), };
|
||||
|
||||
// general tests
|
||||
yield return new[] { new TestCase(new(512, 384), new(2048, 1536), new(2048, 1536)), };
|
||||
yield return new[] { new TestCase(new(2048, 1536), new(1024, 768), new(1024, 768)), };
|
||||
|
||||
// scale to fit width
|
||||
yield return new[] { new TestCase(new(512, 384), new(2048, 3072), new(2048, 1536)), };
|
||||
|
||||
// scale to fit height
|
||||
yield return new[] { 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 class ScaleToFitRatioTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(SizeInfo obj, SizeInfo bounds, decimal expectedResult)
|
||||
{
|
||||
this.Obj = obj;
|
||||
this.Bounds = bounds;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public SizeInfo Obj { get; set; }
|
||||
|
||||
public SizeInfo Bounds { get; set; }
|
||||
|
||||
public decimal ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// identity tests
|
||||
yield return new[] { new TestCase(new(512, 384), new(512, 384), 1), };
|
||||
yield return new[] { new TestCase(new(1024, 768), new(1024, 768), 1), };
|
||||
|
||||
// general tests
|
||||
yield return new[] { new TestCase(new(512, 384), new(2048, 1536), 4), };
|
||||
yield return new[] { new TestCase(new(2048, 1536), new(1024, 768), 0.5M), };
|
||||
|
||||
// scale to fit width
|
||||
yield return new[] { new TestCase(new(512, 384), new(2048, 3072), 4), };
|
||||
|
||||
// scale to fit height
|
||||
yield return new[] { 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,223 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MouseJumpUI.Drawing.Models;
|
||||
using MouseJumpUI.Helpers;
|
||||
|
||||
namespace MouseJumpUI.UnitTests.Helpers;
|
||||
|
||||
[TestClass]
|
||||
public static class DrawingHelperTests
|
||||
{
|
||||
[TestClass]
|
||||
public class CalculateLayoutInfoTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(LayoutConfig layoutConfig, LayoutInfo expectedResult)
|
||||
{
|
||||
this.LayoutConfig = layoutConfig;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public LayoutConfig LayoutConfig { get; set; }
|
||||
|
||||
public LayoutInfo ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// happy path - check the preview form is shown
|
||||
// at the correct size and position on a single screen
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | 0 |
|
||||
// | |
|
||||
// +----------------+
|
||||
var layoutConfig = new LayoutConfig(
|
||||
virtualScreen: new(0, 0, 5120, 1440),
|
||||
screenBounds: new List<Rectangle>
|
||||
{
|
||||
new(0, 0, 5120, 1440),
|
||||
},
|
||||
activatedLocation: new(5120 / 2, 1440 / 2),
|
||||
activatedScreen: 0,
|
||||
maximumFormSize: new(1600, 1200),
|
||||
formPadding: new(5, 5, 5, 5),
|
||||
previewPadding: new(0, 0, 0, 0));
|
||||
var layoutInfo = new LayoutInfo(
|
||||
layoutConfig: layoutConfig,
|
||||
formBounds: new(1760, 491.40625M, 1600, 457.1875M),
|
||||
previewBounds: new(0, 0, 1590, 447.1875M),
|
||||
screenBounds: new List<RectangleInfo>
|
||||
{
|
||||
new(0, 0, 1590, 447.1875M),
|
||||
},
|
||||
activatedScreen: new(0, 0, 5120, 1440));
|
||||
yield return new[] { new TestCase(layoutConfig, layoutInfo) };
|
||||
|
||||
// primary monitor not topmost / leftmost - if there are screens
|
||||
// that are further left or higher 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 negative coordinates gracefully
|
||||
//
|
||||
// +-------+
|
||||
// | 0 +----------------+
|
||||
// +-------+ |
|
||||
// | 1 |
|
||||
// | |
|
||||
// +----------------+
|
||||
layoutConfig = new LayoutConfig(
|
||||
virtualScreen: new(-1920, -472, 7040, 1912),
|
||||
screenBounds: new List<Rectangle>
|
||||
{
|
||||
new(-1920, -472, 1920, 1080),
|
||||
new(0, 0, 5120, 1440),
|
||||
},
|
||||
activatedLocation: new(-960, -236),
|
||||
activatedScreen: 0,
|
||||
maximumFormSize: new(1600, 1200),
|
||||
formPadding: new(5, 5, 5, 5),
|
||||
previewPadding: new(0, 0, 0, 0));
|
||||
layoutInfo = new LayoutInfo(
|
||||
layoutConfig: layoutConfig,
|
||||
formBounds: new(
|
||||
-1760,
|
||||
-456.91477M, // -236 - (((decimal)(1600-10) / 7040 * 1912) + 10) / 2
|
||||
1600,
|
||||
441.829545M // ((decimal)(1600-10) / 7040 * 1912) + 10
|
||||
),
|
||||
previewBounds: new(0, 0, 1590, 431.829545M),
|
||||
screenBounds: new List<RectangleInfo>
|
||||
{
|
||||
new(0, 0, 433.63636M, 243.92045M),
|
||||
new(433.63636M, 106.602270M, 1156.36363M, 325.22727M),
|
||||
},
|
||||
activatedScreen: new(-1920, -472, 1920, 1080));
|
||||
yield return new[] { new TestCase(layoutConfig, layoutInfo) };
|
||||
|
||||
// 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(
|
||||
virtualScreen: new(0, 0, 7168, 1440),
|
||||
screenBounds: new List<Rectangle>
|
||||
{
|
||||
new(6144, 0, 1024, 768),
|
||||
new(0, 0, 6144, 1440),
|
||||
},
|
||||
activatedLocation: new(6656, 384),
|
||||
activatedScreen: 0,
|
||||
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),
|
||||
},
|
||||
activatedScreen: new(6144, 0, 1024, 768));
|
||||
yield return new[] { 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(
|
||||
virtualScreen: new(0, 0, 7424, 1440),
|
||||
screenBounds: new List<Rectangle>
|
||||
{
|
||||
new(6144, 0, 1280, 768),
|
||||
new(0, 0, 6144, 1440),
|
||||
},
|
||||
activatedLocation: new(6784, 384),
|
||||
activatedScreen: 0,
|
||||
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),
|
||||
},
|
||||
activatedScreen: new(6144, 0, 1280, 768));
|
||||
yield return new[] { new TestCase(layoutConfig, layoutInfo) };
|
||||
}
|
||||
|
||||
[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 = DrawingHelper.CalculateLayoutInfo(data.LayoutConfig);
|
||||
var expected = data.ExpectedResult;
|
||||
Assert.AreEqual(expected.FormBounds.X, actual.FormBounds.X, 0.00001M, "FormBounds.X");
|
||||
Assert.AreEqual(expected.FormBounds.Y, actual.FormBounds.Y, 0.00001M, "FormBounds.Y");
|
||||
Assert.AreEqual(expected.FormBounds.Width, actual.FormBounds.Width, 0.00001M, "FormBounds.Width");
|
||||
Assert.AreEqual(expected.FormBounds.Height, actual.FormBounds.Height, 0.00001M, "FormBounds.Height");
|
||||
Assert.AreEqual(expected.FormBounds.ToRectangle(), actual.FormBounds.ToRectangle(), "FormBounds.ToRectangle");
|
||||
Assert.AreEqual(expected.PreviewBounds.X, actual.PreviewBounds.X, 0.00001M, "PreviewBounds.X");
|
||||
Assert.AreEqual(expected.PreviewBounds.Y, actual.PreviewBounds.Y, 0.00001M, "PreviewBounds.Y");
|
||||
Assert.AreEqual(expected.PreviewBounds.Width, actual.PreviewBounds.Width, 0.00001M, "PreviewBounds.Width");
|
||||
Assert.AreEqual(expected.PreviewBounds.Height, actual.PreviewBounds.Height, 0.00001M, "PreviewBounds.Height");
|
||||
Assert.AreEqual(expected.PreviewBounds.ToRectangle(), actual.PreviewBounds.ToRectangle(), "PreviewBounds.ToRectangle");
|
||||
Assert.AreEqual(expected.ScreenBounds.Count, actual.ScreenBounds.Count, "ScreenBounds.Count");
|
||||
for (var i = 0; i < expected.ScreenBounds.Count; i++)
|
||||
{
|
||||
Assert.AreEqual(expected.ScreenBounds[i].X, actual.ScreenBounds[i].X, 0.00001M, $"ScreenBounds[{i}].X");
|
||||
Assert.AreEqual(expected.ScreenBounds[i].Y, actual.ScreenBounds[i].Y, 0.00001M, $"ScreenBounds[{i}].Y");
|
||||
Assert.AreEqual(expected.ScreenBounds[i].Width, actual.ScreenBounds[i].Width, 0.00001M, $"ScreenBounds[{i}].Width");
|
||||
Assert.AreEqual(expected.ScreenBounds[i].Height, actual.ScreenBounds[i].Height, 0.00001M, $"ScreenBounds[{i}].Height");
|
||||
Assert.AreEqual(expected.ScreenBounds[i].ToRectangle(), actual.ScreenBounds[i].ToRectangle(), "ActivatedScreen.ToRectangle");
|
||||
}
|
||||
|
||||
Assert.AreEqual(expected.ActivatedScreen.X, actual.ActivatedScreen.X, "ActivatedScreen.X");
|
||||
Assert.AreEqual(expected.ActivatedScreen.Y, actual.ActivatedScreen.Y, "ActivatedScreen.Y");
|
||||
Assert.AreEqual(expected.ActivatedScreen.Width, actual.ActivatedScreen.Width, "ActivatedScreen.Width");
|
||||
Assert.AreEqual(expected.ActivatedScreen.Height, actual.ActivatedScreen.Height, "ActivatedScreen.Height");
|
||||
Assert.AreEqual(expected.ActivatedScreen.ToRectangle(), actual.ActivatedScreen.ToRectangle(), "ActivatedScreen.ToRectangle");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,514 +0,0 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace MouseJumpUI.Helpers.Tests;
|
||||
|
||||
[TestClass]
|
||||
public static class LayoutHelperTests
|
||||
{
|
||||
[TestClass]
|
||||
public class CenterObjectTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(Size obj, Point midpoint, Point expectedResult)
|
||||
{
|
||||
this.Obj = obj;
|
||||
this.Midpoint = midpoint;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public Size Obj { get; set; }
|
||||
|
||||
public Point Midpoint { get; set; }
|
||||
|
||||
public Point ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// zero-sized object should center exactly on the midpoint
|
||||
yield return new[] { new TestCase(new(0, 0), new(0, 0), new(0, 0)), };
|
||||
|
||||
// odd-sized objects should center above/left of the midpoint
|
||||
yield return new[] { new TestCase(new(1, 1), new(1, 1), new(0, 0)), };
|
||||
yield return new[] { new TestCase(new(1, 1), new(5, 5), new(4, 4)), };
|
||||
|
||||
// even-sized objects should center exactly on the midpoint
|
||||
yield return new[] { new TestCase(new(2, 2), new(1, 1), new(0, 0)), };
|
||||
yield return new[] { new TestCase(new(2, 2), new(5, 5), new(4, 4)), };
|
||||
yield return new[] { new TestCase(new(800, 600), new(1000, 1000), new(600, 700)), };
|
||||
|
||||
// negative result position
|
||||
yield return new[] { new TestCase(new(1000, 1200), new(300, 300), new(-200, -300)), };
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
|
||||
public void RunTestCases(TestCase data)
|
||||
{
|
||||
var actual = LayoutHelper.CenterObject(data.Obj, data.Midpoint);
|
||||
var expected = data.ExpectedResult;
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class CombineRegionsTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(List<Rectangle> bounds, Rectangle expectedResult)
|
||||
{
|
||||
this.Bounds = bounds;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public List<Rectangle> Bounds { get; set; }
|
||||
|
||||
public Rectangle ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// empty list
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
new(),
|
||||
Rectangle.Empty),
|
||||
};
|
||||
|
||||
// empty bounds
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
new()
|
||||
{
|
||||
Rectangle.Empty,
|
||||
},
|
||||
Rectangle.Empty),
|
||||
};
|
||||
|
||||
// single region
|
||||
//
|
||||
// +---+
|
||||
// | 0 |
|
||||
// +---+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
new()
|
||||
{
|
||||
new(100, 100, 100, 100),
|
||||
},
|
||||
new(100, 100, 100, 100)),
|
||||
};
|
||||
|
||||
// multi-monitor desktop
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | 1 +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
new()
|
||||
{
|
||||
new(5120, 0, 1920, 1080),
|
||||
new(0, 0, 5120, 1440),
|
||||
},
|
||||
new(0, 0, 7040, 1440)),
|
||||
};
|
||||
|
||||
// multi-monitor desktop
|
||||
//
|
||||
// note - windows puts the *primary* monitor at the origin (0,0),
|
||||
// so screens positioned *above* or *left* will have negative coordinates
|
||||
//
|
||||
// +-------+
|
||||
// | 0 |
|
||||
// +-------+--------+
|
||||
// | |
|
||||
// | 1 |
|
||||
// | |
|
||||
// +----------------+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
new()
|
||||
{
|
||||
new(0, -1000, 1920, 1080),
|
||||
new(0, 0, 5120, 1440),
|
||||
},
|
||||
new(0, -1000, 5120, 2440)),
|
||||
};
|
||||
|
||||
// multi-monitor desktop
|
||||
//
|
||||
// note - windows puts the *primary* monitor at the origin (0,0),
|
||||
// so screens positioned *above* or *left* will have negative coordinates
|
||||
//
|
||||
// +-------+----------------+
|
||||
// | 0 | |
|
||||
// +-------+ 1 |
|
||||
// | |
|
||||
// +----------------+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
new()
|
||||
{
|
||||
new(-1920, 0, 1920, 1080),
|
||||
new(0, 0, 5120, 1440),
|
||||
},
|
||||
new(-1920, 0, 7040, 1440)),
|
||||
};
|
||||
|
||||
// non-contiguous regions
|
||||
//
|
||||
// +---+
|
||||
// | 0 | +-------+
|
||||
// +---+ | |
|
||||
// | 1 |
|
||||
// | |
|
||||
// +-------+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
new()
|
||||
{
|
||||
new(0, 0, 100, 100),
|
||||
new(200, 150, 200, 200),
|
||||
},
|
||||
new(0, 0, 400, 350)),
|
||||
};
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
|
||||
public void RunTestCases(TestCase data)
|
||||
{
|
||||
var actual = LayoutHelper.CombineRegions(data.Bounds);
|
||||
var expected = data.ExpectedResult;
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class GetMidpointTests
|
||||
{
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class MoveInsideTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(Rectangle obj, Rectangle bounds, Rectangle expectedResult)
|
||||
{
|
||||
this.Obj = obj;
|
||||
this.Bounds = bounds;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public Rectangle Obj { get; set; }
|
||||
|
||||
public Rectangle Bounds { get; set; }
|
||||
|
||||
public Rectangle ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// already inside - obj fills bounds exactly
|
||||
yield return new[]
|
||||
{
|
||||
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[]
|
||||
{
|
||||
new TestCase(new(0, 0, 100, 100), new(0, 0, 200, 200), new(0, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(100, 0, 100, 100), new(0, 0, 200, 200), new(100, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(0, 100, 100, 100), new(0, 0, 200, 200), new(0, 100, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
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[]
|
||||
{
|
||||
new TestCase(new(-50, -50, 100, 100), new(0, 0, 200, 200), new(0, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(250, -50, 100, 100), new(0, 0, 200, 200), new(100, 0, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(-50, 250, 100, 100), new(0, 0, 200, 200), new(0, 100, 100, 100)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
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 = LayoutHelper.MoveInside(data.Obj, data.Bounds);
|
||||
var expected = data.ExpectedResult;
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class ScaleLocationTests
|
||||
{
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class ScaleToFitTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(Size obj, Size bounds, Size expectedResult)
|
||||
{
|
||||
this.Obj = obj;
|
||||
this.Bounds = bounds;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public Size Obj { get; set; }
|
||||
|
||||
public Size Bounds { get; set; }
|
||||
|
||||
public Size ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// identity tests
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(0, 0), new(0, 0), new(0, 0)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(512, 384), new(512, 384), new(512, 384)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(1024, 768), new(1024, 768), new(1024, 768)),
|
||||
};
|
||||
|
||||
// integer scaling factor tests
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(512, 384), new(2048, 1536), new(2048, 1536)),
|
||||
};
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(2048, 1536), new(1024, 768), new(1024, 768)),
|
||||
};
|
||||
|
||||
// scale to fit width
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(512, 384), new(2048, 3072), new(2048, 1536)),
|
||||
};
|
||||
|
||||
// scale to fit height
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(new(512, 384), new(4096, 1536), new(2048, 1536)),
|
||||
};
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
|
||||
public void RunTestCases(TestCase data)
|
||||
{
|
||||
var actual = LayoutHelper.ScaleToFit(data.Obj, data.Bounds);
|
||||
var expected = data.ExpectedResult;
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[TestClass]
|
||||
public class GetPreviewFormBoundsTests
|
||||
{
|
||||
public class TestCase
|
||||
{
|
||||
public TestCase(
|
||||
Rectangle desktopBounds,
|
||||
Point cursorPosition,
|
||||
Rectangle currentMonitorBounds,
|
||||
Size maximumPreviewImageSize,
|
||||
Size previewImagePadding,
|
||||
Rectangle expectedResult)
|
||||
{
|
||||
this.DesktopBounds = desktopBounds;
|
||||
this.CursorPosition = cursorPosition;
|
||||
this.CurrentMonitorBounds = currentMonitorBounds;
|
||||
this.MaximumPreviewImageSize = maximumPreviewImageSize;
|
||||
this.PreviewImagePadding = previewImagePadding;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public Rectangle DesktopBounds { get; set; }
|
||||
|
||||
public Point CursorPosition { get; set; }
|
||||
|
||||
public Rectangle CurrentMonitorBounds { get; set; }
|
||||
|
||||
public Size MaximumPreviewImageSize { get; set; }
|
||||
|
||||
public Size PreviewImagePadding { get; set; }
|
||||
|
||||
public Rectangle ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// multi-monitor desktop
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | 1 +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
//
|
||||
// clicked near top left corner so that the
|
||||
// preview box overhangs the top and left
|
||||
//
|
||||
// +----------------+
|
||||
// | * |
|
||||
// | 1 +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
//
|
||||
// form is centered on mouse cursor and then
|
||||
// nudged back into the top left corner
|
||||
//
|
||||
// +-----+----------+
|
||||
// | * | |
|
||||
// +-----+ 1 +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
desktopBounds: new(-5120, -359, 7040, 1440),
|
||||
cursorPosition: new(-5020, -259),
|
||||
currentMonitorBounds: new(-5120, -359, 5120, 1440),
|
||||
maximumPreviewImageSize: new(1600, 1200),
|
||||
previewImagePadding: new(10, 10),
|
||||
expectedResult: new(-5120, -359, 1610, 337)),
|
||||
};
|
||||
|
||||
// multi-monitor desktop
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | 1 +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
//
|
||||
// clicked in the center of the second monitor
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | * +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
//
|
||||
// form is centered on the mouse cursor
|
||||
//
|
||||
// +----------------+
|
||||
// | +-----+ |
|
||||
// | | * | +-------+
|
||||
// | +-----+ | 0 |
|
||||
// +----------------+-------+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
desktopBounds: new(-5120, -359, 7040, 1440),
|
||||
cursorPosition: new(-2560, 361),
|
||||
currentMonitorBounds: new(-5120, -359, 5120, 1440),
|
||||
maximumPreviewImageSize: new(1600, 1200),
|
||||
previewImagePadding: new(10, 10),
|
||||
expectedResult: new(-3365, 192, 1610, 337)),
|
||||
};
|
||||
|
||||
// multi-monitor desktop
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | 1 +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
//
|
||||
// clicked in the center of the monitor
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | * +-------+
|
||||
// | | 0 |
|
||||
// +----------------+-------+
|
||||
//
|
||||
// max preview is larger than monitor,
|
||||
// form is scaled to monitor size, with
|
||||
// consideration for image padding
|
||||
//
|
||||
// *----------------*
|
||||
// |+--------------+|
|
||||
// || * |+-------+
|
||||
// |+--------------+| 0 |
|
||||
// +----------------+-------+
|
||||
yield return new[]
|
||||
{
|
||||
new TestCase(
|
||||
desktopBounds: new(-5120, -359, 7040, 1440),
|
||||
cursorPosition: new(-2560, 361),
|
||||
currentMonitorBounds: new(-5120, -359, 5120, 1440),
|
||||
maximumPreviewImageSize: new(160000, 120000),
|
||||
previewImagePadding: new(10, 10),
|
||||
expectedResult: new(-5120, -166, 5120, 1055)),
|
||||
};
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)]
|
||||
public void RunTestCases(TestCase data)
|
||||
{
|
||||
var actual = LayoutHelper.GetPreviewFormBounds(
|
||||
desktopBounds: data.DesktopBounds,
|
||||
activatedPosition: data.CursorPosition,
|
||||
activatedMonitorBounds: data.CurrentMonitorBounds,
|
||||
maximumThumbnailImageSize: data.MaximumPreviewImageSize,
|
||||
thumbnailImagePadding: data.PreviewImagePadding);
|
||||
var expected = data.ExpectedResult;
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// 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.Collections.Generic;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MouseJumpUI.Drawing.Models;
|
||||
using MouseJumpUI.Helpers;
|
||||
|
||||
namespace MouseJumpUI.UnitTests.Helpers;
|
||||
|
||||
[TestClass]
|
||||
public static class MouseHelperTests
|
||||
{
|
||||
[TestClass]
|
||||
public class GetJumpLocationTests
|
||||
{
|
||||
public 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; set; }
|
||||
|
||||
public SizeInfo PreviewSize { get; set; }
|
||||
|
||||
public RectangleInfo DesktopBounds { get; set; }
|
||||
|
||||
public PointInfo ExpectedResult { get; set; }
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetTestCases()
|
||||
{
|
||||
// screen corners and midpoint with a zero origin
|
||||
yield return new[] { new TestCase(new(0, 0), new(160, 120), new(0, 0, 1600, 1200), new(0, 0)) };
|
||||
yield return new[] { new TestCase(new(160, 0), new(160, 120), new(0, 0, 1600, 1200), new(1600, 0)) };
|
||||
yield return new[] { new TestCase(new(0, 120), new(160, 120), new(0, 0, 1600, 1200), new(0, 1200)) };
|
||||
yield return new[] { new TestCase(new(160, 120), new(160, 120), new(0, 0, 1600, 1200), new(1600, 1200)) };
|
||||
yield return new[] { 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[] { new TestCase(new(0, 0), new(160, 120), new(1000, 1000, 1600, 1200), new(1000, 1000)) };
|
||||
yield return new[] { new TestCase(new(160, 0), new(160, 120), new(1000, 1000, 1600, 1200), new(2600, 1000)) };
|
||||
yield return new[] { new TestCase(new(0, 120), new(160, 120), new(1000, 1000, 1600, 1200), new(1000, 2200)) };
|
||||
yield return new[] { new TestCase(new(160, 120), new(160, 120), new(1000, 1000, 1600, 1200), new(2600, 2200)) };
|
||||
yield return new[] { 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[] { new TestCase(new(0, 0), new(160, 120), new(-1000, -1000, 1600, 1200), new(-1000, -1000)) };
|
||||
yield return new[] { new TestCase(new(160, 0), new(160, 120), new(-1000, -1000, 1600, 1200), new(600, -1000)) };
|
||||
yield return new[] { new TestCase(new(0, 120), new(160, 120), new(-1000, -1000, 1600, 1200), new(-1000, 200)) };
|
||||
yield return new[] { new TestCase(new(160, 120), new(160, 120), new(-1000, -1000, 1600, 1200), new(600, 200)) };
|
||||
yield return new[] { 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user