-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This reverts most of the changes made in v3 & v4. Mainly, this gets rid of the custom test runner and relies on xunit's built-in test-running logic. This will eliminate flakiness in some of our builds. Also removing the ISpecification interface and instead relying on AsyncSpecification & Specification base classes. Updating documentation to reflect the new state of things. +semver:major
- Loading branch information
Showing
26 changed files
with
132 additions
and
883 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,93 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Xunit.Extensions | ||
{ | ||
/// <summary> | ||
/// The base async specification class | ||
/// </summary> | ||
public abstract class AsyncSpecification : ISpecification, IAsyncLifetime | ||
public abstract class AsyncSpecification : IAsyncLifetime | ||
{ | ||
Exception exception; | ||
static readonly ReaderWriterLockSlim sync = new ReaderWriterLockSlim(); | ||
static readonly Dictionary<Type, bool> typeCache = new Dictionary<Type, bool>(); | ||
|
||
/// <summary> | ||
/// The exception that was thrown when Observe was run; null if no exception was thrown. | ||
/// </summary> | ||
public Exception ThrownException { get; set; } | ||
protected Exception ThrownException => exception; | ||
|
||
public virtual Task InitializeAsync() | ||
{ | ||
return Task.FromResult(0); | ||
} | ||
/// <summary> | ||
/// Initialize the test class all async-like. | ||
/// </summary> | ||
public virtual Task InitializeAsync() => CommonTasks.Completed; | ||
|
||
/// <summary> | ||
/// Performs an action, the outcome of which will be observed to validate the specification. | ||
/// Performs the action to observe the outcome of to validate the specification. | ||
/// </summary> | ||
public abstract Task ObserveAsync(); | ||
|
||
public virtual Task DisposeAsync() | ||
/// <summary> | ||
/// Cleanup the test class all async-like. | ||
/// </summary> | ||
public virtual Task DisposeAsync() => CommonTasks.Completed; | ||
|
||
async Task IAsyncLifetime.InitializeAsync() | ||
{ | ||
return Task.FromResult(0); | ||
await InitializeAsync(); | ||
|
||
try | ||
{ | ||
await ObserveAsync(); | ||
} | ||
catch (Exception ex) | ||
{ | ||
if (!HandleException(ex)) | ||
throw; | ||
} | ||
} | ||
|
||
bool HandleException(Exception ex) | ||
{ | ||
exception = ex; | ||
return ShouldHandleException(); | ||
} | ||
|
||
bool ShouldHandleException() | ||
{ | ||
Type type = GetType(); | ||
|
||
try | ||
{ | ||
sync.EnterReadLock(); | ||
|
||
if (typeCache.ContainsKey(type)) | ||
return typeCache[type]; | ||
} | ||
finally | ||
{ | ||
sync.ExitReadLock(); | ||
} | ||
|
||
try | ||
{ | ||
sync.EnterWriteLock(); | ||
|
||
if (typeCache.ContainsKey(type)) | ||
return typeCache[type]; | ||
|
||
var attrs = type.GetTypeInfo().GetCustomAttributes(typeof(HandleExceptionsAttribute), true).OfType<HandleExceptionsAttribute>(); | ||
|
||
return typeCache[type] = attrs.Any(); | ||
} | ||
finally | ||
{ | ||
sync.ExitWriteLock(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
using System.Threading.Tasks; | ||
|
||
namespace Xunit.Extensions | ||
{ | ||
static class CommonTasks | ||
{ | ||
public static readonly Task Completed = Task.FromResult(0); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,9 @@ | ||
using System; | ||
using Xunit; | ||
|
||
[assembly: TestFramework("Xunit.Extensions.ObservationTestFramework", "Xunit.Bdd")] | ||
|
||
namespace Xunit.Extensions | ||
namespace Xunit.Extensions | ||
{ | ||
/// <summary> | ||
/// Identifies a method as an observation which asserts the specification | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Method)] | ||
public class ObservationAttribute : Attribute | ||
public class ObservationAttribute : FactAttribute | ||
{ | ||
/// <summary> | ||
/// Marks the test so that it will not be run, and gets or sets the skip reason | ||
/// </summary> | ||
public string Skip { get; set; } | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.