Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

#25 added step overloads with a step context parameter #136

Merged
merged 3 commits into from

1 participant

This page is out of date. Refresh to see the latest.
View
9 src/Xbehave.Net35/Xbehave.Net35.csproj
@@ -66,9 +66,15 @@
<Compile Include="..\Xbehave.Net40\ContinueOnFailureAfterAttribute.cs">
<Link>ContinueOnFailureAfterAttribute.cs</Link>
</Compile>
+ <Compile Include="..\Xbehave.Net40\IStepContext.cs">
+ <Link>IStepContext.cs</Link>
+ </Compile>
<Compile Include="..\Xbehave.Net40\OmitArgumentsFromScenarioNamesAttribute.cs">
<Link>OmitArgumentsFromScenarioNamesAttribute.cs</Link>
</Compile>
+ <Compile Include="..\Xbehave.Net40\StepContext.cs">
+ <Link>StepContext.cs</Link>
+ </Compile>
<Compile Include="..\Xbehave.Net40\StepType.cs">
<Link>StepType.cs</Link>
</Compile>
@@ -91,9 +97,6 @@
<Compile Include="..\Xbehave.Net40\Fluent\Step.cs">
<Link>Fluent\Step.cs</Link>
</Compile>
- <Compile Include="..\Xbehave.Net40\Helper.cs">
- <Link>Helper.cs</Link>
- </Compile>
<Compile Include="..\Xbehave.Net40\Properties\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
</Compile>
View
16 src/Xbehave.Net40/DisposableExtensions.cs
@@ -18,6 +18,7 @@ public static class DisposableExtensions
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="obj">The object to be disposed.</param>
/// <returns>The object.</returns>
+ [Obsolete("Use Using(IStep) instead. This deprecated version of the method will fail to register objects for disposal in async steps, in steps with timeouts, or when called from a thread other than the scenario execution thread.")]
public static T Using<T>(this T obj) where T : IDisposable
{
if (obj != null)
@@ -27,5 +28,20 @@ public static class DisposableExtensions
return obj;
}
+
+ /// <summary>
+ /// Immediately registers the <see cref="IDisposable"/> object for disposal after all steps in the current scenario have been executed.
+ /// </summary>
+ /// <typeparam name="T">The type of the object.</typeparam>
+ /// <param name="obj">The object to be disposed.</param>
+ /// <param name="stepContext">The execution context for the current step.</param>
+ /// <returns>The object.</returns>
+ public static T Using<T>(this T obj, IStepContext stepContext) where T : IDisposable
+ {
+ Guard.AgainstNullArgument("stepContext", stepContext);
+
+ stepContext.Using(obj);
+ return obj;
+ }
}
}
View
29 src/Xbehave.Net40/Fluent/Step.cs
@@ -5,16 +5,41 @@
namespace Xbehave.Fluent
{
using System;
+#if NET45
+ using System.Threading.Tasks;
+#endif
+ using Xbehave.Sdk;
internal partial class Step : IStep
{
private readonly Sdk.Step step;
- public Step(Sdk.Step step)
+ public Step(string text, Action body, StepType stepType)
{
- this.step = step;
+ this.step = CurrentScenario.AddStep(text, body, stepType);
}
+ public Step(string text, Action<IStepContext> body, StepType stepType)
+ {
+ var context = new StepContext();
+ this.step = CurrentScenario.AddStep(text, () => body(context), stepType);
+ context.Assign(this.step);
+ }
+
+#if NET45
+ public Step(string text, Func<Task> body, StepType stepType)
+ {
+ this.step = CurrentScenario.AddStep(text, body, stepType);
+ }
+
+ public Step(string text, Func<IStepContext, Task> body, StepType stepType)
+ {
+ var context = new StepContext();
+ this.step = CurrentScenario.AddStep(text, () => body(context), stepType);
+ context.Assign(this.step);
+ }
+
+#endif
public IStep And()
{
return this;
View
17 src/Xbehave.Net40/Helper.cs
@@ -1,17 +0,0 @@
-// <copyright file="Helper.cs" company="xBehave.net contributors">
-// Copyright (c) xBehave.net contributors. All rights reserved.
-// </copyright>
-
-namespace Xbehave
-{
- using System;
- using Xbehave.Sdk;
-
- internal static partial class Helper
- {
- public static Fluent.IStep AddStep(string text, Action body, StepType stepType)
- {
- return new Fluent.Step(CurrentScenario.AddStep(text, body, stepType));
- }
- }
-}
View
23 src/Xbehave.Net40/IStepContext.cs
@@ -0,0 +1,23 @@
+// <copyright file="IStepContext.cs" company="xBehave.net contributors">
+// Copyright (c) xBehave.net contributors. All rights reserved.
+// </copyright>
+
+namespace Xbehave
+{
+ using System;
+ using System.Diagnostics.CodeAnalysis;
+
+ /// <summary>
+ /// A scenario step context.
+ /// </summary>
+ public interface IStepContext
+ {
+ /// <summary>
+ /// Immediately registers the <see cref="IDisposable"/> object for disposal after all steps in the current scenario have been executed.
+ /// </summary>
+ /// <param name="disposable">The object to be disposed.</param>
+ /// <returns>The current <see cref="IStepContext"/>.</returns>
+ [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Using", Justification = "Makes sense here.")]
+ IStepContext Using(IDisposable disposable);
+ }
+}
View
26 src/Xbehave.Net40/StepContext.cs
@@ -0,0 +1,26 @@
+// <copyright file="StepContext.cs" company="xBehave.net contributors">
+// Copyright (c) xBehave.net contributors. All rights reserved.
+// </copyright>
+
+namespace Xbehave
+{
+ using System;
+
+ internal partial class StepContext : IStepContext
+ {
+ private Sdk.Step step;
+
+ public void Assign(Sdk.Step step)
+ {
+ Guard.AgainstNullArgument("step", step);
+
+ this.step = step;
+ }
+
+ public IStepContext Using(IDisposable disposable)
+ {
+ this.step.AddDisposable(disposable);
+ return this;
+ }
+ }
+}
View
99 src/Xbehave.Net40/StepExtensions.cs
@@ -6,9 +6,6 @@ namespace Xbehave
{
using System;
using System.Diagnostics.CodeAnalysis;
-
- using Sdk;
-
using Xbehave.Fluent;
/// <summary>
@@ -29,11 +26,11 @@ public static partial class StepExtensions
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep When(this IStep stepDefinition, string text, Action body)
{
- return Helper.AddStep("When " + text, body, StepType.When);
+ return new Step("When " + text, body, StepType.When);
}
/// <summary>
@@ -49,11 +46,11 @@ public static IStep When(this IStep stepDefinition, string text, Action body)
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep Then(this IStep stepDefinition, string text, Action body)
{
- return Helper.AddStep("Then " + text, body, StepType.Then);
+ return new Step("Then " + text, body, StepType.Then);
}
/// <summary>
@@ -69,11 +66,11 @@ public static IStep Then(this IStep stepDefinition, string text, Action body)
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep And(this IStep stepDefinition, string text, Action body)
{
- return Helper.AddStep("And " + text, body, StepType.And);
+ return new Step("And " + text, body, StepType.And);
}
/// <summary>
@@ -89,11 +86,91 @@ public static IStep And(this IStep stepDefinition, string text, Action body)
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep But(this IStep stepDefinition, string text, Action body)
{
- return Helper.AddStep("But " + text, body, StepType.But);
+ return new Step("But " + text, body, StepType.But);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="stepDefinition">The step definition.</param>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "stepDefinition", Justification = "Part of fluent API.")]
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep When(this IStep stepDefinition, string text, Action<IStepContext> body)
+ {
+ return new Step("When " + text, body, StepType.When);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="stepDefinition">The step definition.</param>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "stepDefinition", Justification = "Part of fluent API.")]
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep Then(this IStep stepDefinition, string text, Action<IStepContext> body)
+ {
+ return new Step("Then " + text, body, StepType.Then);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="stepDefinition">The step definition.</param>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "stepDefinition", Justification = "Part of fluent API.")]
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep And(this IStep stepDefinition, string text, Action<IStepContext> body)
+ {
+ return new Step("And " + text, body, StepType.And);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="stepDefinition">The step definition.</param>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "stepDefinition", Justification = "Part of fluent API.")]
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep But(this IStep stepDefinition, string text, Action<IStepContext> body)
+ {
+ return new Step("But " + text, body, StepType.But);
}
}
}
View
113 src/Xbehave.Net40/StringExtensions.cs
@@ -22,7 +22,7 @@ public static partial class StringExtensions
/// </returns>
public static IStep Given(this string text, Action body)
{
- return Helper.AddStep(text, body, StepType.Given);
+ return new Step(text, body, StepType.Given);
}
/// <summary>
@@ -35,7 +35,7 @@ public static IStep Given(this string text, Action body)
/// </returns>
public static IStep When(this string text, Action body)
{
- return Helper.AddStep(text, body, StepType.When);
+ return new Step(text, body, StepType.When);
}
/// <summary>
@@ -48,7 +48,7 @@ public static IStep When(this string text, Action body)
/// </returns>
public static IStep Then(this string text, Action body)
{
- return Helper.AddStep(text, body, StepType.Then);
+ return new Step(text, body, StepType.Then);
}
/// <summary>
@@ -61,7 +61,7 @@ public static IStep Then(this string text, Action body)
/// </returns>
public static IStep And(this string text, Action body)
{
- return Helper.AddStep(text, body, StepType.And);
+ return new Step(text, body, StepType.And);
}
/// <summary>
@@ -74,7 +74,7 @@ public static IStep And(this string text, Action body)
/// </returns>
public static IStep But(this string text, Action body)
{
- return Helper.AddStep(text, body, StepType.But);
+ return new Step(text, body, StepType.But);
}
/// <summary>
@@ -91,7 +91,7 @@ public static IStep But(this string text, Action body)
public static IStep f(this string text, Action body)
{
var stepType = GetStepType(text);
- return Helper.AddStep(text, body, stepType);
+ return new Step(text, body, stepType);
}
/// <summary>
@@ -108,7 +108,106 @@ public static IStep f(this string text, Action body)
public static IStep _(this string text, Action body)
{
var stepType = GetStepType(text);
- return Helper.AddStep(text, body, stepType);
+ return new Step(text, body, stepType);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep Given(this string text, Action<IStepContext> body)
+ {
+ return new Step(text, body, StepType.Given);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep When(this string text, Action<IStepContext> body)
+ {
+ return new Step(text, body, StepType.When);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep Then(this string text, Action<IStepContext> body)
+ {
+ return new Step(text, body, StepType.Then);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep And(this string text, Action<IStepContext> body)
+ {
+ return new Step(text, body, StepType.And);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep But(this string text, Action<IStepContext> body)
+ {
+ return new Step(text, body, StepType.But);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "f", Justification = "Fluent API")]
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "f", Justification = "Fluent API")]
+ [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "Fluent API")]
+ public static IStep f(this string text, Action<IStepContext> body)
+ {
+ var stepType = GetStepType(text);
+ return new Step(text, body, stepType);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "_", Justification = "Fluent API")]
+ [SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", Justification = "Fluent API")]
+ [CLSCompliant(false)]
+ public static IStep _(this string text, Action<IStepContext> body)
+ {
+ var stepType = GetStepType(text);
+ return new Step(text, body, stepType);
}
/// <summary>
View
3  src/Xbehave.Net40/Xbehave.Net40.csproj
@@ -61,12 +61,13 @@
<Link>Properties\CommonAssemblyInfo.cs</Link>
</Compile>
<Compile Include="BackgroundAttribute.cs" />
+ <Compile Include="IStepContext.cs" />
<Compile Include="OmitArgumentsFromScenarioNamesAttribute.cs" />
<Compile Include="DisposableExtensions.cs" />
<Compile Include="ExampleAttribute.cs" />
<Compile Include="Guard.cs" />
- <Compile Include="Helper.cs" />
<Compile Include="ContinueOnFailureAfterAttribute.cs" />
+ <Compile Include="StepContext.cs" />
<Compile Include="StepExtensions.cs" />
<Compile Include="StepType.cs" />
<Compile Include="StringExtensions.cs" />
View
110 src/Xbehave.Net40/_.cs
@@ -27,11 +27,11 @@ public static partial class _
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep Given(string text, Action body)
{
- return Helper.AddStep("Given " + text, body, StepType.Given);
+ return new Step("Given " + text, body, StepType.Given);
}
/// <summary>
@@ -45,11 +45,11 @@ public static IStep Given(string text, Action body)
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep When(string text, Action body)
{
- return Helper.AddStep("When " + text, body, StepType.When);
+ return new Step("When " + text, body, StepType.When);
}
/// <summary>
@@ -63,11 +63,11 @@ public static IStep When(string text, Action body)
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep Then(string text, Action body)
{
- return Helper.AddStep("Then " + text, body, StepType.Then);
+ return new Step("Then " + text, body, StepType.Then);
}
/// <summary>
@@ -81,11 +81,11 @@ public static IStep Then(string text, Action body)
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep And(string text, Action body)
{
- return Helper.AddStep("And " + text, body, StepType.And);
+ return new Step("And " + text, body, StepType.And);
}
/// <summary>
@@ -99,11 +99,101 @@ public static IStep And(string text, Action body)
[SuppressMessage(
"Microsoft.Globalization",
"CA1303:Do not pass literals as localized parameters",
- MessageId = "Xbehave.Helper.AddStep(System.String,System.Action)",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
Justification = "Text must match method name.")]
public static IStep But(string text, Action body)
{
- return Helper.AddStep("But " + text, body, StepType.But);
+ return new Step("But " + text, body, StepType.But);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep Given(string text, Action<IStepContext> body)
+ {
+ return new Step("Given " + text, body, StepType.Given);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep When(string text, Action<IStepContext> body)
+ {
+ return new Step("When " + text, body, StepType.When);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep Then(string text, Action<IStepContext> body)
+ {
+ return new Step("Then " + text, body, StepType.Then);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep And(string text, Action<IStepContext> body)
+ {
+ return new Step("And " + text, body, StepType.And);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage(
+ "Microsoft.Globalization",
+ "CA1303:Do not pass literals as localized parameters",
+ MessageId = "Xbehave.new Step(System.String,System.Action)",
+ Justification = "Text must match method name.")]
+ public static IStep But(string text, Action<IStepContext> body)
+ {
+ return new Step("But " + text, body, StepType.But);
}
}
}
View
18 src/Xbehave.Net45/Helper.Async.cs
@@ -1,18 +0,0 @@
-// <copyright file="Helper.Async.cs" company="xBehave.net contributors">
-// Copyright (c) xBehave.net contributors. All rights reserved.
-// </copyright>
-
-namespace Xbehave
-{
- using System;
- using System.Threading.Tasks;
- using Xbehave.Sdk;
-
- internal static partial class Helper
- {
- public static Fluent.IStep AddStep(string text, Func<Task> body, StepType stepType)
- {
- return new Fluent.Step(CurrentScenario.AddStep(text, body, stepType));
- }
- }
-}
View
113 src/Xbehave.Net45/StringExtensions.Async.cs
@@ -24,7 +24,7 @@ public static partial class StringExtensions
/// </returns>
public static IStep Given(this string text, Func<Task> body)
{
- return Helper.AddStep(text, body, StepType.Given);
+ return new Step(text, body, StepType.Given);
}
/// <summary>
@@ -37,7 +37,7 @@ public static IStep Given(this string text, Func<Task> body)
/// </returns>
public static IStep When(this string text, Func<Task> body)
{
- return Helper.AddStep(text, body, StepType.When);
+ return new Step(text, body, StepType.When);
}
/// <summary>
@@ -50,7 +50,7 @@ public static IStep When(this string text, Func<Task> body)
/// </returns>
public static IStep Then(this string text, Func<Task> body)
{
- return Helper.AddStep(text, body, StepType.Then);
+ return new Step(text, body, StepType.Then);
}
/// <summary>
@@ -63,7 +63,7 @@ public static IStep Then(this string text, Func<Task> body)
/// </returns>
public static IStep And(this string text, Func<Task> body)
{
- return Helper.AddStep(text, body, StepType.And);
+ return new Step(text, body, StepType.And);
}
/// <summary>
@@ -76,7 +76,7 @@ public static IStep And(this string text, Func<Task> body)
/// </returns>
public static IStep But(this string text, Func<Task> body)
{
- return Helper.AddStep(text, body, StepType.But);
+ return new Step(text, body, StepType.But);
}
/// <summary>
@@ -93,7 +93,7 @@ public static IStep But(this string text, Func<Task> body)
public static IStep f(this string text, Func<Task> body)
{
var stepType = StringExtensions.GetStepType(text);
- return Helper.AddStep(text, body, stepType);
+ return new Step(text, body, stepType);
}
/// <summary>
@@ -110,7 +110,106 @@ public static IStep f(this string text, Func<Task> body)
public static IStep _(this string text, Func<Task> body)
{
var stepType = StringExtensions.GetStepType(text);
- return Helper.AddStep(text, body, stepType);
+ return new Step(text, body, stepType);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep Given(this string text, Func<IStepContext, Task> body)
+ {
+ return new Step(text, body, StepType.Given);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep When(this string text, Func<IStepContext, Task> body)
+ {
+ return new Step(text, body, StepType.When);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep Then(this string text, Func<IStepContext, Task> body)
+ {
+ return new Step(text, body, StepType.Then);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep And(this string text, Func<IStepContext, Task> body)
+ {
+ return new Step(text, body, StepType.And);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ public static IStep But(this string text, Func<IStepContext, Task> body)
+ {
+ return new Step(text, body, StepType.But);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "f", Justification = "Fluent API")]
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "f", Justification = "Fluent API")]
+ [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules", "SA1300:ElementMustBeginWithUpperCaseLetter", Justification = "Fluent API")]
+ public static IStep f(this string text, Func<IStepContext, Task> body)
+ {
+ var stepType = StringExtensions.GetStepType(text);
+ return new Step(text, body, stepType);
+ }
+
+ /// <summary>
+ /// Defines a step in the current scenario.
+ /// </summary>
+ /// <param name="text">The step text.</param>
+ /// <param name="body">The action that will perform the step.</param>
+ /// <returns>
+ /// An instance of <see cref="IStep"/>.
+ /// </returns>
+ [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "_", Justification = "Fluent API")]
+ [SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores", Justification = "Fluent API")]
+ [CLSCompliant(false)]
+ public static IStep _(this string text, Func<IStepContext, Task> body)
+ {
+ var stepType = StringExtensions.GetStepType(text);
+ return new Step(text, body, stepType);
}
}
}
View
8 src/Xbehave.Net45/Xbehave.Net45.csproj
@@ -76,8 +76,8 @@
<Compile Include="..\Xbehave.Net40\Fluent\Step.cs">
<Link>Fluent\Step.cs</Link>
</Compile>
- <Compile Include="..\Xbehave.Net40\Helper.cs">
- <Link>Helper.cs</Link>
+ <Compile Include="..\Xbehave.Net40\IStepContext.cs">
+ <Link>IStepContext.cs</Link>
</Compile>
<Compile Include="..\Xbehave.Net40\OmitArgumentsFromScenarioNamesAttribute.cs">
<Link>OmitArgumentsFromScenarioNamesAttribute.cs</Link>
@@ -94,6 +94,9 @@
<Compile Include="..\Xbehave.Net40\ScenarioAttribute.cs">
<Link>ScenarioAttribute.cs</Link>
</Compile>
+ <Compile Include="..\Xbehave.Net40\StepContext.cs">
+ <Link>StepContext.cs</Link>
+ </Compile>
<Compile Include="..\Xbehave.Net40\StepExtensions.cs">
<Link>StepExtensions.cs</Link>
</Compile>
@@ -108,7 +111,6 @@
</Compile>
<Compile Include="StringExtensions.Async.cs" />
<Compile Include="Guard.cs" />
- <Compile Include="Helper.Async.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\Xbehave.snk">
View
19 src/Xbehave.Sdk.Net40/Step.cs
@@ -17,6 +17,7 @@ public abstract partial class Step
{
private readonly string name;
private readonly object stepType;
+ private readonly List<IDisposable> disposables = new List<IDisposable>();
private readonly List<Action> teardowns = new List<Action>();
public Step(string name, object stepType)
@@ -36,6 +37,16 @@ public object StepType
get { return this.stepType; }
}
+ public IEnumerable<IDisposable> ExtractDisposables
+ {
+ get
+ {
+ var extracted = this.disposables.ToArray();
+ this.disposables.Clear();
+ return extracted;
+ }
+ }
+
public IEnumerable<Action> Teardowns
{
get { return this.teardowns.Select(x => x); }
@@ -47,6 +58,14 @@ public IEnumerable<Action> Teardowns
public int MillisecondsTimeout { get; set; }
+ public void AddDisposable(IDisposable disposable)
+ {
+ if (disposable != null)
+ {
+ this.disposables.Add(disposable);
+ }
+ }
+
public void AddTeardown(Action teardown)
{
if (teardown != null)
View
8 src/Xbehave.Sdk.Net40/SyncStep.cs
@@ -50,7 +50,6 @@ public override void Execute()
}
finally
{
- teardowns = CurrentScenario.ExtractTeardowns();
SynchronizationContext.SetSynchronizationContext(oldSyncContext);
@event.Set();
}
@@ -70,7 +69,12 @@ public override void Execute()
}
finally
{
- foreach (var teardown in teardowns.Concat(this.Teardowns))
+ foreach (var disposable in this.ExtractDisposables)
+ {
+ CurrentScenario.AddTeardown(() => disposable.Dispose());
+ }
+
+ foreach (var teardown in this.Teardowns)
{
CurrentScenario.AddTeardown(teardown);
}
View
5 src/Xbehave.Sdk.Net45/AsyncStep.cs
@@ -35,6 +35,11 @@ public override void Execute()
}
finally
{
+ foreach (var disposable in this.ExtractDisposables)
+ {
+ CurrentScenario.AddTeardown(() => disposable.Dispose());
+ }
+
foreach (var teardown in this.Teardowns)
{
CurrentScenario.AddTeardown(teardown);
View
98 src/test/Xbehave.Features.Net40/ObjectDisposalFeature.cs
@@ -9,6 +9,7 @@ namespace Xbehave.Test.Acceptance
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
+ using System.Threading.Tasks;
using FluentAssertions;
using Xbehave.Test.Acceptance.Infrastructure;
using Xunit.Sdk;
@@ -213,6 +214,31 @@ public static void FailureToCompleteAStep()
.And(() => DisposableObjectsShouldEachHaveBeenDisposedOnceInReverseOrder());
}
+#if NET45
+ [Scenario]
+ public static void RegisteringManyDisposableObjectsInAnAsyncStep()
+ {
+ var feature = default(Type);
+ var results = default(MethodResult[]);
+
+ "Given a step which registers many disposable objects in an async step"
+ .Given(() => feature = typeof(AsyncStep));
+
+ "When running the scenario"
+ .When(() => results = TestRunner.Run(feature).ToArray())
+ .Teardown(Disposable.ClearRecordedEvents);
+
+ "Then there should be no failures"
+ .Then(() => results.Should().NotContain(result => result is FailedResult));
+
+ "And some disposable objects should have been created"
+ .And(() => SomeDisposableObjectsShouldHaveBeenCreated());
+
+ "And the disposable objects should each have been disposed once in reverse order"
+ .And(() => DisposableObjectsShouldEachHaveBeenDisposedOnceInReverseOrder());
+ }
+#endif
+
private static AndConstraint<FluentAssertions.Collections.GenericCollectionAssertions<LifetimeEvent>> SomeDisposableObjectsShouldHaveBeenCreated()
{
return Disposable.RecordedEvents.Where(@event => @event.EventType == LifeTimeEventType.Constructed).Should().NotBeEmpty();
@@ -246,11 +272,11 @@ public static void Scenario()
var disposable2 = default(Disposable);
"Given some disposables"
- .Given(() =>
+ .Given(c =>
{
- disposable0 = new Disposable().Using();
- disposable1 = new Disposable().Using();
- disposable2 = new Disposable().Using();
+ disposable0 = new Disposable().Using(c);
+ disposable1 = new Disposable().Using(c);
+ disposable2 = new Disposable().Using(c);
});
"When using the disposables"
@@ -273,11 +299,11 @@ public static void Scenario()
var disposable2 = default(BadDisposable);
"Given some disposables"
- .Given(() =>
+ .Given(c =>
{
- disposable0 = new BadDisposable().Using();
- disposable1 = new BadDisposable().Using();
- disposable2 = new BadDisposable().Using();
+ disposable0 = new BadDisposable().Using(c);
+ disposable1 = new BadDisposable().Using(c);
+ disposable2 = new BadDisposable().Using(c);
});
"When using the disposables"
@@ -300,11 +326,11 @@ public static void Scenario()
var disposable2 = default(SingleRecursionBadDisposable);
"Given some disposables"
- .Given(() =>
+ .Given(c =>
{
- disposable0 = new SingleRecursionBadDisposable().Using();
- disposable1 = new SingleRecursionBadDisposable().Using();
- disposable2 = new SingleRecursionBadDisposable().Using();
+ disposable0 = new SingleRecursionBadDisposable().Using(c);
+ disposable1 = new SingleRecursionBadDisposable().Using(c);
+ disposable2 = new SingleRecursionBadDisposable().Using(c);
});
"When using the disposables"
@@ -327,13 +353,13 @@ public static void Scenario()
var disposable2 = default(Disposable);
"Given a disposable"
- .Given(() => disposable0 = new Disposable().Using());
+ .Given(c => disposable0 = new Disposable().Using(c));
"And another disposable"
- .Given(() => disposable1 = new Disposable().Using());
+ .Given(c => disposable1 = new Disposable().Using(c));
"And another disposable"
- .Given(() => disposable2 = new Disposable().Using());
+ .Given(c => disposable2 = new Disposable().Using(c));
"When using the disposables"
.When(() =>
@@ -353,7 +379,7 @@ public static void Scenario()
var disposable0 = default(Disposable);
"Given a disposable"
- .Given(() => disposable0 = new Disposable().Using());
+ .Given(c => disposable0 = new Disposable().Using(c));
"When using the disposable"
.When(() => disposable0.Use());
@@ -377,13 +403,13 @@ public static void Scenario()
var disposable2 = default(Disposable);
"Given a disposable"
- .Given(() => disposable0 = new Disposable().Using());
+ .Given(c => disposable0 = new Disposable().Using(c));
"And another disposable"
- .Given(() => disposable1 = new Disposable().Using());
+ .Given(c => disposable1 = new Disposable().Using(c));
"And another disposable"
- .Given(() => disposable2 = new Disposable().Using());
+ .Given(c => disposable2 = new Disposable().Using(c));
"When using the disposables"
.When(() =>
@@ -404,16 +430,42 @@ private static class StepFailsToComplete
public static void Scenario()
{
"Given some disposables"
- .Given(() =>
+ .Given(c =>
{
- new Disposable().Using();
- new Disposable().Using();
- new Disposable().Using();
+ new Disposable().Using(c);
+ new Disposable().Using(c);
+ new Disposable().Using(c);
throw new InvalidOperationException();
});
}
}
+#if NET45
+ private static class AsyncStep
+ {
+ [Scenario]
+ public static void Scenario(Disposable disposable0, Disposable disposable1, Disposable disposable2)
+ {
+ "Given some disposables"
+ .Given(async c =>
+ {
+ await Task.Yield();
+ disposable0 = new Disposable().Using(c);
+ disposable1 = new Disposable().Using(c);
+ disposable2 = new Disposable().Using(c);
+ });
+
+ "When using the disposables"
+ .When(() =>
+ {
+ disposable0.Use();
+ disposable1.Use();
+ disposable2.Use();
+ });
+ }
+ }
+#endif
+
private class Disposable : IDisposable
{
private static readonly ConcurrentQueue<LifetimeEvent> Events = new ConcurrentQueue<LifetimeEvent>();
View
16 src/test/Xbehave.Features.Net40/TeardownFeature.cs
@@ -337,11 +337,11 @@ private static class TeardownsAndDisposables
public static void Scenario()
{
"Given something"
- .Given(() =>
+ .Given(c =>
{
- new Disposable(1).Using();
- new Disposable(2).Using();
- new Disposable(3).Using();
+ new Disposable(1).Using(c);
+ new Disposable(2).Using(c);
+ new Disposable(3).Using(c);
})
.Teardown(() => ActionIds.Enqueue(4))
.And()
@@ -350,11 +350,11 @@ public static void Scenario()
.Teardown(() => ActionIds.Enqueue(6));
"And something else"
- .And(() =>
+ .And(c =>
{
- new Disposable(7).Using();
- new Disposable(8).Using();
- new Disposable(9).Using();
+ new Disposable(7).Using(c);
+ new Disposable(8).Using(c);
+ new Disposable(9).Using(c);
})
.Teardown(() => ActionIds.Enqueue(10))
.And()
Something went wrong with that request. Please try again.