Permalink
Browse files

Making it easier to wait on CLR4 Tasks. Closes #90 and #91.

  • Loading branch information...
1 parent 869adeb commit ffd672e3edfc65accdf8fb727216d41ae5f87f92 @agross agross committed Feb 2, 2012
View
@@ -88,6 +88,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{A3F866
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Machine.Specifications.WebDriverSupport", "Source\Machine.Specifications.WebDriverSupport\Machine.Specifications.WebDriverSupport.csproj", "{0029D44B-6E6C-4FD5-9071-EEA15A765D37}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Machine.Specifications.Clr4", "Source\Machine.Specifications.Clr4\Machine.Specifications.Clr4.csproj", "{4F5B8F3D-21FE-46AE-9D45-4E1ED891F4DF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Machine.Specifications.Clr4.Specs", "Source\Machine.Specifications.Clr4.Specs\Machine.Specifications.Clr4.Specs.csproj", "{8B6A3294-62DB-4838-AF2F-F107A1CC1926}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -214,6 +218,14 @@ Global
{0029D44B-6E6C-4FD5-9071-EEA15A765D37}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0029D44B-6E6C-4FD5-9071-EEA15A765D37}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0029D44B-6E6C-4FD5-9071-EEA15A765D37}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4F5B8F3D-21FE-46AE-9D45-4E1ED891F4DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4F5B8F3D-21FE-46AE-9D45-4E1ED891F4DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4F5B8F3D-21FE-46AE-9D45-4E1ED891F4DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4F5B8F3D-21FE-46AE-9D45-4E1ED891F4DF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B6A3294-62DB-4838-AF2F-F107A1CC1926}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B6A3294-62DB-4838-AF2F-F107A1CC1926}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B6A3294-62DB-4838-AF2F-F107A1CC1926}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B6A3294-62DB-4838-AF2F-F107A1CC1926}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{8B6A3294-62DB-4838-AF2F-F107A1CC1926}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Machine.Specifications.Clr4.Specs</RootNamespace>
+ <AssemblyName>Machine.Specifications.Clr4.Specs</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\Build\Debug\Tests\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\Build\Release\Tests\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\SharedAssemblyInfo.cs">
+ <Link>Properties\SharedAssemblyInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\VersionInfo.cs">
+ <Link>Properties\VersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="TaskSpecificationExtensionsSpecs.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Machine.Specifications.Clr4\Machine.Specifications.Clr4.csproj">
+ <Project>{4F5B8F3D-21FE-46AE-9D45-4E1ED891F4DF}</Project>
+ <Name>Machine.Specifications.Clr4</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Machine.Specifications\Machine.Specifications.csproj">
+ <Project>{CCD02629-1262-4F78-9E9F-AC97B942D0E7}</Project>
+ <Name>Machine.Specifications</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
@@ -0,0 +1,21 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyTitle("Machine.Specifications.Clr4.Specs")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+
+[assembly: Guid("3a951a05-4fad-47b2-a049-1d009bd8cf78")]
@@ -0,0 +1,95 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Machine.Specifications.Clr4.Specs
+{
+ public static class Delayed
+ {
+ static readonly TimeSpan WaitTimeout = TimeSpan.FromMilliseconds(500);
+
+ public static Task<string> Echo(string toEcho)
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ Thread.Sleep(WaitTimeout);
+
+ return toEcho;
+ });
+ }
+
+ public static Task Fail()
+ {
+ return Task.Factory.StartNew(() =>
+ {
+ Thread.Sleep(WaitTimeout);
+
+ throw new InvalidOperationException("something went wrong");
+
+ });
+ }
+
+ public static Task MultipleFails()
+ {
+ return Task.Factory.StartNew(() => Task.WaitAll(Fail(), Fail()));
+ }
+ }
+
+ [Subject(typeof(TaskSpecificationExtensions))]
+ public class when_an_async_operation_runs_without_await
+ {
+ static Task<string> Result;
+
+ Because of = () => { Result = Delayed.Echo("result"); };
+
+ It should_not_wait_for_completion =
+ () => Result.IsCompleted.ShouldBeFalse();
+ }
+
+ [Subject(typeof(TaskSpecificationExtensions))]
+ public class when_an_async_operation_runs_with_await
+ {
+ static string Result;
+
+ Because of = () => { Result = Delayed.Echo("result").Await(); };
+
+ It should_wait_for_completion =
+ () => Result.ShouldEqual("result");
+ }
+
+ [Subject(typeof(TaskSpecificationExtensions), "exception")]
+ public class when_an_async_operation_fails_without_await
+ {
+ static Exception Exception;
+
+ Because of = () => Exception = Catch.Exception(() => Delayed.Fail());
+
+ It should_not_capture_the_exception =
+ () => Exception.ShouldBeNull();
+ }
+
+ [Subject(typeof(TaskSpecificationExtensions), "exception")]
+ public class when_a_single_async_operation_fails_with_await
+ {
+ static Exception Exception;
+
+ Because of = () => Exception = Catch.Exception(() => Delayed.Fail().Await());
+
+ It should_capture_the_first_exception =
+ () => Exception.ShouldBeOfType<InvalidOperationException>();
+ }
+
+ [Subject(typeof(TaskSpecificationExtensions), "exception")]
+ public class when_multiple_async_operations_fail_with_await
+ {
+ static Exception Exception;
+
+ Because of = () => Exception = Catch.Exception(() => Delayed.MultipleFails().Await());
+
+ It should_capture_the_aggregate_exception =
+ () => Exception.ShouldBeOfType<AggregateException>();
+
+ It should_capture_all_inner_exceptions =
+ () => ((AggregateException) Exception).InnerExceptions.Count.ShouldEqual(2);
+ }
+}
@@ -0,0 +1,39 @@
+using System.Threading.Tasks;
+
+namespace Machine.Specifications
+{
+ public class AwaitResult
+ {
+ readonly Task _task;
+
+ public AwaitResult(Task task)
+ {
+ _task = task;
+ }
+
+ public Task AsTask
+ {
+ get { return _task; }
+ }
+ }
+
+ public class AwaitResult<T>
+ {
+ readonly Task<T> _task;
+
+ public AwaitResult(Task<T> task)
+ {
+ _task = task;
+ }
+
+ public Task<T> AsTask
+ {
+ get { return _task; }
+ }
+
+ public static implicit operator T(AwaitResult<T> m)
+ {
+ return m._task.Result;
+ }
+ }
+}
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{4F5B8F3D-21FE-46AE-9D45-4E1ED891F4DF}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Machine.Specifications</RootNamespace>
+ <AssemblyName>Machine.Specifications.Clr4</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Microsoft.CSharp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\SharedAssemblyInfo.cs">
+ <Link>Properties\SharedAssemblyInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\VersionInfo.cs">
+ <Link>Properties\VersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="AwaitResult.cs" />
+ <Compile Include="TaskSpecificationExtensions.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
@@ -0,0 +1,18 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Machine.Specifications.Clr4")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f501eefc-0b39-4082-928a-2bc3fa4d4338")]
@@ -0,0 +1,45 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Machine.Specifications
+{
+ public static class TaskSpecificationExtensions
+ {
+ public static AwaitResult<T> Await<T>(this Task<T> task)
+ {
+ try
+ {
+ task.Wait();
+ }
+ catch (AggregateException ex)
+ {
+ if (ex.InnerExceptions.Count == 1)
+ {
+ throw ex.InnerExceptions.First();
+ }
+ throw;
+ }
+
+ return new AwaitResult<T>(task);
+ }
+
+ public static AwaitResult Await(this Task task)
+ {
+ try
+ {
+ task.Wait();
+ }
+ catch (AggregateException ex)
+ {
+ if (ex.InnerExceptions.Count == 1)
+ {
+ throw ex.InnerExceptions.First();
+ }
+ throw;
+ }
+
+ return new AwaitResult(task);
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit ffd672e

Please sign in to comment.