From 2b7deb90191d60d88881b7caa8aacd2f9a5c2c51 Mon Sep 17 00:00:00 2001
From: smolchanovsky <smolchanovsky@gmail.com>
Date: Tue, 20 Dec 2022 12:56:28 +0300
Subject: [PATCH 1/5] Add parameters to allure report

---
 Allure.XUnit/AllureXunitHelper.cs | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/Allure.XUnit/AllureXunitHelper.cs b/Allure.XUnit/AllureXunitHelper.cs
index 05bc3b98..9d903752 100644
--- a/Allure.XUnit/AllureXunitHelper.cs
+++ b/Allure.XUnit/AllureXunitHelper.cs
@@ -59,7 +59,14 @@ public static void StartTestCase(ITestCaseMessage testCaseMessage)
                     Label.TestClass(testCase.TestMethod.TestClass.Class.Name),
                     Label.TestMethod(testCase.DisplayName),
                     Label.Package(testCase.TestMethod.TestClass.Class.Name)
-                }
+                },
+                parameters = testCase.TestMethod.Method.GetParameters()
+                    .Zip(testCase.TestMethodArguments ?? Array.Empty<object>(), (param, value) => new Parameter
+                    {
+                        name = param.Name,
+                        value = value?.ToString() ?? "null"
+                    })
+                    .ToList()
             };
             UpdateTestDataFromAttributes(testResults.TestResult, testCase);
             AllureLifecycle.Instance.StartTestCase(testResults.TestResultContainer.uuid, testResults.TestResult);

From 74c8a0f1e5d333a2a120af15bf1f2c188f4351ee Mon Sep 17 00:00:00 2001
From: smolchanovsky <smolchanovsky@gmail.com>
Date: Tue, 20 Dec 2022 12:56:56 +0300
Subject: [PATCH 2/5] Add allure attributes for names

---
 Allure.XUnit/AllureNameFormatter.cs           | 24 +++++++++++++++++++
 Allure.XUnit/AllureXunitHelper.cs             | 11 +++++++--
 .../Attributes/AllureFullNameAttribute.cs     | 22 +++++++++++++++++
 .../Attributes/AllureNameAttribute.cs         | 22 +++++++++++++++++
 4 files changed, 77 insertions(+), 2 deletions(-)
 create mode 100644 Allure.XUnit/AllureNameFormatter.cs
 create mode 100644 Allure.XUnit/Attributes/AllureFullNameAttribute.cs
 create mode 100644 Allure.XUnit/Attributes/AllureNameAttribute.cs

diff --git a/Allure.XUnit/AllureNameFormatter.cs b/Allure.XUnit/AllureNameFormatter.cs
new file mode 100644
index 00000000..b8e32d28
--- /dev/null
+++ b/Allure.XUnit/AllureNameFormatter.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Linq;
+using Allure.Net.Commons;
+
+namespace Allure.XUnit
+{
+    public class AllureNameFormatter
+    {
+        private static readonly Func<string, TestResult, string>[] Formatters = {
+            (nameTemplate, testResult) => nameTemplate.Replace(
+                oldValue: "{params}",
+                newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}"))),
+            
+            (nameTemplate, testResult) => nameTemplate.Replace(
+                oldValue: "{args}",
+                newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}: {x.value}"))),
+        };
+        
+        public static string Format(string nameTemplate, TestResult testResult)
+        {
+            return Formatters.Aggregate(nameTemplate, (current, formatter) => formatter(current, testResult));
+        }
+    }
+}
\ No newline at end of file
diff --git a/Allure.XUnit/AllureXunitHelper.cs b/Allure.XUnit/AllureXunitHelper.cs
index 9d903752..ee487bc2 100644
--- a/Allure.XUnit/AllureXunitHelper.cs
+++ b/Allure.XUnit/AllureXunitHelper.cs
@@ -226,11 +226,18 @@ private static void UpdateTestDataFromAttributes(TestResult testResult, ITestCas
                         testResult.labels.AddDistinct("story", storyAttribute.Stories, storyAttribute.Overwrite);
                         break;
 
+                    case AllureNameAttribute nameAttribute:
+                        nameAttribute.UpdateTestResult(testResult);
+                        break;
+                    
+                    case AllureFullNameAttribute fullNameAttribute:
+                        fullNameAttribute.UpdateTestResult(testResult);
+                        break;
+                    
                     case AllureDescriptionAttribute descriptionAttribute:
                         testResult.description = descriptionAttribute.Description;
                         break;
-
-
+                    
                     case AllureIdAttribute allureIdAttribute:
                         var allureIdLabel = new Label {name = "ALLURE_ID", value = allureIdAttribute.AllureId};
                         testResult.labels.AddDistinct(allureIdLabel, false);
diff --git a/Allure.XUnit/Attributes/AllureFullNameAttribute.cs b/Allure.XUnit/Attributes/AllureFullNameAttribute.cs
new file mode 100644
index 00000000..8f270ea4
--- /dev/null
+++ b/Allure.XUnit/Attributes/AllureFullNameAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using Allure.Net.Commons;
+using Allure.XUnit;
+
+namespace Allure.Xunit.Attributes
+{
+    [AttributeUsage(AttributeTargets.Method)]
+    public class AllureFullNameAttribute : Attribute, IAllureInfo
+    {
+        public AllureFullNameAttribute(string fullName)
+        {
+            FullName = fullName ?? throw new ArgumentNullException(nameof(fullName));
+        }
+        
+        internal string FullName { get; }
+        
+        internal void UpdateTestResult(TestResult testResult)
+        {
+            testResult.fullName = AllureNameFormatter.Format(FullName, testResult);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Allure.XUnit/Attributes/AllureNameAttribute.cs b/Allure.XUnit/Attributes/AllureNameAttribute.cs
new file mode 100644
index 00000000..4ebdcb8b
--- /dev/null
+++ b/Allure.XUnit/Attributes/AllureNameAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+using Allure.Net.Commons;
+using Allure.XUnit;
+
+namespace Allure.Xunit.Attributes
+{
+    [AttributeUsage(AttributeTargets.Method)]
+    public class AllureNameAttribute : Attribute, IAllureInfo
+    {
+        public AllureNameAttribute(string name)
+        {
+            Name = name ?? throw new ArgumentNullException(nameof(name));
+        }
+
+        internal string Name { get; }
+        
+        internal void UpdateTestResult(TestResult testResult)
+        {
+            testResult.name = AllureNameFormatter.Format(Name, testResult);
+        }
+    }
+}
\ No newline at end of file

From a6b79c769e8b08b04e906deac4ca7f462a479b01 Mon Sep 17 00:00:00 2001
From: smolchanovsky <smolchanovsky@gmail.com>
Date: Tue, 20 Dec 2022 12:57:15 +0300
Subject: [PATCH 3/5] Add example with random data

---
 .../ExampleParameterisedTests.cs              | 14 +++++++++++++
 .../TestData/TestDataGenerators.cs            | 20 +++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/Allure.XUnit.Examples/ExampleParameterisedTests.cs b/Allure.XUnit.Examples/ExampleParameterisedTests.cs
index 277f3f08..7fbbe33e 100644
--- a/Allure.XUnit.Examples/ExampleParameterisedTests.cs
+++ b/Allure.XUnit.Examples/ExampleParameterisedTests.cs
@@ -59,5 +59,19 @@ public void TestTheoryWithMemberData(MyTestClass a, MyTestClass b)
         {
             Assert.Equal(a.Test, b.Test);
         }
+        
+        [AllureXunitTheory]
+        [AllureName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))]
+        [AllureFullName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))]
+        [AllureParentSuite("AllTests")]
+        [AllureSuite("Test AllureXunitTheory")]
+        [AllureSubSuite("Test Test MemberData with random data")]
+        [MemberData(nameof(TestDataGenerators.RandomData), MemberType = typeof(TestDataGenerators))]
+        public void TestTheoryWithMemberDataThatReturnsRandomData(int value1, int value2, int expected)
+        {
+            var result = value1 + value2;
+
+            Assert.Equal(expected, result);
+        }
     }
 }
diff --git a/Allure.XUnit.Examples/TestData/TestDataGenerators.cs b/Allure.XUnit.Examples/TestData/TestDataGenerators.cs
index e77d1bbf..7ce47ff9 100644
--- a/Allure.XUnit.Examples/TestData/TestDataGenerators.cs
+++ b/Allure.XUnit.Examples/TestData/TestDataGenerators.cs
@@ -1,9 +1,14 @@
+using System;
 using System.Collections.Generic;
+using System.Linq;
 
 namespace Allure.XUnit.Examples.TestData
 {
     public class TestDataGenerators
     {
+        private static readonly object SyncLock = new();
+        private static readonly Random Random = new();
+        
         public static IEnumerable<object[]> Data =>
             new List<object[]>
             {
@@ -21,5 +26,20 @@ public class TestDataGenerators
             new object[] {new MyTestClass {Test = 10}, new MyTestClass {Test = 11}}
         };
 
+        public static IEnumerable<object[]> RandomData =>
+            Enumerable.Range(0, 4).Select(_ => CreateTestData());
+
+        private static object[] CreateTestData()
+        {
+            return new object[] {GetRandomNumber(), GetRandomNumber(), GetRandomNumber()};
+        }
+
+        private static int GetRandomNumber()
+        {
+            lock(SyncLock) 
+            {
+                return Random.Next();
+            }
+        }
     }
 }
\ No newline at end of file

From 8c1705e645cd867222c73a48c5986b27f9344802 Mon Sep 17 00:00:00 2001
From: Aleksandr Piskunov <residentman@mail.ru>
Date: Sun, 12 Mar 2023 20:22:28 +0300
Subject: [PATCH 4/5] Delete redundant attributes. Add TypeExtensions to get
 readable generic type argument name. Add methods to build name and full name
 for a test.

---
 .../ExampleParameterisedTests.cs              | 30 ++++++--
 Allure.XUnit/AllureXunitHelper.cs             | 45 +++++++++---
 .../Attributes/AllureFullNameAttribute.cs     | 22 ------
 .../Attributes/AllureNameAttribute.cs         | 22 ------
 Allure.XUnit/TypeExtensions.cs                | 73 +++++++++++++++++++
 5 files changed, 129 insertions(+), 63 deletions(-)
 delete mode 100644 Allure.XUnit/Attributes/AllureFullNameAttribute.cs
 delete mode 100644 Allure.XUnit/Attributes/AllureNameAttribute.cs
 create mode 100644 Allure.XUnit/TypeExtensions.cs

diff --git a/Allure.XUnit.Examples/ExampleParameterisedTests.cs b/Allure.XUnit.Examples/ExampleParameterisedTests.cs
index 7fbbe33e..131bfc00 100644
--- a/Allure.XUnit.Examples/ExampleParameterisedTests.cs
+++ b/Allure.XUnit.Examples/ExampleParameterisedTests.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 using System.IO;
 using Allure.Xunit.Attributes;
 using Allure.XUnit.Examples.TestData;
@@ -22,10 +23,10 @@ public ExampleParameterisedTests()
         public void TestTheoryWithMemberDataProperty(int value1, int value2, int expected)
         {
             var result = value1 + value2;
-
+        
             Assert.Equal(expected, result);
         }
-
+        
         [AllureXunitTheory]
         [AllureParentSuite("AllTests")]
         [AllureSuite("Test AllureXunitTheory")]
@@ -34,10 +35,10 @@ public void TestTheoryWithMemberDataProperty(int value1, int value2, int expecte
         public void TestTheoryWithClassData(int value1, int value2, int expected)
         {
             var result = value1 + value2;
-
+        
             Assert.Equal(expected, result);
         }
-
+        
         [AllureXunitTheory]
         [AllureParentSuite("AllTests")]
         [AllureSuite("Test AllureXunitTheory")]
@@ -61,11 +62,9 @@ public void TestTheoryWithMemberData(MyTestClass a, MyTestClass b)
         }
         
         [AllureXunitTheory]
-        [AllureName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))]
-        [AllureFullName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))]
         [AllureParentSuite("AllTests")]
         [AllureSuite("Test AllureXunitTheory")]
-        [AllureSubSuite("Test Test MemberData with random data")]
+        [AllureSubSuite("Test test MemberData with random data")]
         [MemberData(nameof(TestDataGenerators.RandomData), MemberType = typeof(TestDataGenerators))]
         public void TestTheoryWithMemberDataThatReturnsRandomData(int value1, int value2, int expected)
         {
@@ -73,5 +72,20 @@ public void TestTheoryWithMemberDataThatReturnsRandomData(int value1, int value2
 
             Assert.Equal(expected, result);
         }
+
+        [AllureXunitTheory]
+        [AllureParentSuite("AllTests")]
+        [AllureSuite("Test AllureXunitTheory")]
+        [AllureSubSuite("Test test with generic arguments")]
+        [InlineData(5, 10)]
+        [InlineData(10, 20)]
+        public void TestTheoryWithInlineDataThatAcceptsGenericArgument(int? value, int? expected)
+        {
+            var result = value * 2;
+
+            Debug.Assert(expected != null, nameof(expected) + " != null");
+            Debug.Assert(result != null, nameof(result) + " != null");
+            Assert.Equal(expected.Value, result.Value);
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/Allure.XUnit/AllureXunitHelper.cs b/Allure.XUnit/AllureXunitHelper.cs
index ee487bc2..64fd8336 100644
--- a/Allure.XUnit/AllureXunitHelper.cs
+++ b/Allure.XUnit/AllureXunitHelper.cs
@@ -5,8 +5,8 @@
 using Allure.Net.Commons;
 using Allure.XUnit;
 using Allure.Xunit.Attributes;
+using Xunit;
 using Xunit.Abstractions;
-using Xunit.Sdk;
 
 namespace Allure.Xunit
 {
@@ -49,9 +49,9 @@ public static void StartTestCase(ITestCaseMessage testCaseMessage)
             testResults.TestResult = new()
             {
                 uuid = uuid,
-                name = testCase.DisplayName,
+                name = BuildName(testCase),
                 historyId = testCase.DisplayName,
-                fullName = testCase.DisplayName,
+                fullName = BuildFullName(testCase),
                 labels = new()
                 {
                     Label.Thread(),
@@ -226,14 +226,6 @@ private static void UpdateTestDataFromAttributes(TestResult testResult, ITestCas
                         testResult.labels.AddDistinct("story", storyAttribute.Stories, storyAttribute.Overwrite);
                         break;
 
-                    case AllureNameAttribute nameAttribute:
-                        nameAttribute.UpdateTestResult(testResult);
-                        break;
-                    
-                    case AllureFullNameAttribute fullNameAttribute:
-                        fullNameAttribute.UpdateTestResult(testResult);
-                        break;
-                    
                     case AllureDescriptionAttribute descriptionAttribute:
                         testResult.description = descriptionAttribute.Description;
                         break;
@@ -254,5 +246,36 @@ private static void UpdateTestDataFromAttributes(TestResult testResult, ITestCas
                 }
             }
         }
+
+        private static string BuildName(ITestCase testCase)
+        {
+            var factAttribute = testCase.TestMethod.Method.GetCustomAttributes(typeof(FactAttribute)).SingleOrDefault();
+            if (factAttribute is null)
+            {
+                return BuildFullName(testCase);
+            }
+
+            var displayName = factAttribute.GetNamedArgument<string>("DisplayName");
+            if (string.IsNullOrWhiteSpace(displayName))
+            {
+                return BuildFullName(testCase);
+            }
+            
+            return displayName;
+        }
+        
+        private static string BuildFullName(ITestCase testCase)
+        {
+            var parameters = testCase.TestMethod.Method
+                .GetParameters()
+                .Select(parameter =>
+                    $"{parameter.ParameterType.ToRuntimeType().GetFullFormattedTypeName()} {parameter.Name}")
+                .ToArray();
+            var parametersSegment = parameters.Any()
+                ? $"({string.Join(", ", parameters)})"
+                : string.Empty;
+
+            return $"{testCase.TestMethod.TestClass.Class.Name}.{testCase.TestMethod.Method.Name}{parametersSegment}";
+        }
     }
 }
\ No newline at end of file
diff --git a/Allure.XUnit/Attributes/AllureFullNameAttribute.cs b/Allure.XUnit/Attributes/AllureFullNameAttribute.cs
deleted file mode 100644
index 8f270ea4..00000000
--- a/Allure.XUnit/Attributes/AllureFullNameAttribute.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using Allure.Net.Commons;
-using Allure.XUnit;
-
-namespace Allure.Xunit.Attributes
-{
-    [AttributeUsage(AttributeTargets.Method)]
-    public class AllureFullNameAttribute : Attribute, IAllureInfo
-    {
-        public AllureFullNameAttribute(string fullName)
-        {
-            FullName = fullName ?? throw new ArgumentNullException(nameof(fullName));
-        }
-        
-        internal string FullName { get; }
-        
-        internal void UpdateTestResult(TestResult testResult)
-        {
-            testResult.fullName = AllureNameFormatter.Format(FullName, testResult);
-        }
-    }
-}
\ No newline at end of file
diff --git a/Allure.XUnit/Attributes/AllureNameAttribute.cs b/Allure.XUnit/Attributes/AllureNameAttribute.cs
deleted file mode 100644
index 4ebdcb8b..00000000
--- a/Allure.XUnit/Attributes/AllureNameAttribute.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using Allure.Net.Commons;
-using Allure.XUnit;
-
-namespace Allure.Xunit.Attributes
-{
-    [AttributeUsage(AttributeTargets.Method)]
-    public class AllureNameAttribute : Attribute, IAllureInfo
-    {
-        public AllureNameAttribute(string name)
-        {
-            Name = name ?? throw new ArgumentNullException(nameof(name));
-        }
-
-        internal string Name { get; }
-        
-        internal void UpdateTestResult(TestResult testResult)
-        {
-            testResult.name = AllureNameFormatter.Format(Name, testResult);
-        }
-    }
-}
\ No newline at end of file
diff --git a/Allure.XUnit/TypeExtensions.cs b/Allure.XUnit/TypeExtensions.cs
new file mode 100644
index 00000000..4951c325
--- /dev/null
+++ b/Allure.XUnit/TypeExtensions.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace Allure.XUnit
+{
+    internal static class TypeExtensions
+    {
+        public static string GetFullFormattedTypeName(this Type type, Func<string, string> namingRule = null)
+        {
+            namingRule ??= typeName => typeName;
+            if (!type.IsGenericType)
+            {
+                return namingRule.Invoke(type.Name);
+            }
+
+            var nameBuilder = new StringBuilder();
+            BuildGenericTypeName(type, nameBuilder, namingRule);
+            return nameBuilder.ToString();
+        }
+
+        private static void BuildGenericTypeName(Type type, StringBuilder nameBuilder, Func<string, string> namingRule)
+        {
+            if (!type.IsGenericType)
+            {
+                return;
+            }
+
+            StartGenericType(type, nameBuilder, namingRule);
+            for (var index = 0; index < type.GenericTypeArguments.Length; index++)
+            {
+                var genericTypeArgument = type.GenericTypeArguments[index];
+                if (genericTypeArgument.IsGenericType)
+                {
+                    BuildGenericTypeName(genericTypeArgument, nameBuilder, namingRule);
+                    AppendDelimiterIfNeeded(type.GenericTypeArguments, nameBuilder, index);
+                    continue;
+                }
+
+                nameBuilder.Append(namingRule.Invoke(genericTypeArgument.Name));
+                AppendDelimiterIfNeeded(type.GenericTypeArguments, nameBuilder, index);
+            }
+
+            EndGenericType(nameBuilder);
+        }
+
+        private static void StartGenericType(
+            MemberInfo type,
+            StringBuilder nameBuilder,
+            Func<string, string> namingRule)
+        {
+            var typeName = namingRule.Invoke(type.Name.Substring(0, type.Name.IndexOf("`", StringComparison.Ordinal)));
+            nameBuilder.Append(typeName).Append('<');
+        }
+
+        private static void EndGenericType(StringBuilder nameBuilder)
+        {
+            nameBuilder.Append('>');
+        }
+
+        private static void AppendDelimiterIfNeeded(
+            IReadOnlyCollection<Type> genericTypeArguments,
+            StringBuilder nameBuilder,
+            int index)
+        {
+            if (genericTypeArguments.Count - index != 1)
+            {
+                nameBuilder.Append(", ");
+            }
+        }
+    }
+}
\ No newline at end of file

From df71b0a947d351ce0b2431dfae1a0ae304e505cc Mon Sep 17 00:00:00 2001
From: Aleksandr Piskunov <residentman@mail.ru>
Date: Mon, 13 Mar 2023 13:13:05 +0300
Subject: [PATCH 5/5] Delete redundant file.

---
 Allure.XUnit/AllureNameFormatter.cs | 24 ------------------------
 1 file changed, 24 deletions(-)
 delete mode 100644 Allure.XUnit/AllureNameFormatter.cs

diff --git a/Allure.XUnit/AllureNameFormatter.cs b/Allure.XUnit/AllureNameFormatter.cs
deleted file mode 100644
index b8e32d28..00000000
--- a/Allure.XUnit/AllureNameFormatter.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Linq;
-using Allure.Net.Commons;
-
-namespace Allure.XUnit
-{
-    public class AllureNameFormatter
-    {
-        private static readonly Func<string, TestResult, string>[] Formatters = {
-            (nameTemplate, testResult) => nameTemplate.Replace(
-                oldValue: "{params}",
-                newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}"))),
-            
-            (nameTemplate, testResult) => nameTemplate.Replace(
-                oldValue: "{args}",
-                newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}: {x.value}"))),
-        };
-        
-        public static string Format(string nameTemplate, TestResult testResult)
-        {
-            return Formatters.Aggregate(nameTemplate, (current, formatter) => formatter(current, testResult));
-        }
-    }
-}
\ No newline at end of file
