Commits

Johannes Rudolph committed c902806

Breaking Change: Observations do now execute with a separate setup and teardown.

Comments (0)

Files changed (17)

src/SubSpec/AssertExecutor.cs

 
 namespace SubSpec
 {
-    internal class AssertExecutor
-    {
+	internal class AssertExecutor
+	{
         private readonly List<SpecificationPrimitive<Action>> _asserts;
         private readonly SpecificationPrimitive<ContextDelegate> _context;
         private readonly SpecificationPrimitive<Action> _do;
 
-        public AssertExecutor(SpecificationPrimitive<ContextDelegate> context, SpecificationPrimitive<Action> @do, List<SpecificationPrimitive<Action>> asserts)
+        public AssertExecutor(SpecificationPrimitive<ContextDelegate> context, SpecificationPrimitive<Action> @do,  List<SpecificationPrimitive<Action>> asserts )
         {
             _asserts = asserts;
             _context = context;
             _do = @do;
         }
 
-        internal class AssertCommand : DelegatingTestCommand
-        {
-            private readonly SpecificationPrimitive<ContextDelegate> _context;
+		public IEnumerable<ITestCommand> AssertCommands(string name, IMethodInfo method)
+		{
+			foreach (var assertion in _asserts)
+			{
+				// do not capture the iteration variable because 
+				// all tests would point to the same assertion
+				var capturableAssertion = assertion;
+				Action test =
+					() =>
+					{
+						using (_context.Execute())
+						{
+                            if (_do != null)
+                                _do.Execute();
 
-            public AssertCommand(SpecificationPrimitive<ContextDelegate> context, ActionTestCommand assert)
-                : base(assert)
-            {
-                _context = context;
-            }
+                            capturableAssertion.Execute();
+						}
+					};
 
-            public override MethodResult Execute(object testClass)
-            {
-                bool testExceptionThrown = false;
+				string testDescription = String.Format("{0}, {1}", name, assertion.Message);
 
-                IDisposable sut = null;
-                try
-                {
-                    sut = _context.Execute();
-
-                    return InnerCommand.Execute(testClass);
-                }
-                catch
-                {
-                    testExceptionThrown = true;
-                    throw;
-                }
-                finally
-                {
-                    List<Exception> afterExceptions = new List<Exception>();
-
-                    try
-                    {
-                        sut.Dispose();
-                    }
-                    catch (Exception ex)
-                    {
-                        afterExceptions.Add(ex);
-                    }
-
-                    if (!testExceptionThrown && afterExceptions.Count > 0)
-                        throw new AfterTestException(afterExceptions);
-                }
-
-            }
-        }
-
-        public IEnumerable<ITestCommand> AssertCommands(string name, IMethodInfo method)
-        {
-            foreach (var assertion in _asserts)
-            {
-                // do not capture the iteration variable because 
-                // all tests would point to the same assertion
-                var capturableAssertion = assertion;
-                Action executeAndAssert =
-                    () =>
-                    {
-                        if (_do != null)
-                            _do.Execute();
-
-                        capturableAssertion.Execute();
-                    };
-
-                string testDescription = String.Format("{0}, {1}", name, assertion.Message);
-
-                ActionTestCommand assert = new ActionTestCommand(method, testDescription, MethodUtility.GetTimeoutParameter(method), executeAndAssert);
-
-                yield return new AssertCommand(_context, assert); ;
-            }
-        }
-    }
+				yield return new ActionTestCommand(method, testDescription, MethodUtility.GetTimeoutParameter(method), test);
+			}
+		}
+	}
 }

src/SubSpec/ContextSetupFailureException.cs

+using System;
+
+namespace SubSpec
+{
+    /// <summary>
+    /// An exception that is thrown from Observations or their teardown whenever the corresponding setup failed.
+    /// </summary>
+#if !SILVERLIGHT
+    [Serializable]
+#endif
+    public class ContextSetupFailedException : Exception
+    {
+        public ContextSetupFailedException( string message ) : base( message ) { }
+
+#if !SILVERLIGHT
+        protected ContextSetupFailedException(
+          System.Runtime.Serialization.SerializationInfo info,
+          System.Runtime.Serialization.StreamingContext context )
+            : base( info, context ) { }
+#endif
+    }
+}

src/SubSpec/ObservationExecutor.cs

         private IDisposable _systemUnderTest;
 
 
-        public ObservationExecutor( SpecificationPrimitive<ContextDelegate> context, SpecificationPrimitive<Action> @do, Func<IEnumerable<SpecificationPrimitive<Action>>> observations )
+        public ObservationExecutor(SpecificationPrimitive<ContextDelegate> context, SpecificationPrimitive<Action> @do, Func<IEnumerable<SpecificationPrimitive<Action>>> observations)
         {
             _observations = observations;
             _context = context;
             _systemUnderTest = null;
         }
 
-        private MethodResult Setup( IMethodInfo method )
+        private static MethodResult ExecuteActionCommand(IMethodInfo method, string name, Action setupAction)
         {
-            Action setupAction =
-                () =>
-                {
-                    try
-                    {
-                        _systemUnderTest = _context.Execute();
+            ITestCommand wrappedCommand = new ActionTestCommand(method, name, MethodUtility.GetTimeoutParameter(method), setupAction); ;
 
-                        if (_do != null)
-                            _do.Execute();
-                    }
-                    catch (Exception)
-                    {
-                        if (_systemUnderTest != null)
-                            QuietDispose( _systemUnderTest );
+            wrappedCommand = new ExceptionAndOutputCaptureCommand(wrappedCommand, method);
+            wrappedCommand = new TimedCommand(wrappedCommand);
 
-                        throw;
-                    }
-                };
-
-            return ExecuteActionCommand( method, setupAction );
+            return wrappedCommand.Execute(null);
         }
 
-        private MethodResult TearDown( IMethodInfo method )
+        public IEnumerable<ITestCommand> ObservationCommands(string name, IMethodInfo method)
         {
-            Action tearDownAction =
-             () =>
-             {
-                 if (_systemUnderTest != null)
-                     _systemUnderTest.Dispose();
-             };
+            if (_observations().Count() == 0)
+                yield break;
 
-            return ExecuteActionCommand( method, tearDownAction );
-        }
+            bool setupExceptionOccurred = false;
 
-        private static MethodResult ExecuteActionCommand( IMethodInfo method, Action setupAction )
-        {
-            ITestCommand wrappedCommand = new ActionTestCommand( method, "", MethodUtility.GetTimeoutParameter( method ), setupAction ); ;
+            Action setupAction = () =>
+            {
+                try
+                {
+                    _systemUnderTest = _context.Execute();
 
-            wrappedCommand = new ExceptionAndOutputCaptureCommand( wrappedCommand, method );
-            wrappedCommand = new TimedCommand( wrappedCommand );
+                    if (_do != null)
+                        _do.Execute();
+                }
+                catch (Exception)
+                {
+                    setupExceptionOccurred = true;
+                    throw;
+                }
+            };
 
-            return wrappedCommand.Execute( null );
-        }
+            yield return new ActionTestCommand(method, "{ Context: " + name, 0, setupAction);
 
-        public IEnumerable<ITestCommand> ObservationCommands( string name, IMethodInfo method )
-        {
-            var setupResult = Setup( method );
-            if (setupResult is FailedResult)
+
+            foreach (var observation in _observations())
             {
-                int observationCount = _observations().Count();
-                // Mark all observations failed
-                for (int i = 0; i < observationCount; i++)
-                {
-                    yield return new FixedResultCommand(method, setupResult);
-                }
+                Action perform = () =>
+                                 {
+                                     if (setupExceptionOccurred)
+                                         throw new ContextSetupFailedException( "Setting up Context failed" );
 
-                yield break;
+                                     observation.Execute();
+                                 };
+
+                yield return new ActionTestCommand(method, "\tObservation: " + observation.Message, 0, perform);
             }
 
-            MethodResult tearDownResult = null;
-            try
+            Action tearDownAction = () =>
             {
-                foreach (var observation in _observations())
-                {
-                    string testDescription = String.Format( "{0}, {1}", name, observation.Message );
-                    Action perform = () =>
-                                     {
-                                         ReplayOutputFromSetup( setupResult );
-                                         observation.Execute();
-                                     };
+                if (_systemUnderTest != null)
+                    _systemUnderTest.Dispose();
 
-                    yield return new ActionTestCommand( method, testDescription, MethodUtility.GetTimeoutParameter( method ), perform );
-                }
-            }
-            finally
-            {
-                tearDownResult = TearDown( method );
-            }
+                if (setupExceptionOccurred)
+                    throw new ContextSetupFailedException( "Setting up Context failed, but Fixtures were disposed." );
+            };
 
-            if (tearDownResult is FailedResult)
-                yield return new FixedResultCommand( method, tearDownResult );
-        }
-
-        private static void ReplayOutputFromSetup( MethodResult setupResult )
-        {
-            Console.Write( setupResult.Output );
-        }
-
-        private static void QuietDispose( IDisposable context )
-        {
-            try
-            {
-                context.Dispose();
-            }
-            catch
-            { }
+            yield return new ActionTestCommand(method, "} TearDown: " + name, 0, tearDownAction);
         }
     }
-}
+}

src/SubSpec/SubSpec.csproj

     <Compile Include="AssertExecutor.cs" />
     <Compile Include="CompositeFixture.cs" />
     <Compile Include="ContextDelegate.cs" />
+    <Compile Include="ContextSetupFailureException.cs" />
     <Compile Include="Expression\SpecificationExpression.cs" />
     <Compile Include="Expression\Verifications.cs" />
     <Compile Include="ObservationExecutor.cs" />

test/SubSpec.Tests/Acceptance Tests/ContextLifetime.cs

 
 		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
+        var first = assemblyNode.AssertionResults().First();
+        var second = assemblyNode.AssertionResults().Second();
 
-		string expectedOutput = "Fixture setup\r\nFixture alive\r\nFixture disposed";
+		const string expectedOutput = "Fixture setup\r\nFixture alive\r\nFixture disposed";
 
-		VerifyTestNodeContextSetup(first, "Pass", expectedOutput);
-		VerifyTestNodeContextSetup(second, "Pass", expectedOutput);
+        SubSpecResultUtility.VerifyPassed(first);
+        SubSpecResultUtility.VerifyOutput(first, expectedOutput);
+
+        SubSpecResultUtility.VerifyPassed(second);
+        SubSpecResultUtility.VerifyOutput(second, expectedOutput);
 	}
 
 	[Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-        var second = ResultXmlUtility.GetResult( assemblyNode, 1 );
-
-        string expectedOutput = "Fixture setup\r\nFixture alive";
-        VerifyTestNodeContextSetup( first, "Pass", expectedOutput );
-        VerifyTestNodeContextSetup( second, "Pass", expectedOutput );
+        VerifyFixtureSetup(assemblyNode.ObservationSetupResult());
+        VerifyFixtureAlive(assemblyNode.ObservationResults().First());
+        VerifyFixtureAlive(assemblyNode.ObservationResults().Second());
+        VerifyFixtureDisposed(assemblyNode.ObservationTeardownResult());
     }
 
-	private static void VerifyTestNodeContextSetup(XmlNode testNode, string expectedResult, string expectedOutput)
+    private static void VerifyFixtureSetup(XmlNode testNode)
+    {
+        SubSpecResultUtility.VerifyPassed(testNode);
+        SubSpecResultUtility.VerifyOutput(testNode, "Fixture setup");
+    }
+    private static void VerifyFixtureAlive(XmlNode testNode)
 	{
-		ResultXmlUtility.AssertAttribute(testNode, "result", expectedResult);
-
-		XmlNode outputNode = testNode.SelectSingleNode("output");
-
-		Assert.Equal(expectedOutput, outputNode.InnerXml.Trim());
+        SubSpecResultUtility.VerifyPassed(testNode);
+        SubSpecResultUtility.VerifyOutput(testNode, "Fixture alive");
 	}
+    private static void VerifyFixtureDisposed(XmlNode testNode)
+    {
+        SubSpecResultUtility.VerifyPassed(testNode);
+        SubSpecResultUtility.VerifyOutput(testNode, "Fixture disposed");
+    }
 }
 
 

test/SubSpec.Tests/Acceptance Tests/ContextSetupTeardownFailure.cs

 using Xunit;
 using System.Xml;
 using SubSpec;
-using System.Collections;
+using System.Linq;
 
 public class ContextSetupTeardownFailure : AcceptanceTest
 {
 
 		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
-
-		VerifyTestNodeFailingContextSetup(first);
-		VerifyTestNodeFailingContextSetup(second);
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.AssertionResults().First(), "System.Exception : Error setting up context" );
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.AssertionResults().Second(), "System.Exception : Error setting up context" );
 	}
 
 	[Fact]
 
 		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
+        string expectedFailure = "System.Exception : Error tearing down context";
 
-		VerifyTestNodeFailingContextTeardown(first, "A");
-		VerifyTestNodeFailingContextTeardown(second, "B");
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.AssertionResults().First(), expectedFailure );
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.AssertionResults().Second(), expectedFailure );
 	}
 	
 	[Fact]
 
 		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-        var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-        var second = ResultXmlUtility.GetResult(assemblyNode, 1);
-
-        VerifyTestNodeFailingContextSetup(first);
-        VerifyTestNodeFailingContextSetup(second);
-	}
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.ObservationSetupResult(), "System.Exception : Error setting up context" );
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.ObservationResults().First(), "SubSpec.ContextSetupFailedException : Setting up Context failed" );
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.ObservationResults().Second(), "SubSpec.ContextSetupFailedException : Setting up Context failed" );
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.ObservationTeardownResult(), "SubSpec.ContextSetupFailedException : Setting up Context failed, but Fixtures were disposed." );
+    }
 
 	[Fact]
-	public void ErrorInContextTeardownPassesObservationsButGeneratesAdditionalFailingTest()
+	public void ErrorInContextTeardownPassesObservationsButMarksTeardownFailed()
 	{
 		string code =
             @"
 
 		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
-		var third = ResultXmlUtility.GetResult(assemblyNode, 2);
-
-		ResultXmlUtility.AssertAttribute(first, "result", "Pass");
-		ResultXmlUtility.AssertAttribute(second, "result", "Pass");
-
-		ResultXmlUtility.AssertAttribute(third, "result", "Fail");
-		Assert.Equal("System.Exception : Error tearing down context", third.SelectSingleNode("failure").SelectSingleNode("message").InnerXml);
+        SubSpecResultUtility.VerifyPassed( assemblyNode.ObservationSetupResult() );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.ObservationResults().First() );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.ObservationResults().Second());
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.ObservationTeardownResult(), "System.Exception : Error tearing down context" );
 	}
-
-	private static void VerifyTestNodeFailingContextSetup(XmlNode first)
-	{
-		ResultXmlUtility.AssertAttribute(first, "result", "Fail");
-
-		XmlNode firstFailureNode = first.SelectSingleNode("failure");
-
-		Assert.Equal("System.Exception : Error setting up context", firstFailureNode.SelectSingleNode("message").InnerXml);
-	}
-
-
-	private static void VerifyTestNodeFailingContextTeardown(XmlNode testNode, string expectedOutput)
-	{
-		ResultXmlUtility.AssertAttribute(testNode, "result", "Fail");
-
-		XmlNode failureNode = testNode.SelectSingleNode("failure");
-		XmlNode outputNode = testNode.SelectSingleNode("output");
-
-        Assert.Equal("Xunit.Sdk.AfterTestException : One or more exceptions were thrown from After methods during test cleanup", failureNode.SelectSingleNode("message").InnerXml);
-		Assert.Equal(expectedOutput, outputNode.InnerXml.Trim());
-	}
-}
-
+}

test/SubSpec.Tests/Acceptance Tests/InvalidSpecifications.cs

 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
 using SubSpec;
 using Xunit;
 using TestUtility;

test/SubSpec.Tests/Acceptance Tests/OneTestPerVerification.cs

 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
 using SubSpec;
 using Xunit;
 using System.Xml;
 
 		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
-
-		ResultXmlUtility.AssertAttribute(first, "result", "Pass");
-		ResultXmlUtility.AssertAttribute(second, "result", "Pass");
+        SubSpecResultUtility.VerifyPassed( assemblyNode.AssertionResults().First() );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.AssertionResults().Second() );
 	}
 
 	[Fact]
-	public void OneTestPerObservation()
+	public void OneTestPerObservationPlusSetupAndTeardown()
 	{
 		string code =
 			@"
 
 		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
-
-		ResultXmlUtility.AssertAttribute(first, "result", "Pass");
-		ResultXmlUtility.AssertAttribute(second, "result", "Pass");
+        SubSpecResultUtility.VerifyPassed( assemblyNode.ObservationSetupResult() );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.ObservationResults().First() );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.ObservationResults().Second() );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.ObservationTeardownResult() );
 	}
 
 }

test/SubSpec.Tests/Acceptance Tests/OutputCapturing.cs

 using Xunit;
 using System.Xml;
 using SubSpec;
+using System.Linq;
 
 public class OutputCapturing : AcceptanceTest
 {
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
-        VerifyStdAndErrOutput( first );
+        VerifyStdAndErrOutputCaptured(assemblyNode.ObservationSetupResult());
     }
 
     [Fact]
                 }
             ";
 
-        XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
+        
+        XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
+        VerifyStdAndErrOutputCaptured(assemblyNode.AssertionResults().First());
 
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
-        VerifyStdAndErrOutput( first );
     }
     [Fact]
-    public void OutputInDoWithObersvationIsCaptured()
+    public void OutputInDoWithObservationIsCaptured()
     {
         string code =
             @"
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
-        VerifyStdAndErrOutput( first );
+        VerifyStdAndErrOutputCaptured(assemblyNode.ObservationSetupResult());
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
-        VerifyStdAndErrOutput( first );
+        VerifyStdAndErrOutputCaptured(assemblyNode.AssertionResults().First());
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
-        VerifyStdAndErrOutput( first );
+        VerifyStdAndErrOutputCaptured(assemblyNode.ObservationResults().First());
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
-        VerifyStdAndErrOutput( first );
+        VerifyStdAndErrOutputCaptured(assemblyNode.AssertionResults().First());
     }
 
-    private static void VerifyStdAndErrOutput( XmlNode first )
+    private static void VerifyStdAndErrOutputCaptured( XmlNode first )
     {
+        SubSpecResultUtility.VerifyPassed(first);
+
         XmlNode outputNode = first.SelectSingleNode( "output" );
 
         Assert.Equal( "err\r\nout\r\n", outputNode.InnerXml );

test/SubSpec.Tests/Acceptance Tests/SpecificationDeclarations.cs

 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.AssertionResults().First() );
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.AssertionResults().First() );
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-
-        ResultXmlUtility.AssertAttribute( first, "result", "Fail" );
-
-        XmlNode failureNode = first.SelectSingleNode( "failure" );
-        Assert.Equal( "System.InvalidOperationException : Specification class does not have a default constructor", failureNode.SelectSingleNode( "message" ).InnerXml );
+        SubSpecResultUtility.VerifyFailedWith( assemblyNode.AssertionResults().First(), "System.InvalidOperationException : Specification class does not have a default constructor" );
     }
 }

test/SubSpec.Tests/Acceptance Tests/SpecificationExpressionExecution.cs

 
 public class SpecificationExpressionExecution : AcceptanceTest
 {
-	[Fact]
-	public void OneTestPerObservation()
-	{
-		string code =
-			@"
+    [Fact( Skip = "Todo" )]
+    public void OneTestPerObservation()
+    {
+        string code =
+            @"
                 using System;
 				using System.Text;
                 using Xunit;
                 }
             ";
 
-		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
+        XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
+        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
+        var second = ResultXmlUtility.GetResult( assemblyNode, 1 );
 
-		ResultXmlUtility.AssertAttribute(first, "result", "Pass");
-		ResultXmlUtility.AssertAttribute(second, "result", "Fail");
-	}
+        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
+        ResultXmlUtility.AssertAttribute( second, "result", "Fail" );
+    }
 
-	[Fact]
-	public void WhereClauseIsOptional()
-	{
-		string code =
-			@"
+    [Fact( Skip = "Todo" )]
+    public void WhereClauseIsOptional()
+    {
+        string code =
+            @"
                 using System;
 				using System.Text;
                 using Xunit;
                 }
             ";
 
-		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
+        XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
+        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
 
-		ResultXmlUtility.AssertAttribute(first, "result", "Pass");
-	}
+        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
+    }
 
-	[Fact(Skip="Todo")]
-	public void TestNamesAreDerivedFromSpec()
-	{
-		string code =
-			@"
+    [Fact( Skip = "Todo" )]
+    public void TestNamesAreDerivedFromSpec()
+    {
+        string code =
+            @"
                 using System;
 				using System.Text;
                 using Xunit;
                 }
             ";
 
-		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location);
+        XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
+        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
 
-		ResultXmlUtility.AssertAttribute(first, "result", "Pass");
+        ResultXmlUtility.AssertAttribute( first, "result", "Pass" );
         ResultXmlUtility.AssertAttribute( first, "name", "ACoolSpecification, " );
     }
 }

test/SubSpec.Tests/Acceptance Tests/ThesisIntegration.cs

 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
 using SubSpec;
 using Xunit;
 using System.Xml;
 using TestUtility;
 using Xunit.Extensions;
+using System.Linq;
 
 public class ThesisIntegration : AcceptanceTest
 {
-	[Fact]
-	public void OneSpecificationPerThesisDataItem()
-	{
-		string code =
-			@"
+    [Fact]
+    public void OneSpecificationPerThesisDataItem()
+    {
+        string code =
+            @"
                 using System;
                 using Xunit;
 				using Xunit.Extensions;
                 }
             ";
 
-		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location, typeof(TheoryAttribute).Assembly.Location);
+        XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location, typeof( TheoryAttribute ).Assembly.Location );
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
+        // Parameter "A"
+        SubSpecResultUtility.VerifyPassed( assemblyNode.AssertionResults().First() );
+        SubSpecResultUtility.VerifyFailed( assemblyNode.AssertionResults().Second() );
 
-		var third = ResultXmlUtility.GetResult(assemblyNode, 2);
-		var fourth = ResultXmlUtility.GetResult(assemblyNode, 3);
+        // Parameter "B"
+        SubSpecResultUtility.VerifyFailed( assemblyNode.AssertionResults().ElementAt( 2 ) );
+        SubSpecResultUtility.VerifyPassed( assemblyNode.AssertionResults().ElementAt( 3 ) );
+    }
 
-		// Parameter "A"
-		ResultXmlUtility.AssertAttribute(first, "result", "Pass");
-		ResultXmlUtility.AssertAttribute(second, "result", "Fail");
-
-		// Parameter "B"
-		ResultXmlUtility.AssertAttribute(third, "result", "Fail");
-		ResultXmlUtility.AssertAttribute(fourth, "result", "Pass");
-	}
-
-	[Fact]
-	public void ThesisHandlesExceptionsInSpecificationSetup()
-	{
-		string code =
-			@"
+    [Fact]
+    public void ThesisHandlesExceptionsInSpecificationSetup()
+    {
+        string code =
+            @"
                 using System;
                 using Xunit;
 				using Xunit.Extensions;
                 }
             ";
 
-		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location, typeof(TheoryAttribute).Assembly.Location);
+        XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location, typeof( TheoryAttribute ).Assembly.Location );
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
-		var second = ResultXmlUtility.GetResult(assemblyNode, 1);
+        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
+        var second = ResultXmlUtility.GetResult( assemblyNode, 1 );
 
-		VerifyExceptionResult(first, "System.Exception : Error in Specification");
-		VerifyExceptionResult(second, "System.Exception : Error in Specification");
-	}
+        SubSpecResultUtility.VerifyFailedWith( first, "System.Exception : Error in Specification" );
+        SubSpecResultUtility.VerifyFailedWith( second, "System.Exception : Error in Specification" );
+    }
 
-	private void VerifyExceptionResult(XmlNode testNode, string expectedException)
-	{
-		ResultXmlUtility.AssertAttribute(testNode, "result", "Fail");
-
-		XmlNode failureNode = testNode.SelectSingleNode("failure");
-
-		Assert.Equal(expectedException, failureNode.SelectSingleNode("message").InnerXml);
-	}
-
-	public void ThesisHandlesNoDataInTheory()
-	{
-		string code =
-			@"
+    public void ThesisHandlesNoDataInTheory()
+    {
+        string code =
+            @"
                 using System;
                 using Xunit;
 				using Xunit.Extensions;
                 }
             ";
 
-		XmlNode assemblyNode = ExecuteWithReferences(code, typeof(SpecificationAttribute).Assembly.Location, typeof(TheoryAttribute).Assembly.Location);
+        XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location, typeof( TheoryAttribute ).Assembly.Location );
 
-		var first = ResultXmlUtility.GetResult(assemblyNode, 0);
+        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
 
-		VerifyExceptionResult(first, "System.InvalidOperationException : No data found for MockTestClass.Spec");
-	}
-
+        SubSpecResultUtility.VerifyFailedWith( first, "System.InvalidOperationException : No data found for MockTestClass.Spec" );
+    }
 }

test/SubSpec.Tests/Acceptance Tests/TimeoutSpecifications.cs

 					public void Spec()
 					{
 						"""".Context(() => {Thread.Sleep(30);}).WithTimeout(10);
-		
 						"""".Assert(() => {});
 					}
                 }";
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-        VerifyTimeoutOccurred( first );
+        VerifyTimeoutOccurred( assemblyNode.AssertionResults().First() );
     }
 
     [Fact]
 					public void Spec()
 					{
 						"""".Context(() => {Thread.Sleep(30);}).WithTimeout(10);
-		
 						"""".Observation(() => {});
 					}
                 }";
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-        VerifyTimeoutOccurred( first );
+        VerifyTimeoutOccurred( assemblyNode.ObservationSetupResult() );
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-        VerifyTimeoutOccurred( first );
+        VerifyTimeoutOccurred( assemblyNode.AssertionResults().First() );
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-        VerifyTimeoutOccurred( first );
+        VerifyTimeoutOccurred( assemblyNode.ObservationSetupResult() );
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-        VerifyTimeoutOccurred( first );
+        VerifyTimeoutOccurred( assemblyNode.AssertionResults().First() );
     }
 
     [Fact]
 
         XmlNode assemblyNode = ExecuteWithReferences( code, typeof( SpecificationAttribute ).Assembly.Location );
 
-        var first = ResultXmlUtility.GetResult( assemblyNode, 0 );
-        VerifyTimeoutOccurred( first );
+        VerifyTimeoutOccurred( assemblyNode.ObservationResults().First() );
     }
 
     private static void VerifyTimeoutOccurred( XmlNode first )

test/SubSpec.Tests/ContextSetupTeardownBehavior.cs

 
 public class ContextSetupTeardownBehavior
 {
-	public class ContextFixture
-	{
-		private bool called = false;
-		public void FailWhenCallingTwice()
-		{
-			if (called)
-				throw new InvalidOperationException("Called twice!");
+    public class ContextFixtureSpy
+    {
+        private bool called = false;
+        public void FailWhenCallingTwice()
+        {
+            if (called)
+                throw new InvalidOperationException( "Called twice!" );
 
-			called = true;
-		}
-	}
+            called = true;
+        }
+    }
 
-	[Fact]
-	public void SutThrowsWhenCalledTwice()
-	{
-		var sut = new ContextFixture();
-		Assert.Throws<InvalidOperationException>(() =>
-		{
-			sut.FailWhenCallingTwice();
-			sut.FailWhenCallingTwice();
-		});
-	}
+    [Fact]
+    public void SutThrowsWhenCalledTwice()
+    {
+        var sut = new ContextFixtureSpy();
+        Assert.Throws<InvalidOperationException>( () =>
+        {
+            sut.FailWhenCallingTwice();
+            sut.FailWhenCallingTwice();
+        } );
+    }
 
-	[Specification]
-	public void MultipleAssertionsShouldCauseActionToBeRepeated()
-	{
-		var sut = new ContextFixture();
-		sut.FailWhenCallingTwice();
+    [Specification]
+    public void MultipleAssertionsShouldCauseActionToBeRepeated()
+    {
+        var sut = new ContextFixtureSpy();
+        sut.FailWhenCallingTwice();
 
-		"Given an externally managed context".Context(() => { });
-		"when we execute an action on it that may be invoked only once".Do(
-			() => Assert.Throws<InvalidOperationException>(() => sut.FailWhenCallingTwice()));
+        "Given an externally managed context"
+            .Context( () => { } );
 
-		"we expect our first assertion to pass".Assert(() => { Assert.True(true); });
-		"we expect the action not to be repeated for the second assertion".Assert(() => { Assert.True(true); });
-	}
+        "when we execute an action on it that may be invoked only once"
+            .Do( () =>
+                Assert.Throws<InvalidOperationException>( () => sut.FailWhenCallingTwice() ) );
 
-	[Specification]
-	public void MultipleAssertionsShouldCauseContextInstantiationToBeRepeated()
-	{
-		var sut = new ContextFixture();
-		sut.FailWhenCallingTwice();
+        "we expect our first assertion to pass"
+            .Assert( () => 
+                Assert.True( true ) );
 
-		"Given a context that may not be established twice".Context(
-			() => Assert.Throws<InvalidOperationException>(() => sut.FailWhenCallingTwice()));
+        "we expect the action not to be repeated for the second assertion"
+            .Assert( () =>  
+                Assert.True( true ) );
+    }
 
-		"".Do(() => { });
+    [Specification]
+    public void MultipleAssertionsShouldCauseContextInstantiationToBeRepeated()
+    {
+        var sut = new ContextFixtureSpy();
+        sut.FailWhenCallingTwice();
 
-		"we expect our first assertion to pass".Assert(() => { Assert.True(true); });
-		"we expect the context instantiation not to be repeated for the second assertion".Assert(() => { Assert.True(true); });
-	}
+        "Given a context that may not be established twice".Context(
+            () => Assert.Throws<InvalidOperationException>( () => sut.FailWhenCallingTwice() ) );
 
-	[Specification]
-	public void MultipleObservationsShouldNotCauseActionToBeRepeated()
-	{
-		var sut = new ContextFixture();
+        "".Do( () => { } );
 
-		"Given an externally managed context".Context(() => { });
-		"when we execute an action on it that may be invoked only once".Do(() => { sut.FailWhenCallingTwice(); });
+        "we expect our first assertion to pass".Assert( () => { Assert.True( true ); } );
+        "we expect the context instantiation not to be repeated for the second assertion".Assert( () => { Assert.True( true ); } );
+    }
 
-		"we expect our first assertion to pass".Observation(() => { Assert.True(true); });
-		"we expect the action not to be repeated for the second assertion".Observation(() => { Assert.True(true); });
-	}
+    [Specification]
+    public void MultipleObservationsShouldNotCauseActionToBeRepeated()
+    {
+        var sut = new ContextFixtureSpy();
 
-	[Specification]
-	public void MultipleObservationsShouldNotCauseContextInstantiationToBeRepeated()
-	{
-		var sut = new ContextFixture();
+        "Given an externally managed context".Context( () => { } );
+        "when we execute an action on it that may be invoked only once".Do( () => { sut.FailWhenCallingTwice(); } );
 
-		"Given a context that may not be established twice".Context(() => { sut.FailWhenCallingTwice(); });
-		"".Do(() => { });
+        "we expect our first assertion to pass".Observation( () => { Assert.True( true ); } );
+        "we expect the action not to be repeated for the second assertion".Observation( () => { Assert.True( true ); } );
+    }
 
-		"we expect our first assertion to pass".Observation(() => { Assert.True(true); });
-		"we expect the context instantiation not to be repeated for the second assertion".Observation(() => { Assert.True(true); });
-	}
+    [Specification]
+    public void MultipleObservationsShouldNotCauseContextInstantiationToBeRepeated()
+    {
+        var sut = new ContextFixtureSpy();
 
-	[Fact]
-	public void ErrorInContextActionForObservationsDisposesContext()
-	{
-		var m = new Mock<IDisposable>();
+        "Given a context that may not be established twice".Context( () => { sut.FailWhenCallingTwice(); } );
+        "".Do( () => { } );
 
-		SpecificationContext.Context("", () => { return m.Object; });
-		SpecificationContext.Do("", () => { throw new Exception(""); });
-		SpecificationContext.Assert("", () => { });
+        "we expect our first assertion to pass".Observation( () => { Assert.True( true ); } );
+        "we expect the context instantiation not to be repeated for the second assertion".Observation( () => { Assert.True( true ); } );
+    }
 
-		SpecificationContext.ToTestCommands(new Mock<IMethodInfo>().Object).Consume();
+    [Fact]
+    public void ErrorInDoForAssertionDisposesContext()
+    {
+        var m = new Mock<IDisposable>();
 
-		m.Verify(x => x.Dispose());
-	}
+        SpecificationContext.Context( "", () => { return m.Object; } );
+        SpecificationContext.Do( "", () => { throw new Exception( "" ); } );
+        SpecificationContext.Assert( "", () => { } );
 
-	[Fact]
-	public void ErrorInContextActionForObservationsDisposesContextQuietly()
-	{
-		var m = new Mock<IDisposable>();
-		m.Setup(x => x.Dispose()).Throws<Exception>();
+        SpecificationContext.ToTestCommands( new Mock<IMethodInfo>().Object ).Consume();
 
-		SpecificationContext.Context("", () => { return m.Object; });
-		SpecificationContext.Do("", () => { throw new Exception(""); });
-		SpecificationContext.Assert("", () => { });
+        m.Verify( x => x.Dispose() );
+    }
 
-		SpecificationContext.ToTestCommands(new Mock<IMethodInfo>().Object).Consume();
+    [Fact]
+    public void ErrorInDoForObservationDisposesContext()
+    {
+        var m = new Mock<IDisposable>();
 
-		m.Verify(x => x.Dispose());
-	}
+        SpecificationContext.Context( "", () => { return m.Object; } );
+        SpecificationContext.Do( "", () => { throw new Exception( "" ); } );
+        SpecificationContext.Observation( "", () => { } );
+
+        SpecificationContext.ToTestCommands( new Mock<IMethodInfo>().Object ).Consume();
+
+        m.Verify( x => x.Dispose() );
+    }
 }
 
 internal static partial class Mixin
 {
-	public static void Consume<T>(this IEnumerable<T> seq)
-	{
-		foreach (var item in seq)
-		{
-		}
-	}
+    public static void Consume( this IEnumerable<ITestCommand> seq )
+    {
+        foreach (var item in seq)
+        {   try
+            {
+                item.Execute(null);
+            }
+            catch
+            {
+            }
+        }
+    }
 }

test/SubSpec.Tests/SubSpec.Tests.csproj

     <Compile Include="Acceptance Tests\OutputCapturing.cs" />
     <Compile Include="Acceptance Tests\SpecificationDeclarations.cs" />
     <Compile Include="Acceptance Tests\SpecificationExpressionExecution.cs" />
+    <Compile Include="SubSpecResultUtility.cs" />
     <Compile Include="Acceptance Tests\TimeoutSpecifications.cs" />
     <Compile Include="CompositeFixtureFacts.cs" />
     <Compile Include="test.utility\AcceptanceTest.cs" />

test/SubSpec.Tests/SubSpecDemo.cs

 using System;
-using System.Linq;
 using Xunit;
 using SubSpec;
 using System.Collections.Generic;
-using SubSpec.Expression;
-using System.Text;
 using System.Threading;
 
 public class SubSpecDemo
             .Observation( () => Assert.NotNull( foo ) );
 
         // Output: 
+        // bar disposed
         // foo diposed
-        // bar disposed
     }
 
-    [Specification]
-    public void ExpressionSyntax()
-    {
-        const int element = 11;
+    //[Specification]
+    //public void ExpressionSyntax()
+    //{
+    //    const int element = 11;
 
-        var spec = from sut in SpecificationExpression.Begin( () => new Stack<int>() )
-                   where sut.Push( element )
-                   select new Observations() 
-					{
-						() => Assert.NotEmpty(sut), 
-						() => Assert.Equal(element, sut.Peek()) 
-					};
-    }
+    //    var spec = from sut in SpecificationExpression.Begin( () => new Stack<int>() )
+    //               where sut.Push( element )
+    //               select new Observations() 
+				//	{
+				//		() => Assert.NotEmpty(sut), 
+				//		() => Assert.Equal(element, sut.Peek()) 
+				//	};
+    //}
 
 }

test/SubSpec.Tests/SubSpecResultUtility.cs

+using System;
+using System.Xml;
+using System.Linq;
+using System.Collections.Generic;
+using Xunit;
+using TestUtility;
+
+
+public static class SubSpecResultUtility
+{
+    public static XmlNode GetClassResult(XmlNode assemblyNode, int classIndex)
+    {
+        XmlNodeList classNodes = assemblyNode.SelectNodes("class");
+        if (classNodes.Count <= classIndex)
+            throw new ArgumentException("Could not find class item with index " + classIndex + " in XML:\r\n" + assemblyNode.OuterXml);
+
+        return classNodes[classIndex];
+    }
+
+    public static XmlNode GetObservationResult(XmlNode assemblyNode, int observationIndex)
+    {
+        return ObservationResults(assemblyNode).ElementAt(observationIndex + 1);
+    }
+
+    public static XmlNode ObservationTeardownResult(this XmlNode assemblyNode)
+    {
+        return GetClassResult(assemblyNode, 0).ChildNodes.Cast<XmlNode>().Single(x => x.Attributes.GetNamedItem("name").Value.StartsWith("}"));
+    }
+
+    public static XmlNode ObservationSetupResult(this XmlNode assemblyNode)
+    {
+        return GetClassResult(assemblyNode, 0).ChildNodes.Cast<XmlNode>().Single(x => x.Attributes.GetNamedItem("name").Value.StartsWith("{"));
+    }
+
+    public static IEnumerable<XmlNode> ObservationResults(this XmlNode assemblyNode)
+    {
+        return GetClassResult(assemblyNode, 0).ChildNodes.Cast<XmlNode>()
+            .SkipWhile(x => !IsObservationSetupNode(x)).Skip(1)
+            .TakeWhile(x => !IsObservationTeardownNode(x))
+            .Select(x => x);
+    }
+
+    private static bool IsObservationSetupNode(XmlNode x)
+    {
+        return x.Attributes.GetNamedItem("name").Value.StartsWith("{");
+    }
+    private static bool IsObservationTeardownNode(XmlNode x)
+    {
+        return x.Attributes.GetNamedItem("name").Value.StartsWith("}");
+    }
+    public static IEnumerable<XmlNode> AssertionResults(this XmlNode assemblyNode)
+    {
+        return GetClassResult(assemblyNode, 0).ChildNodes.Cast<XmlNode>().Except(assemblyNode.ObservationResults());
+    }
+
+    public static XmlNode Second( this IEnumerable<XmlNode> source )
+    {
+        return source.ElementAt(1);
+    }
+    public static XmlNode First( this IEnumerable<XmlNode> source )
+    {
+        return source.First<XmlNode>();
+    }
+
+    public static void VerifyOutput(XmlNode testNode, string expectedOutput)
+    {
+        XmlNode outputNode = testNode.SelectSingleNode("output");
+
+        Assert.Equal(expectedOutput, outputNode.InnerXml.Trim());
+    }
+
+    public static void VerifyPassed(XmlNode testNode)
+    {
+        ResultXmlUtility.AssertAttribute(testNode, "result", "Pass");
+    }
+
+    public static void VerifyFailed(XmlNode testNode)
+    {
+        ResultXmlUtility.AssertAttribute(testNode, "result", "Fail");
+    }
+
+    public static void VerifyFailedWith(XmlNode testNode, string expectedFailure)
+    {
+        VerifyFailed( testNode );
+
+        XmlNode firstFailureNode = testNode.SelectSingleNode( "failure" );
+
+        Assert.Equal( expectedFailure, firstFailureNode.SelectSingleNode( "message" ).InnerXml );
+    }
+}