Permalink
Browse files

create base binding source processor infrasrtrucutre

  • Loading branch information...
1 parent 78b6a69 commit 7fd9e90afca72db4b399a5786efe143289c57079 @gasparnagy gasparnagy committed Jun 27, 2012
Showing with 412 additions and 4 deletions.
  1. +29 −0 IdeIntegration/IdeIntegration/Bindings/BindingSourceAttribute.cs
  2. +13 −0 IdeIntegration/IdeIntegration/Bindings/BindingSourceMethod.cs
  3. +146 −0 IdeIntegration/IdeIntegration/Bindings/BindingSourceProcessor.cs
  4. +17 −0 IdeIntegration/IdeIntegration/Bindings/BindingSourceType.cs
  5. +22 −0 IdeIntegration/IdeIntegration/Bindings/IBindingSourceAttributeValueProvider.cs
  6. +17 −0 IdeIntegration/IdeIntegration/Bindings/IBindingSourceProcessor.cs
  7. +106 −0 IdeIntegration/IdeIntegration/Bindings/ILBindingRegistryBuilder.cs
  8. +27 −0 IdeIntegration/IdeIntegration/Bindings/IdeBindingSourceProcessor.cs
  9. +27 −1 IdeIntegration/IdeIntegration/TechTalk.SpecFlow.IdeIntegration.csproj
  10. +4 −0 IdeIntegration/IdeIntegration/packages.config
  11. +1 −1 Runtime/Bindings/IBindingFactory.cs
  12. +2 −2 Runtime/Bindings/Reflection/BindingReflectionExtensions.cs
  13. BIN packages/Mono.Cecil.0.9.5.3/Mono.Cecil.0.9.5.3.nupkg
  14. BIN packages/Mono.Cecil.0.9.5.3/lib/net20/Mono.Cecil.Mdb.dll
  15. BIN packages/Mono.Cecil.0.9.5.3/lib/net20/Mono.Cecil.Pdb.dll
  16. BIN packages/Mono.Cecil.0.9.5.3/lib/net20/Mono.Cecil.dll
  17. BIN packages/Mono.Cecil.0.9.5.3/lib/net35/Mono.Cecil.Mdb.dll
  18. BIN packages/Mono.Cecil.0.9.5.3/lib/net35/Mono.Cecil.Pdb.dll
  19. BIN packages/Mono.Cecil.0.9.5.3/lib/net35/Mono.Cecil.Rocks.dll
  20. BIN packages/Mono.Cecil.0.9.5.3/lib/net35/Mono.Cecil.dll
  21. BIN packages/Mono.Cecil.0.9.5.3/lib/net40/Mono.Cecil.Mdb.dll
  22. BIN packages/Mono.Cecil.0.9.5.3/lib/net40/Mono.Cecil.Pdb.dll
  23. BIN packages/Mono.Cecil.0.9.5.3/lib/net40/Mono.Cecil.Rocks.dll
  24. BIN packages/Mono.Cecil.0.9.5.3/lib/net40/Mono.Cecil.dll
  25. BIN packages/Mono.Cecil.0.9.5.3/lib/sl40/Mono.Cecil.Rocks.dll
  26. BIN packages/Mono.Cecil.0.9.5.3/lib/sl40/Mono.Cecil.dll
  27. +1 −0 packages/repositories.config
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+using TechTalk.SpecFlow.Bindings.Reflection;
+
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public class BindingSourceAttribute
+ {
+ public IBindingType AttributeType { get; set; }
+
+ public IBindingSourceAttributeValueProvider[] AttributeValues { get; set; }
+ public IDictionary<string, IBindingSourceAttributeValueProvider> NamedAttributeValues { get; set; }
+
+ public TValue TryGetAttributeValue<TValue>(int index, TValue defaultValue = default(TValue))
+ {
+ if (AttributeValues.Length >= index)
+ return AttributeValues[index].GetValue<TValue>();
+ return defaultValue;
+ }
+
+ public TValue TryGetAttributeValue<TValue>(string name, TValue defaultValue = default(TValue))
+ {
+ IBindingSourceAttributeValueProvider valueProvider;
+ if (NamedAttributeValues.TryGetValue(name, out valueProvider))
+ return valueProvider.GetValue<TValue>();
+
+ return defaultValue;
+ }
+ }
+}
@@ -0,0 +1,13 @@
+using TechTalk.SpecFlow.Bindings.Reflection;
+
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public class BindingSourceMethod
+ {
+ public IBindingMethod BindingMethod { get; set; }
+ public bool IsPublic { get; set; }
+ public bool IsStatic { get; set; }
+
+ public BindingSourceAttribute[] Attributes { get; set; }
+ }
+}
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TechTalk.SpecFlow.Bindings;
+using TechTalk.SpecFlow.Bindings.Reflection;
+
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public abstract class BindingSourceProcessor : IBindingSourceProcessor
+ {
+ public static string BINDING_ATTR = typeof(BindingAttribute).FullName;
+
+ private readonly IBindingFactory bindingFactory;
+
+ private BindingScope[] typeScopes;
+
+ protected BindingSourceProcessor(IBindingFactory bindingFactory)
+ {
+ this.bindingFactory = bindingFactory;
+ }
+
+ public bool CanProcessTypeAttribute(string attributeTypeName)
+ {
+ return true;
+ }
+
+ public bool CanProcessMethodAttribute(string attributeTypeName)
+ {
+ return true;
+ }
+
+ public bool PreFilterType(IEnumerable<string> attributeTypeNames)
+ {
+ return attributeTypeNames.Any(attr => attr.Equals(BINDING_ATTR, StringComparison.InvariantCulture));
+ }
+
+ public bool ProcessType(BindingSourceType bindingSourceType)
+ {
+ typeScopes = null;
+
+ if (!CheckType(bindingSourceType))
+ return false;
+
+ typeScopes = GetScopes(bindingSourceType.Attributes).ToArray();
+ return true;
+ }
+
+ private IEnumerable<BindingScope> GetScopes(IEnumerable<BindingSourceAttribute> attributes)
+ {
+ return attributes.Where(attr => attr.AttributeType.TypeEquals(typeof(ScopeAttribute)))
+ .Select(attr => new BindingScope(attr.TryGetAttributeValue<string>("Tag"), attr.TryGetAttributeValue<string>("Feature"), attr.TryGetAttributeValue<string>("Scenario")));
+ }
+
+ private bool CheckType(BindingSourceType bindingSourceType)
+ {
+ return bindingSourceType.Attributes.Any(attr => attr.AttributeType.TypeEquals(typeof(BindingAttribute))) &&
+ bindingSourceType.IsClass &&
+ !bindingSourceType.IsAbstract &&
+ !bindingSourceType.IsGenericTypeDefinition;
+ }
+
+ private bool IsStepDefinitionAttribute(BindingSourceAttribute attribute)
+ {
+ return
+ attribute.AttributeType.TypeEquals(typeof(GivenAttribute)) ||
+ attribute.AttributeType.TypeEquals(typeof(WhenAttribute)) ||
+ attribute.AttributeType.TypeEquals(typeof(ThenAttribute)) ||
+ attribute.AttributeType.TypeEquals(typeof(StepDefinitionAttribute));
+ }
+
+ public void ProcessMethod(BindingSourceMethod bindingSourceMethod)
+ {
+ var methodScopes = typeScopes.Concat(GetScopes(bindingSourceMethod.Attributes)).ToArray();
+
+ ProcessStepDefinitions(bindingSourceMethod, methodScopes);
+ ProcessHooks(bindingSourceMethod, methodScopes);
+ ProcessStepArgumentTransformations(bindingSourceMethod, methodScopes);
+ }
+
+ protected virtual void ProcessStepArgumentTransformations(BindingSourceMethod bindingSourceMethod, BindingScope[] methodScopes)
+ {
+ //TODO
+ }
+
+ protected virtual void ProcessHooks(BindingSourceMethod bindingSourceMethod, BindingScope[] methodScopes)
+ {
+ //TODO
+ }
+
+ protected virtual void ProcessStepDefinitions(BindingSourceMethod bindingSourceMethod, BindingScope[] methodScopes)
+ {
+ foreach (var stepDefinitionAttribute in bindingSourceMethod.Attributes.Where(IsStepDefinitionAttribute))
+ {
+ ProcessStepDefinitionAttribute(bindingSourceMethod, methodScopes, stepDefinitionAttribute);
+ }
+ }
+
+ private void ProcessStepDefinitionAttribute(BindingSourceMethod bindingSourceMethod, BindingScope[] methodScopes, BindingSourceAttribute stepDefinitionAttribute)
+ {
+ ApplyForScope(methodScopes, scope => ProcessStepDefinitionAttribute(bindingSourceMethod, stepDefinitionAttribute, scope));
+ }
+
+ private void ProcessStepDefinitionAttribute(BindingSourceMethod bindingSourceMethod, BindingSourceAttribute stepDefinitionAttribute, BindingScope scope)
+ {
+ var stepDefinitionTypes = GetStepDefinitionTypes(stepDefinitionAttribute);
+ string regex = stepDefinitionAttribute.TryGetAttributeValue<string>(0);
+
+ foreach (var stepDefinitionType in stepDefinitionTypes)
+ {
+ var stepDefinitionBinding = bindingFactory.CreateStepBinding(stepDefinitionType, regex, bindingSourceMethod.BindingMethod, scope);
+ ProcessStepDefinitionBinding(stepDefinitionBinding);
+ }
+ }
+
+ protected abstract void ProcessStepDefinitionBinding(IStepDefinitionBinding stepDefinitionBinding);
+
+ private IEnumerable<StepDefinitionType> GetStepDefinitionTypes(BindingSourceAttribute stepDefinitionAttribute)
+ {
+ if (stepDefinitionAttribute.AttributeType.TypeEquals(typeof(GivenAttribute)))
+ return new[] { StepDefinitionType.Given };
+ if (stepDefinitionAttribute.AttributeType.TypeEquals(typeof(WhenAttribute)))
+ return new[] { StepDefinitionType.When };
+ if (stepDefinitionAttribute.AttributeType.TypeEquals(typeof(ThenAttribute)))
+ return new[] { StepDefinitionType.Then };
+ if (stepDefinitionAttribute.AttributeType.TypeEquals(typeof(StepDefinitionAttribute)))
+ return new[] { StepDefinitionType.Given, StepDefinitionType.When, StepDefinitionType.Then };
+
+ return new StepDefinitionType[0];
+ }
+
+ private void ApplyForScope(BindingScope[] scopes, Action<BindingScope> action)
+ {
+ if (scopes.Any())
+ {
+ foreach (var scope in scopes)
+ {
+ action(scope);
+ }
+ }
+ else
+ {
+ action(null);
+ }
+ }
+ }
+}
@@ -0,0 +1,17 @@
+using TechTalk.SpecFlow.Bindings.Reflection;
+
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public class BindingSourceType
+ {
+ public IBindingType BindingType { get; set; }
+
+ public bool IsClass { get; set; }
+ public bool IsPublic { get; set; }
+ public bool IsAbstract { get; set; }
+ public bool IsGenericTypeDefinition { get; set; }
+ public bool IsNested { get; set; }
+
+ public BindingSourceAttribute[] Attributes { get; set; }
+ }
+}
@@ -0,0 +1,22 @@
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public interface IBindingSourceAttributeValueProvider
+ {
+ TValue GetValue<TValue>();
+ }
+
+ public class BindingSourceAttributeValueProvider : IBindingSourceAttributeValueProvider
+ {
+ private readonly object value;
+
+ public BindingSourceAttributeValueProvider(object value)
+ {
+ this.value = value;
+ }
+
+ public TValue GetValue<TValue>()
+ {
+ return (TValue)value;
+ }
+ }
+}
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public interface IBindingSourceProcessor
+ {
+ bool CanProcessTypeAttribute(string attributeTypeName);
+ bool CanProcessMethodAttribute(string attributeTypeName);
+
+ bool PreFilterType(IEnumerable<string> attributeTypeNames);
+
+ bool ProcessType(BindingSourceType bindingSourceType);
+ void ProcessMethod(BindingSourceMethod bindingSourceMethod);
+ }
+}
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using TechTalk.SpecFlow.Bindings;
+using TechTalk.SpecFlow.Bindings.Reflection;
+
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public class ILBindingRegistryBuilder
+ {
+ public void ProcessStepDefinitionsFromAssembly(string assemblyPath, IBindingSourceProcessor bindingSourceProcessor)
+ {
+ ModuleDefinition module = ModuleDefinition.ReadModule(assemblyPath);
+ foreach (TypeDefinition typeDefinition in module.Types)
+ {
+// ReSharper disable PossibleMultipleEnumeration
+ var filteredAttributes = typeDefinition.CustomAttributes.Where(attr => bindingSourceProcessor.CanProcessTypeAttribute(attr.AttributeType.FullName));
+ if (!bindingSourceProcessor.PreFilterType(filteredAttributes.Select(attr => attr.AttributeType.FullName)))
+ continue;
+
+ var bindingSourceType = CreateBindingSourceType(typeDefinition, filteredAttributes);
+
+ if (!bindingSourceProcessor.ProcessType(bindingSourceType))
+ continue;
+
+ foreach (var methodDefinition in typeDefinition.Methods)
+ {
+ bindingSourceProcessor.ProcessMethod(CreateBindingSourceMethod(methodDefinition, bindingSourceType));
+ }
+// ReSharper restore PossibleMultipleEnumeration
+ }
+ }
+
+ public IEnumerable<IStepDefinitionBinding> GetStepDefinitionsFromAssembly(string assemblyPath)
+ {
+ var bindingProcessor = new IdeBindingSourceProcessor();
+ ProcessStepDefinitionsFromAssembly(assemblyPath, bindingProcessor);
+ return bindingProcessor.ReadStepDefinitionBindings();
+ }
+
+ private BindingSourceMethod CreateBindingSourceMethod(MethodDefinition methodDefinition, BindingSourceType bindingSourceType)
+ {
+ return new BindingSourceMethod
+ {
+ BindingMethod = new BindingMethod(bindingSourceType.BindingType, methodDefinition.Name, GetParameters(methodDefinition), GetReturnType(methodDefinition)),
+ IsPublic = methodDefinition.IsPublic,
+ IsStatic = methodDefinition.IsStatic
+ };
+ }
+
+ private BindingType CreateBindingType(TypeReference typeReference)
+ {
+ return new BindingType(typeReference.Name, typeReference.FullName);
+ }
+
+ private IEnumerable<IBindingParameter> GetParameters(MethodDefinition methodDefinition)
+ {
+ return methodDefinition.Parameters.Select(pd => (IBindingParameter)new BindingParameter(CreateBindingType(pd.ParameterType), pd.Name));
+ }
+
+ private BindingType GetReturnType(MethodDefinition methodDefinition)
+ {
+ if (methodDefinition.ReturnType.FullName.Equals(typeof(void).FullName))
+ return null;
+
+ return CreateBindingType(methodDefinition.ReturnType);
+ }
+
+ private BindingSourceType CreateBindingSourceType(TypeDefinition typeDefinition, IEnumerable<CustomAttribute> filteredAttributes)
+ {
+ return new BindingSourceType
+ {
+ BindingType = CreateBindingType(typeDefinition),
+ IsAbstract = typeDefinition.IsAbstract,
+ IsClass = typeDefinition.IsClass,
+ IsPublic = typeDefinition.IsPublic,
+ IsNested = typeDefinition.IsNested,
+ IsGenericTypeDefinition = typeDefinition.HasGenericParameters,
+ Attributes = GetAttributes(filteredAttributes)
+ };
+ }
+
+ private BindingSourceAttribute CreateAttribute(CustomAttribute attribute)
+ {
+ return new BindingSourceAttribute
+ {
+ AttributeType = CreateBindingType(attribute.AttributeType),
+ AttributeValues = attribute.ConstructorArguments.Select(CreateAttributeValue).ToArray(),
+ NamedAttributeValues = attribute.Fields.Concat(attribute.Properties).ToDictionary(na => na.Name, na => CreateAttributeValue(na.Argument))
+ };
+ }
+
+
+
+ private IBindingSourceAttributeValueProvider CreateAttributeValue(CustomAttributeArgument customAttributeArgument)
+ {
+ return new BindingSourceAttributeValueProvider(customAttributeArgument.Value);
+ }
+
+ private BindingSourceAttribute[] GetAttributes(IEnumerable<CustomAttribute> customAttributes)
+ {
+ return customAttributes.Select(CreateAttribute).ToArray();
+ }
+ }
+}
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using TechTalk.SpecFlow.Bindings;
+using TechTalk.SpecFlow.Configuration;
+
+namespace TechTalk.SpecFlow.IdeIntegration.Bindings
+{
+ public class IdeBindingSourceProcessor : BindingSourceProcessor
+ {
+ private List<IStepDefinitionBinding> stepDefinitionBindings = new List<IStepDefinitionBinding>();
+
+ public IdeBindingSourceProcessor() : base(new BindingFactory(new StepDefinitionRegexCalculator(new RuntimeConfiguration())))
+ {
+ }
+
+ protected override void ProcessStepDefinitionBinding(IStepDefinitionBinding stepDefinitionBinding)
+ {
+ stepDefinitionBindings.Add(stepDefinitionBinding);
+ }
+
+ public IEnumerable<IStepDefinitionBinding> ReadStepDefinitionBindings()
+ {
+ var result = stepDefinitionBindings;
+ stepDefinitionBindings = new List<IStepDefinitionBinding>();
+ return result;
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 7fd9e90

Please sign in to comment.