/Runtime/Bindings/StepArgumentTypeConverter.cs

https://github.com/dablo/SpecFlow
C# | 112 lines | 93 code | 19 blank | 0 comment | 21 complexity | f21e6fcc5e95c28a01b730d81eda55e7 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using TechTalk.SpecFlow.Infrastructure;
  6. using TechTalk.SpecFlow.Tracing;
  7. namespace TechTalk.SpecFlow.Bindings
  8. {
  9. public interface IStepArgumentTypeConverter
  10. {
  11. object Convert(object value, Type typeToConvertTo, CultureInfo cultureInfo);
  12. bool CanConvert(object value, Type typeToConvertTo, CultureInfo cultureInfo);
  13. }
  14. public class StepArgumentTypeConverter : IStepArgumentTypeConverter
  15. {
  16. private readonly ITestTracer testTracer;
  17. private readonly IContextManager contextManager;
  18. public StepArgumentTypeConverter(ITestTracer testTracer, IBindingRegistry bindingRegistry, IContextManager contextManager)
  19. {
  20. this.testTracer = testTracer;
  21. this.contextManager = contextManager;
  22. StepTransformations = bindingRegistry.StepTransformations ?? new List<StepTransformationBinding>();
  23. }
  24. public ICollection<StepTransformationBinding> StepTransformations { get; private set; }
  25. private StepTransformationBinding GetMatchingStepTransformation(object value, Type typeToConvertTo, bool traceWarning)
  26. {
  27. var stepTransformations = StepTransformations.Where(t => CanConvert(t, value, typeToConvertTo)).ToArray();
  28. if (stepTransformations.Length > 1 && traceWarning)
  29. {
  30. testTracer.TraceWarning(string.Format("Multiple step transformation matches to the input ({0}, target type: {1}). We use the first.", value, typeToConvertTo));
  31. }
  32. return stepTransformations.Length > 0 ? stepTransformations[0] : null;
  33. }
  34. public object Convert(object value, Type typeToConvertTo, CultureInfo cultureInfo)
  35. {
  36. if (value == null) throw new ArgumentNullException("value");
  37. if (typeToConvertTo == value.GetType())
  38. return value;
  39. var stepTransformation = GetMatchingStepTransformation(value, typeToConvertTo, true);
  40. if (stepTransformation != null)
  41. return stepTransformation.Transform(contextManager, value, testTracer, this, cultureInfo);
  42. return ConvertSimple(typeToConvertTo, value, cultureInfo);
  43. }
  44. public bool CanConvert(object value, Type typeToConvertTo, CultureInfo cultureInfo)
  45. {
  46. if (value == null) throw new ArgumentNullException("value");
  47. if (typeToConvertTo == value.GetType())
  48. return true;
  49. var stepTransformation = GetMatchingStepTransformation(value, typeToConvertTo, false);
  50. if (stepTransformation != null)
  51. return true;
  52. return CanConvertSimple(typeToConvertTo, value, cultureInfo);
  53. }
  54. private bool CanConvert(StepTransformationBinding stepTransformationBinding, object value, Type typeToConvertTo)
  55. {
  56. if (stepTransformationBinding.ReturnType != typeToConvertTo)
  57. return false;
  58. if (stepTransformationBinding.Regex != null && value is string)
  59. return stepTransformationBinding.Regex.IsMatch((string) value);
  60. return true;
  61. }
  62. private object ConvertSimple(Type typeToConvertTo, object value, CultureInfo cultureInfo)
  63. {
  64. if (typeToConvertTo.IsEnum && value is string)
  65. return Enum.Parse(typeToConvertTo, (string)value, true);
  66. return System.Convert.ChangeType(value, typeToConvertTo, cultureInfo);
  67. }
  68. public bool CanConvertSimple(Type typeToConvertTo, object value, CultureInfo cultureInfo)
  69. {
  70. try
  71. {
  72. ConvertSimple(typeToConvertTo, value, cultureInfo);
  73. return true;
  74. }
  75. catch (InvalidCastException)
  76. {
  77. return false;
  78. }
  79. catch (OverflowException)
  80. {
  81. return false;
  82. }
  83. catch (FormatException)
  84. {
  85. return false;
  86. }
  87. catch (ArgumentException)
  88. {
  89. return false;
  90. }
  91. }
  92. }
  93. }