diff --git a/Reporting/ReflectionHelper.cs b/Reporting/ReflectionHelper.cs deleted file mode 100644 index 30fd504bb..000000000 --- a/Reporting/ReflectionHelper.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Reflection; - -namespace TechTalk.SpecFlow.Reporting -{ - static class ReflectionHelper - { - public static T GetProperty(this object source, string propertyName) - { - return (T)source.GetType().GetProperty(propertyName).GetValue(source, null); - } - - public static void PreserveStackTrace(this Exception ex) - { - Type exceptionType = typeof(Exception); - - // Mono's implementation of System.Exception doesn't contain the method InternalPreserveStackTrace - if (Type.GetType("Mono.Runtime") != null) - { - exceptionType.GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, ex.StackTrace + Environment.NewLine); - } - else - { - exceptionType.GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(ex, new object[0]); - } - } - } -} \ No newline at end of file diff --git a/Reporting/ReflectionHelperExtensions.cs b/Reporting/ReflectionHelperExtensions.cs new file mode 100644 index 000000000..0ee43da74 --- /dev/null +++ b/Reporting/ReflectionHelperExtensions.cs @@ -0,0 +1,13 @@ +using System; +using System.Reflection; + +namespace TechTalk.SpecFlow.Reporting +{ + static class ReflectionHelperExtensions + { + public static T GetProperty(this object source, string propertyName) + { + return (T)source.GetType().GetProperty(propertyName).GetValue(source, null); + } + } +} \ No newline at end of file diff --git a/Reporting/ResourceXmlReader.cs b/Reporting/ResourceXmlReader.cs index 1222a09e4..cd1f33644 100644 --- a/Reporting/ResourceXmlReader.cs +++ b/Reporting/ResourceXmlReader.cs @@ -5,6 +5,9 @@ namespace TechTalk.SpecFlow.Reporting { + /// + /// XML reader for an embedded resource that uses the resource://assembly/resource base URI. + /// internal class ResourceXmlReader : XmlTextReader { private readonly string baseUri; diff --git a/Reporting/TechTalk.SpecFlow.Reporting.csproj b/Reporting/TechTalk.SpecFlow.Reporting.csproj index 25cd2dad5..2c553917c 100644 --- a/Reporting/TechTalk.SpecFlow.Reporting.csproj +++ b/Reporting/TechTalk.SpecFlow.Reporting.csproj @@ -50,6 +50,12 @@ + + Compatibility\ExceptionHelper.cs + + + Compatibility\MonoHelper.cs + VersionInfo.cs @@ -63,7 +69,7 @@ - + diff --git a/Reporting/XmlResourceResolver.cs b/Reporting/XmlResourceResolver.cs index 57be5160d..c957b90a8 100644 --- a/Reporting/XmlResourceResolver.cs +++ b/Reporting/XmlResourceResolver.cs @@ -1,8 +1,9 @@ using System; +using System.Diagnostics; using System.IO; -using System.Net; using System.Reflection; using System.Xml; +using TechTalk.SpecFlow.Compatibility; namespace TechTalk.SpecFlow.Reporting { @@ -14,38 +15,19 @@ public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToRe return base.GetEntity(absoluteUri, role, ofObjectToReturn); string resourceName = absoluteUri.AbsolutePath.TrimStart(Path.AltDirectorySeparatorChar).Replace(Path.AltDirectorySeparatorChar, Type.Delimiter); + Assembly assembly = GetAssemblyFor(absoluteUri.Host); - - if (ofObjectToReturn != null) - { - if (ofObjectToReturn == typeof(ResourceXmlReader) || ofObjectToReturn == typeof(XmlTextReader)) - { - return new ResourceXmlReader(assembly, resourceName); - } - else if (ofObjectToReturn == typeof(Stream)) - { - return assembly.GetManifestResourceStream(resourceName); - } - } - + Debug.Assert(ofObjectToReturn == null || ofObjectToReturn == typeof(Stream)); return assembly.GetManifestResourceStream(resourceName); } - private static Assembly GetAssemblyFor(string host) + private static Assembly GetAssemblyFor(string assemblyName) { - Assembly locatedAssembly = null; - - foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - AssemblyName assemblyName = assembly.GetName(); - - if (!assemblyName.Name.Equals(host, StringComparison.CurrentCultureIgnoreCase)) - continue; - - locatedAssembly = assembly; - } - - return locatedAssembly; + if (MonoHelper.IsMono) + //TODO: find out why Assembly.Load does not work on Mono + return MonoHelper.GetLoadedAssembly(assemblyName); + + return Assembly.Load(assemblyName); } } } diff --git a/Reporting/XsltHelper.cs b/Reporting/XsltHelper.cs index 2e97823f3..f52f9e694 100644 --- a/Reporting/XsltHelper.cs +++ b/Reporting/XsltHelper.cs @@ -48,8 +48,7 @@ public static void TransformHtml(XmlSerializer serializer, object report, Type r argumentList.AddParam("feature-language", "", generatorConfiguration.FeatureLanguage.Name); argumentList.AddParam("tool-language", "", generatorConfiguration.ToolLanguage.Name); - using (var outFileStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write)) - using (var xmlTextWriter = new XmlTextWriter(outFileStream, Encoding.UTF8)) + using (var xmlTextWriter = new XmlTextWriter(outputFilePath, Encoding.UTF8)) { xslt.Transform(xmlOutputReader, argumentList, xmlTextWriter, resourceResolver); } diff --git a/Runtime.Silverlight/Compatibility/ExceptionHelper.cs b/Runtime.Silverlight/Compatibility/ExceptionHelper.cs new file mode 100644 index 000000000..f381c412e --- /dev/null +++ b/Runtime.Silverlight/Compatibility/ExceptionHelper.cs @@ -0,0 +1,12 @@ +using System; + +namespace TechTalk.SpecFlow.Compatibility +{ + internal static class ExceptionHelper + { + public static void PreserveStackTrace(this Exception ex) + { + //do nothing + } + } +} diff --git a/Runtime.Silverlight/TechTalk.SpecFlow.Silverlight.csproj b/Runtime.Silverlight/TechTalk.SpecFlow.Silverlight.csproj index 31868d52a..a072dd715 100644 --- a/Runtime.Silverlight/TechTalk.SpecFlow.Silverlight.csproj +++ b/Runtime.Silverlight/TechTalk.SpecFlow.Silverlight.csproj @@ -196,6 +196,7 @@ + diff --git a/Runtime/Bindings/StepMethodBinding.cs b/Runtime/Bindings/StepMethodBinding.cs index a1fd2e99e..5af43bac7 100644 --- a/Runtime/Bindings/StepMethodBinding.cs +++ b/Runtime/Bindings/StepMethodBinding.cs @@ -145,7 +145,7 @@ public object InvokeAction(object[] arguments, ITestTracer testTracer, out TimeS catch (TargetInvocationException invEx) { var ex = invEx.InnerException; - PreserveStackTrace(ex); + ex.PreserveStackTrace(); throw ex; } } @@ -160,21 +160,6 @@ private CultureInfoScope CreateCultureInfoScope() return new CultureInfoScope(cultureInfo); } - internal void PreserveStackTrace(Exception ex) - { - Type exceptionType = typeof(Exception); - - // Mono's implementation of System.Exception doesn't contain the method InternalPreserveStackTrace - if (Type.GetType("Mono.Runtime") != null) - { - exceptionType.GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, ex.StackTrace + Environment.NewLine); - } - else - { - exceptionType.GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(ex, new object[0]); - } - } - #region extended action types static readonly Type[] actionTypes = new Type[] { typeof(Action), typeof(Action<>), typeof(Action<,>), typeof(Action<,,>), typeof(Action<,,,>), typeof(ExtendedAction<,,,,>), typeof(ExtendedAction<,,,,,>), typeof(ExtendedAction<,,,,,,>), typeof(ExtendedAction<,,,,,,,>), typeof(ExtendedAction<,,,,,,,,>), typeof(ExtendedAction<,,,,,,,,,>) diff --git a/Runtime/Compatibility/ExceptionHelper.cs b/Runtime/Compatibility/ExceptionHelper.cs new file mode 100644 index 000000000..57e20d4a7 --- /dev/null +++ b/Runtime/Compatibility/ExceptionHelper.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace TechTalk.SpecFlow.Compatibility +{ + internal static class ExceptionHelper + { + public static void PreserveStackTrace(this Exception ex) + { + // Mono's implementation of System.Exception doesn't contain the method InternalPreserveStackTrace + if (MonoHelper.IsMono) + MonoHelper.PreserveStackTrace(ex); + else + typeof(Exception).GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(ex, new object[0]); + } + + } +} diff --git a/Runtime/Compatibility/MonoHelper.cs b/Runtime/Compatibility/MonoHelper.cs new file mode 100644 index 000000000..2a87af71f --- /dev/null +++ b/Runtime/Compatibility/MonoHelper.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace TechTalk.SpecFlow.Compatibility +{ + internal class MonoHelper + { + public static bool IsMono { get; private set; } + + static MonoHelper() + { + IsMono = Type.GetType("Mono.Runtime") != null; + } + + public static void PreserveStackTrace(Exception ex) + { + typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, ex.StackTrace + Environment.NewLine); + } + + public static Assembly GetLoadedAssembly(string assemblyName) + { + Assembly locatedAssembly = null; + + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + AssemblyName loadedAssemblyName = assembly.GetName(); + + if (!loadedAssemblyName.Name.Equals(assemblyName, StringComparison.CurrentCultureIgnoreCase)) + continue; + + locatedAssembly = assembly; + } + + return locatedAssembly; + } + } +} diff --git a/Runtime/TechTalk.SpecFlow.csproj b/Runtime/TechTalk.SpecFlow.csproj index f7e811216..e13737d86 100644 --- a/Runtime/TechTalk.SpecFlow.csproj +++ b/Runtime/TechTalk.SpecFlow.csproj @@ -55,6 +55,8 @@ + + diff --git a/Runtime/TestRunner.cs b/Runtime/TestRunner.cs index 8389f167d..a2eda08ed 100644 --- a/Runtime/TestRunner.cs +++ b/Runtime/TestRunner.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Text.RegularExpressions; using TechTalk.SpecFlow.Bindings; +using TechTalk.SpecFlow.Compatibility; using TechTalk.SpecFlow.Configuration; using TechTalk.SpecFlow.ErrorHandling; using TechTalk.SpecFlow.Tracing; @@ -146,7 +147,7 @@ public void CollectScenarioErrors() if (ObjectContainer.ScenarioContext.TestError == null) throw new InvalidOperationException("test failed with an unknown error"); - PreserveStackTrace(ObjectContainer.ScenarioContext.TestError); + ObjectContainer.ScenarioContext.TestError.PreserveStackTrace(); throw ObjectContainer.ScenarioContext.TestError; } @@ -397,21 +398,6 @@ private List GetMatchesWithoutParamCheck(StepArgs stepArgs) return matches; } - internal void PreserveStackTrace(Exception ex) - { - Type exceptionType = typeof(Exception); - - // Mono's implementation of System.Exception doesn't contain the method InternalPreserveStackTrace - if (Type.GetType("Mono.Runtime") != null) - { - exceptionType.GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, ex.StackTrace + Environment.NewLine); - } - else - { - exceptionType.GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(ex, new object[0]); - } - } - private TimeSpan ExecuteStepMatch(BindingMatch match, object[] arguments) { OnStepStart(); diff --git a/Tests/RuntimeTests/NUnitTestExecutor.cs b/Tests/RuntimeTests/NUnitTestExecutor.cs index b9e37de43..bcee4639f 100644 --- a/Tests/RuntimeTests/NUnitTestExecutor.cs +++ b/Tests/RuntimeTests/NUnitTestExecutor.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using NUnit.Framework; +using TechTalk.SpecFlow.Compatibility; namespace TechTalk.SpecFlow.RuntimeTests { @@ -48,26 +49,11 @@ private static void InvokeMethod(object test, MethodInfo testMethod) catch (TargetInvocationException invEx) { var ex = invEx.InnerException; - PreserveStackTrace(ex); + ex.PreserveStackTrace(); throw ex; } } - internal static void PreserveStackTrace(Exception ex) - { - Type exceptionType = typeof(Exception); - - // Mono's implementation of System.Exception doesn't contain the method InternalPreserveStackTrace - if (Type.GetType("Mono.Runtime") != null) - { - exceptionType.GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, ex.StackTrace + Environment.NewLine); - } - else - { - exceptionType.GetMethod("InternalPreserveStackTrace", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(ex, new object[0]); - } - } - private static void ExecuteWithAttribute(object test, Type attributeType) { foreach (var methodInfo in GetMethodsWithAttribute(test, attributeType))