-
Notifications
You must be signed in to change notification settings - Fork 254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: extract reflection behind a provider #3801
Merged
Merged
Changes from 16 commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
6fc0aa1
Abstrace some parts of reflection
nohwnd 99cb77e
some metadata through provider, but construction is still done via ct…
nohwnd e7ad398
Allow running in native with normal adapter
nohwnd d581268
allow-nativeaot-in-engine
nohwnd b983662
move so the hook works
nohwnd 28d61c7
Merge branch 'main' into extract-reflection
nohwnd 3a2e7f5
merges
nohwnd cff718e
Merge branch 'main' into extract-reflection
nohwnd e740ac4
Merge branch 'main' into extract-reflection
nohwnd 62cd127
Merge branch 'main' into extract-reflection
nohwnd 15d568a
main
nohwnd 4ef31e0
Merge branch 'main' into extract-reflection
nohwnd eb091a6
Fixes
nohwnd 1816090
fix
nohwnd dc2c58c
Fix various warnings
nohwnd 28c32cf
Merge branch 'fix-warnings' into extract-reflection
nohwnd a7382b4
Merge branch 'main' into extract-reflection
nohwnd 4bc35f9
Replace env variable with a static class
nohwnd d8c5ded
one test fixed....
nohwnd 8c1c18f
Fix tests
nohwnd f6749ed
Merge branch 'main' into extract-reflection
nohwnd afd042a
fix whitespace
nohwnd 3e731bb
Fix getting memebers for data driven tests
nohwnd a13acf1
Apply suggestions from code review
nohwnd ee723d9
Apply suggestions from code review
nohwnd 6ddaf12
Apply suggestions from code review
nohwnd 3bbaa27
seal and unpublish
nohwnd e59bb66
yeeey more whitespace
nohwnd 38de9e4
class
nohwnd 4188e16
uf
nohwnd fb1fa30
Update eng/Versions.props
nohwnd f2de560
Apply suggestions from code review
nohwnd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
172 changes: 172 additions & 0 deletions
172
src/Adapter/MSTest.TestAdapter/DynamicDataOperations.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
||
#if NET471_OR_GREATER || NETCOREAPP | ||
using System.Collections; | ||
using System.Runtime.CompilerServices; | ||
#endif | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Globalization; | ||
using System.Reflection; | ||
|
||
namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter; | ||
|
||
internal class DynamicDataOperations : IDynamicDataOperations | ||
nohwnd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
public IEnumerable<object[]> GetData(Type? _dynamicDataDeclaringType, DynamicDataSourceType _dynamicDataSourceType, string _dynamicDataSourceName, MethodInfo methodInfo) | ||
{ | ||
// Check if the declaring type of test data is passed in. If not, default to test method's class type. | ||
_dynamicDataDeclaringType ??= methodInfo.DeclaringType; | ||
DebugEx.Assert(_dynamicDataDeclaringType is not null, "Declaring type of test data cannot be null."); | ||
|
||
object? obj = null; | ||
|
||
switch (_dynamicDataSourceType) | ||
{ | ||
case DynamicDataSourceType.Property: | ||
PropertyInfo property = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredProperty(_dynamicDataDeclaringType, _dynamicDataSourceName) | ||
?? throw new ArgumentNullException($"{DynamicDataSourceType.Property} {_dynamicDataSourceName}"); | ||
if (property.GetGetMethod(true) is not { IsStatic: true }) | ||
{ | ||
throw new NotSupportedException( | ||
string.Format( | ||
CultureInfo.InvariantCulture, | ||
FrameworkMessages.DynamicDataInvalidPropertyLayout, | ||
property.DeclaringType?.FullName is { } typeFullName ? $"{typeFullName}.{property.Name}" : property.Name)); | ||
} | ||
|
||
obj = property.GetValue(null, null); | ||
break; | ||
|
||
case DynamicDataSourceType.Method: | ||
MethodInfo method = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredMethod(_dynamicDataDeclaringType, _dynamicDataSourceName) | ||
?? throw new ArgumentNullException($"{DynamicDataSourceType.Method} {_dynamicDataSourceName}"); | ||
if (!method.IsStatic | ||
|| method.ContainsGenericParameters | ||
|| method.GetParameters().Length > 0) | ||
{ | ||
throw new NotSupportedException( | ||
string.Format( | ||
CultureInfo.InvariantCulture, | ||
FrameworkMessages.DynamicDataInvalidPropertyLayout, | ||
method.DeclaringType?.FullName is { } typeFullName ? $"{typeFullName}.{method.Name}" : method.Name)); | ||
} | ||
|
||
obj = method.Invoke(null, null); | ||
break; | ||
} | ||
|
||
if (obj == null) | ||
{ | ||
throw new ArgumentNullException( | ||
string.Format( | ||
CultureInfo.InvariantCulture, | ||
FrameworkMessages.DynamicDataValueNull, | ||
_dynamicDataSourceName, | ||
_dynamicDataDeclaringType.FullName)); | ||
} | ||
|
||
if (!TryGetData(obj, out IEnumerable<object[]>? data)) | ||
{ | ||
throw new ArgumentNullException( | ||
string.Format( | ||
CultureInfo.InvariantCulture, | ||
FrameworkMessages.DynamicDataIEnumerableNull, | ||
_dynamicDataSourceName, | ||
_dynamicDataDeclaringType.FullName)); | ||
} | ||
|
||
if (!data.Any()) | ||
{ | ||
throw new ArgumentException( | ||
string.Format( | ||
CultureInfo.InvariantCulture, | ||
FrameworkMessages.DynamicDataIEnumerableEmpty, | ||
_dynamicDataSourceName, | ||
_dynamicDataDeclaringType.FullName)); | ||
} | ||
|
||
// Data is valid, return it. | ||
return data; | ||
} | ||
|
||
/// <inheritdoc /> | ||
public string? GetDisplayName(string? DynamicDataDisplayName, Type? DynamicDataDisplayNameDeclaringType, MethodInfo methodInfo, object?[]? data) | ||
{ | ||
if (DynamicDataDisplayName != null) | ||
{ | ||
Type? dynamicDisplayNameDeclaringType = DynamicDataDisplayNameDeclaringType ?? methodInfo.DeclaringType; | ||
DebugEx.Assert(dynamicDisplayNameDeclaringType is not null, "Declaring type of test data cannot be null."); | ||
|
||
MethodInfo method = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredMethod(dynamicDisplayNameDeclaringType, DynamicDataDisplayName) | ||
?? throw new ArgumentNullException($"{DynamicDataSourceType.Method} {DynamicDataDisplayName}"); | ||
ParameterInfo[] parameters = method.GetParameters(); | ||
return parameters.Length != 2 || | ||
parameters[0].ParameterType != typeof(MethodInfo) || | ||
parameters[1].ParameterType != typeof(object[]) || | ||
method.ReturnType != typeof(string) || | ||
!method.IsStatic || | ||
!method.IsPublic | ||
? throw new ArgumentNullException( | ||
string.Format( | ||
CultureInfo.InvariantCulture, | ||
FrameworkMessages.DynamicDataDisplayName, | ||
DynamicDataDisplayName, | ||
nameof(String), | ||
string.Join(", ", nameof(MethodInfo), typeof(object[]).Name))) | ||
: method.Invoke(null, [methodInfo, data]) as string; | ||
} | ||
|
||
if (data != null) | ||
{ | ||
// We want to force call to `data.AsEnumerable()` to ensure that objects are casted to strings (using ToString()) | ||
// so that null do appear as "null". If you remove the call, and do string.Join(",", new object[] { null, "a" }), | ||
// you will get empty string while with the call you will get "null,a". | ||
return string.Format(CultureInfo.CurrentCulture, FrameworkMessages.DataDrivenResultDisplayName, methodInfo.Name, | ||
string.Join(",", data.AsEnumerable())); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private static bool TryGetData(object dataSource, [NotNullWhen(true)] out IEnumerable<object[]>? data) | ||
{ | ||
if (dataSource is IEnumerable<object[]> enumerableObjectArray) | ||
{ | ||
data = enumerableObjectArray; | ||
return true; | ||
} | ||
|
||
#if NETCOREAPP || NET471_OR_GREATER | ||
if (dataSource is IEnumerable enumerable) | ||
{ | ||
List<object[]> objects = new(); | ||
foreach (object? entry in enumerable) | ||
{ | ||
if (entry is not ITuple tuple | ||
|| (objects.Count > 0 && objects[^1].Length != tuple.Length)) | ||
{ | ||
data = null; | ||
return false; | ||
} | ||
|
||
object[] array = new object[tuple.Length]; | ||
for (int i = 0; i < tuple.Length; i++) | ||
{ | ||
array[i] = tuple[i]!; | ||
} | ||
|
||
objects.Add(array); | ||
} | ||
|
||
data = objects; | ||
return true; | ||
} | ||
#endif | ||
|
||
data = null; | ||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will go away before merge, but I need it for local development, and I expect some changes will be needed.