diff --git a/IntegrationTests.testsettings b/IntegrationTests.testsettings new file mode 100644 index 0000000..fb61707 --- /dev/null +++ b/IntegrationTests.testsettings @@ -0,0 +1,14 @@ + + + This test run configuration uses the VS IDE host type in the test run. + + + + + + + diff --git a/UnitTests.testsettings b/UnitTests.testsettings new file mode 100644 index 0000000..f9cefbd --- /dev/null +++ b/UnitTests.testsettings @@ -0,0 +1,9 @@ + + + + This test run configuration is used for running the unit tests + diff --git a/VSPackageInstall/GlobalSuppressions.cs b/VSPackageInstall/GlobalSuppressions.cs new file mode 100644 index 0000000..a893f9d --- /dev/null +++ b/VSPackageInstall/GlobalSuppressions.cs @@ -0,0 +1,11 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. Project-level +// suppressions either have no target or are given a specific target +// and scoped to a namespace, type, member, etc. +// +// To add a suppression to this file, right-click the message in the +// Error List, point to "Suppress Message(s)", and click "In Project +// Suppression File". You do not need to add suppressions to this +// file manually. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] diff --git a/VSPackageInstall/Guids.cs b/VSPackageInstall/Guids.cs new file mode 100644 index 0000000..5d457be --- /dev/null +++ b/VSPackageInstall/Guids.cs @@ -0,0 +1,15 @@ +// Guids.cs +// MUST match guids.h +using System; + +namespace VitaliiGanzha.VSPackageInstall +{ + static class GuidList + { + public const string guidVSPackageInstallPkgString = "a527a9c1-ec2f-46a0-a6e3-371859c5845b"; + public const string guidVSPackageInstallCmdSetString = "4fddc919-41be-47b6-ae59-7125c75d1f1e"; + public const string guidToolWindowPersistanceString = "a6862923-42ae-438f-ac76-7a68be1011e3"; + + public static readonly Guid guidVSPackageInstallCmdSet = new Guid(guidVSPackageInstallCmdSetString); + }; +} \ No newline at end of file diff --git a/VSPackageInstall/Key.snk b/VSPackageInstall/Key.snk new file mode 100644 index 0000000..6a24fe5 Binary files /dev/null and b/VSPackageInstall/Key.snk differ diff --git a/VSPackageInstall/MyControl.xaml b/VSPackageInstall/MyControl.xaml new file mode 100644 index 0000000..5761443 --- /dev/null +++ b/VSPackageInstall/MyControl.xaml @@ -0,0 +1,17 @@ + + + + VS Ding + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/VSPackageInstall/VSPackageInstallPackage.cs b/VSPackageInstall/VSPackageInstallPackage.cs new file mode 100644 index 0000000..156ffa7 --- /dev/null +++ b/VSPackageInstall/VSPackageInstallPackage.cs @@ -0,0 +1,147 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Runtime.InteropServices; +using System.ComponentModel.Design; +using EnvDTE; +using EnvDTE80; +using Microsoft.Win32; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Shell; + +namespace VitaliiGanzha.VSPackageInstall +{ + /// + /// This is the class that implements the package exposed by this assembly. + /// + /// The minimum requirement for a class to be considered a valid package for Visual Studio + /// is to implement the IVsPackage interface and register itself with the shell. + /// This package uses the helper classes defined inside the Managed Package Framework (MPF) + /// to do it: it derives from the Package class that provides the implementation of the + /// IVsPackage interface and uses the registration attributes defined in the framework to + /// register itself and its components with the shell. + /// + // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is + // a package. + [PackageRegistration(UseManagedResourcesOnly = true)] + // This attribute is used to register the information needed to show this package + // in the Help/About dialog of Visual Studio. + [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] + // This attribute is needed to let the shell know that this package exposes some menus. + [ProvideMenuResource("Menus.ctmenu", 1)] + // This attribute registers a tool window exposed by this package. + [ProvideToolWindow(typeof(MyToolWindow))] + [Guid(GuidList.guidVSPackageInstallPkgString)] + public sealed class VSPackageInstallPackage : Package + { + private DTE2 applicationObject; + private AddIn addInInstance; + + /// + /// Default constructor of the package. + /// Inside this method you can place any initialization code that does not require + /// any Visual Studio service because at this point the package object is created but + /// not sited yet inside Visual Studio environment. The place to do all the other + /// initialization is the Initialize method. + /// + public VSPackageInstallPackage() + { + Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString())); + } + + /// + /// This function is called when the user clicks the menu item that shows the + /// tool window. See the Initialize method to see how the menu item is associated to + /// this function using the OleMenuCommandService service and the MenuCommand class. + /// + private void ShowToolWindow(object sender, EventArgs e) + { + // Get the instance number 0 of this tool window. This window is single instance so this instance + // is actually the only one. + // The last flag is set to true so that if the tool window does not exists it will be created. + ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true); + if ((null == window) || (null == window.Frame)) + { + throw new NotSupportedException(Resources.CanNotCreateWindow); + } + IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame; + Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show()); + } + + + ///////////////////////////////////////////////////////////////////////////// + // Overridden Package Implementation + #region Package Members + + /// + /// Initialization of the package; this method is called right after the package is sited, so this is the place + /// where you can put all the initialization code that rely on services provided by VisualStudio. + /// + protected override void Initialize() + { + try + { + Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString())); + base.Initialize(); + + // Add our command handlers for menu (commands must exist in the .vsct file) + OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; + if (null != mcs) + { + // Create the command for the menu item. + CommandID menuCommandID = new CommandID(GuidList.guidVSPackageInstallCmdSet, (int)PkgCmdIDList.cmdidVsDing); + MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID); + mcs.AddCommand(menuItem); + // Create the command for the tool window + CommandID toolwndCommandID = new CommandID(GuidList.guidVSPackageInstallCmdSet, (int)PkgCmdIDList.cmdidVsDingWnd); + MenuCommand menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandID); + mcs.AddCommand(menuToolWin); + } + + applicationObject = (DTE2)GetService(typeof(DTE)); + applicationObject.Events.BuildEvents.OnBuildDone += BuildEventsOnOnBuildDone; + } + catch (Exception e) + { + File.WriteAllText(@"c:\temp\test.txt", e.Message); + } + + } + + private void BuildEventsOnOnBuildDone(vsBuildScope scope, vsBuildAction action) + { + System.Media.SystemSounds.Asterisk.Play(); + } + + #endregion + + /// + /// This function is the callback used to execute a command when the a menu item is clicked. + /// See the Initialize method to see how the menu item is associated to this function using + /// the OleMenuCommandService service and the MenuCommand class. + /// + private void MenuItemCallback(object sender, EventArgs e) + { + // Show a Message Box to prove we were here + IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell)); + Guid clsid = Guid.Empty; + int result; + Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox( + 0, + ref clsid, + "VSPackageInstall", + string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.ToString()), + string.Empty, + 0, + OLEMSGBUTTON.OLEMSGBUTTON_OK, + OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, + OLEMSGICON.OLEMSGICON_INFO, + 0, // false + out result)); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/DialogboxPurger.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/DialogboxPurger.cs new file mode 100644 index 0000000..9061a9f --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/DialogboxPurger.cs @@ -0,0 +1,359 @@ + +namespace Microsoft.VsSDK.IntegrationTestLibrary +{ + using System; + using System.Collections.Generic; + using System.Text; + using System.Runtime.InteropServices; + using System.Threading; + using Microsoft.VisualStudio.Shell.Interop; + using Microsoft.VisualStudio.Shell; + + /// + /// This class is responsible to close dialog boxes that pop up during different VS Calls + /// + internal class DialogBoxPurger : IDisposable + { + /// + /// The default number of milliseconds to wait for the threads to signal to terminate. + /// + private const int DefaultMillisecondsToWait = 3500; + + /// + /// Object used for synchronization between thread calls. + /// + internal static volatile object Mutex = new object(); + + /// + /// The IVsUIShell. This cannot be queried on the working thread from the service provider. Must be done in the main thread.!! + /// + private IVsUIShell uiShell; + + /// + /// The button to "press" on the dialog. + /// + private int buttonAction; + + /// + /// Thread signales to the calling thread that it is done. + /// + private bool exitThread = false; + + /// + /// Calling thread signales to this thread to die. + /// + private AutoResetEvent threadDone = new AutoResetEvent(false); + + /// + /// The queued thread started. + /// + private AutoResetEvent threadStarted = new AutoResetEvent(false); + + /// + /// The result of the dialogbox closing for all the dialog boxes. That is if there are two of them and one fails this will be false. + /// + private bool dialogBoxCloseResult = false; + + /// + /// The expected text to see on the dialog box. If set the thread will continue finding the dialog box with this text. + /// + private string expectedDialogBoxText = String.Empty; + + /// + /// The number of the same dialog boxes to wait for. + /// This is for scenarios when two dialog boxes with the same text are popping up. + /// + private int numberOfDialogsToWaitFor = 1; + + /// + /// Has the object been disposed. + /// + private bool isDisposed; + + /// + /// Overloaded ctor. + /// + /// The botton to "press" on the dialog box. + /// The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes + /// The expected dialog box message to check for. + internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor, string expectedDialogMesssage) + { + this.buttonAction = buttonAction; + this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor; + this.expectedDialogBoxText = expectedDialogMesssage; + } + + /// + /// Overloaded ctor. + /// + /// The botton to "press" on the dialog box. + /// The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes + internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor) + { + this.buttonAction = buttonAction; + this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor; + } + + /// + /// Overloaded ctor. + /// + /// The botton to "press" on the dialog box. + /// The expected dialog box message to check for. + internal DialogBoxPurger(int buttonAction, string expectedDialogMesssage) + { + this.buttonAction = buttonAction; + this.expectedDialogBoxText = expectedDialogMesssage; + } + + /// + /// Overloaded ctor. + /// + /// The botton to "press" on the dialog box. + internal DialogBoxPurger(int buttonAction) + { + this.buttonAction = buttonAction; + } + + /// + #region IDisposable Members + + void IDisposable.Dispose() + { + if (this.isDisposed) + { + return; + } + + this.WaitForDialogThreadToTerminate(); + + this.isDisposed = true; + } + + /// + /// Spawns a thread that will start listening to dialog boxes. + /// + internal void Start() + { + // We ask for the uishell here since we cannot do that on the therad that we will spawn. + IVsUIShell uiShell = Package.GetGlobalService(typeof(SVsUIShell)) as IVsUIShell; + + if (uiShell == null) + { + throw new InvalidOperationException("Could not get the uiShell from the serviceProvider"); + } + + this.uiShell = uiShell; + + System.Threading.Thread thread = new System.Threading.Thread(new ThreadStart(this.HandleDialogBoxes)); + thread.Start(); + + // We should never deadlock here, hence do not use the lock. Wait to be sure that the thread started. + this.threadStarted.WaitOne(3500, false); + } + + /// + /// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down, + /// then it will tell to the thread to do it. + /// + internal bool WaitForDialogThreadToTerminate() + { + return this.WaitForDialogThreadToTerminate(DefaultMillisecondsToWait); + } + + /// + /// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down, + /// then it will tell to the thread to do it. + /// + /// The number milliseconds to wait for until the dialog purger thread is signaled to terminate. This is just for safe precaution that we do not hang. + /// The result of the dialog boxes closing + internal bool WaitForDialogThreadToTerminate(int numberOfMillisecondsToWait) + { + bool signaled = false; + + // We give millisecondsToWait sec to bring up and close the dialog box. + signaled = this.threadDone.WaitOne(numberOfMillisecondsToWait, false); + + // Kill the thread since a timeout occured. + if (!signaled) + { + lock (Mutex) + { + // Set the exit thread to true. Next time the thread will kill itselfes if it sees + this.exitThread = true; + } + + // Wait for the thread to finish. We should never deadlock here. + this.threadDone.WaitOne(); + } + + return this.dialogBoxCloseResult; + } + + /// + /// This is the thread method. + /// + private void HandleDialogBoxes() + { + // No synchronization numberOfDialogsToWaitFor since it is readonly + IntPtr[] hwnds = new IntPtr[this.numberOfDialogsToWaitFor]; + bool[] dialogBoxCloseResults = new bool[this.numberOfDialogsToWaitFor]; + + try + { + // Signal that we started + lock (Mutex) + { + this.threadStarted.Set(); + } + + // The loop will be exited either if a message is send by the caller thread or if we found the dialog. If a message box text is specified the loop will not exit until the dialog is found. + bool stayInLoop = true; + int dialogBoxesToWaitFor = 1; + + while (stayInLoop) + { + int hwndIndex = dialogBoxesToWaitFor - 1; + + // We need to lock since the caller might set context to null. + lock (Mutex) + { + if (this.exitThread) + { + break; + } + + // We protect the shell too from reentrency. + this.uiShell.GetDialogOwnerHwnd(out hwnds[hwndIndex]); + + } + + if (hwnds[hwndIndex] != IntPtr.Zero) + { + StringBuilder windowClassName = new StringBuilder(256); + NativeMethods.GetClassName(hwnds[hwndIndex], windowClassName, windowClassName.Capacity); + + // The #32770 is the class name of a messagebox dialog. + if (windowClassName.ToString().Contains("#32770")) + { + IntPtr unmanagedMemoryLocation = IntPtr.Zero; + string dialogBoxText = String.Empty; + try + { + unmanagedMemoryLocation = Marshal.AllocHGlobal(10 * 1024); + NativeMethods.EnumChildWindows(hwnds[hwndIndex], new NativeMethods.CallBack(FindMessageBoxString), unmanagedMemoryLocation); + dialogBoxText = Marshal.PtrToStringUni(unmanagedMemoryLocation); + } + finally + { + if (unmanagedMemoryLocation != IntPtr.Zero) + { + Marshal.FreeHGlobal(unmanagedMemoryLocation); + } + } + + lock (Mutex) + { + + // Since this is running on the main thread be sure that we close the dialog. + bool dialogCloseResult = false; + if (this.buttonAction != 0) + { + dialogCloseResult = NativeMethods.EndDialog(hwnds[hwndIndex], this.buttonAction); + } + + // Check if we have found the right dialog box. + if (String.IsNullOrEmpty(this.expectedDialogBoxText) || (!String.IsNullOrEmpty(dialogBoxText) && String.Compare(this.expectedDialogBoxText, dialogBoxText.Trim(), StringComparison.OrdinalIgnoreCase) == 0)) + { + dialogBoxCloseResults[hwndIndex] = dialogCloseResult; + if (dialogBoxesToWaitFor++ >= this.numberOfDialogsToWaitFor) + { + stayInLoop = false; + } + } + } + } + } + } + } + finally + { + //Let the main thread run a possible close command. + System.Threading.Thread.Sleep(2000); + + foreach (IntPtr hwnd in hwnds) + { + // At this point the dialog should be closed, if not attempt to close it. + if (hwnd != IntPtr.Zero) + { + NativeMethods.SendMessage(hwnd, NativeMethods.WM_CLOSE, 0, new IntPtr(0)); + } + } + + lock (Mutex) + { + // Be optimistic. + this.dialogBoxCloseResult = true; + + for (int i = 0; i < dialogBoxCloseResults.Length; i++) + { + if (!dialogBoxCloseResults[i]) + { + this.dialogBoxCloseResult = false; + break; + } + } + + this.threadDone.Set(); + } + } + } + + /// + /// Finds a messagebox string on a messagebox. + /// + /// The windows handle of the dialog + /// A pointer to the memorylocation the string will be written to + /// True if found. + private static bool FindMessageBoxString(IntPtr hwnd, IntPtr unmanagedMemoryLocation) + { + StringBuilder sb = new StringBuilder(512); + NativeMethods.GetClassName(hwnd, sb, sb.Capacity); + + if (sb.ToString().ToLower().Contains("static")) + { + StringBuilder windowText = new StringBuilder(2048); + NativeMethods.GetWindowText(hwnd, windowText, windowText.Capacity); + + if (windowText.Length > 0) + { + IntPtr stringAsPtr = IntPtr.Zero; + try + { + stringAsPtr = Marshal.StringToHGlobalAnsi(windowText.ToString()); + char[] stringAsArray = windowText.ToString().ToCharArray(); + + // Since unicode characters are copied check if we are out of the allocated length. + // If not add the end terminating zero. + if ((2 * stringAsArray.Length) + 1 < 2048) + { + Marshal.Copy(stringAsArray, 0, unmanagedMemoryLocation, stringAsArray.Length); + Marshal.WriteInt32(unmanagedMemoryLocation, 2 * stringAsArray.Length, 0); + } + } + finally + { + if (stringAsPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(stringAsPtr); + } + } + return false; + } + } + + return true; + } + + #endregion + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/NativeMethods.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/NativeMethods.cs new file mode 100644 index 0000000..8007567 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/NativeMethods.cs @@ -0,0 +1,154 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +namespace Microsoft.VsSDK.IntegrationTestLibrary +{ + using System; + using System.Collections.Generic; + using System.Text; + using System.Runtime.InteropServices; + using System.Threading; + using Microsoft.VisualStudio.Shell.Interop; + + /// + /// Defines pinvoked utility methods and internal VS Constants + /// + internal static class NativeMethods + { + internal delegate bool CallBack(IntPtr hwnd, IntPtr lParam); + + // Declare two overloaded SendMessage functions + [DllImport("user32.dll")] + internal static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg, + UInt32 wParam, IntPtr lParam); + + [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + internal static extern bool PeekMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg, HandleRef hwnd, int msgMin, int msgMax, int remove); + + [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + internal static extern bool TranslateMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg); + + [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + internal static extern int DispatchMessage([In] ref Microsoft.VisualStudio.OLE.Interop.MSG msg); + + [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + internal static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach); + + [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); + + [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + internal static extern uint GetCurrentThreadId(); + + [DllImport("user32")] + internal static extern int EnumChildWindows(IntPtr hwnd, CallBack x, IntPtr y); + + [DllImport("user32")] + internal static extern bool IsWindowVisible(IntPtr hDlg); + + [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] + internal static extern IntPtr SetFocus(IntPtr hWnd); + + [DllImport("user32")] + internal static extern int GetClassName(IntPtr hWnd, + StringBuilder className, + int stringLength); + [DllImport("user32")] + internal static extern int GetWindowText(IntPtr hWnd, StringBuilder className, int stringLength); + + + [DllImport("user32")] + internal static extern bool EndDialog(IntPtr hDlg, int result); + + [DllImport("Kernel32")] + internal static extern long GetLastError(); + + internal const int QS_KEY = 0x0001, + QS_MOUSEMOVE = 0x0002, + QS_MOUSEBUTTON = 0x0004, + QS_POSTMESSAGE = 0x0008, + QS_TIMER = 0x0010, + QS_PAINT = 0x0020, + QS_SENDMESSAGE = 0x0040, + QS_HOTKEY = 0x0080, + QS_ALLPOSTMESSAGE = 0x0100, + QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON, + QS_INPUT = QS_MOUSE | QS_KEY, + QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY, + QS_ALLINPUT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE; + + internal const int Facility_Win32 = 7; + + internal const int WM_CLOSE = 0x0010; + + internal const int + S_FALSE = 0x00000001, + S_OK = 0x00000000, + + IDOK = 1, + IDCANCEL = 2, + IDABORT = 3, + IDRETRY = 4, + IDIGNORE = 5, + IDYES = 6, + IDNO = 7, + IDCLOSE = 8, + IDHELP = 9, + IDTRYAGAIN = 10, + IDCONTINUE = 11; + + internal static long HResultFromWin32(long error) + { + if (error <= 0) + { + return error; + } + + return ((error & 0x0000FFFF) | (Facility_Win32 << 16) | 0x80000000); + } + + /// + /// Please use this "approved" method to compare file names. + /// + public static bool IsSamePath(string file1, string file2) + { + if (file1 == null || file1.Length == 0) + { + return (file2 == null || file2.Length == 0); + } + + Uri uri1 = null; + Uri uri2 = null; + + try + { + if (!Uri.TryCreate(file1, UriKind.Absolute, out uri1) || !Uri.TryCreate(file2, UriKind.Absolute, out uri2)) + { + return false; + } + + if (uri1 != null && uri1.IsFile && uri2 != null && uri2.IsFile) + { + return 0 == String.Compare(uri1.LocalPath, uri2.LocalPath, StringComparison.OrdinalIgnoreCase); + } + + return file1 == file2; + } + catch (UriFormatException e) + { + System.Diagnostics.Trace.WriteLine("Exception " + e.Message); + } + + return false; + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/Utils.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/Utils.cs new file mode 100644 index 0000000..1fa9deb --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/Utils.cs @@ -0,0 +1,401 @@ +using System; +using System.IO; +using System.Text; +using System.Reflection; +using System.Diagnostics; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell; +using EnvDTE; +using EnvDTE80; +using Microsoft.Win32; +using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using Microsoft.VisualStudio; + +namespace Microsoft.VsSDK.IntegrationTestLibrary +{ + /// + /// + public class TestUtils + { + + #region Methods: Handling embedded resources + /// + /// Gets the embedded file identified by the resource name, and converts the + /// file into a string. + /// + /// In VS, is DefaultNamespace.FileName? + /// + public static string GetEmbeddedStringResource(Assembly assembly, string resourceName) + { + string result = null; + + // Use the .NET procedure for loading a file embedded in the assembly + Stream stream = assembly.GetManifestResourceStream(resourceName); + if (stream != null) + { + // Convert bytes to string + byte[] fileContentsAsBytes = new byte[stream.Length]; + stream.Read(fileContentsAsBytes, 0, (int)stream.Length); + result = Encoding.Default.GetString(fileContentsAsBytes); + } + else + { + // Embedded resource not found - list available resources + Debug.WriteLine("Unable to find the embedded resource file '" + resourceName + "'."); + Debug.WriteLine(" Available resources:"); + foreach (string aResourceName in assembly.GetManifestResourceNames()) + { + Debug.WriteLine(" " + aResourceName); + } + } + + return result; + } + /// + /// + /// + /// + /// + /// + /// + public static void WriteEmbeddedResourceToFile(Assembly assembly, string embeddedResourceName, string fileName) + { + // Get file contents + string fileContents = GetEmbeddedStringResource(assembly, embeddedResourceName); + if (fileContents == null) + throw new ApplicationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName); + + // Write to file + StreamWriter sw = new StreamWriter(fileName); + sw.Write(fileContents); + sw.Close(); + } + + /// + /// Writes an embedded resource to a file. + /// + /// The name of the assembly that the embedded resource is defined. + /// The name of the embedded resource. + /// The file to write the embedded resource's content. + public static void WriteEmbeddedResourceToBinaryFile(Assembly assembly, string embeddedResourceName, string fileName) + { + // Get file contents + Stream stream = assembly.GetManifestResourceStream(embeddedResourceName); + if (stream == null) + throw new InvalidOperationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName); + + // Write to file + BinaryWriter sw = null; + FileStream fs = null; + try + { + byte[] fileContentsAsBytes = new byte[stream.Length]; + stream.Read(fileContentsAsBytes, 0, (int)stream.Length); + + FileMode mode = FileMode.CreateNew; + if (File.Exists(fileName)) + { + mode = FileMode.Truncate; + } + + fs = new FileStream(fileName, mode); + + sw = new BinaryWriter(fs); + sw.Write(fileContentsAsBytes); + } + finally + { + if (fs != null) + { + fs.Close(); + } + if (sw != null) + { + sw.Close(); + } + } + } + + #endregion + + #region Methods: Handling temporary files and directories + /// + /// Returns the first available file name on the form + /// [baseFileName]i.[extension] + /// where [i] starts at 1 and increases until there is an available file name + /// in the given directory. Also creates an empty file with that name to mark + /// that file as occupied. + /// + /// Directory that the file should live in. + /// + /// may be null, in which case the .[extension] part + /// is not added. + /// Full file name. + public static string GetNewFileName(string directory, string baseFileName, string extension) + { + // Get the new file name + string fileName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseFileName, extension); + + // Create an empty file to mark it as taken + StreamWriter sw = new StreamWriter(fileName); + + sw.Write(""); + sw.Close(); + return fileName; + } + /// + /// Returns the first available directory name on the form + /// [baseDirectoryName]i + /// where [i] starts at 1 and increases until there is an available directory name + /// in the given directory. Also creates the directory to mark it as occupied. + /// + /// Directory that the file should live in. + /// + /// Full directory name. + public static string GetNewDirectoryName(string directory, string baseDirectoryName) + { + // Get the new file name + string directoryName = GetNewFileOrDirectoryNameWithoutCreatingAnything(directory, baseDirectoryName, null); + + // Create an empty directory to make it as occupied + Directory.CreateDirectory(directoryName); + + return directoryName; + } + + /// + /// + /// + /// + /// + /// + /// + private static string GetNewFileOrDirectoryNameWithoutCreatingAnything(string directory, string baseFileName, string extension) + { + // - get a file name that we can use + string fileName; + int i = 1; + + string fullFileName = null; + while (true) + { + // construct next file name + fileName = baseFileName + i; + if (extension != null) + fileName += '.' + extension; + + // check if that file exists in the directory + fullFileName = Path.Combine(directory, fileName); + + if (!File.Exists(fullFileName) && !Directory.Exists(fullFileName)) + break; + else + i++; + } + + return fullFileName; + } + #endregion + + #region Methods: Handling solutions + /// + /// Closes the currently open solution (if any), and creates a new solution with the given name. + /// + /// Name of new solution. + public void CreateEmptySolution(string directory, string solutionName) + { + CloseCurrentSolution(__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave); + + string solutionDirectory = GetNewDirectoryName(directory, solutionName); + + // Create and force save solution + IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); + solutionService.CreateSolution(solutionDirectory, solutionName, (uint)__VSCREATESOLUTIONFLAGS.CSF_SILENT); + solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0); + DTE dte = VsIdeTestHostContext.Dte; + Assert.AreEqual(solutionName + ".sln", Path.GetFileName(dte.Solution.FileName), "Newly created solution has wrong Filename"); + } + + public void CloseCurrentSolution(__VSSLNSAVEOPTIONS saveoptions) + { + // Get solution service + IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); + + // Close already open solution + solutionService.CloseSolutionElement((uint)saveoptions, null, 0); + } + + public void ForceSaveSolution() + { + // Get solution service + IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); + + // Force-save the solution + solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, null, 0); + } + + /// + /// Get current number of open project in solution + /// + /// + public int ProjectCount() + { + // Get solution service + IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); + object projectCount; + solutionService.GetProperty((int)__VSPROPID.VSPROPID_ProjectCount, out projectCount); + return (int)projectCount; + } + #endregion + + #region Methods: Handling projects + /// + /// Creates a project. + /// + /// Name of new project. + /// Name of project template to use + /// language + /// New project. + public void CreateProjectFromTemplate(string projectName, string templateName, string language, bool exclusive) + { + DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); + + Solution2 sol = dte.Solution as Solution2; + string projectTemplate = sol.GetProjectTemplate(templateName, language); + + // - project name and directory + string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName; + string projectDirectory = GetNewDirectoryName(solutionDirectory, projectName); + + dte.Solution.AddFromTemplate(projectTemplate, projectDirectory, projectName, false); + } + #endregion + + #region Methods: Handling project items + /// + /// Create a new item in the project + /// + /// the parent collection for the new item + /// + /// + /// + /// + public ProjectItem AddNewItemFromVsTemplate(ProjectItems parent, string templateName, string language, string name) + { + if (parent == null) + throw new ArgumentException("project"); + if (name == null) + throw new ArgumentException("name"); + + DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); + + Solution2 sol = dte.Solution as Solution2; + + string filename = sol.GetProjectItemTemplate(templateName, language); + + parent.AddFromTemplate(filename, name); + + return parent.Item(name); + } + + /// + /// Save an open document. + /// + /// for filebased documents this is the full path to the document + public void SaveDocument(string documentMoniker) + { + // Get document cookie and hierarchy for the file + IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable)); + uint docCookie; + IntPtr docData; + IVsHierarchy hierarchy; + uint itemId; + runningDocumentTableService.FindAndLockDocument( + (uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock, + documentMoniker, + out hierarchy, + out itemId, + out docData, + out docCookie); + + // Save the document + IVsSolution solutionService = (IVsSolution)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)); + solutionService.SaveSolutionElement((uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_ForceSave, hierarchy, docCookie); + } + + public void CloseInEditorWithoutSaving(string fullFileName) + { + // Get the RDT service + IVsRunningDocumentTable runningDocumentTableService = (IVsRunningDocumentTable)VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsRunningDocumentTable)); + Assert.IsNotNull(runningDocumentTableService, "Failed to get the Running Document Table Service"); + + // Get our document cookie and hierarchy for the file + uint docCookie; + IntPtr docData; + IVsHierarchy hierarchy; + uint itemId; + runningDocumentTableService.FindAndLockDocument( + (uint)Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS.RDT_NoLock, + fullFileName, + out hierarchy, + out itemId, + out docData, + out docCookie); + + // Get the SolutionService + IVsSolution solutionService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(IVsSolution)) as IVsSolution; + Assert.IsNotNull(solutionService, "Failed to get IVsSolution service"); + + // Close the document + solutionService.CloseSolutionElement( + (uint)__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave, + hierarchy, + docCookie); + } + #endregion + + #region Methods: Handling Toolwindows + public bool CanFindToolwindow(Guid persistenceGuid) + { + IVsUIShell uiShellService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsUIShell)) as IVsUIShell; + Assert.IsNotNull(uiShellService); + IVsWindowFrame windowFrame; + int hr = uiShellService.FindToolWindow((uint)__VSFINDTOOLWIN.FTW_fFindFirst, ref persistenceGuid, out windowFrame); + Assert.IsTrue(hr == VSConstants.S_OK); + + return (windowFrame != null); + } + #endregion + + #region Methods: Loading packages + public IVsPackage LoadPackage(Guid packageGuid) + { + IVsShell shellService = (IVsShell)VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)); + IVsPackage package; + shellService.LoadPackage(ref packageGuid, out package); + Assert.IsNotNull(package, "Failed to load package"); + return package; + } + #endregion + + /// + /// Executes a Command (menu item) in the given context + /// + public void ExecuteCommand(CommandID cmd) + { + object Customin = null; + object Customout = null; + string guidString = cmd.Guid.ToString("B").ToUpper(); + int cmdId = cmd.ID; + DTE dte = VsIdeTestHostContext.Dte; + dte.Commands.Raise(guidString, cmdId, ref Customin, ref Customout); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/Key.snk b/VSPackageInstall/VSPackageInstall_IntegrationTests/Key.snk new file mode 100644 index 0000000..6a24fe5 Binary files /dev/null and b/VSPackageInstall/VSPackageInstall_IntegrationTests/Key.snk differ diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/MenuItemTest.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/MenuItemTest.cs new file mode 100644 index 0000000..8d22566 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/MenuItemTest.cs @@ -0,0 +1,66 @@ +using System; +using System.Globalization; +using System.ComponentModel.Design; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell; +using Microsoft.VsSDK.IntegrationTestLibrary; +using Microsoft.VSSDK.Tools.VsIdeTesting; + +namespace VSPackageInstall_IntegrationTests +{ + [TestClass()] + public class MenuItemTest + { + private delegate void ThreadInvoker(); + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + /// + ///A test for lauching the command and closing the associated dialogbox + /// + [TestMethod()] + [HostType("VS IDE")] + public void LaunchCommand() + { + UIThreadInvoker.Invoke((ThreadInvoker)delegate() + { + CommandID menuItemCmd = new CommandID(VitaliiGanzha.VSPackageInstall.GuidList.guidVSPackageInstallCmdSet, (int)VitaliiGanzha.VSPackageInstall.PkgCmdIDList.cmdidVsDing); + + // Create the DialogBoxListener Thread. + string expectedDialogBoxText = string.Format(CultureInfo.CurrentCulture, "{0}\n\nInside {1}.MenuItemCallback()", "VSPackageInstall", "VitaliiGanzha.VSPackageInstall.VSPackageInstallPackage"); + DialogBoxPurger purger = new DialogBoxPurger(NativeMethods.IDOK, expectedDialogBoxText); + + try + { + purger.Start(); + + TestUtils testUtils = new TestUtils(); + testUtils.ExecuteCommand(menuItemCmd); + } + finally + { + Assert.IsTrue(purger.WaitForDialogThreadToTerminate(), "The dialog box has not shown"); + } + }); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/PackageTest.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/PackageTest.cs new file mode 100644 index 0000000..62e9689 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/PackageTest.cs @@ -0,0 +1,59 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell; +using EnvDTE; + +namespace VSPackageInstall_IntegrationTests +{ + /// + /// Integration test for package validation + /// + [TestClass] + public class PackageTest + { + private delegate void ThreadInvoker(); + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + [TestMethod] + [HostType("VS IDE")] + public void PackageLoadTest() + { + UIThreadInvoker.Invoke((ThreadInvoker)delegate() + { + + //Get the Shell Service + IVsShell shellService = VsIdeTestHostContext.ServiceProvider.GetService(typeof(SVsShell)) as IVsShell; + Assert.IsNotNull(shellService); + + //Validate package load + IVsPackage package; + Guid packageGuid = new Guid(VitaliiGanzha.VSPackageInstall.GuidList.guidVSPackageInstallPkgString); + Assert.IsTrue(0 == shellService.LoadPackage(ref packageGuid, out package)); + Assert.IsNotNull(package, "Package failed to load"); + + }); + } + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CPPProjectTests.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CPPProjectTests.cs new file mode 100644 index 0000000..d146f65 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CPPProjectTests.cs @@ -0,0 +1,109 @@ +using System; +using System.Text; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VsSDK.IntegrationTestLibrary; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using EnvDTE; +using System.IO; + +namespace VSPackageInstall_IntegrationTests.IntegrationTests +{ + [TestClass] + public class CPPProjectTests + { + #region fields + private delegate void ThreadInvoker(); + private TestContext _testContext; + #endregion + + #region properties + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get { return _testContext; } + set { _testContext = value; } + } + #endregion + + #region ctors + public CPPProjectTests() + { + } + #endregion + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + [HostType("VS IDE")] + [TestMethod] + public void CPPWinformsApplication() + { + UIThreadInvoker.Invoke((ThreadInvoker)delegate() + { + //Solution and project creation parameters + string solutionName = "CPPWinApp"; + string projectName = "CPPWinApp"; + + //Template parameters + string projectType = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"; + string projectTemplateName = Path.Combine("vcNet", "mc++appwiz.vsz"); + + string itemTemplateName = "newc++file.cpp"; + string newFileName = "Test.cpp"; + + DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); + + TestUtils testUtils = new TestUtils(); + + testUtils.CreateEmptySolution(TestContext.TestDir, solutionName); + Assert.AreEqual(0, testUtils.ProjectCount()); + + //Add new CPP Windows application project to existing solution + string solutionDirectory = Directory.GetParent(dte.Solution.FullName).FullName; + string projectDirectory = TestUtils.GetNewDirectoryName(solutionDirectory, projectName); + string projectTemplatePath = Path.Combine(dte.Solution.get_TemplatePath(projectType), projectTemplateName); + Assert.IsTrue(File.Exists(projectTemplatePath), string.Format("Could not find template file: {0}", projectTemplatePath)); + dte.Solution.AddFromTemplate(projectTemplatePath, projectDirectory, projectName, false); + + //Verify that the new project has been added to the solution + Assert.AreEqual(1, testUtils.ProjectCount()); + + //Get the project + Project project = dte.Solution.Item(1); + Assert.IsNotNull(project); + Assert.IsTrue(string.Compare(project.Name, projectName, StringComparison.InvariantCultureIgnoreCase) == 0); + + //Verify Adding new code file to project + string newItemTemplatePath = Path.Combine(dte.Solution.ProjectItemsTemplatePath(projectType), itemTemplateName); + Assert.IsTrue(File.Exists(newItemTemplatePath)); + ProjectItem item = project.ProjectItems.AddFromTemplate(newItemTemplatePath, newFileName); + Assert.IsNotNull(item); + + }); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CSharpProjectTests.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CSharpProjectTests.cs new file mode 100644 index 0000000..0d34ad0 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CSharpProjectTests.cs @@ -0,0 +1,83 @@ +using System; +using System.Text; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VsSDK.IntegrationTestLibrary; +using Microsoft.VSSDK.Tools.VsIdeTesting; + +namespace VSPackageInstall_IntegrationTests.IntegrationTests +{ + [TestClass] + public class CSharpProjectTests + { + #region fields + private delegate void ThreadInvoker(); + private TestContext _testContext; + #endregion + + #region properties + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get { return _testContext; } + set { _testContext = value; } + } + #endregion + + #region ctors + public CSharpProjectTests() + { + } + #endregion + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + [TestMethod] + [HostType("VS IDE")] + public void WinformsApplication() + { + UIThreadInvoker.Invoke((ThreadInvoker)delegate() + { + TestUtils testUtils = new TestUtils(); + + testUtils.CreateEmptySolution(TestContext.TestDir, "CSWinApp"); + Assert.AreEqual(0, testUtils.ProjectCount()); + + //Create Winforms application project + //TestUtils.CreateProjectFromTemplate("MyWindowsApp", "Windows Application", "CSharp", false); + //Assert.AreEqual(1, TestUtils.ProjectCount()); + + //TODO Verify that we can debug launch the application + + //TODO Set Break point and verify that will hit + + //TODO Verify Adding new project item to project + + }); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/SolutionTests.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/SolutionTests.cs new file mode 100644 index 0000000..00e4e51 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/SolutionTests.cs @@ -0,0 +1,55 @@ +using System; +using System.Text; +using System.Collections.Generic; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using EnvDTE; +using System.IO; +using Microsoft.VsSDK.IntegrationTestLibrary; + + +namespace VSPackageInstall_IntegrationTests.IntegrationTests +{ + [TestClass] + public class SolutionTests + { + #region fields + private delegate void ThreadInvoker(); + private TestContext _testContext; + #endregion + + #region properties + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get { return _testContext; } + set { _testContext = value; } + } + #endregion + + + #region ctors + public SolutionTests() + { + } + + #endregion + + [TestMethod] + [HostType("VS IDE")] + public void CreateEmptySolution() + { + UIThreadInvoker.Invoke((ThreadInvoker)delegate() + { + TestUtils testUtils = new TestUtils(); + testUtils.CloseCurrentSolution(__VSSLNSAVEOPTIONS.SLNSAVEOPT_NoSave); + testUtils.CreateEmptySolution(TestContext.TestDir, "EmptySolution"); + }); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/VBProjectTests.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/VBProjectTests.cs new file mode 100644 index 0000000..d9253df --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/VBProjectTests.cs @@ -0,0 +1,101 @@ +using System; +using System.Text; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VsSDK.IntegrationTestLibrary; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using EnvDTE; + +namespace VSPackageInstall_IntegrationTests.IntegrationTests +{ + [TestClass] + public class VisualBasicProjectTests + { + #region fields + private delegate void ThreadInvoker(); + private TestContext _testContext; + #endregion + + #region properties + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get { return _testContext; } + set { _testContext = value; } + } + #endregion + + #region ctors + public VisualBasicProjectTests() + { + } + #endregion + + #region Additional test attributes + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + #endregion + + [HostType("VS IDE")] + [TestMethod] + public void VBWinformsApplication() + { + UIThreadInvoker.Invoke((ThreadInvoker)delegate() + { + //Solution and project creation parameters + string solutionName = "VBWinApp"; + string projectName = "VBWinApp"; + + //Template parameters + string language = "VisualBasic"; + string projectTemplateName = "WindowsApplication.Zip"; + string itemTemplateName = "CodeFile.zip"; + string newFileName = "Test.vb"; + + DTE dte = (DTE)VsIdeTestHostContext.ServiceProvider.GetService(typeof(DTE)); + + TestUtils testUtils = new TestUtils(); + + testUtils.CreateEmptySolution(TestContext.TestDir, solutionName); + Assert.AreEqual(0, testUtils.ProjectCount()); + + //Add new Windows application project to existing solution + testUtils.CreateProjectFromTemplate(projectName, projectTemplateName, language, false); + + //Verify that the new project has been added to the solution + Assert.AreEqual(1, testUtils.ProjectCount()); + + //Get the project + Project project = dte.Solution.Item(1); + Assert.IsNotNull(project); + Assert.IsTrue(string.Compare(project.Name, projectName, StringComparison.InvariantCultureIgnoreCase) == 0); + + //Verify Adding new code file to project + ProjectItem newCodeFileItem = testUtils.AddNewItemFromVsTemplate(project.ProjectItems, itemTemplateName, language, newFileName); + Assert.IsNotNull(newCodeFileItem, "Could not create new project item"); + + }); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/ToolWindowTest.cs b/VSPackageInstall/VSPackageInstall_IntegrationTests/ToolWindowTest.cs new file mode 100644 index 0000000..ef5e460 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/ToolWindowTest.cs @@ -0,0 +1,56 @@ +using System; +using System.ComponentModel.Design; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.OLE.Interop; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell; +using Microsoft.VsSDK.IntegrationTestLibrary; +using Microsoft.VSSDK.Tools.VsIdeTesting; + +namespace VSPackageInstall_IntegrationTests +{ + + [TestClass()] + public class ToolWindowTest + { + private delegate void ThreadInvoker(); + + private TestContext testContextInstance; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + /// + ///A test for showing the toolwindow + /// + [TestMethod()] + [HostType("VS IDE")] + public void ShowToolWindow() + { + UIThreadInvoker.Invoke((ThreadInvoker)delegate() + { + CommandID toolWindowCmd = new CommandID(VitaliiGanzha.VSPackageInstall.GuidList.guidVSPackageInstallCmdSet, (int)VitaliiGanzha.VSPackageInstall.PkgCmdIDList.cmdidVsDingWnd); + + TestUtils testUtils = new TestUtils(); + testUtils.ExecuteCommand(toolWindowCmd); + + Assert.IsTrue(testUtils.CanFindToolwindow(new Guid(VitaliiGanzha.VSPackageInstall.GuidList.guidToolWindowPersistanceString))); + + }); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_IntegrationTests/VSPackageInstall_IntegrationTests.csproj b/VSPackageInstall/VSPackageInstall_IntegrationTests/VSPackageInstall_IntegrationTests.csproj new file mode 100644 index 0000000..e6bf3bb --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_IntegrationTests/VSPackageInstall_IntegrationTests.csproj @@ -0,0 +1,91 @@ + + + + Debug + AnyCPU + 2.0 + {77A542CC-52C0-4387-B57B-63AF5F597EA1} + Library + Properties + VSPackageInstall_IntegrationTests + VSPackageInstall_IntegrationTests + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Key.snk + + + true + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6} + VSPackageInstall + + + + + \ No newline at end of file diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/Key.snk b/VSPackageInstall/VSPackageInstall_UnitTests/Key.snk new file mode 100644 index 0000000..6a24fe5 Binary files /dev/null and b/VSPackageInstall/VSPackageInstall_UnitTests/Key.snk differ diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/MenuItemCallback.cs b/VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/MenuItemCallback.cs new file mode 100644 index 0000000..b5aac3f --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/MenuItemCallback.cs @@ -0,0 +1,80 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +using System; +using System.Collections; +using System.Text; +using System.Reflection; +using System.ComponentModel.Design; +using Microsoft.VsSDK.UnitTestLibrary; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.Shell; +using VitaliiGanzha.VSPackageInstall; + +namespace VSPackageInstall_UnitTests.MenuItemTests +{ + [TestClass()] + public class MenuItemTest + { + /// + /// Verify that a new menu command object gets added to the OleMenuCommandService. + /// This action takes place In the Initialize method of the Package object + /// + [TestMethod] + public void InitializeMenuCommand() + { + // Create the package + IVsPackage package = new VSPackageInstallPackage() as IVsPackage; + Assert.IsNotNull(package, "The object does not implement IVsPackage"); + + // Create a basic service provider + OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); + + // Site the package + Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); + + //Verify that the menu command can be found + CommandID menuCommandID = new CommandID(VitaliiGanzha.VSPackageInstall.GuidList.guidVSPackageInstallCmdSet, (int)VitaliiGanzha.VSPackageInstall.PkgCmdIDList.cmdidVsDing); + System.Reflection.MethodInfo info = typeof(Package).GetMethod("GetService", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.IsNotNull(info); + OleMenuCommandService mcs = info.Invoke(package, new object[] { (typeof(IMenuCommandService)) }) as OleMenuCommandService; + Assert.IsNotNull(mcs.FindCommand(menuCommandID)); + } + + [TestMethod] + public void MenuItemCallback() + { + // Create the package + IVsPackage package = new VSPackageInstallPackage() as IVsPackage; + Assert.IsNotNull(package, "The object does not implement IVsPackage"); + + // Create a basic service provider + OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); + + // Create a UIShell service mock and proffer the service so that it can called from the MenuItemCallback method + BaseMock uishellMock = UIShellServiceMock.GetUiShellInstance(); + serviceProvider.AddService(typeof(SVsUIShell), uishellMock, true); + + // Site the package + Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); + + //Invoke private method on package class and observe that the method does not throw + System.Reflection.MethodInfo info = package.GetType().GetMethod("MenuItemCallback", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.IsNotNull(info, "Failed to get the private method MenuItemCallback throug refplection"); + info.Invoke(package, new object[] { null, null }); + + //Clean up services + serviceProvider.RemoveService(typeof(SVsUIShell)); + + } + } +} diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/UIShellServiceMock.cs b/VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/UIShellServiceMock.cs new file mode 100644 index 0000000..2d9b464 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/UIShellServiceMock.cs @@ -0,0 +1,76 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +using System; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VsSDK.UnitTestLibrary; + +namespace VSPackageInstall_UnitTests +{ + static class UIShellServiceMock + { + private static GenericMockFactory uiShellFactory; + + #region UiShell Getters + /// + /// Returns an IVsUiShell that does not implement any methods + /// + /// + internal static BaseMock GetUiShellInstance() + { + if (uiShellFactory == null) + { + uiShellFactory = new GenericMockFactory("UiShell", new Type[] { typeof(IVsUIShell), typeof(IVsUIShellOpenDocument) }); + } + BaseMock uiShell = uiShellFactory.GetInstance(); + return uiShell; + } + + /// + /// Get an IVsUiShell that implements SetWaitCursor, SaveDocDataToFile, ShowMessageBox + /// + /// uishell mock + internal static BaseMock GetUiShellInstance0() + { + BaseMock uiShell = GetUiShellInstance(); + string name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "SetWaitCursor"); + uiShell.AddMethodCallback(name, new EventHandler(SetWaitCursorCallBack)); + + name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "SaveDocDataToFile"); + uiShell.AddMethodCallback(name, new EventHandler(SaveDocDataToFileCallBack)); + + name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "ShowMessageBox"); + uiShell.AddMethodCallback(name, new EventHandler(ShowMessageBoxCallBack)); + return uiShell; + } + #endregion + + #region Callbacks + private static void SetWaitCursorCallBack(object caller, CallbackArgs arguments) + { + arguments.ReturnValue = VSConstants.S_OK; + } + + private static void SaveDocDataToFileCallBack(object caller, CallbackArgs arguments) + { + arguments.ReturnValue = VSConstants.S_OK; + } + + private static void ShowMessageBoxCallBack(object caller, CallbackArgs arguments) + { + arguments.ReturnValue = VSConstants.S_OK; + arguments.SetParameter(10, (int)System.Windows.Forms.DialogResult.Yes); + } + + #endregion + } +} \ No newline at end of file diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/MyToolWindow.cs b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/MyToolWindow.cs new file mode 100644 index 0000000..23e98ae --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/MyToolWindow.cs @@ -0,0 +1,58 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +using System; +using System.Collections; +using System.Text; +using System.Reflection; +using Microsoft.VsSDK.UnitTestLibrary; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using VitaliiGanzha.VSPackageInstall; + +namespace VSPackageInstall_UnitTests.MyToolWindowTest +{ + /// + ///This is a test class for MyToolWindowTest and is intended + ///to contain all MyToolWindowTest Unit Tests + /// + [TestClass()] + public class MyToolWindowTest + { + + /// + ///MyToolWindow Constructor test + /// + [TestMethod()] + public void MyToolWindowConstructorTest() + { + + MyToolWindow target = new MyToolWindow(); + Assert.IsNotNull(target, "Failed to create an instance of MyToolWindow"); + + MethodInfo method = target.GetType().GetMethod("get_Content", BindingFlags.Public | BindingFlags.Instance); + Assert.IsNotNull(method.Invoke(target, null), "MyControl object was not instantiated"); + + } + + /// + ///Verify the Content property is valid. + /// + [TestMethod()] + public void WindowPropertyTest() + { + MyToolWindow target = new MyToolWindow(); + Assert.IsNotNull(target.Content, "Content property was null"); + } + + } +} diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/ShowToolWindow.cs b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/ShowToolWindow.cs new file mode 100644 index 0000000..bc7e9c5 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/ShowToolWindow.cs @@ -0,0 +1,77 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +using System; +using System.Collections; +using System.Text; +using System.Reflection; +using Microsoft.VsSDK.UnitTestLibrary; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VSSDK.Tools.VsIdeTesting; +using VitaliiGanzha.VSPackageInstall; + +namespace VSPackageInstall_UnitTests.MyToolWindowTest +{ + [TestClass()] + public class ShowToolWindowTest + { + + [TestMethod()] + public void ValidateToolWindowShown() + { + IVsPackage package = new VSPackageInstallPackage() as IVsPackage; + + // Create a basic service provider + OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); + + //Add uishell service that knows how to create a toolwindow + BaseMock uiShellService = UIShellServiceMock.GetUiShellInstanceCreateToolWin(); + serviceProvider.AddService(typeof(SVsUIShell), uiShellService, false); + + // Site the package + Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); + + MethodInfo method = typeof(VSPackageInstallPackage).GetMethod("ShowToolWindow", BindingFlags.NonPublic | BindingFlags.Instance); + + object result = method.Invoke(package, new object[] { null, null }); + } + + [TestMethod()] + [ExpectedException(typeof(InvalidOperationException), "Did not throw expected exception when windowframe object was null")] + public void ShowToolwindowNegativeTest() + { + IVsPackage package = new VSPackageInstallPackage() as IVsPackage; + + // Create a basic service provider + OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); + + //Add uishell service that knows how to create a toolwindow + BaseMock uiShellService = UIShellServiceMock.GetUiShellInstanceCreateToolWinReturnsNull(); + serviceProvider.AddService(typeof(SVsUIShell), uiShellService, false); + + // Site the package + Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); + + MethodInfo method = typeof(VSPackageInstallPackage).GetMethod("ShowToolWindow", BindingFlags.NonPublic | BindingFlags.Instance); + + //Invoke thows TargetInvocationException, but we want it's inner Exception thrown by ShowToolWindow, InvalidOperationException. + try + { + object result = method.Invoke(package, new object[] { null, null }); + } + catch (Exception e) + { + throw e.InnerException; + } + } + } +} diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/UIShellServiceMock.cs b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/UIShellServiceMock.cs new file mode 100644 index 0000000..404dfb6 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/UIShellServiceMock.cs @@ -0,0 +1,84 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +using System; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VsSDK.UnitTestLibrary; + +namespace VSPackageInstall_UnitTests.MyToolWindowTest +{ + static class UIShellServiceMock + { + private static GenericMockFactory uiShellFactory; + + #region UiShell Getters + /// + /// Returns an IVsUiShell that does not implement any methods + /// + /// + internal static BaseMock GetUiShellInstance() + { + if (uiShellFactory == null) + { + uiShellFactory = new GenericMockFactory("UiShell", new Type[] { typeof(IVsUIShell), typeof(IVsUIShellOpenDocument) }); + } + BaseMock uiShell = uiShellFactory.GetInstance(); + return uiShell; + } + + /// + /// Get an IVsUiShell that implement CreateToolWindow + /// + /// uishell mock + internal static BaseMock GetUiShellInstanceCreateToolWin() + { + BaseMock uiShell = GetUiShellInstance(); + string name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "CreateToolWindow"); + uiShell.AddMethodCallback(name, new EventHandler(CreateToolWindowCallBack)); + + return uiShell; + } + + /// + /// Get an IVsUiShell that implement CreateToolWindow (negative test) + /// + /// uishell mock + internal static BaseMock GetUiShellInstanceCreateToolWinReturnsNull() + { + BaseMock uiShell = GetUiShellInstance(); + string name = string.Format("{0}.{1}", typeof(IVsUIShell).FullName, "CreateToolWindow"); + uiShell.AddMethodCallback(name, new EventHandler(CreateToolWindowNegativeTestCallBack)); + + return uiShell; + } + #endregion + + #region Callbacks + private static void CreateToolWindowCallBack(object caller, CallbackArgs arguments) + { + arguments.ReturnValue = VSConstants.S_OK; + + // Create the output mock object for the frame + IVsWindowFrame frame = WindowFrameMock.GetBaseFrame(); + arguments.SetParameter(9, frame); + } + + private static void CreateToolWindowNegativeTestCallBack(object caller, CallbackArgs arguments) + { + arguments.ReturnValue = VSConstants.S_OK; + + //set the windowframe object to null + arguments.SetParameter(9, null); + } + #endregion + } +} \ No newline at end of file diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/WindowFrameMock.cs b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/WindowFrameMock.cs new file mode 100644 index 0000000..90d190c --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/WindowFrameMock.cs @@ -0,0 +1,39 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VsSDK.UnitTestLibrary; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; + +namespace VSPackageInstall_UnitTests.MyToolWindowTest +{ + class WindowFrameMock + { + const string propertiesName = "properties"; + + private static GenericMockFactory frameFactory = null; + + /// + /// Return a IVsWindowFrame without any special implementation + /// + /// + internal static IVsWindowFrame GetBaseFrame() + { + if (frameFactory == null) + frameFactory = new GenericMockFactory("WindowFrame", new Type[] { typeof(IVsWindowFrame), typeof(IVsWindowFrame2) }); + IVsWindowFrame frame = (IVsWindowFrame)frameFactory.GetInstance(); + return frame; + } + } +} diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/PackageTest.cs b/VSPackageInstall/VSPackageInstall_UnitTests/PackageTest.cs new file mode 100644 index 0000000..bcf1b0a --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/PackageTest.cs @@ -0,0 +1,56 @@ +/*************************************************************************** + +Copyright (c) Microsoft Corporation. All rights reserved. +This code is licensed under the Visual Studio SDK license terms. +THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. + +***************************************************************************/ + +using System; +using System.Collections; +using System.Text; +using System.Reflection; +using Microsoft.VsSDK.UnitTestLibrary; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using VitaliiGanzha.VSPackageInstall; + +namespace VSPackageInstall_UnitTests +{ + [TestClass()] + public class PackageTest + { + [TestMethod()] + public void CreateInstance() + { + VSPackageInstallPackage package = new VSPackageInstallPackage(); + } + + [TestMethod()] + public void IsIVsPackage() + { + VSPackageInstallPackage package = new VSPackageInstallPackage(); + Assert.IsNotNull(package as IVsPackage, "The object does not implement IVsPackage"); + } + + [TestMethod()] + public void SetSite() + { + // Create the package + IVsPackage package = new VSPackageInstallPackage() as IVsPackage; + Assert.IsNotNull(package, "The object does not implement IVsPackage"); + + // Create a basic service provider + OleServiceProvider serviceProvider = OleServiceProvider.CreateOleServiceProviderWithBasicServices(); + + // Site the package + Assert.AreEqual(0, package.SetSite(serviceProvider), "SetSite did not return S_OK"); + + // Unsite the package + Assert.AreEqual(0, package.SetSite(null), "SetSite(null) did not return S_OK"); + } + } +} diff --git a/VSPackageInstall/VSPackageInstall_UnitTests/VSPackageInstall_UnitTests.csproj b/VSPackageInstall/VSPackageInstall_UnitTests/VSPackageInstall_UnitTests.csproj new file mode 100644 index 0000000..76429a2 --- /dev/null +++ b/VSPackageInstall/VSPackageInstall_UnitTests/VSPackageInstall_UnitTests.csproj @@ -0,0 +1,84 @@ + + + + Debug + AnyCPU + 2.0 + {E620FC0C-6208-4216-9899-47DF43578E4C} + Library + Properties + VSPackageInstall_UnitTests + VSPackageInstall_UnitTests + v4.5 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + Key.snk + + + true + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6} + VSPackageInstall + + + + \ No newline at end of file diff --git a/VSPackageInstall/source.extension.vsixmanifest b/VSPackageInstall/source.extension.vsixmanifest new file mode 100644 index 0000000..94e6d18 --- /dev/null +++ b/VSPackageInstall/source.extension.vsixmanifest @@ -0,0 +1,18 @@ + + + + + VSPackageInstall + Visual Studio sound notifications + + + + + + + + + + + + diff --git a/VsDingExtension.sln b/VsDingExtension.sln new file mode 100644 index 0000000..8d4d4f1 --- /dev/null +++ b/VsDingExtension.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VsDingExtension", "VsDingExtension\VsDingExtension.csproj", "{54C786E5-FD14-4036-92AE-E9F25B71534B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSPackageInstall", "VSPackageInstall\VSPackageInstall.csproj", "{20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSPackageInstall_IntegrationTests", "VSPackageInstall\VSPackageInstall_IntegrationTests\VSPackageInstall_IntegrationTests.csproj", "{77A542CC-52C0-4387-B57B-63AF5F597EA1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5BD9D4DB-8683-4698-8D24-01EE7306F73A}" + ProjectSection(SolutionItems) = preProject + IntegrationTests.testsettings = IntegrationTests.testsettings + UnitTests.testsettings = UnitTests.testsettings + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSPackageInstall_UnitTests", "VSPackageInstall\VSPackageInstall_UnitTests\VSPackageInstall_UnitTests.csproj", "{E620FC0C-6208-4216-9899-47DF43578E4C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {54C786E5-FD14-4036-92AE-E9F25B71534B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54C786E5-FD14-4036-92AE-E9F25B71534B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54C786E5-FD14-4036-92AE-E9F25B71534B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54C786E5-FD14-4036-92AE-E9F25B71534B}.Release|Any CPU.Build.0 = Release|Any CPU + {20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6}.Release|Any CPU.Build.0 = Release|Any CPU + {77A542CC-52C0-4387-B57B-63AF5F597EA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77A542CC-52C0-4387-B57B-63AF5F597EA1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77A542CC-52C0-4387-B57B-63AF5F597EA1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77A542CC-52C0-4387-B57B-63AF5F597EA1}.Release|Any CPU.Build.0 = Release|Any CPU + {E620FC0C-6208-4216-9899-47DF43578E4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E620FC0C-6208-4216-9899-47DF43578E4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E620FC0C-6208-4216-9899-47DF43578E4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E620FC0C-6208-4216-9899-47DF43578E4C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal