-
Notifications
You must be signed in to change notification settings - Fork 269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding support for DiaNavigation in UWP test adapter #258
Changes from all commits
4618711
28ac1bf
fee3732
2fb3077
ee0e1fd
45053d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices | ||
{ | ||
using System; | ||
using System.Reflection; | ||
|
||
#pragma warning disable SA1649 // SA1649FileNameMustMatchTypeName | ||
|
||
internal static class DiaSessionOperations | ||
{ | ||
private static MethodInfo methodGetNavigationData; | ||
private static PropertyInfo propertyFileName; | ||
private static PropertyInfo propertyMinLineNumber; | ||
private static Type typeDiaSession; | ||
private static Type typeDiaNavigationData; | ||
|
||
/// <summary> | ||
/// Initializes static members of the <see cref="FileOperations"/> class. | ||
/// </summary> | ||
/// <remarks>Initializes DiaSession.</remarks> | ||
static DiaSessionOperations() | ||
{ | ||
const string diaSessionTypeName = "Microsoft.VisualStudio.TestPlatform.ObjectModel.DiaSession, Microsoft.VisualStudio.TestPlatform.ObjectModel"; | ||
const string diaNavigationDataTypeName = "Microsoft.VisualStudio.TestPlatform.ObjectModel.DiaNavigationData, Microsoft.VisualStudio.TestPlatform.ObjectModel"; | ||
|
||
Initialize(diaSessionTypeName, diaNavigationDataTypeName); | ||
} | ||
|
||
/// <summary> | ||
/// Creates a Navigation session for the source file. | ||
/// This is used to get file path and line number information for its components. | ||
/// </summary> | ||
/// <param name="source"> The source file. </param> | ||
/// <returns> A Navigation session instance for the current platform. </returns> | ||
internal static object CreateNavigationSession(string source) | ||
{ | ||
// Create instance only when DiaSession is found in Object Model. | ||
if (typeDiaSession != null && typeDiaNavigationData != null) | ||
{ | ||
var messageFormatOnException = string.Join("MSTestDiscoverer:DiaSession: Could not create diaSession for source:", source, ". Reason:{0}"); | ||
return SafeInvoke(() => Activator.CreateInstance(typeDiaSession, source), messageFormatOnException); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/// <summary> | ||
/// Get's the navigation data for a navigation session. | ||
/// </summary> | ||
/// <param name="navigationSession"> The navigation session. </param> | ||
/// <param name="className"> The class name. </param> | ||
/// <param name="methodName"> The method name. </param> | ||
/// <param name="minLineNumber"> The min line number. </param> | ||
/// <param name="fileName"> The file name. </param> | ||
internal static void GetNavigationData(object navigationSession, string className, string methodName, out int minLineNumber, out string fileName) | ||
{ | ||
// Set default values. | ||
fileName = null; | ||
minLineNumber = -1; | ||
|
||
// Get navigation data only when DiaSession is found in Object Model. | ||
if (typeDiaSession != null && typeDiaNavigationData != null) | ||
{ | ||
var messageFormatOnException = string.Join("MSTestDiscoverer:DiaSession: Could not get navigation data for class:", className, ". Reason:{0}"); | ||
var data = SafeInvoke(() => methodGetNavigationData.Invoke(navigationSession, new object[] { className, methodName }), messageFormatOnException); | ||
|
||
if (data != null) | ||
{ | ||
fileName = (string)propertyFileName?.GetValue(data); | ||
minLineNumber = (int)(propertyMinLineNumber?.GetValue(data) ?? -1); | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Dispose's the navigation session instance. | ||
/// </summary> | ||
/// <param name="navigationSession"> The navigation session. </param> | ||
internal static void DisposeNavigationSession(object navigationSession) | ||
{ | ||
var diaSession = navigationSession as IDisposable; | ||
diaSession?.Dispose(); | ||
} | ||
|
||
/// <summary> | ||
/// 1. Initializes DiaSession. | ||
/// 2. Assists in Unit Testing. | ||
/// </summary> | ||
/// <param name="diaSession">Type name of DiaSession class.</param> | ||
/// <param name="diaNavigationData">Type name of DiaNavigationData class.</param> | ||
internal static void Initialize(string diaSession, string diaNavigationData) | ||
{ | ||
typeDiaSession = Type.GetType(diaSession, false); | ||
typeDiaNavigationData = Type.GetType(diaNavigationData, false); | ||
|
||
if (typeDiaSession != null && typeDiaNavigationData != null) | ||
{ | ||
methodGetNavigationData = typeDiaSession.GetRuntimeMethod("GetNavigationData", new[] { typeof(string), typeof(string) }); | ||
propertyFileName = typeDiaNavigationData.GetRuntimeProperty("FileName"); | ||
propertyMinLineNumber = typeDiaNavigationData.GetRuntimeProperty("MinLineNumber"); | ||
} | ||
} | ||
|
||
private static object SafeInvoke<T>(Func<T> action, string messageFormatOnException = null) | ||
{ | ||
try | ||
{ | ||
return action.Invoke(); | ||
} | ||
catch (Exception) | ||
{ | ||
// todo : Add EqtTrace | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
|
||
#pragma warning restore SA1649 // SA1649FileNameMustMatchTypeName | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
// Friend assemblies | ||
using System.Runtime.CompilerServices; | ||
|
||
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.UWP.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,274 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace MSTestAdapter.PlatformServices.Tests.Services | ||
{ | ||
#if NETCOREAPP1_0 | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
#else | ||
extern alias FrameworkV1; | ||
|
||
using Assert = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.Assert; | ||
using TestClass = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute; | ||
using TestInitialize = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute; | ||
using TestMethod = FrameworkV1::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute; | ||
#endif | ||
|
||
using System; | ||
using System.IO; | ||
using System.Reflection; | ||
using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; | ||
using MSTestAdapter.TestUtilities; | ||
#pragma warning disable SA1649 // SA1649FileNameMustMatchTypeName | ||
|
||
[TestClass] | ||
public class DiaSessionOperationsTests | ||
{ | ||
private FileOperations fileOperations; | ||
|
||
public DiaSessionOperationsTests() | ||
{ | ||
this.fileOperations = new FileOperations(); | ||
} | ||
|
||
[TestMethod] | ||
public void CreateNavigationSessionShouldReurnNullIfSourceIsNull() | ||
{ | ||
try | ||
{ | ||
DiaSessionOperations.Initialize(typeof(MockDiaSession).AssemblyQualifiedName, typeof(MockDiaNavigationData).AssemblyQualifiedName); | ||
|
||
Assert.IsNull(this.fileOperations.CreateNavigationSession(null)); | ||
Assert.IsTrue(MockDiaSession.IsConstructorInvoked); | ||
} | ||
finally | ||
{ | ||
MockDiaSession.Reset(); | ||
} | ||
} | ||
|
||
[TestMethod] | ||
public void CreateNavigationSessionShuldReturnNullIfDiaSessionNotFound() | ||
{ | ||
try | ||
{ | ||
DiaSessionOperations.Initialize(string.Empty, string.Empty); | ||
|
||
Assert.IsNull(this.fileOperations.CreateNavigationSession(null)); | ||
Assert.IsFalse(MockDiaSession.IsConstructorInvoked); | ||
} | ||
finally | ||
{ | ||
MockDiaSession.Reset(); | ||
} | ||
} | ||
|
||
[TestMethod] | ||
public void CreateNavigationSessionShouldReturnDiaSession() | ||
{ | ||
try | ||
{ | ||
DiaSessionOperations.Initialize( | ||
typeof(MockDiaSession).AssemblyQualifiedName, | ||
typeof(MockDiaNavigationData).AssemblyQualifiedName); | ||
|
||
var diaSession = this.fileOperations.CreateNavigationSession(typeof(DiaSessionOperationsTests).GetTypeInfo().Assembly.Location); | ||
|
||
Assert.IsTrue(diaSession is MockDiaSession); | ||
} | ||
finally | ||
{ | ||
MockDiaSession.Reset(); | ||
} | ||
} | ||
|
||
[TestMethod] | ||
public void GetNavigationDataShouldReturnDataFromNavigationSession() | ||
{ | ||
try | ||
{ | ||
DiaSessionOperations.Initialize( | ||
typeof(MockDiaSession).AssemblyQualifiedName, | ||
typeof(MockDiaNavigationData).AssemblyQualifiedName); | ||
var navigationData = new MockDiaNavigationData() { FileName = "mock", MinLineNumber = 86 }; | ||
MockDiaSession.DiaNavigationData = navigationData; | ||
|
||
var diaSession = this.fileOperations.CreateNavigationSession(typeof(DiaSessionOperationsTests).GetTypeInfo().Assembly.Location); | ||
this.fileOperations.GetNavigationData( | ||
diaSession, | ||
typeof(DiaSessionOperationsTests).FullName, | ||
"GetNavigationDataShouldReturnDataFromNavigationSession", | ||
out int minLineNumber, | ||
out string fileName); | ||
|
||
Assert.AreEqual(navigationData.MinLineNumber, minLineNumber); | ||
Assert.AreEqual(navigationData.FileName, fileName); | ||
Assert.IsTrue(MockDiaSession.IsGetNavigationDataInvoked); | ||
} | ||
finally | ||
{ | ||
MockDiaSession.Reset(); | ||
} | ||
} | ||
|
||
[TestMethod] | ||
public void GetNavigationDataShouldNotThrowOnNullNavigationSession() | ||
{ | ||
DiaSessionOperations.Initialize(string.Empty, string.Empty); | ||
|
||
this.fileOperations.GetNavigationData( | ||
null, | ||
typeof(DiaSessionOperationsTests).FullName, | ||
"GetNavigationDataShouldReturnDataFromNavigationSession", | ||
out int minLineNumber, | ||
out string fileName); | ||
|
||
Assert.AreEqual(-1, minLineNumber); | ||
Assert.IsNull(fileName); | ||
} | ||
|
||
[TestMethod] | ||
public void GetNavigationDataShouldNotThrowOnMissingFileNameField() | ||
{ | ||
try | ||
{ | ||
DiaSessionOperations.Initialize( | ||
typeof(MockDiaSession).AssemblyQualifiedName, | ||
typeof(MockDiaNavigationData3).AssemblyQualifiedName); | ||
var navigationData = new MockDiaNavigationData3() { MinLineNumber = 86 }; | ||
MockDiaSession.DiaNavigationData = navigationData; | ||
|
||
var diaSession = this.fileOperations.CreateNavigationSession(typeof(DiaSessionOperationsTests).GetTypeInfo().Assembly.Location); | ||
this.fileOperations.GetNavigationData( | ||
diaSession, | ||
typeof(DiaSessionOperationsTests).FullName, | ||
"GetNavigationDataShouldReturnDataFromNavigationSession", | ||
out int minLineNumber, | ||
out string fileName); | ||
|
||
Assert.AreEqual(86, minLineNumber); | ||
Assert.IsNull(fileName); | ||
} | ||
finally | ||
{ | ||
MockDiaSession.Reset(); | ||
} | ||
} | ||
|
||
[TestMethod] | ||
public void GetNavigationDataShouldNotThrowOnMissingLineNumberField() | ||
{ | ||
try | ||
{ | ||
DiaSessionOperations.Initialize( | ||
typeof(MockDiaSession).AssemblyQualifiedName, | ||
typeof(MockDiaNavigationData2).AssemblyQualifiedName); | ||
var navigationData = new MockDiaNavigationData2() { FileName = "mock" }; | ||
MockDiaSession.DiaNavigationData = navigationData; | ||
|
||
var diaSession = this.fileOperations.CreateNavigationSession(typeof(DiaSessionOperationsTests).GetTypeInfo().Assembly.Location); | ||
this.fileOperations.GetNavigationData( | ||
diaSession, | ||
typeof(DiaSessionOperationsTests).FullName, | ||
"GetNavigationDataShouldReturnDataFromNavigationSession", | ||
out int minLineNumber, | ||
out string fileName); | ||
|
||
Assert.AreEqual(-1, minLineNumber); | ||
Assert.AreEqual(navigationData.FileName, fileName); | ||
} | ||
finally | ||
{ | ||
MockDiaSession.Reset(); | ||
} | ||
} | ||
|
||
[TestMethod] | ||
public void DisposeNavigationSessionShouldDisposeDiaSession() | ||
{ | ||
try | ||
{ | ||
DiaSessionOperations.Initialize( | ||
typeof(MockDiaSession).AssemblyQualifiedName, | ||
typeof(MockDiaNavigationData).AssemblyQualifiedName); | ||
|
||
var diaSession = this.fileOperations.CreateNavigationSession(typeof(DiaSessionOperationsTests).GetTypeInfo().Assembly.Location); | ||
this.fileOperations.DisposeNavigationSession(diaSession); | ||
|
||
Assert.IsTrue(MockDiaSession.IsDisposeInvoked); | ||
} | ||
finally | ||
{ | ||
MockDiaSession.Reset(); | ||
} | ||
} | ||
} | ||
|
||
public class MockDiaSession : IDisposable | ||
{ | ||
static MockDiaSession() | ||
{ | ||
IsConstructorInvoked = false; | ||
IsGetNavigationDataInvoked = false; | ||
IsDisposeInvoked = false; | ||
} | ||
|
||
public MockDiaSession(string source) | ||
{ | ||
IsConstructorInvoked = true; | ||
if (string.IsNullOrEmpty(source)) | ||
{ | ||
throw new Exception(); | ||
} | ||
} | ||
|
||
public static bool IsConstructorInvoked { get; set; } | ||
|
||
public static IDiaNavigationData DiaNavigationData { get; set; } | ||
|
||
public static bool IsGetNavigationDataInvoked { get; set; } | ||
|
||
public static bool IsDisposeInvoked { get; set; } | ||
|
||
public static void Reset() | ||
{ | ||
IsConstructorInvoked = false; | ||
IsGetNavigationDataInvoked = false; | ||
} | ||
|
||
public object GetNavigationData(string className, string methodName) | ||
{ | ||
IsGetNavigationDataInvoked = true; | ||
return DiaNavigationData; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
IsDisposeInvoked = true; | ||
} | ||
} | ||
|
||
public interface IDiaNavigationData | ||
{ | ||
} | ||
|
||
public class MockDiaNavigationData : IDiaNavigationData | ||
{ | ||
public string FileName { get; set; } | ||
|
||
public int MinLineNumber { get; set; } | ||
} | ||
|
||
public class MockDiaNavigationData2 : IDiaNavigationData | ||
{ | ||
public string FileName { get; set; } | ||
} | ||
|
||
public class MockDiaNavigationData3 : IDiaNavigationData | ||
{ | ||
public int MinLineNumber { get; set; } | ||
} | ||
|
||
#pragma warning restore SA1649 // SA1649FileNameMustMatchTypeName | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,57 @@ public void GetNavigationDataShouldReturnNullFileName() | |
Assert.AreEqual(-1, minLineNumber); | ||
} | ||
|
||
// Enable these tests when we take dependency on TpV2 object model | ||
// In Tpv1 UWP Object model these below methods are not defined. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would we ever do this given that we want to support UWP in 14.0? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If not, how do we run these tests? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we would move to Tpv2 object model, once we have made it default. Right now I do not want to go into problem of acquiring it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm.. This is a debt we are carrying forward. Please file a bug to track this. |
||
/* | ||
[TestMethod] | ||
public void CreateNavigationSessionShouldReturnDiaSession() | ||
{ | ||
var diaSession = this.fileOperations.CreateNavigationSession(Assembly.GetExecutingAssembly().Location); | ||
Assert.IsNotNull(diaSession); | ||
} | ||
[TestMethod] | ||
public void GetNavigationDataShouldReturnDataFromNavigationSession() | ||
{ | ||
var diaSession = this.fileOperations.CreateNavigationSession(Assembly.GetExecutingAssembly().Location); | ||
int minLineNumber; | ||
string fileName; | ||
this.fileOperations.GetNavigationData( | ||
diaSession, | ||
typeof(UniversalFileOperationsTests).FullName, | ||
"GetNavigationDataShouldReturnDataFromNavigationSession", | ||
out minLineNumber, | ||
out fileName); | ||
Assert.AreNotEqual(-1, minLineNumber); | ||
Assert.IsNotNull(fileName); | ||
} | ||
[TestMethod] | ||
public void GetNavigationDataShouldNotThrowOnNullNavigationSession() | ||
{ | ||
int minLineNumber; | ||
string fileName; | ||
this.fileOperations.GetNavigationData( | ||
null, | ||
typeof(UniversalFileOperationsTests).FullName, | ||
"GetNavigationDataShouldNotThrowOnNullNavigationSession", | ||
out minLineNumber, | ||
out fileName); | ||
Assert.AreEqual(-1, minLineNumber); | ||
Assert.IsNull(fileName); | ||
} | ||
[TestMethod] | ||
public void DisposeNavigationSessionShouldNotThrowOnNullNavigationSession() | ||
{ | ||
// This should not throw. | ||
this.fileOperations.DisposeNavigationSession(null); | ||
} | ||
*/ | ||
|
||
/// <summary> | ||
/// The get full file path should return assembly file name. | ||
/// </summary> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for getting these enabled. Can we close this issue now: #261