Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/linker
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2017-05-09 17:50:55 +0300
committerGitHub <noreply@github.com>2017-05-09 17:50:55 +0300
commite3c3100f21b4afdcd5180d1c1dc61d24f1e09931 (patch)
treea500b72fdd0541253c5a4923fa26eb53ade4283d /linker
parente4dfcf006b0705aba6b204aab2d603b781c5fc44 (diff)
Test framework (#101)
Diffstat (limited to 'linker')
-rw-r--r--linker/Mono.Linker.Steps/MarkStep.cs29
-rw-r--r--linker/Mono.Linker.Steps/ResolveFromXmlStep.cs11
-rw-r--r--linker/Tests/Extensions/CecilExtensions.cs122
-rw-r--r--linker/Tests/Extensions/NiceIO.cs891
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs11
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs13
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs16
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs7
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs15
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs8
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs22
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs16
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs13
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs16
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs9
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/CoreLinkAttribute.cs13
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs7
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs13
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs13
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj64
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Advanced/DeadCodeElimination1.cs19
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Advanced/FieldThatOnlyGetsSetIsRemoved.cs21
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeIsKept.cs19
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInConstructorIsKept.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept.cs32
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInFieldIsKept.cs25
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInPropertySetterIsKept.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithUsedSetter.cs19
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedFieldIsKept.cs23
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedMethodIsKept.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedPropertyIsKept.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/ComplexNestedClassesHasUnusedRemoved.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/InterfaceMethodImplementedOnBaseClassDoesNotGetStripped.cs37
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/MultiLevelNestedClassesAllRemovedWhenNonUsed.cs19
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/NestedDelegateInvokeMethodsPreserved.cs24
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UninvokedInterfaceMemberGetsRemoved.cs24
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedClassGetsRemoved.cs10
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedFieldGetsRemoved.cs20
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedMethodGetsRemoved.cs22
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedNestedClassGetsRemoved.cs11
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertyGetsRemoved.cs20
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertySetterRemoved.cs17
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Basic/UsedPropertyIsKept.cs19
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/CoreLink/LinkingOfCoreLibrariesRemovesUnusedTypes.cs15
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/CorrectOverloadedMethodGetsStrippedInGenericClass.cs37
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/DerivedClassWithMethodOfSameNameAsBaseButDifferentNumberOfGenericParametersUnusedBaseWillGetStripped.cs30
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/GenericInstanceInterfaceMethodImplementedWithDifferentGenericArgumentNameDoesNotGetStripped.cs30
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameter.cs27
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase.cs31
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase2.cs31
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/OverrideWithAnotherVirtualMethodOfSameNameWithDifferentParameterType.cs34
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInGenericClassIsNotStripped.cs21
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInstanceInGenericClassIsNotStripped.cs21
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodWithNoParametersIsNotStripped.cs27
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/FieldsOfTypeMarkedSequentialLayoutAreNotRemoved.cs17
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/DefaultConstructorOfReturnTypeIsNotRemoved.cs22
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorIsRemoved.cs27
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs28
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesAreNotRemoved.cs23
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs23
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesWhenHasThisAreNotRemoved.cs21
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/DefaultConstructorOfReturnTypeIsNotRemoved.cs22
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorIsRemoved.cs27
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs28
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesAreNotRemoved.cs23
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs23
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Interop/UnusedTypeWithSequentialLayoutIsRemoved.cs15
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.cs72
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.xml6
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.cs17
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.xml7
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs21
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.xml7
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.cs14
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.xml5
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml10
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.cs14
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.xml5
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.cs85
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.xml5
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.cs66
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.xml7
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.cs74
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.xml5
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.xml8
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.cs50
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.xml5
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj140
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/References/ReferencesAreRemovedWhenAllUsagesAreRemoved.cs20
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticConstructorGetsRemoved.cs20
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticMethodGetsRemoved.cs23
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass2.cs29
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass3.cs26
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass4.cs30
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass5.cs29
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass6.cs38
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/HarderToDetectUnusedVirtualMethodGetsRemoved.cs30
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/TypeGetsMarkedThatImplementsAlreadyMarkedInterfaceMethod.cs35
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UnusedVirtualMethodRemoved.cs24
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UsedVirtualMethodNotRemoved.cs29
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsPerservedIfBaseMethodGetsInvoked.cs28
-rw-r--r--linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsStrippedIfImplementingMethodGetsInvokedDirectly.cs27
-rw-r--r--linker/Tests/Mono.Linker.Tests.csproj44
-rw-r--r--linker/Tests/Mono.Linker.Tests/AbstractLinkingTestFixture.cs167
-rw-r--r--linker/Tests/Mono.Linker.Tests/AbstractTestFixture.cs118
-rw-r--r--linker/Tests/Mono.Linker.Tests/AssemblyInfo.cs42
-rw-r--r--linker/Tests/Mono.Linker.Tests/IntegrationTestFixture.cs123
-rw-r--r--linker/Tests/Mono.Linker.Tests/LinkingTestFixture.cs67
-rw-r--r--linker/Tests/Mono.Linker.Tests/ResolveLinkedAssemblyStep.cs80
-rw-r--r--linker/Tests/Mono.Linker.Tests/XmlLinkingTestFixture.cs118
-rw-r--r--linker/Tests/TestCases/Integration/Crypto/Test.cs16
-rwxr-xr-xlinker/Tests/TestCases/Integration/Crypto/Test.exebin3072 -> 0 bytes
-rw-r--r--linker/Tests/TestCases/Linker/MultipleReferences/Bar.cs18
-rw-r--r--linker/Tests/TestCases/Linker/MultipleReferences/Baz.cs15
-rw-r--r--linker/Tests/TestCases/Linker/MultipleReferences/Foo.cs22
-rw-r--r--linker/Tests/TestCases/Linker/MultipleReferences/Program.cs23
-rw-r--r--linker/Tests/TestCases/Linker/Simple/Library.cs39
-rw-r--r--linker/Tests/TestCases/Linker/Simple/Program.cs18
-rw-r--r--linker/Tests/TestCases/Linker/VirtualCall/Library.cs27
-rw-r--r--linker/Tests/TestCases/Linker/VirtualCall/Library.dllbin3072 -> 0 bytes
-rw-r--r--linker/Tests/TestCases/Linker/VirtualCall/Makefile5
-rw-r--r--linker/Tests/TestCases/Linker/VirtualCall/Program.cs20
-rw-r--r--linker/Tests/TestCases/Linker/VirtualCall/Program.exebin3072 -> 0 bytes
-rw-r--r--linker/Tests/TestCases/MarkAttribute.cs9
-rw-r--r--linker/Tests/TestCases/NotLinkedAttribute.cs9
-rw-r--r--linker/Tests/TestCases/TestCase.cs42
-rw-r--r--linker/Tests/TestCases/TestCases.csproj69
-rw-r--r--linker/Tests/TestCases/TestDatabase.cs108
-rw-r--r--linker/Tests/TestCases/TestSuites.cs76
-rw-r--r--linker/Tests/TestCases/Xml/Generics/Library.cs61
-rw-r--r--linker/Tests/TestCases/Xml/Generics/desc.xml5
-rw-r--r--linker/Tests/TestCases/Xml/Interface/Library.cs29
-rw-r--r--linker/Tests/TestCases/Xml/Interface/desc.xml5
-rw-r--r--linker/Tests/TestCases/Xml/NestedNested/Library.cs19
-rw-r--r--linker/Tests/TestCases/Xml/NestedNested/desc.xml5
-rw-r--r--linker/Tests/TestCases/Xml/PreserveFieldsRequired/Library.cs35
-rw-r--r--linker/Tests/TestCases/Xml/PreserveFieldsRequired/desc.xml7
-rw-r--r--linker/Tests/TestCases/Xml/ReferenceInAttributes/LibLib.cs23
-rw-r--r--linker/Tests/TestCases/Xml/ReferenceInAttributes/Library.cs81
-rw-r--r--linker/Tests/TestCases/Xml/ReferenceInAttributes/desc.xml5
-rw-r--r--linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/Library.cs37
-rw-r--r--linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/desc.xml5
-rw-r--r--linker/Tests/TestCases/Xml/SimpleXml/Library.cs48
-rw-r--r--linker/Tests/TestCases/Xml/SimpleXml/desc.xml10
-rwxr-xr-xlinker/Tests/TestCases/Xml/XmlPattern/Library.cs36
-rwxr-xr-xlinker/Tests/TestCases/Xml/XmlPattern/desc.xml7
-rw-r--r--linker/Tests/TestCasesRunner/AssemblyChecker.cs323
-rw-r--r--linker/Tests/TestCasesRunner/ExpectationsProvider.cs12
-rw-r--r--linker/Tests/TestCasesRunner/LinkXmlHelpers.cs30
-rw-r--r--linker/Tests/TestCasesRunner/LinkedTestCaseResult.cs19
-rw-r--r--linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs42
-rw-r--r--linker/Tests/TestCasesRunner/LinkerDriver.cs8
-rw-r--r--linker/Tests/TestCasesRunner/ManagedCompilationResult.cs15
-rw-r--r--linker/Tests/TestCasesRunner/ObjectFactory.cs31
-rw-r--r--linker/Tests/TestCasesRunner/ResultChecker.cs62
-rw-r--r--linker/Tests/TestCasesRunner/TestCaseCollector.cs125
-rw-r--r--linker/Tests/TestCasesRunner/TestCaseCompiler.cs41
-rw-r--r--linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs5
-rw-r--r--linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs75
-rw-r--r--linker/Tests/TestCasesRunner/TestCaseSandbox.cs83
-rw-r--r--linker/Tests/TestCasesRunner/TestRunner.cs78
-rw-r--r--linker/Tests/Tests/PreserveActionComparisonTests.cs30
164 files changed, 4713 insertions, 1445 deletions
diff --git a/linker/Mono.Linker.Steps/MarkStep.cs b/linker/Mono.Linker.Steps/MarkStep.cs
index b0c5025c5..d92d06ad1 100644
--- a/linker/Mono.Linker.Steps/MarkStep.cs
+++ b/linker/Mono.Linker.Steps/MarkStep.cs
@@ -1124,7 +1124,7 @@ namespace Mono.Linker.Steps {
MarkMethods (type);
break;
case TypePreserve.Fields:
- MarkFields (type, true);
+ MarkFields (type, true, true);
break;
case TypePreserve.Methods:
MarkMethods (type);
@@ -1150,7 +1150,7 @@ namespace Mono.Linker.Steps {
MarkMethodCollection (list);
}
- protected void MarkFields (TypeDefinition type, bool includeStatic)
+ protected void MarkFields (TypeDefinition type, bool includeStatic, bool markBackingFieldsOnlyIfPropertyMarked = false)
{
if (!type.HasFields)
return;
@@ -1158,10 +1158,35 @@ namespace Mono.Linker.Steps {
foreach (FieldDefinition field in type.Fields) {
if (!includeStatic && field.IsStatic)
continue;
+
+ if (markBackingFieldsOnlyIfPropertyMarked && field.Name.EndsWith (">k__BackingField")) {
+ // We can't reliably construct the expected property name from the backing field name for all compilers
+ // because csc shortens the name of the backing field in some cases
+ // For example:
+ // Field Name = <IFoo<int>.Bar>k__BackingField
+ // Property Name = IFoo<System.Int32>.Bar
+ //
+ // instead we will search the properties and find the one that makes use of the current backing field
+ var propertyDefinition = SearchPropertiesForMatchingFieldDefinition (field);
+ if (propertyDefinition != null && !Annotations.IsMarked (propertyDefinition))
+ continue;
+ }
MarkField (field);
}
}
+ static PropertyDefinition SearchPropertiesForMatchingFieldDefinition (FieldDefinition field)
+ {
+ foreach (var property in field.DeclaringType.Properties) {
+ foreach (var ins in property.GetMethod.Body.Instructions) {
+ if (ins.Operand != null && ins.Operand == field)
+ return property;
+ }
+ }
+
+ return null;
+ }
+
protected void MarkStaticFields(TypeDefinition type)
{
if (!type.HasFields)
diff --git a/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs b/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs
index 948e98649..582069911 100644
--- a/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs
+++ b/linker/Mono.Linker.Steps/ResolveFromXmlStep.cs
@@ -223,15 +223,8 @@ namespace Mono.Linker.Steps {
}
}
- switch (preserve) {
- case TypePreserve.Nothing:
- if (!nav.HasChildren)
- Annotations.SetPreserve (type, TypePreserve.All);
- break;
- default:
+ if (preserve != TypePreserve.Nothing)
Annotations.SetPreserve (type, preserve);
- break;
- }
if (nav.HasChildren) {
MarkSelectedFields (nav, type);
@@ -261,7 +254,7 @@ namespace Mono.Linker.Steps {
{
string attribute = GetAttribute (nav, _preserve);
if (attribute == null || attribute.Length == 0)
- return TypePreserve.Nothing;
+ return nav.HasChildren ? TypePreserve.Nothing : TypePreserve.All;
try {
return (TypePreserve) Enum.Parse (typeof (TypePreserve), attribute, true);
diff --git a/linker/Tests/Extensions/CecilExtensions.cs b/linker/Tests/Extensions/CecilExtensions.cs
new file mode 100644
index 000000000..747abf570
--- /dev/null
+++ b/linker/Tests/Extensions/CecilExtensions.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Mono.Cecil;
+
+namespace Mono.Linker.Tests.Extensions {
+ public static class CecilExtensions {
+ public static IEnumerable<TypeDefinition> AllDefinedTypes (this AssemblyDefinition assemblyDefinition)
+ {
+ return assemblyDefinition.Modules.SelectMany (m => m.AllDefinedTypes ());
+ }
+
+ public static IEnumerable<TypeDefinition> AllDefinedTypes (this ModuleDefinition moduleDefinition)
+ {
+ foreach (var typeDefinition in moduleDefinition.Types) {
+ yield return typeDefinition;
+
+ foreach (var definition in typeDefinition.AllDefinedTypes ())
+ yield return definition;
+ }
+ }
+
+ public static IEnumerable<TypeDefinition> AllDefinedTypes (this TypeDefinition typeDefinition)
+ {
+ foreach (var nestedType in typeDefinition.NestedTypes) {
+ yield return nestedType;
+
+ foreach (var definition in nestedType.AllDefinedTypes ())
+ yield return definition;
+ }
+ }
+
+ public static IEnumerable<IMemberDefinition> AllMembers (this ModuleDefinition module)
+ {
+ foreach (var type in module.AllDefinedTypes ()) {
+ yield return type;
+
+ foreach (var member in type.AllMembers ())
+ yield return member;
+ }
+ }
+
+ public static IEnumerable<IMemberDefinition> AllMembers (this TypeDefinition type)
+ {
+ foreach (var field in type.Fields)
+ yield return field;
+
+ foreach (var prop in type.Properties)
+ yield return prop;
+
+ foreach (var method in type.Methods)
+ yield return method;
+
+ foreach (var @event in type.Events)
+ yield return @event;
+ }
+
+ public static bool HasAttribute (this ICustomAttributeProvider provider, string name)
+ {
+ return provider.CustomAttributes.Any (ca => ca.AttributeType.Name == name);
+ }
+
+ public static bool HasAttributeDerivedFrom (this ICustomAttributeProvider provider, string name)
+ {
+ return provider.CustomAttributes.Any (ca => ca.AttributeType.Resolve ().DerivesFrom (name));
+ }
+
+ public static bool DerivesFrom (this TypeDefinition type, string baseTypeName)
+ {
+ if (type.Name == baseTypeName)
+ return true;
+
+ if (type.BaseType == null)
+ return false;
+
+ if (type.BaseType.Name == baseTypeName)
+ return true;
+
+ return type.BaseType.Resolve ().DerivesFrom (baseTypeName);
+ }
+
+ public static PropertyDefinition GetPropertyDefinition (this MethodDefinition method)
+ {
+ if (!method.IsSetter && !method.IsGetter)
+ throw new ArgumentException ();
+
+ var propertyName = method.Name.Substring (4);
+ return method.DeclaringType.Properties.First (p => p.Name == propertyName);
+ }
+
+ public static string GetSignature (this MethodDefinition method)
+ {
+ var builder = new StringBuilder ();
+ builder.Append (method.Name);
+ if (method.HasGenericParameters) {
+ builder.Append ('<');
+
+ for (int i = 0; i < method.GenericParameters.Count - 1; i++)
+ builder.Append ($"{method.GenericParameters [i]},");
+
+ builder.Append ($"{method.GenericParameters [method.GenericParameters.Count - 1]}>");
+ }
+
+ builder.Append ("(");
+
+ if (method.HasParameters) {
+ for (int i = 0; i < method.Parameters.Count - 1; i++) {
+ // TODO: modifiers
+ // TODO: default values
+ builder.Append ($"{method.Parameters [i].ParameterType},");
+ }
+
+ builder.Append (method.Parameters [method.Parameters.Count - 1].ParameterType);
+ }
+
+ builder.Append (")");
+
+ return builder.ToString ();
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Extensions/NiceIO.cs b/linker/Tests/Extensions/NiceIO.cs
new file mode 100644
index 000000000..2bded17f1
--- /dev/null
+++ b/linker/Tests/Extensions/NiceIO.cs
@@ -0,0 +1,891 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace Mono.Linker.Tests.Extensions
+{
+ public class NPath : IEquatable<NPath>, IComparable
+ {
+ private static readonly StringComparison PathStringComparison = IsLinux() ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
+
+ private readonly string[] _elements;
+ private readonly bool _isRelative;
+ private readonly string _driveLetter;
+
+ #region construction
+
+ public NPath(string path)
+ {
+ if (path == null)
+ throw new ArgumentNullException();
+
+ path = ParseDriveLetter(path, out _driveLetter);
+
+ if (path == "/")
+ {
+ _isRelative = false;
+ _elements = new string[] { };
+ }
+ else
+ {
+ var split = path.Split('/', '\\');
+
+ _isRelative = _driveLetter == null && IsRelativeFromSplitString(split);
+
+ _elements = ParseSplitStringIntoElements(split.Where(s => s.Length > 0).ToArray());
+ }
+ }
+
+ private NPath(string[] elements, bool isRelative, string driveLetter)
+ {
+ _elements = elements;
+ _isRelative = isRelative;
+ _driveLetter = driveLetter;
+ }
+
+ private string[] ParseSplitStringIntoElements(IEnumerable<string> inputs)
+ {
+ var stack = new List<string>();
+
+ foreach (var input in inputs.Where(input => input.Length != 0))
+ {
+ if (input == ".")
+ {
+ if ((stack.Count > 0) && (stack.Last() != "."))
+ continue;
+ }
+ else if (input == "..")
+ {
+ if (HasNonDotDotLastElement(stack))
+ {
+ stack.RemoveAt(stack.Count - 1);
+ continue;
+ }
+ if (!_isRelative)
+ throw new ArgumentException("You cannot create a path that tries to .. past the root");
+ }
+ stack.Add(input);
+ }
+ return stack.ToArray();
+ }
+
+ private static bool HasNonDotDotLastElement(List<string> stack)
+ {
+ return stack.Count > 0 && stack[stack.Count - 1] != "..";
+ }
+
+ private string ParseDriveLetter(string path, out string driveLetter)
+ {
+ if (path.Length >= 2 && path[1] == ':')
+ {
+ driveLetter = path[0].ToString();
+ return path.Substring(2);
+ }
+
+ driveLetter = null;
+ return path;
+ }
+
+ private static bool IsRelativeFromSplitString(string[] split)
+ {
+ if (split.Length < 2)
+ return true;
+
+ return split[0].Length != 0 || !split.Any(s => s.Length > 0);
+ }
+
+ public NPath Combine(params string[] append)
+ {
+ return Combine(append.Select(a => new NPath(a)).ToArray());
+ }
+
+ public NPath Combine(params NPath[] append)
+ {
+ if (!append.All(p => p.IsRelative))
+ throw new ArgumentException("You cannot .Combine a non-relative path");
+
+ return new NPath(ParseSplitStringIntoElements(_elements.Concat(append.SelectMany(p => p._elements))), _isRelative, _driveLetter);
+ }
+
+ public NPath Parent
+ {
+ get
+ {
+ if (_elements.Length == 0)
+ throw new InvalidOperationException("Parent is called on an empty path");
+
+ var newElements = _elements.Take(_elements.Length - 1).ToArray();
+
+ return new NPath(newElements, _isRelative, _driveLetter);
+ }
+ }
+
+ public NPath RelativeTo(NPath path)
+ {
+ if (!IsChildOf(path))
+ {
+ if (!IsRelative && !path.IsRelative && _driveLetter != path._driveLetter)
+ throw new ArgumentException("Path.RelativeTo() was invoked with two paths that are on different volumes. invoked on: " + ToString() + " asked to be made relative to: " + path);
+
+ NPath commonParent = null;
+ foreach (var parent in RecursiveParents)
+ {
+ commonParent = path.RecursiveParents.FirstOrDefault(otherParent => otherParent == parent);
+
+ if (commonParent != null)
+ break;
+ }
+
+ if (commonParent == null)
+ throw new ArgumentException("Path.RelativeTo() was unable to find a common parent between " + ToString() + " and " + path);
+
+ if (IsRelative && path.IsRelative && commonParent.IsEmpty())
+ throw new ArgumentException("Path.RelativeTo() was invoked with two relative paths that do not share a common parent. Invoked on: " + ToString() + " asked to be made relative to: " + path);
+
+ var depthDiff = path.Depth - commonParent.Depth;
+ return new NPath(Enumerable.Repeat("..", depthDiff).Concat(_elements.Skip(commonParent.Depth)).ToArray(), true, null);
+ }
+
+ return new NPath(_elements.Skip(path._elements.Length).ToArray(), true, null);
+ }
+
+ public NPath ChangeExtension(string extension)
+ {
+ ThrowIfRoot();
+
+ var newElements = (string[])_elements.Clone();
+ newElements[newElements.Length - 1] = Path.ChangeExtension(_elements[_elements.Length - 1], WithDot(extension));
+ if (extension == string.Empty)
+ newElements[newElements.Length - 1] = newElements[newElements.Length - 1].TrimEnd('.');
+ return new NPath(newElements, _isRelative, _driveLetter);
+ }
+ #endregion construction
+
+ #region inspection
+
+ public bool IsRelative
+ {
+ get { return _isRelative; }
+ }
+
+ public string FileName
+ {
+ get
+ {
+ ThrowIfRoot();
+
+ return _elements.Last();
+ }
+ }
+
+ public string FileNameWithoutExtension
+ {
+ get { return Path.GetFileNameWithoutExtension(FileName); }
+ }
+
+ public IEnumerable<string> Elements
+ {
+ get { return _elements; }
+ }
+
+ public int Depth
+ {
+ get { return _elements.Length; }
+ }
+
+ public bool Exists(string append = "")
+ {
+ return Exists(new NPath(append));
+ }
+
+ public bool Exists(NPath append)
+ {
+ return FileExists(append) || DirectoryExists(append);
+ }
+
+ public bool DirectoryExists(string append = "")
+ {
+ return DirectoryExists(new NPath(append));
+ }
+
+ public bool DirectoryExists(NPath append)
+ {
+ return Directory.Exists(Combine(append).ToString());
+ }
+
+ public bool FileExists(string append = "")
+ {
+ return FileExists(new NPath(append));
+ }
+
+ public bool FileExists(NPath append)
+ {
+ return File.Exists(Combine(append).ToString());
+ }
+
+ public string ExtensionWithDot
+ {
+ get
+ {
+ if (IsRoot)
+ throw new ArgumentException("A root directory does not have an extension");
+
+ var last = _elements.Last();
+ var index = last.LastIndexOf(".");
+ if (index < 0) return String.Empty;
+ return last.Substring(index);
+ }
+ }
+
+ public string InQuotes()
+ {
+ return "\"" + ToString() + "\"";
+ }
+
+ public string InQuotes(SlashMode slashMode)
+ {
+ return "\"" + ToString(slashMode) + "\"";
+ }
+
+ public override string ToString()
+ {
+ return ToString(SlashMode.Native);
+ }
+
+ public string ToString(SlashMode slashMode)
+ {
+ // Check if it's linux root /
+ if (IsRoot && string.IsNullOrEmpty(_driveLetter))
+ return Slash(slashMode).ToString();
+
+ if (_isRelative && _elements.Length == 0)
+ return ".";
+
+ var sb = new StringBuilder();
+ if (_driveLetter != null)
+ {
+ sb.Append(_driveLetter);
+ sb.Append(":");
+ }
+ if (!_isRelative)
+ sb.Append(Slash(slashMode));
+ var first = true;
+ foreach (var element in _elements)
+ {
+ if (!first)
+ sb.Append(Slash(slashMode));
+
+ sb.Append(element);
+ first = false;
+ }
+ return sb.ToString();
+ }
+
+ static char Slash(SlashMode slashMode)
+ {
+ switch (slashMode)
+ {
+ case SlashMode.Backward:
+ return '\\';
+ case SlashMode.Forward:
+ return '/';
+ default:
+ return Path.DirectorySeparatorChar;
+ }
+ }
+
+ public override bool Equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
+ // If parameter cannot be cast to Point return false.
+ var p = obj as NPath;
+ if ((Object)p == null)
+ return false;
+
+ return Equals(p);
+ }
+
+ public bool Equals(NPath p)
+ {
+ if (p._isRelative != _isRelative)
+ return false;
+
+ if (!string.Equals(p._driveLetter, _driveLetter, PathStringComparison))
+ return false;
+
+ if (p._elements.Length != _elements.Length)
+ return false;
+
+ for (var i = 0; i != _elements.Length; i++)
+ if (!string.Equals(p._elements[i], _elements[i], PathStringComparison))
+ return false;
+
+ return true;
+ }
+
+ public static bool operator ==(NPath a, NPath b)
+ {
+ // If both are null, or both are same instance, return true.
+ if (ReferenceEquals(a, b))
+ return true;
+
+ // If one is null, but not both, return false.
+ if (((object)a == null) || ((object)b == null))
+ return false;
+
+ // Return true if the fields match:
+ return a.Equals(b);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ int hash = 17;
+ // Suitable nullity checks etc, of course :)
+ hash = hash * 23 + _isRelative.GetHashCode();
+ foreach (var element in _elements)
+ hash = hash * 23 + element.GetHashCode();
+ if (_driveLetter != null)
+ hash = hash * 23 + _driveLetter.GetHashCode();
+ return hash;
+ }
+ }
+
+ public int CompareTo(object obj)
+ {
+ if (obj == null)
+ return -1;
+
+ return this.ToString().CompareTo(((NPath)obj).ToString());
+ }
+
+ public static bool operator !=(NPath a, NPath b)
+ {
+ return !(a == b);
+ }
+
+ public bool HasExtension(params string[] extensions)
+ {
+ var extensionWithDotLower = ExtensionWithDot.ToLower();
+ return extensions.Any(e => WithDot(e).ToLower() == extensionWithDotLower);
+ }
+
+ private static string WithDot(string extension)
+ {
+ return extension.StartsWith(".") ? extension : "." + extension;
+ }
+
+ private bool IsEmpty()
+ {
+ return _elements.Length == 0;
+ }
+
+ public bool IsRoot
+ {
+ get { return _elements.Length == 0 && !_isRelative; }
+ }
+
+ #endregion inspection
+
+ #region directory enumeration
+
+ public IEnumerable<NPath> Files(string filter, bool recurse = false)
+ {
+ return Directory.GetFiles(ToString(), filter, recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).Select(s => new NPath(s));
+ }
+
+ public IEnumerable<NPath> Files(bool recurse = false)
+ {
+ return Files("*", recurse);
+ }
+
+ public IEnumerable<NPath> Contents(string filter, bool recurse = false)
+ {
+ return Files(filter, recurse).Concat(Directories(filter, recurse));
+ }
+
+ public IEnumerable<NPath> Contents(bool recurse = false)
+ {
+ return Contents("*", recurse);
+ }
+
+ public IEnumerable<NPath> Directories(string filter, bool recurse = false)
+ {
+ return Directory.GetDirectories(ToString(), filter, recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).Select(s => new NPath(s));
+ }
+
+ public IEnumerable<NPath> Directories(bool recurse = false)
+ {
+ return Directories("*", recurse);
+ }
+
+ #endregion
+
+ #region filesystem writing operations
+ public NPath CreateFile()
+ {
+ ThrowIfRelative();
+ ThrowIfRoot();
+ EnsureParentDirectoryExists();
+ File.WriteAllBytes(ToString(), new byte[0]);
+ return this;
+ }
+
+ public NPath CreateFile(string file)
+ {
+ return CreateFile(new NPath(file));
+ }
+
+ public NPath CreateFile(NPath file)
+ {
+ if (!file.IsRelative)
+ throw new ArgumentException("You cannot call CreateFile() on an existing path with a non relative argument");
+ return Combine(file).CreateFile();
+ }
+
+ public NPath CreateDirectory()
+ {
+ ThrowIfRelative();
+
+ if (IsRoot)
+ throw new NotSupportedException("CreateDirectory is not supported on a root level directory because it would be dangerous:" + ToString());
+
+ Directory.CreateDirectory(ToString());
+ return this;
+ }
+
+ public NPath CreateDirectory(string directory)
+ {
+ return CreateDirectory(new NPath(directory));
+ }
+
+ public NPath CreateDirectory(NPath directory)
+ {
+ if (!directory.IsRelative)
+ throw new ArgumentException("Cannot call CreateDirectory with an absolute argument");
+
+ return Combine(directory).CreateDirectory();
+ }
+
+ public NPath Copy(string dest)
+ {
+ return Copy(new NPath(dest));
+ }
+
+ public NPath Copy(string dest, Func<NPath, bool> fileFilter)
+ {
+ return Copy(new NPath(dest), fileFilter);
+ }
+
+ public NPath Copy(NPath dest)
+ {
+ return Copy(dest, p => true);
+ }
+
+ public NPath Copy(NPath dest, Func<NPath, bool> fileFilter)
+ {
+ ThrowIfRelative();
+ if (dest.IsRelative)
+ dest = Parent.Combine(dest);
+
+ if (dest.DirectoryExists())
+ return CopyWithDeterminedDestination(dest.Combine(FileName), fileFilter);
+
+ return CopyWithDeterminedDestination(dest, fileFilter);
+ }
+
+ public NPath MakeAbsolute()
+ {
+ if (!IsRelative)
+ return this;
+
+ return NPath.CurrentDirectory.Combine(this);
+ }
+
+ NPath CopyWithDeterminedDestination(NPath absoluteDestination, Func<NPath, bool> fileFilter)
+ {
+ if (absoluteDestination.IsRelative)
+ throw new ArgumentException("absoluteDestination must be absolute");
+
+ if (FileExists())
+ {
+ if (!fileFilter(absoluteDestination))
+ return null;
+
+ absoluteDestination.EnsureParentDirectoryExists();
+
+ File.Copy(ToString(), absoluteDestination.ToString(), true);
+ return absoluteDestination;
+ }
+
+ if (DirectoryExists())
+ {
+ absoluteDestination.EnsureDirectoryExists();
+ foreach (var thing in Contents())
+ thing.CopyWithDeterminedDestination(absoluteDestination.Combine(thing.RelativeTo(this)), fileFilter);
+ return absoluteDestination;
+ }
+
+ throw new ArgumentException("Copy() called on path that doesnt exist: " + ToString());
+ }
+
+ public void Delete(DeleteMode deleteMode = DeleteMode.Normal)
+ {
+ ThrowIfRelative();
+
+ if (IsRoot)
+ throw new NotSupportedException("Delete is not supported on a root level directory because it would be dangerous:" + ToString());
+
+ if (FileExists())
+ File.Delete(ToString());
+ else if (DirectoryExists())
+ try
+ {
+ Directory.Delete(ToString(), true);
+ }
+ catch (IOException)
+ {
+ if (deleteMode == DeleteMode.Normal)
+ throw;
+ }
+ else
+ throw new InvalidOperationException("Trying to delete a path that does not exist: " + ToString());
+ }
+
+ public void DeleteIfExists(DeleteMode deleteMode = DeleteMode.Normal)
+ {
+ ThrowIfRelative();
+
+ if (FileExists() || DirectoryExists())
+ Delete(deleteMode);
+ }
+
+ public NPath DeleteContents()
+ {
+ ThrowIfRelative();
+
+ if (IsRoot)
+ throw new NotSupportedException("DeleteContents is not supported on a root level directory because it would be dangerous:" + ToString());
+
+ if (FileExists())
+ throw new InvalidOperationException("It is not valid to perform this operation on a file");
+
+ if (DirectoryExists())
+ {
+ try
+ {
+ Files().Delete();
+ Directories().Delete();
+ }
+ catch (IOException)
+ {
+ if (Files(true).Any())
+ throw;
+ }
+
+ return this;
+ }
+
+ return EnsureDirectoryExists();
+ }
+
+ public static NPath CreateTempDirectory(string myprefix)
+ {
+ var random = new Random();
+ while (true)
+ {
+ var candidate = new NPath(Path.GetTempPath() + "/" + myprefix + "_" + random.Next());
+ if (!candidate.Exists())
+ return candidate.CreateDirectory();
+ }
+ }
+
+ public NPath Move(string dest)
+ {
+ return Move(new NPath(dest));
+ }
+
+ public NPath Move(NPath dest)
+ {
+ ThrowIfRelative();
+
+ if (IsRoot)
+ throw new NotSupportedException("Move is not supported on a root level directory because it would be dangerous:" + ToString());
+
+ if (dest.IsRelative)
+ return Move(Parent.Combine(dest));
+
+ if (dest.DirectoryExists())
+ return Move(dest.Combine(FileName));
+
+ if (FileExists())
+ {
+ dest.EnsureParentDirectoryExists();
+ File.Move(ToString(), dest.ToString());
+ return dest;
+ }
+
+ if (DirectoryExists())
+ {
+ Directory.Move(ToString(), dest.ToString());
+ return dest;
+ }
+
+ throw new ArgumentException("Move() called on a path that doesn't exist: " + ToString());
+ }
+
+ #endregion
+
+ #region special paths
+
+ public static NPath CurrentDirectory
+ {
+ get
+ {
+ return new NPath(Directory.GetCurrentDirectory());
+ }
+ }
+
+ public static NPath HomeDirectory
+ {
+ get
+ {
+ if (Path.DirectorySeparatorChar == '\\')
+ return new NPath(Environment.GetEnvironmentVariable("USERPROFILE"));
+ return new NPath(Environment.GetEnvironmentVariable("HOME"));
+ }
+ }
+
+ public static NPath SystemTemp
+ {
+ get
+ {
+ return new NPath(Path.GetTempPath());
+ }
+ }
+
+ #endregion
+
+ private void ThrowIfRelative()
+ {
+ if (_isRelative)
+ throw new ArgumentException("You are attempting an operation on a Path that requires an absolute path, but the path is relative");
+ }
+
+ private void ThrowIfRoot()
+ {
+ if (IsRoot)
+ throw new ArgumentException("You are attempting an operation that is not valid on a root level directory");
+ }
+
+ public NPath EnsureDirectoryExists(string append = "")
+ {
+ return EnsureDirectoryExists(new NPath(append));
+ }
+
+ public NPath EnsureDirectoryExists(NPath append)
+ {
+ var combined = Combine(append);
+ if (combined.DirectoryExists())
+ return combined;
+ combined.EnsureParentDirectoryExists();
+ combined.CreateDirectory();
+ return combined;
+ }
+
+ public NPath EnsureParentDirectoryExists()
+ {
+ var parent = Parent;
+ parent.EnsureDirectoryExists();
+ return parent;
+ }
+
+ public NPath FileMustExist()
+ {
+ if (!FileExists())
+ throw new FileNotFoundException("File was expected to exist : " + ToString());
+
+ return this;
+ }
+
+ public NPath DirectoryMustExist()
+ {
+ if (!DirectoryExists())
+ throw new DirectoryNotFoundException("Expected directory to exist : " + ToString());
+
+ return this;
+ }
+
+ public bool IsChildOf(string potentialBasePath)
+ {
+ return IsChildOf(new NPath(potentialBasePath));
+ }
+
+ public bool IsChildOf(NPath potentialBasePath)
+ {
+ if ((IsRelative && !potentialBasePath.IsRelative) || !IsRelative && potentialBasePath.IsRelative)
+ throw new ArgumentException("You can only call IsChildOf with two relative paths, or with two absolute paths");
+
+ // If the other path is the root directory, then anything is a child of it as long as it's not a Windows path
+ if (potentialBasePath.IsRoot)
+ {
+ if (_driveLetter != potentialBasePath._driveLetter)
+ return false;
+ return true;
+ }
+
+ if (IsEmpty())
+ return false;
+
+ if (Equals(potentialBasePath))
+ return true;
+
+ return Parent.IsChildOf(potentialBasePath);
+ }
+
+ public IEnumerable<NPath> RecursiveParents
+ {
+ get
+ {
+ var candidate = this;
+ while (true)
+ {
+ if (candidate.IsEmpty())
+ yield break;
+
+ candidate = candidate.Parent;
+ yield return candidate;
+ }
+ }
+ }
+
+ public NPath ParentContaining(string needle)
+ {
+ return ParentContaining(new NPath(needle));
+ }
+
+ public NPath ParentContaining(NPath needle)
+ {
+ ThrowIfRelative();
+
+ return RecursiveParents.FirstOrDefault(p => p.Exists(needle));
+ }
+
+ public NPath WriteAllText(string contents)
+ {
+ ThrowIfRelative();
+ EnsureParentDirectoryExists();
+ File.WriteAllText(ToString(), contents);
+ return this;
+ }
+
+ public string ReadAllText()
+ {
+ ThrowIfRelative();
+ return File.ReadAllText(ToString());
+ }
+
+ public NPath WriteAllLines(string[] contents)
+ {
+ ThrowIfRelative();
+ EnsureParentDirectoryExists();
+ File.WriteAllLines(ToString(), contents);
+ return this;
+ }
+
+ public string[] ReadAllLines()
+ {
+ ThrowIfRelative();
+ return File.ReadAllLines(ToString());
+ }
+
+ public IEnumerable<NPath> CopyFiles(NPath destination, bool recurse, Func<NPath, bool> fileFilter = null)
+ {
+ destination.EnsureDirectoryExists();
+ return Files(recurse).Where(fileFilter ?? AlwaysTrue).Select(file => file.Copy(destination.Combine(file.RelativeTo(this)))).ToArray();
+ }
+
+ public IEnumerable<NPath> MoveFiles(NPath destination, bool recurse, Func<NPath, bool> fileFilter = null)
+ {
+ if (IsRoot)
+ throw new NotSupportedException("MoveFiles is not supported on this directory because it would be dangerous:" + ToString());
+
+ destination.EnsureDirectoryExists();
+ return Files(recurse).Where(fileFilter ?? AlwaysTrue).Select(file => file.Move(destination.Combine(file.RelativeTo(this)))).ToArray();
+ }
+
+ static bool AlwaysTrue(NPath p)
+ {
+ return true;
+ }
+
+ private static bool IsLinux()
+ {
+ return Directory.Exists("/proc");
+ }
+ }
+
+ public static class Extensions
+ {
+ public static IEnumerable<NPath> Copy(this IEnumerable<NPath> self, string dest)
+ {
+ return Copy(self, new NPath(dest));
+ }
+
+ public static IEnumerable<NPath> Copy(this IEnumerable<NPath> self, NPath dest)
+ {
+ if (dest.IsRelative)
+ throw new ArgumentException("When copying multiple files, the destination cannot be a relative path");
+ dest.EnsureDirectoryExists();
+ return self.Select(p => p.Copy(dest.Combine(p.FileName))).ToArray();
+ }
+
+ public static IEnumerable<NPath> Move(this IEnumerable<NPath> self, string dest)
+ {
+ return Move(self, new NPath(dest));
+ }
+
+ public static IEnumerable<NPath> Move(this IEnumerable<NPath> self, NPath dest)
+ {
+ if (dest.IsRelative)
+ throw new ArgumentException("When moving multiple files, the destination cannot be a relative path");
+ dest.EnsureDirectoryExists();
+ return self.Select(p => p.Move(dest.Combine(p.FileName))).ToArray();
+ }
+
+ public static IEnumerable<NPath> Delete(this IEnumerable<NPath> self)
+ {
+ foreach (var p in self)
+ p.Delete();
+ return self;
+ }
+
+ public static IEnumerable<string> InQuotes(this IEnumerable<NPath> self, SlashMode forward = SlashMode.Native)
+ {
+ return self.Select(p => p.InQuotes(forward));
+ }
+
+ public static NPath ToNPath(this string path)
+ {
+ return new NPath(path);
+ }
+ }
+
+ public enum SlashMode
+ {
+ Native,
+ Forward,
+ Backward
+ }
+
+ public enum DeleteMode
+ {
+ Normal,
+ Soft
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs
new file mode 100644
index 000000000..47f0f3415
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/BaseExpectedLinkedBehaviorAttribute.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Diagnostics;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
+ /// <summary>
+ /// Base attribute for attributes that mark up the expected behavior of the linker on a member
+ /// </summary>
+ [Conditional("INCLUDE_EXPECTATIONS")]
+ public abstract class BaseExpectedLinkedBehaviorAttribute : Attribute {
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs
new file mode 100644
index 000000000..9d3cfacc7
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/IgnoreTestCaseAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
+ [AttributeUsage (AttributeTargets.Class)]
+ public class IgnoreTestCaseAttribute : Attribute {
+ public readonly string Reason;
+
+ public IgnoreTestCaseAttribute (string reason)
+ {
+ Reason = reason;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs
new file mode 100644
index 000000000..086304179
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAssemblyAttribute.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
+ /// <summary>
+ /// Verifies that an assembly does exist in the output directory
+ /// </summary>
+ [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)]
+ public class KeptAssemblyAttribute : KeptAttribute {
+ public readonly string FileName;
+
+ public KeptAssemblyAttribute (string fileName)
+ {
+ FileName = fileName;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs
new file mode 100644
index 000000000..837c97152
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttribute.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
+ [AttributeUsage (AttributeTargets.All, Inherited = false)]
+ public class KeptAttribute : BaseExpectedLinkedBehaviorAttribute {
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs
new file mode 100644
index 000000000..c183e62d2
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptAttributeAttribute.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ [AttributeUsage (AttributeTargets.All, AllowMultiple = true, Inherited = false)]
+ public class KeptAttributeAttribute : KeptAttribute
+ {
+ public readonly string AttributeName;
+
+ public KeptAttributeAttribute (string attributeName)
+ {
+ AttributeName = attributeName;
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs
new file mode 100644
index 000000000..a4160490a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBackingFieldAttribute.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
+ public sealed class KeptBackingFieldAttribute : KeptAttribute {
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs
new file mode 100644
index 000000000..ff1f2fa84
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptBaseTypeAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
+ public sealed class KeptBaseTypeAttribute : KeptAttribute
+ {
+ public readonly Type BaseType;
+ public readonly object [] GenericParameterNames;
+
+ public KeptBaseTypeAttribute (Type baseType)
+ {
+ BaseType = baseType;
+ }
+
+ public KeptBaseTypeAttribute (Type baseType, params object[] typeArguments)
+ {
+ BaseType = baseType;
+ GenericParameterNames = typeArguments;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs
new file mode 100644
index 000000000..5014bd23a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptInterfaceAttribute.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Diagnostics;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions
+{
+ [AttributeUsage (AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
+ public class KeptInterfaceAttribute : KeptAttribute
+ {
+ public readonly Type InterfaceType;
+
+ public KeptInterfaceAttribute (Type interfaceType)
+ {
+ InterfaceType = interfaceType;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs
new file mode 100644
index 000000000..00e55f266
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/KeptMemberAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
+ [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)]
+ public sealed class KeptMemberAttribute : KeptAttribute {
+ public readonly string Name;
+
+ public KeptMemberAttribute (string name)
+ {
+ Name = name;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs
new file mode 100644
index 000000000..4bb6a320a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Assertions/RemovedAssemblyAttribute.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
+ /// <summary>
+ /// Verifies that an assembly does not exist in the output directory
+ /// </summary>
+ [AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)]
+ public class RemovedAssemblyAttribute : BaseExpectedLinkedBehaviorAttribute {
+ public readonly string FileName;
+
+ public RemovedAssemblyAttribute (string fileName)
+ {
+ FileName = fileName;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs
new file mode 100644
index 000000000..d98584eab
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/BaseMetadataAttribute.cs
@@ -0,0 +1,9 @@
+using System;
+using System.Diagnostics;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Metadata
+{
+ [Conditional("INCLUDE_EXPECTATIONS")]
+ public abstract class BaseMetadataAttribute : Attribute {
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/CoreLinkAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/CoreLinkAttribute.cs
new file mode 100644
index 000000000..7529a6255
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/CoreLinkAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Metadata {
+ [AttributeUsage (AttributeTargets.Class)]
+ public class CoreLinkAttribute : BaseMetadataAttribute {
+ public readonly string Value;
+
+ public CoreLinkAttribute (string value)
+ {
+ Value = value;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs
new file mode 100644
index 000000000..11cd069c3
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/NotATestCaseAttribute.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Metadata {
+ [AttributeUsage (AttributeTargets.Class)]
+ public class NotATestCaseAttribute : BaseMetadataAttribute {
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs
new file mode 100644
index 000000000..0a37a2149
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/ReferenceAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Metadata {
+ [AttributeUsage (AttributeTargets.Class)]
+ public class ReferenceAttribute : BaseMetadataAttribute {
+ public readonly string Value;
+
+ public ReferenceAttribute (string value)
+ {
+ Value = value;
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs
new file mode 100644
index 000000000..805b1ac56
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Metadata/SandboxDependencyAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Mono.Linker.Tests.Cases.Expectations.Metadata {
+ [AttributeUsage (AttributeTargets.Class)]
+ public class SandboxDependencyAttribute : BaseMetadataAttribute {
+ public readonly string RelativePathToFile;
+
+ public SandboxDependencyAttribute (string relativePathToFile)
+ {
+ RelativePathToFile = relativePathToFile;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj
new file mode 100644
index 000000000..dfb15ba2a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{2C26601F-3E2F-45B9-A02F-58EE9296E19E}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Mono.Linker.Tests.Cases.Expectations</RootNamespace>
+ <AssemblyName>Mono.Linker.Tests.Cases.Expectations</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Assertions\IgnoreTestCaseAttribute.cs" />
+ <Compile Include="Assertions\KeptAssemblyAttribute.cs" />
+ <Compile Include="Assertions\KeptAttribute.cs" />
+ <Compile Include="Assertions\BaseExpectedLinkedBehaviorAttribute.cs" />
+ <Compile Include="Assertions\KeptBackingFieldAttribute.cs" />
+ <Compile Include="Assertions\KeptMemberAttribute.cs" />
+ <Compile Include="Assertions\RemovedAssemblyAttribute.cs" />
+ <Compile Include="Metadata\BaseMetadataAttribute.cs" />
+ <Compile Include="Metadata\CoreLinkAttribute.cs" />
+ <Compile Include="Metadata\NotATestCaseAttribute.cs" />
+ <Compile Include="Metadata\ReferenceAttribute.cs" />
+ <Compile Include="Metadata\SandboxDependencyAttribute.cs" />
+ <Compile Include="Assertions\KeptBaseTypeAttribute.cs" />
+ <Compile Include="Assertions\KeptInterfaceAttribute.cs" />
+ <Compile Include="Assertions\KeptAttributeAttribute.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Advanced/DeadCodeElimination1.cs b/linker/Tests/Mono.Linker.Tests.Cases/Advanced/DeadCodeElimination1.cs
new file mode 100644
index 000000000..339d223b6
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Advanced/DeadCodeElimination1.cs
@@ -0,0 +1,19 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Advanced {
+ [IgnoreTestCase ("We cannot do this yet")]
+ class DeadCodeElimination1 {
+ public static void Main ()
+ {
+ object o = null;
+ if (o is B)
+ ((B) o).Method ();
+ }
+
+ class B {
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Advanced/FieldThatOnlyGetsSetIsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Advanced/FieldThatOnlyGetsSetIsRemoved.cs
new file mode 100644
index 000000000..8c4933ad2
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Advanced/FieldThatOnlyGetsSetIsRemoved.cs
@@ -0,0 +1,21 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Advanced {
+ [IgnoreTestCase ("We cannot do this yet")]
+ class FieldThatOnlyGetsSetIsRemoved {
+ public static void Main ()
+ {
+ new B ().Method ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ public int _unused = 3;
+
+ [Kept]
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeIsKept.cs
new file mode 100644
index 000000000..887db4a00
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeIsKept.cs
@@ -0,0 +1,19 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ [Foo]
+ class AttributeOnPreservedTypeIsKept {
+ public static void Main ()
+ {
+ }
+
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ [Kept]
+ public FooAttribute ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInConstructorIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInConstructorIsKept.cs
new file mode 100644
index 000000000..1e810d3fa
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInConstructorIsKept.cs
@@ -0,0 +1,26 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ [Foo (typeof (A))]
+ class AttributeOnPreservedTypeWithTypeUsedInConstructorIsKept {
+ public static void Main ()
+ {
+ }
+
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ [Kept]
+ public FooAttribute (Type val)
+ {
+ }
+ }
+
+ [Kept]
+ class A {
+ public A ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept.cs
new file mode 100644
index 000000000..ff815a73b
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept.cs
@@ -0,0 +1,32 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace NamespaceForAttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept {
+ [Kept]
+ class A {
+ public A ()
+ {
+ }
+ }
+}
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ [Foo (typeof (NamespaceForAttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept.A))]
+ class AttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept {
+ public static void Main ()
+ {
+ }
+
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ [Kept]
+ public FooAttribute (Type val)
+ {
+ }
+ }
+
+ // This A is not used and should be removed
+ class A {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInFieldIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInFieldIsKept.cs
new file mode 100644
index 000000000..7721da824
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInFieldIsKept.cs
@@ -0,0 +1,25 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ [Foo (Val = typeof (A))]
+ class AttributeOnPreservedTypeWithTypeUsedInFieldIsKept {
+ public static void Main ()
+ {
+ }
+
+ [KeptMember(".ctor()")]
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ [Kept]
+ public Type Val;
+ }
+
+ [Kept]
+ class A {
+ public A ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInPropertySetterIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInPropertySetterIsKept.cs
new file mode 100644
index 000000000..fd5d66e1b
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithTypeUsedInPropertySetterIsKept.cs
@@ -0,0 +1,26 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ [Foo (Val = typeof (A))]
+ class AttributeOnPreservedTypeWithTypeUsedInPropertySetterIsKept {
+ public static void Main ()
+ {
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ [Kept]
+ [KeptBackingField]
+ public Type Val { get; [Kept] set; }
+ }
+
+ [Kept]
+ class A {
+ public A ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithUsedSetter.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithUsedSetter.cs
new file mode 100644
index 000000000..bf443dbc8
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnPreservedTypeWithUsedSetter.cs
@@ -0,0 +1,19 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ [Foo (Val = 1)]
+ class AttributeOnPreservedTypeWithUsedSetter {
+ public static void Main ()
+ {
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ [Kept]
+ [KeptBackingField]
+ public int Val { get; [Kept] set; }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedFieldIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedFieldIsKept.cs
new file mode 100644
index 000000000..c94848a00
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedFieldIsKept.cs
@@ -0,0 +1,23 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ class AttributeOnUsedFieldIsKept {
+ public static void Main ()
+ {
+ var val = new A ().field;
+ }
+
+ [KeptMember (".ctor()")]
+ class A {
+ [Kept]
+ [Foo] public int field;
+ }
+
+ [Kept]
+ [KeptMember(".ctor()")]
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedMethodIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedMethodIsKept.cs
new file mode 100644
index 000000000..c6e31bab6
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedMethodIsKept.cs
@@ -0,0 +1,26 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ class AttributeOnUsedMethodIsKept {
+ public static void Main ()
+ {
+ new A ().Method ();
+ }
+
+ [KeptMember (".ctor()")]
+ class A {
+ [Foo]
+ [Kept]
+ public void Method ()
+ {
+ }
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedPropertyIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedPropertyIsKept.cs
new file mode 100644
index 000000000..b6edc511b
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Attributes/AttributeOnUsedPropertyIsKept.cs
@@ -0,0 +1,26 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Attributes {
+ class AttributeOnUsedPropertyIsKept {
+ public static void Main ()
+ {
+ var val = new A ().Field;
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptMember ("get_Field()")]
+ class A {
+ [Kept]
+ [KeptBackingField]
+ [Foo]
+ public int Field { get; set; }
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (System.Attribute))]
+ class FooAttribute : Attribute {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/ComplexNestedClassesHasUnusedRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/ComplexNestedClassesHasUnusedRemoved.cs
new file mode 100644
index 000000000..fbdbee204
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/ComplexNestedClassesHasUnusedRemoved.cs
@@ -0,0 +1,26 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class ComplexNestedClassesHasUnusedRemoved {
+ public static void Main ()
+ {
+ new A.AB.ABD ();
+ }
+
+ [Kept]
+ public class A {
+ [Kept]
+ public class AB {
+ public class ABC {
+ }
+
+ [Kept]
+ [KeptMember(".ctor()")]
+ public class ABD {
+ public class ABDE {
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/InterfaceMethodImplementedOnBaseClassDoesNotGetStripped.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/InterfaceMethodImplementedOnBaseClassDoesNotGetStripped.cs
new file mode 100644
index 000000000..fa0b762a8
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/InterfaceMethodImplementedOnBaseClassDoesNotGetStripped.cs
@@ -0,0 +1,37 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class InterfaceMethodImplementedOnBaseClassDoesNotGetStripped {
+ public static void Main ()
+ {
+ I1 i1 = new Derived ();
+ i1.Used ();
+ }
+
+ public interface I1 {
+ void Unused ();
+
+ [Kept]
+ void Used ();
+ }
+
+ [KeptMember (".ctor()")]
+ public class Base {
+ public void Unused ()
+ {
+ }
+
+ [Kept]
+ public void Used ()
+ {
+ }
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (Base))]
+ [KeptInterface (typeof (I1))]
+ public class Derived : Base, I1 {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/MultiLevelNestedClassesAllRemovedWhenNonUsed.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/MultiLevelNestedClassesAllRemovedWhenNonUsed.cs
new file mode 100644
index 000000000..dd5f8628e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/MultiLevelNestedClassesAllRemovedWhenNonUsed.cs
@@ -0,0 +1,19 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class MultiLevelNestedClassesAllRemovedWhenNonUsed {
+ public static void Main ()
+ {
+ }
+
+ public class A {
+ public class AB {
+ public class ABC {
+ }
+
+ public class ABD {
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/NestedDelegateInvokeMethodsPreserved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/NestedDelegateInvokeMethodsPreserved.cs
new file mode 100644
index 000000000..c3e231781
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/NestedDelegateInvokeMethodsPreserved.cs
@@ -0,0 +1,24 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class NestedDelegateInvokeMethodsPreserved {
+ [Kept]
+ static B.Delegate @delegate;
+
+ static void Main ()
+ {
+ System.GC.KeepAlive (@delegate);
+ }
+
+ [Kept]
+ public class B {
+ [Kept]
+ [KeptMember ("Invoke()")]
+ [KeptMember ("BeginInvoke(System.AsyncCallback,System.Object)")]
+ [KeptMember ("EndInvoke(System.IAsyncResult)")]
+ [KeptMember (".ctor(System.Object,System.IntPtr)")]
+ [KeptBaseType (typeof (System.MulticastDelegate))]
+ public delegate void Delegate ();
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UninvokedInterfaceMemberGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UninvokedInterfaceMemberGetsRemoved.cs
new file mode 100644
index 000000000..11771f4db
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UninvokedInterfaceMemberGetsRemoved.cs
@@ -0,0 +1,24 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class UninvokedInterfaceMemberGetsRemoved {
+ public static void Main ()
+ {
+ new B ();
+ }
+
+ [Kept]
+ interface I {
+ void Method ();
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ [KeptInterface (typeof (I))]
+ class B : I {
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedClassGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedClassGetsRemoved.cs
new file mode 100644
index 000000000..85d60e33d
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedClassGetsRemoved.cs
@@ -0,0 +1,10 @@
+namespace Mono.Linker.Tests.Cases.Basic {
+ public class UnusedClassGetsRemoved {
+ public static void Main ()
+ {
+ }
+ }
+
+ class Unused {
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedFieldGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedFieldGetsRemoved.cs
new file mode 100644
index 000000000..6edcf5729
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedFieldGetsRemoved.cs
@@ -0,0 +1,20 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class UnusedFieldGetsRemoved {
+ public static void Main ()
+ {
+ new B ().Method ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ public int _unused;
+
+ [Kept]
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedMethodGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedMethodGetsRemoved.cs
new file mode 100644
index 000000000..eaded4de5
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedMethodGetsRemoved.cs
@@ -0,0 +1,22 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class UnusedMethodGetsRemoved {
+ public static void Main ()
+ {
+ new UnusedMethodGetsRemoved.B ().Method ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ public void Unused ()
+ {
+ }
+
+ [Kept]
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedNestedClassGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedNestedClassGetsRemoved.cs
new file mode 100644
index 000000000..7ff2fc3a6
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedNestedClassGetsRemoved.cs
@@ -0,0 +1,11 @@
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ public class UnusedNestedClassGetsRemoved {
+ public static void Main ()
+ {
+ }
+
+ class Unused {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertyGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertyGetsRemoved.cs
new file mode 100644
index 000000000..63d82842e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertyGetsRemoved.cs
@@ -0,0 +1,20 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class UnusedPropertyGetsRemoved {
+ public static void Main ()
+ {
+ new UnusedPropertyGetsRemoved.B ().Method ();
+ }
+
+ [KeptMember(".ctor()")]
+ class B {
+ public int Unused { get; set; }
+
+ [Kept]
+ public void Method ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertySetterRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertySetterRemoved.cs
new file mode 100644
index 000000000..9bf680e77
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UnusedPropertySetterRemoved.cs
@@ -0,0 +1,17 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class UnusedPropertySetterRemoved {
+ public static void Main ()
+ {
+ var val = new UnusedPropertySetterRemoved.B ().PartiallyUsed;
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept] // FIXME: Should be removed
+ [KeptBackingField]
+ public int PartiallyUsed { [Kept] get; set; }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Basic/UsedPropertyIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UsedPropertyIsKept.cs
new file mode 100644
index 000000000..8adc71f27
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Basic/UsedPropertyIsKept.cs
@@ -0,0 +1,19 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Basic {
+ class UsedPropertyIsKept {
+ public static void Main ()
+ {
+ var obj = new B ();
+ obj.Prop = 1;
+ var val = obj.Prop;
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept]
+ [KeptBackingField]
+ public int Prop { [Kept] get; [Kept] set; }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/CoreLink/LinkingOfCoreLibrariesRemovesUnusedTypes.cs b/linker/Tests/Mono.Linker.Tests.Cases/CoreLink/LinkingOfCoreLibrariesRemovesUnusedTypes.cs
new file mode 100644
index 000000000..c7bb5aae4
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/CoreLink/LinkingOfCoreLibrariesRemovesUnusedTypes.cs
@@ -0,0 +1,15 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.CoreLink {
+ [CoreLink ("link")]
+ [KeptAssembly ("mscorlib.dll")]
+ // We can't check everything that should be removed, but we should be able to check a few niche things that
+ // we known should be removed which will at least verify that the core library was processed
+ // TODO by Mike : List a few types
+ class LinkingOfCoreLibrariesRemovesUnusedTypes {
+ public static void Main ()
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/CorrectOverloadedMethodGetsStrippedInGenericClass.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/CorrectOverloadedMethodGetsStrippedInGenericClass.cs
new file mode 100644
index 000000000..362c3bb3d
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/CorrectOverloadedMethodGetsStrippedInGenericClass.cs
@@ -0,0 +1,37 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ class CorrectOverloadedMethodGetsStrippedInGenericClass {
+ public static void Main ()
+ {
+ // Call overloaded method through the abstract base class
+ GenericClassWithTwoOverloadedAbstractMethods<float> item = new SpecializedClassWithTwoOverloadedVirtualMethods ();
+ item.OverloadedMethod (5);
+ }
+
+ [KeptMember (".ctor()")]
+ public abstract class GenericClassWithTwoOverloadedAbstractMethods<T> {
+ public abstract string OverloadedMethod (T thing); // Don't call this one, it should be stripped
+
+ [Kept]
+ public abstract string OverloadedMethod (int thing); // Call to this should preserve the overriden one
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (GenericClassWithTwoOverloadedAbstractMethods<System.Single>))]
+ public class SpecializedClassWithTwoOverloadedVirtualMethods : GenericClassWithTwoOverloadedAbstractMethods<float> {
+ // Don't call this one, it should be stripped
+ public override string OverloadedMethod (float thing)
+ {
+ return "first";
+ }
+
+ // Don't call this one, but it shouldn't be stripped because the method it overrides is invoked
+ [Kept]
+ public override string OverloadedMethod (int thing)
+ {
+ return "second";
+ }
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/DerivedClassWithMethodOfSameNameAsBaseButDifferentNumberOfGenericParametersUnusedBaseWillGetStripped.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/DerivedClassWithMethodOfSameNameAsBaseButDifferentNumberOfGenericParametersUnusedBaseWillGetStripped.cs
new file mode 100644
index 000000000..b13f8267e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/DerivedClassWithMethodOfSameNameAsBaseButDifferentNumberOfGenericParametersUnusedBaseWillGetStripped.cs
@@ -0,0 +1,30 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ class DerivedClassWithMethodOfSameNameAsBaseButDifferentNumberOfGenericParametersUnusedBaseWillGetStripped {
+ public static void Main (string [] args)
+ {
+ MyDerived obj = new MyDerived ();
+ obj.Method<int, int> (1);
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ class MyBase {
+ public virtual T Method<T> (T arg1)
+ {
+ return arg1;
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (MyBase))]
+ class MyDerived : MyBase {
+ [Kept]
+ public virtual T Method<T, K> (T arg1)
+ {
+ return arg1;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/GenericInstanceInterfaceMethodImplementedWithDifferentGenericArgumentNameDoesNotGetStripped.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/GenericInstanceInterfaceMethodImplementedWithDifferentGenericArgumentNameDoesNotGetStripped.cs
new file mode 100644
index 000000000..4a912d678
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/GenericInstanceInterfaceMethodImplementedWithDifferentGenericArgumentNameDoesNotGetStripped.cs
@@ -0,0 +1,30 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ class GenericInstanceInterfaceMethodImplementedWithDifferentGenericArgumentNameDoesNotGetStripped {
+ public static void Main ()
+ {
+ ISomething it = new Concrete ();
+ it.ShouldNotGetStripped<int> ();
+ }
+
+ [Kept]
+ public class GenericType<T> {
+ }
+
+ public interface ISomething {
+ [Kept]
+ GenericType<TInInterface> ShouldNotGetStripped<TInInterface> ();
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptInterface (typeof (ISomething))]
+ public class Concrete : ISomething {
+ [Kept]
+ public GenericType<TInConcrete> ShouldNotGetStripped<TInConcrete> ()
+ {
+ throw new System.Exception ();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameter.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameter.cs
new file mode 100644
index 000000000..a656b1775
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameter.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ class MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameter {
+ public static void Main (string [] args)
+ {
+ Derived<int, int> tmp = new Derived<int, int> ();
+ tmp.Method<int> (null);
+ }
+
+ [KeptMember (".ctor()")]
+ public abstract class Base<TSource> {
+ [Kept]
+ public abstract TResult1 Method<TResult1> (System.Func<TSource, TResult1> arg);
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (Base<>), "TResult1")]
+ public class Derived<TSource, TResult1> : Base<TResult1> {
+ [Kept]
+ public override TResult2 Method<TResult2> (System.Func<TResult1, TResult2> arg)
+ {
+ return arg (default (TResult1));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase.cs
new file mode 100644
index 000000000..78eb14425
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase.cs
@@ -0,0 +1,31 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ class MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase {
+ public static void Main (string [] args)
+ {
+ Derived<int, int> tmp = new Derived<int, int> ();
+ tmp.Method<int> (null);
+ }
+
+ [Kept]
+ public class Base<TSource> {
+
+ [KeptMember (".ctor()")]
+ public abstract class Nested {
+ [Kept]
+ public abstract TResult1 Method<TResult1> (System.Func<TSource, TResult1> arg);
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (Base<>.Nested), "TResult1")]
+ public class Derived<TSource, TResult1> : Base<TResult1>.Nested {
+ [Kept]
+ public override TResult2 Method<TResult2> (System.Func<TResult1, TResult2> arg)
+ {
+ return arg (default (TResult1));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase2.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase2.cs
new file mode 100644
index 000000000..888e4278d
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase2.cs
@@ -0,0 +1,31 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ class MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase2 {
+ public static void Main (string [] args)
+ {
+ Derived<int, int> tmp = new Derived<int, int> ();
+ tmp.Method<int> (null);
+ }
+
+ [Kept]
+ public class Base<TSource> {
+
+ [KeptMember (".ctor()")]
+ public abstract class Nested<T1, T2, T3> {
+ [Kept]
+ public abstract TResult1 Method<TResult1> (System.Func<TSource, TResult1> arg);
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (Base<>.Nested<,,>), "TResult1", typeof (int), typeof (int), typeof (string))]
+ public class Derived<TSource, TResult1> : Base<TResult1>.Nested<int, int, string> {
+ [Kept]
+ public override TResult2 Method<TResult2> (System.Func<TResult1, TResult2> arg)
+ {
+ return arg (default (TResult1));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/OverrideWithAnotherVirtualMethodOfSameNameWithDifferentParameterType.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/OverrideWithAnotherVirtualMethodOfSameNameWithDifferentParameterType.cs
new file mode 100644
index 000000000..ba81282b8
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/OverrideWithAnotherVirtualMethodOfSameNameWithDifferentParameterType.cs
@@ -0,0 +1,34 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ class OverrideWithAnotherVirtualMethodOfSameNameWithDifferentParameterType {
+ public static void Main (string [] args)
+ {
+ new Derived<double, int> ().Method (1.0);
+ }
+
+ [KeptMember (".ctor()")]
+ public class Base<S> {
+ [Kept]
+ public virtual S Method (S arg)
+ {
+ return arg;
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (Base<>), "K")]
+ public class Derived<K, S> : Base<K> {
+ [Kept]
+ public override K Method (K arg)
+ {
+ return arg;
+ }
+
+ public virtual S Method (S arg)
+ {
+ return arg;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInGenericClassIsNotStripped.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInGenericClassIsNotStripped.cs
new file mode 100644
index 000000000..908e0d50d
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInGenericClassIsNotStripped.cs
@@ -0,0 +1,21 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ public class UsedOverloadedGenericMethodInGenericClassIsNotStripped {
+ public static void Main ()
+ {
+ B<int>.Method (true);
+ }
+
+ class B<TBase> {
+ [Kept]
+ public static void Method<T> (T value)
+ {
+ }
+
+ public static void Method (TBase value)
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInstanceInGenericClassIsNotStripped.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInstanceInGenericClassIsNotStripped.cs
new file mode 100644
index 000000000..a565d4cf5
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodInstanceInGenericClassIsNotStripped.cs
@@ -0,0 +1,21 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ public class UsedOverloadedGenericMethodInstanceInGenericClassIsNotStripped {
+ public static void Main ()
+ {
+ B<int>.Method (1);
+ }
+
+ class B<TBase> {
+ public static void Method<T> (T value)
+ {
+ }
+
+ [Kept]
+ public static void Method (TBase value)
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodWithNoParametersIsNotStripped.cs b/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodWithNoParametersIsNotStripped.cs
new file mode 100644
index 000000000..52e1ff7b2
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Generics/UsedOverloadedGenericMethodWithNoParametersIsNotStripped.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Generics {
+ public class UsedOverloadedGenericMethodWithNoParametersIsNotStripped {
+ public static void Main ()
+ {
+ B.Call<string, int> ();
+ }
+
+ public class B {
+ public static void Method<T> ()
+ {
+ }
+
+ [Kept]
+ public static void Method<TKey, TValue> ()
+ {
+ }
+
+ [Kept]
+ public static void Call<TKey, TValue> ()
+ {
+ B.Method<TKey, TValue> ();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/FieldsOfTypeMarkedSequentialLayoutAreNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/FieldsOfTypeMarkedSequentialLayoutAreNotRemoved.cs
new file mode 100644
index 000000000..852a066e1
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/FieldsOfTypeMarkedSequentialLayoutAreNotRemoved.cs
@@ -0,0 +1,17 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop {
+ class FieldsOfTypeMarkedSequentialLayoutAreNotRemoved {
+ public static void Main ()
+ {
+ new A ();
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ [KeptMember (".ctor()")]
+ class A {
+ [Kept] int a;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/DefaultConstructorOfReturnTypeIsNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/DefaultConstructorOfReturnTypeIsNotRemoved.cs
new file mode 100644
index 000000000..ecfe75123
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/DefaultConstructorOfReturnTypeIsNotRemoved.cs
@@ -0,0 +1,22 @@
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.InternalCalls {
+ class DefaultConstructorOfReturnTypeIsNotRemoved {
+ public static void Main ()
+ {
+ var a = SomeMethod ();
+ }
+
+ class A {
+ [Kept]
+ public A ()
+ {
+ }
+ }
+
+ [Kept]
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ static extern A SomeMethod ();
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorIsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorIsRemoved.cs
new file mode 100644
index 000000000..ab21994f0
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorIsRemoved.cs
@@ -0,0 +1,27 @@
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.InternalCalls {
+ class UnusedDefaultConstructorIsRemoved {
+ public static void Main ()
+ {
+ var a = new A (1);
+ SomeMethod (a);
+ }
+
+ class A {
+ public A ()
+ {
+ }
+
+ [Kept]
+ public A (int other)
+ {
+ }
+ }
+
+ [Kept]
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ static extern void SomeMethod (A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs
new file mode 100644
index 000000000..d181ecd0a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs
@@ -0,0 +1,28 @@
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.InternalCalls {
+ class UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved {
+ public static void Main ()
+ {
+ var a = new A (1);
+ SomeMethod (ref a);
+ }
+
+ class A {
+ [Kept]
+ public A ()
+ {
+ }
+
+ [Kept]
+ public A (int other)
+ {
+ }
+ }
+
+ [Kept]
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ static extern void SomeMethod (ref A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesAreNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesAreNotRemoved.cs
new file mode 100644
index 000000000..09809a60e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesAreNotRemoved.cs
@@ -0,0 +1,23 @@
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.InternalCalls {
+ class UnusedFieldsOfTypesAreNotRemoved {
+ public static void Main ()
+ {
+ var a = new A ();
+ SomeMethod (a);
+ }
+
+ [KeptMember (".ctor()")]
+ class A {
+ [Kept] private int field1;
+
+ [Kept] private int field2;
+ }
+
+ [Kept]
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ static extern void SomeMethod (A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs
new file mode 100644
index 000000000..d4f3c3779
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs
@@ -0,0 +1,23 @@
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.InternalCalls {
+ class UnusedFieldsOfTypesPassedByRefAreNotRemoved {
+ public static void Main ()
+ {
+ var a = new A ();
+ SomeMethod (ref a);
+ }
+
+ [KeptMember (".ctor()")]
+ class A {
+ [Kept] private int field1;
+
+ [Kept] private int field2;
+ }
+
+ [Kept]
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ static extern void SomeMethod (ref A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesWhenHasThisAreNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesWhenHasThisAreNotRemoved.cs
new file mode 100644
index 000000000..df77357d6
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/InternalCalls/UnusedFieldsOfTypesWhenHasThisAreNotRemoved.cs
@@ -0,0 +1,21 @@
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.InternalCalls {
+ class UnusedFieldsOfTypesWhenHasThisAreNotRemoved {
+ public static void Main ()
+ {
+ A a = new A ();
+ a.SomeMethod ();
+ }
+
+ [KeptMember (".ctor()")]
+ class A {
+ [Kept] private int field1;
+
+ [Kept]
+ [MethodImpl (MethodImplOptions.InternalCall)]
+ public extern void SomeMethod ();
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/DefaultConstructorOfReturnTypeIsNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/DefaultConstructorOfReturnTypeIsNotRemoved.cs
new file mode 100644
index 000000000..d714d0d95
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/DefaultConstructorOfReturnTypeIsNotRemoved.cs
@@ -0,0 +1,22 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke {
+ class DefaultConstructorOfReturnTypeIsNotRemoved {
+ public static void Main ()
+ {
+ var a = SomeMethod ();
+ }
+
+ class A {
+ [Kept]
+ public A ()
+ {
+ }
+ }
+
+ [Kept]
+ [DllImport ("Unused")]
+ private static extern A SomeMethod ();
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorIsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorIsRemoved.cs
new file mode 100644
index 000000000..041cc9c98
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorIsRemoved.cs
@@ -0,0 +1,27 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke {
+ class UnusedDefaultConstructorIsRemoved {
+ public static void Main ()
+ {
+ var a = new A (1);
+ SomeMethod (a);
+ }
+
+ class A {
+ public A ()
+ {
+ }
+
+ [Kept]
+ public A (int other)
+ {
+ }
+ }
+
+ [Kept]
+ [DllImport ("Unused")]
+ private static extern void SomeMethod (A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs
new file mode 100644
index 000000000..db2514a4a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs
@@ -0,0 +1,28 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke {
+ class UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved {
+ public static void Main ()
+ {
+ var a = new A (1);
+ SomeMethod (ref a);
+ }
+
+ class A {
+ [Kept]
+ public A ()
+ {
+ }
+
+ [Kept]
+ public A (int other)
+ {
+ }
+ }
+
+ [Kept]
+ [DllImport ("Unused")]
+ private static extern void SomeMethod (ref A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesAreNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesAreNotRemoved.cs
new file mode 100644
index 000000000..a34c4d6bb
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesAreNotRemoved.cs
@@ -0,0 +1,23 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke {
+ class UnusedFieldsOfTypesAreNotRemoved {
+ public static void Main ()
+ {
+ var a = new A ();
+ SomeMethod (a);
+ }
+
+ [KeptMember (".ctor()")]
+ class A {
+ [Kept] private int field1;
+
+ [Kept] private int field2;
+ }
+
+ [Kept]
+ [DllImport ("Unused")]
+ private static extern void SomeMethod (A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs
new file mode 100644
index 000000000..50ae45fe3
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/PInvoke/UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs
@@ -0,0 +1,23 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop.PInvoke {
+ class UnusedFieldsOfTypesPassedByRefAreNotRemoved {
+ public static void Main ()
+ {
+ var a = new A ();
+ SomeMethod (ref a);
+ }
+
+ [KeptMember (".ctor()")]
+ class A {
+ [Kept] private int field1;
+
+ [Kept] private int field2;
+ }
+
+ [Kept]
+ [DllImport ("Unused")]
+ private static extern void SomeMethod (ref A a);
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Interop/UnusedTypeWithSequentialLayoutIsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Interop/UnusedTypeWithSequentialLayoutIsRemoved.cs
new file mode 100644
index 000000000..00c47a342
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Interop/UnusedTypeWithSequentialLayoutIsRemoved.cs
@@ -0,0 +1,15 @@
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Interop {
+ class UnusedTypeWithSequentialLayoutIsRemoved {
+ static void Main ()
+ {
+ }
+
+ [StructLayout (LayoutKind.Sequential)]
+ class B {
+ int a;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.cs
new file mode 100644
index 000000000..d65701772
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.cs
@@ -0,0 +1,72 @@
+
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml
+{
+ class TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved {
+ public static void Main () {
+ }
+
+ [Kept]
+ [KeptInterface(typeof (IFoo<System.Int32>))]
+ [KeptInterface(typeof (IFoo<System.String>))]
+ [KeptInterface(typeof (IFoo<Cat>))]
+ [KeptInterface(typeof (IFoo2<System.Int32>))]
+ [KeptInterface(typeof (IFoo3<System.Int32,System.String,System.Char>))]
+ [KeptInterface(typeof (IDog))]
+ [KeptInterface(typeof (IFoo<IFoo<System.Int32>>))]
+ class Unused : IFoo<int>, IFoo<string>, IFoo<Cat>, IFoo2<int>, IFoo3<int, string, char>, IDog, IFoo<IFoo<int>> {
+ [Kept]
+ public int Field1;
+
+ [Kept]
+ public IFoo<int> Field2;
+
+ public IFoo<int> Property1 { get; set; }
+
+ string IDog.Name { get; set; }
+
+ int IFoo<int>.Bar { get; set; }
+
+ int IFoo<string>.Bar { get; set; }
+
+ int IFoo<Cat>.Bar { get; set; }
+
+ int Bar2 { get; set; }
+
+ int IFoo2<int>.Bar2 { get; set; }
+
+ int Bar3 { get; set; }
+
+ int IFoo3<int, string, char>.Bar3 { get; set; }
+
+ int IFoo<IFoo<int>>.Bar { get; set; }
+ }
+
+ [Kept]
+ interface IDog {
+ string Name { get; set; }
+ }
+
+ [Kept]
+ interface IFoo<T> {
+
+ int Bar { get; set; }
+ }
+
+ [Kept]
+ interface IFoo2<T> {
+ int Bar2 { get; set; }
+ }
+
+ [Kept]
+ interface IFoo3<T, K, J> {
+ int Bar3 { get; set; }
+ }
+
+ [Kept]
+ class Cat {
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.xml
new file mode 100644
index 000000000..338ee7f76
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.xml
@@ -0,0 +1,6 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved/Unused" preserve="fields">
+ </type>
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.cs
new file mode 100644
index 000000000..bc1b0f337
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.cs
@@ -0,0 +1,17 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedFieldPreservedByLinkXmlIsKept {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ class Unused {
+ [Kept]
+ private int _preserved;
+
+ private int _notPreserved;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.xml
new file mode 100644
index 000000000..46db550dc
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedFieldPreservedByLinkXmlIsKept.xml
@@ -0,0 +1,7 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedFieldPreservedByLinkXmlIsKept/Unused">
+ <field signature="System.Int32 _preserved" />
+ </type>
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs
new file mode 100644
index 000000000..99584fd9f
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs
@@ -0,0 +1,21 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedMethodPreservedByLinkXmlIsKept {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ class Unused {
+ [Kept]
+ private void PreservedMethod ()
+ {
+ }
+
+ private void NotPreservedMethod ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.xml
new file mode 100644
index 000000000..231a0d203
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.xml
@@ -0,0 +1,7 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedMethodPreservedByLinkXmlIsKept/Unused">
+ <method signature="System.Void PreservedMethod()" />
+ </type>
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.cs
new file mode 100644
index 000000000..5e319acfd
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.cs
@@ -0,0 +1,14 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedNestedTypePreservedByLinkXmlIsKept {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ class Unused {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.xml
new file mode 100644
index 000000000..7990e8fec
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedNestedTypePreservedByLinkXmlIsKept.xml
@@ -0,0 +1,5 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedNestedTypePreservedByLinkXmlIsKept/Unused" />
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs
new file mode 100644
index 000000000..65084580f
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.cs
@@ -0,0 +1,26 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedPropertyPreservedByLinkXmlIsKept {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ class Unused {
+ [Kept]
+ [KeptBackingField]
+ public int PreservedProperty1 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ public int PreservedProperty2 { [Kept] get; set; }
+
+ [Kept]
+ [KeptBackingField]
+ public int PreservedProperty3 { get; [Kept] set; }
+
+ public int NotPreservedProperty { get; set; }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml
new file mode 100644
index 000000000..1e182255d
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedPropertyPreservedByLinkXmlIsKept.xml
@@ -0,0 +1,10 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedPropertyPreservedByLinkXmlIsKept/Unused">
+ <method signature="System.Int32 get_PreservedProperty1()" />
+ <method signature="System.Void set_PreservedProperty1(System.Int32)" />
+ <method signature="System.Int32 get_PreservedProperty2()" />
+ <method signature="System.Void set_PreservedProperty3(System.Int32)" />
+ </type>
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.cs
new file mode 100644
index 000000000..edaff63eb
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.cs
@@ -0,0 +1,14 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedTypePreservedByLinkXmlIsKept {
+ public static void Main ()
+ {
+ }
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ class UnusedTypePreservedByLinkXmlIsKeptUnusedType {
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.xml
new file mode 100644
index 000000000..ffb652e1e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypePreservedByLinkXmlIsKept.xml
@@ -0,0 +1,5 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedTypePreservedByLinkXmlIsKeptUnusedType" />
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.cs
new file mode 100644
index 000000000..02fb956f2
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.cs
@@ -0,0 +1,85 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedTypeWithPreserveAllHasAllMembersPreserved {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ class Unused {
+ [Kept]
+ public int Field1;
+
+ [Kept]
+ private int Field2;
+
+ [Kept]
+ internal int Field3;
+
+ [Kept]
+ public static int Field4;
+
+ [Kept]
+ private static int Field5;
+
+ [Kept]
+ internal static int Field6;
+
+ [Kept]
+ [KeptBackingField]
+ public string Property1 { [Kept] get; [Kept] set;}
+
+ [Kept]
+ [KeptBackingField]
+ private string Property2 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ internal string Property3 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ public static string Property4 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ private static string Property5 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ internal static string Property6 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ public void Method1 ()
+ {
+ }
+
+ [Kept]
+ private void Method2 ()
+ {
+ }
+
+ [Kept]
+ internal void Method3 ()
+ {
+ }
+
+ [Kept]
+ public static void Method4 ()
+ {
+ }
+
+ [Kept]
+ private static void Method5 ()
+ {
+ }
+
+ [Kept]
+ internal static void Method6 ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.xml
new file mode 100644
index 000000000..7987a7765
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveAllHasAllMembersPreserved.xml
@@ -0,0 +1,5 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedTypeWithPreserveAllHasAllMembersPreserved/Unused" preserve="all" />
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.cs
new file mode 100644
index 000000000..1af6f4530
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.cs
@@ -0,0 +1,66 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedTypeWithPreserveFieldsHasMethodsRemoved {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ class Unused {
+ [Kept]
+ public int Field1;
+
+ [Kept]
+ private int Field2;
+
+ [Kept]
+ internal int Field3;
+
+ [Kept]
+ public static int Field4;
+
+ [Kept]
+ private static int Field5;
+
+ [Kept]
+ internal static int Field6;
+
+ public string Property1 { get; set; }
+ private string Property2 { get; set; }
+ internal string Property3 { get; set; }
+ public static string Property4 { get; set; }
+ private static string Property5 { get; set; }
+ internal static string Property6 { get; set; }
+
+ [Kept]
+ public void PreservedMethod ()
+ {
+ }
+
+ public void Method1 ()
+ {
+ }
+
+ private void Method2 ()
+ {
+ }
+
+ internal void Method3 ()
+ {
+ }
+
+ public static void Method4 ()
+ {
+ }
+
+ private static void Method5 ()
+ {
+ }
+
+ internal static void Method6 ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.xml
new file mode 100644
index 000000000..619a8db26
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveFieldsHasMethodsRemoved.xml
@@ -0,0 +1,7 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedTypeWithPreserveFieldsHasMethodsRemoved/Unused" preserve="fields">
+ <method signature="System.Void PreservedMethod()" />
+ </type>
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.cs
new file mode 100644
index 000000000..8a79d2d2b
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.cs
@@ -0,0 +1,74 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedTypeWithPreserveMethodsHasFieldsRemoved {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ class Unused {
+ public int Field1;
+ private int Field2;
+ internal int Field3;
+ public static int Field4;
+ private static int Field5;
+ internal static int Field6;
+
+ [Kept]
+ [KeptBackingField]
+ public string Property1 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ private string Property2 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ internal string Property3 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ public static string Property4 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ private static string Property5 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ [KeptBackingField]
+ internal static string Property6 { [Kept] get; [Kept] set; }
+
+ [Kept]
+ public void Method1 ()
+ {
+ }
+
+ [Kept]
+ private void Method2 ()
+ {
+ }
+
+ [Kept]
+ internal void Method3 ()
+ {
+ }
+
+ [Kept]
+ public static void Method4 ()
+ {
+ }
+
+ [Kept]
+ private static void Method5 ()
+ {
+ }
+
+ [Kept]
+ internal static void Method6 ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.xml
new file mode 100644
index 000000000..20723f8ed
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveMethodsHasFieldsRemoved.xml
@@ -0,0 +1,5 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedTypeWithPreserveMethodsHasFieldsRemoved/Unused" preserve="methods" />
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.cs
new file mode 100644
index 000000000..b9d404f22
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.cs
@@ -0,0 +1,26 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedTypeWithPreserveNothingAndPreserveMembers {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ class Unused {
+ [Kept]
+ public int Field1;
+
+ private int Field2;
+
+ [Kept]
+ public void Method1 ()
+ {
+ }
+
+ private void Method2 ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.xml
new file mode 100644
index 000000000..d672e9e09
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingAndPreserveMembers.xml
@@ -0,0 +1,8 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedTypeWithPreserveNothingAndPreserveMembers/Unused" preserve="nothing">
+ <field signature="System.Int32 Field1" />
+ <method signature="System.Void Method1()" />
+ </type>
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.cs
new file mode 100644
index 000000000..d6ea29b89
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.cs
@@ -0,0 +1,50 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.LinkXml {
+ class UnusedTypeWithPreserveNothingHasMembersRemoved {
+ public static void Main ()
+ {
+ }
+
+ [Kept]
+ class Unused {
+ public int Field1;
+ private int Field2;
+ internal int Field3;
+ public static int Field4;
+ private static int Field5;
+ internal static int Field6;
+
+ public string Property1 { get; set; }
+ private string Property2 { get; set; }
+ internal string Property3 { get; set; }
+ public static string Property4 { get; set; }
+ private static string Property5 { get; set; }
+ internal static string Property6 { get; set; }
+
+ public void Method1 ()
+ {
+ }
+
+ private void Method2 ()
+ {
+ }
+
+ internal void Method3 ()
+ {
+ }
+
+ public static void Method4 ()
+ {
+ }
+
+ private static void Method5 ()
+ {
+ }
+
+ internal static void Method6 ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.xml b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.xml
new file mode 100644
index 000000000..f76df307a
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/LinkXml/UnusedTypeWithPreserveNothingHasMembersRemoved.xml
@@ -0,0 +1,5 @@
+<linker>
+ <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <type fullname="Mono.Linker.Tests.Cases.LinkXml.UnusedTypeWithPreserveNothingHasMembersRemoved/Unused" preserve="nothing" />
+ </assembly>
+</linker> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj b/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
new file mode 100644
index 000000000..245bc0936
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{B6BEE6AA-ADA0-4E1D-9A17-FBF2936F82B5}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Mono.Linker.Tests.Cases</RootNamespace>
+ <AssemblyName>Mono.Linker.Tests.Cases</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE;INCLUDE_EXPECTATIONS</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE;INCLUDE_EXPECTATIONS</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Attributes\AttributeOnPreservedTypeWithTypeUsedInConstructorIsKept.cs" />
+ <Compile Include="Attributes\AttributeOnPreservedTypeWithTypeUsedInDifferentNamespaceIsKept.cs" />
+ <Compile Include="Attributes\AttributeOnPreservedTypeWithTypeUsedInFieldIsKept.cs" />
+ <Compile Include="Attributes\AttributeOnUsedFieldIsKept.cs" />
+ <Compile Include="Attributes\AttributeOnPreservedTypeIsKept.cs" />
+ <Compile Include="Attributes\AttributeOnPreservedTypeWithTypeUsedInPropertySetterIsKept.cs" />
+ <Compile Include="Attributes\AttributeOnPreservedTypeWithUsedSetter.cs" />
+ <Compile Include="Attributes\AttributeOnUsedMethodIsKept.cs" />
+ <Compile Include="Attributes\AttributeOnUsedPropertyIsKept.cs" />
+ <Compile Include="Basic\ComplexNestedClassesHasUnusedRemoved.cs" />
+ <Compile Include="Basic\InterfaceMethodImplementedOnBaseClassDoesNotGetStripped.cs" />
+ <Compile Include="Basic\MultiLevelNestedClassesAllRemovedWhenNonUsed.cs" />
+ <Compile Include="Basic\NestedDelegateInvokeMethodsPreserved.cs" />
+ <Compile Include="Basic\UninvokedInterfaceMemberGetsRemoved.cs" />
+ <Compile Include="Basic\UnusedFieldGetsRemoved.cs" />
+ <Compile Include="Basic\UnusedMethodGetsRemoved.cs" />
+ <Compile Include="Basic\UnusedPropertyGetsRemoved.cs" />
+ <Compile Include="Basic\UnusedPropertySetterRemoved.cs" />
+ <Compile Include="Basic\UsedPropertyIsKept.cs" />
+ <Compile Include="CoreLink\LinkingOfCoreLibrariesRemovesUnusedTypes.cs" />
+ <Compile Include="Advanced\DeadCodeElimination1.cs" />
+ <Compile Include="Advanced\FieldThatOnlyGetsSetIsRemoved.cs" />
+ <Compile Include="Generics\CorrectOverloadedMethodGetsStrippedInGenericClass.cs" />
+ <Compile Include="Generics\DerivedClassWithMethodOfSameNameAsBaseButDifferentNumberOfGenericParametersUnusedBaseWillGetStripped.cs" />
+ <Compile Include="Generics\GenericInstanceInterfaceMethodImplementedWithDifferentGenericArgumentNameDoesNotGetStripped.cs" />
+ <Compile Include="Generics\MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameter.cs" />
+ <Compile Include="Generics\MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase.cs" />
+ <Compile Include="Generics\MethodWithParameterWhichHasGenericParametersAndOverrideUsesADifferentNameForGenericParameterNestedCase2.cs" />
+ <Compile Include="Generics\OverrideWithAnotherVirtualMethodOfSameNameWithDifferentParameterType.cs" />
+ <Compile Include="Interop\InternalCalls\DefaultConstructorOfReturnTypeIsNotRemoved.cs" />
+ <Compile Include="Interop\PInvoke\DefaultConstructorOfReturnTypeIsNotRemoved.cs" />
+ <Compile Include="Interop\InternalCalls\UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs" />
+ <Compile Include="Interop\PInvoke\UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved.cs" />
+ <Compile Include="Interop\InternalCalls\UnusedDefaultConstructorIsRemoved.cs" />
+ <Compile Include="Interop\PInvoke\UnusedDefaultConstructorIsRemoved.cs" />
+ <Compile Include="Interop\FieldsOfTypeMarkedSequentialLayoutAreNotRemoved.cs" />
+ <Compile Include="Interop\InternalCalls\UnusedFieldsOfTypesAreNotRemoved.cs" />
+ <Compile Include="Interop\InternalCalls\UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs" />
+ <Compile Include="Interop\PInvoke\UnusedFieldsOfTypesAreNotRemoved.cs" />
+ <Compile Include="Interop\PInvoke\UnusedFieldsOfTypesPassedByRefAreNotRemoved.cs" />
+ <Compile Include="Interop\InternalCalls\UnusedFieldsOfTypesWhenHasThisAreNotRemoved.cs" />
+ <Compile Include="Interop\UnusedTypeWithSequentialLayoutIsRemoved.cs" />
+ <Compile Include="LinkXml\TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.cs" />
+ <Compile Include="LinkXml\UnusedFieldPreservedByLinkXmlIsKept.cs" />
+ <Compile Include="LinkXml\UnusedMethodPreservedByLinkXmlIsKept.cs" />
+ <Compile Include="LinkXml\UnusedNestedTypePreservedByLinkXmlIsKept.cs" />
+ <Compile Include="LinkXml\UnusedPropertyPreservedByLinkXmlIsKept.cs" />
+ <Compile Include="LinkXml\UnusedTypePreservedByLinkXmlIsKept.cs" />
+ <Compile Include="LinkXml\UnusedTypeWithPreserveAllHasAllMembersPreserved.cs" />
+ <Compile Include="LinkXml\UnusedTypeWithPreserveFieldsHasMethodsRemoved.cs" />
+ <Compile Include="LinkXml\UnusedTypeWithPreserveMethodsHasFieldsRemoved.cs" />
+ <Compile Include="LinkXml\UnusedTypeWithPreserveNothingAndPreserveMembers.cs" />
+ <Compile Include="LinkXml\UnusedTypeWithPreserveNothingHasMembersRemoved.cs" />
+ <Compile Include="References\ReferencesAreRemovedWhenAllUsagesAreRemoved.cs" />
+ <Compile Include="VirtualMethods\ClassImplemtingInterfaceMethodsThroughBaseClass2.cs" />
+ <Compile Include="VirtualMethods\ClassImplemtingInterfaceMethodsThroughBaseClass3.cs" />
+ <Compile Include="VirtualMethods\ClassImplemtingInterfaceMethodsThroughBaseClass4.cs" />
+ <Compile Include="VirtualMethods\ClassImplemtingInterfaceMethodsThroughBaseClass5.cs" />
+ <Compile Include="VirtualMethods\ClassImplemtingInterfaceMethodsThroughBaseClass6.cs" />
+ <Compile Include="VirtualMethods\HarderToDetectUnusedVirtualMethodGetsRemoved.cs" />
+ <Compile Include="Basic\UnusedClassGetsRemoved.cs" />
+ <Compile Include="Basic\UnusedNestedClassGetsRemoved.cs" />
+ <Compile Include="Statics\UnusedStaticMethodGetsRemoved.cs" />
+ <Compile Include="VirtualMethods\UnusedVirtualMethodRemoved.cs" />
+ <Compile Include="VirtualMethods\UsedVirtualMethodNotRemoved.cs" />
+ <Compile Include="Generics\UsedOverloadedGenericMethodInGenericClassIsNotStripped.cs" />
+ <Compile Include="Generics\UsedOverloadedGenericMethodInstanceInGenericClassIsNotStripped.cs" />
+ <Compile Include="Generics\UsedOverloadedGenericMethodWithNoParametersIsNotStripped.cs" />
+ <Compile Include="Statics\UnusedStaticConstructorGetsRemoved.cs" />
+ <Compile Include="VirtualMethods\TypeGetsMarkedThatImplementsAlreadyMarkedInterfaceMethod.cs" />
+ <Compile Include="VirtualMethods\VirtualMethodGetsPerservedIfBaseMethodGetsInvoked.cs" />
+ <Compile Include="VirtualMethods\VirtualMethodGetsStrippedIfImplementingMethodGetsInvokedDirectly.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="LinkXml\TypeWithPreserveFieldsHasBackingFieldsOfPropertiesRemoved.xml" />
+ <Content Include="LinkXml\UnusedFieldPreservedByLinkXmlIsKept.xml" />
+ <Content Include="LinkXml\UnusedMethodPreservedByLinkXmlIsKept.xml" />
+ <Content Include="LinkXml\UnusedNestedTypePreservedByLinkXmlIsKept.xml" />
+ <Content Include="LinkXml\UnusedPropertyPreservedByLinkXmlIsKept.xml" />
+ <Content Include="LinkXml\UnusedTypePreservedByLinkXmlIsKept.xml" />
+ <Content Include="LinkXml\UnusedTypeWithPreserveAllHasAllMembersPreserved.xml" />
+ <Content Include="LinkXml\UnusedTypeWithPreserveFieldsHasMethodsRemoved.xml" />
+ <Content Include="LinkXml\UnusedTypeWithPreserveMethodsHasFieldsRemoved.xml" />
+ <Content Include="LinkXml\UnusedTypeWithPreserveNothingAndPreserveMembers.xml" />
+ <Content Include="LinkXml\UnusedTypeWithPreserveNothingHasMembersRemoved.xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Mono.Linker.Tests.Cases.Expectations\Mono.Linker.Tests.Cases.Expectations.csproj">
+ <Project>{2C26601F-3E2F-45B9-A02F-58EE9296E19E}</Project>
+ <Name>Mono.Linker.Tests.Cases.Expectations</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/References/ReferencesAreRemovedWhenAllUsagesAreRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/References/ReferencesAreRemovedWhenAllUsagesAreRemoved.cs
new file mode 100644
index 000000000..664a0c98d
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/References/ReferencesAreRemovedWhenAllUsagesAreRemoved.cs
@@ -0,0 +1,20 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.References {
+ [CoreLink ("link")]
+ [Reference ("System.dll")]
+ [RemovedAssembly ("System.dll")]
+ class ReferencesAreRemovedWhenAllUsagesAreRemoved {
+ public static void Main ()
+ {
+ }
+
+ private static void Unused ()
+ {
+ // Use something from System.dll so that we know the input assembly was compiled with the reference
+ var uri = new Uri ("w/e");
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticConstructorGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticConstructorGetsRemoved.cs
new file mode 100644
index 000000000..83c1d1ea8
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticConstructorGetsRemoved.cs
@@ -0,0 +1,20 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Statics {
+ class UnusedStaticConstructorGetsRemoved {
+ public static void Main ()
+ {
+ }
+
+ static void Dead ()
+ {
+ new B ();
+ }
+
+ class B {
+ static B ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticMethodGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticMethodGetsRemoved.cs
new file mode 100644
index 000000000..31c7c6ef0
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/Statics/UnusedStaticMethodGetsRemoved.cs
@@ -0,0 +1,23 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.Statics {
+ public class UnusedStaticMethodGetsRemoved {
+ public static void Main ()
+ {
+ A.UsedMethod ();
+ }
+ }
+
+ [Kept]
+ class A {
+ [Kept]
+ public static void UsedMethod ()
+ {
+ }
+
+ static void UnusedMethod ()
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass2.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass2.cs
new file mode 100644
index 000000000..f370e9e5d
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass2.cs
@@ -0,0 +1,29 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class ClassImplemtingInterfaceMethodsThroughBaseClass2 {
+ public static void Main ()
+ {
+ new B ();
+ IFoo i = null;
+ i.Foo ();
+ }
+
+ interface IFoo {
+ [Kept]
+ void Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept] // FIXME: Should be removed
+ public void Foo ()
+ {
+ }
+ }
+
+ class A : B, IFoo {
+ //my IFoo.Foo() is actually implemented by B which doesn't know about it.
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass3.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass3.cs
new file mode 100644
index 000000000..362407bd1
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass3.cs
@@ -0,0 +1,26 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class ClassImplemtingInterfaceMethodsThroughBaseClass3 {
+ public static void Main ()
+ {
+ new B ().Foo ();
+ }
+
+ interface IFoo {
+ void Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept]
+ public void Foo ()
+ {
+ }
+ }
+
+ class A : B, IFoo {
+ //my IFoo.Foo() is actually implemented by B which doesn't know about it.
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass4.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass4.cs
new file mode 100644
index 000000000..829ab01c7
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass4.cs
@@ -0,0 +1,30 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class ClassImplemtingInterfaceMethodsThroughBaseClass4 {
+ public static void Main ()
+ {
+ new A ().Foo ();
+ }
+
+ [Kept]
+ interface IFoo {
+ void Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept]
+ public void Foo ()
+ {
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (B))]
+ [KeptInterface (typeof (IFoo))] // FIXME: Why is it not removed
+ class A : B, IFoo {
+ //my IFoo.Foo() is actually implemented by B which doesn't know about it.
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass5.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass5.cs
new file mode 100644
index 000000000..10868a8a2
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass5.cs
@@ -0,0 +1,29 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class ClassImplemtingInterfaceMethodsThroughBaseClass5 {
+ public static void Main ()
+ {
+ new A ();
+ }
+
+ [Kept]
+ interface IFoo {
+ void Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ public void Foo ()
+ {
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (B))]
+ [KeptInterface (typeof (IFoo))]
+ class A : B, IFoo {
+ //my IFoo.Foo() is actually implemented by B which doesn't know about it.
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass6.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass6.cs
new file mode 100644
index 000000000..bb295c9c2
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/ClassImplemtingInterfaceMethodsThroughBaseClass6.cs
@@ -0,0 +1,38 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class ClassImplemtingInterfaceMethodsThroughBaseClass6 {
+ public static void Main ()
+ {
+ B tmp = new B ();
+ IFoo i = new C ();
+ i.Foo ();
+ }
+
+ interface IFoo {
+ [Kept]
+ void Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept] // FIXME: Needs to be removed
+ public void Foo ()
+ {
+ }
+ }
+
+ class A : B, IFoo {
+ //my IFoo.Foo() is actually implemented by B which doesn't know about it.
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptInterface (typeof (IFoo))]
+ class C : IFoo {
+ [Kept]
+ public void Foo ()
+ {
+ }
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/HarderToDetectUnusedVirtualMethodGetsRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/HarderToDetectUnusedVirtualMethodGetsRemoved.cs
new file mode 100644
index 000000000..c08e69afd
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/HarderToDetectUnusedVirtualMethodGetsRemoved.cs
@@ -0,0 +1,30 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class HarderToDetectUnusedVirtualMethodGetsRemoved {
+ public static void Main ()
+ {
+ new Base ().Call ();
+ }
+
+ static void DeadCode ()
+ {
+ new B ();
+ }
+
+ [Kept]
+ [KeptMember (".ctor()")]
+ class Base {
+ [Kept]
+ public virtual void Call ()
+ {
+ }
+ }
+
+ class B : Base {
+ public override void Call ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/TypeGetsMarkedThatImplementsAlreadyMarkedInterfaceMethod.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/TypeGetsMarkedThatImplementsAlreadyMarkedInterfaceMethod.cs
new file mode 100644
index 000000000..880ac679e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/TypeGetsMarkedThatImplementsAlreadyMarkedInterfaceMethod.cs
@@ -0,0 +1,35 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class TypeGetsMarkedThatImplementsAlreadyMarkedInterfaceMethod {
+ public static void Main ()
+ {
+ IFoo i = new A ();
+ i.Foo ();
+ }
+
+ interface IFoo {
+ [Kept]
+ void Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptInterface (typeof (IFoo))]
+ class B : IFoo {
+ [Kept]
+ public void Foo ()
+ {
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptInterface (typeof (IFoo))]
+ class A : IFoo {
+ [Kept]
+ public void Foo ()
+ {
+ new B (); /*this will cause us to mark B, but will we be smart enough to realize B.Foo implements the already marked IFoo.Foo?*/
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UnusedVirtualMethodRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UnusedVirtualMethodRemoved.cs
new file mode 100644
index 000000000..115ca8648
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UnusedVirtualMethodRemoved.cs
@@ -0,0 +1,24 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class UnusedVirtualMethodRemoved {
+ public static void Main ()
+ {
+ new Base ().Call ();
+ }
+
+ [KeptMember (".ctor()")]
+ class Base {
+ [Kept]
+ public virtual void Call ()
+ {
+ }
+ }
+
+ class B : Base {
+ public override void Call ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UsedVirtualMethodNotRemoved.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UsedVirtualMethodNotRemoved.cs
new file mode 100644
index 000000000..e695cca7e
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/UsedVirtualMethodNotRemoved.cs
@@ -0,0 +1,29 @@
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ public class UsedVirtualMethodNotRemoved {
+ public static void Main ()
+ {
+ new B ();
+ new Base ().Call ();
+ }
+
+ [KeptMember (".ctor()")]
+ class Base {
+ [Kept]
+ public virtual void Call ()
+ {
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (Base))]
+ class B : Base {
+ [Kept]
+ public override void Call ()
+ {
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsPerservedIfBaseMethodGetsInvoked.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsPerservedIfBaseMethodGetsInvoked.cs
new file mode 100644
index 000000000..372105cd3
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsPerservedIfBaseMethodGetsInvoked.cs
@@ -0,0 +1,28 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class VirtualMethodGetsPerservedIfBaseMethodGetsInvoked {
+ public static void Main ()
+ {
+ new A ();
+ new B ().Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept]
+ public virtual void Foo ()
+ {
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (B))]
+ class A : B {
+ [Kept]
+ public override void Foo ()
+ {
+ }
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsStrippedIfImplementingMethodGetsInvokedDirectly.cs b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsStrippedIfImplementingMethodGetsInvokedDirectly.cs
new file mode 100644
index 000000000..f1baa44eb
--- /dev/null
+++ b/linker/Tests/Mono.Linker.Tests.Cases/VirtualMethods/VirtualMethodGetsStrippedIfImplementingMethodGetsInvokedDirectly.cs
@@ -0,0 +1,27 @@
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.VirtualMethods {
+ class VirtualMethodGetsStrippedIfImplementingMethodGetsInvokedDirectly {
+ public static void Main ()
+ {
+ new A ().Foo ();
+ }
+
+ [KeptMember (".ctor()")]
+ class B {
+ [Kept] // TODO: Would be nice to be removed
+ public virtual void Foo ()
+ {
+ }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (B))]
+ class A : B {
+ [Kept]
+ public override void Foo ()
+ {
+ }
+ }
+ }
+}
diff --git a/linker/Tests/Mono.Linker.Tests.csproj b/linker/Tests/Mono.Linker.Tests.csproj
index b3438c91b..7e1b44418 100644
--- a/linker/Tests/Mono.Linker.Tests.csproj
+++ b/linker/Tests/Mono.Linker.Tests.csproj
@@ -10,6 +10,7 @@
<StartupObject>
</StartupObject>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
+ <RootNamespace>Mono.Linker</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -45,15 +46,9 @@
</Reference>
</ItemGroup>
<ItemGroup>
- <Compile Include="Mono.Linker.Tests\AbstractLinkingTestFixture.cs" />
- <Compile Include="Mono.Linker.Tests\AbstractTestFixture.cs" />
- <Compile Include="Mono.Linker.Tests\LinkingTestFixture.cs" />
- <Compile Include="Mono.Linker.Tests\AssemblyInfo.cs" />
- <Compile Include="Mono.Linker.Tests\XmlLinkingTestFixture.cs" />
- <Compile Include="Mono.Linker.Tests\ResolveLinkedAssemblyStep.cs" />
- </ItemGroup>
- <ItemGroup>
<Folder Include="Properties\" />
+ <Folder Include="TestCasesRunner\" />
+ <Folder Include="Extensions\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\cecil\Mono.Cecil.csproj">
@@ -64,12 +59,39 @@
<Project>{DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}</Project>
<Name>Mono.Linker</Name>
</ProjectReference>
- <ProjectReference Include="TestCases\TestCases.csproj">
- <Project>{26D857FB-EEE3-4A5B-95BC-DAB39F880A99}</Project>
- <Name>TestCases</Name>
+ <ProjectReference Include="Mono.Linker.Tests.Cases\Mono.Linker.Tests.Cases.csproj">
+ <Project>{B6BEE6AA-ADA0-4E1D-9A17-FBF2936F82B5}</Project>
+ <Name>Mono.Linker.Tests.Cases</Name>
+ </ProjectReference>
+ <ProjectReference Include="Mono.Linker.Tests.Cases.Expectations\Mono.Linker.Tests.Cases.Expectations.csproj">
+ <Project>{2C26601F-3E2F-45B9-A02F-58EE9296E19E}</Project>
+ <Name>Mono.Linker.Tests.Cases.Expectations</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
+ <ItemGroup>
+ <Compile Include="TestCases\TestSuites.cs" />
+ <Compile Include="TestCases\TestDatabase.cs" />
+ <Compile Include="Tests\PreserveActionComparisonTests.cs" />
+ <Compile Include="TestCasesRunner\LinkXmlHelpers.cs" />
+ <Compile Include="TestCasesRunner\LinkedTestCaseResult.cs" />
+ <Compile Include="TestCasesRunner\ManagedCompilationResult.cs" />
+ <Compile Include="TestCasesRunner\TestCaseCollector.cs" />
+ <Compile Include="TestCasesRunner\TestCaseLinkerOptions.cs" />
+ <Compile Include="TestCasesRunner\TestRunner.cs" />
+ <Compile Include="TestCases\TestCase.cs" />
+ <Compile Include="Extensions\NiceIO.cs" />
+ <Compile Include="Extensions\CecilExtensions.cs" />
+ <Compile Include="TestCasesRunner\ExpectationsProvider.cs" />
+ <Compile Include="TestCasesRunner\AssemblyChecker.cs" />
+ <Compile Include="TestCasesRunner\LinkerArgumentBuilder.cs" />
+ <Compile Include="TestCasesRunner\LinkerDriver.cs" />
+ <Compile Include="TestCasesRunner\ObjectFactory.cs" />
+ <Compile Include="TestCasesRunner\ResultChecker.cs" />
+ <Compile Include="TestCasesRunner\TestCaseCompiler.cs" />
+ <Compile Include="TestCasesRunner\TestCaseMetadaProvider.cs" />
+ <Compile Include="TestCasesRunner\TestCaseSandbox.cs" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/linker/Tests/Mono.Linker.Tests/AbstractLinkingTestFixture.cs b/linker/Tests/Mono.Linker.Tests/AbstractLinkingTestFixture.cs
deleted file mode 100644
index d25aeab32..000000000
--- a/linker/Tests/Mono.Linker.Tests/AbstractLinkingTestFixture.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-//
-// AbstractLinkingTestFixture.cs
-//
-// Author:
-// Jb Evain (jbevain@gmail.com)
-//
-// (C) 2006 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.IO;
-using Mono.Cecil;
-using Mono.Linker.Steps;
-using NUnit.Framework;
-using System.Linq;
-using System.Collections.Generic;
-
-namespace Mono.Linker.Tests
-{
-
- public abstract class AbstractLinkingTestFixture : AbstractTestFixture
- {
-
- [SetUp]
- public override void SetUp ()
- {
- base.SetUp ();
-
- TestCasesRoot = "Linker";
- }
-
- [TearDown]
- public override void TearDown ()
- {
- base.TearDown ();
-
- string output = GetOutputPath ();
- if (Directory.Exists (output))
- Directory.Delete (output, true);
- }
-
- protected override Pipeline GetPipeline ()
- {
- Pipeline p = new Pipeline ();
- p.AppendStep (new LoadReferencesStep ());
- p.AppendStep (new BlacklistStep ());
- p.AppendStep (new TypeMapStep ());
- p.AppendStep (new MarkStep ());
- p.AppendStep (new SweepStep ());
- p.AppendStep (new CleanStep ());
- p.AppendStep (new OutputStep ());
- return p;
- }
-
- protected override void RunTest (string testCase)
- {
- base.RunTest (testCase);
-
- Prepare ();
- }
-
- void Prepare ()
- {
- Context = GetContext ();
- string output = GetOutputPath ();
- if (Directory.Exists (output))
- Directory.Delete (output, true);
- Directory.CreateDirectory (output);
- }
-
- protected override void Run ()
- {
- base.Run ();
- Compare ();
- }
-
- void Compare ()
- {
- bool compared = false;
- foreach (AssemblyDefinition assembly in Context.GetAssemblies ()) {
- if (Context.Annotations.GetAction (assembly) != AssemblyAction.Link)
- continue;
-
- string fileName = GetAssemblyFileName (assembly);
-
- var original = AssemblyDefinition.ReadAssembly (Path.Combine (GetTestCasePath (), fileName));
- var linked = AssemblyDefinition.ReadAssembly (Path.Combine (GetOutputPath (), fileName));
- compared = CompareAssemblies (original, linked);
- }
-
- Assert.IsTrue (compared, $"No data compared (are you missing '{TestCase}' namespace for the test case?)");
- }
-
- bool CompareAssemblies (AssemblyDefinition original, AssemblyDefinition linked)
- {
- bool compared = false;
- foreach (TypeDefinition originalType in original.MainModule.Types) {
- if (!originalType.FullName.StartsWith (TestCase, System.StringComparison.Ordinal))
- continue;
-
- compared = true;
-
- TypeDefinition linkedType = linked.MainModule.Types.FirstOrDefault (l => l.FullName == originalType.FullName);
- if (MustBeLinked (originalType)) {
- Assert.IsNull (linkedType, string.Format ("Type `{0}' was not linked", originalType));
- continue;
- }
-
- Assert.IsNotNull (linkedType, string.Format ("Type `{0}' was linked", originalType));
- CompareTypes (originalType, linkedType);
- }
-
- return compared;
- }
-
- static void CompareTypes (TypeDefinition type, TypeDefinition linkedType)
- {
- foreach (FieldDefinition originalField in type.Fields) {
- IEnumerable<FieldDefinition> fd = linkedType.Fields;
- FieldDefinition linkedField = fd.FirstOrDefault (l => l.Name == originalField.Name);// TODO: also get with the type!
- if (MustBeLinked (originalField)) {
- Assert.IsNull (linkedField, string.Format ("Field `{0}' should not have been linked", originalField));
- continue;
- }
-
- Assert.IsNotNull (linkedField, string.Format ("Field `{0}' should have been linked", originalField));
- }
-
- foreach (MethodDefinition originalMethod in type.Methods) {
- MethodDefinition linkedMethod = linkedType.Methods.FirstOrDefault (l => l.Name == originalMethod.Name && l.Parameters.Count == originalMethod.Parameters.Count); // TODO: lame
- if (MustBeLinked (originalMethod)) {
- Assert.IsNull (linkedMethod, string.Format ("Method `{0}' was not linked", originalMethod));
- continue;
- }
-
- Assert.IsNotNull (linkedMethod, string.Format ("Method `{0}' was linked", originalMethod));
- }
- }
-
- static bool MustBeLinked (ICustomAttributeProvider provider)
- {
- foreach (CustomAttribute ca in provider.CustomAttributes)
- if (ca.Constructor.DeclaringType.Name == "AssertLinkedAttribute")
- return true;
-
- return false;
- }
- }
-}
diff --git a/linker/Tests/Mono.Linker.Tests/AbstractTestFixture.cs b/linker/Tests/Mono.Linker.Tests/AbstractTestFixture.cs
deleted file mode 100644
index 1ea047d73..000000000
--- a/linker/Tests/Mono.Linker.Tests/AbstractTestFixture.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-//
-// AbstractTestFixture.cs
-//
-// Author:
-// Jb Evain (jbevain@gmail.com)
-//
-// (C) 2006 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.IO;
-
-using Mono.Cecil;
-
-using NUnit.Framework;
-
-namespace Mono.Linker.Tests
-{
-
- public abstract class AbstractTestFixture
- {
-
- string _testCasesRoot;
- string _testCase;
- LinkContext _context;
- Pipeline _pipeline;
-
- protected LinkContext Context {
- get { return _context; }
- set { _context = value; }
- }
-
- protected Pipeline Pipeline {
- get { return _pipeline; }
- set { _pipeline = value; }
- }
-
- public string TestCasesRoot {
- get { return _testCasesRoot; }
- set { _testCasesRoot = value; }
- }
-
- public string TestCase {
- get { return _testCase; }
- set { _testCase = value; }
- }
-
- [SetUp]
- public virtual void SetUp ()
- {
- _pipeline = GetPipeline ();
- }
-
- [TearDown]
- public virtual void TearDown ()
- {
- }
-
- protected virtual Pipeline GetPipeline ()
- {
- return new Pipeline ();
- }
-
- protected virtual LinkContext GetContext ()
- {
- LinkContext context = new LinkContext (_pipeline);
- context.OutputDirectory = GetOutputPath ();
- context.CoreAction = AssemblyAction.Copy;
- return context;
- }
-
- protected string GetOutputPath ()
- {
- return Path.Combine (
- Path.GetTempPath (),
- _testCase);
- }
-
- protected string GetTestCasePath ()
- {
- return Path.GetDirectoryName (GetType ().Assembly.Location);
- }
-
- protected virtual void RunTest (string testCase)
- {
- _testCase = testCase;
- _context = GetContext ();
- }
-
- protected virtual void Run ()
- {
- _pipeline.Process (_context);
- }
-
- protected static string GetAssemblyFileName (AssemblyDefinition asm)
- {
- return asm.Name.Name + (asm.MainModule.Kind == ModuleKind.Dll ? ".dll" : ".exe");
- }
- }
-}
diff --git a/linker/Tests/Mono.Linker.Tests/AssemblyInfo.cs b/linker/Tests/Mono.Linker.Tests/AssemblyInfo.cs
deleted file mode 100644
index 0c169fdd6..000000000
--- a/linker/Tests/Mono.Linker.Tests/AssemblyInfo.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// AssemblyInfo.cs
-//
-// Author:
-// Jb Evain (jbevain@gmail.com)
-//
-// (C) 2006 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-[assembly: AssemblyTitle ("Mono.Linker.Tests")]
-[assembly: AssemblyDescription ("NUnit tests for Mono's CIL Linker")]
-[assembly: AssemblyConfiguration ("")]
-[assembly: AssemblyProduct ("")]
-[assembly: AssemblyCopyright ("(C) 2006, Jb Evain")]
-[assembly: AssemblyCulture ("")]
-
-[assembly: CLSCompliant (false)]
-[assembly: ComVisible (false)]
-
diff --git a/linker/Tests/Mono.Linker.Tests/IntegrationTestFixture.cs b/linker/Tests/Mono.Linker.Tests/IntegrationTestFixture.cs
deleted file mode 100644
index f455f6559..000000000
--- a/linker/Tests/Mono.Linker.Tests/IntegrationTestFixture.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-//
-// IntegrationTestFixture.cs
-//
-// Author:
-// Jb Evain (jbevain@novell.com)
-//
-// (C) 2007 Novell, Inc.
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using Mono.Linker.Steps;
-using NUnit.Framework;
-
-namespace Mono.Linker.Tests {
-
- [TestFixture]
- public class IntegrationTestFixture : AbstractTestFixture {
-
- [SetUp]
- public override void SetUp ()
- {
- base.SetUp ();
-
- TestCasesRoot = "Integration";
- }
-
- [Test]
- public void TestHelloWorld ()
- {
- RunTest ("HelloWorld");
- }
-
- [Test]
- public void TestCrypto ()
- {
- RunTest ("Crypto");
- }
-
- protected override LinkContext GetContext()
- {
- LinkContext context = base.GetContext ();
- context.CoreAction = AssemblyAction.Link;
- return context;
- }
-
- protected override Pipeline GetPipeline ()
- {
- Pipeline p = new Pipeline ();
- p.AppendStep (new LoadReferencesStep ());
- p.AppendStep (new BlacklistStep ());
- p.AppendStep (new TypeMapStep ());
- p.AppendStep (new MarkStep ());
- p.AppendStep (new SweepStep ());
- p.AppendStep (new CleanStep ());
- p.AppendStep (new OutputStep ());
- return p;
- }
-
- protected override void RunTest (string testCase)
- {
- if (!OnMono ())
- Assert.Ignore ("Integration tests are only runnable on Mono");
-
- base.RunTest (testCase);
- string test = Path.Combine (GetTestCasePath (), "Test.exe");
-
- string original = Execute (GetTestCasePath (), "Test.exe");
-
- Pipeline.PrependStep (
- new ResolveFromAssemblyStep (
- test));
-
- Run ();
-
- string linked = Execute (Context.OutputDirectory, "Test.exe");
-
- Assert.AreEqual (original, linked);
- }
-
- static bool OnMono ()
- {
- return Type.GetType ("System.MonoType") != null;
- }
-
- static string Execute (string directory, string file)
- {
- Process p = new Process ();
- p.StartInfo.EnvironmentVariables ["MONO_PATH"] = directory;
- p.StartInfo.CreateNoWindow = true;
- p.StartInfo.WorkingDirectory = directory;
- p.StartInfo.FileName = "mono";
- p.StartInfo.Arguments = file;
- p.StartInfo.RedirectStandardOutput = true;
- p.StartInfo.UseShellExecute = false;
-
- p.Start ();
- p.WaitForExit ();
-
- return p.StandardOutput.ReadToEnd ();
- }
- }
-}
diff --git a/linker/Tests/Mono.Linker.Tests/LinkingTestFixture.cs b/linker/Tests/Mono.Linker.Tests/LinkingTestFixture.cs
deleted file mode 100644
index 6201f4885..000000000
--- a/linker/Tests/Mono.Linker.Tests/LinkingTestFixture.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// AssemblyLinkingTestFixture.cs
-//
-// Author:
-// Jb Evain (jbevain@gmail.com)
-//
-// (C) 2006 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.IO;
-using NUnit.Framework;
-
-namespace Mono.Linker.Tests {
-
- [TestFixture]
- public class LinkingTestFixture : AbstractLinkingTestFixture {
-
- [Test]
- public void TestSimple ()
- {
- RunTest ("Simple");
- }
-
- [Test]
- public void TestVirtualCall ()
- {
- RunTest ("VirtualCall");
- }
-
- [Test]
- public void TestMultipleReferences ()
- {
- RunTest ("MultipleReferences");
- }
-
- protected override void RunTest (string testCase)
- {
- var fullTestCaseName = "TestCases.Linker." + testCase;
- base.RunTest (fullTestCaseName);
-
- var step = new ResolveLinkedAssemblyStep (fullTestCaseName, Path.Combine (GetTestCasePath (), "TestCases.dll"));
-
- Pipeline.PrependStep (step);
-
- Run ();
- }
- }
-}
diff --git a/linker/Tests/Mono.Linker.Tests/ResolveLinkedAssemblyStep.cs b/linker/Tests/Mono.Linker.Tests/ResolveLinkedAssemblyStep.cs
deleted file mode 100644
index 7610288a2..000000000
--- a/linker/Tests/Mono.Linker.Tests/ResolveLinkedAssemblyStep.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using Mono.Linker.Steps;
-using Mono.Cecil;
-using System.Linq;
-using Mono.Collections.Generic;
-
-namespace Mono.Linker.Tests
-{
- class ResolveLinkedAssemblyStep : ResolveFromAssemblyStep
- {
- string testCase;
-
- public ResolveLinkedAssemblyStep (string testCase, string assembly)
- : base (assembly)
- {
- this.testCase = testCase;
- }
-
- protected override void ProcessLibrary (AssemblyDefinition assembly)
- {
- SetAction (Context, assembly, AssemblyAction.Link);
-
- Annotations.Push (assembly);
-
- foreach (TypeDefinition type in assembly.MainModule.Types)
- MarkType (type);
-
- Annotations.Pop ();
- }
-
- static bool MarkMember (ICustomAttributeProvider member)
- {
- if (!member.HasCustomAttributes)
- return false;
-
- return member.CustomAttributes.Any (l => l.AttributeType.FullName == "TestCases.MarkAttribute");
- }
-
- void MarkType (TypeDefinition type)
- {
- if (type.Namespace != testCase)
- return;
-
- if (MarkMember (type))
- Annotations.Mark (type);
-
- Annotations.Push (type);
-
- if (type.HasFields)
- MarkFields (type.Fields);
- if (type.HasMethods)
- MarkMethods (type.Methods);
- if (type.HasNestedTypes)
- foreach (var nested in type.NestedTypes)
- MarkType (nested);
-
- Annotations.Pop ();
- }
-
- void MarkFields (Collection<FieldDefinition> fields)
- {
- foreach (var field in fields) {
- if (MarkMember (field)) {
- Annotations.Mark (field.DeclaringType);
- Annotations.Mark (field);
- }
- }
- }
-
- void MarkMethods (Collection<MethodDefinition> methods)
- {
- foreach (MethodDefinition method in methods) {
- if (MarkMember(method)) {
- Annotations.Mark (method.DeclaringType);
- Annotations.Mark (method);
- Annotations.SetAction (method, MethodAction.Parse);
- }
- }
- }
- }
-}
diff --git a/linker/Tests/Mono.Linker.Tests/XmlLinkingTestFixture.cs b/linker/Tests/Mono.Linker.Tests/XmlLinkingTestFixture.cs
deleted file mode 100644
index c87b05f3b..000000000
--- a/linker/Tests/Mono.Linker.Tests/XmlLinkingTestFixture.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-//
-// XmlLinkingTestFixture.cs
-//
-// Author:
-// Jb Evain (jbevain@gmail.com)
-//
-// (C) 2006 Jb Evain
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.IO;
-using System.Xml.XPath;
-
-using Mono.Linker.Steps;
-using NUnit.Framework;
-
-namespace Mono.Linker.Tests {
-
- [TestFixture]
- public class XmlLinkingTestFixture : AbstractLinkingTestFixture {
-
- [Test]
- public void TestSimpleXml ()
- {
- RunTest ("SimpleXml");
- }
-
- [Test]
- public void TestInterface ()
- {
- RunTest ("Interface");
- }
-
- [Test]
- public void TestReferenceInVirtualMethod ()
- {
- RunTest ("ReferenceInVirtualMethod");
- }
-
- [Test]
- public void TestGenerics ()
- {
- RunTest ("Generics");
- }
-
- [Test]
- public void TestNestedNested ()
- {
- RunTest ("NestedNested");
- }
-
- [Test]
- public void TestPreserveFieldsRequired ()
- {
- RunTest ("PreserveFieldsRequired");
- }
-
- [Test]
- public void TestReferenceInAttributes ()
- {
- RunTest ("ReferenceInAttributes");
- }
-
- [Test]
- public void TestXmlPattern ()
- {
- RunTest ("XmlPattern");
- }
-
- protected override void RunTest (string testCase)
- {
- var fullTestCaseName = "TestCases.Xml." + testCase;
- string resourceName = fullTestCaseName + ".desc.xml";
-
- var ms = new MemoryStream ();
- var assembly = typeof (TestCases.AssertLinkedAttribute).Assembly;
- using (Stream stream = assembly.GetManifestResourceStream (resourceName)) {
- Assert.IsNotNull (stream, "Missing embedded desc.xml");
- using (StreamReader reader = new StreamReader (stream)) {
- stream.CopyTo (ms);
- }
- }
-
- ms.Seek (0, SeekOrigin.Begin);
-
- base.RunTest (fullTestCaseName);
-
- Pipeline.PrependStep (new ResolveFromXmlStep (new XPathDocument (ms)));
-
- string cd = Environment.CurrentDirectory;
- Environment.CurrentDirectory = GetTestCasePath ();
- try {
- Run ();
- } finally {
- Environment.CurrentDirectory = cd;
- }
- }
- }
-}
diff --git a/linker/Tests/TestCases/Integration/Crypto/Test.cs b/linker/Tests/TestCases/Integration/Crypto/Test.cs
deleted file mode 100644
index 8c38f9297..000000000
--- a/linker/Tests/TestCases/Integration/Crypto/Test.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-using System.Security.Cryptography;
-using System.Text;
-
-class Test {
-
- static void Main ()
- {
- byte [] foo = Encoding.UTF8.GetBytes ("foobared");
-
- HashAlgorithm ha = MD5.Create ();
- byte [] hash = ha.ComputeHash (foo);
-
- Console.WriteLine (Encoding.UTF8.GetString (hash));
- }
-}
diff --git a/linker/Tests/TestCases/Integration/Crypto/Test.exe b/linker/Tests/TestCases/Integration/Crypto/Test.exe
deleted file mode 100755
index 2decc4983..000000000
--- a/linker/Tests/TestCases/Integration/Crypto/Test.exe
+++ /dev/null
Binary files differ
diff --git a/linker/Tests/TestCases/Linker/MultipleReferences/Bar.cs b/linker/Tests/TestCases/Linker/MultipleReferences/Bar.cs
deleted file mode 100644
index 371d7e109..000000000
--- a/linker/Tests/TestCases/Linker/MultipleReferences/Bar.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-
-namespace TestCases.Linker.MultipleReferences
-{
- public class Bar
- {
- string bang = "bang !";
-
- public Bar ()
- {
- }
-
- public void Bang ()
- {
- Console.WriteLine (bang);
- }
- }
-}
diff --git a/linker/Tests/TestCases/Linker/MultipleReferences/Baz.cs b/linker/Tests/TestCases/Linker/MultipleReferences/Baz.cs
deleted file mode 100644
index 8dc3ad8b5..000000000
--- a/linker/Tests/TestCases/Linker/MultipleReferences/Baz.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace TestCases.Linker.MultipleReferences
-{
- public class Baz
- {
- public void Chain (Foo f)
- {
- f.b.Bang ();
- }
-
- [AssertLinked]
- public void Lurman ()
- {
- }
- }
-}
diff --git a/linker/Tests/TestCases/Linker/MultipleReferences/Foo.cs b/linker/Tests/TestCases/Linker/MultipleReferences/Foo.cs
deleted file mode 100644
index 78eaddd45..000000000
--- a/linker/Tests/TestCases/Linker/MultipleReferences/Foo.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace TestCases.Linker.MultipleReferences
-{
- public class Foo
- {
- public Bar b;
-
- public Foo (Bar b)
- {
- this.b = b;
- }
-
- public void UseBar ()
- {
- b.Bang ();
- }
-
- [AssertLinked]
- public void Blam ()
- {
- }
- }
-}
diff --git a/linker/Tests/TestCases/Linker/MultipleReferences/Program.cs b/linker/Tests/TestCases/Linker/MultipleReferences/Program.cs
deleted file mode 100644
index 2b4be8d27..000000000
--- a/linker/Tests/TestCases/Linker/MultipleReferences/Program.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace TestCases.Linker.MultipleReferences
-{
- public class Program
- {
- [Mark]
- public static int Main ()
- {
- Program p = new Program ();
- p.Run ();
-
- return 0;
- }
-
- void Run ()
- {
- Foo f = new Foo (new Bar ());
- f.UseBar ();
-
- Baz b = new Baz ();
- b.Chain (f);
- }
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Linker/Simple/Library.cs b/linker/Tests/TestCases/Linker/Simple/Library.cs
deleted file mode 100644
index 69f171375..000000000
--- a/linker/Tests/TestCases/Linker/Simple/Library.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System;
-
-namespace TestCases.Linker.Simple
-{
- public class Library
- {
- private int _pouet;
- [AssertLinked] private int _hey;
-
- public Library ()
- {
- _pouet = 1;
- }
-
- [AssertLinked]
- public Library (int pouet)
- {
- _pouet = pouet;
- }
-
- public int Hello ()
- {
- Console.WriteLine ("Hello");
- return _pouet;
- }
-
- [AssertLinked]
- public void Hey (int hey)
- {
- _hey = hey;
- Console.WriteLine (_hey);
- }
- }
-
- [AssertLinked]
- public class Toy
- {
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Linker/Simple/Program.cs b/linker/Tests/TestCases/Linker/Simple/Program.cs
deleted file mode 100644
index 9e5c67e58..000000000
--- a/linker/Tests/TestCases/Linker/Simple/Program.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace TestCases.Linker.Simple
-{
- public class Program
- {
- [Mark]
- public static int Test ()
- {
- Program p = new Program ();
- return p.Run ();
- }
-
- int Run ()
- {
- Library lib = new Library ();
- return lib.Hello ();
- }
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Linker/VirtualCall/Library.cs b/linker/Tests/TestCases/Linker/VirtualCall/Library.cs
deleted file mode 100644
index c2dae1f81..000000000
--- a/linker/Tests/TestCases/Linker/VirtualCall/Library.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-namespace TestCases.Linker.VirtualCall
-{
- public class Library
- {
- public Library ()
- {
- }
-
- public int Shebang ()
- {
- return Bang ();
- }
-
- protected virtual int Bang ()
- {
- return 1;
- }
- }
-
- public class PowerFulLibrary : Library
- {
- protected override int Bang ()
- {
- return 0;
- }
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Linker/VirtualCall/Library.dll b/linker/Tests/TestCases/Linker/VirtualCall/Library.dll
deleted file mode 100644
index 0f2ff3f93..000000000
--- a/linker/Tests/TestCases/Linker/VirtualCall/Library.dll
+++ /dev/null
Binary files differ
diff --git a/linker/Tests/TestCases/Linker/VirtualCall/Makefile b/linker/Tests/TestCases/Linker/VirtualCall/Makefile
deleted file mode 100644
index 356b52945..000000000
--- a/linker/Tests/TestCases/Linker/VirtualCall/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../../config.make
-
-all:
- MCS /t:library Library.cs
- MCS /r:Library.dll Program.cs
diff --git a/linker/Tests/TestCases/Linker/VirtualCall/Program.cs b/linker/Tests/TestCases/Linker/VirtualCall/Program.cs
deleted file mode 100644
index 49c041698..000000000
--- a/linker/Tests/TestCases/Linker/VirtualCall/Program.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace TestCases.Linker.VirtualCall
-{
- public class Program
- {
- [Mark]
- public static int Test ()
- {
- Program p = new Program ();
- return p.Run ();
- }
-
- int Run ()
- {
- Library lib = new PowerFulLibrary ();
- return lib.Shebang ();
- }
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Linker/VirtualCall/Program.exe b/linker/Tests/TestCases/Linker/VirtualCall/Program.exe
deleted file mode 100644
index f5a9bec00..000000000
--- a/linker/Tests/TestCases/Linker/VirtualCall/Program.exe
+++ /dev/null
Binary files differ
diff --git a/linker/Tests/TestCases/MarkAttribute.cs b/linker/Tests/TestCases/MarkAttribute.cs
deleted file mode 100644
index 7f73bc147..000000000
--- a/linker/Tests/TestCases/MarkAttribute.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-
-namespace TestCases
-{
- [AttributeUsage (AttributeTargets.Method | AttributeTargets.Field)]
- public class MarkAttribute : Attribute
- {
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/NotLinkedAttribute.cs b/linker/Tests/TestCases/NotLinkedAttribute.cs
deleted file mode 100644
index 82bd1ea68..000000000
--- a/linker/Tests/TestCases/NotLinkedAttribute.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System;
-
-namespace TestCases
-{
- [AttributeUsage (AttributeTargets.All)]
- public class AssertLinkedAttribute : Attribute
- {
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/TestCase.cs b/linker/Tests/TestCases/TestCase.cs
new file mode 100644
index 000000000..cb73b6685
--- /dev/null
+++ b/linker/Tests/TestCases/TestCase.cs
@@ -0,0 +1,42 @@
+using System;
+using Mono.Linker.Tests.Extensions;
+
+namespace Mono.Linker.Tests.TestCases {
+ public class TestCase {
+ public TestCase (NPath sourceFile, NPath rootCasesDirectory, NPath originalTestCaseAssemblyPath)
+ {
+ SourceFile = sourceFile;
+ OriginalTestCaseAssemblyPath = originalTestCaseAssemblyPath;
+ Name = sourceFile.FileNameWithoutExtension;
+ DisplayName = $"{sourceFile.RelativeTo (rootCasesDirectory).Parent.ToString (SlashMode.Forward).Replace ('/', '.')}.{sourceFile.FileNameWithoutExtension}";
+
+ // A little hacky, but good enough for name. No reason why namespace & type names
+ // should not follow the directory structure
+ ReconstructedFullTypeName = $"{sourceFile.Parent.RelativeTo (rootCasesDirectory.Parent).ToString (SlashMode.Forward).Replace ('/', '.')}.{sourceFile.FileNameWithoutExtension}";
+ }
+
+ public string Name { get; }
+
+ public string DisplayName { get; }
+
+ public NPath SourceFile { get; }
+
+ public NPath OriginalTestCaseAssemblyPath { get; }
+
+ public string ReconstructedFullTypeName { get; }
+
+ public bool HasLinkXmlFile {
+ get { return SourceFile.ChangeExtension ("xml").FileExists (); }
+ }
+
+ public NPath LinkXmlFile {
+ get
+ {
+ if (!HasLinkXmlFile)
+ throw new InvalidOperationException ("This test case does not have a link xml file");
+
+ return SourceFile.ChangeExtension ("xml");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCases/TestCases.csproj b/linker/Tests/TestCases/TestCases.csproj
deleted file mode 100644
index 451fe7952..000000000
--- a/linker/Tests/TestCases/TestCases.csproj
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProjectGuid>{26D857FB-EEE3-4A5B-95BC-DAB39F880A99}</ProjectGuid>
- <OutputType>Library</OutputType>
- <RootNamespace>TestCases</RootNamespace>
- <AssemblyName>TestCases</AssemblyName>
- <TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug</OutputPath>
- <DefineConstants>DEBUG;</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <Optimize>true</Optimize>
- <OutputPath>bin\Release</OutputPath>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- </ItemGroup>
- <ItemGroup>
- </ItemGroup>
- <ItemGroup>
- </ItemGroup>
- <ItemGroup>
- <Compile Include="NotLinkedAttribute.cs" />
- <Compile Include="Linker\Simple\Library.cs" />
- <Compile Include="Linker\Simple\Program.cs" />
- <Compile Include="MarkAttribute.cs" />
- <Compile Include="Linker\VirtualCall\Library.cs" />
- <Compile Include="Linker\VirtualCall\Program.cs" />
- <Compile Include="Linker\MultipleReferences\Bar.cs" />
- <Compile Include="Linker\MultipleReferences\Baz.cs" />
- <Compile Include="Linker\MultipleReferences\Foo.cs" />
- <Compile Include="Linker\MultipleReferences\Program.cs" />
- <Compile Include="Xml\Generics\Library.cs" />
- <Compile Include="Xml\SimpleXml\Library.cs" />
- <Compile Include="Xml\Interface\Library.cs" />
- <Compile Include="Xml\PreserveFieldsRequired\Library.cs" />
- <Compile Include="Xml\NestedNested\Library.cs" />
- <Compile Include="Xml\ReferenceInVirtualMethod\Library.cs" />
- <Compile Include="Xml\XmlPattern\Library.cs" />
- <Compile Include="Xml\ReferenceInAttributes\LibLib.cs" />
- <Compile Include="Xml\ReferenceInAttributes\Library.cs" />
- </ItemGroup>
- <ItemGroup>
- <Folder Include="Xml\" />
- </ItemGroup>
- <ItemGroup>
- <EmbeddedResource Include="Xml\Generics\desc.xml" />
- <EmbeddedResource Include="Xml\SimpleXml\desc.xml" />
- <EmbeddedResource Include="Xml\Interface\desc.xml" />
- <EmbeddedResource Include="Xml\PreserveFieldsRequired\desc.xml" />
- <EmbeddedResource Include="Xml\NestedNested\desc.xml" />
- <EmbeddedResource Include="Xml\ReferenceInVirtualMethod\desc.xml" />
- <EmbeddedResource Include="Xml\XmlPattern\desc.xml" />
- <EmbeddedResource Include="Xml\ReferenceInAttributes\desc.xml" />
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-</Project> \ No newline at end of file
diff --git a/linker/Tests/TestCases/TestDatabase.cs b/linker/Tests/TestCases/TestDatabase.cs
new file mode 100644
index 000000000..2575b8d46
--- /dev/null
+++ b/linker/Tests/TestCases/TestDatabase.cs
@@ -0,0 +1,108 @@
+using System.Linq;
+using System.Collections.Generic;
+using NUnit.Framework;
+using System.Runtime.CompilerServices;
+using System.IO;
+using Mono.Linker.Tests.TestCasesRunner;
+
+namespace Mono.Linker.Tests.TestCases
+{
+ static class TestDatabase
+ {
+ public static IEnumerable<TestCaseData> XmlTests()
+ {
+ return NUnitCasesByPrefix("LinkXml.");
+ }
+
+ public static IEnumerable<TestCaseData> BasicTests()
+ {
+ return NUnitCasesByPrefix("Basic.");
+ }
+
+ public static IEnumerable<TestCaseData> VirtualMethodsTests()
+ {
+ return NUnitCasesByPrefix("VirtualMethods.");
+ }
+
+ public static IEnumerable<TestCaseData> AttributeTests()
+ {
+ return NUnitCasesByPrefix("Attributes.");
+ }
+
+ public static IEnumerable<TestCaseData> GenericsTests()
+ {
+ return NUnitCasesByPrefix("Generics.");
+ }
+
+ public static IEnumerable<TestCaseData> CoreLinkTests()
+ {
+ return NUnitCasesByPrefix("CoreLink.");
+ }
+
+ public static IEnumerable<TestCaseData> StaticsTests()
+ {
+ return NUnitCasesByPrefix("Statics.");
+ }
+
+ public static IEnumerable<TestCaseData> InteropTests()
+ {
+ return NUnitCasesByPrefix("Interop.");
+ }
+
+ public static IEnumerable<TestCaseData> ReferencesTests()
+ {
+ return NUnitCasesByPrefix("References.");
+ }
+
+ public static IEnumerable<TestCaseData> OtherTests()
+ {
+ var allGroupedTestNames = new HashSet<string>(
+ XmlTests()
+ .Concat(BasicTests())
+ .Concat(XmlTests())
+ .Concat(VirtualMethodsTests())
+ .Concat(AttributeTests())
+ .Concat(GenericsTests())
+ .Concat(CoreLinkTests())
+ .Concat(StaticsTests())
+ .Concat(InteropTests())
+ .Concat(ReferencesTests ())
+ .Select(c => ((TestCase)c.Arguments[0]).ReconstructedFullTypeName));
+
+ return AllCases().Where(c => !allGroupedTestNames.Contains(c.ReconstructedFullTypeName)).Select(c => CreateNUnitTestCase(c, c.DisplayName));
+ }
+
+ static IEnumerable<TestCase> AllCases()
+ {
+ string rootSourceDirectory;
+ string testCaseAssemblyPath;
+ GetDirectoryPaths(out rootSourceDirectory, out testCaseAssemblyPath);
+ return new TestCaseCollector(rootSourceDirectory, testCaseAssemblyPath)
+ .Collect()
+ .OrderBy(c => c.DisplayName)
+ .ToArray();
+ }
+
+ static IEnumerable<TestCaseData> NUnitCasesByPrefix(string testNamePrefix)
+ {
+ return AllCases()
+ .Where(c => c.DisplayName.StartsWith(testNamePrefix))
+ .Select(c => CreateNUnitTestCase(c, c.DisplayName.Substring(testNamePrefix.Length)))
+ .OrderBy(c => c.TestName);
+ }
+
+ static TestCaseData CreateNUnitTestCase(TestCase testCase, string displayName)
+ {
+ var data = new TestCaseData(testCase);
+ data.SetName(displayName);
+ return data;
+ }
+
+ static void GetDirectoryPaths(out string rootSourceDirectory, out string testCaseAssemblyPath, [CallerFilePath] string thisFile = null)
+ {
+ var thisDirectory = Path.GetDirectoryName(thisFile);
+ rootSourceDirectory = Path.GetFullPath(Path.Combine(thisDirectory, "..", "Mono.Linker.Tests.Cases"));
+ testCaseAssemblyPath = Path.GetFullPath(Path.Combine(rootSourceDirectory, "bin", "Debug", "Mono.Linker.Tests.Cases.dll"));
+ }
+ }
+}
diff --git a/linker/Tests/TestCases/TestSuites.cs b/linker/Tests/TestCases/TestSuites.cs
new file mode 100644
index 000000000..ca5a0eb7e
--- /dev/null
+++ b/linker/Tests/TestCases/TestSuites.cs
@@ -0,0 +1,76 @@
+using Mono.Linker.Tests.TestCasesRunner;
+using NUnit.Framework;
+
+namespace Mono.Linker.Tests.TestCases
+{
+ [TestFixture]
+ public class All
+ {
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.BasicTests))]
+ public void BasicTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.VirtualMethodsTests))]
+ public void VirtualMethodTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.XmlTests))]
+ public void XmlTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.AttributeTests))]
+ public void AttributesTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.GenericsTests))]
+ public void GenericsTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.StaticsTests))]
+ public void StaticsTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.CoreLinkTests))]
+ public void CoreLinkTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.InteropTests))]
+ public void InteropTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ [TestCaseSource(typeof(TestDatabase), nameof(TestDatabase.ReferencesTests))]
+ public void ReferencesTests(TestCase testCase)
+ {
+ Run(testCase);
+ }
+
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.OtherTests))]
+ public void OtherTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
+ protected virtual void Run (TestCase testCase)
+ {
+ var runner = new TestRunner (new ObjectFactory ());
+ var linkedResult = runner.Run (testCase);
+ new ResultChecker ().Check (linkedResult);
+ }
+ }
+}
diff --git a/linker/Tests/TestCases/Xml/Generics/Library.cs b/linker/Tests/TestCases/Xml/Generics/Library.cs
deleted file mode 100644
index 9505cb2f9..000000000
--- a/linker/Tests/TestCases/Xml/Generics/Library.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-
-namespace TestCases.Xml.Generics
-{
- public class Foo
- {
- void Bar ()
- {
- int i = 42;
- string s = "hey";
-
- Baz<int> bi = new Baz<int> (i);
- bi.Gazonk ();
- bi.Bat<string> (i, s);
-
- Baz<string> bs = new Baz<string> (s);
- bs.Gazonk ();
- bs.Bat<int> (s, i);
- bs.BiroBiro ();
-
- bs.Blam<Bang> ();
- }
- }
-
- public class Baz<T>
- {
- T _t;
-
- public Baz (T t)
- {
- _t = t;
- }
-
- public void Gazonk ()
- {
- Console.WriteLine (_t);
- }
-
- public void Bat<M> (T t, M m)
- {
- Console.WriteLine ("{0}{1}", t, m);
- }
-
- public void Blam<M> ()
- {
- }
-
- public T [] BiroBiro ()
- {
- return new T [0];
- }
- }
-
- class Bang
- {
- [AssertLinked]
- public Bang ()
- {
- }
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Xml/Generics/desc.xml b/linker/Tests/TestCases/Xml/Generics/desc.xml
deleted file mode 100644
index d84422937..000000000
--- a/linker/Tests/TestCases/Xml/Generics/desc.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.Generics.Foo" />
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCases/Xml/Interface/Library.cs b/linker/Tests/TestCases/Xml/Interface/Library.cs
deleted file mode 100644
index 4bbedd4ba..000000000
--- a/linker/Tests/TestCases/Xml/Interface/Library.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace TestCases.Xml.Interface
-{
- public class Foo : IFoo
- {
- public void Gazonk ()
- {
- }
- }
-
- public interface IFoo : IBar
- {
- }
-
- public interface IBar
- {
- [AssertLinked]
- void Gazonk ();
- }
-
- [AssertLinked]
- public class Baz : IBaz
- {
- }
-
- [AssertLinked]
- public interface IBaz
- {
- }
-}
diff --git a/linker/Tests/TestCases/Xml/Interface/desc.xml b/linker/Tests/TestCases/Xml/Interface/desc.xml
deleted file mode 100644
index 2cba1a23d..000000000
--- a/linker/Tests/TestCases/Xml/Interface/desc.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.Interface.Foo" />
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCases/Xml/NestedNested/Library.cs b/linker/Tests/TestCases/Xml/NestedNested/Library.cs
deleted file mode 100644
index 5e024ab6c..000000000
--- a/linker/Tests/TestCases/Xml/NestedNested/Library.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace TestCases.Xml.NestedNested
-{
- public class Foo
- {
- }
-
- [AssertLinked]
- public class Bar
- {
- [AssertLinked]
- public class Baz
- {
- [AssertLinked]
- public class Gazonk
- {
- }
- }
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Xml/NestedNested/desc.xml b/linker/Tests/TestCases/Xml/NestedNested/desc.xml
deleted file mode 100644
index 28a21adde..000000000
--- a/linker/Tests/TestCases/Xml/NestedNested/desc.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.NestedNested.Foo" />
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCases/Xml/PreserveFieldsRequired/Library.cs b/linker/Tests/TestCases/Xml/PreserveFieldsRequired/Library.cs
deleted file mode 100644
index edf9e340c..000000000
--- a/linker/Tests/TestCases/Xml/PreserveFieldsRequired/Library.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-namespace TestCases.Xml.PreserveFieldsRequired
-{
- public class Foo
- {
- public Foo ()
- {
- new NotRequiredButUsedNotPreserved ();
- new NotRequiredButUsedAndFieldsPreserved ();
- }
- }
-
- public class NotRequiredButUsedNotPreserved
- {
-
- [AssertLinked] public int foo;
- [AssertLinked] public int bar;
- }
-
- public class NotRequiredButUsedAndFieldsPreserved
- {
- public int foo;
- public int bar;
-
- [AssertLinked]
- public int FooBar ()
- {
- return foo + bar;
- }
- }
-
- [AssertLinked]
- public class NotRequiredAndNotUsed
- {
- }
-}
diff --git a/linker/Tests/TestCases/Xml/PreserveFieldsRequired/desc.xml b/linker/Tests/TestCases/Xml/PreserveFieldsRequired/desc.xml
deleted file mode 100644
index e7f7d5c53..000000000
--- a/linker/Tests/TestCases/Xml/PreserveFieldsRequired/desc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.PreserveFieldsRequired.Foo" />
- <type fullname="TestCases.Xml.PreserveFieldsRequired.NotRequiredButUsedNotPreserved" preserve="nothing" required="false" />
- <type fullname="TestCases.Xml.PreserveFieldsRequired.NotRequiredButUsedAndFieldsPreserved" preserve="fields" required="false" />
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCases/Xml/ReferenceInAttributes/LibLib.cs b/linker/Tests/TestCases/Xml/ReferenceInAttributes/LibLib.cs
deleted file mode 100644
index c42523e6e..000000000
--- a/linker/Tests/TestCases/Xml/ReferenceInAttributes/LibLib.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-
-namespace TestCases.Xml.ReferenceInAttributes
-{
- public class LibLibAttribute : Attribute
- {
- public Type LibLibType {
- [AssertLinked]
- get { return null; }
- set { }
- }
- }
-
- public class BilBil
- {
-
- [AssertLinked]
- public BilBil ()
- {
- }
- }
-}
-
diff --git a/linker/Tests/TestCases/Xml/ReferenceInAttributes/Library.cs b/linker/Tests/TestCases/Xml/ReferenceInAttributes/Library.cs
deleted file mode 100644
index 4d2c4ba28..000000000
--- a/linker/Tests/TestCases/Xml/ReferenceInAttributes/Library.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-
-namespace TestCases.Xml.ReferenceInAttributes
-{
- public class BarAttribute : Attribute
- {
- public BarAttribute ()
- {
- }
-
- public BarAttribute (Type type)
- {
- }
-
- public Type FieldType;
-
- public Type PropertyType {
- [AssertLinked]
- get { return null; }
- set { }
- }
- }
-
- [Bar (typeof (Guy_A))]
- public class Foo
- {
-
- [Bar (FieldType = typeof (Guy_B))]
- public Foo a;
-
- [Bar (PropertyType = typeof (Guy_C))]
- public Foo b;
-
- [LibLib (LibLibType = typeof (BilBil))]
- public Foo c;
-
- [LibLib (LibLibType = typeof (Guy_D))]
- public Foo d;
- }
-
- public class Guy_A
- {
-
- [AssertLinked]
- public Guy_A ()
- {
- }
- }
-
- public class Guy_B
- {
-
- [AssertLinked]
- public Guy_B ()
- {
- }
- }
-
- public class Guy_C
- {
-
- [AssertLinked]
- public Guy_C ()
- {
- }
- }
-
- public class Guy_D
- {
-
- [AssertLinked]
- public Guy_D ()
- {
- }
- }
-
- [AssertLinked]
- public class Baz
- {
- }
-}
diff --git a/linker/Tests/TestCases/Xml/ReferenceInAttributes/desc.xml b/linker/Tests/TestCases/Xml/ReferenceInAttributes/desc.xml
deleted file mode 100644
index 927ba58e6..000000000
--- a/linker/Tests/TestCases/Xml/ReferenceInAttributes/desc.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.ReferenceInAttributes.Foo" />
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/Library.cs b/linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/Library.cs
deleted file mode 100644
index 8c0ee9c98..000000000
--- a/linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/Library.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-
-namespace TestCases.Xml.ReferenceInVirtualMethod
-{
- public class Foo
- {
- public void Do ()
- {
- Bar b = new Baz ();
- b.Bang ();
- }
- }
-
- public class Bar
- {
- public virtual void Bang ()
- {
- }
- }
-
- public class Baz : Bar
- {
- private string _hey;
-
- public string Hey {
- [AssertLinked]
- get { return _hey; }
- [AssertLinked]
- set { _hey = value; }
- }
-
- public override void Bang ()
- {
- Console.WriteLine (_hey);
- }
- }
-}
diff --git a/linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/desc.xml b/linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/desc.xml
deleted file mode 100644
index 1372a44b9..000000000
--- a/linker/Tests/TestCases/Xml/ReferenceInVirtualMethod/desc.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.ReferenceInVirtualMethod.Foo" />
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCases/Xml/SimpleXml/Library.cs b/linker/Tests/TestCases/Xml/SimpleXml/Library.cs
deleted file mode 100644
index f36710f8a..000000000
--- a/linker/Tests/TestCases/Xml/SimpleXml/Library.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-
-namespace TestCases.Xml.SimpleXml
-{
- public class Foo
- {
-
- int _baz;
- [AssertLinked] int _shebang;
-
- public Foo ()
- {
- _baz = 42;
- }
-
- public int Baz ()
- {
- return _baz;
- }
-
- [AssertLinked]
- public int Shebang (int bang)
- {
- return _shebang = bang * 2;
- }
- }
-
- public class Bar
- {
-
- int _truc;
-
- public Bar ()
- {
- _truc = 12;
- }
-
- public int Truc ()
- {
- return _truc;
- }
- }
-
- [AssertLinked]
- public class Gazonk
- {
- }
-}
diff --git a/linker/Tests/TestCases/Xml/SimpleXml/desc.xml b/linker/Tests/TestCases/Xml/SimpleXml/desc.xml
deleted file mode 100644
index 552a4a326..000000000
--- a/linker/Tests/TestCases/Xml/SimpleXml/desc.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.SimpleXml.Foo">
- <field signature="System.Int32 _baz" />
- <method signature="System.Void .ctor()" />
- <method signature="System.Int32 Baz()" />
- </type>
- <type fullname="TestCases.Xml.SimpleXml.Bar" />
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCases/Xml/XmlPattern/Library.cs b/linker/Tests/TestCases/Xml/XmlPattern/Library.cs
deleted file mode 100755
index eb40b473f..000000000
--- a/linker/Tests/TestCases/Xml/XmlPattern/Library.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-namespace TestCases.Xml.XmlPattern
-{
- [AssertLinked]
- public class BarBar
- {
- }
-
- public class FooBaz
- {
-
- public FooBaz ()
- {
- }
-
- [AssertLinked]
- public void BarBaz ()
- {
- }
- }
-
- public class TrucBaz
- {
-
- public TrucBaz ()
- {
- }
- }
-
- public class BazBaz
- {
-
- public BazBaz ()
- {
- }
- }
-} \ No newline at end of file
diff --git a/linker/Tests/TestCases/Xml/XmlPattern/desc.xml b/linker/Tests/TestCases/Xml/XmlPattern/desc.xml
deleted file mode 100755
index 19ca58298..000000000
--- a/linker/Tests/TestCases/Xml/XmlPattern/desc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<linker>
- <assembly fullname="TestCases">
- <type fullname="TestCases.Xml.XmlPattern.*Baz">
- <method signature="System.Void .ctor()" />
- </type>
- </assembly>
-</linker>
diff --git a/linker/Tests/TestCasesRunner/AssemblyChecker.cs b/linker/Tests/TestCasesRunner/AssemblyChecker.cs
new file mode 100644
index 000000000..e9ed80abc
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/AssemblyChecker.cs
@@ -0,0 +1,323 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Mono.Cecil;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Extensions;
+using NUnit.Framework;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ class AssemblyChecker {
+ readonly AssemblyDefinition originalAssembly, linkedAssembly;
+
+ HashSet<string> linkedMembers;
+ HashSet<string> verifiedBackingFields = new HashSet<string> ();
+
+ public AssemblyChecker (AssemblyDefinition original, AssemblyDefinition linked)
+ {
+ this.originalAssembly = original;
+ this.linkedAssembly = linked;
+ }
+
+ public void Verify ()
+ {
+ // TODO: Implement fully, probably via custom Kept attribute
+ Assert.IsFalse (linkedAssembly.MainModule.HasExportedTypes);
+
+ VerifyCustomAttributes (linkedAssembly, originalAssembly);
+
+ linkedMembers = new HashSet<string> (linkedAssembly.MainModule.AllMembers ().Select (s => {
+ return s.FullName;
+ }), StringComparer.Ordinal);
+
+ var membersToAssert = originalAssembly.MainModule.Types;
+ foreach (var originalMember in membersToAssert) {
+ var td = originalMember as TypeDefinition;
+ if (td != null) {
+ if (td.Name == "<Module>") {
+ linkedMembers.Remove (td.Name);
+ continue;
+ }
+
+ TypeDefinition linkedType = linkedAssembly.MainModule.GetType (originalMember.FullName);
+ VerifyTypeDefinition (td, linkedType);
+ linkedMembers.Remove (td.FullName);
+
+ continue;
+ }
+
+ throw new NotImplementedException ($"Don't know how to check member of type {originalMember.GetType ()}");
+ }
+
+ Assert.IsEmpty (linkedMembers, "Linked output includes unexpected member");
+ }
+
+ protected virtual void VerifyTypeDefinition (TypeDefinition original, TypeDefinition linked)
+ {
+ ModuleDefinition linkedModule = linked?.Module;
+
+ //
+ // Little bit complex check to allow easier test writting to match
+ // - It has [Kept] attribute or any variation of it
+ // - It contains Main method
+ // - It contains at least one member which has [Kept] attribute (not recursive)
+ //
+ bool expectedKept =
+ original.HasAttributeDerivedFrom (nameof (KeptAttribute)) ||
+ (linked != null && linkedModule.Assembly.EntryPoint.DeclaringType == linked) ||
+ original.AllMembers ().Any (l => l.HasAttribute (nameof (KeptAttribute)));
+
+ if (!expectedKept) {
+ if (linked != null)
+ Assert.Fail ($"Type `{original}' should have been removed");
+
+ return;
+ }
+
+ if (linked == null)
+ Assert.Fail ($"Type `{original}' should have been kept");
+
+ if (!original.IsInterface)
+ VerifyBaseType (original, linked);
+
+ VerifyInterfaces (original, linked);
+
+ VerifyGenericParameters (original, linked);
+ VerifyCustomAttributes (original, linked);
+
+ foreach (var td in original.NestedTypes) {
+ VerifyTypeDefinition (td, linked?.NestedTypes.FirstOrDefault (l => td.FullName == l.FullName));
+ linkedMembers.Remove (td.FullName);
+ }
+
+ // Need to check properties before fields so that the KeptBackingFieldAttribute is handled correctly
+ foreach (var p in original.Properties) {
+ VerifyProperty (p, linked?.Properties.FirstOrDefault (l => p.Name == l.Name), linked);
+ linkedMembers.Remove (p.FullName);
+ }
+
+ foreach (var f in original.Fields) {
+ if (verifiedBackingFields.Contains (f.FullName))
+ continue;
+ VerifyField (f, linked?.Fields.FirstOrDefault (l => f.Name == l.Name));
+ linkedMembers.Remove (f.FullName);
+ }
+
+ foreach (var m in original.Methods) {
+ VerifyMethod (m, linked?.Methods.FirstOrDefault (l => m.GetSignature () == l.GetSignature ()));
+ linkedMembers.Remove (m.FullName);
+ }
+
+ foreach (var e in original.Events) {
+ VerifyEvent (e, linked?.Events.FirstOrDefault (l => e.Name == l.Name));
+ linkedMembers.Remove (e.FullName);
+ }
+ }
+
+ void VerifyBaseType (TypeDefinition src, TypeDefinition linked)
+ {
+ string expectedBaseName;
+ var expectedBaseGenericAttr = src.CustomAttributes.FirstOrDefault (w => w.AttributeType.Name == nameof (KeptBaseTypeAttribute) && w.ConstructorArguments.Count > 1);
+ if (expectedBaseGenericAttr != null) {
+ StringBuilder builder = new StringBuilder ();
+ builder.Append (expectedBaseGenericAttr.ConstructorArguments [0].Value);
+ builder.Append ("<");
+ bool separator = false;
+ foreach (var caa in (CustomAttributeArgument[])expectedBaseGenericAttr.ConstructorArguments [1].Value) {
+ if (separator)
+ builder.Append (",");
+ else
+ separator = true;
+
+ var arg = (CustomAttributeArgument)caa.Value;
+ builder.Append (arg.Value);
+ }
+
+ builder.Append (">");
+ expectedBaseName = builder.ToString ();
+ } else {
+ expectedBaseName = GetCustomAttributeCtorValues<object> (src, nameof (KeptBaseTypeAttribute)).FirstOrDefault ()?.ToString () ?? "System.Object";
+ }
+ Assert.AreEqual (expectedBaseName, linked.BaseType?.FullName);
+ }
+
+ void VerifyInterfaces (TypeDefinition src, TypeDefinition linked)
+ {
+ var expectedInterfaces = new HashSet<string> (GetCustomAttributeCtorValues<object> (src, nameof (KeptInterfaceAttribute)).Select (val => val.ToString ()));
+ if (expectedInterfaces.Count == 0) {
+ Assert.IsFalse (linked.HasInterfaces, $"Type `{src}' has unexpected interfaces");
+ } else {
+ foreach (var iface in linked.Interfaces) {
+ Assert.IsTrue (expectedInterfaces.Remove (iface.InterfaceType.FullName), $"Type `{src}' interface `{iface.InterfaceType.FullName}' should have been removed");
+ }
+
+ Assert.IsEmpty (expectedInterfaces);
+ }
+ }
+
+ void VerifyField (FieldDefinition src, FieldDefinition linked)
+ {
+ bool expectedKept = ShouldBeKept (src);
+
+ if (!expectedKept) {
+ if (linked != null)
+ Assert.Fail ($"Field `{src}' should have been removed");
+
+ return;
+ }
+
+ VerifyFieldKept (src, linked);
+ }
+
+ void VerifyFieldKept (FieldDefinition src, FieldDefinition linked)
+ {
+ if (linked == null)
+ Assert.Fail ($"Field `{src}' should have been kept");
+
+ Assert.AreEqual (src?.Attributes, linked?.Attributes, $"Field `{src}' attributes");
+ Assert.AreEqual (src?.Constant, linked?.Constant, $"Field `{src}' value");
+
+ VerifyCustomAttributes (src, linked);
+ }
+
+ void VerifyProperty (PropertyDefinition src, PropertyDefinition linked, TypeDefinition linkedType)
+ {
+ VerifyBackingField (src, linkedType);
+
+ bool expectedKept = ShouldBeKept (src);
+
+ if (!expectedKept) {
+ if (linked != null)
+ Assert.Fail ($"Property `{src}' should have been removed");
+
+ return;
+ }
+
+ if (linked == null)
+ Assert.Fail ($"Property `{src}' should have been kept");
+
+ Assert.AreEqual (src?.Attributes, linked?.Attributes, $"Property `{src}' attributes");
+ Assert.AreEqual (src?.Constant, linked?.Constant, $"Property `{src}' value");
+
+ VerifyCustomAttributes (src, linked);
+ }
+
+ void VerifyEvent (EventDefinition src, EventDefinition linked)
+ {
+ bool expectedKept = ShouldBeKept (src);
+
+ if (!expectedKept) {
+ if (linked != null)
+ Assert.Fail ($"Event `{src}' should have been removed");
+
+ return;
+ }
+
+ if (linked == null)
+ Assert.Fail ($"Event `{src}' should have been kept");
+
+ Assert.AreEqual (src?.Attributes, linked?.Attributes, $"Event `{src}' attributes");
+
+ VerifyCustomAttributes (src, linked);
+ }
+
+ void VerifyMethod (MethodDefinition src, MethodDefinition linked)
+ {
+ var srcSignature = src.GetSignature ();
+ bool expectedKept = ShouldBeKept (src, srcSignature) || (linked != null && linked.DeclaringType.Module.EntryPoint == linked);
+
+ if (!expectedKept) {
+ if (linked != null)
+ Assert.Fail ($"Method `{src.FullName}' should have been removed");
+
+ return;
+ }
+
+ if (linked == null)
+ Assert.Fail ($"Method `{src.FullName}' should have been kept");
+
+ Assert.AreEqual (src?.Attributes, linked?.Attributes, $"Method `{src}' attributes");
+
+ VerifyGenericParameters (src, linked);
+ VerifyCustomAttributes (src, linked);
+ }
+
+ void VerifyBackingField (PropertyDefinition src, TypeDefinition linkedType)
+ {
+ var keptBackingFieldAttribute = src.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (KeptBackingFieldAttribute));
+ if (keptBackingFieldAttribute == null)
+ return;
+
+ var backingFieldName = $"<{src.Name}>k__BackingField";
+ var srcField = src.DeclaringType.Fields.FirstOrDefault (f => f.Name == backingFieldName);
+
+ if (srcField == null) {
+ // Can add more here if necessary
+ backingFieldName = backingFieldName.Replace ("System.Int32", "int");
+ backingFieldName = backingFieldName.Replace ("System.String", "string");
+ backingFieldName = backingFieldName.Replace ("System.Char", "char");
+
+ srcField = src.DeclaringType.Fields.FirstOrDefault (f => f.Name == backingFieldName);
+ }
+
+ if (srcField == null)
+ Assert.Fail ($"Property `{src}', could not locate the expected backing field {backingFieldName}");
+
+ VerifyFieldKept (srcField, linkedType?.Fields.FirstOrDefault (l => srcField.Name == l.Name));
+ verifiedBackingFields.Add (srcField.FullName);
+ linkedMembers.Remove (srcField.FullName);
+ }
+
+ static void VerifyCustomAttributes (ICustomAttributeProvider src, ICustomAttributeProvider linked)
+ {
+ var expectedAttrs = new List<string> (GetCustomAttributeCtorValues<string> (src, nameof (KeptAttributeAttribute)));
+ var linkedAttrs = new List<string> (FilterLinkedAttributes (linked));
+
+ // FIXME: Linker unused attributes removal is not working
+ // Assert.That (linkedAttrs, Is.EquivalentTo (expectedAttrs), $"Custom attributes on `{src}' are not matching");
+ }
+
+ static IEnumerable<string> FilterLinkedAttributes (ICustomAttributeProvider linked)
+ {
+ foreach (var attr in linked.CustomAttributes) {
+ switch (attr.AttributeType.FullName) {
+ case "System.Runtime.CompilerServices.RuntimeCompatibilityAttribute":
+ continue;
+ }
+
+ yield return attr.AttributeType.FullName;
+ }
+ }
+
+ static void VerifyGenericParameters (IGenericParameterProvider src, IGenericParameterProvider linked)
+ {
+ Assert.AreEqual (src.HasGenericParameters, linked.HasGenericParameters);
+ if (src.HasGenericParameters) {
+ for (int i = 0; i < src.GenericParameters.Count; ++i) {
+ // TODO: Verify constraints
+ VerifyCustomAttributes (src.GenericParameters [i], linked.GenericParameters [i]);
+ }
+ }
+ }
+
+ static bool ShouldBeKept<T> (T member, string signature = null) where T : MemberReference, ICustomAttributeProvider
+ {
+ if (member.HasAttribute (nameof (KeptAttribute)))
+ return true;
+
+ ICustomAttributeProvider cap = (ICustomAttributeProvider)member.DeclaringType;
+ if (cap == null)
+ return false;
+
+ return GetCustomAttributeCtorValues<string> (cap, nameof (KeptMemberAttribute)).Any (a => a == (signature ?? member.Name));
+ }
+
+ static IEnumerable<T> GetCustomAttributeCtorValues<T> (ICustomAttributeProvider provider, string attributeName) where T : class
+ {
+ return provider.CustomAttributes.
+ Where (w => w.AttributeType.Name == attributeName && w.Constructor.Parameters.Count == 1).
+ Select (l => l.ConstructorArguments [0].Value as T);
+ }
+ }
+}
diff --git a/linker/Tests/TestCasesRunner/ExpectationsProvider.cs b/linker/Tests/TestCasesRunner/ExpectationsProvider.cs
new file mode 100644
index 000000000..79280a35a
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/ExpectationsProvider.cs
@@ -0,0 +1,12 @@
+using Mono.Cecil;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public static class ExpectationsProvider {
+
+ public static bool IsAssemblyAssertion (CustomAttribute attr)
+ {
+ return attr.AttributeType.Name == nameof (KeptAssemblyAttribute) || attr.AttributeType.Name == nameof (RemovedAssemblyAttribute);
+ }
+ }
+}
diff --git a/linker/Tests/TestCasesRunner/LinkXmlHelpers.cs b/linker/Tests/TestCasesRunner/LinkXmlHelpers.cs
new file mode 100644
index 000000000..c7e70cf71
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/LinkXmlHelpers.cs
@@ -0,0 +1,30 @@
+using System.Text;
+using Mono.Cecil;
+using Mono.Linker.Tests.Extensions;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public static class LinkXmlHelpers {
+ public static void WriteXmlFileToPreserveEntryPoint (NPath targetProgram, NPath xmlFile)
+ {
+ using (var assembly = AssemblyDefinition.ReadAssembly (targetProgram.ToString ())) {
+ var method = assembly.EntryPoint;
+
+ var sb = new StringBuilder ();
+ sb.AppendLine ("<linker>");
+
+ sb.AppendLine (" <assembly fullname=\"" + assembly.FullName + "\">");
+
+ if (method != null) {
+ sb.AppendLine (" <type fullname=\"" + method.DeclaringType.FullName + "\">");
+ sb.AppendLine (" <method name=\"" + method.Name + "\"/>");
+ sb.AppendLine (" </type>");
+ }
+
+ sb.AppendLine (" </assembly>");
+
+ sb.AppendLine ("</linker>");
+ xmlFile.WriteAllText (sb.ToString ());
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/LinkedTestCaseResult.cs b/linker/Tests/TestCasesRunner/LinkedTestCaseResult.cs
new file mode 100644
index 000000000..2d05f6d09
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/LinkedTestCaseResult.cs
@@ -0,0 +1,19 @@
+using Mono.Linker.Tests.Extensions;
+using Mono.Linker.Tests.TestCases;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class LinkedTestCaseResult {
+ public readonly TestCase TestCase;
+ public readonly NPath InputAssemblyPath;
+ public readonly NPath OutputAssemblyPath;
+ public readonly NPath ExpectationsAssemblyPath;
+
+ public LinkedTestCaseResult (TestCase testCase, NPath inputAssemblyPath, NPath outputAssemblyPath, NPath expectationsAssemblyPath)
+ {
+ TestCase = testCase;
+ InputAssemblyPath = inputAssemblyPath;
+ OutputAssemblyPath = outputAssemblyPath;
+ ExpectationsAssemblyPath = expectationsAssemblyPath;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs b/linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs
new file mode 100644
index 000000000..49114eb84
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/LinkerArgumentBuilder.cs
@@ -0,0 +1,42 @@
+using System.Collections.Generic;
+using Mono.Linker.Tests.Extensions;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class LinkerArgumentBuilder {
+ private readonly List<string> _arguments = new List<string> ();
+
+ public virtual void AddSearchDirectory (NPath directory)
+ {
+ Append ("-d");
+ Append (directory.ToString ());
+ }
+
+ public virtual void AddOutputDirectory (NPath directory)
+ {
+ Append ("-o");
+ Append (directory.ToString ());
+ }
+
+ public virtual void AddLinkXmlFile (NPath path)
+ {
+ Append ("-x");
+ Append (path.ToString ());
+ }
+
+ public virtual void AddCoreLink (string value)
+ {
+ Append ("-c");
+ Append (value);
+ }
+
+ public string [] ToArgs ()
+ {
+ return _arguments.ToArray ();
+ }
+
+ protected void Append (string arg)
+ {
+ _arguments.Add (arg);
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/LinkerDriver.cs b/linker/Tests/TestCasesRunner/LinkerDriver.cs
new file mode 100644
index 000000000..dc2469ca3
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/LinkerDriver.cs
@@ -0,0 +1,8 @@
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class LinkerDriver {
+ public virtual void Link (string [] args)
+ {
+ Driver.Main (args);
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/ManagedCompilationResult.cs b/linker/Tests/TestCasesRunner/ManagedCompilationResult.cs
new file mode 100644
index 000000000..ccce993f9
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/ManagedCompilationResult.cs
@@ -0,0 +1,15 @@
+using Mono.Linker.Tests.Extensions;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class ManagedCompilationResult {
+ public ManagedCompilationResult (NPath inputAssemblyPath, NPath expectationsAssemblyPath)
+ {
+ InputAssemblyPath = inputAssemblyPath;
+ ExpectationsAssemblyPath = expectationsAssemblyPath;
+ }
+
+ public NPath InputAssemblyPath { get; }
+
+ public NPath ExpectationsAssemblyPath { get; }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/ObjectFactory.cs b/linker/Tests/TestCasesRunner/ObjectFactory.cs
new file mode 100644
index 000000000..d756df6f9
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/ObjectFactory.cs
@@ -0,0 +1,31 @@
+using Mono.Cecil;
+using Mono.Linker.Tests.TestCases;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class ObjectFactory {
+ public virtual TestCaseSandbox CreateSandbox (TestCase testCase)
+ {
+ return new TestCaseSandbox (testCase);
+ }
+
+ public virtual TestCaseCompiler CreateCompiler ()
+ {
+ return new TestCaseCompiler ();
+ }
+
+ public virtual LinkerDriver CreateLinker ()
+ {
+ return new LinkerDriver ();
+ }
+
+ public virtual TestCaseMetadaProvider CreateMetadataProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition)
+ {
+ return new TestCaseMetadaProvider (testCase, fullTestCaseAssemblyDefinition);
+ }
+
+ public virtual LinkerArgumentBuilder CreateLinkerArgumentBuilder ()
+ {
+ return new LinkerArgumentBuilder ();
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/ResultChecker.cs b/linker/Tests/TestCasesRunner/ResultChecker.cs
new file mode 100644
index 000000000..df66381fd
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/ResultChecker.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Linker.Tests.Extensions;
+using NUnit.Framework;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class ResultChecker {
+
+ public virtual void Check (LinkedTestCaseResult linkResult)
+ {
+ Assert.IsTrue (linkResult.OutputAssemblyPath.FileExists (), $"The linked output assembly was not found. Expected at {linkResult.OutputAssemblyPath}");
+
+ using (var original = ReadAssembly (linkResult.ExpectationsAssemblyPath)) {
+ PerformOutputAssemblyChecks (original.Definition, linkResult.OutputAssemblyPath.Parent);
+
+ using (var linked = ReadAssembly (linkResult.OutputAssemblyPath)) {
+ var checker = new AssemblyChecker (original.Definition, linked.Definition);
+ checker.Verify ();
+ }
+ }
+ }
+
+ static AssemblyContainer ReadAssembly (NPath assemblyPath)
+ {
+ var readerParams = new ReaderParameters ();
+ var resolver = new AssemblyResolver ();
+ readerParams.AssemblyResolver = resolver;
+ resolver.AddSearchDirectory (assemblyPath.Parent.ToString ());
+ return new AssemblyContainer (AssemblyDefinition.ReadAssembly (assemblyPath.ToString (), readerParams), resolver);
+ }
+
+ void PerformOutputAssemblyChecks (AssemblyDefinition original, NPath outputDirectory)
+ {
+ var assembliesToCheck = original.MainModule.Types.SelectMany (t => t.CustomAttributes).Where (attr => ExpectationsProvider.IsAssemblyAssertion(attr));
+
+ foreach (var assemblyAttr in assembliesToCheck) {
+ var name = (string) assemblyAttr.ConstructorArguments.First ().Value;
+ var expectedPath = outputDirectory.Combine (name);
+ Assert.IsTrue (expectedPath.FileExists (), $"Expected the assembly {name} to exist in {outputDirectory}, but it did not");
+ }
+ }
+
+ struct AssemblyContainer : IDisposable
+ {
+ public readonly AssemblyResolver Resolver;
+ public readonly AssemblyDefinition Definition;
+
+ public AssemblyContainer (AssemblyDefinition definition, AssemblyResolver resolver)
+ {
+ Definition = definition;
+ Resolver = resolver;
+ }
+
+ public void Dispose ()
+ {
+ Resolver?.Dispose ();
+ Definition?.Dispose ();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/TestCaseCollector.cs b/linker/Tests/TestCasesRunner/TestCaseCollector.cs
new file mode 100644
index 000000000..c84ff3534
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/TestCaseCollector.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Linker.Tests.TestCases;
+using Mono.Linker.Tests.Extensions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class TestCaseCollector {
+ private readonly NPath _rootDirectory;
+ private readonly NPath _testCaseAssemblyPath;
+
+ public TestCaseCollector (string rootDirectory, string testCaseAssemblyPath)
+ : this (rootDirectory.ToNPath (), testCaseAssemblyPath.ToNPath ())
+ {
+ }
+
+ public TestCaseCollector (NPath rootDirectory, NPath testCaseAssemblyPath)
+ {
+ _rootDirectory = rootDirectory;
+ _testCaseAssemblyPath = testCaseAssemblyPath;
+ }
+
+ public IEnumerable<TestCase> Collect ()
+ {
+ return Collect (AllSourceFiles ());
+ }
+
+ public TestCase Collect (NPath sourceFile)
+ {
+ return Collect (new [] { sourceFile }).First ();
+ }
+
+ public IEnumerable<TestCase> Collect (IEnumerable<NPath> sourceFiles)
+ {
+ _rootDirectory.DirectoryMustExist ();
+ _testCaseAssemblyPath.FileMustExist ();
+
+ using (var caseAssemblyDefinition = AssemblyDefinition.ReadAssembly (_testCaseAssemblyPath.ToString ())) {
+ foreach (var file in sourceFiles) {
+ TestCase testCase;
+ if (CreateCase (caseAssemblyDefinition, file, out testCase))
+ yield return testCase;
+ }
+ }
+ }
+
+ public IEnumerable<NPath> AllSourceFiles ()
+ {
+ _rootDirectory.DirectoryMustExist ();
+
+ foreach (var file in _rootDirectory.Files ("*.cs")) {
+ yield return file;
+ }
+
+ foreach (var subDir in _rootDirectory.Directories ()) {
+ if (subDir.FileName == "bin" || subDir.FileName == "obj" || subDir.FileName == "Properties")
+ continue;
+
+ foreach (var file in subDir.Files ("*.cs", true)) {
+ yield return file;
+ }
+ }
+ }
+
+ private bool CreateCase (AssemblyDefinition caseAssemblyDefinition, NPath sourceFile, out TestCase testCase)
+ {
+ var potentialCase = new TestCase (sourceFile, _rootDirectory, _testCaseAssemblyPath);
+
+ var typeDefinition = FindTypeDefinition (caseAssemblyDefinition, potentialCase);
+
+ if (typeDefinition == null)
+ throw new InvalidOperationException ($"Could not find the matching type for test case {sourceFile}. Ensure the file name and class name match");
+
+ if (typeDefinition.HasAttribute (nameof (NotATestCaseAttribute))) {
+ testCase = null;
+ return false;
+ }
+
+ // Verify the class as a static main method
+ var mainMethod = typeDefinition.Methods.FirstOrDefault (m => m.Name == "Main");
+
+ if (mainMethod == null)
+ throw new InvalidOperationException ($"{typeDefinition} in {sourceFile} is missing a Main() method");
+
+ if (!mainMethod.IsStatic)
+ throw new InvalidOperationException ($"The Main() method for {typeDefinition} in {sourceFile} should be static");
+
+ testCase = potentialCase;
+ return true;
+ }
+
+ private static TypeDefinition FindTypeDefinition (AssemblyDefinition caseAssemblyDefinition, TestCase testCase)
+ {
+ var typeDefinition = caseAssemblyDefinition.MainModule.GetType (testCase.ReconstructedFullTypeName);
+
+ // For all of the Test Cases, the full type name we constructed from the directory structure will be correct and we can successfully find
+ // the type from GetType.
+ if (typeDefinition != null)
+ return typeDefinition;
+
+ // However, some of types are supporting types rather than test cases. and may not follow the standardized naming scheme of the test cases
+ // We still need to be able to locate these type defs so that we can parse some of the metadata on them.
+ // One example, Unity run's into this with it's tests that require a type UnityEngine.MonoBehaviours to exist. This tpe is defined in it's own
+ // file and it cannot follow our standardized naming directory & namespace naming scheme since the namespace must be UnityEngine
+ foreach (var type in caseAssemblyDefinition.MainModule.Types) {
+ // Let's assume we should never have to search for a test case that has no namespace. If we don't find the type from GetType, then o well, that's not a test case.
+ if (string.IsNullOrEmpty (type.Namespace))
+ continue;
+
+ if (type.Name == testCase.Name) {
+ // This isn't foolproof, but let's do a little extra vetting to make sure the type we found corresponds to the source file we are
+ // processing.
+ if (!testCase.SourceFile.ReadAllText ().Contains ($"namespace {type.Namespace}"))
+ continue;
+
+ return type;
+ }
+ }
+
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/TestCaseCompiler.cs b/linker/Tests/TestCasesRunner/TestCaseCompiler.cs
new file mode 100644
index 000000000..ce203b478
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/TestCaseCompiler.cs
@@ -0,0 +1,41 @@
+using System;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Mono.Linker.Tests.Extensions;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class TestCaseCompiler {
+ public virtual NPath CompileTestIn (NPath outputDirectory, IEnumerable<string> sourceFiles, IEnumerable<string> references, IEnumerable<string> defines)
+ {
+ var compilerOptions = CreateCompilerOptions (outputDirectory, references, defines);
+ var provider = CodeDomProvider.CreateProvider ("C#");
+ var result = provider.CompileAssemblyFromFile (compilerOptions, sourceFiles.ToArray ());
+ if (!result.Errors.HasErrors)
+ return compilerOptions.OutputAssembly.ToNPath ();
+
+ var errors = new StringBuilder ();
+ foreach (var error in result.Errors)
+ errors.AppendLine (error.ToString ());
+ throw new Exception ("Compilation errors: " + errors);
+ }
+
+ protected virtual CompilerParameters CreateCompilerOptions (NPath outputDirectory, IEnumerable<string> references, IEnumerable<string> defines)
+ {
+ var outputPath = outputDirectory.Combine ("test.exe");
+
+ var compilerParameters = new CompilerParameters
+ {
+ OutputAssembly = outputPath.ToString (),
+ GenerateExecutable = true
+ };
+
+ compilerParameters.CompilerOptions = defines?.Aggregate (string.Empty, (buff, arg) => $"{buff} /define:{arg}");
+
+ compilerParameters.ReferencedAssemblies.AddRange (references.ToArray ());
+
+ return compilerParameters;
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs b/linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs
new file mode 100644
index 000000000..49e0992e1
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/TestCaseLinkerOptions.cs
@@ -0,0 +1,5 @@
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class TestCaseLinkerOptions {
+ public string CoreLink;
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs
new file mode 100644
index 000000000..d4bfc1f19
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/TestCaseMetadaProvider.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+using Mono.Linker.Tests.Extensions;
+using Mono.Linker.Tests.TestCases;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class TestCaseMetadaProvider {
+ protected readonly TestCase _testCase;
+ protected readonly AssemblyDefinition _fullTestCaseAssemblyDefinition;
+ protected readonly TypeDefinition _testCaseTypeDefinition;
+
+ public TestCaseMetadaProvider (TestCase testCase, AssemblyDefinition fullTestCaseAssemblyDefinition)
+ {
+ _testCase = testCase;
+ _fullTestCaseAssemblyDefinition = fullTestCaseAssemblyDefinition;
+ // The test case types are never nested so we don't need to worry about that
+ _testCaseTypeDefinition = fullTestCaseAssemblyDefinition.MainModule.GetType (_testCase.ReconstructedFullTypeName);
+
+ if (_testCaseTypeDefinition == null)
+ throw new InvalidOperationException ($"Could not find the type definition for {_testCase.Name} in {_testCase.SourceFile}");
+ }
+
+ public virtual TestCaseLinkerOptions GetLinkerOptions ()
+ {
+ // This will end up becoming more complicated as we get into more complex test cases that require additional
+ // data
+ var value = "skip";
+ var coreLinkAttribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (CoreLinkAttribute));
+ if (coreLinkAttribute != null)
+ value = (string) coreLinkAttribute.ConstructorArguments.First ().Value;
+ return new TestCaseLinkerOptions {CoreLink = value};
+ }
+
+ public virtual IEnumerable<string> GetReferencedAssemblies ()
+ {
+ yield return "mscorlib.dll";
+
+ foreach (var referenceAttr in _testCaseTypeDefinition.CustomAttributes.Where (attr => attr.AttributeType.Name == nameof (ReferenceAttribute))) {
+ yield return (string) referenceAttr.ConstructorArguments.First ().Value;
+ }
+ }
+
+ public virtual IEnumerable<NPath> GetExtraLinkerSearchDirectories ()
+ {
+ yield break;
+ }
+
+ public bool IsIgnored (out string reason)
+ {
+ var ignoreAttribute = _testCaseTypeDefinition.CustomAttributes.FirstOrDefault (attr => attr.AttributeType.Name == nameof (IgnoreTestCaseAttribute));
+ if (ignoreAttribute != null) {
+ reason = (string)ignoreAttribute.ConstructorArguments.First ().Value;
+ return true;
+ }
+
+ reason = null;
+ return false;
+ }
+
+ public virtual IEnumerable<NPath> AdditionalFilesToSandbox ()
+ {
+ foreach (var attr in _testCaseTypeDefinition.CustomAttributes) {
+ if (attr.AttributeType.Name != nameof (SandboxDependencyAttribute))
+ continue;
+
+ var relativeDepPath = ((string) attr.ConstructorArguments.First ().Value).ToNPath ();
+ yield return _testCase.SourceFile.Parent.Combine (relativeDepPath);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/TestCaseSandbox.cs b/linker/Tests/TestCasesRunner/TestCaseSandbox.cs
new file mode 100644
index 000000000..7eb29f4b7
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/TestCaseSandbox.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Extensions;
+using Mono.Linker.Tests.TestCases;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class TestCaseSandbox {
+ protected readonly TestCase _testCase;
+ protected readonly NPath _directory;
+
+ public TestCaseSandbox (TestCase testCase)
+ : this (testCase, NPath.SystemTemp)
+ {
+ }
+
+ public TestCaseSandbox (TestCase testCase, NPath rootTemporaryDirectory)
+ : this (testCase, rootTemporaryDirectory, string.Empty)
+ {
+ }
+
+ public TestCaseSandbox (TestCase testCase, string rootTemporaryDirectory, string namePrefix)
+ : this (testCase, rootTemporaryDirectory.ToNPath (), namePrefix)
+ {
+ }
+
+ public TestCaseSandbox (TestCase testCase, NPath rootTemporaryDirectory, string namePrefix)
+ {
+ _testCase = testCase;
+ var name = string.IsNullOrEmpty (namePrefix) ? "linker_tests" : $"{namePrefix}_linker_tests";
+ _directory = rootTemporaryDirectory.Combine (name);
+
+ _directory.DeleteContents ();
+
+ InputDirectory = _directory.Combine ("input").EnsureDirectoryExists ();
+ OutputDirectory = _directory.Combine ("output").EnsureDirectoryExists ();
+ ExpectationsDirectory = _directory.Combine ("expectations").EnsureDirectoryExists ();
+ }
+
+ public NPath InputDirectory { get; }
+
+ public NPath OutputDirectory { get; }
+
+ public NPath ExpectationsDirectory { get; }
+
+ public IEnumerable<NPath> SourceFiles {
+ get { return _directory.Files ("*.cs"); }
+ }
+
+ public IEnumerable<NPath> InputDirectoryReferences {
+ get { return InputDirectory.Files ("*.dll"); }
+ }
+
+ public IEnumerable<NPath> ExpectationsDirectoryReferences {
+ get { return ExpectationsDirectory.Files ("*.dll"); }
+ }
+
+ public IEnumerable<NPath> LinkXmlFiles {
+ get { return InputDirectory.Files ("*.xml"); }
+ }
+
+ public virtual void Populate (TestCaseMetadaProvider metadataProvider)
+ {
+ _testCase.SourceFile.Copy (_directory);
+
+ if (_testCase.HasLinkXmlFile)
+ _testCase.LinkXmlFile.Copy (InputDirectory);
+
+ GetExpectationsAssemblyPath ().Copy (InputDirectory);
+
+ foreach (var dep in metadataProvider.AdditionalFilesToSandbox ()) {
+ dep.FileMustExist ().Copy (_directory);
+ }
+
+ InputDirectoryReferences.Copy (ExpectationsDirectory);
+ }
+
+ private static NPath GetExpectationsAssemblyPath ()
+ {
+ return new Uri (typeof (KeptAttribute).Assembly.CodeBase).LocalPath.ToNPath ();
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/TestCasesRunner/TestRunner.cs b/linker/Tests/TestCasesRunner/TestRunner.cs
new file mode 100644
index 000000000..0763ca142
--- /dev/null
+++ b/linker/Tests/TestCasesRunner/TestRunner.cs
@@ -0,0 +1,78 @@
+using System.Linq;
+using Mono.Cecil;
+using Mono.Linker.Tests.TestCases;
+using NUnit.Framework;
+
+namespace Mono.Linker.Tests.TestCasesRunner {
+ public class TestRunner {
+ private readonly ObjectFactory _factory;
+
+ public TestRunner (ObjectFactory factory)
+ {
+ _factory = factory;
+ }
+
+ public LinkedTestCaseResult Run (TestCase testCase)
+ {
+ using (var fullTestCaseAssemblyDefinition = AssemblyDefinition.ReadAssembly (testCase.OriginalTestCaseAssemblyPath.ToString ())) {
+ var metadataProvider = _factory.CreateMetadataProvider (testCase, fullTestCaseAssemblyDefinition);
+
+ string ignoreReason;
+ if (metadataProvider.IsIgnored (out ignoreReason))
+ Assert.Ignore (ignoreReason);
+
+ var sandbox = Sandbox (testCase, metadataProvider);
+ var compilationResult = Compile (sandbox, metadataProvider);
+ PrepForLink (sandbox, compilationResult);
+ return Link (testCase, sandbox, compilationResult, metadataProvider);
+ }
+ }
+
+ private TestCaseSandbox Sandbox (TestCase testCase, TestCaseMetadaProvider metadataProvider)
+ {
+ var sandbox = _factory.CreateSandbox (testCase);
+ sandbox.Populate (metadataProvider);
+ return sandbox;
+ }
+
+ private ManagedCompilationResult Compile (TestCaseSandbox sandbox, TestCaseMetadaProvider metadataProvider)
+ {
+ var compiler = _factory.CreateCompiler ();
+ var sourceFiles = sandbox.SourceFiles.Select(s => s.ToString()).ToArray();
+
+ var references = metadataProvider.GetReferencedAssemblies ().Concat (sandbox.InputDirectoryReferences.Select (r => r.ToString ())).ToArray ();
+ var inputAssemblyPath = compiler.CompileTestIn (sandbox.InputDirectory, sourceFiles, references, null);
+
+ references = metadataProvider.GetReferencedAssemblies ().Concat (sandbox.ExpectationsDirectoryReferences.Select (r => r.ToString ())).ToArray ();
+ var expectationsAssemblyPath = compiler.CompileTestIn (sandbox.ExpectationsDirectory, sourceFiles, references, new [] { "INCLUDE_EXPECTATIONS" });
+ return new ManagedCompilationResult (inputAssemblyPath, expectationsAssemblyPath);
+ }
+
+ private void PrepForLink (TestCaseSandbox sandbox, ManagedCompilationResult compilationResult)
+ {
+ var entryPointLinkXml = sandbox.InputDirectory.Combine ("entrypoint.xml");
+ LinkXmlHelpers.WriteXmlFileToPreserveEntryPoint (compilationResult.InputAssemblyPath, entryPointLinkXml);
+ }
+
+ private LinkedTestCaseResult Link (TestCase testCase, TestCaseSandbox sandbox, ManagedCompilationResult compilationResult, TestCaseMetadaProvider metadataProvider)
+ {
+ var linker = _factory.CreateLinker ();
+ var builder = _factory.CreateLinkerArgumentBuilder ();
+ var caseDefinedOptions = metadataProvider.GetLinkerOptions ();
+
+ builder.AddOutputDirectory (sandbox.OutputDirectory);
+ foreach (var linkXmlFile in sandbox.LinkXmlFiles)
+ builder.AddLinkXmlFile (linkXmlFile);
+
+ builder.AddSearchDirectory (sandbox.InputDirectory);
+ foreach (var extraSearchDir in metadataProvider.GetExtraLinkerSearchDirectories ())
+ builder.AddSearchDirectory (extraSearchDir);
+
+ builder.AddCoreLink (caseDefinedOptions.CoreLink);
+
+ linker.Link (builder.ToArgs ());
+
+ return new LinkedTestCaseResult (testCase, compilationResult.InputAssemblyPath, sandbox.OutputDirectory.Combine (compilationResult.InputAssemblyPath.FileName), compilationResult.ExpectationsAssemblyPath);
+ }
+ }
+} \ No newline at end of file
diff --git a/linker/Tests/Tests/PreserveActionComparisonTests.cs b/linker/Tests/Tests/PreserveActionComparisonTests.cs
new file mode 100644
index 000000000..21c881468
--- /dev/null
+++ b/linker/Tests/Tests/PreserveActionComparisonTests.cs
@@ -0,0 +1,30 @@
+using NUnit.Framework;
+
+namespace Mono.Linker.Tests
+{
+ [TestFixture]
+ public class PreserveActionComparisonTests
+ {
+ [TestCase (TypePreserve.All, TypePreserve.All, TypePreserve.All)]
+ [TestCase (TypePreserve.All, TypePreserve.Methods, TypePreserve.All)]
+ [TestCase (TypePreserve.All, TypePreserve.Fields, TypePreserve.All)]
+ [TestCase (TypePreserve.All, TypePreserve.Nothing, TypePreserve.All)]
+ [TestCase (TypePreserve.Methods, TypePreserve.All, TypePreserve.All)]
+ [TestCase (TypePreserve.Methods, TypePreserve.Methods, TypePreserve.Methods)]
+ [TestCase (TypePreserve.Methods, TypePreserve.Fields, TypePreserve.All)]
+ [TestCase (TypePreserve.Methods, TypePreserve.Nothing, TypePreserve.Methods)]
+ [TestCase (TypePreserve.Fields, TypePreserve.All, TypePreserve.All)]
+ [TestCase (TypePreserve.Fields, TypePreserve.Methods, TypePreserve.All)]
+ [TestCase (TypePreserve.Fields, TypePreserve.Fields, TypePreserve.Fields)]
+ [TestCase (TypePreserve.Fields, TypePreserve.Nothing, TypePreserve.Fields)]
+ [TestCase (TypePreserve.Nothing, TypePreserve.All, TypePreserve.All)]
+ [TestCase (TypePreserve.Nothing, TypePreserve.Methods, TypePreserve.Methods)]
+ [TestCase (TypePreserve.Nothing, TypePreserve.Fields, TypePreserve.Fields)]
+ [TestCase (TypePreserve.Nothing, TypePreserve.Nothing, TypePreserve.Nothing)]
+ public void VerifyBehaviorOfChoosePreserveActionWhichPreservesTheMost (TypePreserve left, TypePreserve right, TypePreserve expected)
+ {
+ Assert.That (expected, Is.EqualTo (AnnotationStore.ChoosePreserveActionWhichPreservesTheMost (left, right)));
+ Assert.That (expected, Is.EqualTo (AnnotationStore.ChoosePreserveActionWhichPreservesTheMost (right, left)));
+ }
+ }
+}