Skip to content

Commit 50787d2

Browse files
committed
First attempt
1 parent f8b32b1 commit 50787d2

File tree

3 files changed

+61
-217
lines changed

3 files changed

+61
-217
lines changed

TestStack.BDDfy/Processors/ScenarioExecutor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public void InitializeScenario()
2828

2929
var possibleTargets = memberInfos
3030
.OfType<FieldInfo>()
31-
.Select(f => new StepArgument(f, _scenario.TestObject))
32-
.Union(memberInfos.OfType<PropertyInfo>().Select(m => new StepArgument(m, _scenario.TestObject)))
31+
.Select(f => new StepArgument(f, () => _scenario.TestObject))
32+
.Union(memberInfos.OfType<PropertyInfo>().Select(m => new StepArgument(m, () => _scenario.TestObject)))
3333
.Union(_scenario.Steps.SelectMany(s=>s.Arguments))
3434
.ToArray();
3535

Lines changed: 32 additions & 209 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections;
32
using System.Collections.Generic;
43
using System.Linq;
54
using System.Linq.Expressions;
@@ -20,231 +19,55 @@ public static IEnumerable<StepArgument> ExtractArguments<T>(this Expression<Acti
2019
if (methodCallExpression == null)
2120
throw new InvalidOperationException("Please provide a *method call* lambda expression.");
2221

23-
return ExtractArguments(methodCallExpression, value, false);
22+
return new ArgumentExtractorVisitor().ExtractArguments(expression, value);
2423
}
2524

2625
public static IEnumerable<StepArgument> ExtractArguments<T>(this Expression<Func<T, Task>> expression, T value)
2726
{
28-
var lambdaExpression = expression as LambdaExpression;
29-
if (lambdaExpression == null)
30-
throw new InvalidOperationException("Please provide a lambda expression.");
31-
32-
var methodCallExpression = lambdaExpression.Body as MethodCallExpression;
33-
if (methodCallExpression == null)
34-
throw new InvalidOperationException("Please provide a *method call* lambda expression.");
35-
36-
return ExtractArguments(methodCallExpression, value, false);
37-
}
38-
39-
private static IEnumerable<StepArgument> ExtractArguments<T>(Expression expression, T value)
40-
{
41-
if (expression == null || expression is ParameterExpression)
42-
return new StepArgument[0];
43-
44-
var memberExpression = expression as MemberExpression;
45-
if (memberExpression != null)
46-
return new[] { ExtractArgument(memberExpression, value) };
47-
48-
var constantExpression = expression as ConstantExpression;
49-
if (constantExpression != null)
50-
return ExtractArguments(constantExpression, value);
51-
52-
var newArrayExpression = expression as NewArrayExpression;
53-
if (newArrayExpression != null)
54-
return ExtractArguments(newArrayExpression, value);
55-
56-
var newExpression = expression as NewExpression;
57-
if (newExpression != null)
58-
return ExtractArguments(newExpression, value);
59-
60-
var unaryExpression = expression as UnaryExpression;
61-
if (unaryExpression != null)
62-
return ExtractArguments(unaryExpression, value);
63-
64-
var methodCallExpression = expression as MethodCallExpression;
65-
if (methodCallExpression != null)
66-
return Invoke(methodCallExpression, ExtractArguments(methodCallExpression, value));
67-
68-
return new StepArgument[0];
69-
}
70-
71-
private static IEnumerable<StepArgument> Invoke(MethodCallExpression methodCallExpression, IEnumerable<StepArgument> args)
72-
{
73-
var constantExpression = methodCallExpression.Object as ConstantExpression;
74-
var stepArguments = args.ToArray();
75-
if (constantExpression != null)
76-
return new[] { new StepArgument(() => methodCallExpression.Method.Invoke(constantExpression.Value, stepArguments.Select(s => s.Value).ToArray())) };
77-
78-
return new[] { new StepArgument(() =>
79-
{
80-
var value = stepArguments.First().Value;
81-
var parameters = stepArguments.Skip(1).Select(s => s.Value).ToArray();
82-
return methodCallExpression.Method.Invoke(value, parameters);
83-
}) };
27+
return new ArgumentExtractorVisitor().ExtractArguments(expression, value);
8428
}
8529

86-
private static IEnumerable<StepArgument> ExtractArguments<T>(MethodCallExpression methodCallExpression, T value, bool extractArgsFromExpression = true)
30+
private class ArgumentExtractorVisitor : ExpressionVisitor
8731
{
88-
var constants = new List<StepArgument>();
89-
foreach (var arg in methodCallExpression.Arguments)
90-
{
91-
constants.AddRange(ExtractArguments(arg, value));
92-
}
32+
private List<StepArgument> _arguments;
9333

94-
if (extractArgsFromExpression)
34+
public IEnumerable<StepArgument> ExtractArguments(LambdaExpression methodCallExpression, object value)
9535
{
96-
constants.AddRange(ExtractArguments(methodCallExpression.Object, value));
36+
_arguments = new List<StepArgument>();
37+
Visit(methodCallExpression);
38+
return _arguments;
9739
}
9840

99-
return constants;
100-
}
101-
102-
private static IEnumerable<StepArgument> ExtractArguments<T>(UnaryExpression unaryExpression, T value)
103-
{
104-
return ExtractArguments(unaryExpression.Operand, value);
105-
}
106-
107-
private static IEnumerable<StepArgument> ExtractArguments<T>(NewExpression newExpression, T value)
108-
{
109-
var arguments = new List<StepArgument>();
110-
foreach (var argumentExpression in newExpression.Arguments)
41+
protected override Expression VisitMethodCall(MethodCallExpression node)
11142
{
112-
arguments.AddRange(ExtractArguments(argumentExpression, value));
113-
}
114-
115-
return new[] { new StepArgument(() => newExpression.Constructor.Invoke(arguments.Select(o => o.Value).ToArray())) };
116-
}
117-
118-
private static IEnumerable<StepArgument> ExtractArguments<T>(NewArrayExpression newArrayExpression, T value)
119-
{
120-
Type type = newArrayExpression.Type.GetElementType();
121-
if (type is IConvertible)
122-
return ExtractConvertibleTypeArrayConstants(newArrayExpression, type);
123-
124-
return ExtractNonConvertibleArrayConstants(newArrayExpression, type, value);
125-
}
126-
127-
private static IEnumerable<StepArgument> ExtractNonConvertibleArrayConstants<T>(NewArrayExpression newArrayExpression, Type type, T value)
128-
{
129-
var arrayElements = CreateList(type);
130-
foreach (var arrayElementExpression in newArrayExpression.Expressions)
131-
{
132-
object arrayElement;
133-
134-
var constantExpression = arrayElementExpression as ConstantExpression;
135-
if (constantExpression != null)
136-
arrayElement = constantExpression.Value;
137-
else
138-
arrayElement = ExtractArguments(arrayElementExpression, value).Select(o => o.Value).ToArray();
139-
140-
if (arrayElement is object[])
43+
var arguments = node.Arguments.Select(a =>
14144
{
142-
foreach (var item in (object[])arrayElement)
143-
arrayElements.Add(item);
144-
}
145-
else
146-
arrayElements.Add(arrayElement);
147-
}
148-
149-
return ToArray(arrayElements).Select(o => new StepArgument(() => o));
150-
}
151-
152-
private static IEnumerable<object> ToArray(IList list)
153-
{
154-
var toArrayMethod = list.GetType().GetMethod("ToArray");
155-
yield return toArrayMethod.Invoke(list, new Type[] { });
156-
}
157-
158-
private static IList CreateList(Type type)
159-
{
160-
return (IList)typeof(List<>).MakeGenericType(type).GetConstructor(new Type[0]).Invoke(BindingFlags.CreateInstance, null, null, null);
161-
}
162-
163-
private static IEnumerable<StepArgument> ExtractConvertibleTypeArrayConstants(NewArrayExpression newArrayExpression, Type type)
164-
{
165-
var arrayElements = CreateList(type);
166-
foreach (var arrayElementExpression in newArrayExpression.Expressions)
167-
{
168-
var arrayElement = ((ConstantExpression)arrayElementExpression).Value;
169-
arrayElements.Add(Convert.ChangeType(arrayElement, arrayElementExpression.Type, null));
170-
}
171-
172-
return new[] { new StepArgument(() => ToArray(arrayElements)) };
173-
}
174-
175-
private static IEnumerable<StepArgument> ExtractArguments<T>(ConstantExpression constantExpression, T value)
176-
{
177-
var expression = constantExpression.Value as Expression;
178-
if (expression != null)
179-
{
180-
return ExtractArguments(expression, value);
181-
}
182-
183-
var constants = new List<StepArgument>();
184-
if (constantExpression.Type == typeof(string) ||
185-
constantExpression.Type == typeof(decimal) ||
186-
constantExpression.Type.IsPrimitive ||
187-
constantExpression.Type.IsEnum ||
188-
constantExpression.Value == null)
189-
constants.Add(new StepArgument(() => constantExpression.Value));
190-
191-
return constants;
192-
}
193-
194-
private static StepArgument ExtractArgument<T>(MemberExpression memberExpression, T value)
195-
{
196-
var constExpression = memberExpression.Expression as ConstantExpression;
197-
if (constExpression != null)
198-
return ExtractConstant(memberExpression, constExpression);
199-
200-
var fieldInfo = memberExpression.Member as FieldInfo;
201-
if (fieldInfo != null)
202-
return ExtractFieldValue(memberExpression, fieldInfo, value);
203-
204-
var propertyInfo = memberExpression.Member as PropertyInfo;
205-
if (propertyInfo != null)
206-
return ExtractPropertyValue(memberExpression, propertyInfo, value);
207-
208-
throw new InvalidOperationException("Unknown expression type: " + memberExpression.GetType().Name);
209-
}
210-
211-
private static StepArgument ExtractFieldValue<T>(MemberExpression memberExpression, FieldInfo fieldInfo, T value)
212-
{
213-
if (fieldInfo.IsStatic)
214-
return new StepArgument(fieldInfo, null);
215-
216-
return new StepArgument(fieldInfo, value);
217-
}
218-
219-
private static StepArgument ExtractConstant(MemberExpression memberExpression, ConstantExpression constExpression)
220-
{
221-
var valIsConstant = constExpression != null;
222-
Type declaringType = memberExpression.Member.DeclaringType;
223-
object declaringObject = memberExpression.Member.DeclaringType;
224-
225-
if (valIsConstant)
226-
{
227-
declaringType = constExpression.Type;
228-
declaringObject = constExpression.Value;
45+
switch (a.NodeType)
46+
{
47+
case ExpressionType.MemberAccess:
48+
var memberExpression = (MemberExpression)a;
49+
var field = memberExpression.Member as FieldInfo;
50+
if (field != null)
51+
{
52+
var o = field.IsStatic ? null : GetValue(memberExpression.Expression);
53+
return new StepArgument(field, o);
54+
}
55+
var propertyInfo = (PropertyInfo)memberExpression.Member;
56+
var methodInfo = propertyInfo.GetGetMethod(true);
57+
var declaringObject = methodInfo == null || methodInfo.IsStatic ? null : GetValue(memberExpression.Expression);
58+
return new StepArgument(propertyInfo, declaringObject);
59+
default:
60+
return new StepArgument(GetValue(a));
61+
}
62+
});
63+
_arguments.AddRange(arguments);
64+
return node;
22965
}
23066

231-
var member = declaringType.GetMember(memberExpression.Member.Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).Single();
232-
233-
if (member.MemberType == MemberTypes.Field)
234-
return new StepArgument((FieldInfo)member, declaringObject);
235-
236-
return new StepArgument((PropertyInfo)member, declaringObject);
237-
}
238-
239-
private static StepArgument ExtractPropertyValue<T>(MemberExpression expression, PropertyInfo member, T value)
240-
{
241-
var memberExpression = expression.Expression as MemberExpression;
242-
if (memberExpression != null)
67+
private static Func<object> GetValue(Expression a)
24368
{
244-
var extractArguments = ExtractArgument(memberExpression, value).Value;
245-
return new StepArgument(member, extractArguments);
69+
return Expression.Lambda<Func<object>>(Expression.Convert(a, typeof(object))).Compile();
24670
}
247-
return new StepArgument(member, value);
24871
}
24972
}
25073
}

TestStack.BDDfy/Scanners/StepScanners/Fluent/StepArgument.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,40 @@ public class StepArgument
88
private readonly Action<object> _set = o => { };
99
private readonly Func<object> _get;
1010

11-
public StepArgument(FieldInfo member, object declaringObject)
11+
public StepArgument(FieldInfo member, Func<object> declaringObject)
1212
{
1313
Name = member.Name;
14-
_get = () => member.GetValue(declaringObject);
15-
_set = o => member.SetValue(declaringObject, o);
14+
_get = () => member.GetValue(declaringObject == null ? null : declaringObject());
15+
_set = o => member.SetValue(declaringObject == null ? null : declaringObject(), o);
1616
ArgumentType = member.FieldType;
1717
}
1818

19-
public StepArgument(PropertyInfo member, object declaringObject)
19+
public StepArgument(PropertyInfo member, Func<object> declaringObject)
2020
{
2121
Name = member.Name;
22-
_get = () => member.GetGetMethod(true).Invoke(declaringObject, null);
23-
_set = o => member.GetSetMethod(true).Invoke(declaringObject, new[] { o });
22+
_get = () =>
23+
{
24+
if (declaringObject == null)
25+
return member.GetGetMethod(true).Invoke(null, null);
26+
27+
var declaringObjectValue = declaringObject();
28+
if (declaringObjectValue == null)
29+
return null;
30+
return member.GetGetMethod(true).Invoke(declaringObjectValue, null);
31+
};
32+
_set = o =>
33+
{
34+
if (declaringObject == null)
35+
{
36+
member.GetSetMethod(true).Invoke(null, new[] {o});
37+
return;
38+
}
39+
40+
var declaringObjectValue = declaringObject();
41+
if (declaringObjectValue == null)
42+
return;
43+
member.GetSetMethod(true).Invoke(declaringObjectValue, new[] { o });
44+
};
2445
ArgumentType = member.PropertyType;
2546
}
2647

0 commit comments

Comments
 (0)