This commit is contained in:
vitaliiy@outlook.com 2014-03-12 20:32:09 -07:00
parent 8b61ca41fa
commit 17883e16e1
41 changed files with 3173 additions and 0 deletions

View file

@ -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;
/// <summary>
/// This class is responsible to close dialog boxes that pop up during different VS Calls
/// </summary>
internal class DialogBoxPurger : IDisposable
{
/// <summary>
/// The default number of milliseconds to wait for the threads to signal to terminate.
/// </summary>
private const int DefaultMillisecondsToWait = 3500;
/// <summary>
/// Object used for synchronization between thread calls.
/// </summary>
internal static volatile object Mutex = new object();
/// <summary>
/// The IVsUIShell. This cannot be queried on the working thread from the service provider. Must be done in the main thread.!!
/// </summary>
private IVsUIShell uiShell;
/// <summary>
/// The button to "press" on the dialog.
/// </summary>
private int buttonAction;
/// <summary>
/// Thread signales to the calling thread that it is done.
/// </summary>
private bool exitThread = false;
/// <summary>
/// Calling thread signales to this thread to die.
/// </summary>
private AutoResetEvent threadDone = new AutoResetEvent(false);
/// <summary>
/// The queued thread started.
/// </summary>
private AutoResetEvent threadStarted = new AutoResetEvent(false);
/// <summary>
/// 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.
/// </summary>
private bool dialogBoxCloseResult = false;
/// <summary>
/// The expected text to see on the dialog box. If set the thread will continue finding the dialog box with this text.
/// </summary>
private string expectedDialogBoxText = String.Empty;
/// <summary>
/// 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.
/// </summary>
private int numberOfDialogsToWaitFor = 1;
/// <summary>
/// Has the object been disposed.
/// </summary>
private bool isDisposed;
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="numberOfDialogsToWaitFor">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</param>
/// <param name="expectedDialogMesssage">The expected dialog box message to check for.</param>
internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor, string expectedDialogMesssage)
{
this.buttonAction = buttonAction;
this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
this.expectedDialogBoxText = expectedDialogMesssage;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="numberOfDialogsToWaitFor">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</param>
internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor)
{
this.buttonAction = buttonAction;
this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="expectedDialogMesssage">The expected dialog box message to check for.</param>
internal DialogBoxPurger(int buttonAction, string expectedDialogMesssage)
{
this.buttonAction = buttonAction;
this.expectedDialogBoxText = expectedDialogMesssage;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
internal DialogBoxPurger(int buttonAction)
{
this.buttonAction = buttonAction;
}
/// <summary>
#region IDisposable Members
void IDisposable.Dispose()
{
if (this.isDisposed)
{
return;
}
this.WaitForDialogThreadToTerminate();
this.isDisposed = true;
}
/// <summary>
/// Spawns a thread that will start listening to dialog boxes.
/// </summary>
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);
}
/// <summary>
/// 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.
/// </summary>
internal bool WaitForDialogThreadToTerminate()
{
return this.WaitForDialogThreadToTerminate(DefaultMillisecondsToWait);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="millisecondsToWait">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. </param>
/// <returns>The result of the dialog boxes closing</returns>
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;
}
/// <summary>
/// This is the thread method.
/// </summary>
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();
}
}
}
/// <summary>
/// Finds a messagebox string on a messagebox.
/// </summary>
/// <param name="hwnd">The windows handle of the dialog</param>
/// <param name="unmanagedMemoryLocation">A pointer to the memorylocation the string will be written to</param>
/// <returns>True if found.</returns>
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
}
}

View file

@ -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;
/// <summary>
/// Defines pinvoked utility methods and internal VS Constants
/// </summary>
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);
}
/// <devdoc>
/// Please use this "approved" method to compare file names.
/// </devdoc>
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;
}
}
}

View file

@ -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
{
/// <summary>
/// </summary>
public class TestUtils
{
#region Methods: Handling embedded resources
/// <summary>
/// Gets the embedded file identified by the resource name, and converts the
/// file into a string.
/// </summary>
/// <param name="resourceName">In VS, is DefaultNamespace.FileName?</param>
/// <returns></returns>
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;
}
/// <summary>
///
/// </summary>
/// <param name="embeddedResourceName"></param>
/// <param name="baseFileName"></param>
/// <param name="fileExtension"></param>
/// <returns></returns>
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();
}
/// <summary>
/// Writes an embedded resource to a file.
/// </summary>
/// <param name="assembly">The name of the assembly that the embedded resource is defined.</param>
/// <param name="embeddedResourceName">The name of the embedded resource.</param>
/// <param name="fileName">The file to write the embedded resource's content.</param>
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
/// <summary>
/// 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.
/// </summary>
/// <param name="directory">Directory that the file should live in.</param>
/// <param name="baseFileName"></param>
/// <param name="extension">may be null, in which case the .[extension] part
/// is not added.</param>
/// <returns>Full file name.</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="directory">Directory that the file should live in.</param>
/// <param name="baseDirectoryName"></param>
/// <returns>Full directory name.</returns>
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;
}
/// <summary>
///
/// </summary>
/// <param name="directory"></param>
/// <param name="baseFileName"></param>
/// <param name="extension"></param>
/// <returns></returns>
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
/// <summary>
/// Closes the currently open solution (if any), and creates a new solution with the given name.
/// </summary>
/// <param name="solutionName">Name of new solution.</param>
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);
}
/// <summary>
/// Get current number of open project in solution
/// </summary>
/// <returns></returns>
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
/// <summary>
/// Creates a project.
/// </summary>
/// <param name="projectName">Name of new project.</param>
/// <param name="templateName">Name of project template to use</param>
/// <param name="language">language</param>
/// <returns>New project.</returns>
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
/// <summary>
/// Create a new item in the project
/// </summary>
/// <param name="parent">the parent collection for the new item</param>
/// <param name="templateName"></param>
/// <param name="language"></param>
/// <param name="name"></param>
/// <returns></returns>
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);
}
/// <summary>
/// Save an open document.
/// </summary>
/// <param name="documentMoniker">for filebased documents this is the full path to the document</param>
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
/// <summary>
/// Executes a Command (menu item) in the given context
/// </summary>
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);
}
}
}

View file

@ -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;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
/// <summary>
///A test for lauching the command and closing the associated dialogbox
///</summary>
[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");
}
});
}
}
}

View file

@ -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
{
/// <summary>
/// Integration test for package validation
/// </summary>
[TestClass]
public class PackageTest
{
private delegate void ThreadInvoker();
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
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");
});
}
}
}

View file

@ -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
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
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<int>(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<int>(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);
});
}
}
}

View file

@ -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
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
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<int>(0, testUtils.ProjectCount());
//Create Winforms application project
//TestUtils.CreateProjectFromTemplate("MyWindowsApp", "Windows Application", "CSharp", false);
//Assert.AreEqual<int>(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
});
}
}
}

View file

@ -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
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
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");
});
}
}
}

View file

@ -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
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
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<int>(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<int>(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");
});
}
}
}

View file

@ -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;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
/// <summary>
///A test for showing the toolwindow
///</summary>
[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)));
});
}
}
}

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{77A542CC-52C0-4387-B57B-63AF5F597EA1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VSPackageInstall_IntegrationTests</RootNamespace>
<AssemblyName>VSPackageInstall_IntegrationTests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<ItemGroup>
<Reference Include="envdte" />
<Reference Include="envdte80" />
<Reference Include="Microsoft.VisualStudio.OLE.Interop" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.10.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.11.0">
<EmbedInteropTypes>true</EmbedInteropTypes>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.12.0" />
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="Microsoft.VSSDK.TestHostFramework" />
</ItemGroup>
<ItemGroup>
<!--<Compile Include="Properties\AssemblyInfo.cs" />-->
<!---->
<Compile Include="MenuItemTest.cs" />
<!---->
<!---->
<Compile Include="ToolWindowTest.cs" />
<!---->
<!---->
<Compile Include="PackageTest.cs" />
<Compile Include="IntegrationTest Library\DialogboxPurger.cs" />
<Compile Include="IntegrationTest Library\NativeMethods.cs" />
<Compile Include="IntegrationTest Library\Utils.cs" />
<Compile Include="SignOff-Tests\CPPProjectTests.cs" />
<Compile Include="SignOff-Tests\CSharpProjectTests.cs" />
<Compile Include="SignOff-Tests\SolutionTests.cs" />
<Compile Include="SignOff-Tests\VBProjectTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Key.snk" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VSPackageInstall.csproj">
<Project>{20191D13-7CC1-4F9B-9CB8-42F22ACE4CA6}</Project>
<Name>VSPackageInstall</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>