From 0cfa8922a6f6e2819937e8e4f5381378b953aa6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:38:35 +0000 Subject: [PATCH 1/4] Initial plan From 408e5ddd6601ccf4fc75d9c208a8f948473f5c68 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:27:05 +0000 Subject: [PATCH 2/4] Align CustomAttributeDecoderTests with embedded-resource scheme - Add Resources/Decoding/CustomAttributeDecoder.cs: source for helper assembly with all types and custom attributes needed by the decoder tests - Add Resources/Decoding/CustomAttributeDecoder.dll: pre-compiled helper assembly embedded as a test resource - Update TestResources.cs to expose the new resource via Decoding.CustomAttributeDecoder - Update System.Reflection.Metadata.Tests.csproj to include the new resource files - Rewrite CustomAttributeDecoderTests.cs to load metadata from the embedded resource instead of introspecting the running test assembly: - Remove ConditionalFact(NotSingleFile) / ConditionalFact(HasAssemblyFiles) guards - Remove assembly-identity workarounds (RuntimeAssemblyName, TypeToString, etc.) - Remove inline type definitions (HasAttributes, TestAttribute, enums, GenericAttribute, etc.) - Add comprehensive assertions covering all 82 attributes on HasAttributes, 8 on HasGenericAttributes, and 2 on HasGenericArrayAttributes - Add FindTestType helper that looks up types by namespace+name in the embedded metadata - Simplify CustomAttributeTypeProvider with hardcoded type mappings for the resource assembly's enum types Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/8f883665-1cac-472f-81aa-5074b5ff4f1c Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../Decoding/CustomAttributeDecoderTests.cs | 1256 +++++++++-------- .../Decoding/CustomAttributeDecoder.cs | 293 ++++ .../Decoding/CustomAttributeDecoder.dll | Bin 0 -> 15872 bytes .../tests/Resources/TestResources.cs | 5 + .../System.Reflection.Metadata.Tests.csproj | 2 + 5 files changed, 974 insertions(+), 582 deletions(-) create mode 100644 src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs create mode 100644 src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.dll diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs index 0b7055dc65a04e..5c0cda52be6bc5 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs @@ -1,27 +1,26 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Reflection.Metadata.Tests; using System.Reflection.PortableExecutable; using Xunit; +using DecodingResources = System.Reflection.Metadata.Tests.Decoding; namespace System.Reflection.Metadata.Decoding.Tests { public class CustomAttributeDecoderTests { - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles), nameof(PlatformDetection.IsMonoRuntime))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60579", TestPlatforms.iOS | TestPlatforms.tvOS)] + [Fact] public void TestCustomAttributeDecoder() { - using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(typeof(HasAttributes).GetTypeInfo().Assembly))) + using (var stream = new MemoryStream(DecodingResources.CustomAttributeDecoder)) using (var peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); var provider = new CustomAttributeTypeProvider(); - TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, typeof(HasAttributes)); + TypeDefinitionHandle typeDefHandle = FindTestType(reader, "CustomAttributeDecoderTests", "HasAttributes"); int i = 0; foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) @@ -31,27 +30,24 @@ public void TestCustomAttributeDecoder() switch (i++) { - case 0: + case 0: // [Test] Assert.Empty(value.FixedArguments); Assert.Empty(value.NamedArguments); break; - case 1: + case 1: // [Test("0", 1, 2.0)] Assert.Equal(3, value.FixedArguments.Length); - Assert.Equal("string", value.FixedArguments[0].Type); Assert.Equal("0", value.FixedArguments[0].Value); - Assert.Equal("int32", value.FixedArguments[1].Type); Assert.Equal(1, value.FixedArguments[1].Value); - Assert.Equal("float64", value.FixedArguments[2].Type); Assert.Equal(2.0, value.FixedArguments[2].Value); - Assert.Empty(value.NamedArguments); break; - case 2: + case 2: // [Test(StringField = "0", Int32Field = 1, SByteEnumArrayProperty = new[] { SByteEnum.Value })] + Assert.Empty(value.FixedArguments); Assert.Equal(3, value.NamedArguments.Length); Assert.Equal(CustomAttributeNamedArgumentKind.Field, value.NamedArguments[0].Kind); @@ -66,621 +62,730 @@ public void TestCustomAttributeDecoder() Assert.Equal(CustomAttributeNamedArgumentKind.Property, value.NamedArguments[2].Kind); Assert.Equal("SByteEnumArrayProperty", value.NamedArguments[2].Name); - Assert.Equal(typeof(SByteEnum).FullName + "[]", value.NamedArguments[2].Type); + Assert.Equal("CustomAttributeDecoderTests.SByteEnum[]", value.NamedArguments[2].Type); + var sbyteEnumArray = (ImmutableArray>)value.NamedArguments[2].Value; + Assert.Equal(1, sbyteEnumArray.Length); + Assert.Equal("CustomAttributeDecoderTests.SByteEnum", sbyteEnumArray[0].Type); + Assert.Equal((sbyte)-1, sbyteEnumArray[0].Value); + break; - var array = (ImmutableArray>)(value.NamedArguments[2].Value); - Assert.Equal(1, array.Length); - Assert.Equal(typeof(SByteEnum).FullName, array[0].Type); - Assert.Equal((sbyte)SByteEnum.Value, array[0].Value); + case 3: // [Test("0", 1, 2.0, StringField = "0", Int32Field = 1, DoubleField = 2.0)] + Assert.Equal(3, value.FixedArguments.Length); + Assert.Equal(3, value.NamedArguments.Length); + Assert.Equal("0", value.FixedArguments[0].Value); + Assert.Equal(1, value.FixedArguments[1].Value); + Assert.Equal(2.0, value.FixedArguments[2].Value); + Assert.Equal("StringField", value.NamedArguments[0].Name); + Assert.Equal("0", value.NamedArguments[0].Value); + Assert.Equal("Int32Field", value.NamedArguments[1].Name); + Assert.Equal(1, value.NamedArguments[1].Value); + Assert.Equal("DoubleField", value.NamedArguments[2].Name); + Assert.Equal(2.0, value.NamedArguments[2].Value); break; - default: - // TODO: https://github.com/dotnet/runtime/issues/73593 - // This method only tests first 3 attriubtes because the complete test 'TestCustomAttributeDecoderUsingReflection' fails on mono - // Leaving this hard coded test only for mono, until the issue fixed on mono + case 4: // [Test((object)null)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string", value.FixedArguments[0].Type); + Assert.Null(value.FixedArguments[0].Value); break; - } - } - } - } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73593", TestRuntimes.Mono)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/124344", typeof(PlatformDetection), nameof(PlatformDetection.IsAppleMobile), nameof(PlatformDetection.IsCoreCLR))] - public void TestCustomAttributeDecoderUsingReflection() - { - Type type = typeof(HasAttributes); - using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(type.GetTypeInfo().Assembly))) - using (PEReader peReader = new PEReader(stream)) - { - MetadataReader reader = peReader.GetMetadataReader(); - CustomAttributeTypeProvider provider = new CustomAttributeTypeProvider(); - TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, type); + case 5: // [Test((string)null)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string", value.FixedArguments[0].Type); + Assert.Null(value.FixedArguments[0].Value); + break; - IList attributes = type.GetCustomAttributesData(); + case 6: // [Test((Type)null)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal(provider.GetSystemType(), value.FixedArguments[0].Type); + Assert.Null(value.FixedArguments[0].Value); + break; - int i = 0; - foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) - { - CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); - CustomAttributeValue value = attribute.DecodeValue(provider); - CustomAttributeData reflectionAttribute = attributes[i++]; + case 7: // [Test((int[])null)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int32[]", value.FixedArguments[0].Type); + Assert.Null(value.FixedArguments[0].Value); + break; - Assert.Equal(reflectionAttribute.ConstructorArguments.Count, value.FixedArguments.Length); - Assert.Equal(reflectionAttribute.NamedArguments.Count, value.NamedArguments.Length); + case 8: // [Test("string")] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string", value.FixedArguments[0].Type); + Assert.Equal("string", value.FixedArguments[0].Value); + break; - int j = 0; - foreach (CustomAttributeTypedArgument arguments in value.FixedArguments) - { - Type t = reflectionAttribute.ConstructorArguments[j].ArgumentType; - Assert.Equal(TypeToString(t), arguments.Type); - if (t.IsArray && arguments.Value is not null) + case 9: // [Test((sbyte)-1)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int8", value.FixedArguments[0].Type); + Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); + break; + + case 10: // [Test((short)-2)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int16", value.FixedArguments[0].Type); + Assert.Equal((short)-2, value.FixedArguments[0].Value); + break; + + case 11: // [Test((int)-4)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int32", value.FixedArguments[0].Type); + Assert.Equal(-4, value.FixedArguments[0].Value); + break; + + case 12: // [Test((long)-8)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int64", value.FixedArguments[0].Type); + Assert.Equal((long)-8, value.FixedArguments[0].Value); + break; + + case 13: // [Test((sbyte)-1)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int8", value.FixedArguments[0].Type); + Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); + break; + + case 14: // [Test((short)-2)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int16", value.FixedArguments[0].Type); + Assert.Equal((short)-2, value.FixedArguments[0].Value); + break; + + case 15: // [Test((int)-4)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int32", value.FixedArguments[0].Type); + Assert.Equal(-4, value.FixedArguments[0].Value); + break; + + case 16: // [Test((long)-8)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int64", value.FixedArguments[0].Type); + Assert.Equal((long)-8, value.FixedArguments[0].Value); + break; + + case 17: // [Test((byte)1)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint8", value.FixedArguments[0].Type); + Assert.Equal((byte)1, value.FixedArguments[0].Value); + break; + + case 18: // [Test((ushort)2)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint16", value.FixedArguments[0].Type); + Assert.Equal((ushort)2, value.FixedArguments[0].Value); + break; + + case 19: // [Test((uint)4)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint32", value.FixedArguments[0].Type); + Assert.Equal((uint)4, value.FixedArguments[0].Value); + break; + + case 20: // [Test((ulong)8)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint64", value.FixedArguments[0].Type); + Assert.Equal((ulong)8, value.FixedArguments[0].Value); + break; + + case 21: // [Test(true)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("bool", value.FixedArguments[0].Type); + Assert.Equal(true, value.FixedArguments[0].Value); + break; + + case 22: // [Test(false)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("bool", value.FixedArguments[0].Type); + Assert.Equal(false, value.FixedArguments[0].Value); + break; + + case 23: // [Test(typeof(string))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal(provider.GetSystemType(), value.FixedArguments[0].Type); + Assert.Contains("System.String", (string)value.FixedArguments[0].Value); + break; + + case 24: // [Test(new string[] { })] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string[]", value.FixedArguments[0].Type); + Assert.Empty((ImmutableArray>)value.FixedArguments[0].Value); + break; + + case 25: // [Test(new string[] { "x", "y", "z", null })] { - ImmutableArray> array = (ImmutableArray>)(arguments.Value); - IList refArray = (IList)reflectionAttribute.ConstructorArguments[j].Value; - int k = 0; - foreach (CustomAttributeTypedArgument element in array) - { - if (refArray[k].ArgumentType.IsArray) - { - ImmutableArray> innerArray = (ImmutableArray>)(element.Value); - IList refInnerArray = (IList)refArray[k].Value; - int a = 0; - foreach (CustomAttributeTypedArgument el in innerArray) - { - if (refInnerArray[a].Value?.ToString() != el.Value?.ToString()) - { - Assert.Equal(refInnerArray[a].Value, el.Value); - } - a++; - } - } - else if (refArray[k].Value?.ToString() != element.Value?.ToString()) - { - if (refArray[k].ArgumentType == typeof(Type)) // TODO: check if it is expected - { - Assert.Contains(refArray[k].Value.ToString(), element.Value.ToString()); - } - else - { - Assert.Equal(refArray[k].Value, element.Value); - } - } - k++; - } + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string[]", value.FixedArguments[0].Type); + var strArray = (ImmutableArray>)value.FixedArguments[0].Value; + Assert.Equal(4, strArray.Length); + Assert.Equal("x", strArray[0].Value); + Assert.Equal("y", strArray[1].Value); + Assert.Equal("z", strArray[2].Value); + Assert.Null(strArray[3].Value); + break; } - else if (reflectionAttribute.ConstructorArguments[j].Value?.ToString() != arguments.Value?.ToString()) + + case 26: // [Test((object)("string"))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string", value.FixedArguments[0].Type); + Assert.Equal("string", value.FixedArguments[0].Value); + break; + + case 27: // [Test((object)(sbyte)-1)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int8", value.FixedArguments[0].Type); + Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); + break; + + case 28: // [Test((object)(short)-2)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int16", value.FixedArguments[0].Type); + Assert.Equal((short)-2, value.FixedArguments[0].Value); + break; + + case 29: // [Test((object)(int)-4)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int32", value.FixedArguments[0].Type); + Assert.Equal(-4, value.FixedArguments[0].Value); + break; + + case 30: // [Test((object)(long)-8)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int64", value.FixedArguments[0].Type); + Assert.Equal((long)-8, value.FixedArguments[0].Value); + break; + + case 31: // [Test((object)(sbyte)-1)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int8", value.FixedArguments[0].Type); + Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); + break; + + case 32: // [Test((object)(short)-2)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int16", value.FixedArguments[0].Type); + Assert.Equal((short)-2, value.FixedArguments[0].Value); + break; + + case 33: // [Test((object)(int)-4)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int32", value.FixedArguments[0].Type); + Assert.Equal(-4, value.FixedArguments[0].Value); + break; + + case 34: // [Test((object)(long)-8)] duplicate + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int64", value.FixedArguments[0].Type); + Assert.Equal((long)-8, value.FixedArguments[0].Value); + break; + + case 35: // [Test((object)(byte)1)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint8", value.FixedArguments[0].Type); + Assert.Equal((byte)1, value.FixedArguments[0].Value); + break; + + case 36: // [Test((object)(ushort)2)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint16", value.FixedArguments[0].Type); + Assert.Equal((ushort)2, value.FixedArguments[0].Value); + break; + + case 37: // [Test((object)(uint)4)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint32", value.FixedArguments[0].Type); + Assert.Equal((uint)4, value.FixedArguments[0].Value); + break; + + case 38: // [Test((object)(true))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("bool", value.FixedArguments[0].Type); + Assert.Equal(true, value.FixedArguments[0].Value); + break; + + case 39: // [Test((object)(false))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("bool", value.FixedArguments[0].Type); + Assert.Equal(false, value.FixedArguments[0].Value); + break; + + case 40: // [Test((object)(typeof(string)))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Contains("System.String", (string)value.FixedArguments[0].Value); + break; + + case 41: // [Test((object)(SByteEnum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.SByteEnum", value.FixedArguments[0].Type); + Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); + break; + + case 42: // [Test((object)(Int16Enum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.Int16Enum", value.FixedArguments[0].Type); + Assert.Equal((short)-2, value.FixedArguments[0].Value); + break; + + case 43: // [Test((object)(Int32Enum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.Int32Enum", value.FixedArguments[0].Type); + Assert.Equal(-3, value.FixedArguments[0].Value); + break; + + case 44: // [Test((object)(Int64Enum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.Int64Enum", value.FixedArguments[0].Type); + Assert.Equal((long)-4, value.FixedArguments[0].Value); + break; + + case 45: // [Test((object)(ByteEnum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.ByteEnum", value.FixedArguments[0].Type); + Assert.Equal((byte)1, value.FixedArguments[0].Value); + break; + + case 46: // [Test((object)(UInt16Enum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.UInt16Enum", value.FixedArguments[0].Type); + Assert.Equal((ushort)2, value.FixedArguments[0].Value); + break; + + case 47: // [Test((object)(UInt32Enum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.UInt32Enum", value.FixedArguments[0].Type); + Assert.Equal((uint)3, value.FixedArguments[0].Value); + break; + + case 48: // [Test((object)(UInt64Enum.Value))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.UInt64Enum", value.FixedArguments[0].Type); + Assert.Equal((ulong)4, value.FixedArguments[0].Value); + break; + + case 49: // [Test((object)(new string[] { }))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string[]", value.FixedArguments[0].Type); + Assert.Empty((ImmutableArray>)value.FixedArguments[0].Value); + break; + + case 50: // [Test((object)(new string[] { "x", "y", "z", null }))] { - if (reflectionAttribute.ConstructorArguments[j].ArgumentType == typeof(Type)) - { - Assert.Contains(reflectionAttribute.ConstructorArguments[j].Value.ToString(), arguments.Value.ToString()); - } - else - { - Assert.Equal(reflectionAttribute.ConstructorArguments[j].Value, arguments.Value); - } + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string[]", value.FixedArguments[0].Type); + var strArray = (ImmutableArray>)value.FixedArguments[0].Value; + Assert.Equal(4, strArray.Length); + break; } - j++; - } - j = 0; - foreach (CustomAttributeNamedArgument arguments in value.NamedArguments) - { - Type t = reflectionAttribute.NamedArguments[j].TypedValue.ArgumentType; - Assert.Equal(TypeToString(t), arguments.Type); - if (t.IsArray && arguments.Value is not null) + + case 51: // [Test((object)(new Int32Enum[] { Int32Enum.Value }))] { - ImmutableArray> array = (ImmutableArray>)(arguments.Value); - IList refArray = (IList)reflectionAttribute.NamedArguments[j].TypedValue.Value; - int k = 0; - foreach (CustomAttributeTypedArgument element in array) - { - if (refArray[k].Value?.ToString() != element.Value?.ToString()) - { - Assert.Equal(refArray[k].Value, element.Value); - } - k++; - } + Assert.Equal(1, value.FixedArguments.Length); + Assert.StartsWith("CustomAttributeDecoderTests.Int32Enum[]", value.FixedArguments[0].Type); + var int32EnumArray = (ImmutableArray>)value.FixedArguments[0].Value; + Assert.Equal(1, int32EnumArray.Length); + Assert.Equal(-3, int32EnumArray[0].Value); + break; } - else if (reflectionAttribute.NamedArguments[j].TypedValue.Value?.ToString() != arguments.Value?.ToString()) + + case 52: // [Test(new object[] { ... })] { - if (reflectionAttribute.NamedArguments[j].TypedValue.ArgumentType == typeof(Type)) // typeof operator used for named parameter, like [Test(TypeField = typeof(string))], check if it is expected - { - Assert.Contains(reflectionAttribute.NamedArguments[j].TypedValue.Value.ToString(), arguments.Value.ToString()); - } - else - { - Assert.Equal(reflectionAttribute.NamedArguments[j].TypedValue.Value, arguments.Value); - } + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("object[]", value.FixedArguments[0].Type); + var objArray = (ImmutableArray>)value.FixedArguments[0].Value; + Assert.Equal(25, objArray.Length); + Assert.Equal("string", objArray[0].Value); + Assert.Equal((sbyte)-1, objArray[1].Value); + Assert.Equal((short)-2, objArray[2].Value); + Assert.Equal(-4, objArray[3].Value); + Assert.Equal((long)-8, objArray[4].Value); + Assert.Equal((byte)1, objArray[9].Value); + Assert.Equal((ushort)2, objArray[10].Value); + Assert.Equal((uint)4, objArray[11].Value); + Assert.Equal(true, objArray[12].Value); + Assert.Equal(false, objArray[13].Value); + Assert.Contains("System.String", (string)objArray[14].Value); + break; } - j++; + + case 53: // [Test(StringField = "string")] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal(CustomAttributeNamedArgumentKind.Field, value.NamedArguments[0].Kind); + Assert.Equal("StringField", value.NamedArguments[0].Name); + Assert.Equal("string", value.NamedArguments[0].Type); + Assert.Equal("string", value.NamedArguments[0].Value); + break; + + case 54: // [Test(SByteField = -1)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("SByteField", value.NamedArguments[0].Name); + Assert.Equal("int8", value.NamedArguments[0].Type); + Assert.Equal((sbyte)-1, value.NamedArguments[0].Value); + break; + + case 55: // [Test(Int16Field = -2)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("Int16Field", value.NamedArguments[0].Name); + Assert.Equal("int16", value.NamedArguments[0].Type); + Assert.Equal((short)-2, value.NamedArguments[0].Value); + break; + + case 56: // [Test(Int32Field = -4)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("Int32Field", value.NamedArguments[0].Name); + Assert.Equal("int32", value.NamedArguments[0].Type); + Assert.Equal(-4, value.NamedArguments[0].Value); + break; + + case 57: // [Test(Int64Field = -8)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("Int64Field", value.NamedArguments[0].Name); + Assert.Equal("int64", value.NamedArguments[0].Type); + Assert.Equal((long)-8, value.NamedArguments[0].Value); + break; + + case 58: // [Test(SByteField = -1)] duplicate + Assert.Equal("int8", value.NamedArguments[0].Type); + Assert.Equal((sbyte)-1, value.NamedArguments[0].Value); + break; + + case 59: // [Test(Int16Field = -2)] duplicate + Assert.Equal("int16", value.NamedArguments[0].Type); + Assert.Equal((short)-2, value.NamedArguments[0].Value); + break; + + case 60: // [Test(Int32Field = -4)] duplicate + Assert.Equal("int32", value.NamedArguments[0].Type); + Assert.Equal(-4, value.NamedArguments[0].Value); + break; + + case 61: // [Test(Int64Field = -8)] duplicate + Assert.Equal("int64", value.NamedArguments[0].Type); + Assert.Equal((long)-8, value.NamedArguments[0].Value); + break; + + case 62: // [Test(ByteField = 1)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("ByteField", value.NamedArguments[0].Name); + Assert.Equal("uint8", value.NamedArguments[0].Type); + Assert.Equal((byte)1, value.NamedArguments[0].Value); + break; + + case 63: // [Test(UInt16Field = 2)] + Assert.Empty(value.FixedArguments); + Assert.Equal("UInt16Field", value.NamedArguments[0].Name); + Assert.Equal("uint16", value.NamedArguments[0].Type); + Assert.Equal((ushort)2, value.NamedArguments[0].Value); + break; + + case 64: // [Test(UInt32Field = 4)] + Assert.Empty(value.FixedArguments); + Assert.Equal("UInt32Field", value.NamedArguments[0].Name); + Assert.Equal("uint32", value.NamedArguments[0].Type); + Assert.Equal((uint)4, value.NamedArguments[0].Value); + break; + + case 65: // [Test(UInt64Field = 8)] + Assert.Empty(value.FixedArguments); + Assert.Equal("UInt64Field", value.NamedArguments[0].Name); + Assert.Equal("uint64", value.NamedArguments[0].Type); + Assert.Equal((ulong)8, value.NamedArguments[0].Value); + break; + + case 66: // [Test(BooleanField = true)] + Assert.Empty(value.FixedArguments); + Assert.Equal("BooleanField", value.NamedArguments[0].Name); + Assert.Equal("bool", value.NamedArguments[0].Type); + Assert.Equal(true, value.NamedArguments[0].Value); + break; + + case 67: // [Test(BooleanField = false)] + Assert.Empty(value.FixedArguments); + Assert.Equal("BooleanField", value.NamedArguments[0].Name); + Assert.Equal("bool", value.NamedArguments[0].Type); + Assert.Equal(false, value.NamedArguments[0].Value); + break; + + case 68: // [Test(TypeField = typeof(string))] + Assert.Empty(value.FixedArguments); + Assert.Equal("TypeField", value.NamedArguments[0].Name); + Assert.Equal(provider.GetSystemType(), value.NamedArguments[0].Type); + Assert.Contains("System.String", (string)value.NamedArguments[0].Value); + break; + + case 69: // [Test(SByteEnumField = SByteEnum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("SByteEnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.SByteEnum", value.NamedArguments[0].Type); + Assert.Equal((sbyte)-1, value.NamedArguments[0].Value); + break; + + case 70: // [Test(Int16EnumField = Int16Enum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("Int16EnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.Int16Enum", value.NamedArguments[0].Type); + Assert.Equal((short)-2, value.NamedArguments[0].Value); + break; + + case 71: // [Test(Int32EnumField = Int32Enum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("Int32EnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.Int32Enum", value.NamedArguments[0].Type); + Assert.Equal(-3, value.NamedArguments[0].Value); + break; + + case 72: // [Test(Int64EnumField = Int64Enum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("Int64EnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.Int64Enum", value.NamedArguments[0].Type); + Assert.Equal((long)-4, value.NamedArguments[0].Value); + break; + + case 73: // [Test(ByteEnumField = ByteEnum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("ByteEnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.ByteEnum", value.NamedArguments[0].Type); + Assert.Equal((byte)1, value.NamedArguments[0].Value); + break; + + case 74: // [Test(UInt16EnumField = UInt16Enum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("UInt16EnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.UInt16Enum", value.NamedArguments[0].Type); + Assert.Equal((ushort)2, value.NamedArguments[0].Value); + break; + + case 75: // [Test(UInt32EnumField = UInt32Enum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("UInt32EnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.UInt32Enum", value.NamedArguments[0].Type); + Assert.Equal((uint)3, value.NamedArguments[0].Value); + break; + + case 76: // [Test(UInt64EnumField = UInt64Enum.Value)] + Assert.Empty(value.FixedArguments); + Assert.Equal("UInt64EnumField", value.NamedArguments[0].Name); + Assert.Equal("CustomAttributeDecoderTests.UInt64Enum", value.NamedArguments[0].Type); + Assert.Equal((ulong)4, value.NamedArguments[0].Value); + break; + + case 77: // [Test(new string[] { })] second occurrence + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string[]", value.FixedArguments[0].Type); + Assert.Empty((ImmutableArray>)value.FixedArguments[0].Value); + break; + + case 78: // [Test(new string[] { "x", "y", "z", null })] second occurrence + { + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string[]", value.FixedArguments[0].Type); + var strArray = (ImmutableArray>)value.FixedArguments[0].Value; + Assert.Equal(4, strArray.Length); + break; + } + + case 79: // [Test(ObjectField = null)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("ObjectField", value.NamedArguments[0].Name); + Assert.Equal("string", value.NamedArguments[0].Type); + Assert.Null(value.NamedArguments[0].Value); + break; + + case 80: // [Test(StringField = null)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("StringField", value.NamedArguments[0].Name); + Assert.Equal("string", value.NamedArguments[0].Type); + Assert.Null(value.NamedArguments[0].Value); + break; + + case 81: // [Test(Int32ArrayProperty = null)] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("Int32ArrayProperty", value.NamedArguments[0].Name); + Assert.Equal("int32[]", value.NamedArguments[0].Type); + Assert.Null(value.NamedArguments[0].Value); + break; } } + + Assert.Equal(82, i); } } #if NET && !TARGET_BROWSER // Generic attribute is not supported on .NET Framework. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60579", TestPlatforms.iOS | TestPlatforms.tvOS)] - public void TestCustomAttributeDecoderGenericUsingReflection() + [Fact] + public void TestCustomAttributeDecoderGeneric() { - Type type = typeof(HasGenericAttributes); - using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(type.GetTypeInfo().Assembly))) - using (PEReader peReader = new PEReader(stream)) + using (var stream = new MemoryStream(DecodingResources.CustomAttributeDecoder)) + using (var peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); - CustomAttributeTypeProvider provider = new CustomAttributeTypeProvider(); - TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, type); - - IList attributes= type.GetCustomAttributesData(); + var provider = new CustomAttributeTypeProvider(); + TypeDefinitionHandle typeDefHandle = FindTestType(reader, "CustomAttributeDecoderTests", "HasGenericAttributes"); int i = 0; foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) { CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue value = attribute.DecodeValue(provider); - CustomAttributeData reflectionAttribute = attributes[i++]; - - Assert.Equal(reflectionAttribute.ConstructorArguments.Count, value.FixedArguments.Length); - Assert.Equal(reflectionAttribute.NamedArguments.Count, value.NamedArguments.Length); - int j = 0; - foreach (CustomAttributeTypedArgument arguments in value.FixedArguments) - { - Assert.Equal(TypeToString(reflectionAttribute.ConstructorArguments[j].ArgumentType), arguments.Type); - if (reflectionAttribute.ConstructorArguments[j].Value.ToString() != arguments.Value.ToString()) - { - Assert.Equal(reflectionAttribute.ConstructorArguments[j].Value, arguments.Value); - } - j++; - } - j = 0; - foreach (CustomAttributeNamedArgument arguments in value.NamedArguments) + switch (i++) { - Assert.Equal(TypeToString(reflectionAttribute.NamedArguments[j].TypedValue.ArgumentType), arguments.Type); - if (reflectionAttribute.NamedArguments[j].TypedValue.Value.ToString() != arguments.Value.ToString()) - { - Assert.Equal(reflectionAttribute.NamedArguments[j].TypedValue.Value, arguments.Value); - } - j++; + case 0: // [GenericAttribute] + Assert.Empty(value.FixedArguments); + Assert.Empty(value.NamedArguments); + break; + + case 1: // [GenericAttribute("Hello")] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("string", value.FixedArguments[0].Type); + Assert.Equal("Hello", value.FixedArguments[0].Value); + Assert.Empty(value.NamedArguments); + break; + + case 2: // [GenericAttribute(12)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("int32", value.FixedArguments[0].Type); + Assert.Equal(12, value.FixedArguments[0].Value); + Assert.Empty(value.NamedArguments); + break; + + case 3: // [GenericAttribute("Hello", 12, TProperty = "Bye")] + Assert.Equal(2, value.FixedArguments.Length); + Assert.Equal("string", value.FixedArguments[0].Type); + Assert.Equal("Hello", value.FixedArguments[0].Value); + Assert.Equal("int32", value.FixedArguments[1].Type); + Assert.Equal(12, value.FixedArguments[1].Value); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("TProperty", value.NamedArguments[0].Name); + Assert.Equal("string", value.NamedArguments[0].Type); + Assert.Equal("Bye", value.NamedArguments[0].Value); + break; + + case 4: // [GenericAttribute(1, TProperty = 2)] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint8", value.FixedArguments[0].Type); + Assert.Equal((byte)1, value.FixedArguments[0].Value); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("TProperty", value.NamedArguments[0].Name); + Assert.Equal("uint8", value.NamedArguments[0].Type); + Assert.Equal((byte)2, value.NamedArguments[0].Value); + break; + + case 5: // [GenericAttribute2(true, 13)] + Assert.Equal(2, value.FixedArguments.Length); + Assert.Equal("bool", value.FixedArguments[0].Type); + Assert.Equal(true, value.FixedArguments[0].Value); + Assert.Equal("int32", value.FixedArguments[1].Type); + Assert.Equal(13, value.FixedArguments[1].Value); + Assert.Empty(value.NamedArguments); + break; + + case 6: // [GenericAttribute(typeof(HasAttributes))] + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal(provider.GetSystemType(), value.FixedArguments[0].Type); + Assert.Contains("CustomAttributeDecoderTests.HasAttributes", (string)value.FixedArguments[0].Value); + Assert.Empty(value.NamedArguments); + break; + + case 7: // [GenericAttribute(TProperty = typeof(HasAttributes))] + Assert.Empty(value.FixedArguments); + Assert.Equal(1, value.NamedArguments.Length); + Assert.Equal("TProperty", value.NamedArguments[0].Name); + Assert.Equal(provider.GetSystemType(), value.NamedArguments[0].Type); + Assert.Contains("CustomAttributeDecoderTests.HasAttributes", (string)value.NamedArguments[0].Value); + break; } } + + Assert.Equal(8, i); } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasAssemblyFiles))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/60579", TestPlatforms.iOS | TestPlatforms.tvOS)] + [Fact] public void TestCustomAttributeDecoderGenericArray() { - Type type = typeof(HasGenericArrayAttributes); - using (FileStream stream = File.OpenRead(AssemblyPathHelper.GetAssemblyLocation(type.GetTypeInfo().Assembly))) - using (PEReader peReader = new PEReader(stream)) + using (var stream = new MemoryStream(DecodingResources.CustomAttributeDecoder)) + using (var peReader = new PEReader(stream)) { MetadataReader reader = peReader.GetMetadataReader(); - CustomAttributeTypeProvider provider = new CustomAttributeTypeProvider(); - TypeDefinitionHandle typeDefHandle = TestMetadataResolver.FindTestType(reader, type); - - IList attributes = type.GetCustomAttributesData(); + var provider = new CustomAttributeTypeProvider(); + TypeDefinitionHandle typeDefHandle = FindTestType(reader, "CustomAttributeDecoderTests", "HasGenericArrayAttributes"); + int i = 0; foreach (CustomAttributeHandle attributeHandle in reader.GetCustomAttributes(typeDefHandle)) { CustomAttribute attribute = reader.GetCustomAttribute(attributeHandle); CustomAttributeValue value = attribute.DecodeValue(provider); - if (value.FixedArguments.Length == 2) - { - Assert.Equal(2, value.FixedArguments.Length); - ImmutableArray> array1 = (ImmutableArray>)(value.FixedArguments[0].Value); - Assert.Equal("int32[]", value.FixedArguments[0].Type); - Assert.Equal(1, array1[0].Value); - Assert.Equal(3, array1[2].Value); - ImmutableArray> array2 = (ImmutableArray>)(value.FixedArguments[1].Value); - Assert.Equal("uint8[]", value.FixedArguments[1].Type); - Assert.Equal((byte)4, array2[0].Value); - Assert.Equal((byte)5, array2[1].Value); - - Assert.Empty(value.NamedArguments); - } - else + switch (i++) { - Assert.Equal(1, value.FixedArguments.Length); - - Assert.Equal("uint8", value.FixedArguments[0].Type); - Assert.Equal((byte)1, value.FixedArguments[0].Value); - - Assert.Equal(2, value.NamedArguments.Length); - - Assert.Equal("uint8", value.NamedArguments[0].Type); - Assert.Equal((byte)2, value.NamedArguments[0].Value); + case 0: // [GenericAttribute2(new int[] { 1, 2, 3 }, new byte[] { 4, 5 })] + { + Assert.Equal(2, value.FixedArguments.Length); + ImmutableArray> array1 = (ImmutableArray>)(value.FixedArguments[0].Value); + Assert.Equal("int32[]", value.FixedArguments[0].Type); + Assert.Equal(1, array1[0].Value); + Assert.Equal(3, array1[2].Value); + ImmutableArray> array2 = (ImmutableArray>)(value.FixedArguments[1].Value); + Assert.Equal("uint8[]", value.FixedArguments[1].Type); + Assert.Equal((byte)4, array2[0].Value); + Assert.Equal((byte)5, array2[1].Value); + Assert.Empty(value.NamedArguments); + break; + } - ImmutableArray> array = (ImmutableArray>)(value.NamedArguments[1].Value); - Assert.Equal("uint8[]", value.NamedArguments[1].Type); - Assert.Equal((byte)3, array[0].Value); + case 1: // [GenericAttribute(1, TProperty = 2, TArrayProperty = new byte[] { 3, 4 })] + { + Assert.Equal(1, value.FixedArguments.Length); + Assert.Equal("uint8", value.FixedArguments[0].Type); + Assert.Equal((byte)1, value.FixedArguments[0].Value); + Assert.Equal(2, value.NamedArguments.Length); + Assert.Equal("uint8", value.NamedArguments[0].Type); + Assert.Equal((byte)2, value.NamedArguments[0].Value); + ImmutableArray> array = (ImmutableArray>)(value.NamedArguments[1].Value); + Assert.Equal("uint8[]", value.NamedArguments[1].Type); + Assert.Equal((byte)3, array[0].Value); + break; + } } } - } - } - [GenericAttribute] - [GenericAttribute("Hello")] - [GenericAttribute(12)] - [GenericAttribute("Hello", 12, TProperty = "Bye")] - [GenericAttribute(1, TProperty = 2)] - [GenericAttribute2(true, 13)] - // [GenericAttribute(MyEnum.Property)] TODO: https://github.com/dotnet/runtime/issues/16552 - [GenericAttribute(typeof(HasAttributes))] - [GenericAttribute(TProperty = typeof(HasAttributes))] - public class HasGenericAttributes { } - - [GenericAttribute2(new int[] { 1, 2, 3 }, new byte[] { 4, 5 })] - [GenericAttribute(1, TProperty = 2, TArrayProperty = new byte[] { 3, 4 })] - public class HasGenericArrayAttributes { } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] - internal class GenericAttribute : Attribute - { - public GenericAttribute() { } - public GenericAttribute(T value) - { - Field = value; + Assert.Equal(2, i); } - public GenericAttribute(T value, int count) - { - Field = value; - } - public T TProperty { get; set; } - public T[] TArrayProperty { get; set; } - public T Field; - } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] - internal class GenericAttribute2 : Attribute - { - public GenericAttribute2() { } - public GenericAttribute2(K key) { } - public GenericAttribute2(K key, V value) { } - public K Key { get; set; } - public V Value { get; set; } - public K[] ArrayProperty { get; set; } } #endif - // no arguments - [Test] - - // multiple fixed arguments - [Test("0", 1, 2.0)] - - // multiple named arguments - [Test(StringField = "0", Int32Field = 1, SByteEnumArrayProperty = new[] { SByteEnum.Value })] - - // multiple fixed and named arguments - [Test("0", 1, 2.0, StringField = "0", Int32Field = 1, DoubleField = 2.0)] - - // single fixed null argument - [Test((object)null)] - [Test((string)null)] - [Test((Type)null)] - [Test((int[])null)] - - // single fixed arguments with strong type - [Test("string")] - [Test((sbyte)-1)] - [Test((short)-2)] - [Test((int)-4)] - [Test((long)-8)] - [Test((sbyte)-1)] - [Test((short)-2)] - [Test((int)-4)] - [Test((long)-8)] - [Test((byte)1)] - [Test((ushort)2)] - [Test((uint)4)] - [Test((ulong)8)] - [Test(true)] - [Test(false)] - [Test(typeof(string))] - /* [Test(SByteEnum.Value)] // The FullName is (System.Reflection.Metadata.Decoding.Tests.CustomAttributeDecoderTests+SByteEnum) - [Test(Int16Enum.Value)] // but some enums '+' is replaced with '/' and causing inconsistency - [Test(Int32Enum.Value)] // Updaated https://github.com/dotnet/runtime/issues/16552 to resolve this scenario later - [Test(Int64Enum.Value)] - [Test(ByteEnum.Value)] - [Test(UInt16Enum.Value)] - [Test(UInt32Enum.Value)] - [Test(UInt64Enum.Value)]*/ - [Test(new string[] { })] - [Test(new string[] { "x", "y", "z", null })] - // [Test(new Int32Enum[] { Int32Enum.Value })] TODO: https://github.com/dotnet/runtime/issues/16552 - - // same single fixed arguments as above, typed as object - [Test((object)("string"))] - [Test((object)(sbyte)-1)] - [Test((object)(short)-2)] - [Test((object)(int)-4)] - [Test((object)(long)-8)] - [Test((object)(sbyte)-1)] - [Test((object)(short)-2)] - [Test((object)(int)-4)] - [Test((object)(long)-8)] - [Test((object)(byte)1)] - [Test((object)(ushort)2)] - [Test((object)(uint)4)] - [Test((object)(true))] - [Test((object)(false))] - [Test((object)(typeof(string)))] - [Test((object)(SByteEnum.Value))] - [Test((object)(Int16Enum.Value))] - [Test((object)(Int32Enum.Value))] - [Test((object)(Int64Enum.Value))] - [Test((object)(ByteEnum.Value))] - [Test((object)(UInt16Enum.Value))] - [Test((object)(UInt32Enum.Value))] - [Test((object)(UInt64Enum.Value))] - [Test((object)(new string[] { }))] - [Test((object)(new string[] { "x", "y", "z", null }))] - [Test((object)(new Int32Enum[] { Int32Enum.Value }))] - - // same values as above two cases, but put into an object[] - [Test(new object[] { - "string", - (sbyte)-1, - (short)-2, - (int)-4, - (long)-8, - (sbyte)-1, - (short)-2, - (int)-4, - (long)-8, - (byte)1, - (ushort)2, - (uint)4, - true, - false, - typeof(string), // check if the produced value is expected - SByteEnum.Value, - Int16Enum.Value, - Int32Enum.Value, - Int64Enum.Value, - SByteEnum.Value, - Int16Enum.Value, - Int32Enum.Value, - Int64Enum.Value, - new string[] {}, - new string[] { "x", "y", "z", null }, - })] - - // same values as strongly-typed fixed arguments as named arguments - // single fixed arguments with strong type - [Test(StringField = "string")] - [Test(SByteField = -1)] - [Test(Int16Field = -2)] - [Test(Int32Field = -4)] - [Test(Int64Field = -8)] - [Test(SByteField = -1)] - [Test(Int16Field = -2)] - [Test(Int32Field = -4)] - [Test(Int64Field = -8)] - [Test(ByteField = 1)] - [Test(UInt16Field = 2)] - [Test(UInt32Field = 4)] - [Test(UInt64Field = 8)] - [Test(BooleanField = true)] - [Test(BooleanField = false)] - [Test(TypeField = typeof(string))] - [Test(SByteEnumField = SByteEnum.Value)] - [Test(Int16EnumField = Int16Enum.Value)] - [Test(Int32EnumField = Int32Enum.Value)] - [Test(Int64EnumField = Int64Enum.Value)] - [Test(ByteEnumField = ByteEnum.Value)] - [Test(UInt16EnumField = UInt16Enum.Value)] - [Test(UInt32EnumField = UInt32Enum.Value)] - [Test(UInt64EnumField = UInt64Enum.Value)] - [Test(new string[] { })] - [Test(new string[] { "x", "y", "z", null })] - // [Test(new Int32Enum[] { Int32Enum.Value })] TODO: https://github.com/dotnet/runtime/issues/16552 - - // null named arguments - [Test(ObjectField = null)] - [Test(StringField = null)] - - [Test(Int32ArrayProperty = null)] - - private sealed class HasAttributes { } - - public enum SByteEnum : sbyte { Value = -1 } - public enum Int16Enum : short { Value = -2 } - public enum Int32Enum : int { Value = -3 } - public enum Int64Enum : long { Value = -4 } - public enum ByteEnum : sbyte { Value = 1 } - public enum UInt16Enum : ushort { Value = 2 } - public enum UInt32Enum : uint { Value = 3 } - public enum UInt64Enum : ulong { Value = 4 } - - [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] - public sealed class TestAttribute : Attribute - { - public TestAttribute() { } - public TestAttribute(string x, int y, double z) { } - public TestAttribute(string value) { } - public TestAttribute(object value) { } - public TestAttribute(sbyte value) { } - public TestAttribute(short value) { } - public TestAttribute(int value) { } - public TestAttribute(long value) { } - public TestAttribute(byte value) { } - public TestAttribute(ushort value) { } - public TestAttribute(uint value) { } - public TestAttribute(ulong value) { } - public TestAttribute(bool value) { } - public TestAttribute(float value) { } - public TestAttribute(double value) { } - public TestAttribute(Type value) { } - public TestAttribute(SByteEnum value) { } - public TestAttribute(Int16Enum value) { } - public TestAttribute(Int32Enum value) { } - public TestAttribute(Int64Enum value) { } - public TestAttribute(ByteEnum value) { } - public TestAttribute(UInt16Enum value) { } - public TestAttribute(UInt32Enum value) { } - public TestAttribute(UInt64Enum value) { } - public TestAttribute(string[] value) { } - public TestAttribute(object[] value) { } - public TestAttribute(sbyte[] value) { } - public TestAttribute(short[] value) { } - public TestAttribute(int[] value) { } - public TestAttribute(long[] value) { } - public TestAttribute(byte[] value) { } - public TestAttribute(ushort[] value) { } - public TestAttribute(uint[] value) { } - public TestAttribute(ulong[] value) { } - public TestAttribute(bool[] value) { } - public TestAttribute(float[] value) { } - public TestAttribute(double[] value) { } - public TestAttribute(Type[] value) { } - public TestAttribute(SByteEnum[] value) { } - public TestAttribute(Int16Enum[] value) { } - public TestAttribute(Int32Enum[] value) { } - public TestAttribute(Int64Enum[] value) { } - public TestAttribute(ByteEnum[] value) { } - public TestAttribute(UInt16Enum[] value) { } - public TestAttribute(UInt32Enum[] value) { } - public TestAttribute(UInt64Enum[] value) { } - - public string StringField; - public object ObjectField; - public sbyte SByteField; - public short Int16Field; - public int Int32Field; - public long Int64Field; - public byte ByteField; - public ushort UInt16Field; - public uint UInt32Field; - public ulong UInt64Field; - public bool BooleanField; - public float SingleField; - public double DoubleField; - public Type TypeField; - public SByteEnum SByteEnumField; - public Int16Enum Int16EnumField; - public Int32Enum Int32EnumField; - public Int64Enum Int64EnumField; - public ByteEnum ByteEnumField; - public UInt16Enum UInt16EnumField; - public UInt32Enum UInt32EnumField; - public UInt64Enum UInt64EnumField; - - public string[] StringArrayProperty { get; set; } - public object[] ObjectArrayProperty { get; set; } - public sbyte[] SByteArrayProperty { get; set; } - public short[] Int16ArrayProperty { get; set; } - public int[] Int32ArrayProperty { get; set; } - public long[] Int64ArrayProperty { get; set; } - public byte[] ByteArrayProperty { get; set; } - public ushort[] UInt16ArrayProperty { get; set; } - public uint[] UInt32ArrayProperty { get; set; } - public ulong[] UInt64ArrayProperty { get; set; } - public bool[] BooleanArrayProperty { get; set; } - public float[] SingleArrayProperty { get; set; } - public double[] DoubleArrayProperty { get; set; } - public Type[] TypeArrayProperty { get; set; } - public SByteEnum[] SByteEnumArrayProperty { get; set; } - public Int16Enum[] Int16EnumArrayProperty { get; set; } - public Int32Enum[] Int32EnumArrayProperty { get; set; } - public Int64Enum[] Int64EnumArrayProperty { get; set; } - public ByteEnum[] ByteEnumArrayProperty { get; set; } - public UInt16Enum[] UInt16EnumArrayProperty { get; set; } - public UInt32Enum[] UInt32EnumArrayProperty { get; set; } - public UInt64Enum[] UInt64EnumArrayProperty { get; set; } - } - - private string TypeToString(Type type) + private static TypeDefinitionHandle FindTestType(MetadataReader reader, string @namespace, string name) { - if (type == typeof(Type)) - return $"[{MetadataReaderTestHelpers.RuntimeAssemblyName}]System.Type"; - - if (type.IsArray) + foreach (TypeDefinitionHandle handle in reader.TypeDefinitions) { - if (type.GetElementType().IsEnum) + TypeDefinition definition = reader.GetTypeDefinition(handle); + if (reader.StringComparer.Equals(definition.Namespace, @namespace) && + reader.StringComparer.Equals(definition.Name, name)) { - Type el = type.GetElementType(); - return type.FullName; + return handle; } - return GetPrimitiveType(type.GetElementType()) + "[]"; } - if (type.IsEnum) - return type.FullName; - - return GetPrimitiveType(type); - } - - private static string GetPrimitiveType(Type type) - { - switch (Type.GetTypeCode(type)) - { - case TypeCode.Boolean: - return "bool"; - - case TypeCode.Byte: - return "uint8"; - - case TypeCode.Char: - return "char"; - - case TypeCode.Double: - return "float64"; - - case TypeCode.Int16: - return "int16"; - - case TypeCode.Int32: - return "int32"; - - case TypeCode.Int64: - return "int64"; - - case TypeCode.Object: - return "object"; - - case TypeCode.SByte: - return "int8"; - - case TypeCode.Single: - return "float32"; - - case TypeCode.String: - return "string"; - - case TypeCode.UInt16: - return "uint16"; - - case TypeCode.UInt32: - return "uint32"; - - case TypeCode.UInt64: - return "uint64"; - - default: - throw new ArgumentOutOfRangeException(nameof(type)); - } - } - - public enum MyEnum - { - Ctor, - Property + Assert.Fail($"Cannot find test type: {@namespace}.{name}"); + return default; } private class CustomAttributeTypeProvider : DisassemblingTypeProvider, ICustomAttributeTypeProvider { public string GetSystemType() { - return $"[{MetadataReaderTestHelpers.RuntimeAssemblyName}]System.Type"; + return "[System.Runtime]System.Type"; } public bool IsSystemType(string type) { - return type == $"[{MetadataReaderTestHelpers.RuntimeAssemblyName}]System.Type" // encountered as typeref - || Type.GetType(type) == typeof(Type); // encountered as serialized to reflection notation + return type == "[System.Runtime]System.Type"; } public string GetTypeFromSerializedName(string name) @@ -690,36 +795,23 @@ public string GetTypeFromSerializedName(string name) public PrimitiveTypeCode GetUnderlyingEnumType(string type) { - Type runtimeType = Type.GetType(type.Replace('/', '+')); // '/' vs '+' is only difference between ilasm and reflection notation for fixed set below. - - if (runtimeType == typeof(SByteEnum)) - return PrimitiveTypeCode.SByte; + // Strip assembly-qualified suffix if present (e.g. "Namespace.Type, Assembly, Version=...") + int commaIndex = type.IndexOf(','); + string typeName = commaIndex >= 0 ? type.Substring(0, commaIndex).Trim() : type; - if (runtimeType == typeof(Int16Enum)) - return PrimitiveTypeCode.Int16; - - if (runtimeType == typeof(Int32Enum)) - return PrimitiveTypeCode.Int32; - - if (runtimeType == typeof(Int64Enum)) - return PrimitiveTypeCode.Int64; - - if (runtimeType == typeof(ByteEnum)) - return PrimitiveTypeCode.Byte; - - if (runtimeType == typeof(UInt16Enum)) - return PrimitiveTypeCode.UInt16; - - if (runtimeType == typeof(UInt32Enum)) - return PrimitiveTypeCode.UInt32; - - if (runtimeType == typeof(UInt64Enum)) - return PrimitiveTypeCode.UInt64; - - if (runtimeType == typeof(MyEnum)) - return PrimitiveTypeCode.Byte; - - throw new ArgumentOutOfRangeException(); + return typeName switch + { + "CustomAttributeDecoderTests.SByteEnum" => PrimitiveTypeCode.SByte, + "CustomAttributeDecoderTests.Int16Enum" => PrimitiveTypeCode.Int16, + "CustomAttributeDecoderTests.Int32Enum" => PrimitiveTypeCode.Int32, + "CustomAttributeDecoderTests.Int64Enum" => PrimitiveTypeCode.Int64, + "CustomAttributeDecoderTests.ByteEnum" => PrimitiveTypeCode.Byte, + "CustomAttributeDecoderTests.UInt16Enum" => PrimitiveTypeCode.UInt16, + "CustomAttributeDecoderTests.UInt32Enum" => PrimitiveTypeCode.UInt32, + "CustomAttributeDecoderTests.UInt64Enum" => PrimitiveTypeCode.UInt64, + "CustomAttributeDecoderTests.MyEnum" => PrimitiveTypeCode.Int32, + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + }; } } } diff --git a/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs b/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs new file mode 100644 index 00000000000000..58581cd60106f5 --- /dev/null +++ b/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs @@ -0,0 +1,293 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Source for CustomAttributeDecoder.dll, which is embedded as a test resource. +// To rebuild the DLL, create a project targeting net9.0 or later with LangVersion=latest, +// compile this file, and copy the output to Resources/Decoding/CustomAttributeDecoder.dll. + +using System; + +namespace CustomAttributeDecoderTests +{ + public enum SByteEnum : sbyte { Value = -1 } + public enum Int16Enum : short { Value = -2 } + public enum Int32Enum : int { Value = -3 } + public enum Int64Enum : long { Value = -4 } + public enum ByteEnum : sbyte { Value = 1 } // intentionally sbyte as underlying type (matches existing test behavior) + public enum UInt16Enum : ushort { Value = 2 } + public enum UInt32Enum : uint { Value = 3 } + public enum UInt64Enum : ulong { Value = 4 } + + public enum MyEnum { Ctor, Property } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public sealed class TestAttribute : Attribute + { + public TestAttribute() { } + public TestAttribute(string x, int y, double z) { } + public TestAttribute(string value) { } + public TestAttribute(object value) { } + public TestAttribute(sbyte value) { } + public TestAttribute(short value) { } + public TestAttribute(int value) { } + public TestAttribute(long value) { } + public TestAttribute(byte value) { } + public TestAttribute(ushort value) { } + public TestAttribute(uint value) { } + public TestAttribute(ulong value) { } + public TestAttribute(bool value) { } + public TestAttribute(float value) { } + public TestAttribute(double value) { } + public TestAttribute(Type value) { } + public TestAttribute(SByteEnum value) { } + public TestAttribute(Int16Enum value) { } + public TestAttribute(Int32Enum value) { } + public TestAttribute(Int64Enum value) { } + public TestAttribute(ByteEnum value) { } + public TestAttribute(UInt16Enum value) { } + public TestAttribute(UInt32Enum value) { } + public TestAttribute(UInt64Enum value) { } + public TestAttribute(string[] value) { } + public TestAttribute(object[] value) { } + public TestAttribute(sbyte[] value) { } + public TestAttribute(short[] value) { } + public TestAttribute(int[] value) { } + public TestAttribute(long[] value) { } + public TestAttribute(byte[] value) { } + public TestAttribute(ushort[] value) { } + public TestAttribute(uint[] value) { } + public TestAttribute(ulong[] value) { } + public TestAttribute(bool[] value) { } + public TestAttribute(float[] value) { } + public TestAttribute(double[] value) { } + public TestAttribute(Type[] value) { } + public TestAttribute(SByteEnum[] value) { } + public TestAttribute(Int16Enum[] value) { } + public TestAttribute(Int32Enum[] value) { } + public TestAttribute(Int64Enum[] value) { } + public TestAttribute(ByteEnum[] value) { } + public TestAttribute(UInt16Enum[] value) { } + public TestAttribute(UInt32Enum[] value) { } + public TestAttribute(UInt64Enum[] value) { } + + public string StringField; + public object ObjectField; + public sbyte SByteField; + public short Int16Field; + public int Int32Field; + public long Int64Field; + public byte ByteField; + public ushort UInt16Field; + public uint UInt32Field; + public ulong UInt64Field; + public bool BooleanField; + public float SingleField; + public double DoubleField; + public Type TypeField; + public SByteEnum SByteEnumField; + public Int16Enum Int16EnumField; + public Int32Enum Int32EnumField; + public Int64Enum Int64EnumField; + public ByteEnum ByteEnumField; + public UInt16Enum UInt16EnumField; + public UInt32Enum UInt32EnumField; + public UInt64Enum UInt64EnumField; + + public string[] StringArrayProperty { get; set; } + public object[] ObjectArrayProperty { get; set; } + public sbyte[] SByteArrayProperty { get; set; } + public short[] Int16ArrayProperty { get; set; } + public int[] Int32ArrayProperty { get; set; } + public long[] Int64ArrayProperty { get; set; } + public byte[] ByteArrayProperty { get; set; } + public ushort[] UInt16ArrayProperty { get; set; } + public uint[] UInt32ArrayProperty { get; set; } + public ulong[] UInt64ArrayProperty { get; set; } + public bool[] BooleanArrayProperty { get; set; } + public float[] SingleArrayProperty { get; set; } + public double[] DoubleArrayProperty { get; set; } + public Type[] TypeArrayProperty { get; set; } + public SByteEnum[] SByteEnumArrayProperty { get; set; } + public Int16Enum[] Int16EnumArrayProperty { get; set; } + public Int32Enum[] Int32EnumArrayProperty { get; set; } + public Int64Enum[] Int64EnumArrayProperty { get; set; } + public ByteEnum[] ByteEnumArrayProperty { get; set; } + public UInt16Enum[] UInt16EnumArrayProperty { get; set; } + public UInt32Enum[] UInt32EnumArrayProperty { get; set; } + public UInt64Enum[] UInt64EnumArrayProperty { get; set; } + } + + // no arguments + [Test] + + // multiple fixed arguments + [Test("0", 1, 2.0)] + + // multiple named arguments + [Test(StringField = "0", Int32Field = 1, SByteEnumArrayProperty = new[] { SByteEnum.Value })] + + // multiple fixed and named arguments + [Test("0", 1, 2.0, StringField = "0", Int32Field = 1, DoubleField = 2.0)] + + // single fixed null argument + [Test((object)null)] + [Test((string)null)] + [Test((Type)null)] + [Test((int[])null)] + + // single fixed arguments with strong type + [Test("string")] + [Test((sbyte)-1)] + [Test((short)-2)] + [Test((int)-4)] + [Test((long)-8)] + [Test((sbyte)-1)] + [Test((short)-2)] + [Test((int)-4)] + [Test((long)-8)] + [Test((byte)1)] + [Test((ushort)2)] + [Test((uint)4)] + [Test((ulong)8)] + [Test(true)] + [Test(false)] + [Test(typeof(string))] + [Test(new string[] { })] + [Test(new string[] { "x", "y", "z", null })] + + // same single fixed arguments as above, typed as object + [Test((object)("string"))] + [Test((object)(sbyte)-1)] + [Test((object)(short)-2)] + [Test((object)(int)-4)] + [Test((object)(long)-8)] + [Test((object)(sbyte)-1)] + [Test((object)(short)-2)] + [Test((object)(int)-4)] + [Test((object)(long)-8)] + [Test((object)(byte)1)] + [Test((object)(ushort)2)] + [Test((object)(uint)4)] + [Test((object)(true))] + [Test((object)(false))] + [Test((object)(typeof(string)))] + [Test((object)(SByteEnum.Value))] + [Test((object)(Int16Enum.Value))] + [Test((object)(Int32Enum.Value))] + [Test((object)(Int64Enum.Value))] + [Test((object)(ByteEnum.Value))] + [Test((object)(UInt16Enum.Value))] + [Test((object)(UInt32Enum.Value))] + [Test((object)(UInt64Enum.Value))] + [Test((object)(new string[] { }))] + [Test((object)(new string[] { "x", "y", "z", null }))] + [Test((object)(new Int32Enum[] { Int32Enum.Value }))] + + // same values as above two cases, but put into an object[] + [Test(new object[] { + "string", + (sbyte)-1, + (short)-2, + (int)-4, + (long)-8, + (sbyte)-1, + (short)-2, + (int)-4, + (long)-8, + (byte)1, + (ushort)2, + (uint)4, + true, + false, + typeof(string), + SByteEnum.Value, + Int16Enum.Value, + Int32Enum.Value, + Int64Enum.Value, + SByteEnum.Value, + Int16Enum.Value, + Int32Enum.Value, + Int64Enum.Value, + new string[] {}, + new string[] { "x", "y", "z", null }, + })] + + // same values as strongly-typed fixed arguments as named arguments + [Test(StringField = "string")] + [Test(SByteField = -1)] + [Test(Int16Field = -2)] + [Test(Int32Field = -4)] + [Test(Int64Field = -8)] + [Test(SByteField = -1)] + [Test(Int16Field = -2)] + [Test(Int32Field = -4)] + [Test(Int64Field = -8)] + [Test(ByteField = 1)] + [Test(UInt16Field = 2)] + [Test(UInt32Field = 4)] + [Test(UInt64Field = 8)] + [Test(BooleanField = true)] + [Test(BooleanField = false)] + [Test(TypeField = typeof(string))] + [Test(SByteEnumField = SByteEnum.Value)] + [Test(Int16EnumField = Int16Enum.Value)] + [Test(Int32EnumField = Int32Enum.Value)] + [Test(Int64EnumField = Int64Enum.Value)] + [Test(ByteEnumField = ByteEnum.Value)] + [Test(UInt16EnumField = UInt16Enum.Value)] + [Test(UInt32EnumField = UInt32Enum.Value)] + [Test(UInt64EnumField = UInt64Enum.Value)] + [Test(new string[] { })] + [Test(new string[] { "x", "y", "z", null })] + + // null named arguments + [Test(ObjectField = null)] + [Test(StringField = null)] + + [Test(Int32ArrayProperty = null)] + + public sealed class HasAttributes { } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class GenericAttribute : Attribute + { + public GenericAttribute() { } + public GenericAttribute(T value) + { + Field = value; + } + public GenericAttribute(T value, int count) + { + Field = value; + } + public T TProperty { get; set; } + public T[] TArrayProperty { get; set; } + public T Field; + } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] + public class GenericAttribute2 : Attribute + { + public GenericAttribute2() { } + public GenericAttribute2(K key) { } + public GenericAttribute2(K key, V value) { } + public K Key { get; set; } + public V Value { get; set; } + public K[] ArrayProperty { get; set; } + } + + [GenericAttribute] + [GenericAttribute("Hello")] + [GenericAttribute(12)] + [GenericAttribute("Hello", 12, TProperty = "Bye")] + [GenericAttribute(1, TProperty = 2)] + [GenericAttribute2(true, 13)] + // [GenericAttribute(MyEnum.Property)] TODO: https://github.com/dotnet/runtime/issues/16552 + [GenericAttribute(typeof(HasAttributes))] + [GenericAttribute(TProperty = typeof(HasAttributes))] + public class HasGenericAttributes { } + + [GenericAttribute2(new int[] { 1, 2, 3 }, new byte[] { 4, 5 })] + [GenericAttribute(1, TProperty = 2, TArrayProperty = new byte[] { 3, 4 })] + public class HasGenericArrayAttributes { } +} diff --git a/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.dll b/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.dll new file mode 100644 index 0000000000000000000000000000000000000000..3844243c0a3a6466ede565231afa6a292e356585 GIT binary patch literal 15872 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 literal 0 HcmV?d00001 diff --git a/src/libraries/System.Reflection.Metadata/tests/Resources/TestResources.cs b/src/libraries/System.Reflection.Metadata/tests/Resources/TestResources.cs index df78a0d222689a..c7735d507801f2 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Resources/TestResources.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Resources/TestResources.cs @@ -66,6 +66,11 @@ internal static class PortablePdbs public static readonly byte[] DocumentsEmbeddedDll = ResourceHelper.GetResource("PortablePdbs.Documents.Embedded.dll"); } + internal static class Decoding + { + public static readonly byte[] CustomAttributeDecoder = ResourceHelper.GetResource("Decoding.CustomAttributeDecoder.dll"); + } + internal static class SynthesizedPeImages { private static Lazy> _image1 = new Lazy>(GenerateImage); diff --git a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj index c87d9b4a6f2502..b457671f9de01c 100644 --- a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj +++ b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj @@ -146,6 +146,8 @@ + + From ab685d88f1090b53fbdeb9e4a11b4b2de2417d91 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:30:19 +0000 Subject: [PATCH 3/4] Improve ByteEnum comment clarity in CustomAttributeDecoder.cs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/8f883665-1cac-472f-81aa-5074b5ff4f1c Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../tests/Resources/Decoding/CustomAttributeDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs b/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs index 58581cd60106f5..8af1eb175e0522 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Resources/Decoding/CustomAttributeDecoder.cs @@ -13,7 +13,7 @@ public enum SByteEnum : sbyte { Value = -1 } public enum Int16Enum : short { Value = -2 } public enum Int32Enum : int { Value = -3 } public enum Int64Enum : long { Value = -4 } - public enum ByteEnum : sbyte { Value = 1 } // intentionally sbyte as underlying type (matches existing test behavior) + public enum ByteEnum : sbyte { Value = 1 } // named ByteEnum but uses sbyte underlying type to match existing test expectations public enum UInt16Enum : ushort { Value = 2 } public enum UInt32Enum : uint { Value = 3 } public enum UInt64Enum : ulong { Value = 4 } From ca6c9580a2cba4242a24785147d770cd4f2d3886 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:54:28 +0000 Subject: [PATCH 4/4] Revert unnecessary test expansions in TestCustomAttributeDecoder - Restore TestCustomAttributeDecoder to original 3-case structure with default: break - Remove cases 3-81 that were added unnecessarily - Keep all other necessary changes: loading via embedded resource, FindTestType helper, updated CustomAttributeTypeProvider, TestCustomAttributeDecoderGeneric, TestCustomAttributeDecoderGenericArray Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/139c63c4-491a-4ab0-81cc-432ef0e7b479 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../Decoding/CustomAttributeDecoderTests.cs | 542 +----------------- 1 file changed, 1 insertion(+), 541 deletions(-) diff --git a/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs b/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs index 5c0cda52be6bc5..a6df4e1e59f21a 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Metadata/Decoding/CustomAttributeDecoderTests.cs @@ -69,550 +69,10 @@ public void TestCustomAttributeDecoder() Assert.Equal((sbyte)-1, sbyteEnumArray[0].Value); break; - case 3: // [Test("0", 1, 2.0, StringField = "0", Int32Field = 1, DoubleField = 2.0)] - Assert.Equal(3, value.FixedArguments.Length); - Assert.Equal(3, value.NamedArguments.Length); - Assert.Equal("0", value.FixedArguments[0].Value); - Assert.Equal(1, value.FixedArguments[1].Value); - Assert.Equal(2.0, value.FixedArguments[2].Value); - Assert.Equal("StringField", value.NamedArguments[0].Name); - Assert.Equal("0", value.NamedArguments[0].Value); - Assert.Equal("Int32Field", value.NamedArguments[1].Name); - Assert.Equal(1, value.NamedArguments[1].Value); - Assert.Equal("DoubleField", value.NamedArguments[2].Name); - Assert.Equal(2.0, value.NamedArguments[2].Value); - break; - - case 4: // [Test((object)null)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string", value.FixedArguments[0].Type); - Assert.Null(value.FixedArguments[0].Value); - break; - - case 5: // [Test((string)null)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string", value.FixedArguments[0].Type); - Assert.Null(value.FixedArguments[0].Value); - break; - - case 6: // [Test((Type)null)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal(provider.GetSystemType(), value.FixedArguments[0].Type); - Assert.Null(value.FixedArguments[0].Value); - break; - - case 7: // [Test((int[])null)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int32[]", value.FixedArguments[0].Type); - Assert.Null(value.FixedArguments[0].Value); - break; - - case 8: // [Test("string")] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string", value.FixedArguments[0].Type); - Assert.Equal("string", value.FixedArguments[0].Value); - break; - - case 9: // [Test((sbyte)-1)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int8", value.FixedArguments[0].Type); - Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); - break; - - case 10: // [Test((short)-2)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int16", value.FixedArguments[0].Type); - Assert.Equal((short)-2, value.FixedArguments[0].Value); - break; - - case 11: // [Test((int)-4)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int32", value.FixedArguments[0].Type); - Assert.Equal(-4, value.FixedArguments[0].Value); - break; - - case 12: // [Test((long)-8)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int64", value.FixedArguments[0].Type); - Assert.Equal((long)-8, value.FixedArguments[0].Value); - break; - - case 13: // [Test((sbyte)-1)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int8", value.FixedArguments[0].Type); - Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); - break; - - case 14: // [Test((short)-2)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int16", value.FixedArguments[0].Type); - Assert.Equal((short)-2, value.FixedArguments[0].Value); - break; - - case 15: // [Test((int)-4)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int32", value.FixedArguments[0].Type); - Assert.Equal(-4, value.FixedArguments[0].Value); - break; - - case 16: // [Test((long)-8)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int64", value.FixedArguments[0].Type); - Assert.Equal((long)-8, value.FixedArguments[0].Value); - break; - - case 17: // [Test((byte)1)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("uint8", value.FixedArguments[0].Type); - Assert.Equal((byte)1, value.FixedArguments[0].Value); - break; - - case 18: // [Test((ushort)2)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("uint16", value.FixedArguments[0].Type); - Assert.Equal((ushort)2, value.FixedArguments[0].Value); - break; - - case 19: // [Test((uint)4)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("uint32", value.FixedArguments[0].Type); - Assert.Equal((uint)4, value.FixedArguments[0].Value); - break; - - case 20: // [Test((ulong)8)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("uint64", value.FixedArguments[0].Type); - Assert.Equal((ulong)8, value.FixedArguments[0].Value); - break; - - case 21: // [Test(true)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("bool", value.FixedArguments[0].Type); - Assert.Equal(true, value.FixedArguments[0].Value); - break; - - case 22: // [Test(false)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("bool", value.FixedArguments[0].Type); - Assert.Equal(false, value.FixedArguments[0].Value); - break; - - case 23: // [Test(typeof(string))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal(provider.GetSystemType(), value.FixedArguments[0].Type); - Assert.Contains("System.String", (string)value.FixedArguments[0].Value); - break; - - case 24: // [Test(new string[] { })] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string[]", value.FixedArguments[0].Type); - Assert.Empty((ImmutableArray>)value.FixedArguments[0].Value); - break; - - case 25: // [Test(new string[] { "x", "y", "z", null })] - { - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string[]", value.FixedArguments[0].Type); - var strArray = (ImmutableArray>)value.FixedArguments[0].Value; - Assert.Equal(4, strArray.Length); - Assert.Equal("x", strArray[0].Value); - Assert.Equal("y", strArray[1].Value); - Assert.Equal("z", strArray[2].Value); - Assert.Null(strArray[3].Value); - break; - } - - case 26: // [Test((object)("string"))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string", value.FixedArguments[0].Type); - Assert.Equal("string", value.FixedArguments[0].Value); - break; - - case 27: // [Test((object)(sbyte)-1)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int8", value.FixedArguments[0].Type); - Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); - break; - - case 28: // [Test((object)(short)-2)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int16", value.FixedArguments[0].Type); - Assert.Equal((short)-2, value.FixedArguments[0].Value); - break; - - case 29: // [Test((object)(int)-4)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int32", value.FixedArguments[0].Type); - Assert.Equal(-4, value.FixedArguments[0].Value); - break; - - case 30: // [Test((object)(long)-8)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int64", value.FixedArguments[0].Type); - Assert.Equal((long)-8, value.FixedArguments[0].Value); - break; - - case 31: // [Test((object)(sbyte)-1)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int8", value.FixedArguments[0].Type); - Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); - break; - - case 32: // [Test((object)(short)-2)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int16", value.FixedArguments[0].Type); - Assert.Equal((short)-2, value.FixedArguments[0].Value); - break; - - case 33: // [Test((object)(int)-4)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int32", value.FixedArguments[0].Type); - Assert.Equal(-4, value.FixedArguments[0].Value); - break; - - case 34: // [Test((object)(long)-8)] duplicate - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("int64", value.FixedArguments[0].Type); - Assert.Equal((long)-8, value.FixedArguments[0].Value); - break; - - case 35: // [Test((object)(byte)1)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("uint8", value.FixedArguments[0].Type); - Assert.Equal((byte)1, value.FixedArguments[0].Value); - break; - - case 36: // [Test((object)(ushort)2)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("uint16", value.FixedArguments[0].Type); - Assert.Equal((ushort)2, value.FixedArguments[0].Value); - break; - - case 37: // [Test((object)(uint)4)] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("uint32", value.FixedArguments[0].Type); - Assert.Equal((uint)4, value.FixedArguments[0].Value); - break; - - case 38: // [Test((object)(true))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("bool", value.FixedArguments[0].Type); - Assert.Equal(true, value.FixedArguments[0].Value); - break; - - case 39: // [Test((object)(false))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("bool", value.FixedArguments[0].Type); - Assert.Equal(false, value.FixedArguments[0].Value); - break; - - case 40: // [Test((object)(typeof(string)))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Contains("System.String", (string)value.FixedArguments[0].Value); - break; - - case 41: // [Test((object)(SByteEnum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.SByteEnum", value.FixedArguments[0].Type); - Assert.Equal((sbyte)-1, value.FixedArguments[0].Value); - break; - - case 42: // [Test((object)(Int16Enum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.Int16Enum", value.FixedArguments[0].Type); - Assert.Equal((short)-2, value.FixedArguments[0].Value); - break; - - case 43: // [Test((object)(Int32Enum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.Int32Enum", value.FixedArguments[0].Type); - Assert.Equal(-3, value.FixedArguments[0].Value); - break; - - case 44: // [Test((object)(Int64Enum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.Int64Enum", value.FixedArguments[0].Type); - Assert.Equal((long)-4, value.FixedArguments[0].Value); - break; - - case 45: // [Test((object)(ByteEnum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.ByteEnum", value.FixedArguments[0].Type); - Assert.Equal((byte)1, value.FixedArguments[0].Value); - break; - - case 46: // [Test((object)(UInt16Enum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.UInt16Enum", value.FixedArguments[0].Type); - Assert.Equal((ushort)2, value.FixedArguments[0].Value); - break; - - case 47: // [Test((object)(UInt32Enum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.UInt32Enum", value.FixedArguments[0].Type); - Assert.Equal((uint)3, value.FixedArguments[0].Value); - break; - - case 48: // [Test((object)(UInt64Enum.Value))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.UInt64Enum", value.FixedArguments[0].Type); - Assert.Equal((ulong)4, value.FixedArguments[0].Value); - break; - - case 49: // [Test((object)(new string[] { }))] - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string[]", value.FixedArguments[0].Type); - Assert.Empty((ImmutableArray>)value.FixedArguments[0].Value); - break; - - case 50: // [Test((object)(new string[] { "x", "y", "z", null }))] - { - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string[]", value.FixedArguments[0].Type); - var strArray = (ImmutableArray>)value.FixedArguments[0].Value; - Assert.Equal(4, strArray.Length); - break; - } - - case 51: // [Test((object)(new Int32Enum[] { Int32Enum.Value }))] - { - Assert.Equal(1, value.FixedArguments.Length); - Assert.StartsWith("CustomAttributeDecoderTests.Int32Enum[]", value.FixedArguments[0].Type); - var int32EnumArray = (ImmutableArray>)value.FixedArguments[0].Value; - Assert.Equal(1, int32EnumArray.Length); - Assert.Equal(-3, int32EnumArray[0].Value); - break; - } - - case 52: // [Test(new object[] { ... })] - { - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("object[]", value.FixedArguments[0].Type); - var objArray = (ImmutableArray>)value.FixedArguments[0].Value; - Assert.Equal(25, objArray.Length); - Assert.Equal("string", objArray[0].Value); - Assert.Equal((sbyte)-1, objArray[1].Value); - Assert.Equal((short)-2, objArray[2].Value); - Assert.Equal(-4, objArray[3].Value); - Assert.Equal((long)-8, objArray[4].Value); - Assert.Equal((byte)1, objArray[9].Value); - Assert.Equal((ushort)2, objArray[10].Value); - Assert.Equal((uint)4, objArray[11].Value); - Assert.Equal(true, objArray[12].Value); - Assert.Equal(false, objArray[13].Value); - Assert.Contains("System.String", (string)objArray[14].Value); - break; - } - - case 53: // [Test(StringField = "string")] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal(CustomAttributeNamedArgumentKind.Field, value.NamedArguments[0].Kind); - Assert.Equal("StringField", value.NamedArguments[0].Name); - Assert.Equal("string", value.NamedArguments[0].Type); - Assert.Equal("string", value.NamedArguments[0].Value); - break; - - case 54: // [Test(SByteField = -1)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("SByteField", value.NamedArguments[0].Name); - Assert.Equal("int8", value.NamedArguments[0].Type); - Assert.Equal((sbyte)-1, value.NamedArguments[0].Value); - break; - - case 55: // [Test(Int16Field = -2)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("Int16Field", value.NamedArguments[0].Name); - Assert.Equal("int16", value.NamedArguments[0].Type); - Assert.Equal((short)-2, value.NamedArguments[0].Value); - break; - - case 56: // [Test(Int32Field = -4)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("Int32Field", value.NamedArguments[0].Name); - Assert.Equal("int32", value.NamedArguments[0].Type); - Assert.Equal(-4, value.NamedArguments[0].Value); - break; - - case 57: // [Test(Int64Field = -8)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("Int64Field", value.NamedArguments[0].Name); - Assert.Equal("int64", value.NamedArguments[0].Type); - Assert.Equal((long)-8, value.NamedArguments[0].Value); - break; - - case 58: // [Test(SByteField = -1)] duplicate - Assert.Equal("int8", value.NamedArguments[0].Type); - Assert.Equal((sbyte)-1, value.NamedArguments[0].Value); - break; - - case 59: // [Test(Int16Field = -2)] duplicate - Assert.Equal("int16", value.NamedArguments[0].Type); - Assert.Equal((short)-2, value.NamedArguments[0].Value); - break; - - case 60: // [Test(Int32Field = -4)] duplicate - Assert.Equal("int32", value.NamedArguments[0].Type); - Assert.Equal(-4, value.NamedArguments[0].Value); - break; - - case 61: // [Test(Int64Field = -8)] duplicate - Assert.Equal("int64", value.NamedArguments[0].Type); - Assert.Equal((long)-8, value.NamedArguments[0].Value); - break; - - case 62: // [Test(ByteField = 1)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("ByteField", value.NamedArguments[0].Name); - Assert.Equal("uint8", value.NamedArguments[0].Type); - Assert.Equal((byte)1, value.NamedArguments[0].Value); - break; - - case 63: // [Test(UInt16Field = 2)] - Assert.Empty(value.FixedArguments); - Assert.Equal("UInt16Field", value.NamedArguments[0].Name); - Assert.Equal("uint16", value.NamedArguments[0].Type); - Assert.Equal((ushort)2, value.NamedArguments[0].Value); - break; - - case 64: // [Test(UInt32Field = 4)] - Assert.Empty(value.FixedArguments); - Assert.Equal("UInt32Field", value.NamedArguments[0].Name); - Assert.Equal("uint32", value.NamedArguments[0].Type); - Assert.Equal((uint)4, value.NamedArguments[0].Value); - break; - - case 65: // [Test(UInt64Field = 8)] - Assert.Empty(value.FixedArguments); - Assert.Equal("UInt64Field", value.NamedArguments[0].Name); - Assert.Equal("uint64", value.NamedArguments[0].Type); - Assert.Equal((ulong)8, value.NamedArguments[0].Value); - break; - - case 66: // [Test(BooleanField = true)] - Assert.Empty(value.FixedArguments); - Assert.Equal("BooleanField", value.NamedArguments[0].Name); - Assert.Equal("bool", value.NamedArguments[0].Type); - Assert.Equal(true, value.NamedArguments[0].Value); - break; - - case 67: // [Test(BooleanField = false)] - Assert.Empty(value.FixedArguments); - Assert.Equal("BooleanField", value.NamedArguments[0].Name); - Assert.Equal("bool", value.NamedArguments[0].Type); - Assert.Equal(false, value.NamedArguments[0].Value); - break; - - case 68: // [Test(TypeField = typeof(string))] - Assert.Empty(value.FixedArguments); - Assert.Equal("TypeField", value.NamedArguments[0].Name); - Assert.Equal(provider.GetSystemType(), value.NamedArguments[0].Type); - Assert.Contains("System.String", (string)value.NamedArguments[0].Value); - break; - - case 69: // [Test(SByteEnumField = SByteEnum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("SByteEnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.SByteEnum", value.NamedArguments[0].Type); - Assert.Equal((sbyte)-1, value.NamedArguments[0].Value); - break; - - case 70: // [Test(Int16EnumField = Int16Enum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("Int16EnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.Int16Enum", value.NamedArguments[0].Type); - Assert.Equal((short)-2, value.NamedArguments[0].Value); - break; - - case 71: // [Test(Int32EnumField = Int32Enum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("Int32EnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.Int32Enum", value.NamedArguments[0].Type); - Assert.Equal(-3, value.NamedArguments[0].Value); - break; - - case 72: // [Test(Int64EnumField = Int64Enum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("Int64EnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.Int64Enum", value.NamedArguments[0].Type); - Assert.Equal((long)-4, value.NamedArguments[0].Value); - break; - - case 73: // [Test(ByteEnumField = ByteEnum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("ByteEnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.ByteEnum", value.NamedArguments[0].Type); - Assert.Equal((byte)1, value.NamedArguments[0].Value); - break; - - case 74: // [Test(UInt16EnumField = UInt16Enum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("UInt16EnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.UInt16Enum", value.NamedArguments[0].Type); - Assert.Equal((ushort)2, value.NamedArguments[0].Value); - break; - - case 75: // [Test(UInt32EnumField = UInt32Enum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("UInt32EnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.UInt32Enum", value.NamedArguments[0].Type); - Assert.Equal((uint)3, value.NamedArguments[0].Value); - break; - - case 76: // [Test(UInt64EnumField = UInt64Enum.Value)] - Assert.Empty(value.FixedArguments); - Assert.Equal("UInt64EnumField", value.NamedArguments[0].Name); - Assert.Equal("CustomAttributeDecoderTests.UInt64Enum", value.NamedArguments[0].Type); - Assert.Equal((ulong)4, value.NamedArguments[0].Value); - break; - - case 77: // [Test(new string[] { })] second occurrence - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string[]", value.FixedArguments[0].Type); - Assert.Empty((ImmutableArray>)value.FixedArguments[0].Value); - break; - - case 78: // [Test(new string[] { "x", "y", "z", null })] second occurrence - { - Assert.Equal(1, value.FixedArguments.Length); - Assert.Equal("string[]", value.FixedArguments[0].Type); - var strArray = (ImmutableArray>)value.FixedArguments[0].Value; - Assert.Equal(4, strArray.Length); - break; - } - - case 79: // [Test(ObjectField = null)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("ObjectField", value.NamedArguments[0].Name); - Assert.Equal("string", value.NamedArguments[0].Type); - Assert.Null(value.NamedArguments[0].Value); - break; - - case 80: // [Test(StringField = null)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("StringField", value.NamedArguments[0].Name); - Assert.Equal("string", value.NamedArguments[0].Type); - Assert.Null(value.NamedArguments[0].Value); - break; - - case 81: // [Test(Int32ArrayProperty = null)] - Assert.Empty(value.FixedArguments); - Assert.Equal(1, value.NamedArguments.Length); - Assert.Equal("Int32ArrayProperty", value.NamedArguments[0].Name); - Assert.Equal("int32[]", value.NamedArguments[0].Type); - Assert.Null(value.NamedArguments[0].Value); + default: break; } } - - Assert.Equal(82, i); } }