[Mouse Jump] - screenshot performance (#24607) (#24630)

* [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:
Michael Clayton
2023-03-17 18:12:27 +00:00
committed by GitHub
parent 5cbe9dd911
commit e6767c8e8b
36 changed files with 2121 additions and 951 deletions

View File

@@ -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);
}
}
}

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 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);
}
}
}

View File

@@ -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");
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}