diff --git a/Allure.NUnit.Examples/AllureStepArgumentFormattingTest.cs b/Allure.NUnit.Examples/AllureStepArgumentFormattingTest.cs new file mode 100644 index 00000000..154bb9d9 --- /dev/null +++ b/Allure.NUnit.Examples/AllureStepArgumentFormattingTest.cs @@ -0,0 +1,40 @@ +using System; +using Allure.Net.Commons; +using NUnit.Allure.Attributes; +using NUnit.Framework; + +namespace Allure.NUnit.Examples; + +[AllureSuite("Tests - Steps")] +public class AllureStepArgumentFormattingTest : BaseTest +{ + [AllureStep("Step with params #{0}")] + private static void StepWithCustomClassParams(CustomClass firstParam) + { + Console.WriteLine(firstParam); + } + + [OneTimeSetUp] + public static void OneTimeSetUp() + { + AllureLifecycle.Instance.AddTypeFormatter(new CustomClassFormatter()); + } + + [Test] + [AllureName("Test with custom formatting for step argument")] + public void StepWithCustomParamTest() + { + StepWithCustomClassParams(new CustomClass { I = 10, S = "string" }); + } + + private class CustomClass + { + public int I { get; init; } + public string S { get; init; } + } + + private class CustomClassFormatter : TypeFormatter + { + public override string Format(CustomClass value) => $"___{value.S} + {value.I}___"; + } +} \ No newline at end of file diff --git a/Allure.NUnit/Core/Steps/AllureStepAspect.cs b/Allure.NUnit/Core/Steps/AllureStepAspect.cs index 2d52372c..c553ebbc 100644 --- a/Allure.NUnit/Core/Steps/AllureStepAspect.cs +++ b/Allure.NUnit/Core/Steps/AllureStepAspect.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using Allure.Net.Commons; using AspectInjector.Broker; @@ -16,12 +17,19 @@ public object WrapStep( [Argument(Source.Arguments)] object[] arguments, [Argument(Source.Target)] Func method) { + var parameterInfos = methodBase.GetParameters(); var stepName = methodBase.GetCustomAttribute().StepName; + var typeFormatters = AllureLifecycle.Instance.TypeFormatters; + for (var i = 0; i < arguments.Length; i++) { - - stepName = stepName?.Replace("{" + i + "}", arguments[i]?.ToString() ?? "null"); + var parameterType = parameterInfos.ElementAtOrDefault(i)?.ParameterType; + var typeFormatter = parameterType is null || !typeFormatters.ContainsKey(parameterType) + ? null + : typeFormatters[parameterType]; + var formattedArgument = typeFormatter?.Format(arguments[i]) ?? arguments[i]?.ToString() ?? "null"; + stepName = stepName?.Replace("{" + i + "}", formattedArgument); } var stepResult = string.IsNullOrEmpty(stepName) diff --git a/Allure.Net.Commons/AllureLifecycle.cs b/Allure.Net.Commons/AllureLifecycle.cs index 91ba8ed9..56aa2a69 100644 --- a/Allure.Net.Commons/AllureLifecycle.cs +++ b/Allure.Net.Commons/AllureLifecycle.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Runtime.CompilerServices; using System.Threading; @@ -15,6 +17,11 @@ namespace Allure.Net.Commons { public class AllureLifecycle { + private readonly Dictionary typeFormatters = new(); + + public IReadOnlyDictionary TypeFormatters => + new ReadOnlyDictionary(typeFormatters); + private static readonly object Lockobj = new(); private static AllureLifecycle instance; private readonly AllureStorage storage; @@ -60,6 +67,12 @@ public static AllureLifecycle Instance } } + public void AddTypeFormatter(TypeFormatter typeFormatter) => + AddTypeFormatterImpl(typeof(T), typeFormatter); + + private void AddTypeFormatterImpl(Type type, ITypeFormatter formatter) => + typeFormatters[type] = formatter; + #region TestContainer public virtual AllureLifecycle StartTestContainer(TestResultContainer container) diff --git a/Allure.Net.Commons/TypeFormatter.cs b/Allure.Net.Commons/TypeFormatter.cs new file mode 100644 index 00000000..7e7b4a30 --- /dev/null +++ b/Allure.Net.Commons/TypeFormatter.cs @@ -0,0 +1,16 @@ +namespace Allure.Net.Commons; + +public interface ITypeFormatter +{ + string Format(object value); +} + +public abstract class TypeFormatter : ITypeFormatter +{ + public abstract string Format(T value); + + string ITypeFormatter.Format(object value) + { + return Format((T)value); + } +} \ No newline at end of file