diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/AbstractIdeIntegrationTest.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/AbstractIdeIntegrationTest.cs
deleted file mode 100644
index 86900ce..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/AbstractIdeIntegrationTest.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests
-{
- using System;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Threading;
- using Microsoft.VisualStudio.Shell.Interop;
- using Microsoft.VisualStudio.Threading;
- using Tvl.VisualStudio.MouseFastScroll.IntegrationTests.Threading;
- using Xunit;
-
- public abstract class AbstractIdeIntegrationTest : IAsyncLifetime, IDisposable
- {
- private JoinableTaskContext _joinableTaskContext;
- private JoinableTaskCollection _joinableTaskCollection;
- private JoinableTaskFactory _joinableTaskFactory;
-
- protected AbstractIdeIntegrationTest()
- {
- Assert.True(Application.Current.Dispatcher.CheckAccess());
-
- if (ServiceProvider.GetService(typeof(SVsTaskSchedulerService)) is IVsTaskSchedulerService2 taskSchedulerService)
- {
- JoinableTaskContext = (JoinableTaskContext)taskSchedulerService.GetAsyncTaskContext();
- }
- else
- {
- JoinableTaskContext = new JoinableTaskContext();
- }
- }
-
- protected static IServiceProvider ServiceProvider => Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider;
-
- protected JoinableTaskContext JoinableTaskContext
- {
- get
- {
- return _joinableTaskContext ?? throw new InvalidOperationException();
- }
-
- private set
- {
- if (value == _joinableTaskContext)
- {
- return;
- }
-
- if (value is null)
- {
- _joinableTaskContext = null;
- _joinableTaskCollection = null;
- _joinableTaskFactory = null;
- }
- else
- {
- _joinableTaskContext = value;
- _joinableTaskCollection = value.CreateCollection();
- _joinableTaskFactory = value.CreateFactory(_joinableTaskCollection).WithPriority(Application.Current.Dispatcher, DispatcherPriority.Background);
- }
- }
- }
-
- protected JoinableTaskFactory JoinableTaskFactory => _joinableTaskFactory ?? throw new InvalidOperationException();
-
- public virtual Task InitializeAsync()
- {
- return Task.CompletedTask;
- }
-
- public virtual async Task DisposeAsync()
- {
- await _joinableTaskCollection.JoinTillEmptyAsync();
- JoinableTaskContext = null;
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Harness/IntegrationHelper.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Harness/IntegrationHelper.cs
deleted file mode 100644
index 063e7df..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Harness/IntegrationHelper.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.Harness
-{
- using System;
- using System.Runtime.InteropServices;
-
- ///
- /// Provides some helper functions used by the other classes in the project.
- ///
- internal static class IntegrationHelper
- {
- public static bool AttachThreadInput(uint idAttach, uint idAttachTo)
- {
- var success = NativeMethods.AttachThreadInput(idAttach, idAttachTo, true);
-
- if (!success)
- {
- var hresult = Marshal.GetHRForLastWin32Error();
- Marshal.ThrowExceptionForHR(hresult);
- }
-
- return success;
- }
-
- public static bool DetachThreadInput(uint idAttach, uint idAttachTo)
- {
- var success = NativeMethods.AttachThreadInput(idAttach, idAttachTo, false);
-
- if (!success)
- {
- var hresult = Marshal.GetHRForLastWin32Error();
- Marshal.ThrowExceptionForHR(hresult);
- }
-
- return success;
- }
-
- public static IntPtr GetForegroundWindow()
- {
- // Attempt to get the foreground window in a loop, as the NativeMethods function can return IntPtr.Zero
- // in certain circumstances, such as when a window is losing activation.
- var foregroundWindow = IntPtr.Zero;
-
- do
- {
- foregroundWindow = NativeMethods.GetForegroundWindow();
- }
- while (foregroundWindow == IntPtr.Zero);
-
- return foregroundWindow;
- }
-
- public static void SetForegroundWindow(IntPtr window)
- {
- var foregroundWindow = GetForegroundWindow();
-
- if (window == foregroundWindow)
- {
- return;
- }
-
- var activeThreadId = NativeMethods.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero);
- var currentThreadId = NativeMethods.GetCurrentThreadId();
-
- var threadInputsAttached = false;
-
- try
- {
- // No need to re-attach threads in case when VS initializaed an UI thread for a debugged application.
- if (activeThreadId != currentThreadId)
- {
- // Attach the thread inputs so that 'SetActiveWindow' and 'SetFocus' work
- threadInputsAttached = AttachThreadInput(currentThreadId, activeThreadId);
- }
-
- // Make the window a top-most window so it will appear above any existing top-most windows
- NativeMethods.SetWindowPos(window, (IntPtr)NativeMethods.HWND_TOPMOST, 0, 0, 0, 0, NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOMOVE);
-
- // Move the window into the foreground as it may not have been achieved by the 'SetWindowPos' call
- var success = NativeMethods.SetForegroundWindow(window);
-
- if (!success)
- {
- throw new InvalidOperationException("Setting the foreground window failed.");
- }
-
- // Ensure the window is 'Active' as it may not have been achieved by 'SetForegroundWindow'
- NativeMethods.SetActiveWindow(window);
-
- // Give the window the keyboard focus as it may not have been achieved by 'SetActiveWindow'
- NativeMethods.SetFocus(window);
-
- // Remove the 'Top-Most' qualification from the window
- NativeMethods.SetWindowPos(window, (IntPtr)NativeMethods.HWND_NOTOPMOST, 0, 0, 0, 0, NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOMOVE);
- }
- finally
- {
- if (threadInputsAttached)
- {
- // Finally, detach the thread inputs from eachother
- DetachThreadInput(currentThreadId, activeThreadId);
- }
- }
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Harness/NativeMethods.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Harness/NativeMethods.cs
index 1581f07..76d477d 100644
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Harness/NativeMethods.cs
+++ b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Harness/NativeMethods.cs
@@ -5,106 +5,14 @@ namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.Harness
{
using System;
using System.Runtime.InteropServices;
- using System.Text;
- using IBindCtx = Microsoft.VisualStudio.OLE.Interop.IBindCtx;
- using IRunningObjectTable = Microsoft.VisualStudio.OLE.Interop.IRunningObjectTable;
internal static class NativeMethods
{
- private const string Kernel32 = "kernel32.dll";
- private const string Ole32 = "ole32.dll";
private const string User32 = "User32.dll";
- public const int RPC_E_CALL_REJECTED = unchecked((int)0x80010001);
- public const int RPC_E_SERVERCALL_RETRYLATER = unchecked((int)0x8001010A);
-
- public const uint GA_PARENT = 1;
- public const uint GA_ROOT = 2;
- public const uint GA_ROOTOWNER = 3;
-
- public const uint GW_HWNDFIRST = 0;
- public const uint GW_HWNDLAST = 1;
- public const uint GW_HWNDNEXT = 2;
- public const uint GW_HWNDPREV = 3;
- public const uint GW_OWNER = 4;
- public const uint GW_CHILD = 5;
- public const uint GW_ENABLEDPOPUP = 6;
-
- public const int HWND_NOTOPMOST = -2;
- public const int HWND_TOPMOST = -1;
- public const int HWND_TOP = 0;
- public const int HWND_BOTTOM = 1;
-
- public const uint INPUT_MOUSE = 0;
- public const uint INPUT_KEYBOARD = 1;
- public const uint INPUT_HARDWARE = 2;
-
- public const uint KEYEVENTF_NONE = 0x0000;
- public const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
- public const uint KEYEVENTF_KEYUP = 0x0002;
- public const uint KEYEVENTF_UNICODE = 0x0004;
- public const uint KEYEVENTF_SCANCODE = 0x0008;
-
- public const uint SWP_NOSIZE = 0x0001;
- public const uint SWP_NOMOVE = 0x0002;
- public const uint SWP_NOZORDER = 0x0004;
- public const uint SWP_NOREDRAW = 0x008;
- public const uint SWP_NOACTIVATE = 0x0010;
- public const uint SWP_DRAWFRAME = 0x0020;
- public const uint SWP_FRAMECHANGED = 0x0020;
- public const uint SWP_SHOWWINDOW = 0x0040;
- public const uint SWP_HIDEWINDOW = 0x0080;
- public const uint SWP_NOCOPYBITS = 0x0100;
- public const uint SWP_NOOWNERZORDER = 0x0200;
- public const uint SWP_NOREPOSITION = 0x0200;
- public const uint SWP_NOSENDCHANGING = 0x0400;
- public const uint SWP_DEFERERASE = 0x2000;
- public const uint SWP_ASYNCWINDOWPOS = 0x4000;
-
- public const uint WM_GETTEXT = 0x000D;
- public const uint WM_GETTEXTLENGTH = 0x000E;
-
- public const uint MAPVK_VK_TO_VSC = 0;
- public const uint MAPVK_VSC_TO_VK = 1;
- public const uint MAPVK_VK_TO_CHAR = 2;
- public const uint MAPVK_VSC_TO_KV_EX = 3;
-
public const int SM_CXSCREEN = 0;
public const int SM_CYSCREEN = 1;
- public static readonly int SizeOf_INPUT = Marshal.SizeOf();
-
- [UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = false)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public delegate bool WNDENUMPROC(IntPtr hWnd, IntPtr lParam);
-
- [DllImport(Kernel32)]
- public static extern uint GetCurrentThreadId();
-
- [DllImport(User32, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, [MarshalAs(UnmanagedType.Bool)] bool fAttach);
-
- [DllImport(User32)]
- public static extern IntPtr GetForegroundWindow();
-
- [DllImport(User32)]
- public static extern uint GetWindowThreadProcessId(IntPtr hWnd, [Optional] IntPtr lpdwProcessId);
-
- [DllImport(User32, SetLastError = true)]
- public static extern IntPtr SetActiveWindow(IntPtr hWnd);
-
- [DllImport(User32, SetLastError = true)]
- public static extern IntPtr SetFocus(IntPtr hWnd);
-
- [DllImport(User32, SetLastError = false)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool SetForegroundWindow(IntPtr hWnd);
-
- [DllImport(User32, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- public static extern bool SetWindowPos(IntPtr hWnd, [Optional] IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
-
[DllImport(User32, CharSet = CharSet.Unicode)]
public static extern int GetSystemMetrics(int nIndex);
@@ -127,50 +35,5 @@ public struct POINT
public IntPtr x;
public IntPtr y;
}
-
- [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 8)]
- public struct INPUT
- {
- [FieldOffset(0)]
- public uint Type;
-
- [FieldOffset(4)]
- public MOUSEINPUT mi;
-
- [FieldOffset(4)]
- public KEYBDINPUT ki;
-
- [FieldOffset(4)]
- public HARDWAREINPUT hi;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
- public struct HARDWAREINPUT
- {
- public uint uMsg;
- public ushort wParamL;
- public ushort wParamH;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
- public struct KEYBDINPUT
- {
- public ushort wVk;
- public ushort wScan;
- public uint dwFlags;
- public uint time;
- public IntPtr dwExtraInfo;
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
- public struct MOUSEINPUT
- {
- public int dx;
- public int dy;
- public uint mouseData;
- public uint dwFlags;
- public uint time;
- public IntPtr dwExtraInfo;
- }
}
}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/IdeFactTest.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/IdeFactTest.cs
deleted file mode 100644
index 8b0b70c..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/IdeFactTest.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests
-{
- using System.Diagnostics;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- using Microsoft.VisualStudio.Shell.Interop;
- using Microsoft.VisualStudio.Threading;
- using Xunit;
- using _DTE = EnvDTE._DTE;
- using DTE = EnvDTE.DTE;
- using ServiceProvider = Microsoft.VisualStudio.Shell.ServiceProvider;
-
- public class IdeFactTest : AbstractIdeIntegrationTest
- {
- [IdeFact]
- public void TestOpenAndCloseIDE()
- {
- Assert.Equal("devenv", Process.GetCurrentProcess().ProcessName);
- var dte = (DTE)ServiceProvider.GetService(typeof(_DTE));
- Assert.NotNull(dte);
- }
-
- [IdeFact]
- public void TestRunsOnUIThread()
- {
- Assert.True(Application.Current.Dispatcher.CheckAccess());
- }
-
- [IdeFact]
- public async Task TestRunsOnUIThreadAsync()
- {
- Assert.True(Application.Current.Dispatcher.CheckAccess());
- await Task.Yield();
- Assert.True(Application.Current.Dispatcher.CheckAccess());
- }
-
- [IdeFact]
- public async Task TestYieldsToWorkAsync()
- {
- Assert.True(Application.Current.Dispatcher.CheckAccess());
-
- var task = Application.Current.Dispatcher.InvokeAsync(() => { }).Task;
- Assert.False(task.IsCompleted);
- await task;
-
- Assert.True(Application.Current.Dispatcher.CheckAccess());
- }
-
- [IdeFact]
- public async Task TestJoinableTaskFactoryAsync()
- {
- Assert.NotNull(JoinableTaskContext);
- Assert.NotNull(JoinableTaskFactory);
- Assert.Equal(Thread.CurrentThread, JoinableTaskContext.MainThread);
-
- await TaskScheduler.Default;
-
- Assert.NotEqual(Thread.CurrentThread, JoinableTaskContext.MainThread);
-
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- Assert.Equal(Thread.CurrentThread, JoinableTaskContext.MainThread);
- }
-
- [IdeFact(MinVersion = VisualStudioVersion.VS2012, MaxVersion = VisualStudioVersion.VS2012)]
- public void TestJoinableTaskFactoryProvidedByTest()
- {
- var taskSchedulerServiceObject = ServiceProvider.GetService(typeof(SVsTaskSchedulerService));
- Assert.NotNull(taskSchedulerServiceObject);
-
- var taskSchedulerService = taskSchedulerServiceObject as IVsTaskSchedulerService;
- Assert.NotNull(taskSchedulerService);
-
- var taskSchedulerService2 = taskSchedulerServiceObject as IVsTaskSchedulerService2;
- Assert.Null(taskSchedulerService2);
-
- Assert.NotNull(JoinableTaskContext);
- }
-
- [IdeFact(MinVersion = VisualStudioVersion.VS2013)]
- public void TestJoinableTaskFactoryObtainedFromEnvironment()
- {
- var taskSchedulerServiceObject = ServiceProvider.GetService(typeof(SVsTaskSchedulerService));
- Assert.NotNull(taskSchedulerServiceObject);
-
- var taskSchedulerService = taskSchedulerServiceObject as IVsTaskSchedulerService2;
- Assert.NotNull(taskSchedulerService);
-
- Assert.Same(JoinableTaskContext, taskSchedulerService.GetAsyncTaskContext());
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/EditorInProcess.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/EditorInProcess.cs
new file mode 100644
index 0000000..3794882
--- /dev/null
+++ b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/EditorInProcess.cs
@@ -0,0 +1,120 @@
+// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
+// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
+
+namespace Microsoft.VisualStudio.Extensibility.Testing
+{
+ using System.Threading;
+ using System.Threading.Tasks;
+ using System.Windows;
+ using Microsoft.VisualStudio.Shell.Interop;
+ using Microsoft.VisualStudio.Text;
+ using Microsoft.VisualStudio.Text.Formatting;
+ using Tvl.VisualStudio.MouseFastScroll.IntegrationTests.InProcess;
+
+ internal partial class EditorInProcess
+ {
+ public async Task GetTextAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ return view.TextSnapshot.GetText();
+ }
+
+ public async Task SetTextAsync(string text, CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ var textSnapshot = view.TextSnapshot;
+ var replacementSpan = new SnapshotSpan(textSnapshot, 0, textSnapshot.Length);
+ view.TextBuffer.Replace(replacementSpan, text);
+ }
+
+ public async Task ActivateAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var dte = await GetRequiredGlobalServiceAsync(cancellationToken);
+ dte.ActiveDocument.Activate();
+ }
+
+ public async Task GetCaretPositionAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+
+ var subjectBuffer = view.GetBufferContainingCaret();
+ Assumes.Present(subjectBuffer);
+
+ var bufferPosition = view.Caret.Position.BufferPosition;
+ return bufferPosition.Position;
+ }
+
+ public async Task MoveCaretAsync(int position, CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ var subjectBuffer = view.GetBufferContainingCaret();
+ var point = new SnapshotPoint(subjectBuffer.CurrentSnapshot, position);
+
+ view.Caret.MoveTo(point);
+ }
+
+ public async Task IsCaretOnScreenAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ var caret = view.Caret;
+
+ return caret.Left >= view.ViewportLeft
+ && caret.Right <= view.ViewportRight
+ && caret.Top >= view.ViewportTop
+ && caret.Bottom <= view.ViewportBottom;
+ }
+
+ public async Task GetFirstVisibleLineAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ return view.TextViewLines.FirstVisibleLine.Start.GetContainingLine().LineNumber;
+ }
+
+ public async Task GetLastVisibleLineAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ return view.TextViewLines.LastVisibleLine.Start.GetContainingLine().LineNumber;
+ }
+
+ public async Task GetLastVisibleLineStateAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ return view.TextViewLines.LastVisibleLine.VisibilityState;
+ }
+
+ public async Task GetCenterOfEditorOnScreenAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ var center = new Point(view.VisualElement.ActualWidth / 2, view.VisualElement.ActualHeight / 2);
+ return view.VisualElement.PointToScreen(center);
+ }
+
+ public async Task GetZoomLevelAsync(CancellationToken cancellationToken)
+ {
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ var view = await GetActiveTextViewAsync(cancellationToken);
+ return view.ZoomLevel;
+ }
+ }
+}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/Editor_InProc2.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/Editor_InProc2.cs
deleted file mode 100644
index 68326ba..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/Editor_InProc2.cs
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.InProcess
-{
- using System;
- using System.Runtime.InteropServices;
- using System.Threading.Tasks;
- using System.Windows;
- using Microsoft.VisualStudio.Text;
- using Microsoft.VisualStudio.Text.Editor;
- using Microsoft.VisualStudio.Text.Formatting;
- using Microsoft.VisualStudio.TextManager.Interop;
- using Microsoft.VisualStudio.Threading;
-
- internal class Editor_InProc2 : TextViewWindow_InProc2
- {
- private static readonly Guid IWpfTextViewId = new Guid("8C40265E-9FDB-4F54-A0FD-EBB72B7D0476");
-
- public Editor_InProc2(JoinableTaskFactory joinableTaskFactory)
- : base(joinableTaskFactory)
- {
- }
-
- protected override async Task GetActiveTextViewAsync()
- {
- return (await GetActiveTextViewHostAsync()).TextView;
- }
-
- private async Task GetActiveVsTextViewAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var vsTextManager = await GetGlobalServiceAsync();
-
- var hresult = vsTextManager.GetActiveView(fMustHaveFocus: 1, pBuffer: null, ppView: out var vsTextView);
- Marshal.ThrowExceptionForHR(hresult);
-
- return vsTextView;
- }
-
- private async Task GetActiveTextViewHostAsync()
- {
- // The active text view might not have finished composing yet, waiting for the application to 'idle'
- // means that it is done pumping messages (including WM_PAINT) and the window should return the correct text view
- await WaitForApplicationIdleAsync();
-
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var activeVsTextView = (IVsUserData)await GetActiveVsTextViewAsync();
-
- var hresult = activeVsTextView.GetData(IWpfTextViewId, out var wpfTextViewHost);
- Marshal.ThrowExceptionForHR(hresult);
-
- return (IWpfTextViewHost)wpfTextViewHost;
- }
-
- public async Task ActivateAsync()
- {
- (await GetDTEAsync()).ActiveDocument.Activate();
- }
-
- public async Task GetTextAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- return view.TextSnapshot.GetText();
- }
-
- public async Task SetTextAsync(string text)
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- var textSnapshot = view.TextSnapshot;
- var replacementSpan = new SnapshotSpan(textSnapshot, 0, textSnapshot.Length);
- view.TextBuffer.Replace(replacementSpan, text);
- }
-
- public async Task MoveCaretAsync(int position)
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- var subjectBuffer = view.GetBufferContainingCaret();
- var point = new SnapshotPoint(subjectBuffer.CurrentSnapshot, position);
-
- view.Caret.MoveTo(point);
- }
-
- public async Task IsCaretOnScreenAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- var caret = view.Caret;
-
- return caret.Left >= view.ViewportLeft
- && caret.Right <= view.ViewportRight
- && caret.Top >= view.ViewportTop
- && caret.Bottom <= view.ViewportBottom;
- }
-
- protected override Task GetBufferContainingCaretAsync(IWpfTextView view)
- {
- return Task.FromResult(view.GetBufferContainingCaret());
- }
-
- public async Task GetFirstVisibleLineAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- return view.TextViewLines.FirstVisibleLine.Start.GetContainingLine().LineNumber;
- }
-
- public async Task GetLastVisibleLineAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- return view.TextViewLines.LastVisibleLine.Start.GetContainingLine().LineNumber;
- }
-
- public async Task GetLastVisibleLineStateAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- return view.TextViewLines.LastVisibleLine.VisibilityState;
- }
-
- public async Task GetCenterOfEditorOnScreenAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- var center = new Point(view.VisualElement.ActualWidth / 2, view.VisualElement.ActualHeight / 2);
- return view.VisualElement.PointToScreen(center);
- }
-
- public async Task GetZoomLevelAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- return view.ZoomLevel;
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/IdeSendKeys.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/IdeSendKeys.cs
index 87cff0c..002adeb 100644
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/IdeSendKeys.cs
+++ b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/IdeSendKeys.cs
@@ -4,189 +4,80 @@
namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.Harness
{
using System;
- using System.Runtime.InteropServices;
+ using System.Threading;
using System.Threading.Tasks;
- using Microsoft.VisualStudio.Threading;
- using Tvl.VisualStudio.MouseFastScroll.IntegrationTests.InProcess;
+ using Microsoft.VisualStudio.Extensibility.Testing;
using WindowsInput;
using WindowsInput.Native;
- public class IdeSendKeys
+ [TestService]
+ internal partial class IdeSendKeys : InProcComponent
{
- private readonly VisualStudio_InProc2 _visualStudio;
-
- public IdeSendKeys(JoinableTaskFactory joinableTaskFactory)
- {
- _visualStudio = new VisualStudio_InProc2(joinableTaskFactory);
- }
-
internal async Task SendAsync(params object[] keys)
{
- await SendAsync(inputSimulator =>
- {
- foreach (var key in keys)
+ await SendAsync(
+ inputSimulator =>
{
- switch (key)
+ foreach (var key in keys)
{
- case string str:
- var text = str.Replace("\r\n", "\r").Replace("\n", "\r");
- int index = 0;
- while (index < text.Length)
+ switch (key)
{
- if (text[index] == '\r')
- {
- inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
- index++;
- }
- else
+ case string str:
+ var text = str.Replace("\r\n", "\r").Replace("\n", "\r");
+ int index = 0;
+ while (index < text.Length)
{
- int nextIndex = text.IndexOf('\r', index);
- if (nextIndex == -1)
+ if (text[index] == '\r')
{
- nextIndex = text.Length;
+ inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN);
+ index++;
+ }
+ else
+ {
+ int nextIndex = text.IndexOf('\r', index);
+ if (nextIndex == -1)
+ {
+ nextIndex = text.Length;
+ }
+
+ inputSimulator.Keyboard.TextEntry(text.Substring(index, nextIndex - index));
+ index = nextIndex;
}
-
- inputSimulator.Keyboard.TextEntry(text.Substring(index, nextIndex - index));
- index = nextIndex;
}
- }
- break;
+ break;
- case char c:
- inputSimulator.Keyboard.TextEntry(c);
- break;
+ case char c:
+ inputSimulator.Keyboard.TextEntry(c);
+ break;
- case VirtualKeyCode virtualKeyCode:
- inputSimulator.Keyboard.KeyPress(virtualKeyCode);
- break;
+ case VirtualKeyCode virtualKeyCode:
+ inputSimulator.Keyboard.KeyPress(virtualKeyCode);
+ break;
- case null:
- throw new ArgumentNullException(nameof(keys));
+ case null:
+ throw new ArgumentNullException(nameof(keys));
- default:
- throw new ArgumentException($"Unexpected type encountered: {key.GetType()}", nameof(keys));
+ default:
+ throw new ArgumentException($"Unexpected type encountered: {key.GetType()}", nameof(keys));
+ }
}
- }
- });
+ },
+ CancellationToken.None);
}
- internal async Task SendAsync(Action actions)
+ internal async Task SendAsync(Action actions, CancellationToken cancellationToken)
{
if (actions == null)
{
throw new ArgumentNullException(nameof(actions));
}
- var foregroundWindow = IntPtr.Zero;
-
- try
- {
- var foreground = GetForegroundWindow();
- await _visualStudio.ActivateMainWindowAsync();
-
- await Task.Run(() => actions(new InputSimulator()));
- }
- finally
- {
- if (foregroundWindow != IntPtr.Zero)
- {
- SetForegroundWindow(foregroundWindow);
- }
- }
-
- await InProcComponent2.WaitForApplicationIdleAsync();
- }
-
- private static bool AttachThreadInput(uint idAttach, uint idAttachTo)
- {
- var success = NativeMethods.AttachThreadInput(idAttach, idAttachTo, true);
- if (!success)
- {
- var hresult = Marshal.GetHRForLastWin32Error();
- Marshal.ThrowExceptionForHR(hresult);
- }
-
- return success;
- }
-
- private static bool DetachThreadInput(uint idAttach, uint idAttachTo)
- {
- var success = NativeMethods.AttachThreadInput(idAttach, idAttachTo, false);
- if (!success)
- {
- var hresult = Marshal.GetHRForLastWin32Error();
- Marshal.ThrowExceptionForHR(hresult);
- }
-
- return success;
- }
-
- private static IntPtr GetForegroundWindow()
- {
- // Attempt to get the foreground window in a loop, as the NativeMethods function can return IntPtr.Zero
- // in certain circumstances, such as when a window is losing activation.
- var foregroundWindow = IntPtr.Zero;
+ await TestServices.Editor.ActivateAsync(cancellationToken);
- do
- {
- foregroundWindow = NativeMethods.GetForegroundWindow();
- }
- while (foregroundWindow == IntPtr.Zero);
-
- return foregroundWindow;
- }
-
- private static void SetForegroundWindow(IntPtr window, bool skipAttachingThread = false)
- {
- var foregroundWindow = GetForegroundWindow();
-
- if (window == foregroundWindow)
- {
- return;
- }
+ await Task.Run(() => actions(new InputSimulator()));
- var activeThreadId = NativeMethods.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero);
- var currentThreadId = NativeMethods.GetCurrentThreadId();
-
- var threadInputsAttached = false;
-
- try
- {
- // No need to re-attach threads in case when VS initializaed an UI thread for a debugged application.
- if (!skipAttachingThread)
- {
- // Attach the thread inputs so that 'SetActiveWindow' and 'SetFocus' work
- threadInputsAttached = AttachThreadInput(currentThreadId, activeThreadId);
- }
-
- // Make the window a top-most window so it will appear above any existing top-most windows
- NativeMethods.SetWindowPos(window, (IntPtr)NativeMethods.HWND_TOPMOST, 0, 0, 0, 0, NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOMOVE);
-
- // Move the window into the foreground as it may not have been achieved by the 'SetWindowPos' call
- var success = NativeMethods.SetForegroundWindow(window);
- if (!success)
- {
- throw new InvalidOperationException("Setting the foreground window failed.");
- }
-
- // Ensure the window is 'Active' as it may not have been achieved by 'SetForegroundWindow'
- NativeMethods.SetActiveWindow(window);
-
- // Give the window the keyboard focus as it may not have been achieved by 'SetActiveWindow'
- NativeMethods.SetFocus(window);
-
- // Remove the 'Top-Most' qualification from the window
- NativeMethods.SetWindowPos(window, (IntPtr)NativeMethods.HWND_NOTOPMOST, 0, 0, 0, 0, NativeMethods.SWP_NOSIZE | NativeMethods.SWP_NOMOVE);
- }
- finally
- {
- if (threadInputsAttached)
- {
- // Finally, detach the thread inputs from eachother
- DetachThreadInput(currentThreadId, activeThreadId);
- }
- }
+ await WaitForApplicationIdleAsync(cancellationToken);
}
}
}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/InProcComponent2.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/InProcComponent2.cs
deleted file mode 100644
index 0623e65..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/InProcComponent2.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.InProcess
-{
- using System;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Threading;
- using Microsoft.VisualStudio.Threading;
- using static Microsoft.VisualStudio.Shell.VsTaskLibraryHelper;
- using DTE = EnvDTE.DTE;
- using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.IAsyncServiceProvider;
- using SAsyncServiceProvider = Microsoft.VisualStudio.Shell.Interop.SAsyncServiceProvider;
- using SDTE = Microsoft.VisualStudio.Shell.Interop.SDTE;
- using ServiceProvider = Microsoft.VisualStudio.Shell.ServiceProvider;
-
- internal abstract class InProcComponent2
- {
- protected InProcComponent2(JoinableTaskFactory joinableTaskFactory)
- {
- JoinableTaskFactory = joinableTaskFactory ?? throw new ArgumentNullException(nameof(joinableTaskFactory));
- }
-
- protected JoinableTaskFactory JoinableTaskFactory
- {
- get;
- }
-
- protected async Task GetGlobalServiceAsync()
- where TService : class
- where TInterface : class
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- if (ServiceProvider.GlobalProvider.GetService(typeof(SAsyncServiceProvider)) is IAsyncServiceProvider asyncServiceProvider)
- {
- return (TInterface)await asyncServiceProvider.QueryServiceAsync(typeof(TService).GUID);
- }
- else
- {
- return (TInterface)ServiceProvider.GlobalProvider.GetService(typeof(TService));
- }
- }
-
- protected async Task GetDTEAsync()
- {
- return await GetGlobalServiceAsync();
- }
-
- ///
- /// Waiting for the application to 'idle' means that it is done pumping messages (including WM_PAINT).
- ///
- protected internal static async Task WaitForApplicationIdleAsync()
- {
- await Application.Current.Dispatcher.InvokeAsync(() => { }, DispatcherPriority.ApplicationIdle);
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/TextViewWindow_InProc2.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/TextViewWindow_InProc2.cs
deleted file mode 100644
index 2c9f6c4..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/TextViewWindow_InProc2.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.InProcess
-{
- using System.Threading.Tasks;
- using Microsoft.VisualStudio.Text;
- using Microsoft.VisualStudio.Text.Editor;
- using Microsoft.VisualStudio.Threading;
-
- internal abstract class TextViewWindow_InProc2 : InProcComponent2
- {
- protected TextViewWindow_InProc2(JoinableTaskFactory joinableTaskFactory)
- : base(joinableTaskFactory)
- {
- }
-
- protected abstract Task GetActiveTextViewAsync();
-
- protected abstract Task GetBufferContainingCaretAsync(IWpfTextView view);
-
- public async Task GetCaretPositionAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var view = await GetActiveTextViewAsync();
- var subjectBuffer = await GetBufferContainingCaretAsync(view);
- var bufferPosition = view.Caret.Position.BufferPosition;
- return bufferPosition.Position;
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/VisualStudio_InProc2.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/VisualStudio_InProc2.cs
deleted file mode 100644
index 703042e..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/InProcess/VisualStudio_InProc2.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.InProcess
-{
- using System;
- using System.Diagnostics;
- using System.Threading.Tasks;
- using Microsoft.VisualStudio.Threading;
- using Tvl.VisualStudio.MouseFastScroll.IntegrationTests.Harness;
-
- internal partial class VisualStudio_InProc2 : InProcComponent2
- {
- public VisualStudio_InProc2(JoinableTaskFactory joinableTaskFactory)
- : base(joinableTaskFactory)
- {
- }
-
- public async Task ActivateMainWindowAsync()
- {
- await JoinableTaskFactory.SwitchToMainThreadAsync();
-
- var dte = await GetDTEAsync();
-
- var activeVisualStudioWindow = (IntPtr)dte.ActiveWindow.HWnd;
- Debug.WriteLine($"DTE.ActiveWindow.HWnd = {activeVisualStudioWindow}");
-
- if (activeVisualStudioWindow == IntPtr.Zero)
- {
- activeVisualStudioWindow = (IntPtr)dte.MainWindow.HWnd;
- Debug.WriteLine($"DTE.MainWindow.HWnd = {activeVisualStudioWindow}");
- }
-
- IntegrationHelper.SetForegroundWindow(activeVisualStudioWindow);
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Properties/AssemblyInfo.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Properties/AssemblyInfo.cs
index 5c5cfac..2194433 100644
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Properties/AssemblyInfo.cs
+++ b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Properties/AssemblyInfo.cs
@@ -3,6 +3,7 @@
using System;
using System.Runtime.InteropServices;
+using Xunit;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
@@ -13,3 +14,5 @@
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
+
+[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)]
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/ScrollingIntegrationTest.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/ScrollingIntegrationTest.cs
index 1ca9136..e7aa7ce 100644
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/ScrollingIntegrationTest.cs
+++ b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/ScrollingIntegrationTest.cs
@@ -8,13 +8,13 @@ namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
+ using Microsoft.VisualStudio.Extensibility.Testing;
+ using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text.Formatting;
using Tvl.VisualStudio.MouseFastScroll.IntegrationTests.Harness;
- using Tvl.VisualStudio.MouseFastScroll.IntegrationTests.InProcess;
using WindowsInput.Native;
using Xunit;
using Xunit.Abstractions;
- using _DTE = EnvDTE._DTE;
using DTE = EnvDTE.DTE;
using vsSaveChanges = EnvDTE.vsSaveChanges;
@@ -23,8 +23,6 @@ public class ScrollingIntegrationTest : AbstractIdeIntegrationTest
public ScrollingIntegrationTest(ITestOutputHelper testOutputHelper)
{
TestOutputHelper = testOutputHelper;
- Editor = new Editor_InProc2(JoinableTaskFactory);
- SendKeys = new IdeSendKeys(JoinableTaskFactory);
}
protected ITestOutputHelper TestOutputHelper
@@ -32,95 +30,91 @@ protected ITestOutputHelper TestOutputHelper
get;
}
- private Editor_InProc2 Editor
- {
- get;
- }
-
- private IdeSendKeys SendKeys
- {
- get;
- }
-
[IdeFact]
public async Task BasicScrollingBehaviorAsync()
{
- var dte = (DTE)ServiceProvider.GetService(typeof(_DTE));
+ var dte = await TestServices.Shell.GetRequiredGlobalServiceAsync(HangMitigatingCancellationToken);
var window = dte.ItemOperations.NewFile(Name: Guid.NewGuid() + ".txt");
string initialText = string.Join(string.Empty, Enumerable.Range(0, 400).Select(i => Guid.NewGuid() + Environment.NewLine));
- await Editor.SetTextAsync(initialText);
+ await TestServices.Editor.SetTextAsync(initialText, HangMitigatingCancellationToken);
string additionalTypedText = Guid.NewGuid().ToString() + "\n" + Guid.NewGuid().ToString();
- await Editor.ActivateAsync();
- await SendKeys.SendAsync(additionalTypedText);
+ await TestServices.Editor.ActivateAsync(HangMitigatingCancellationToken);
+ await TestServices.IdeSendKeys.SendAsync(additionalTypedText);
string expected = initialText + additionalTypedText.Replace("\n", Environment.NewLine);
- Assert.Equal(expected, await Editor.GetTextAsync());
+ Assert.Equal(expected, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken));
- Assert.Equal(expected.Length, await Editor.GetCaretPositionAsync());
+ Assert.Equal(expected.Length, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
// Move the caret and verify the final position. Note that the MoveCaret operation does not scroll the view.
- int firstVisibleLine = await Editor.GetFirstVisibleLineAsync();
+ int firstVisibleLine = await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken);
Assert.True(firstVisibleLine > 0, "Expected the view to start after the first line at this point.");
- await Editor.MoveCaretAsync(0);
- Assert.Equal(0, await Editor.GetCaretPositionAsync());
- Assert.Equal(firstVisibleLine, await Editor.GetFirstVisibleLineAsync());
-
- await SendKeys.SendAsync(inputSimulator =>
- {
- inputSimulator.Keyboard
- .KeyDown(VirtualKeyCode.CONTROL)
- .KeyPress(VirtualKeyCode.HOME)
- .KeyUp(VirtualKeyCode.CONTROL);
- });
-
- Assert.True(await Editor.IsCaretOnScreenAsync());
- firstVisibleLine = await Editor.GetFirstVisibleLineAsync();
+ await TestServices.Editor.MoveCaretAsync(0, HangMitigatingCancellationToken);
+ Assert.Equal(0, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
+ Assert.Equal(firstVisibleLine, await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken));
+
+ await TestServices.IdeSendKeys.SendAsync(
+ inputSimulator =>
+ {
+ inputSimulator.Keyboard
+ .KeyDown(VirtualKeyCode.CONTROL)
+ .KeyPress(VirtualKeyCode.HOME)
+ .KeyUp(VirtualKeyCode.CONTROL);
+ },
+ HangMitigatingCancellationToken);
+
+ Assert.True(await TestServices.Editor.IsCaretOnScreenAsync(HangMitigatingCancellationToken));
+ firstVisibleLine = await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken);
Assert.Equal(0, firstVisibleLine);
- int lastVisibleLine = await Editor.GetLastVisibleLineAsync();
- var lastVisibleLineState = await Editor.GetLastVisibleLineStateAsync();
+ int lastVisibleLine = await TestServices.Editor.GetLastVisibleLineAsync(HangMitigatingCancellationToken);
+ var lastVisibleLineState = await TestServices.Editor.GetLastVisibleLineStateAsync(HangMitigatingCancellationToken);
Assert.True(firstVisibleLine < lastVisibleLine);
- Point point = await Editor.GetCenterOfEditorOnScreenAsync();
+ Point point = await TestServices.Editor.GetCenterOfEditorOnScreenAsync(HangMitigatingCancellationToken);
await MoveMouseAsync(point);
- await SendKeys.SendAsync(inputSimulator => inputSimulator.Mouse.VerticalScroll(-1));
+ await TestServices.IdeSendKeys.SendAsync(inputSimulator => inputSimulator.Mouse.VerticalScroll(-1), HangMitigatingCancellationToken);
- Assert.Equal(0, await Editor.GetCaretPositionAsync());
- Assert.Equal(3, await Editor.GetFirstVisibleLineAsync());
+ Assert.Equal(0, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
+ Assert.Equal(3, await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken));
await MoveMouseAsync(point);
- await SendKeys.SendAsync(inputSimulator => inputSimulator.Mouse.VerticalScroll(1));
+ await TestServices.IdeSendKeys.SendAsync(inputSimulator => inputSimulator.Mouse.VerticalScroll(1), HangMitigatingCancellationToken);
- Assert.Equal(0, await Editor.GetCaretPositionAsync());
- Assert.Equal(0, await Editor.GetFirstVisibleLineAsync());
+ Assert.Equal(0, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
+ Assert.Equal(0, await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken));
await MoveMouseAsync(point);
- await SendKeys.SendAsync(inputSimulator =>
- {
- inputSimulator
- .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
- .Mouse.VerticalScroll(-1)
- .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
- });
+ await TestServices.IdeSendKeys.SendAsync(
+ inputSimulator =>
+ {
+ inputSimulator
+ .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
+ .Mouse.VerticalScroll(-1)
+ .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
+ },
+ HangMitigatingCancellationToken);
int expectedLastVisibleLine = lastVisibleLine + (lastVisibleLineState == VisibilityState.FullyVisible ? 1 : 0);
- Assert.Equal(0, await Editor.GetCaretPositionAsync());
- Assert.Equal(expectedLastVisibleLine, await Editor.GetFirstVisibleLineAsync());
+ Assert.Equal(0, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
+ Assert.Equal(expectedLastVisibleLine, await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken));
await MoveMouseAsync(point);
- await SendKeys.SendAsync(inputSimulator =>
- {
- inputSimulator
- .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
- .Mouse.VerticalScroll(1)
- .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
- });
-
- Assert.Equal(0, await Editor.GetCaretPositionAsync());
- Assert.Equal(0, await Editor.GetFirstVisibleLineAsync());
+ await TestServices.IdeSendKeys.SendAsync(
+ inputSimulator =>
+ {
+ inputSimulator
+ .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
+ .Mouse.VerticalScroll(1)
+ .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
+ },
+ HangMitigatingCancellationToken);
+
+ Assert.Equal(0, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
+ Assert.Equal(0, await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken));
window.Close(vsSaveChanges.vsSaveChangesNo);
}
@@ -131,65 +125,71 @@ await SendKeys.SendAsync(inputSimulator =>
[IdeFact]
public async Task ZoomDisabledAsync()
{
- var dte = (DTE)ServiceProvider.GetService(typeof(_DTE));
+ var dte = await TestServices.Shell.GetRequiredGlobalServiceAsync(HangMitigatingCancellationToken);
var window = dte.ItemOperations.NewFile(Name: Guid.NewGuid() + ".txt");
string initialText = string.Join(string.Empty, Enumerable.Range(0, 400).Select(i => Guid.NewGuid() + Environment.NewLine));
- await Editor.SetTextAsync(initialText);
+ await TestServices.Editor.SetTextAsync(initialText, HangMitigatingCancellationToken);
string additionalTypedText = Guid.NewGuid().ToString() + "\n" + Guid.NewGuid().ToString();
- await SendKeys.SendAsync(additionalTypedText);
+ await TestServices.IdeSendKeys.SendAsync(additionalTypedText);
string expected = initialText + additionalTypedText.Replace("\n", Environment.NewLine);
- Assert.Equal(expected, await Editor.GetTextAsync());
+ Assert.Equal(expected, await TestServices.Editor.GetTextAsync(HangMitigatingCancellationToken));
- Assert.Equal(expected.Length, await Editor.GetCaretPositionAsync());
+ Assert.Equal(expected.Length, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
- await SendKeys.SendAsync(inputSimulator =>
- {
- inputSimulator.Keyboard
- .KeyDown(VirtualKeyCode.CONTROL)
- .KeyPress(VirtualKeyCode.HOME)
- .KeyUp(VirtualKeyCode.CONTROL);
- });
+ await TestServices.IdeSendKeys.SendAsync(
+ inputSimulator =>
+ {
+ inputSimulator.Keyboard
+ .KeyDown(VirtualKeyCode.CONTROL)
+ .KeyPress(VirtualKeyCode.HOME)
+ .KeyUp(VirtualKeyCode.CONTROL);
+ },
+ HangMitigatingCancellationToken);
- int firstVisibleLine = await Editor.GetFirstVisibleLineAsync();
+ int firstVisibleLine = await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken);
Assert.Equal(0, firstVisibleLine);
- int lastVisibleLine = await Editor.GetLastVisibleLineAsync();
- var lastVisibleLineState = await Editor.GetLastVisibleLineStateAsync();
+ int lastVisibleLine = await TestServices.Editor.GetLastVisibleLineAsync(HangMitigatingCancellationToken);
+ var lastVisibleLineState = await TestServices.Editor.GetLastVisibleLineStateAsync(HangMitigatingCancellationToken);
Assert.True(firstVisibleLine < lastVisibleLine);
- double zoomLevel = await Editor.GetZoomLevelAsync();
+ double zoomLevel = await TestServices.Editor.GetZoomLevelAsync(HangMitigatingCancellationToken);
- Point point = await Editor.GetCenterOfEditorOnScreenAsync();
+ Point point = await TestServices.Editor.GetCenterOfEditorOnScreenAsync(HangMitigatingCancellationToken);
await MoveMouseAsync(point);
- await SendKeys.SendAsync(inputSimulator =>
- {
- inputSimulator
- .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
- .Mouse.VerticalScroll(-1)
- .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
- });
+ await TestServices.IdeSendKeys.SendAsync(
+ inputSimulator =>
+ {
+ inputSimulator
+ .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
+ .Mouse.VerticalScroll(-1)
+ .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
+ },
+ HangMitigatingCancellationToken);
int expectedLastVisibleLine = lastVisibleLine + (lastVisibleLineState == VisibilityState.FullyVisible ? 1 : 0);
- Assert.Equal(0, await Editor.GetCaretPositionAsync());
- Assert.Equal(expectedLastVisibleLine, await Editor.GetFirstVisibleLineAsync());
- Assert.Equal(zoomLevel, await Editor.GetZoomLevelAsync());
+ Assert.Equal(0, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
+ Assert.Equal(expectedLastVisibleLine, await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken));
+ Assert.Equal(zoomLevel, await TestServices.Editor.GetZoomLevelAsync(HangMitigatingCancellationToken));
await MoveMouseAsync(point);
- await SendKeys.SendAsync(inputSimulator =>
- {
- inputSimulator
- .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
- .Mouse.VerticalScroll(1)
- .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
- });
-
- Assert.Equal(0, await Editor.GetCaretPositionAsync());
- Assert.Equal(0, await Editor.GetFirstVisibleLineAsync());
- Assert.Equal(zoomLevel, await Editor.GetZoomLevelAsync());
+ await TestServices.IdeSendKeys.SendAsync(
+ inputSimulator =>
+ {
+ inputSimulator
+ .Keyboard.KeyDown(VirtualKeyCode.CONTROL)
+ .Mouse.VerticalScroll(1)
+ .Keyboard.Sleep(10).KeyUp(VirtualKeyCode.CONTROL);
+ },
+ HangMitigatingCancellationToken);
+
+ Assert.Equal(0, await TestServices.Editor.GetCaretPositionAsync(HangMitigatingCancellationToken));
+ Assert.Equal(0, await TestServices.Editor.GetFirstVisibleLineAsync(HangMitigatingCancellationToken));
+ Assert.Equal(zoomLevel, await TestServices.Editor.GetZoomLevelAsync(HangMitigatingCancellationToken));
window.Close(vsSaveChanges.vsSaveChangesNo);
}
@@ -202,7 +202,7 @@ private async Task MoveMouseAsync(Point point)
var virtualPoint = new ScaleTransform(65535.0 / horizontalResolution, 65535.0 / verticalResolution).Transform(point);
TestOutputHelper.WriteLine($"Screen resolution of ({horizontalResolution}, {verticalResolution}) translates mouse to ({virtualPoint.X}, {virtualPoint.Y}).");
- await SendKeys.SendAsync(inputSimulator => inputSimulator.Mouse.MoveMouseTo(virtualPoint.X, virtualPoint.Y));
+ await TestServices.IdeSendKeys.SendAsync(inputSimulator => inputSimulator.Mouse.MoveMouseTo(virtualPoint.X, virtualPoint.Y), HangMitigatingCancellationToken);
// ⚠ The call to GetCursorPos is required for correct behavior.
var actualPoint = NativeMethods.GetCursorPos();
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Threading/JoinableTaskFactoryExtensions.cs b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Threading/JoinableTaskFactoryExtensions.cs
deleted file mode 100644
index 86fee12..0000000
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Threading/JoinableTaskFactoryExtensions.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
-// Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
-
-namespace Tvl.VisualStudio.MouseFastScroll.IntegrationTests.Threading
-{
- using System.Threading;
- using System.Windows.Threading;
- using Microsoft;
- using Microsoft.VisualStudio.Threading;
-
- // JoinableTaskFactory.WithPriority is available in later releases of vs-threading, but we reference 1.2.0.0 for
- // compatibility with Visual Studio 2013.
- // https://github.com/Microsoft/vs-threading/pull/142
- internal static class JoinableTaskFactoryExtensions
- {
- internal static JoinableTaskFactory WithPriority(this JoinableTaskFactory joinableTaskFactory, Dispatcher dispatcher, DispatcherPriority priority)
- {
- Requires.NotNull(joinableTaskFactory, nameof(joinableTaskFactory));
- Requires.NotNull(dispatcher, nameof(dispatcher));
-
- return new DispatcherJoinableTaskFactory(joinableTaskFactory, dispatcher, priority);
- }
-
- private class DispatcherJoinableTaskFactory : DelegatingJoinableTaskFactory
- {
- private readonly Dispatcher _dispatcher;
- private readonly DispatcherPriority _priority;
-
- public DispatcherJoinableTaskFactory(JoinableTaskFactory innerFactory, Dispatcher dispatcher, DispatcherPriority priority)
- : base(innerFactory)
- {
- _dispatcher = dispatcher;
- _priority = priority;
- }
-
- protected override void PostToUnderlyingSynchronizationContext(SendOrPostCallback callback, object state)
- {
- _dispatcher.BeginInvoke(_priority, callback, state);
- }
- }
- }
-}
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Tvl.VisualStudio.MouseFastScroll.IntegrationTests.csproj b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Tvl.VisualStudio.MouseFastScroll.IntegrationTests.csproj
index 48f170e..84d7c98 100644
--- a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Tvl.VisualStudio.MouseFastScroll.IntegrationTests.csproj
+++ b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/Tvl.VisualStudio.MouseFastScroll.IntegrationTests.csproj
@@ -2,8 +2,9 @@
- net46
+ net472;net46
true
+ 9
Mouse Fast Scroll extension for Visual Studio integration tests
@@ -14,18 +15,34 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<_Parameter1>Tvl.VisualStudio.MouseFastScroll.vsix
@@ -36,6 +53,12 @@
+
+
+ PreserveNewest
+
+
+
diff --git a/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/xunit.runner.json b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/xunit.runner.json
new file mode 100644
index 0000000..1c72a42
--- /dev/null
+++ b/Tvl.VisualStudio.MouseFastScroll.IntegrationTests/xunit.runner.json
@@ -0,0 +1,3 @@
+{
+ "shadowCopy": false
+}
diff --git a/appveyor.yml b/appveyor.yml
index 1db2c42..eb0a8e2 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,5 +1,5 @@
version: 1.0.{build}
-image: Visual Studio 2019
+image: Visual Studio 2022
configuration: Release
platform: Any CPU
init:
@@ -11,7 +11,7 @@ build:
test_script:
- ps: |
$unitTestAssembly = "Tvl.VisualStudio.MouseFastScroll.UnitTests\bin\$env:CONFIGURATION\net452\Tvl.VisualStudio.MouseFastScroll.UnitTests.dll"
- $integrationTestAssembly = "Tvl.VisualStudio.MouseFastScroll.IntegrationTests\bin\$env:CONFIGURATION\net46\Tvl.VisualStudio.MouseFastScroll.IntegrationTests.dll"
+ $integrationTestAssembly = "Tvl.VisualStudio.MouseFastScroll.IntegrationTests\bin\$env:CONFIGURATION\net472\Tvl.VisualStudio.MouseFastScroll.IntegrationTests.dll"
$buildProperties = [xml](Get-Content Directory.Build.props)
$openCoverVersion = $buildProperties.SelectSingleNode('/Project/ItemGroup/PackageReference[@Include="OpenCover"]').Version
$openCoverConsole = Join-Path (Join-Path $env:UserProfile '.nuget\packages\') "opencover\$openCoverVersion\tools\OpenCover.Console.exe"