diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Microsoft.DotNet.XHarness.iOS.Shared.csproj b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Microsoft.DotNet.XHarness.iOS.Shared.csproj index 9a15ed58e6f4..d50bb048ff0c 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Microsoft.DotNet.XHarness.iOS.Shared.csproj +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/Microsoft.DotNet.XHarness.iOS.Shared.csproj @@ -11,4 +11,7 @@ + + + diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/ProjectDefinition.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/ProjectDefinition.cs index dd3c157a44e4..7114b773477e 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/ProjectDefinition.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/ProjectDefinition.cs @@ -4,6 +4,8 @@ using System.Reflection; using System.Collections.Generic; +using Mono.Cecil; + namespace Microsoft.DotNet.XHarness.iOS.Shared.TestImporter { /// /// Class that defines a bcl test project. A bcl test project by definition is the combination of the name @@ -24,6 +26,16 @@ public bool IsXUnit { } } + Dictionary assemblies = new Dictionary (); + AssemblyDefinition LoadAssembly (string path) + { + lock (assemblies) { + if (!assemblies.TryGetValue (path, out var ad)) + assemblies [path] = ad = AssemblyDefinition.ReadAssembly (path, new ReaderParameters (ReadingMode.Deferred)); + return ad; + } + } + public ProjectDefinition (string name, IAssemblyLocator locator, ITestAssemblyDefinitionFactory factory, string [] assemblies, string extraArgs) { if (assemblies.Length == 0) @@ -51,12 +63,12 @@ public ProjectDefinition (string name, IAssemblyLocator locator, ITestAssemblyDe ExtraArgs = extraArgs; } - static (string FailureMessage, IEnumerable References) GetAssemblyReferences (string assemblyPath) + (string FailureMessage, IEnumerable References) GetAssemblyReferences (string assemblyPath) { if (!File.Exists (assemblyPath)) return ($"The file {assemblyPath} does not exist.", null); - var a = Assembly.LoadFile (assemblyPath); - return (null, a.GetReferencedAssemblies ().Select ((arg) => arg.Name)); + var ad = LoadAssembly (assemblyPath); + return (null, ad.MainModule.AssemblyReferences.Select ((arg) => arg.Name)); } /// @@ -97,32 +109,35 @@ public bool Validate () return (failureMessage, set); } - public (string FailureMessage, Dictionary Types) GetTypeForAssemblies (string monoRootPath, Platform platform) + public (string FailureMessage, Dictionary Types) GetTypeForAssemblies (string monoRootPath, Platform platform) { if (monoRootPath == null) throw new ArgumentNullException (nameof (monoRootPath)); - var dict = new Dictionary (); + var dict = new Dictionary (); // loop over the paths, grab the assembly, find a type and then add it foreach (var definition in TestAssemblies) { var path = definition.GetPath (platform); if (!File.Exists (path)) return ($"The assembly {path} does not exist. Please make sure it exists, then re-generate the project files by executing 'git clean -xfd && make' in the tests/ directory.", null); - var a = Assembly.LoadFile (path); - try { - var types = a.ExportedTypes; - if (!types.Any ()) { - continue; - } - dict [Path.GetFileName (path)] = types.First (t => !t.IsGenericType && (t.FullName.EndsWith ("Test") || t.FullName.EndsWith ("Tests")) && t.Namespace != null); - } catch (ReflectionTypeLoadException e) { // ReflectionTypeLoadException - // we did get an exception, possible reason, the type comes from an assebly not loaded, but - // nevertheless we can do something about it, get all the not null types in the exception - // and use one of them - var types = e.Types.Where (t => t != null).Where (t => !t.IsGenericType && (t.FullName.EndsWith ("Test") || t.FullName.EndsWith ("Tests")) && t.Namespace != null); - if (types.Any ()) { - dict [Path.GetFileName (path)] = types.First (); - } - } + var ad = LoadAssembly (path); + var accessibleType = ad.MainModule.Types.FirstOrDefault ((t) => { + if (!t.IsPublic) + return false; + + if (t.HasGenericParameters) + return false; + + if (t.Namespace == null) + return false; + + if (!t.FullName.EndsWith ("Test", StringComparison.OrdinalIgnoreCase) && !t.FullName.EndsWith ("Tests", StringComparison.OrdinalIgnoreCase)) + return false; + + return true; + }); + if (accessibleType == null) + continue; + dict [Path.GetFileName (path)] = accessibleType; } return (null, dict); } diff --git a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/Templates/Managed/RegisterTypeGenerator.cs b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/Templates/Managed/RegisterTypeGenerator.cs index cffe420d0ff7..ab315fd5950c 100644 --- a/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/Templates/Managed/RegisterTypeGenerator.cs +++ b/tests/xharness/Microsoft.DotNet.XHarness.iOS.Shared/TestImporter/Templates/Managed/RegisterTypeGenerator.cs @@ -4,6 +4,8 @@ using System.Threading.Tasks; using System.Collections.Generic; +using Mono.Cecil; + namespace Microsoft.DotNet.XHarness.iOS.Shared.TestImporter.Templates.Managed { public static class RegisterTypeGenerator { @@ -11,7 +13,7 @@ public static class RegisterTypeGenerator { static readonly string KeysReplacement = "%KEY VALUES%"; static readonly string IsxUnitReplacement = "%IS XUNIT%"; - public static async Task GenerateCodeAsync ((string FailureMessage, Dictionary Types) typeRegistration, bool isXunit, + public static async Task GenerateCodeAsync ((string FailureMessage, Dictionary Types) typeRegistration, bool isXunit, Stream template) { var importStringBuilder = new StringBuilder ();