Skip to content

Commit

Permalink
Merge pull request #454 from nunit/jnm2/replace_cecil
Browse files Browse the repository at this point in the history
Replaced Mono.Cecil
  • Loading branch information
OsirisTerje authored Feb 20, 2018
2 parents 323b598 + b4703ae commit 2f4079d
Show file tree
Hide file tree
Showing 22 changed files with 517 additions and 323 deletions.
15 changes: 9 additions & 6 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ foreach (var (framework, vstestFramework, adapterDir) in new[] {
VSTest(GetTestAssemblyPath(framework), settings);
});

// Workaround for https://github.com/nunit/nunit3-vs-adapter/issues/47
// (presence of a filter causes explicit tests to start running)
const string NoNavigationTests = "TestCategory!=Navigation&TestCategory!=LongRunning";

Task($"DotnetTest-{framework}")
.IsDependentOn("Build")
.Does(() =>
Expand All @@ -188,7 +192,8 @@ foreach (var (framework, vstestFramework, adapterDir) in new[] {
Framework = framework,
NoBuild = true,
TestAdapterPath = adapterDir,
Settings = File("DisableAppDomain.runsettings")
Settings = File("DisableAppDomain.runsettings"),
Filter = framework == "net45" ? NoNavigationTests : null
});
});

Expand All @@ -200,7 +205,8 @@ foreach (var (framework, vstestFramework, adapterDir) in new[] {
{
TestAdapterPath = adapterDir,
Framework = vstestFramework,
Settings = File("DisableAppDomain.runsettings")
Settings = File("DisableAppDomain.runsettings"),
TestCaseFilter = framework == "net45" ? NoNavigationTests : null
});
});
}
Expand Down Expand Up @@ -230,10 +236,7 @@ Task("CreateWorkingImage")
ADAPTER_BIN_DIR_NET35 + "NUnit3.TestAdapter.dll",
ADAPTER_BIN_DIR_NET35 + "nunit.engine.dll",
ADAPTER_BIN_DIR_NET35 + "nunit.engine.api.dll",
ADAPTER_BIN_DIR_NET35 + "Mono.Cecil.dll",
ADAPTER_BIN_DIR_NET35 + "Mono.Cecil.Pdb.dll",
ADAPTER_BIN_DIR_NET35 + "Mono.Cecil.Mdb.dll",
ADAPTER_BIN_DIR_NET35 + "Mono.Cecil.Rocks.dll"
ADAPTER_BIN_DIR_NET35 + "Mono.Cecil.dll"
};

var net35Dir = PACKAGE_IMAGE_DIR + "build/net35";
Expand Down
3 changes: 0 additions & 3 deletions nuget/NUnit3TestAdapter.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@ The package works with Visual Studio 2012 and newer.</description>
<file src="build\net35\nunit.engine.dll" target="build\net35\nunit.engine.dll" />
<file src="build\net35\nunit.engine.api.dll" target="build\net35\nunit.engine.api.dll" />
<file src="build\net35\Mono.Cecil.dll" target="build\net35\Mono.Cecil.dll" />
<file src="build\net35\Mono.Cecil.Pdb.dll" target="build\net35\Mono.Cecil.Pdb.dll" />
<file src="build\net35\Mono.Cecil.Mdb.dll" target="build\net35\Mono.Cecil.Mdb.dll" />
<file src="build\net35\Mono.Cecil.Rocks.dll" target="build\net35\Mono.Cecil.Rocks.dll" />
<file src="build\net35\NUnit3TestAdapter.props" target="build\net35\NUnit3TestAdapter.props" />

<file src="build\netcoreapp1.0\NUnit3.TestAdapter.dll" target="build\netcoreapp1.0\NUnit3.TestAdapter.dll" />
Expand Down
15 changes: 0 additions & 15 deletions nuget/net35/NUnit3TestAdapter.props
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,5 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Mono.Cecil.Pdb.dll">
<Link>Mono.Cecil.Pdb.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Mono.Cecil.Mdb.dll">
<Link>Mono.Cecil.Mdb.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Mono.Cecil.Rocks.dll">
<Link>Mono.Cecil.Rocks.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<AssemblyName>NUnit.VisualStudio.TestAdapter.ExternalTests</AssemblyName>
<RootNamespace>NUnit.VisualStudio.TestAdapter.Tests</RootNamespace>
<TargetFrameworks>net45;netstandard1.6</TargetFrameworks>
<DebugType Condition="'$(TargetFramework)' != '' AND '$(TargetFramework)' != 'netstandard1.6'">Full</DebugType>
</PropertyGroup>

<ItemGroup>
Expand Down
3 changes: 0 additions & 3 deletions src/NUnit3TestAdapterInstall/NUnit3TestAdapterInstall.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@
</PropertyGroup>
<ItemGroup>
<VsixSourceItem Include="$(VsixInputFileLocation)\Mono.Cecil.dll" />
<VsixSourceItem Include="$(VsixInputFileLocation)\Mono.Cecil.Mdb.dll" />
<VsixSourceItem Include="$(VsixInputFileLocation)\Mono.Cecil.Pdb.dll" />
<VsixSourceItem Include="$(VsixInputFileLocation)\Mono.Cecil.Rocks.dll" />
<VsixSourceItem Include="$(VsixInputFileLocation)\nunit.engine.api.dll" />
<VsixSourceItem Include="$(VsixInputFileLocation)\nunit.engine.dll" />
<VsixSourceItem Include="$(VsixInputFileLocation)\NUnit3.TestAdapter.dll" />
Expand Down
112 changes: 112 additions & 0 deletions src/NUnitTestAdapter/Metadata/DirectReflectionMetadataProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// ***********************************************************************
// Copyright (c) 2018 Charlie Poole, Terje Sandstrom
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using NUnit.VisualStudio.TestAdapter.Internal;

#if NETCOREAPP1_0
using System.Runtime.Loader;
#endif

namespace NUnit.VisualStudio.TestAdapter.Metadata
{
internal sealed class DirectReflectionMetadataProvider : IMetadataProvider
{
public TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName)
{
var type = TryGetSingleMethod(assemblyPath, reflectedTypeName, methodName)?.DeclaringType;
if (type == null) return null;

#if NET35
if (type.IsGenericType)
#else
if (type.IsConstructedGenericType)
#endif
{
type = type.GetGenericTypeDefinition();
}

return new TypeInfo(type);
}

public TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName)
{
var method = TryGetSingleMethod(assemblyPath, reflectedTypeName, methodName);
if (method == null) return null;

var candidate = (Type)null;

foreach (var attributeData in CustomAttributeData.GetCustomAttributes(method))
{
for (var current = attributeData.Constructor.DeclaringType; current != null; current = current.GetTypeInfo().BaseType)
{
if (current.FullName != "System.Runtime.CompilerServices.StateMachineAttribute") continue;

var parameters = attributeData.Constructor.GetParameters();
for (var i = 0; i < parameters.Length; i++)
{
if (parameters[i].Name != "stateMachineType") continue;
var argument = attributeData.ConstructorArguments[i].Value as Type;
if (argument != null)
{
if (candidate != null) return null;
candidate = argument;
}
}
}
}

if (candidate == null) return null;
return new TypeInfo(candidate);
}

private static MethodInfo TryGetSingleMethod(string assemblyPath, string reflectedTypeName, string methodName)
{
try
{
#if NETCOREAPP1_0
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
#else
var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
#endif

var type = assembly.GetType(reflectedTypeName, throwOnError: false);
if (type == null) return null;

var methods = type.GetMethods().Where(m => m.Name == methodName).Take(2).ToList();
return methods.Count == 1 ? methods[0] : null;
}
catch (FileNotFoundException)
{
return null;
}
}

void IDisposable.Dispose()
{
}
}
}
33 changes: 33 additions & 0 deletions src/NUnitTestAdapter/Metadata/IMetadataProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// ***********************************************************************
// Copyright (c) 2018 Charlie Poole, Terje Sandstrom
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************

using System;

namespace NUnit.VisualStudio.TestAdapter.Metadata
{
internal interface IMetadataProvider : IDisposable
{
TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName);
TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// ***********************************************************************
// Copyright (c) 2018 Charlie Poole, Terje Sandstrom
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************

#if !NETCOREAPP1_0
using System;
using System.IO;
using System.Reflection;

namespace NUnit.VisualStudio.TestAdapter.Metadata
{
internal sealed partial class ReflectionAppDomainMetadataProvider : IMetadataProvider
{
private AppDomain _appDomain;
private AppDomainHelper _helper;

private AppDomainHelper GetHelper()
{
if (_helper == null)
{
var adapterAssembly = typeof(ReflectionAppDomainMetadataProvider).Assembly;
var adapterAssemblyPath = adapterAssembly.ManifestModule.FullyQualifiedName;

_appDomain = AppDomain.CreateDomain(
friendlyName: typeof(ReflectionAppDomainMetadataProvider).FullName,
securityInfo: null,
info: new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(adapterAssemblyPath) });

_appDomain.ReflectionOnlyAssemblyResolve += AppDomainReflectionOnlyAssemblyResolve;

_helper = (AppDomainHelper)_appDomain.CreateInstanceAndUnwrap(adapterAssembly.FullName, typeof(AppDomainHelper).FullName);
}

return _helper;
}

private static Assembly AppDomainReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
{
return Assembly.ReflectionOnlyLoad(args.Name);
}

public void Dispose()
{
if (_appDomain != null)
AppDomain.Unload(_appDomain);
}

public TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName)
{
return GetHelper().GetDeclaringType(assemblyPath, reflectedTypeName, methodName);
}

public TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName)
{
return GetHelper().GetStateMachineType(assemblyPath, reflectedTypeName, methodName);
}

private sealed class AppDomainHelper : MarshalByRefObject
{
private readonly DirectReflectionMetadataProvider provider = new DirectReflectionMetadataProvider();

public TypeInfo? GetDeclaringType(string assemblyPath, string reflectedTypeName, string methodName)
{
return provider.GetDeclaringType(assemblyPath, reflectedTypeName, methodName);
}

public TypeInfo? GetStateMachineType(string assemblyPath, string reflectedTypeName, string methodName)
{
return provider.GetStateMachineType(assemblyPath, reflectedTypeName, methodName);
}
}
}
}
#endif
50 changes: 50 additions & 0 deletions src/NUnitTestAdapter/Metadata/TypeInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// ***********************************************************************
// Copyright (c) 2018 Charlie Poole, Terje Sandstrom
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************

using System;
using System.Reflection;
using NUnit.VisualStudio.TestAdapter.Internal;

namespace NUnit.VisualStudio.TestAdapter.Metadata
{
#if !NETCOREAPP1_0
[Serializable]
#endif
public struct TypeInfo
{
public TypeInfo(Type type)
{
AssemblyPath = type.GetTypeInfo().Assembly.Location;
FullName = type.FullName;
}

public TypeInfo(string assemblyPath, string fullName)
{
AssemblyPath = assemblyPath;
FullName = fullName;
}

public string AssemblyPath { get; }
public string FullName { get; }
}
}
Loading

0 comments on commit 2f4079d

Please sign in to comment.