diff --git a/TestPlatform.sln b/TestPlatform.sln index cd278af64a..b53343e569 100644 --- a/TestPlatform.sln +++ b/TestPlatform.sln @@ -159,6 +159,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.Exte EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.collector", "test\coverlet.collector\coverlet.collector.csproj", "{074F5BD6-DC05-460B-B78F-044D125FD787}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests", "test\Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests\Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests.csproj", "{DCD0C39E-C78C-4A44-B0BD-7325254A2E97}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -781,6 +783,18 @@ Global {074F5BD6-DC05-460B-B78F-044D125FD787}.Release|x64.Build.0 = Release|Any CPU {074F5BD6-DC05-460B-B78F-044D125FD787}.Release|x86.ActiveCfg = Release|Any CPU {074F5BD6-DC05-460B-B78F-044D125FD787}.Release|x86.Build.0 = Release|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Debug|x64.ActiveCfg = Debug|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Debug|x64.Build.0 = Debug|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Debug|x86.ActiveCfg = Debug|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Debug|x86.Build.0 = Debug|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|Any CPU.Build.0 = Release|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|x64.ActiveCfg = Release|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|x64.Build.0 = Release|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|x86.ActiveCfg = Release|Any CPU + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -849,6 +863,7 @@ Global {236A71E3-01DA-4679-9DFF-16A8E079ACFF} = {5E7F18A8-F843-4C8A-AB02-4C7D9205C6CF} {41248B96-6E15-4E5E-A78F-859897676814} = {020E15EA-731F-4667-95AF-226671E0C3AE} {074F5BD6-DC05-460B-B78F-044D125FD787} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} + {DCD0C39E-C78C-4A44-B0BD-7325254A2E97} = {B27FAFDF-2DBA-4AB0-BA85-FD5F21D359D6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {0541B30C-FF51-4E28-B172-83F5F3934BCD} diff --git a/eng/Versions.props b/eng/Versions.props index 2091e6983a..2db97894ff 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -75,5 +75,11 @@ 1.0.0-beta2-19554-01 1.0.0-beta.20509.7 1.0.0-beta.20055.1 + + + + 3.8.0-3.20427.2 diff --git a/scripts/build.ps1 b/scripts/build.ps1 index 7fc073d38c..9ae18a49c5 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -119,7 +119,7 @@ $language = @("cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-BR", "ru", "tr # Capture error state in any step globally to modify return code $Script:ScriptFailed = $false -Import-Module "$($CurrentScriptDir.FullName)\verify-nupkgs.ps1" +Import-Module -Name "$($CurrentScriptDir.FullName)\verify-nupkgs.ps1" -Scope Local # Update the version in the dependencies props to be the TPB_version version, this is not ideal but because changing how this is resolved would # mean that we need to change the whole build process this is a solution with the least amount of impact, that does not require us to keep track of @@ -253,7 +253,6 @@ function Invoke-TestAssetsBuild Write-Log "Invoke-TestAssetsBuild: Start test assets build." $dotnetExe = Get-DotNetPath - Write-Log ".. .. Build: Source: $TPB_TestAssets_Solution" Write-Verbose "$dotnetExe build $TPB_TestAssets_Solution --configuration $TPB_Configuration -v:minimal -p:Version=$TPB_Version -p:CIBuild=$TPB_CIBuild" & $dotnetExe build $TPB_TestAssets_Solution --configuration $TPB_Configuration -v:minimal -p:CIBuild=$TPB_CIBuild -p:LocalizedBuild=$TPB_LocalizedBuild -bl:"$($env:TP_ROOT_DIR)\TestAssets.binlog" diff --git a/scripts/verify-nupkgs.ps1 b/scripts/verify-nupkgs.ps1 index 3e34a790a0..0b3878e422 100644 --- a/scripts/verify-nupkgs.ps1 +++ b/scripts/verify-nupkgs.ps1 @@ -8,7 +8,6 @@ function Unzip [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath) } - function Verify-Nuget-Packages($packageDirectory) { Write-Log "Starting Verify-Nuget-Packages." @@ -59,4 +58,4 @@ function Verify-Nuget-Packages($packageDirectory) } Write-Log "Completed Verify-Nuget-Packages." -} +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.MethodBase.cs b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.MethodBase.cs new file mode 100644 index 0000000000..5e20bad1bd --- /dev/null +++ b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.MethodBase.cs @@ -0,0 +1,56 @@ +// 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.PlatformAbstractions.Extensions +{ + using System; + using System.Reflection; + + public static partial class ReflectionExtensions + { +#if NETSTANDARD1_0 || NETSTANDARD1_3 || WINDOWS_UWP + private static readonly Type methodBase = typeof(MethodBase); + + private const string MemberTypePropertyName = "MemberType"; + private const string ReflectedTypePropertyName = "ReflectedType"; + private const string MethodHandlePropertyName = "MethodHandle"; + + private static readonly PropertyInfo memberTypeProperty = methodBase.GetRuntimeProperty(MemberTypePropertyName); + private static readonly PropertyInfo reflectedTypeProperty = methodBase.GetRuntimeProperty(ReflectedTypePropertyName); + private static readonly PropertyInfo methodHandleProperty = methodBase.GetRuntimeProperty(MethodHandlePropertyName); +#endif + + public static bool IsMethod(this MethodBase method) + { +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + return method.MemberType == MemberTypes.Method; +#else + AssertSupport(memberTypeProperty, MemberTypePropertyName, methodBase.FullName); + + return (int)memberTypeProperty.GetValue(method) == 8; +#endif + } + + public static Type GetReflectedType(this MethodBase method) + { +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + return method.ReflectedType; +#else + AssertSupport(memberTypeProperty, ReflectedTypePropertyName, methodBase.FullName); + + return reflectedTypeProperty.GetValue(method) as Type; +#endif + } + + public static RuntimeMethodHandle GetMethodHandle(this MethodBase method) + { +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + return method.MethodHandle; +#else + AssertSupport(memberTypeProperty, MethodHandlePropertyName, methodBase.FullName); + + return (RuntimeMethodHandle)methodHandleProperty.GetValue(method); +#endif + } + } +} diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.Type.cs b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.Type.cs new file mode 100644 index 0000000000..65670afd06 --- /dev/null +++ b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.Type.cs @@ -0,0 +1,29 @@ +// 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.PlatformAbstractions.Extensions +{ + using System; + using System.Reflection; + + public static partial class ReflectionExtensions + { + public static bool IsGenericType(this Type type) + { +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + return type.IsGenericType; +#else + return type.GetTypeInfo().IsGenericType; +#endif + } + + public static MethodBase GetDeclaringMethod(this Type type) + { +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + return type.DeclaringMethod; +#else + return type.GetTypeInfo().DeclaringMethod; +#endif + } + } +} diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.cs b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.cs new file mode 100644 index 0000000000..010567f0eb --- /dev/null +++ b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/ReflectionExtensions.cs @@ -0,0 +1,21 @@ +// 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.PlatformAbstractions.Extensions +{ + using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Resources; + + using System; + + public static partial class ReflectionExtensions + { + private static void AssertSupport(T obj, string methodName, string className) + where T : class + { + if (obj == null) + { + throw new NotImplementedException(string.Format(Resources.MethodNotImplementedOnPlatform, className, methodName)); + } + } + } +} diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Utilities/StringBuilderExtensions.cs b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/StringBuilderExtensions.cs similarity index 100% rename from src/Microsoft.TestPlatform.CoreUtilities/Utilities/StringBuilderExtensions.cs rename to src/Microsoft.TestPlatform.CoreUtilities/Extensions/StringBuilderExtensions.cs diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Utilities/StringExtensions.cs b/src/Microsoft.TestPlatform.CoreUtilities/Extensions/StringExtensions.cs similarity index 100% rename from src/Microsoft.TestPlatform.CoreUtilities/Utilities/StringExtensions.cs rename to src/Microsoft.TestPlatform.CoreUtilities/Extensions/StringExtensions.cs diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.Designer.cs b/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.Designer.cs index 6a615e84d7..2f96768586 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.Designer.cs +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.Designer.cs @@ -206,5 +206,16 @@ internal static string NoDotnetExeFound return ResourceManager.GetString("NoDotnetExeFound", resourceCulture); } } + + /// + /// Looks up a localized string similar to '{0}.{1}' is not implemented on this platform!. + /// + internal static string MethodNotImplementedOnPlatform + { + get + { + return ResourceManager.GetString("MethodNotImplementedOnPlatform", resourceCulture); + } + } } } diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx b/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx index ba520ac0b1..27a397f0d5 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/Resources.resx @@ -165,4 +165,10 @@ Error getting process name. + + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf index d3fcf4893f..47832fc031 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.cs.xlf @@ -160,6 +160,13 @@ Hostitele {0} nešlo najít. Ujistěte se, jestli je {0} nainstalovaný na počítači a dostupný v cestě určené proměnnou prostředí PATH. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf index e56739c937..7540c20d89 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.de.xlf @@ -160,6 +160,13 @@ Der Host "{0}" wurde nicht gefunden. Stellen Sie sicher, dass "{0}" auf dem Computer installiert und in der PATH-Umgebungsvariablen verfügbar ist. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf index b428568d5f..f0b6d9d623 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.es.xlf @@ -160,6 +160,13 @@ No se pudo encontrar el host "{0}". Asegúrese de que "{0}" está instalado en el equipo y está disponible en la variable de entorno PATH. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf index 776258dfeb..ca8c35a132 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.fr.xlf @@ -160,6 +160,13 @@ L'hôte '{0}' est introuvable. Vérifiez que '{0}' est installé sur la machine et qu'il est disponible dans la variable d'environnement PATH. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf index 2a67405108..406e82c52f 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.it.xlf @@ -160,6 +160,13 @@ L'host '{0}' non è stato trovato. Assicurarsi che '{0}' sia installato nel computer e che sia disponibile nella variabile di ambiente PATH. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf index f7540bc847..bb418fbaac 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ja.xlf @@ -160,6 +160,13 @@ '{0}' ホストが見つかりませんでした。'{0}' がコンピューターにインストールされており、PATH 環境変数で使用できることを確認してください。 + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf index 045f1456c0..7a0d780acc 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ko.xlf @@ -160,6 +160,13 @@ ‘{0}’ 호스트를 찾을 수 없습니다. ‘{0}’이(가) 컴퓨터에 설치되어 있고 PATH 환경 변수에서 사용할 수 있는지 확인하세요. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf index 1a4f72c7c4..d6c0d233a4 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pl.xlf @@ -160,6 +160,13 @@ Nie można znaleźć hosta „{0}”. Upewnij się, że element „{0}” jest zainstalowany na maszynie i jest dostępny w zmiennej środowiskowej PATH. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf index c1ca953991..01c4d89016 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.pt-BR.xlf @@ -160,6 +160,13 @@ Não foi possível encontrar o host '{0}'. Verifique se o '{0}' está instalado no computador e está disponível na variável de ambiente PATH. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf index 439e58c02c..009f2c3f84 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.ru.xlf @@ -160,6 +160,13 @@ Не удалось найти хост "{0}". Убедитесь, что "{0}" установлен на компьютере и доступен в переменной среды PATH. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf index e137c740bd..ac138ce520 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.tr.xlf @@ -160,6 +160,13 @@ '{0}' konağı bulunamadı. '{0}' konağının makinede yüklü olduğundan ve PATH ortam değişkeninde bulunduğundan emin olun. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf index 615147279b..f557a28547 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.xlf @@ -67,6 +67,13 @@ Could not find {0}. Make sure that the dotnet is installed on the machine. + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf index 0c695e40d6..32b1ad3e48 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hans.xlf @@ -160,6 +160,13 @@ 找不到“{0}”主机。请确保计算机上已安装“{0}”且位于 PATH 环境变量中。 + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf index ba717bee60..3cf3379924 100644 --- a/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf +++ b/src/Microsoft.TestPlatform.CoreUtilities/Resources/xlf/Resources.zh-Hant.xlf @@ -160,6 +160,13 @@ 找不到 '{0}' 主機。請確認 '{0}' 已安裝在機器上,而且可在 PATH 環境變數中使用。 + + '{0}.{1}' is not implemented on this platform! + '{0}.{1}' is not implemented on this platform! + '{className}.{methodName}' is not implemented on this platform! + +Example: 'System.Reflection.MethodBase' is not implemented on this platform! + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Friends.cs b/src/Microsoft.TestPlatform.ObjectModel/Friends.cs index ea3b21f6f1..f71fffd5c1 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Friends.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/Friends.cs @@ -12,3 +12,4 @@ [assembly: InternalsVisibleTo("Microsoft.TestPlatform.ObjectModel.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("datacollector.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] [assembly: InternalsVisibleTo("Microsoft.TestPlatform.Extensions.EventLogCollector.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] +[assembly: InternalsVisibleTo("Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")] \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/FullyQualifiedNameHelper.Reflection.cs b/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/FullyQualifiedNameHelper.Reflection.cs new file mode 100644 index 0000000000..7f034d4175 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/FullyQualifiedNameHelper.Reflection.cs @@ -0,0 +1,277 @@ +// 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.ObjectModel.FullyQualifiedNameUtilities +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources; + using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Extensions; + + using System; + using System.Globalization; + using System.Linq; + using System.Reflection; + using System.Text; + + public static partial class FullyQualifiedNameHelper + { + /// + /// Gets fully qualified type and method name from given MethodBase instance. + /// + /// + /// A MethodBase instance to get fully qualified type and method name. + /// + /// + /// When this method returns, contains the fully qualified type name of the . + /// This parameter is passed uninitialized; any value originally supplied in result will be overwritten. + /// + /// + /// When this method returns, contains the fully qualified method name of the . + /// This parameter is passed uninitialized; any value originally supplied in result will be overwritten. + /// + /// is null. + /// must describe a method. + /// + /// Required functionality on is missing on the current platform. + /// + public static void GetFullyQualifiedName(MethodBase method, out string fullTypeName, out string fullMethodName) + { + if (method == null) + { + throw new ArgumentNullException(nameof(method)); + } + + if (!method.IsMethod()) + { + throw new NotSupportedException(nameof(method)); + } + + var semanticType = method.GetReflectedType(); + if (semanticType.IsGenericType()) + { + // The type might have some of its generic parameters specified, so make + // sure we are working with the open form of the generic type. + semanticType = semanticType.GetGenericTypeDefinition(); + + // The method might have some of its parameters specified by the original closed type + // declaration. Here we use the method handle (basically metadata token) to create + // a new method reference using the open form of the reflected type. The intent is + // to strip all generic type parameters. + var methodHandle = method.GetMethodHandle(); + method = MethodBase.GetMethodFromHandle(methodHandle, semanticType.TypeHandle); + } + + if (method.IsGenericMethod) + { + // If this method is generic, then convert to the generic method definition + // so that we get the open generic type definitions for parameters. + method = ((MethodInfo)method).GetGenericMethodDefinition(); + } + + var methodBuilder = new StringBuilder(); + var typeBuilder = new StringBuilder(); + + // Namespace and Type Name (with arity designation) + AppendTypeString(typeBuilder, semanticType, closedType: false); + + // Method Name with method arity + methodBuilder.Append(method.Name); + var arity = method.GetGenericArguments().Length; + if (arity > 0) + { + methodBuilder.Append('`'); + methodBuilder.Append(arity); + } + + // Type Parameters + var paramList = method.GetParameters(); + if (paramList.Any()) + { + methodBuilder.Append('('); + foreach (var p in paramList) + { + AppendTypeString(methodBuilder, p.ParameterType, closedType: true); + methodBuilder.Append(','); + } + // Replace the last ',' with ')' + methodBuilder[methodBuilder.Length - 1] = ')'; + } + + fullTypeName = typeBuilder.ToString(); + fullMethodName = methodBuilder.ToString(); + } + + /// + /// Gets the object with the specified + /// and in the instance. + /// + /// + /// An instance to search in. + /// + /// + /// The fully qualified name of the type. + /// + /// + /// The fully qualified name of the method. + /// + /// + /// A object that represents specified parameters, throws if null. + /// + /// + /// Values specified with and + /// does not correspond to a method in the instance, or malformed. + /// + public static MethodBase GetMethodFromFullyQualifiedName(Assembly assembly, string fullTypeName, string fullMethodName) + { + Type type; + +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + type = assembly.GetType(fullTypeName, throwOnError: false, ignoreCase: false); +#else + try + { + type = assembly.GetType(fullTypeName); + } + catch + { + type = null; + } +#endif + + if (type == null) + { + string message = String.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorTypeNotFound, fullTypeName); + throw new InvalidQualifiedNameException(message); + } + + MethodInfo method = null; + FullyQualifiedNameParser.ParseMethodName(fullMethodName, out var methodName, out var methodArity, out var parameterTypes); + if (!string.IsNullOrWhiteSpace(methodName)) + { + method = FindMethod(type, methodName, methodArity, parameterTypes); + } + + if (method == null) + { + string message = String.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorMethodNotFound, methodName, fullTypeName); + throw new InvalidQualifiedNameException(message); + } + + return method; + } + + private static MethodInfo FindMethod(Type type, string methodName, int methodArity, string[] parameterTypes) + { + bool filter(MemberInfo mbr, object param) + { + var method = mbr as MethodInfo; + if (method.Name != methodName || method.GetGenericArguments().Length != methodArity) + { + return false; + } + + var paramList = method.GetParameters(); + if (paramList.Length == 0 && parameterTypes == null) + { + return true; + } + else if (parameterTypes == null || paramList.Length != parameterTypes.Length) + { + return false; + } + + for (int i = 0; i < paramList.Length; i++) + { + if (TypeString(paramList[i].ParameterType, closedType: true) != parameterTypes[i]) + { + return false; + } + } + + return true; + } + +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + var methods = type.FindMembers(MemberTypes.Method, bindingFlags, filter, null); + return (MethodInfo)methods.SingleOrDefault(); +#else + return type.GetRuntimeMethods().Where(m => filter(m, null)).SingleOrDefault(); +#endif + } + + private static void AppendTypeString(StringBuilder b, Type type, bool closedType) + { + if (type.IsArray) + { + AppendTypeString(b, type.GetElementType(), closedType); + b.Append('['); + for (int i = 0; i < type.GetArrayRank() - 1; i++) + { + b.Append(','); + } + b.Append(']'); + } + else if (type.IsGenericParameter) + { + if (type.GetDeclaringMethod() != null) + { + b.Append('!'); + } + b.Append('!'); + b.Append(type.GenericParameterPosition); + } + else + { + b.Append(type.Namespace); + b.Append('.'); + + AppendNestedTypeName(b, type); + + if (closedType) + { + AppendGenericTypeParameters(b, type); + } + } + } + + private static void AppendNestedTypeName(StringBuilder b, Type type) + { + if (type.IsNested) + { + AppendNestedTypeName(b, type.DeclaringType); + b.Append('+'); + } + b.Append(type.Name); + } + + private static void AppendGenericTypeParameters(StringBuilder b, Type type) + { + Type[] genargs; + +#if !NETSTANDARD1_0 && !NETSTANDARD1_3 && !WINDOWS_UWP + genargs = type.GetGenericArguments(); +#else + genargs = type.GetTypeInfo().GenericTypeArguments; +#endif + + if (genargs.Any()) + { + b.Append('<'); + foreach (var argType in genargs) + { + AppendTypeString(b, argType, closedType: true); + b.Append(','); + } + // Replace the last ',' with '>' + b[b.Length - 1] = '>'; + } + } + + private static string TypeString(Type type, bool closedType) + { + var builder = new StringBuilder(); + AppendTypeString(builder, type, closedType); + return builder.ToString(); + } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/FullyQualifiedNameParser.cs b/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/FullyQualifiedNameParser.cs new file mode 100644 index 0000000000..070fb2bc29 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/FullyQualifiedNameParser.cs @@ -0,0 +1,188 @@ +// 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.ObjectModel.FullyQualifiedNameUtilities +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources; + + using System.Collections.Generic; + using System.Diagnostics; + using System.Globalization; + using System.Linq; + + public class FullyQualifiedNameParser + { + internal static void ParseTypeName(string fullTypeName, out string namespaceName, out string typeName) + { + int pos = fullTypeName.LastIndexOf('.'); + if (pos == -1) + { + namespaceName = string.Empty; + typeName = fullTypeName; + } + else + { + namespaceName = fullTypeName.Substring(0, pos); + typeName = fullTypeName.Substring(pos + 1); + } + } + + internal static void ParseMethodName(string fullMethodName, out string methodName, out int arity, out string[] parameterTypes) + { + int pos = ParseMethodName(fullMethodName, 0, out methodName, out arity); + pos = ParseParameterTypeList(fullMethodName, pos, out parameterTypes); + if (pos != fullMethodName.Length) + { + string message = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorUnexpectedCharactersAtEnd, pos); + throw new InvalidQualifiedNameException(message); + } + } + + private static string Capture(string fullMethodName, int start, int end) + => fullMethodName.Substring(start, end - start); + + private static int ParseMethodName(string fullMethodName, int start, out string methodName, out int arity) + { + int i = start; + for (; i < fullMethodName.Length; i++) + { + switch (fullMethodName[i]) + { + case var w when char.IsWhiteSpace(w): + string message = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorWhitespaceNotValid, i); + throw new InvalidQualifiedNameException(message); + case '`': + methodName = Capture(fullMethodName, start, i); + return ParseArity(fullMethodName, i, out arity); + case '(': + methodName = Capture(fullMethodName, start, i); + arity = 0; + return i; + } + } + methodName = Capture(fullMethodName, start, i); + arity = 0; + return i; + } + + // parse arity in the form `nn where nn is an integer value. + private static int ParseArity(string fullMethodName, int start, out int arity) + { + arity = 0; + Debug.Assert(fullMethodName[start] == '`'); + + int i = start + 1; // skip initial '`' char + for (; i < fullMethodName.Length; i++) + { + if (fullMethodName[i] == '(') break; + } + if (!int.TryParse(Capture(fullMethodName, start + 1, i), out arity)) + { + string message = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorMethodArityMustBeNumeric); + throw new InvalidQualifiedNameException(message); + } + return i; + } + + private static int ParseParameterTypeList(string fullMethodName, int start, out string[] parameterTypes) + { + parameterTypes = null; + if (start == fullMethodName.Length) + { + return start; + } + Debug.Assert(fullMethodName[start] == '('); + + var types = new List(); + + int i = start + 1; // skip initial '(' char + for (; i < fullMethodName.Length; i++) + { + switch (fullMethodName[i]) + { + case ')': + if (types.Any()) + { + parameterTypes = types.ToArray(); + } + return i + 1; // consume right parens + case ',': + break; + default: + i = ParseParameterType(fullMethodName, i, out var parameterType); + types.Add(parameterType); + break; + } + } + + string message = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorIncompleteFullyQualifiedName); + throw new InvalidQualifiedNameException(message); + } + + private static int ParseParameterType(string fullMethodName, int start, out string parameterType) + { + parameterType = string.Empty; + + int i = start; + for (; i < fullMethodName.Length; i++) + { + switch (fullMethodName[i]) + { + case '<': + i = ParseGenericBrackets(fullMethodName, i + 1); + break; + case '[': + i = ParseArrayBrackets(fullMethodName, i + 1); + break; + case ',': + case ')': + parameterType = Capture(fullMethodName, start, i); + return i - 1; + case var w when char.IsWhiteSpace(w): + string message = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorWhitespaceNotValid, i); + throw new InvalidQualifiedNameException(message); + } + } + return i; + } + + private static int ParseArrayBrackets(string fullMethodName, int start) + { + for (int i = start; i < fullMethodName.Length; i++) + { + switch (fullMethodName[i]) + { + case ']': + return i; + case var w when char.IsWhiteSpace(w): + string msg = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorWhitespaceNotValid, i); + throw new InvalidQualifiedNameException(msg); + } + } + + string message = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorIncompleteFullyQualifiedName); + throw new InvalidQualifiedNameException(message); + } + + private static int ParseGenericBrackets(string fullMethodName, int start) + { + for (int i = start; i < fullMethodName.Length; i++) + { + switch (fullMethodName[i]) + { + case '<': + i = ParseGenericBrackets(fullMethodName, i + 1); + break; + case '>': + return i; + case var w when char.IsWhiteSpace(w): + string msg = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorWhitespaceNotValid, i); + throw new InvalidQualifiedNameException(msg); + } + } + + string message = string.Format(CultureInfo.CurrentCulture, FullyQualifiedNameMessages.ErrorIncompleteFullyQualifiedName); + throw new InvalidQualifiedNameException(message); + } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/InvalidQualifiedNameException.cs b/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/InvalidQualifiedNameException.cs new file mode 100644 index 0000000000..9697695e57 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/FullyQualifiedNameUtilities/InvalidQualifiedNameException.cs @@ -0,0 +1,12 @@ +// 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.ObjectModel.FullyQualifiedNameUtilities +{ + using System; + + public class InvalidQualifiedNameException : Exception + { + public InvalidQualifiedNameException(string message) : base(message) { } + } +} \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj index 134b75a559..d40dd82625 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj +++ b/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj @@ -26,7 +26,7 @@ - + @@ -95,6 +95,11 @@ True CommonResources.resx + + True + True + FullyQualifiedNameMessages.resx + True True @@ -107,6 +112,10 @@ Resources\CommonResources.tt CommonResources.Designer.cs + + ResXFileCodeGenerator + FullyQualifiedNameMessages.Designer.cs + ResXFileCodeGenerator Resources.Designer.cs diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/FullyQualifiedNameMessages.Designer.cs b/src/Microsoft.TestPlatform.ObjectModel/Resources/FullyQualifiedNameMessages.Designer.cs new file mode 100644 index 0000000000..b5a220f21d --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/FullyQualifiedNameMessages.Designer.cs @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources { + using System; + using System.Reflection; + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class FullyQualifiedNameMessages { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal FullyQualifiedNameMessages() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.VisualStudio.TestPlatform.ObjectModel.Resources.FullyQualifiedNameMessages", + typeof(FullyQualifiedNameMessages).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to FullyQualifiedName is incomplete. + /// + internal static string ErrorIncompleteFullyQualifiedName { + get { + return ResourceManager.GetString("ErrorIncompleteFullyQualifiedName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method arity must be numeric. + /// + internal static string ErrorMethodArityMustBeNumeric { + get { + return ResourceManager.GetString("ErrorMethodArityMustBeNumeric", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Method '{0}' not found on type '{1}'. + /// + internal static string ErrorMethodNotFound { + get { + return ResourceManager.GetString("ErrorMethodNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type '{0}' not found. + /// + internal static string ErrorTypeNotFound { + get { + return ResourceManager.GetString("ErrorTypeNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected characters after the end of the FullyQualifiedName (pos: {0}). + /// + internal static string ErrorUnexpectedCharactersAtEnd { + get { + return ResourceManager.GetString("ErrorUnexpectedCharactersAtEnd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whitespace is not valid in a FullyQualifiedName (pos: {0}). + /// + internal static string ErrorWhitespaceNotValid { + get { + return ResourceManager.GetString("ErrorWhitespaceNotValid", resourceCulture); + } + } + } +} diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/FullyQualifiedNameMessages.resx b/src/Microsoft.TestPlatform.ObjectModel/Resources/FullyQualifiedNameMessages.resx new file mode 100644 index 0000000000..facc0e2836 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/FullyQualifiedNameMessages.resx @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + FullyQualifiedName is incomplete + + + Method arity must be numeric + + + Method '{0}' not found on type '{1}' + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + {0} is the position of invalid whitespace + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.cs.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.cs.xlf new file mode 100644 index 0000000000..be586565f4 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.cs.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + PlněKvalifikovanýNázev je neúplný. + + + + Method arity must be numeric + Arita metody musí být číselná. + + + + Method '{0}' not found on type '{1}' + Metoda {0} nebyla nalezena u typu {1}. + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Typ {0} nebyl nalezen. + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Neočekávané znaky na konci položky PlněKvalifikovanýNázev (pos: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + V položce PlněKvalifikovanýNázev není povolena mezera (pos: {0}). + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.de.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.de.xlf new file mode 100644 index 0000000000..fb9bb753f1 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.de.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName ist unvollständig. + + + + Method arity must be numeric + Die Stelligkeit der Methode muss numerisch sein. + + + + Method '{0}' not found on type '{1}' + Die Methode "{0}" wurde für den Typ "{1}" nicht gefunden. + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Der Typ "{0}" wurde nicht gefunden. + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Nach dem Ende von FullyQualifiedName (Pos: {0}) wurden unerwartete Zeichen gefunden. + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + Leerzeichen sind in einem FullyQualifiedName (Pos: {0}) unzulässig. + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.es.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.es.xlf new file mode 100644 index 0000000000..dd998fb5eb --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.es.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName está incompleto + + + + Method arity must be numeric + La aridad del método debe ser numérica + + + + Method '{0}' not found on type '{1}' + Método "{0}" no encontrado en el tipo "{1}" + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Tipo "{0}" no encontrado + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Caracteres inesperados después del final de FullyQualifiedName (pos: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + El espacio en blanco no es válido en un elemento FullyQualifiedName (pos: {0}) + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.fr.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.fr.xlf new file mode 100644 index 0000000000..7dbb65e0a8 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.fr.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName est incomplet + + + + Method arity must be numeric + L'arité de la méthode doit être numérique + + + + Method '{0}' not found on type '{1}' + Méthode '{0}' introuvable sur le type '{1}' + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Type '{0}' introuvable + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Caractères inattendus après la fin du FullyQualifiedName (pos : {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + Les espaces blancs ne sont pas valides dans un FullyQualifiedName (pos : {0}) + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.it.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.it.xlf new file mode 100644 index 0000000000..0fc1c0e095 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.it.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + L'elemento FullyQualifiedName è incompleto + + + + Method arity must be numeric + Il grado del metodo deve essere numerico + + + + Method '{0}' not found on type '{1}' + Il metodo '{0}' non è stato trovato nel tipo '{1}' + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Il tipo '{0}' non è stato trovato + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Caratteri imprevisti dopo la fine dell'elemento FullyQualifiedName (pos.: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + Gli spazi vuoti non sono validi in un elemento FullyQualifiedName (pos.: {0}) + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ja.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ja.xlf new file mode 100644 index 0000000000..17ab6b75cf --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ja.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName が不完全です。 + + + + Method arity must be numeric + メソッドのアリティは、数値でなければなりません。 + + + + Method '{0}' not found on type '{1}' + メソッド '{0}' が型 '{1}' に見つかりませんでした。 + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + 型 '{0}' が見つかりません。 + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + FullyQualifiedName (pos: {0}) の末尾の後ろに予期しない文字があります + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + FullyQualifiedName (pos: {0}) では空白は無効です + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ko.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ko.xlf new file mode 100644 index 0000000000..ad6f1c6842 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ko.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName이 불완전합니다. + + + + Method arity must be numeric + 메서드 인자 수는 숫자여야 합니다. + + + + Method '{0}' not found on type '{1}' + '{0}' 메서드를 '{1}' 형식에서 찾을 수 없습니다. + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + '{0}' 형식을 찾을 수 없습니다. + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + FullyQualifiedName의 끝 다음에 예기치 않은 문자가 있습니다(pos: {0}). + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + FullyQualifiedName에서 공백은 유효하지 않습니다(pos: {0}). + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.pl.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.pl.xlf new file mode 100644 index 0000000000..175545e2a4 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.pl.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + Wartość FullyQualifiedName jest niepełna + + + + Method arity must be numeric + Liczba argumentów metody musi być liczbą + + + + Method '{0}' not found on type '{1}' + Nie znaleziono metody „{0}” w typie „{1}” + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Nie znaleziono typu „{0}” + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Nieoczekiwane znaki za końcem wartości FullyQualifiedName (pozycja: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + Biały znak jest niedozwolony w wartości FullyQualifiedName (pozycja: {0}) + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.pt-BR.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.pt-BR.xlf new file mode 100644 index 0000000000..ed08cfbcab --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.pt-BR.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName está incompleto + + + + Method arity must be numeric + A aridade do método deve ser numérica + + + + Method '{0}' not found on type '{1}' + Método '{0}' não encontrado no tipo '{1}' + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Tipo '{0}' não encontrado + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Caracteres inesperados após o fnal de FullyQualifiedName (pos: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + Espaço em branco não é válido em um FullyQualifiedName (pos: {0}) + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ru.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ru.xlf new file mode 100644 index 0000000000..06f76a8f35 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.ru.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName (Полное имя) содержит не все данные + + + + Method arity must be numeric + Арность метода должна быть числовым значением + + + + Method '{0}' not found on type '{1}' + Метод "{0}" не найден для типа "{1}" + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + Тип "{0}" не найден + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + Непредусмотренные символы после FullyQualifiedName (Полного имени), позиция: {0} + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + Пробел в FullyQualifiedName (Полном имени) недопустим, позиция: {0} + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.tr.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.tr.xlf new file mode 100644 index 0000000000..73331c7d9a --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.tr.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName eksik + + + + Method arity must be numeric + Method sayısı sayısal bir değer olmalıdır + + + + Method '{0}' not found on type '{1}' + '{1}' türünde '{0}' metodu bulunamadı + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + {0} türü bulunamadı. + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + FullyQualifiedName’den sonra beklenmeyen karakterler (konum: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + FullyQualifiedName’de boşluk geçersizdir (konum: {0}) + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.xlf new file mode 100644 index 0000000000..426cbfbfdb --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.xlf @@ -0,0 +1,31 @@ + + + + + + FullyQualifiedName is incomplete + + + + Method arity must be numeric + + + + Method '{0}' not found on type '{1}' + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.zh-Hans.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.zh-Hans.xlf new file mode 100644 index 0000000000..ecee83ab45 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.zh-Hans.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName 不完整 + + + + Method arity must be numeric + 方法参数数量必须是数值 + + + + Method '{0}' not found on type '{1}' + 类型“{1}”上找不到方法“{0}” + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + 找不到类型“{0}” + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + FullyQualifiedName (pos: {0}) 末尾后有不需要的字符 + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + FullyQualifiedName (pos: {0}) 中空白无效 + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.zh-Hant.xlf b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.zh-Hant.xlf new file mode 100644 index 0000000000..2e6a4cd377 --- /dev/null +++ b/src/Microsoft.TestPlatform.ObjectModel/Resources/xlf/FullyQualifiedNameMessages.zh-Hant.xlf @@ -0,0 +1,37 @@ + + + + + + FullyQualifiedName is incomplete + FullyQualifiedName 不完整 + + + + Method arity must be numeric + 方法 arity 必須為數值 + + + + Method '{0}' not found on type '{1}' + 在類型 '{1}' 上找不到方法 '{0}' + {0} is the method name, {1} is the full type name. + + + Type '{0}' not found + 找不到類型 '{0}' + {0} is the full type name. + + + Unexpected characters after the end of the FullyQualifiedName (pos: {0}) + FullyQualifiedName (pos: {0}) 的結尾出現未預期的字元 + {0} is the position of unexpected characters + + + Whitespace is not valid in a FullyQualifiedName (pos: {0}) + 空白字元在 FullyQualifiedName (pos: {0}) 中無效 + {0} is the position of invalid whitespace + + + + \ No newline at end of file diff --git a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs index a4493a5b31..d11b5e62e4 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/TestCase.cs @@ -10,6 +10,7 @@ namespace Microsoft.VisualStudio.TestPlatform.ObjectModel using System.Linq; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Utilities; + using System.Reflection; /// /// Stores information about a test case. @@ -21,13 +22,15 @@ public sealed class TestCase : TestObject /// LocalExtensionData which can be used by Adapter developers for local transfer of extended properties. /// Note that this data is available only for in-Proc execution, and may not be available for OutProc executors /// - private Object localExtensionData; + private object localExtensionData; private Guid defaultId = Guid.Empty; private Guid id; private string displayName; private string fullyQualifiedName; private string source; + private string managedMethod; + private string managedType; #region Constructor @@ -64,6 +67,63 @@ public TestCase(string fullyQualifiedName, Uri executorUri, string source) this.LineNumber = -1; } + /// + /// Initializes a new instance of the class. + /// + /// + /// Fully qualified name of the test case. + /// + /// + /// Managed method to extract the values of and . + /// + /// + /// The Uri of the executor to use for running this test. + /// + /// + /// Test container source from which the test is discovered. + /// + /// + /// If is specified, TestId will be calculated based on that instead of . + /// + public TestCase(string fullyQualifiedName, MethodBase method, Uri executorUri, string source) + : this(fullyQualifiedName, executorUri, source) + { + ValidateArg.NotNull(method, nameof(method)); + + FullyQualifiedNameUtilities.FullyQualifiedNameHelper.GetFullyQualifiedName(method, out var managedType, out var managedMethod); + + ManagedType = managedType; + ManagedMethod = managedMethod; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Fully qualified name of the test case. + /// + /// + /// Managed method to extract the values of and . + /// + /// + /// The Uri of the executor to use for running this test. + /// + /// + /// Test container source from which the test is discovered. + /// + /// + /// If and are specified, TestId will be calculated based on those instead of . + /// + public TestCase(string fullyQualifiedName, string managedType, string managedMethod, Uri executorUri, string source) + : this(fullyQualifiedName, executorUri, source) + { + ValidateArg.NotNullOrWhiteSpace(managedType, nameof(managedType)); + ValidateArg.NotNullOrWhiteSpace(managedMethod, nameof(managedMethod)); + + ManagedType = managedType; + ManagedMethod = managedMethod; + } + #endregion #region Properties @@ -92,6 +152,7 @@ public Guid Id { this.defaultId = this.GetTestId(); } + return this.defaultId; } @@ -104,23 +165,44 @@ public Guid Id } } + /// + /// Gets or sets the fully specified type name metadata format. + /// + /// + /// NamespaceA.NamespaceB.ClassName`1+InnerClass`2 + /// + [DataMember] + public string ManagedType { + get => managedType; + + // defaultId should be reset as it is based on ManagedType, ManagedMethod and Source. + set => SetVariableAndResetId(ref managedType, value); + } + + /// + /// Gets or sets the fully specified method name metadata format. + /// + /// + /// MethodName`2(ParamTypeA,ParamTypeB,) + /// + [DataMember] + public string ManagedMethod { + get => managedMethod; + + // defaultId should be reset as it is based on ManagedType, ManagedMethod and Source. + set => SetVariableAndResetId(ref managedMethod, value); + } + /// /// Gets or sets the fully qualified name of the test case. /// [DataMember] public string FullyQualifiedName { - get - { - return this.fullyQualifiedName; - } - set - { - this.fullyQualifiedName = value; + get => fullyQualifiedName; - // defaultId should be reset as it is based on FullyQualifiedName and Source. - this.defaultId = Guid.Empty; - } + // defaultId should be reset as it is based on FullyQualifiedName and Source. + set => SetVariableAndResetId(ref fullyQualifiedName, value); } /// @@ -131,7 +213,17 @@ public string DisplayName { get { - return string.IsNullOrEmpty(this.displayName) ? this.FullyQualifiedName : this.displayName; + if(string.IsNullOrEmpty(this.displayName)) + { + if(string.IsNullOrWhiteSpace(managedType) || string.IsNullOrWhiteSpace(managedMethod)) + { + return this.FullyQualifiedName; + } + + return $"{managedType}.{ManagedMethod}"; + } + + return this.displayName; } set { @@ -199,7 +291,14 @@ public override IEnumerable Properties /// public override string ToString() { - return this.FullyQualifiedName; + if (string.IsNullOrWhiteSpace(ManagedType) || string.IsNullOrWhiteSpace(ManagedMethod)) + { + return this.FullyQualifiedName; + } + else + { + return $"{ManagedType}.{ManagedMethod}"; + } } #endregion @@ -234,10 +333,27 @@ private Guid GetTestId() // do nothing } - string testcaseFullName = this.ExecutorUri + source + this.FullyQualifiedName; + var testcaseFullName = this.ExecutorUri + source; + + // If ManagedType and ManagedMethod properties are filled than TestId should be based on those. + if( string.IsNullOrWhiteSpace(managedType) || string.IsNullOrWhiteSpace(managedMethod)) + { + testcaseFullName += this.FullyQualifiedName; + } + else + { + testcaseFullName += $"{managedType}.{managedMethod}"; + } + return EqtHash.GuidFromString(testcaseFullName); } + private void SetVariableAndResetId(ref T variable, T value) + { + variable = value; + this.defaultId = Guid.Empty; + } + #endregion #region Protected Methods @@ -260,6 +376,10 @@ protected override object ProtectedGetPropertyValue(TestProperty property, objec return this.ExecutorUri; case "TestCase.FullyQualifiedName": return this.FullyQualifiedName; + case "TestCase.ManagedType": + return this.ManagedType; + case "TestCase.ManagedMethod": + return this.ManagedMethod; case "TestCase.Id": return this.Id; case "TestCase.LineNumber": @@ -282,19 +402,40 @@ protected override void ProtectedSetPropertyValue(TestProperty property, object switch (property.Id) { case "TestCase.CodeFilePath": - this.CodeFilePath = (string)value; return; + this.CodeFilePath = value as string; + return; + case "TestCase.DisplayName": - this.DisplayName = (string)value; return; + this.DisplayName = value as string; + return; + case "TestCase.ExecutorUri": - this.ExecutorUri = value as Uri ?? new Uri((string)value); return; + this.ExecutorUri = value as Uri ?? new Uri(value as string); + return; + case "TestCase.FullyQualifiedName": - this.FullyQualifiedName = (string)value; return; + this.FullyQualifiedName = value as string; + return; + + case "TestCase.ManagedType": + this.ManagedType = value as string; + return; + + case "TestCase.ManagedMethod": + this.ManagedMethod = value as string; + return; + case "TestCase.Id": - this.Id = value is Guid ? (Guid)value : Guid.Parse((string)value); return; + this.Id = value is Guid ? (Guid)value : Guid.Parse(value as string); + return; + case "TestCase.LineNumber": - this.LineNumber = (int)value; return; + this.LineNumber = (int)value; + return; + case "TestCase.Source": - this.Source = (string)value; return; + this.Source = value as string; + return; } // It is a custom test case property. Should be set in the TestObject store. @@ -317,6 +458,8 @@ public static class TestCaseProperties /// private const string IdLabel = "Id"; private const string FullyQualifiedNameLabel = "FullyQualifiedName"; + private const string ManagedTypeLabel = "ManagedType"; + private const string ManagedMethodLabel = "ManagedMethod"; private const string NameLabel = "Name"; private const string ExecutorUriLabel = "Executor Uri"; private const string SourceLabel = "Source"; @@ -331,6 +474,12 @@ public static class TestCaseProperties [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty FullyQualifiedName = TestProperty.Register("TestCase.FullyQualifiedName", FullyQualifiedNameLabel, string.Empty, string.Empty, typeof(string), ValidateName, TestPropertyAttributes.Hidden, typeof(TestCase)); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly TestProperty ManagedType = TestProperty.Register("TestCase.ManagedType", ManagedTypeLabel, string.Empty, string.Empty, typeof(string), ValidateName, TestPropertyAttributes.Hidden, typeof(TestCase)); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly TestProperty ManagedMethod = TestProperty.Register("TestCase.ManagedMethod", ManagedMethodLabel, string.Empty, string.Empty, typeof(string), ValidateName, TestPropertyAttributes.Hidden, typeof(TestCase)); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] public static readonly TestProperty DisplayName = TestProperty.Register("TestCase.DisplayName", NameLabel, string.Empty, string.Empty, typeof(string), ValidateDisplay, TestPropertyAttributes.None, typeof(TestCase)); @@ -352,6 +501,8 @@ public static class TestCaseProperties DisplayName, ExecutorUri, FullyQualifiedName, + ManagedType, + ManagedMethod, Id, LineNumber, Source diff --git a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs index 6ddd654e19..2cb9fc8d34 100644 --- a/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs +++ b/test/Microsoft.TestPlatform.CommunicationUtilities.UnitTests/Serialization/TestResultSerializationTests.cs @@ -218,7 +218,7 @@ public void TestResultObjectShouldSerializeAttachmentsV2() result.StartTime = default(DateTimeOffset); result.EndTime = default(DateTimeOffset); result.Attachments.Add(new AttachmentSet(new Uri("http://dummyUri"), "sampleAttachment")); - var expectedJson = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Outcome\":0,\"ErrorMessage\":null,\"ErrorStackTrace\":null,\"DisplayName\":null,\"Messages\":[],\"ComputerName\":null,\"Duration\":\"00:00:00\",\"StartTime\":\"0001-01-01T00:00:00+00:00\",\"EndTime\":\"0001-01-01T00:00:00+00:00\",\"Properties\":[]}"; + var expectedJson = "{\"TestCase\":{\"Id\":\"28e7a7ed-8fb9-05b7-5e90-4a8c52f32b5b\",\"ManagedType\":null,\"ManagedMethod\":null,\"FullyQualifiedName\":\"sampleTestClass.sampleTestCase\",\"DisplayName\":\"sampleTestClass.sampleTestCase\",\"ExecutorUri\":\"executor://sampleTestExecutor\",\"Source\":\"sampleTest.dll\",\"CodeFilePath\":null,\"LineNumber\":-1,\"Properties\":[]},\"Attachments\":[{\"Uri\":\"http://dummyUri\",\"DisplayName\":\"sampleAttachment\",\"Attachments\":[]}],\"Outcome\":0,\"ErrorMessage\":null,\"ErrorStackTrace\":null,\"DisplayName\":null,\"Messages\":[],\"ComputerName\":null,\"Duration\":\"00:00:00\",\"StartTime\":\"0001-01-01T00:00:00+00:00\",\"EndTime\":\"0001-01-01T00:00:00+00:00\",\"Properties\":[]}"; var json = Serialize(result, 2); diff --git a/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FindMethodExtensions.cs b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FindMethodExtensions.cs new file mode 100644 index 0000000000..a5c9fb18ed --- /dev/null +++ b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FindMethodExtensions.cs @@ -0,0 +1,101 @@ +// 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.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests +{ + using Microsoft.CodeAnalysis; + + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + + internal static class FindMethodExtensions + { + private const BindingFlags PrivateBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + + internal static MethodInfo FindMethod(this Type type, string signature) + => type.FindMembers(MemberTypes.Method, PrivateBindingFlags, + (mbr, sig) => mbr.ToString() == (string)sig, signature).FirstOrDefault() as MethodInfo; + + internal static IMethodSymbol FindMethod( + this INamedTypeSymbol type, + string methodName, + int methodGenericArity = -1, + params ITypeSymbol[] methodParameterTypes) + { + var candidates = GetCandidateMethods(type, methodName); + if (candidates.Any() && !candidates.Skip(1).Any()) + { + return candidates.Single(); + } + + if (methodGenericArity != -1) + { + candidates = candidates.Where(m => m.Arity == methodGenericArity); + if (candidates.Any() && !candidates.Skip(1).Any()) + { + return candidates.Single(); + } + } + + if (methodParameterTypes != null && methodParameterTypes.Length >= 0) + { + candidates = candidates.Where(m => m.Parameters.Length == methodParameterTypes.Length); + if (candidates.Any() && !candidates.Skip(1).Any()) + { + return candidates.Single(); + } + + candidates = candidates.Where(m => m.Parameters.Select(p => p.Type).SequenceEqual(methodParameterTypes)); + } + + Debug.Assert(candidates.Any() && !candidates.Skip(1).Any()); + return candidates.SingleOrDefault(); + } + + internal static IMethodSymbol FindMethod( + this INamedTypeSymbol type, + string methodName, + int methodGenericArity, + int methodParameterCount, + Func selector) + { + var candidates = GetCandidateMethods(type, methodName); + if (candidates.Any() && !candidates.Skip(1).Any()) + { + return candidates.Single(); + } + + candidates = candidates.Where(m => m.Arity == methodGenericArity); + if (candidates.Any() && !candidates.Skip(1).Any()) + { + return candidates.Single(); + } + + candidates = candidates.Where(m => m.Parameters.Length == methodParameterCount); + if (candidates.Any() && !candidates.Skip(1).Any()) + { + return candidates.Single(); + } + + candidates = candidates.Where(selector); + + Debug.Assert(candidates.Any() && !candidates.Skip(1).Any()); + return candidates.SingleOrDefault(); + } + + private static IEnumerable GetCandidateMethods(INamedTypeSymbol type, string methodName) + { + var candidates = type.GetMembers(methodName).OfType(); + + if (type.BaseType != null && type.BaseType.SpecialType != SpecialType.System_Object) + { + candidates = candidates.Union(GetCandidateMethods(type.BaseType, methodName)); + } + + return candidates; + } + } +} diff --git a/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FullyQualifiedNameParserTests.cs b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FullyQualifiedNameParserTests.cs new file mode 100644 index 0000000000..dc380aa895 --- /dev/null +++ b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FullyQualifiedNameParserTests.cs @@ -0,0 +1,75 @@ +// 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.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests +{ + using Microsoft.VisualStudio.TestPlatform.ObjectModel.FullyQualifiedNameUtilities; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class FullyQualifiedNameParserTests + { + [TestMethod] + public void ParseTypeName() + { + (string, string) Parse(string fullTypeName) + { + FullyQualifiedNameParser.ParseTypeName(fullTypeName, out var namespaceName, out var typeName); + return (namespaceName, typeName); + }; + + Assert.AreEqual(("NS", "Class"), Parse("NS.Class")); + Assert.AreEqual(("NS.NS", "Class"), Parse("NS.NS.Class")); + Assert.AreEqual(("NS.NS", "Class`2"), Parse("NS.NS.Class`2")); + Assert.AreEqual(("NS.NS", "ClassA`2+ClassInner"), Parse("NS.NS.ClassA`2+ClassInner")); + Assert.AreEqual(("NS.NS", "ClassA`2+ClassInner`1"), Parse("NS.NS.ClassA`2+ClassInner`1")); + Assert.AreEqual(("", "ClassA`2+ClassInner`1"), Parse("ClassA`2+ClassInner`1")); + } + + [TestMethod] + public void ParseMethodName() + { + (string, int, string[]) Parse(string methodName) + { + FullyQualifiedNameParser.ParseMethodName(methodName, out var method, out var arity, out var parameterTypes); + return (method, arity, parameterTypes); + } + + void AssertParse(string expectedMethod, int expectedArity, string[] expectedParams, string expression) + { + var (method, arity, parameters) = Parse(expression); + Assert.AreEqual(expectedMethod, method); + Assert.AreEqual(expectedArity, arity); + CollectionAssert.AreEqual(expectedParams, parameters, "parameter comparison"); + } + + Assert.AreEqual(("Method", 0, null), Parse("Method")); + Assert.AreEqual(("Method", 0, null), Parse("Method()")); + Assert.AreEqual(("Method", 2, null), Parse("Method`2()")); + AssertParse("Method", 0, new string[] { "System.Int32" }, "Method(System.Int32)"); + AssertParse("Method", 0, new string[] { "TypeA", "List" }, "Method(TypeA,List)"); + AssertParse("Method", 1, new string[] { "B", "List" }, "Method`1(B,List)"); + AssertParse("Method", 0, new string[] { "B[]" }, "Method(B[])"); + AssertParse("Method", 0, new string[] { "A[,]", "B[,,][]" }, "Method(A[,],B[,,][])"); + } + + [TestMethod] + public void ParseInvalidMethodName() + { + (string, int, string[]) Parse(string methodName) + { + FullyQualifiedNameParser.ParseMethodName(methodName, out var method, out var arity, out var parameterTypes); + return (method, arity, parameterTypes); + } + + Assert.ThrowsException(() => Parse(" Method"), "Whitespace is not valid in a FullyQualifiedName (pos: 0)"); + Assert.ThrowsException(() => Parse("Method( List)"), "Whitespace is not valid in a FullyQualifiedName (pos: 7)"); + + Assert.ThrowsException(() => Parse("Method(List)xa"), "Unexpected characters after the end of the FullyQualifiedName (pos: 7)"); + + Assert.ThrowsException(() => Parse("Method("), "FullyQualifiedName is incomplete"); + Assert.ThrowsException(() => Parse("Method`4a"), "Method arity must be numeric"); + } + + } +} diff --git a/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FullyQualifiedNameRoundTripTests.cs b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FullyQualifiedNameRoundTripTests.cs new file mode 100644 index 0000000000..23a854aeea --- /dev/null +++ b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/FullyQualifiedNameRoundTripTests.cs @@ -0,0 +1,938 @@ +// 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.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests +{ + using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.CSharp; + using Microsoft.VisualStudio.TestPlatform.ObjectModel.FullyQualifiedNameUtilities; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + using System.IO; + using System.Linq; + using System.Reflection; + + [TestClass] + [DeploymentItem("TestClasses.cs")] + public partial class FullyQualifiedNameRoundTripTests + { + private const BindingFlags PrivateBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + private Compilation _compilation; + + [TestInitialize] + public void Initialize() + => _compilation = CSharpCompilation.Create( + "Test.dll", + new[] { CSharpSyntaxTree.ParseText(File.ReadAllText("TestClasses.cs")) }, + new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }); + + [TestMethod] + public void Simple1() + { + var outer = _compilation.GetTypeByMetadataName("TestClasses.Outer"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method0"), + containingTypeSymbol: outer, + methodSymbol: outer.FindMethod("Method0"), + fullTypeName: "TestClasses.Outer", + fullMethodName: "Method0"); + } + + [TestMethod] + public void Simple2() + { + var outer = _compilation.GetTypeByMetadataName("TestClasses.Outer"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method1"), + containingTypeSymbol: outer, + methodSymbol: outer.FindMethod("Method1"), + fullTypeName: "TestClasses.Outer", + fullMethodName: "Method1(System.Int32)"); + } + + [TestMethod] + public void Simple3() + { + var outer = _compilation.GetTypeByMetadataName("TestClasses.Outer"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method2"), + containingTypeSymbol: outer, + methodSymbol: outer.FindMethod("Method2"), + fullTypeName: "TestClasses.Outer", + fullMethodName: "Method2(System.Collections.Generic.List`1)"); + } + + [TestMethod] + public void Simple4() + { + var outer = _compilation.GetTypeByMetadataName("TestClasses.Outer"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method3"), + containingTypeSymbol: outer, + methodSymbol: outer.FindMethod("Method3"), + fullTypeName: "TestClasses.Outer", + fullMethodName: "Method3(System.String,System.Int32)"); + } + + [TestMethod] + public void Nested1() + { + var outerInner = _compilation.GetTypeByMetadataName("TestClasses.Outer+Inner"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method0"), + containingTypeSymbol: outerInner, + methodSymbol: outerInner.FindMethod("Method0"), + fullTypeName: "TestClasses.Outer+Inner", + fullMethodName: "Method0"); + } + + [TestMethod] + public void Nested2() + { + var outerInner = _compilation.GetTypeByMetadataName("TestClasses.Outer+Inner"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method1"), + containingTypeSymbol: outerInner, + methodSymbol: outerInner.FindMethod("Method1"), + fullTypeName: "TestClasses.Outer+Inner", + fullMethodName: "Method1(System.Int32)"); + } + + [TestMethod] + public void OpenGeneric1() + { + var outerT = _compilation.GetTypeByMetadataName("TestClasses.Outer`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method0"), + containingTypeSymbol: outerT, + methodSymbol: outerT.FindMethod("Method0"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method0"); + } + + [TestMethod] + public void OpenGeneric2() + { + var outerT = _compilation.GetTypeByMetadataName("TestClasses.Outer`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method1"), + containingTypeSymbol: outerT, + methodSymbol: outerT.FindMethod("Method1"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method1(!0)"); + } + + [TestMethod] + public void OpenGeneric3() + { + var outerT = _compilation.GetTypeByMetadataName("TestClasses.Outer`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method2"), + containingTypeSymbol: outerT, + methodSymbol: outerT.FindMethod("Method2"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method2`1(!!0[])"); + } + + [TestMethod] + public void OpenGeneric4() + { + var outerT = _compilation.GetTypeByMetadataName("TestClasses.Outer`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>).GetMethod("Method3"), + containingTypeSymbol: outerT, + methodSymbol: outerT.FindMethod("Method3"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method3`1(!0,!!0)"); + } + + [TestMethod] + public void OpenGenericNested1() + { + var outerTInnterV = _compilation.GetTypeByMetadataName("TestClasses.Outer`1+Inner`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method0"), + containingTypeSymbol: outerTInnterV, + methodSymbol: outerTInnterV.FindMethod("Method0"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method0"); + } + + [TestMethod] + public void OpenGenericNested2() + { + var outerTInnterV = _compilation.GetTypeByMetadataName("TestClasses.Outer`1+Inner`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method1"), + containingTypeSymbol: outerTInnterV, + methodSymbol: outerTInnterV.FindMethod("Method1"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method1(!0)"); + } + + [TestMethod] + public void OpenGenericNested3() + { + var outerTInnterV = _compilation.GetTypeByMetadataName("TestClasses.Outer`1+Inner`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method2"), + containingTypeSymbol: outerTInnterV, + methodSymbol: outerTInnterV.FindMethod("Method2"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method2(!1)"); + } + + [TestMethod] + public void OpenGenericNested4() + { + var outerTInnterV = _compilation.GetTypeByMetadataName("TestClasses.Outer`1+Inner`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method3"), + containingTypeSymbol: outerTInnterV, + methodSymbol: outerTInnterV.FindMethod("Method3"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method3`1(!0,!!0,!1)"); + } + + [TestMethod] + public void OpenGenericNested5() + { + var outerTInnterV = _compilation.GetTypeByMetadataName("TestClasses.Outer`1+Inner`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>.Inner<>).GetMethod("Method4"), + containingTypeSymbol: outerTInnterV, + methodSymbol: outerTInnterV.FindMethod("Method4"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method4`2(!!1,!!0)"); + } + + [TestMethod] + public void OpenGenericNested6() + { + var outerTInnerVMoreInnerI = _compilation.GetTypeByMetadataName("TestClasses.Outer`1+Inner`1+MoreInner`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer<>.Inner<>.MoreInner<>).GetMethod("Method0"), + containingTypeSymbol: outerTInnerVMoreInnerI, + methodSymbol: outerTInnerVMoreInnerI.FindMethod("Method0"), + fullTypeName: "TestClasses.Outer`1+Inner`1+MoreInner`1", + fullMethodName: "Method0`1(!0,!1,!2,!!0)"); + } + + [TestMethod] + public void ClosedGeneric1() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method0"), + containingTypeSymbol: outerTInt, + methodSymbol: outerTInt.FindMethod("Method0"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method0"); + } + + [TestMethod] + public void ClosedGeneric2() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method1"), + containingTypeSymbol: outerTInt, + methodSymbol: outerTInt.FindMethod("Method1"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method1(!0)"); + } + + [TestMethod] + public void ClosedGeneric3() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method2"), + containingTypeSymbol: outerTInt, + methodSymbol: outerTInt.FindMethod("Method2"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method2`1(!!0[])"); + } + + [TestMethod] + public void ClosedGeneric4() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method3"), + containingTypeSymbol: outerTInt, + methodSymbol: outerTInt.FindMethod("Method3"), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method3`1(!0,!!0)"); + } + + [TestMethod] + public void ClosedGenericNested1() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var @string = _compilation.GetSpecialType(SpecialType.System_String); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + var outerTIntInnerVString = outerTInt.GetTypeMembers().Single().Construct(@string); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method0"), + containingTypeSymbol: outerTIntInnerVString, + methodSymbol: outerTIntInnerVString.FindMethod("Method0"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method0"); + } + + [TestMethod] + public void ClosedGenericNested2() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var @string = _compilation.GetSpecialType(SpecialType.System_String); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + var outerTIntInnerVString = outerTInt.GetTypeMembers().Single().Construct(@string); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method1"), + containingTypeSymbol: outerTIntInnerVString, + methodSymbol: outerTIntInnerVString.FindMethod("Method1"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method1(!0)"); + } + + [TestMethod] + public void ClosedGenericNested3() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var @string = _compilation.GetSpecialType(SpecialType.System_String); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + var outerTIntInnerVString = outerTInt.GetTypeMembers().Single().Construct(@string); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method2"), + containingTypeSymbol: outerTIntInnerVString, + methodSymbol: outerTIntInnerVString.FindMethod("Method2"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method2(!1)"); + } + + [TestMethod] + public void ClosedGenericNested4() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var @string = _compilation.GetSpecialType(SpecialType.System_String); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + var outerTIntInnerVString = outerTInt.GetTypeMembers().Single().Construct(@string); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method3"), + containingTypeSymbol: outerTIntInnerVString, + methodSymbol: outerTIntInnerVString.FindMethod("Method3"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method3`1(!0,!!0,!1)"); + } + + [TestMethod] + public void ClosedGenericNested5() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var @string = _compilation.GetSpecialType(SpecialType.System_String); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + var outerTIntInnerVString = outerTInt.GetTypeMembers().Single().Construct(@string); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method4"), + containingTypeSymbol: outerTIntInnerVString, + methodSymbol: outerTIntInnerVString.FindMethod("Method4"), + fullTypeName: "TestClasses.Outer`1+Inner`1", + fullMethodName: "Method4`2(!!1,!!0)"); + } + + [TestMethod] + public void ClosedGenericMethod1() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var @string = _compilation.GetSpecialType(SpecialType.System_String); + var outerTInt = _compilation.GetTypeByMetadataName("TestClasses.Outer`1").Construct(@int); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer).GetMethod("Method3").MakeGenericMethod(typeof(string)), + containingTypeSymbol: outerTInt, + methodSymbol: outerTInt.FindMethod("Method3").Construct(@string), + fullTypeName: "TestClasses.Outer`1", + fullMethodName: "Method3`1(!0,!!0)"); + } + + [TestMethod] + public void ClosedGenericMethod2() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var outerInner = _compilation.GetTypeByMetadataName("TestClasses.Outer+Inner"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method2").MakeGenericMethod(typeof(int)), + containingTypeSymbol: outerInner, + methodSymbol: outerInner.FindMethod("Method2").Construct(@int), + fullTypeName: "TestClasses.Outer+Inner", + fullMethodName: "Method2`1(System.Int32)"); + } + + [TestMethod] + public void ClosedGenericMethod3() + { + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var @float = _compilation.GetSpecialType(SpecialType.System_Single); + var @string = _compilation.GetSpecialType(SpecialType.System_String); + var outerInner = _compilation.GetTypeByMetadataName("TestClasses.Outer+Inner"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Outer.Inner).GetMethod("Method3").MakeGenericMethod(typeof(float), typeof(string)), + containingTypeSymbol: outerInner, + methodSymbol: outerInner.FindMethod("Method3").Construct(@float, @string), + fullTypeName: "TestClasses.Outer+Inner", + fullMethodName: "Method3`2(System.Int32)"); + } + + [TestMethod] + public void ExplicitInterfaceImplementation1() + { + var impl = _compilation.GetTypeByMetadataName("TestClasses.Impl"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Impl).GetMethod("TestClasses.IImplementation.ImplMethod0", PrivateBindingFlags), + containingTypeSymbol: impl, + methodSymbol: impl.FindMethod("TestClasses.IImplementation.ImplMethod0"), + fullTypeName: "TestClasses.Impl", + fullMethodName: "TestClasses.IImplementation.ImplMethod0"); + } + + [TestMethod] + public void ExplicitInterfaceImplementation2() + { + var impl = _compilation.GetTypeByMetadataName("TestClasses.Impl"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Impl).GetMethod("TestClasses.IImplementation.ImplMethod1", PrivateBindingFlags), + containingTypeSymbol: impl, + methodSymbol: impl.FindMethod("TestClasses.IImplementation.ImplMethod1"), + fullTypeName: "TestClasses.Impl", + fullMethodName: "TestClasses.IImplementation.ImplMethod1(System.Int32)"); + } + + [TestMethod] + public void GenericExplicitInterfaceImplementation1() + { + var implT = _compilation.GetTypeByMetadataName("TestClasses.Impl`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Impl<>).GetMethod("TestClasses.IImplementation.ImplMethod0", PrivateBindingFlags), + containingTypeSymbol: implT, + methodSymbol: implT.FindMethod("TestClasses.IImplementation.ImplMethod0"), + fullTypeName: "TestClasses.Impl`1", + fullMethodName: "TestClasses.IImplementation.ImplMethod0"); + } + + [TestMethod] + public void GenericExplicitInterfaceImplementation2() + { + var implT = _compilation.GetTypeByMetadataName("TestClasses.Impl`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Impl<>).GetMethod("TestClasses.IImplementation.ImplMethod1", PrivateBindingFlags), + containingTypeSymbol: implT, + methodSymbol: implT.FindMethod("TestClasses.IImplementation.ImplMethod1"), + fullTypeName: "TestClasses.Impl`1", + fullMethodName: "TestClasses.IImplementation.ImplMethod1(!0)"); + } + + [TestMethod] + public void GenericExplicitInterfaceImplementation3() + { + var implT = _compilation.GetTypeByMetadataName("TestClasses.Impl`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Impl<>).GetMethod("TestClasses.IImplementation.ImplMethod2", PrivateBindingFlags), + containingTypeSymbol: implT, + methodSymbol: implT.FindMethod("TestClasses.IImplementation.ImplMethod2"), + fullTypeName: "TestClasses.Impl`1", + fullMethodName: "TestClasses.IImplementation.ImplMethod2`1(!0,!!0,System.String)"); + } + + [TestMethod] + public void Inheritance1() + { + var outerPrime = _compilation.GetTypeByMetadataName("TestClasses.OuterPrime"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.OuterPrime).GetMethod("Method3"), + containingTypeSymbol: outerPrime, + methodSymbol: outerPrime.FindMethod("Method3"), + fullTypeName: "TestClasses.OuterPrime", + fullMethodName: "Method3(System.String,System.Int32)"); + } + + [TestMethod] + public void Inheritance2() + { + var outerPrimeZ = _compilation.GetTypeByMetadataName("TestClasses.OuterPrime`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.OuterPrime<>).GetMethod("Method3"), + containingTypeSymbol: outerPrimeZ, + methodSymbol: outerPrimeZ.FindMethod("Method3"), + fullTypeName: "TestClasses.OuterPrime`1", + fullMethodName: "Method3`1(!0,!!0)"); + } + + [TestMethod] + public void Inheritance3() + { + var outerPrimeYZ = _compilation.GetTypeByMetadataName("TestClasses.OuterPrime`2"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.OuterPrime<,>).GetMethod("Method3"), + containingTypeSymbol: outerPrimeYZ, + methodSymbol: outerPrimeYZ.FindMethod("Method3"), + fullTypeName: "TestClasses.OuterPrime`2", + fullMethodName: "Method3`1(!1,!!0)"); + } + + [TestMethod] + public void Inheritance4() + { + var outerString = _compilation.GetTypeByMetadataName("TestClasses.OuterString"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.OuterString).GetMethod("Method3"), + containingTypeSymbol: outerString, + methodSymbol: outerString.FindMethod("Method3"), + fullTypeName: "TestClasses.OuterString", + fullMethodName: "Method3`1(System.String,!!0)"); + } + + [TestMethod] + public void Overloads1() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0()"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 0), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0"); + } + + [TestMethod] + public void Overloads2() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(Int32)"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 0, @int), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0(System.Int32)"); + } + + [TestMethod] + public void Overloads3() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(Int32, TestClasses.Overloads)"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 0, @int, overloads), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0(System.Int32,TestClasses.Overloads)"); + } + + [TestMethod] + public void Overloads4() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var intptr = _compilation.CreatePointerTypeSymbol(@int); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(Int32*)"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 0, intptr), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0(System.Int32*)"); + } + + [TestMethod] + public void Overloads5() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var dynamic = _compilation.DynamicType; + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(System.Object)"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 0, dynamic), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0(System.Object)"); + } + + [TestMethod] + public void Overloads6() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](U)"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, 1, m => m.Parameters.Single().Type == m.TypeParameters.Single()), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(!!0)"); + } + + [TestMethod] + public void Overloads7() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U]()"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1"); + } + + [TestMethod] + public void Overloads8() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U,T]()"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 2), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`2"); + } + + [TestMethod] + public void Overloads9() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](U[])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, 1, + m => m.Parameters.Single().Type is IArrayTypeSymbol arrayType && + arrayType.Rank == 1 && + arrayType.ElementType == m.TypeParameters.Single()), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(!!0[])"); + } + + [TestMethod] + public void Overloads10() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](U[][])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, 1, + m => m.Parameters.Single().Type is IArrayTypeSymbol arrayType && + arrayType.Rank == 1 && + arrayType.ElementType is IArrayTypeSymbol innerArrayType && + innerArrayType.Rank == 1 && + innerArrayType.ElementType == m.TypeParameters.Single()), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(!!0[][])"); + } + + [TestMethod] + public void Overloads11() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](U[,])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, 1, + m => m.Parameters.Single().Type is IArrayTypeSymbol arrayType && + arrayType.Rank == 2 && + arrayType.ElementType == m.TypeParameters.Single()), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(!!0[,])"); + } + + [TestMethod] + public void Overloads12() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](U[,,])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, 1, + m => m.Parameters.Single().Type is IArrayTypeSymbol arrayType && + arrayType.Rank == 3 && + arrayType.ElementType == m.TypeParameters.Single()), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(!!0[,,])"); + } + + [TestMethod] + public void Overloads13() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var @int = _compilation.GetSpecialType(SpecialType.System_Int32); + var listInt = _compilation.GetTypeByMetadataName("System.Collections.Generic.List`1").Construct(@int); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](System.Collections.Generic.List`1[System.Int32])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, listInt), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(System.Collections.Generic.List`1)"); + } + + [TestMethod] + public void Overloads14() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var list = _compilation.GetTypeByMetadataName("System.Collections.Generic.List`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](System.Collections.Generic.List`1[U])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, 1, + m => + m.Parameters.Single().Type is INamedTypeSymbol p && + p.OriginalDefinition == list && + p.TypeArguments.Single() == m.TypeParameters.Single()), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(System.Collections.Generic.List`1)"); + } + + [TestMethod] + public void Overloads15() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var tuple2 = _compilation.GetTypeByMetadataName("System.Tuple`2"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U,V](System.Tuple`2[U,V], System.Tuple`2[V,U])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 2, 2, + m => + m.Parameters.First() is INamedTypeSymbol p1 && + p1.OriginalDefinition == tuple2 && + p1.TypeArguments.SequenceEqual(m.TypeParameters) && + m.Parameters.Last() is INamedTypeSymbol p2 && + p2.OriginalDefinition == tuple2 && + p2.TypeArguments.SequenceEqual(m.TypeParameters.Reverse())), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`2(System.Tuple`2,System.Tuple`2)"); + } + + [TestMethod] + public void Overloads16() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var tuple1 = _compilation.GetTypeByMetadataName("System.Tuple`1"); + var tuple2 = _compilation.GetTypeByMetadataName("System.Tuple`2"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(System.Tuple`1[System.Tuple`2[System.String[,],System.Int32]])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 0, 1, + m => + m.Parameters.Single().Type is INamedTypeSymbol p && + p.OriginalDefinition == tuple1 && + p.TypeArguments.Single() is INamedTypeSymbol t && + t.OriginalDefinition == tuple2), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0(System.Tuple`1>)"); + } + + [TestMethod] + public void Overloads17() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var tuple1 = _compilation.GetTypeByMetadataName("System.Tuple`1"); + var tuple2 = _compilation.GetTypeByMetadataName("System.Tuple`2"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0(System.Tuple`2[System.Tuple`1[System.String],System.Tuple`1[System.Int32]])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 0, 1, + m => + m.Parameters.Single().Type is INamedTypeSymbol p && + p.OriginalDefinition == tuple2 && + p.TypeArguments.All(t => t.OriginalDefinition == tuple1)), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0(System.Tuple`2,System.Tuple`1>)"); + } + + [TestMethod] + public void Overloads18() + { + var overloads = _compilation.GetTypeByMetadataName("TestClasses.Overloads"); + var tuple1 = _compilation.GetTypeByMetadataName("System.Tuple`1"); + + VerifyRoundTrip( + methodInfo: typeof(TestClasses.Overloads).FindMethod("Void Overload0[U](System.Tuple`1[System.Tuple`1[TestClasses.Outer`1+Inner`1[U,U]]])"), + containingTypeSymbol: overloads, + methodSymbol: overloads.FindMethod("Overload0", 1, 1, + m => + m.Parameters.Single().Type is INamedTypeSymbol p && + p.OriginalDefinition == tuple1 && + p.TypeArguments.Single() is INamedTypeSymbol t && + t.OriginalDefinition == tuple1), + fullTypeName: "TestClasses.Overloads", + fullMethodName: "Overload0`1(System.Tuple`1>>)"); + } + + #region Helpers + private void VerifyRoundTrip( + MethodInfo methodInfo, + INamedTypeSymbol containingTypeSymbol, + IMethodSymbol methodSymbol, + string fullTypeName, + string fullMethodName) + { + VerifyRoundTripFromMethodInfo(methodInfo, fullTypeName, fullMethodName); + VerifyRoundTripFromName(fullTypeName, fullMethodName, methodInfo); + // VerifyRoundTripFromMethodSymbol(containingTypeSymbol, methodSymbol, fullTypeName, fullMethodName); + // VerifyRoundTripFromName(fullTypeName, fullMethodName, containingTypeSymbol, methodSymbol); + } + + private void VerifyRoundTripFromMethodInfo( + MethodInfo methodInfo, + string expectedFullTypeName, + string expectedFullMethodName) + { + // Generate the fqn for the Reflection MethodInfo + FullyQualifiedNameHelper.GetFullyQualifiedName(methodInfo, out var fullTypeName, out var fullMethodName); + + Assert.AreEqual(expectedFullTypeName, fullTypeName); + Assert.AreEqual(expectedFullMethodName, fullMethodName); + + // Lookup the Reflection MethodInfo using fullTypeName and fullMethodName + var roundTrippedMethodInfo = FullyQualifiedNameHelper.GetMethodFromFullyQualifiedName( + Assembly.GetExecutingAssembly(), + fullTypeName, + fullMethodName); + + Assert.AreEqual(methodInfo.MetadataToken, roundTrippedMethodInfo.MetadataToken); + } + + private void VerifyRoundTripFromName( + string fullTypeName, + string fullMethodName, + MethodInfo expectedMethodInfo) + { + // Lookup the Reflection MethodInfo using fullTypeName and fullMethodName + var methodInfo = FullyQualifiedNameHelper.GetMethodFromFullyQualifiedName( + Assembly.GetExecutingAssembly(), + fullTypeName, + fullMethodName); + + Assert.AreEqual(expectedMethodInfo.MetadataToken, methodInfo.MetadataToken); + + // Generate the fqn for the Reflection MethodInfo + FullyQualifiedNameHelper.GetFullyQualifiedName( + methodInfo, + out var roundTrippedFullTypeName, + out var roundTrippedFullMethodName); + + Assert.AreEqual(fullTypeName, roundTrippedFullTypeName); + Assert.AreEqual(fullMethodName, roundTrippedFullMethodName); + } + + // private void VerifyRoundTripFromMethodSymbol( + // INamedTypeSymbol containingTypeSymbol, + // IMethodSymbol methodSymbol, + // string expectedFullTypeName, + // string expectedFullMethodName) + // { + // // Generate the fqn for the Roslyn IMethodSymbol + // FullyQualifiedNameHelper.GetFullyQualifiedName( + // containingTypeSymbol, + // methodSymbol, + // out var fullTypeName, + // out var fullMethodName); + + // Assert.AreEqual(expectedFullTypeName, fullTypeName); + // Assert.AreEqual(expectedFullMethodName, fullMethodName); + + // // Lookup the Roslyn ITypeSymbol and IMethodSymbol using fullTypeName and fullMethodName + // var roundTrippedContainingTypeSymbol = _compilation.GetTypeByMetadataName(fullTypeName); + + // Assert.AreEqual(containingTypeSymbol.OriginalDefinition, roundTrippedContainingTypeSymbol.OriginalDefinition); + + // var roundTrippedMethodSymbol = FullyQualifiedNameHelper.GetMethodFromFullyQualifiedName( + // _compilation, + // fullTypeName, + // fullMethodName); + + // Assert.AreEqual(methodSymbol.OriginalDefinition, roundTrippedMethodSymbol.OriginalDefinition); + // } + + // private void VerifyRoundTripFromName( + // string fullTypeName, + // string fullMethodName, + // INamedTypeSymbol expectedContainingTypeSymbol, + // IMethodSymbol expectedMethodSymbol) + // { + // // Lookup the Roslyn ITypeSymbol and IMethodSymbol using fullTypeName and fullMethodName + // var containingTypeSymbol = _compilation.GetTypeByMetadataName(fullTypeName); + // + // Assert.AreEqual(expectedContainingTypeSymbol.OriginalDefinition, containingTypeSymbol.OriginalDefinition); + // + // var methodSymbol = FullyQualifiedNameHelper.GetMethodFromFullyQualifiedName( + // _compilation, + // fullTypeName, + // fullMethodName); + // + // Assert.AreEqual(expectedMethodSymbol.OriginalDefinition, methodSymbol.OriginalDefinition); + // + // // Generate the fqn for the Roslyn IMethodSymbol + // FullyQualifiedNameHelper.GetFullyQualifiedName( + // containingTypeSymbol, + // methodSymbol, + // out var roundTrippedFullTypeName, + // out var roundTrippedFullMethodName); + // + // Assert.AreEqual(fullTypeName, roundTrippedFullTypeName); + // Assert.AreEqual(fullMethodName, roundTrippedFullMethodName); + // } + #endregion + } +} diff --git a/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests.csproj b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests.csproj new file mode 100644 index 0000000000..58f8320dca --- /dev/null +++ b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests.csproj @@ -0,0 +1,30 @@ + + + + ..\..\ + true + + + + netcoreapp2.1 + Exe + Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests + true + 3.8.0-3.20427.2 + $(NoWarn);RS1024 + + + + + + + + + + + PreserveNewest + + + + + diff --git a/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/Program.cs b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/Program.cs new file mode 100644 index 0000000000..f512f67afb --- /dev/null +++ b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/Program.cs @@ -0,0 +1,12 @@ +// 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.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests +{ + public static class Program + { + public static void Main(string[] args) + { + } + } +} \ No newline at end of file diff --git a/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/TestClasses.cs b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/TestClasses.cs new file mode 100644 index 0000000000..f40b044ec0 --- /dev/null +++ b/test/Microsoft.TestPlatform.ObjectModel.FullyQualifiedNameUtilities.UnitTests/TestClasses.cs @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace TestClasses +{ + using System; + using System.Collections.Generic; + + internal class Outer + { + public void Method0() { } + public void Method1(int i) { } + public void Method2(List ls) { } + public void Method3(string p, int l) { } + internal class Inner + { + public void Method0() { } + public void Method1(int i) { } + public void Method2(int i) { } + public void Method3(int i) { } + } + } + + internal class OuterPrime : Outer { } + + internal class Outer + { + public void Method0() { } + public void Method1(T t) { } + public void Method2(U[] u) { } + public void Method3(T t, U u) { } + + internal class Inner + { + public void Method0() { } + public void Method1(T t) { } + public void Method2(V v) { } + public void Method3(T t, U u, V v) { } + public void Method4(X x, U u) { } + public void Method5(List x, U u) { } + + internal class MoreInner + { + public void Method0(T t, V v, I i, U u) { } + } + } + } + + internal class OuterPrime : Outer { } + + internal class OuterPrime : Outer { } + + internal class OuterString : Outer { } + + internal interface IImplementation + { + void ImplMethod0(); + void ImplMethod1(int i); + } + + internal class Impl : IImplementation + { + void IImplementation.ImplMethod0() { } + void IImplementation.ImplMethod1(int i) { } + } + + internal interface IImplementation + { + void ImplMethod0(); + void ImplMethod1(T t); + void ImplMethod2(T t, U u, string s); + } + + internal class Impl : IImplementation + { + void IImplementation.ImplMethod0() { } + void IImplementation.ImplMethod1(T t) { } + void IImplementation.ImplMethod2(T t, U u, string s) { } + } + + internal class Overloads + { + public void Overload0() { } + public void Overload0(int i) { } + public void Overload0(int i, Overloads c) { } + public unsafe void Overload0(int* p) { } + public void Overload0(dynamic d) { } + public void Overload0(U u) { } + public void Overload0() { } + public void Overload0() { } + public void Overload0(U[] u) { } + public void Overload0(U[][] u) { } + public void Overload0(U[,] u) { } + public void Overload0(U[,,] u) { } + public void Overload0(List l) { } + public void Overload0(List l) { } + public void Overload0(Tuple t0, Tuple t1) { } + public void Overload0(Tuple> t0) { } + public void Overload0(Tuple, Tuple> t) { } + public void Overload0(Tuple.Inner>> t) { } + } +}