From b90275f5a01f885a37387f9b5c678c16a56fb891 Mon Sep 17 00:00:00 2001 From: John Salem Date: Wed, 12 Dec 2018 14:32:17 -0800 Subject: [PATCH] Expose `Iscollectible` property on Assembly and MemberInfo (dotnet/corefx#33979) * Expose IsCollectible on MemberInfo * Adding skeleton for testing IsCollectible property on MemberInfo/MethodInfo * Add test for generic tests being loaded using Assembly.LoadFrom * Expose IsCollectible on Systme.Reflection.Assembly * Adding tests for generics with type parameters from collectible assembly * Rename test class to be more general * Removing unnecessary comments * Add test skips for uapaot * Add missing Dispose() to tests * Fix typos and add framework exclusion for NetFx * Simplify TestAssemblyLoadContext.Load() per feedback * Finish simplification of TestAssemblyLoadContext and added statics to tests * Prevent IsCollectible tests from compiling on netfx Commit migrated from https://github.com/dotnet/corefx/commit/d38db578d8a611f28a62de1005a9299d199bf5a9 --- src/libraries/System.Runtime/ref/System.Runtime.cs | 2 + .../tests/System.Runtime.Tests.csproj | 4 + .../tests/System/Reflection/IsCollectibleTests.cs | 219 +++++++++++++++++++++ .../TestCollectibleAssembly/Configurations.props | 8 + .../TestCollectibleAssembly.cs | 31 +++ .../TestCollectibleAssembly.csproj | 10 + 6 files changed, 274 insertions(+) create mode 100644 src/libraries/System.Runtime/tests/System/Reflection/IsCollectibleTests.cs create mode 100644 src/libraries/System.Runtime/tests/TestCollectibleAssembly/Configurations.props create mode 100644 src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.cs create mode 100644 src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.csproj diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 39de1a1..a778cf9 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -5273,6 +5273,7 @@ namespace System.Reflection public virtual System.Collections.Generic.IEnumerable Modules { get { throw null; } } public virtual bool ReflectionOnly { get { throw null; } } public virtual System.Security.SecurityRuleSet SecurityRuleSet { get { throw null; } } + public virtual bool IsCollectible { get { throw null; } } public virtual event System.Reflection.ModuleResolveEventHandler ModuleResolve { add { } remove { } } public object CreateInstance(string typeName) { throw null; } public object CreateInstance(string typeName, bool ignoreCase) { throw null; } @@ -5856,6 +5857,7 @@ namespace System.Reflection public virtual System.Reflection.Module Module { get { throw null; } } public abstract string Name { get; } public abstract System.Type ReflectedType { get; } + public virtual bool IsCollectible { get { throw null; } } public override bool Equals(object obj) { throw null; } public abstract object[] GetCustomAttributes(bool inherit); public abstract object[] GetCustomAttributes(System.Type attributeType, bool inherit); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index fac38f9..ffad656 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -244,6 +244,7 @@ + @@ -297,6 +298,9 @@ {9F312D76-9AF1-4E90-B3B0-815A1EC6C346} TestLoadAssembly + + TestCollectibleAssembly + diff --git a/src/libraries/System.Runtime/tests/System/Reflection/IsCollectibleTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/IsCollectibleTests.cs new file mode 100644 index 0000000..251ac3a --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Reflection/IsCollectibleTests.cs @@ -0,0 +1,219 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.Loader; +using Xunit; + +namespace System.Reflection.Tests +{ + public class TestAssemblyLoadContext : AssemblyLoadContext + { + public TestAssemblyLoadContext() : base(true) {} + protected override Assembly Load(AssemblyName assemblyName) => null; + } + + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "AssemblyLoadContext not available in NetFx")] + [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Assembly.LoadFrom() is not supported on UapAot")] + public class IsCollectibleTests : RemoteExecutorTestBase + { + static public string asmNameString = "TestCollectibleAssembly"; + static public string asmPath = Path.Combine(Environment.CurrentDirectory, "TestCollectibleAssembly.dll"); + + static public Func assemblyResolver = (asmName) => + asmName.Name == asmNameString ? Assembly.LoadFrom(asmPath) : null; + + static public Func collectibleAssemblyResolver(AssemblyLoadContext alc) => + (asmName) => + asmName.Name == asmNameString ? alc.LoadFromAssemblyPath(asmPath) : null; + + static public Func typeResolver(bool shouldThrowIfNotFound) => + (asm, simpleTypeName, isCaseSensitive) => asm == null ? + Type.GetType(simpleTypeName, shouldThrowIfNotFound, isCaseSensitive) : + asm.GetType(simpleTypeName, shouldThrowIfNotFound, isCaseSensitive); + + [Fact] + public void Assembly_IsCollectibleFalse_WhenUsingAssemblyLoad() + { + RemoteInvoke(() => { + Assembly asm = Assembly.LoadFrom(asmPath); + + Assert.NotNull(asm); + + Assert.False(asm.IsCollectible); + + return SuccessExitCode; + }).Dispose(); + } + + [Fact] + public void Assembly_IsCollectibleTrue_WhenUsingAssemblyLoadContext() + { + RemoteInvoke(() => { + AssemblyLoadContext alc = new TestAssemblyLoadContext(); + + Assembly asm = alc.LoadFromAssemblyPath(asmPath); + + Assert.NotNull(asm); + + Assert.True(asm.IsCollectible); + + return SuccessExitCode; + }).Dispose(); + } + + [Theory] + [InlineData("MyField")] + [InlineData("MyProperty")] + [InlineData("MyMethod")] + [InlineData("MyGenericMethod")] + [InlineData("MyStaticMethod")] + [InlineData("MyStaticField")] + [InlineData("MyStaticGenericMethod")] + public void MemberInfo_IsCollectibleFalse_WhenUsingAssemblyLoad(string memberName) + { + RemoteInvoke((marshalledName) => + { + Type t1 = Type.GetType( + "TestCollectibleAssembly.MyTestClass, TestCollectibleAssembly, Version=1.0.0.0", + assemblyResolver, + typeResolver(false), + true + ); + + Assert.NotNull(t1); + + var member = t1.GetMember(marshalledName).FirstOrDefault(); + + Assert.NotNull(member); + + Assert.False(member.IsCollectible); + + return SuccessExitCode; + }, memberName).Dispose(); + } + + [Theory] + [InlineData("MyStaticGenericField")] + [InlineData("MyStaticField")] + [InlineData("MyStaticGenericMethod")] + [InlineData("MyStaticMethod")] + [InlineData("MyGenericField")] + [InlineData("MyGenericProperty")] + [InlineData("MyGenericMethod")] + public void MemberInfoGeneric_IsCollectibleFalse_WhenUsingAssemblyLoad(string memberName) + { + RemoteInvoke((marshalledName) => + { + Type t1 = Type.GetType( + "TestCollectibleAssembly.MyGenericTestClass`1[System.Int32], TestCollectibleAssembly, Version=1.0.0.0", + assemblyResolver, + typeResolver(false), + true + ); + + Assert.NotNull(t1); + + var member = t1.GetMember(marshalledName).FirstOrDefault(); + + Assert.NotNull(member); + + Assert.False(member.IsCollectible); + + return SuccessExitCode; + }, memberName).Dispose(); + } + + [Theory] + [InlineData("MyField")] + [InlineData("MyProperty")] + [InlineData("MyMethod")] + [InlineData("MyGenericMethod")] + [InlineData("MyStaticMethod")] + [InlineData("MyStaticField")] + [InlineData("MyStaticGenericMethod")] + public void MemberInfo_IsCollectibleTrue_WhenUsingAssemblyLoadContext(string memberName) + { + RemoteInvoke((marshalledName) => + { + AssemblyLoadContext alc = new TestAssemblyLoadContext(); + + Type t1 = Type.GetType( + "TestCollectibleAssembly.MyTestClass, TestCollectibleAssembly, Version=1.0.0.0", + collectibleAssemblyResolver(alc), + typeResolver(false), + true + ); + + Assert.NotNull(t1); + + var member = t1.GetMember(marshalledName).FirstOrDefault(); + + Assert.NotNull(member); + + Assert.True(member.IsCollectible); + + return SuccessExitCode; + }, memberName).Dispose(); + } + + [Theory] + [InlineData("MyStaticGenericField")] + [InlineData("MyStaticField")] + [InlineData("MyStaticGenericMethod")] + [InlineData("MyStaticMethod")] + [InlineData("MyGenericField")] + [InlineData("MyGenericProperty")] + [InlineData("MyGenericMethod")] + public void MemberInfoGeneric_IsCollectibleTrue_WhenUsingAssemblyLoadContext(string memberName) + { + RemoteInvoke((marshalledName) => + { + AssemblyLoadContext alc = new TestAssemblyLoadContext(); + + Type t1 = Type.GetType( + "TestCollectibleAssembly.MyGenericTestClass`1[System.Int32], TestCollectibleAssembly, Version=1.0.0.0", + collectibleAssemblyResolver(alc), + typeResolver(false), + true + ); + + Assert.NotNull(t1); + + var member = t1.GetMember(marshalledName).FirstOrDefault(); + + Assert.NotNull(member); + + Assert.True(member.IsCollectible); + + return SuccessExitCode; + }, memberName).Dispose(); + } + + [Fact] + public void GenericWithCollectibleTypeParameter_IsCollectibleTrue_WhenUsingAssemblyLoadContext() + { + RemoteInvoke(() => + { + AssemblyLoadContext alc = new TestAssemblyLoadContext(); + + Type t1 = Type.GetType( + "System.Collections.Generic.Dictionary`2[[System.Int32],[TestCollectibleAssembly.MyTestClass, TestCollectibleAssembly, Version=1.0.0.0]]", + collectibleAssemblyResolver(alc), + typeResolver(false), + true + ); + + Assert.NotNull(t1); + + Assert.True(t1.IsCollectible); + + return SuccessExitCode; + }).Dispose(); + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Runtime/tests/TestCollectibleAssembly/Configurations.props b/src/libraries/System.Runtime/tests/TestCollectibleAssembly/Configurations.props new file mode 100644 index 0000000..c398e42 --- /dev/null +++ b/src/libraries/System.Runtime/tests/TestCollectibleAssembly/Configurations.props @@ -0,0 +1,8 @@ + + + + + netstandard; + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.cs b/src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.cs new file mode 100644 index 0000000..6c41562 --- /dev/null +++ b/src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace TestCollectibleAssembly +{ + public class MyTestClass + { + public bool MyField = false; + public int MyProperty => 1; + public int MyMethod() { return 1 * 1; } + public T MyGenericMethod(T arg1) { return arg1; } + + public static int MyStaticField = 1; + public static int MyStaticMethod() { return 1 * 1; } + + public static T MyStaticGenericMethod(T arg1) { return arg1; } + } + + public class MyGenericTestClass + { + public T MyGenericField; + public T MyGenericProperty { get; set; } + public T MyGenericMethod(T arg1) { return arg1; } + + public static T MyStaticGenericField; + public static int MyStaticField =1; + public static int MyStaticMethod() { return 1 * 1; } + public static T MyStaticGenericMethod(T arg1) { return arg1; } + } +} \ No newline at end of file diff --git a/src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.csproj b/src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.csproj new file mode 100644 index 0000000..4de809e --- /dev/null +++ b/src/libraries/System.Runtime/tests/TestCollectibleAssembly/TestCollectibleAssembly.csproj @@ -0,0 +1,10 @@ + + + true + 1.0.0.0 + netstandard-Debug;netstandard-Release + + + + + \ No newline at end of file -- 2.7.4