Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ExecutableAttribute on methods when using the fluent interface #284

Open
MovGP0 opened this issue Oct 18, 2022 · 0 comments

Comments

@MovGP0
Copy link

MovGP0 commented Oct 18, 2022

When using the fluent interface the ExecutableAttributes (Given, When, Then) are not supported.

Here is some example code to illustrate how it might be implemented:

void Main()
{
	var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
	var bez = "bez";
	new Foo().Given(s => s.BarAsync("let", bez, cts.Token));
}

public sealed class Foo
{
	[When("foo {0} {1} baz")]
	public ValueTask<int> BarAsync(string let, string bar, CancellationToken cancellationToken)
	{
		return ValueTask.FromResult(0);
	}
}

public static class TestExtensions
{
	private static IEnumerable<Type> GetParentTypes(this Type type)
	{
		yield return type;
		if (type.BaseType == null) yield break;
		
		yield return type.BaseType;
		
		foreach (Type b in type.BaseType.GetParentTypes())
		{
			yield return b;
		}		
	}

	private static object GetValue(this MemberInfo memberInfo, object forObject)
	{
		switch (memberInfo.MemberType)
		{
			case MemberTypes.Field:
				return ((FieldInfo)memberInfo).GetValue(forObject);
			case MemberTypes.Property:
				return ((PropertyInfo)memberInfo).GetValue(forObject);
			default:
				throw new NotImplementedException();
		}
	}

	public static void Given<T>(this T model, Expression<Func<T, ValueTask<int>>> expression)
		where T:class
	{
		var argumentProvider = (expression.Body as MethodCallExpression);
		
		var formatString = argumentProvider
			.Method
			.CustomAttributes
			.Where(cad => cad.AttributeType.GetParentTypes().Any(t => t == typeof(ExecutableAttribute)))
			.Select(c => (ExecutableAttribute)c.Constructor.Invoke(c.ConstructorArguments.Select(c => c.Value).ToArray()))
			.Select(e => e.StepTitle)
			.FirstOrDefault();

		for (int i = 0; i < argumentProvider.Arguments.Count; i++)
		{
			if (!formatString.Contains("{" + i + "}")) continue;
			
			var argumentExpression = argumentProvider.Arguments[i];
			if (argumentExpression.NodeType == ExpressionType.Constant)
			{
				var str = argumentExpression.ToString();
				formatString = formatString.Replace("{" + i + "}", str);
			}
			else if(argumentExpression is MemberExpression me)
			{
				if (me.Expression is ConstantExpression ce)
				{
					var value = me.Member.GetValue(ce.Value)?.ToString();
					formatString = formatString.Replace("{" + i + "}", value);
				}
			}
		}
		
		Console.WriteLine(formatString); // foo "let" bez baz
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant