From 05c7a799ed6d72f4048515c20d35aca51d3e019f Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Wed, 7 Aug 2013 15:41:49 +0100 Subject: [PATCH 1/9] Reordered the ConventionResult.For arguments --- .../ConventionAssertionClassTests.cs | 2 +- .../Conventions/AllMethodsAreVirtual.cs | 2 +- .../Conventions/FilesAreEmbeddedResources.cs | 5 ++--- .../ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs | 2 +- TestStack.ConventionTests/Internal/ConventionResult.cs | 8 +++----- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index d6b66ff..5823a29 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -30,7 +30,7 @@ public class FailingConvention : IConvention { public ConventionResult Execute(FakeData data) { - return ConventionResult.For(new[] { "" }, "Header", (s, builder) => builder.AppendLine("Different")); + return ConventionResult.For("Header", new[] { "" }, (s, builder) => builder.AppendLine("Different")); } } } diff --git a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs index 7d43b01..99b4154 100644 --- a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs +++ b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs @@ -25,7 +25,7 @@ public ConventionResult Execute(Types data) let nonVirtuals = applicableType.NonVirtualMethods() where nonVirtuals.Any() select Tuple.Create(applicableType, nonVirtuals); - return ConventionResult.For(items, HeaderMessage, DescribeTypeAndMethods); + return ConventionResult.For(HeaderMessage, items, DescribeTypeAndMethods); } // I like how that's encapsulated in the reusable convention type, whereas previously it was part of the convention/test code diff --git a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs index 73b8e60..fe3f402 100644 --- a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs +++ b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs @@ -8,9 +8,8 @@ public class FilesAreEmbeddedResources : IConvention { public ConventionResult Execute(ProjectFiles data) { - return ConventionResult.For(data.Files.Where(s => s.ReferenceType != "EmbeddedResource"), - "The following files which should be embedded resources:", - (t, m) => m.AppendLine("\t" + t.FilePath)); + return ConventionResult.For("The following files which should be embedded resources:", + data.Files.Where(s => s.ReferenceType != "EmbeddedResource"), (t, m) => m.AppendLine("\t" + t.FilePath)); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs index 716c654..8d8efba 100644 --- a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs +++ b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs @@ -14,7 +14,7 @@ public ConventionResult Execute(ProjectReferences data) { var invalid = data.References.Where(IsBinOrObjReference); var header = string.Format("Some invalid assembly references found in {0}", data.Assembly.GetName().Name); - return ConventionResult.For(invalid, header, FormatLine); + return ConventionResult.For(header, invalid, FormatLine); } void FormatLine(ProjectReference assemblyReference, StringBuilder m) diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index 59e655c..41e50ec 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -19,8 +19,7 @@ public bool Failed } public static ConventionResult For( - IEnumerable items, - string header, + string header, IEnumerable items, Action itemDescriptor) { var array = items.ToArray(); @@ -41,11 +40,10 @@ public static ConventionResult For( } public static ConventionResult For( - IEnumerable items, - string header, + IEnumerable items, string header, Func itemDescriptor) { - return For(items, header, (item, message) => message.AppendLine(itemDescriptor(item))); + return For(header, items, (item, message) => message.AppendLine(itemDescriptor(item))); } public static ConventionResult ForSymmetric( From 2ee34062a8e443ecc69c2f4a2e01c606c11cf672 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Wed, 7 Aug 2013 15:42:12 +0100 Subject: [PATCH 2/9] Making failure more explicit for ConventionResult --- ConventionTests.sln.DotSettings | 1 + .../Internal/ConventionResult.cs | 16 ++++++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/ConventionTests.sln.DotSettings b/ConventionTests.sln.DotSettings index b5ca155..2941484 100644 --- a/ConventionTests.sln.DotSettings +++ b/ConventionTests.sln.DotSettings @@ -1,4 +1,5 @@  + DO_NOT_SHOW <?xml version="1.0" encoding="utf-16"?><Profile name="all"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><CSReorderTypeMembers>True</CSReorderTypeMembers></Profile> all False diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index 41e50ec..af09e8f 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -7,29 +7,26 @@ public class ConventionResult { - ConventionResult() + ConventionResult(bool failed) { + Failed = failed; } public string Message { get; private set; } - public bool Failed - { - get { return !string.IsNullOrEmpty(Message); } - } + public bool Failed { get; private set; } public static ConventionResult For( string header, IEnumerable items, Action itemDescriptor) { var array = items.ToArray(); - var result = new ConventionResult(); if (array.None()) { - return result; + return new ConventionResult(failed: false); } - // NOTE: we might possibly want to abstract the StringBuilder to have more high level construct that would allow us to plug rich reports here... + var result = new ConventionResult(true); var message = new StringBuilder(header); message.AppendLine(); message.AppendLine(string.Empty.PadRight(header.Length, '-')); @@ -53,10 +50,9 @@ public static ConventionResult ForSymmetric( { var firstArray = firstResults.ToArray(); var secondArray = secondResults.ToArray(); - var result = new ConventionResult(); if (firstArray.None() && secondArray.None()) { - return result; + return new ConventionResult(failed: true); } var message = new StringBuilder(); From 86153757919b34f8ce5555b419b4d6b6f168459c Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Thu, 8 Aug 2013 12:55:55 +0100 Subject: [PATCH 3/9] Massive refactor around reporting... --- ...nClassTests.approval_mismatch.approved.txt | 7 +- .../ConventionAssertionClassTests.cs | 18 ++- ...ssemblies_referencing_bin_obj.approved.txt | 6 +- ..._obj_with_approved_exceptions.approved.txt | 7 +- .../ProjectBasedConventions.cs | 14 +-- ...cripts_not_embedded_resources.approved.txt | 6 +- ...rces_with_approved_exceptions.approved.txt | 7 +- ...sses_have_default_constructor.approved.txt | 6 +- ...uctor_wth_approved_exceptions.approved.txt | 7 +- ...tions.all_methods_are_virtual.approved.txt | 6 +- ...rtual_wth_approved_exceptions.approved.txt | 7 +- .../TypeBasedConventions.cs | 6 +- ....dtos_exists_in_dto_namespace.approved.txt | 10 +- ...space_wth_approved_exceptions.approved.txt | 14 ++- TestStack.ConventionTests/Convention.cs | 106 ++++++++++++++++-- .../ConventionData/AbstractProjectData.cs | 2 + .../ConventionData/ProjectFiles.cs | 11 +- .../ConventionData/ProjectReferences.cs | 7 +- .../ConventionData/Types.cs | 20 +++- .../ConventionFailure.cs | 17 +++ TestStack.ConventionTests/ConventionReport.cs | 29 +++++ .../ConventionReportTextRenderer.cs | 52 +++++++++ .../ConventionReportTraceRenderer.cs | 14 +++ .../ConventionResultExceptionReporter.cs | 18 +++ .../AllClassesHaveDefaultConstructor.cs | 16 +-- .../Conventions/AllMethodsAreVirtual.cs | 34 +----- .../ClassTypeHasSpecificNamespace.cs | 44 +++++--- .../Conventions/FilesAreEmbeddedResources.cs | 24 +++- .../Conventions/ISymmetricConvention.cs | 12 ++ ...NotReferenceDllsFromBinOrObjDirectories.cs | 20 ++-- TestStack.ConventionTests/IConvention.cs | 7 +- TestStack.ConventionTests/IConventionData.cs | 1 + .../IConventionReportRenderer.cs | 7 ++ .../ICreateReportLineFor.cs | 7 ++ .../Internal/ConventionResult.cs | 93 --------------- TestStack.ConventionTests/Result.cs | 8 ++ .../TestStack.ConventionTests.csproj | 10 +- 37 files changed, 433 insertions(+), 247 deletions(-) create mode 100644 TestStack.ConventionTests/ConventionFailure.cs create mode 100644 TestStack.ConventionTests/ConventionReport.cs create mode 100644 TestStack.ConventionTests/ConventionReportTextRenderer.cs create mode 100644 TestStack.ConventionTests/ConventionReportTraceRenderer.cs create mode 100644 TestStack.ConventionTests/ConventionResultExceptionReporter.cs create mode 100644 TestStack.ConventionTests/Conventions/ISymmetricConvention.cs create mode 100644 TestStack.ConventionTests/IConventionReportRenderer.cs create mode 100644 TestStack.ConventionTests/ICreateReportLineFor.cs delete mode 100644 TestStack.ConventionTests/Internal/ConventionResult.cs create mode 100644 TestStack.ConventionTests/Result.cs diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt index 1f1503b..11906c4 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt @@ -1,4 +1,5 @@ -Header ------- +Passed: 'Header' for 'Fake data' +-------------------------------- -Approved Exception +With approved exceptions: + Approved Exception \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 5823a29..3a587d8 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -1,8 +1,8 @@ namespace TestStack.ConventionTests.Tests { + using System.Collections.Generic; using ApprovalTests.Reporters; using NUnit.Framework; - using TestStack.ConventionTests.Internal; [TestFixture] [UseReporter(typeof(DiffReporter))] //NOTE: Can we take care of this in IsWithApprovedExceptions? @@ -19,18 +19,26 @@ public void approval_mismatch() StringAssert.Contains("does not match approved file", ex.Message); } - public class FakeData : IConventionData + public class FakeData : IConventionData, ICreateReportLineFor { + public string Description { get { return "Fake data"; } } + public void EnsureHasNonEmptySource() { } + + public ConventionFailure CreateReportLine(string failingData) + { + return new ConventionFailure(failingData); + } } - public class FailingConvention : IConvention + public class FailingConvention : IConvention { - public ConventionResult Execute(FakeData data) + public string ConventionTitle { get { return "Header"; } } + public IEnumerable GetFailingData(FakeData data) { - return ConventionResult.For("Header", new[] { "" }, (s, builder) => builder.AppendLine("Different")); + return new[] {"Different"}; } } } diff --git a/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj.approved.txt b/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj.approved.txt index 5c77681..c1f4909 100644 --- a/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj.approved.txt +++ b/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj.approved.txt @@ -1,4 +1,4 @@ -Some invalid assembly references found in TestStack.ConventionTests.Tests -------------------------------------------------------------------------- +Failed: 'Project must not reference dlls from bin or obj directories' for 'TestStack.ConventionTests.Tests' +----------------------------------------------------------------------------------------------------------- - bin\Debug\ApprovalTests.dll + bin\Debug\ApprovalTests.dll \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj_with_approved_exceptions.approved.txt b/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj_with_approved_exceptions.approved.txt index 5c77681..1b176e9 100644 --- a/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj_with_approved_exceptions.approved.txt +++ b/TestStack.ConventionTests.Tests/ProjectBasedConventions.assemblies_referencing_bin_obj_with_approved_exceptions.approved.txt @@ -1,4 +1,5 @@ -Some invalid assembly references found in TestStack.ConventionTests.Tests -------------------------------------------------------------------------- +Passed: 'Project must not reference dlls from bin or obj directories' for 'TestStack.ConventionTests.Tests' +----------------------------------------------------------------------------------------------------------- - bin\Debug\ApprovalTests.dll +With approved exceptions: + bin\Debug\ApprovalTests.dll \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs b/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs index c003a56..45ee86e 100644 --- a/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs +++ b/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs @@ -57,11 +57,8 @@ public void scripts_not_embedded_resources() .Returns(XDocument.Parse(Resources.ProjectFileWithInvalidSqlScriptFile)); var projectLocator = Substitute.For(); - var project = new ProjectFiles(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator) - { - Items = i => i.FilePath.EndsWith(".sql") - }; - var ex = Assert.Throws(() => Convention.Is(new FilesAreEmbeddedResources(), project)); + var project = new ProjectFiles(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator); + var ex = Assert.Throws(() => Convention.Is(new FilesAreEmbeddedResources(".sql"), project)); Approvals.Verify(ex.Message); } @@ -70,15 +67,12 @@ public void scripts_not_embedded_resources() public void scripts_not_embedded_resources_with_approved_exceptions() { var projectLocator = Substitute.For(); - var project = new ProjectFiles(typeof(ProjectBasedConventions).Assembly, projectProvider, projectLocator) - { - Items = i => i.FilePath.EndsWith(".sql") - }; + var project = new ProjectFiles(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator); projectProvider .LoadProjectDocument(Arg.Any()) .Returns(XDocument.Parse(Resources.ProjectFileWithInvalidSqlScriptFile)); - Convention.IsWithApprovedExeptions(new FilesAreEmbeddedResources(), project); + Convention.IsWithApprovedExeptions(new FilesAreEmbeddedResources(".sql"), project); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources.approved.txt b/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources.approved.txt index a12b82e..4ce889e 100644 --- a/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources.approved.txt +++ b/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources.approved.txt @@ -1,4 +1,4 @@ -The following files which should be embedded resources: -------------------------------------------------------- +Failed: '.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' +------------------------------------------------------------------------------------- - Scripts\Script2.sql + Scripts\Script2.sql \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources_with_approved_exceptions.approved.txt b/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources_with_approved_exceptions.approved.txt index a12b82e..0217788 100644 --- a/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources_with_approved_exceptions.approved.txt +++ b/TestStack.ConventionTests.Tests/ProjectBasedConventions.scripts_not_embedded_resources_with_approved_exceptions.approved.txt @@ -1,4 +1,5 @@ -The following files which should be embedded resources: -------------------------------------------------------- +Passed: '.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' +------------------------------------------------------------------------------------- - Scripts\Script2.sql +With approved exceptions: + Scripts\Script2.sql \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor.approved.txt index 02f6b64..173a5a4 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor.approved.txt @@ -1,5 +1,5 @@ -The following types do not have default constructor ---------------------------------------------------- +Failed: 'Types must have a default constructor' for 'nHibernate Entitites' +-------------------------------------------------------------------------- TestAssembly.ClassWithNoDefaultCtor - TestAssembly.ClassWithPrivateDefaultCtor + TestAssembly.ClassWithPrivateDefaultCtor \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor_wth_approved_exceptions.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor_wth_approved_exceptions.approved.txt index 02f6b64..3cad8d9 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor_wth_approved_exceptions.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_classes_have_default_constructor_wth_approved_exceptions.approved.txt @@ -1,5 +1,6 @@ -The following types do not have default constructor ---------------------------------------------------- +Passed: 'Types must have a default constructor' for 'nHibernate Entitites' +-------------------------------------------------------------------------- +With approved exceptions: TestAssembly.ClassWithNoDefaultCtor - TestAssembly.ClassWithPrivateDefaultCtor + TestAssembly.ClassWithPrivateDefaultCtor \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual.approved.txt index b951c4b..ec20755 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual.approved.txt @@ -1,4 +1,4 @@ -The following methods are not virtual. --------------------------------------- +Failed: 'Methods must be virtual' for 'nHibernate Entitites' +------------------------------------------------------------ - TestAssembly.SampleDomainClass.TestNonVirtual + TestAssembly.SampleDomainClass.TestNonVirtual \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual_wth_approved_exceptions.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual_wth_approved_exceptions.approved.txt index b951c4b..c1902ad 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual_wth_approved_exceptions.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.all_methods_are_virtual_wth_approved_exceptions.approved.txt @@ -1,4 +1,5 @@ -The following methods are not virtual. --------------------------------------- +Passed: 'Methods must be virtual' for 'nHibernate Entitites' +------------------------------------------------------------ - TestAssembly.SampleDomainClass.TestNonVirtual +With approved exceptions: + TestAssembly.SampleDomainClass.TestNonVirtual \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.cs b/TestStack.ConventionTests.Tests/TypeBasedConventions.cs index 51f7df6..5f3c2d4 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.cs +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.cs @@ -17,7 +17,7 @@ public class TypeBasedConventions public TypeBasedConventions() { var itemsToVerify = typeof (SampleDomainClass).Assembly.GetTypes(); - nhibernateEntities = new Types + nhibernateEntities = new Types("nHibernate Entitites") { TypesToVerify = itemsToVerify }; @@ -54,7 +54,7 @@ public void all_methods_are_virtual_wth_approved_exceptions() [Test] public void dtos_exists_in_dto_namespace() { - var types = new Types + var types = new Types("TestAssembly types") { TypesToVerify = new[] { typeof(SomeDto), typeof(BlahDto), typeof(AnotherClass)} }; @@ -67,7 +67,7 @@ public void dtos_exists_in_dto_namespace() [Test] public void dtos_exists_in_dto_namespace_wth_approved_exceptions() { - var types = new Types + var types = new Types("TestAssembly types") { TypesToVerify = new[] { typeof(SomeDto), typeof(BlahDto), typeof(AnotherClass) } }; diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace.approved.txt index 2a5fb4f..b864151 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace.approved.txt @@ -1,10 +1,10 @@ -Dtos must be under the 'TestAssembly.Dtos' namespace ----------------------------------------------------- +Failed: 'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +--------------------------------------------------------------------------------------- TestAssembly.SomeDto -Non-Dtos must not be under the 'TestAssembly.Dtos' namespace ------------------------------------------------------------- +Failed: 'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +----------------------------------------------------------------------------------------------- - TestAssembly.Dtos.AnotherClass + TestAssembly.Dtos.AnotherClass \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions.approved.txt index 2a5fb4f..6d0ccc9 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions.approved.txt @@ -1,10 +1,14 @@ -Dtos must be under the 'TestAssembly.Dtos' namespace ----------------------------------------------------- +Passed: 'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +--------------------------------------------------------------------------------------- +With approved exceptions: TestAssembly.SomeDto -Non-Dtos must not be under the 'TestAssembly.Dtos' namespace ------------------------------------------------------------- - TestAssembly.Dtos.AnotherClass + +Passed: 'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +----------------------------------------------------------------------------------------------- + +With approved exceptions: + TestAssembly.Dtos.AnotherClass \ No newline at end of file diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 0d60479..31254b6 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -1,36 +1,118 @@ namespace TestStack.ConventionTests { - using System.Diagnostics; + using System.Collections.Generic; + using System.Linq; using ApprovalTests; using ApprovalTests.Core.Exceptions; + using TestStack.ConventionTests.Conventions; + using TestStack.ConventionTests.Internal; public static class Convention { - public static void Is(IConvention convention, TData data) where TData : IConventionData + static readonly List Reports = new List(); + + public static IEnumerable ConventionReports { get { return Reports; } } + + public static void Is(IConvention convention, TDataSource data) + where TDataSource : IConventionData, ICreateReportLineFor { - data.EnsureHasNonEmptySource(); - var result = convention.Execute(data); + Is(convention, data, new ConventionResultExceptionReporter()); + } - if (result.Failed) - throw new ConventionFailedException(result.Message); + public static void Is(IConvention convention, TDataSource data, IConventionReportRenderer reporter) + where TDataSource : IConventionData, ICreateReportLineFor + { + var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + + Reports.Add(conventionResult); + + new ConventionReportTraceRenderer().Render(conventionResult); + reporter.Render(conventionResult); } - public static void IsWithApprovedExeptions(IConvention convention, TData data) where TData : IConventionData + public static void IsWithApprovedExeptions(IConvention convention, TDataSource data) + where TDataSource : IConventionData, ICreateReportLineFor { - data.EnsureHasNonEmptySource(); - var result = convention.Execute(data); + var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); - // should we encapsulate Approvals behind Settings? try { - Approvals.Verify(result.Message); + var conventionReportTextRenderer = new ConventionReportTextRenderer(); + conventionReportTextRenderer.RenderItems(conventionResult); + conventionResult.WithApprovedException(conventionReportTextRenderer.Output); + + conventionReportTextRenderer.Render(conventionResult); + Approvals.Verify(conventionReportTextRenderer.Output); - Trace.WriteLine(string.Format("{0} has approved exceptions:\r\n\r\n{1}", convention.GetType().Name, result.Message)); + new ConventionReportTraceRenderer().Render(conventionResult); } catch (ApprovalException ex) { throw new ConventionFailedException("Approved exceptions for convention differs\r\n\r\n"+ex.Message, ex); } } + + public static void Is(ISymmetricConvention convention, TDataSource data) + where TDataSource : IConventionData, ICreateReportLineFor + { + Is(convention, data, new ConventionResultExceptionReporter()); + } + + public static void Is(ISymmetricConvention convention, TDataSource data, IConventionReportRenderer reporter) + where TDataSource : IConventionData, ICreateReportLineFor + { + var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); + + Reports.Add(conventionResult); + Reports.Add(inverseConventionResult); + + new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult); + reporter.Render(conventionResult, inverseConventionResult); + } + + public static void IsWithApprovedExeptions(ISymmetricConvention convention, TDataSource data) + where TDataSource : IConventionData, ICreateReportLineFor + { + var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); + + try + { + var conventionReportTextRenderer = new ConventionReportTextRenderer(); + // Add approved exceptions to report + conventionReportTextRenderer.RenderItems(conventionResult); + conventionResult.WithApprovedException(conventionReportTextRenderer.Output); + + // Add approved exceptions to inverse report + conventionReportTextRenderer.RenderItems(inverseConventionResult); + inverseConventionResult.WithApprovedException(conventionReportTextRenderer.Output); + + //Render both, with approved exceptions included + conventionReportTextRenderer.Render(conventionResult, inverseConventionResult); + Approvals.Verify(conventionReportTextRenderer.Output); + + // Trace on success + new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult); + } + catch (ApprovalException ex) + { + throw new ConventionFailedException("Approved exceptions for convention differs\r\n\r\n" + ex.Message, ex); + } + } + + static ConventionReport GetConventionReport(string conventionTitle, TDataType[] failingData, TDataSource data) + where TDataSource : IConventionData, ICreateReportLineFor + { + data.EnsureHasNonEmptySource(); + var passed = failingData.None(); + + var conventionResult = new ConventionReport( + passed ? Result.Passed : Result.Failed, + conventionTitle, + data.Description, + failingData.Select(data.CreateReportLine)); + return conventionResult; + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs b/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs index d4f5d29..8f05bff 100644 --- a/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs +++ b/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs @@ -20,6 +20,8 @@ protected AbstractProjectData(Assembly assembly, IProjectProvider projectProvide public IProjectProvider ProjectProvider { get; private set; } + public string Description { get { return Assembly.GetName().Name; } } + public void EnsureHasNonEmptySource() { if (ProjectLocator.ResolveProjectFilePath(Assembly) == null) diff --git a/TestStack.ConventionTests/ConventionData/ProjectFiles.cs b/TestStack.ConventionTests/ConventionData/ProjectFiles.cs index 2138ad6..6e3129c 100644 --- a/TestStack.ConventionTests/ConventionData/ProjectFiles.cs +++ b/TestStack.ConventionTests/ConventionData/ProjectFiles.cs @@ -1,20 +1,17 @@ namespace TestStack.ConventionTests.ConventionData { - using System; using System.Linq; using System.Reflection; using System.Xml.Linq; using TestStack.ConventionTests.Internal; - public class ProjectFiles : AbstractProjectData + public class ProjectFiles : AbstractProjectData, ICreateReportLineFor { public ProjectFiles(Assembly assembly, IProjectProvider projectProvider, IProjectLocator projectLocator) : base(assembly, projectProvider, projectLocator) { - Items = PredicateHelpers.All(); } - public ProjectFile[] Files { get @@ -31,11 +28,13 @@ public ProjectFile[] Files ReferenceType = refElem.Name.LocalName, FilePath = refElem.Attribute("Include").Value }) - .Where(Items) .ToArray(); } } - public Func Items { get; set; } + public ConventionFailure CreateReportLine(ProjectFile failingData) + { + return new ConventionFailure(failingData.FilePath); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionData/ProjectReferences.cs b/TestStack.ConventionTests/ConventionData/ProjectReferences.cs index b22aa2a..dfc97b0 100644 --- a/TestStack.ConventionTests/ConventionData/ProjectReferences.cs +++ b/TestStack.ConventionTests/ConventionData/ProjectReferences.cs @@ -7,7 +7,7 @@ using System.Xml.Linq; using TestStack.ConventionTests.Internal; - public class ProjectReferences : AbstractProjectData + public class ProjectReferences : AbstractProjectData, ICreateReportLineFor { public ProjectReferences(Assembly assembly, IProjectProvider projectProvider, IProjectLocator projectLocator) : base(assembly, projectProvider, projectLocator) @@ -43,5 +43,10 @@ static IEnumerable AllProjectReferences(XDocument projDefinition) } public Func Items { get; set; } + + public ConventionFailure CreateReportLine(ProjectReference failingData) + { + return new ConventionFailure(failingData.ReferencedPath); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionData/Types.cs b/TestStack.ConventionTests/ConventionData/Types.cs index 74d1cc0..ef87707 100644 --- a/TestStack.ConventionTests/ConventionData/Types.cs +++ b/TestStack.ConventionTests/ConventionData/Types.cs @@ -1,20 +1,38 @@ namespace TestStack.ConventionTests.ConventionData { using System; + using System.Reflection; using TestStack.ConventionTests.Conventions; using TestStack.ConventionTests.Internal; /// /// This is where we set what our convention is all about. /// - public class Types : IConventionData + public class Types : IConventionData, ICreateReportLineFor, ICreateReportLineFor { + public Types(string descriptionOfTypes) + { + Description = descriptionOfTypes; + } + public Type[] TypesToVerify { get; set; } + public string Description { get; private set; } + public void EnsureHasNonEmptySource() { if (TypesToVerify.None()) throw new ConventionSourceInvalidException("You must supply types to verify"); } + + public ConventionFailure CreateReportLine(Type failingData) + { + return new ConventionFailure(failingData.FullName); + } + + public ConventionFailure CreateReportLine(MethodInfo failingData) + { + return new ConventionFailure(failingData.DeclaringType + "." + failingData.Name); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionFailure.cs b/TestStack.ConventionTests/ConventionFailure.cs new file mode 100644 index 0000000..702e440 --- /dev/null +++ b/TestStack.ConventionTests/ConventionFailure.cs @@ -0,0 +1,17 @@ +namespace TestStack.ConventionTests +{ + public class ConventionFailure + { + public string Failure { get; set; } + + public ConventionFailure(string failure) + { + Failure = failure; + } + + public override string ToString() + { + return Failure; + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionReport.cs b/TestStack.ConventionTests/ConventionReport.cs new file mode 100644 index 0000000..d2fd0c4 --- /dev/null +++ b/TestStack.ConventionTests/ConventionReport.cs @@ -0,0 +1,29 @@ +namespace TestStack.ConventionTests +{ + using System.Collections.Generic; + using System.Linq; + + public class ConventionReport + { + public Result Result { get; private set; } + public string ConventionTitle { get; private set; } + public string DataDescription { get; private set; } + public IEnumerable ConventionFailures { get; private set; } + public string ApprovedException { get; private set; } + + public ConventionReport(Result result, string conventionTitle, string dataDescription, IEnumerable conventionFailures) + { + Result = result; + ConventionTitle = conventionTitle; + DataDescription = dataDescription; + ConventionFailures = conventionFailures; + } + + public void WithApprovedException(string output) + { + ApprovedException = output; + Result = Result.Passed; + ConventionFailures = Enumerable.Empty(); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionReportTextRenderer.cs b/TestStack.ConventionTests/ConventionReportTextRenderer.cs new file mode 100644 index 0000000..94ac63d --- /dev/null +++ b/TestStack.ConventionTests/ConventionReportTextRenderer.cs @@ -0,0 +1,52 @@ +namespace TestStack.ConventionTests +{ + using System.Text; + + public class ConventionReportTextRenderer : IConventionReportRenderer + { + public void Render(params ConventionReport[] conventionResult) + { + var stringBuilder = new StringBuilder(); + + foreach (var conventionReport in conventionResult) + { + var title = string.Format("{0}: '{1}' for '{2}'", conventionReport.Result, conventionReport.ConventionTitle, + conventionReport.DataDescription); + stringBuilder.AppendLine(title); + stringBuilder.AppendLine(string.Empty.PadRight(title.Length, '-')); + stringBuilder.AppendLine(); + + if (!string.IsNullOrEmpty(conventionReport.ApprovedException)) + { + stringBuilder.AppendLine("With approved exceptions:"); + stringBuilder.AppendLine(conventionReport.ApprovedException); + stringBuilder.AppendLine(); + } + + RenderItems(conventionReport, stringBuilder); + stringBuilder.AppendLine(); + stringBuilder.AppendLine(); + } + + Output = stringBuilder.ToString().TrimEnd(); + } + + public string Output { get; private set; } + + public void RenderItems(ConventionReport conventionResult) + { + var stringBuilder = new StringBuilder(); + RenderItems(conventionResult, stringBuilder); + Output = stringBuilder.ToString(); + } + + static void RenderItems(ConventionReport conventionReport, StringBuilder stringBuilder) + { + foreach (var conventionFailure in conventionReport.ConventionFailures) + { + stringBuilder.Append("\t"); + stringBuilder.AppendLine(conventionFailure.ToString()); + } + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionReportTraceRenderer.cs b/TestStack.ConventionTests/ConventionReportTraceRenderer.cs new file mode 100644 index 0000000..a9895c0 --- /dev/null +++ b/TestStack.ConventionTests/ConventionReportTraceRenderer.cs @@ -0,0 +1,14 @@ +namespace TestStack.ConventionTests +{ + using System.Diagnostics; + + public class ConventionReportTraceRenderer : IConventionReportRenderer + { + public void Render(params ConventionReport[] conventionResult) + { + var conventionReportTextRenderer = new ConventionReportTextRenderer(); + conventionReportTextRenderer.Render(conventionResult); + Trace.WriteLine(conventionReportTextRenderer.Output); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionResultExceptionReporter.cs b/TestStack.ConventionTests/ConventionResultExceptionReporter.cs new file mode 100644 index 0000000..b51dcba --- /dev/null +++ b/TestStack.ConventionTests/ConventionResultExceptionReporter.cs @@ -0,0 +1,18 @@ +namespace TestStack.ConventionTests +{ + using System.Diagnostics; + using System.Linq; + + public class ConventionResultExceptionReporter : IConventionReportRenderer + { + public void Render(params ConventionReport[] conventionResult) + { + var conventionReportTextRenderer = new ConventionReportTextRenderer(); + conventionReportTextRenderer.Render(conventionResult); + if (conventionResult.Any(r => r.Result == Result.Failed)) + { + throw new ConventionFailedException(conventionReportTextRenderer.Output); + } + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs index 3881284..1ee0810 100644 --- a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs +++ b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs @@ -1,22 +1,18 @@ namespace TestStack.ConventionTests.Conventions { + using System; + using System.Collections.Generic; using System.Linq; using TestStack.ConventionTests.ConventionData; using TestStack.ConventionTests.Internal; - public class AllClassesHaveDefaultConstructor : IConvention + public class AllClassesHaveDefaultConstructor : IConvention { - public AllClassesHaveDefaultConstructor() - { - HeaderMessage = "The following types do not have default constructor"; - } - - public string HeaderMessage { get; set; } + public string ConventionTitle { get { return "Types must have a default constructor"; } } - public ConventionResult Execute(Types data) + public IEnumerable GetFailingData(Types data) { - var invalid = data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false); - return ConventionResult.For(invalid, HeaderMessage, t => "\t" + t); + return data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs index 99b4154..bd9a7b7 100644 --- a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs +++ b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs @@ -1,44 +1,18 @@ namespace TestStack.ConventionTests.Conventions { - using System; using System.Collections.Generic; using System.Linq; using System.Reflection; - using System.Text; using TestStack.ConventionTests.ConventionData; using TestStack.ConventionTests.Internal; - public class AllMethodsAreVirtual : IConvention + public class AllMethodsAreVirtual : IConvention { - public AllMethodsAreVirtual() - { - HeaderMessage = "The following methods are not virtual."; - } - - public string HeaderMessage { get; set; } - - public ConventionResult Execute(Types data) - { - // do we want to encapsulate that in some way? - // also notice how data gives us types, yet the convention acts upon methods. - var items = from applicableType in data.TypesToVerify - let nonVirtuals = applicableType.NonVirtualMethods() - where nonVirtuals.Any() - select Tuple.Create(applicableType, nonVirtuals); - return ConventionResult.For(HeaderMessage, items, DescribeTypeAndMethods); - } + public string ConventionTitle { get { return "Methods must be virtual"; } } - // I like how that's encapsulated in the reusable convention type, whereas previously it was part of the convention/test code - void DescribeTypeAndMethods(Tuple> item, StringBuilder message) + public IEnumerable GetFailingData(Types data) { - foreach (var method in item.Item2) - { - message.Append("\t"); - message.Append(item.Item1); - message.Append("."); - message.Append(method.Name); - message.AppendLine(); - } + return data.TypesToVerify.SelectMany(t => t.NonVirtualMethods()); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs index 700b47d..fb7e9b9 100644 --- a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs +++ b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs @@ -1,9 +1,9 @@ namespace TestStack.ConventionTests.Conventions { using System; + using System.Collections.Generic; using System.Linq; using TestStack.ConventionTests.ConventionData; - using TestStack.ConventionTests.Internal; /// /// This convention allows you to enforce a particular type of class is under a namespace, for instance. @@ -14,7 +14,7 @@ /// /// This is a Symmetric convention, and will verify all of a Class Type lives in the namespace, but also that only that class type is in that namespace /// - public class ClassTypeHasSpecificNamespace : IConvention + public class ClassTypeHasSpecificNamespace : ISymmetricConvention { readonly Func classIsApplicable; readonly string namespaceToCheck; @@ -33,24 +33,34 @@ public ClassTypeHasSpecificNamespace(Func classIsApplicable, string this.classType = classType; } - public ConventionResult Execute(Types data) + public string ConventionTitle { - var applicableTypes = data.TypesToVerify.Where(classIsApplicable); - var nonApplicableTypes = data.TypesToVerify.Where(t => !classIsApplicable(t)); + get + { + return string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck); + } + } - var applicableTypesWhichDoNotConform = applicableTypes - .Where(t => t.Namespace == null || !t.Namespace.StartsWith(namespaceToCheck)) - .ToArray(); - var nonApplicableTypesInNamespace = nonApplicableTypes - .Where(t => t.Namespace != null && t.Namespace.StartsWith(namespaceToCheck)) - .ToArray(); + public string InverseTitle + { + get + { + return string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck); + } + } - return ConventionResult.ForSymmetric( - string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck), - applicableTypesWhichDoNotConform, - string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck), - nonApplicableTypesInNamespace, - t => "\t" + t.FullName); + public IEnumerable GetFailingData(Types data) + { + return data.TypesToVerify + .Where(classIsApplicable) + .Where(t => t.Namespace == null || !t.Namespace.StartsWith(namespaceToCheck)); + } + + public IEnumerable GetFailingInverseData(Types data) + { + return data.TypesToVerify + .Where(t => !classIsApplicable(t)) + .Where(t => t.Namespace != null && t.Namespace.StartsWith(namespaceToCheck)); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs index fe3f402..8e23ae5 100644 --- a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs +++ b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs @@ -1,15 +1,29 @@ namespace TestStack.ConventionTests.Conventions { + using System.Collections.Generic; using System.Linq; using TestStack.ConventionTests.ConventionData; - using TestStack.ConventionTests.Internal; - public class FilesAreEmbeddedResources : IConvention + public class FilesAreEmbeddedResources : IConvention { - public ConventionResult Execute(ProjectFiles data) + public FilesAreEmbeddedResources(string fileExtension) { - return ConventionResult.For("The following files which should be embedded resources:", - data.Files.Where(s => s.ReferenceType != "EmbeddedResource"), (t, m) => m.AppendLine("\t" + t.FilePath)); + FileExtension = fileExtension; + } + + public string ConventionTitle + { + get + { + return string.Format("{0} Files must be embedded resources", FileExtension); + } + } + + public string FileExtension { get; set; } + + public IEnumerable GetFailingData(ProjectFiles data) + { + return data.Files.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource"); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/ISymmetricConvention.cs b/TestStack.ConventionTests/Conventions/ISymmetricConvention.cs new file mode 100644 index 0000000..e33ede0 --- /dev/null +++ b/TestStack.ConventionTests/Conventions/ISymmetricConvention.cs @@ -0,0 +1,12 @@ +namespace TestStack.ConventionTests.Conventions +{ + using System.Collections.Generic; + + public interface ISymmetricConvention where T : IConventionData + { + string ConventionTitle { get; } + string InverseTitle { get; } + IEnumerable GetFailingData(T data); + IEnumerable GetFailingInverseData(T data); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs index 8d8efba..92f144f 100644 --- a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs +++ b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs @@ -1,30 +1,24 @@ namespace TestStack.ConventionTests.Conventions { + using System.Collections.Generic; using System.Linq; - using System.Text; using System.Text.RegularExpressions; using TestStack.ConventionTests.ConventionData; - using TestStack.ConventionTests.Internal; - public class ProjectDoesNotReferenceDllsFromBinOrObjDirectories : IConvention + public class ProjectDoesNotReferenceDllsFromBinOrObjDirectories : IConvention { const string AssemblyReferencingObjRegex = @"^(?.*?(obj|bin).*?)$"; - public ConventionResult Execute(ProjectReferences data) + static bool IsBinOrObjReference(ProjectReference reference) { - var invalid = data.References.Where(IsBinOrObjReference); - var header = string.Format("Some invalid assembly references found in {0}", data.Assembly.GetName().Name); - return ConventionResult.For(header, invalid, FormatLine); + return Regex.IsMatch(reference.ReferencedPath, AssemblyReferencingObjRegex, RegexOptions.IgnoreCase); } - void FormatLine(ProjectReference assemblyReference, StringBuilder m) - { - m.AppendLine("\t" + assemblyReference.ReferencedPath); - } + public string ConventionTitle { get { return "Project must not reference dlls from bin or obj directories"; } } - static bool IsBinOrObjReference(ProjectReference reference) + public IEnumerable GetFailingData(ProjectReferences data) { - return Regex.IsMatch(reference.ReferencedPath, AssemblyReferencingObjRegex, RegexOptions.IgnoreCase); + return data.References.Where(IsBinOrObjReference); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/IConvention.cs b/TestStack.ConventionTests/IConvention.cs index 82a0908..d3c3a38 100644 --- a/TestStack.ConventionTests/IConvention.cs +++ b/TestStack.ConventionTests/IConvention.cs @@ -1,9 +1,10 @@ namespace TestStack.ConventionTests { - using TestStack.ConventionTests.Internal; + using System.Collections.Generic; - public interface IConvention where T : IConventionData + public interface IConvention where T : IConventionData { - ConventionResult Execute(T data); + string ConventionTitle { get; } + IEnumerable GetFailingData(T data); } } \ No newline at end of file diff --git a/TestStack.ConventionTests/IConventionData.cs b/TestStack.ConventionTests/IConventionData.cs index 26b0215..5cb17b8 100644 --- a/TestStack.ConventionTests/IConventionData.cs +++ b/TestStack.ConventionTests/IConventionData.cs @@ -2,6 +2,7 @@ { public interface IConventionData { + string Description { get; } void EnsureHasNonEmptySource(); } } \ No newline at end of file diff --git a/TestStack.ConventionTests/IConventionReportRenderer.cs b/TestStack.ConventionTests/IConventionReportRenderer.cs new file mode 100644 index 0000000..e0ff8eb --- /dev/null +++ b/TestStack.ConventionTests/IConventionReportRenderer.cs @@ -0,0 +1,7 @@ +namespace TestStack.ConventionTests +{ + public interface IConventionReportRenderer + { + void Render(params ConventionReport[] conventionResult); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/ICreateReportLineFor.cs b/TestStack.ConventionTests/ICreateReportLineFor.cs new file mode 100644 index 0000000..eb156e2 --- /dev/null +++ b/TestStack.ConventionTests/ICreateReportLineFor.cs @@ -0,0 +1,7 @@ +namespace TestStack.ConventionTests +{ + public interface ICreateReportLineFor + { + ConventionFailure CreateReportLine(T failingData); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs deleted file mode 100644 index af09e8f..0000000 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace TestStack.ConventionTests.Internal -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - - public class ConventionResult - { - ConventionResult(bool failed) - { - Failed = failed; - } - - public string Message { get; private set; } - - public bool Failed { get; private set; } - - public static ConventionResult For( - string header, IEnumerable items, - Action itemDescriptor) - { - var array = items.ToArray(); - if (array.None()) - { - return new ConventionResult(failed: false); - } - - var result = new ConventionResult(true); - var message = new StringBuilder(header); - message.AppendLine(); - message.AppendLine(string.Empty.PadRight(header.Length, '-')); - message.AppendLine(); - Array.ForEach(array, r => itemDescriptor(r, message)); - result.Message = message.ToString(); - return result; - } - - public static ConventionResult For( - IEnumerable items, string header, - Func itemDescriptor) - { - return For(header, items, (item, message) => message.AppendLine(itemDescriptor(item))); - } - - public static ConventionResult ForSymmetric( - string firstHeader, TResult[] firstResults, - string secondHeader, TResult[] secondResults, - Action itemDescriptor) - { - var firstArray = firstResults.ToArray(); - var secondArray = secondResults.ToArray(); - if (firstArray.None() && secondArray.None()) - { - return new ConventionResult(failed: true); - } - - var message = new StringBuilder(); - if (firstArray.Any()) - { - message.AppendLine(firstHeader); - message.AppendLine(string.Empty.PadRight(firstHeader.Length, '-')); - message.AppendLine(); - Array.ForEach(firstArray, r => itemDescriptor(r, message)); - } - if (secondArray.Any()) - { - if (firstArray.Any()) - { - message.AppendLine(); - message.AppendLine(); - } - message.AppendLine(secondHeader); - message.AppendLine(string.Empty.PadRight(secondHeader.Length, '-')); - message.AppendLine(); - Array.ForEach(secondArray, r => itemDescriptor(r, message)); - } - result.Message = message.ToString(); - return result; - } - - public static ConventionResult ForSymmetric( - string firstHeader, TResult[] firstResults, - string secondHeader, TResult[] secondResults, - Func itemDescriptor) - { - return ForSymmetric( - firstHeader, firstResults, secondHeader, - secondResults, - (item, message) => message.AppendLine(itemDescriptor(item))); - } - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/Result.cs b/TestStack.ConventionTests/Result.cs new file mode 100644 index 0000000..1ade252 --- /dev/null +++ b/TestStack.ConventionTests/Result.cs @@ -0,0 +1,8 @@ +namespace TestStack.ConventionTests +{ + public enum Result + { + Passed, + Failed + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 5f2b876..6a3ffba 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -60,17 +60,24 @@ + + + + + + - + + @@ -85,6 +92,7 @@ + From 75ebb13280590716df589d3a9e7a557c53053b67 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Thu, 8 Aug 2013 13:46:03 +0100 Subject: [PATCH 4/9] Moved things around --- .../ConventionAssertionClassTests.cs | 1 + TestStack.ConventionTests/ConventionReport.cs | 1 + .../ConventionReportTextRenderer.cs | 2 +- .../ConventionReportTraceRenderer.cs | 26 +++++++++---------- .../ConventionResultExceptionReporter.cs | 3 +-- .../{ => Internal}/ICreateReportLineFor.cs | 12 ++++----- .../{ => Internal}/Result.cs | 14 +++++----- .../TestStack.ConventionTests.csproj | 10 +++---- 8 files changed, 35 insertions(+), 34 deletions(-) rename TestStack.ConventionTests/{ => Internal}/ConventionReportTextRenderer.cs (94%) rename TestStack.ConventionTests/{ => Internal}/ConventionReportTraceRenderer.cs (87%) rename TestStack.ConventionTests/{ => Internal}/ConventionResultExceptionReporter.cs (86%) rename TestStack.ConventionTests/{ => Internal}/ICreateReportLineFor.cs (69%) rename TestStack.ConventionTests/{ => Internal}/Result.cs (55%) diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 3a587d8..5afa207 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using ApprovalTests.Reporters; using NUnit.Framework; + using TestStack.ConventionTests.Internal; [TestFixture] [UseReporter(typeof(DiffReporter))] //NOTE: Can we take care of this in IsWithApprovedExceptions? diff --git a/TestStack.ConventionTests/ConventionReport.cs b/TestStack.ConventionTests/ConventionReport.cs index d2fd0c4..d7bcd12 100644 --- a/TestStack.ConventionTests/ConventionReport.cs +++ b/TestStack.ConventionTests/ConventionReport.cs @@ -2,6 +2,7 @@ { using System.Collections.Generic; using System.Linq; + using TestStack.ConventionTests.Internal; public class ConventionReport { diff --git a/TestStack.ConventionTests/ConventionReportTextRenderer.cs b/TestStack.ConventionTests/Internal/ConventionReportTextRenderer.cs similarity index 94% rename from TestStack.ConventionTests/ConventionReportTextRenderer.cs rename to TestStack.ConventionTests/Internal/ConventionReportTextRenderer.cs index 94ac63d..697b4de 100644 --- a/TestStack.ConventionTests/ConventionReportTextRenderer.cs +++ b/TestStack.ConventionTests/Internal/ConventionReportTextRenderer.cs @@ -1,4 +1,4 @@ -namespace TestStack.ConventionTests +namespace TestStack.ConventionTests.Internal { using System.Text; diff --git a/TestStack.ConventionTests/ConventionReportTraceRenderer.cs b/TestStack.ConventionTests/Internal/ConventionReportTraceRenderer.cs similarity index 87% rename from TestStack.ConventionTests/ConventionReportTraceRenderer.cs rename to TestStack.ConventionTests/Internal/ConventionReportTraceRenderer.cs index a9895c0..7d0a3be 100644 --- a/TestStack.ConventionTests/ConventionReportTraceRenderer.cs +++ b/TestStack.ConventionTests/Internal/ConventionReportTraceRenderer.cs @@ -1,14 +1,14 @@ -namespace TestStack.ConventionTests -{ - using System.Diagnostics; - - public class ConventionReportTraceRenderer : IConventionReportRenderer - { - public void Render(params ConventionReport[] conventionResult) - { - var conventionReportTextRenderer = new ConventionReportTextRenderer(); - conventionReportTextRenderer.Render(conventionResult); - Trace.WriteLine(conventionReportTextRenderer.Output); - } - } +namespace TestStack.ConventionTests.Internal +{ + using System.Diagnostics; + + public class ConventionReportTraceRenderer : IConventionReportRenderer + { + public void Render(params ConventionReport[] conventionResult) + { + var conventionReportTextRenderer = new ConventionReportTextRenderer(); + conventionReportTextRenderer.Render(conventionResult); + Trace.WriteLine(conventionReportTextRenderer.Output); + } + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionResultExceptionReporter.cs b/TestStack.ConventionTests/Internal/ConventionResultExceptionReporter.cs similarity index 86% rename from TestStack.ConventionTests/ConventionResultExceptionReporter.cs rename to TestStack.ConventionTests/Internal/ConventionResultExceptionReporter.cs index b51dcba..d9babfd 100644 --- a/TestStack.ConventionTests/ConventionResultExceptionReporter.cs +++ b/TestStack.ConventionTests/Internal/ConventionResultExceptionReporter.cs @@ -1,6 +1,5 @@ -namespace TestStack.ConventionTests +namespace TestStack.ConventionTests.Internal { - using System.Diagnostics; using System.Linq; public class ConventionResultExceptionReporter : IConventionReportRenderer diff --git a/TestStack.ConventionTests/ICreateReportLineFor.cs b/TestStack.ConventionTests/Internal/ICreateReportLineFor.cs similarity index 69% rename from TestStack.ConventionTests/ICreateReportLineFor.cs rename to TestStack.ConventionTests/Internal/ICreateReportLineFor.cs index eb156e2..3628b0b 100644 --- a/TestStack.ConventionTests/ICreateReportLineFor.cs +++ b/TestStack.ConventionTests/Internal/ICreateReportLineFor.cs @@ -1,7 +1,7 @@ -namespace TestStack.ConventionTests -{ - public interface ICreateReportLineFor - { - ConventionFailure CreateReportLine(T failingData); - } +namespace TestStack.ConventionTests.Internal +{ + public interface ICreateReportLineFor + { + ConventionFailure CreateReportLine(T failingData); + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Result.cs b/TestStack.ConventionTests/Internal/Result.cs similarity index 55% rename from TestStack.ConventionTests/Result.cs rename to TestStack.ConventionTests/Internal/Result.cs index 1ade252..99a054d 100644 --- a/TestStack.ConventionTests/Result.cs +++ b/TestStack.ConventionTests/Internal/Result.cs @@ -1,8 +1,8 @@ -namespace TestStack.ConventionTests -{ - public enum Result - { - Passed, - Failed - } +namespace TestStack.ConventionTests.Internal +{ + public enum Result + { + Passed, + Failed + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 6a3ffba..0b7edbe 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -62,9 +62,9 @@ - - - + + + @@ -77,7 +77,7 @@ - + @@ -92,7 +92,7 @@ - + From 6cb6ed460ccc28c2a8df1e29c4b4eff66cc8a6a4 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Thu, 8 Aug 2013 14:42:39 +0100 Subject: [PATCH 5/9] Added a crappy html renderer, but we have the conventions being outputted in a single file --- TestStack.ConventionTests/Convention.cs | 61 ++++++++++++--- .../HtmlReportRenderer.cs | 77 +++++++++++++++++++ .../TestStack.ConventionTests.csproj | 2 + 3 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 TestStack.ConventionTests/HtmlReportRenderer.cs diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 31254b6..99f5d3d 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -1,7 +1,10 @@ namespace TestStack.ConventionTests { + using System; using System.Collections.Generic; + using System.IO; using System.Linq; + using System.Reflection; using ApprovalTests; using ApprovalTests.Core.Exceptions; using TestStack.ConventionTests.Conventions; @@ -9,6 +12,7 @@ public static class Convention { + static readonly HtmlReportRenderer HtmlRenderer = new HtmlReportRenderer(AssemblyDirectory); static readonly List Reports = new List(); public static IEnumerable ConventionReports { get { return Reports; } } @@ -22,18 +26,26 @@ public static void Is(IConvention(IConvention convention, TDataSource data, IConventionReportRenderer reporter) where TDataSource : IConventionData, ICreateReportLineFor { - var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + try + { + var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); - Reports.Add(conventionResult); + Reports.Add(conventionResult); - new ConventionReportTraceRenderer().Render(conventionResult); - reporter.Render(conventionResult); + new ConventionReportTraceRenderer().Render(conventionResult); + reporter.Render(conventionResult); + } + finally + { + HtmlRenderer.Render(Reports.ToArray()); + } } public static void IsWithApprovedExeptions(IConvention convention, TDataSource data) where TDataSource : IConventionData, ICreateReportLineFor { var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + Reports.Add(conventionResult); try { @@ -50,6 +62,10 @@ public static void IsWithApprovedExeptions(IConvention(ISymmetricConvention convention, TDataSource data) @@ -61,14 +77,21 @@ public static void Is(ISymmetricConvention(ISymmetricConvention convention, TDataSource data, IConventionReportRenderer reporter) where TDataSource : IConventionData, ICreateReportLineFor { - var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); - var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); + try + { + var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); - Reports.Add(conventionResult); - Reports.Add(inverseConventionResult); + Reports.Add(conventionResult); + Reports.Add(inverseConventionResult); - new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult); - reporter.Render(conventionResult, inverseConventionResult); + new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult); + reporter.Render(conventionResult, inverseConventionResult); + } + finally + { + HtmlRenderer.Render(Reports.ToArray()); + } } public static void IsWithApprovedExeptions(ISymmetricConvention convention, TDataSource data) @@ -76,6 +99,8 @@ public static void IsWithApprovedExeptions(ISymmetricCon { var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); + Reports.Add(conventionResult); + Reports.Add(inverseConventionResult); try { @@ -99,6 +124,10 @@ public static void IsWithApprovedExeptions(ISymmetricCon { throw new ConventionFailedException("Approved exceptions for convention differs\r\n\r\n" + ex.Message, ex); } + finally + { + HtmlRenderer.Render(Reports.ToArray()); + } } static ConventionReport GetConventionReport(string conventionTitle, TDataType[] failingData, TDataSource data) @@ -114,5 +143,17 @@ static ConventionReport GetConventionReport(string conve failingData.Select(data.CreateReportLine)); return conventionResult; } + + // http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917 + static string AssemblyDirectory + { + get + { + string codeBase = Assembly.GetExecutingAssembly().CodeBase; + var uri = new UriBuilder(codeBase); + string path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path); + } + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/HtmlReportRenderer.cs b/TestStack.ConventionTests/HtmlReportRenderer.cs new file mode 100644 index 0000000..b1dc540 --- /dev/null +++ b/TestStack.ConventionTests/HtmlReportRenderer.cs @@ -0,0 +1,77 @@ +namespace TestStack.ConventionTests +{ + using System.IO; + using System.Text; + using System.Web.UI; + + public class HtmlReportRenderer : IConventionReportRenderer + { + readonly string file; + + public HtmlReportRenderer(string assemblyDirectory) + { + file = Path.Combine(assemblyDirectory, "Conventions.htm"); + } + + public void Render(params ConventionReport[] conventionResult) + { + var sb = new StringBuilder(); + var html = new HtmlTextWriter(new StringWriter(sb)); + html.WriteLine(""); + html.RenderBeginTag(HtmlTextWriterTag.Html); // + html.RenderBeginTag(HtmlTextWriterTag.Head); // + html.RenderEndTag(); // + html.WriteLine(); + html.RenderBeginTag(HtmlTextWriterTag.Body); // + + html.RenderBeginTag(HtmlTextWriterTag.H1); + html.Write("Project Conventions"); + html.RenderEndTag(); + + foreach (var conventionReport in conventionResult) + { + html.RenderBeginTag(HtmlTextWriterTag.P); + html.RenderBeginTag(HtmlTextWriterTag.Div); + html.RenderBeginTag(HtmlTextWriterTag.Strong); + html.Write(conventionReport.Result+": "); + html.RenderEndTag(); + var title = string.Format("{0} for {1}", conventionReport.ConventionTitle, conventionReport.DataDescription); + html.Write(title); + if (!string.IsNullOrEmpty(conventionReport.ApprovedException)) + { + html.RenderBeginTag(HtmlTextWriterTag.Div); + html.RenderBeginTag(HtmlTextWriterTag.Strong); + html.WriteLine("With approved exceptions:"); + html.RenderEndTag(); + html.RenderEndTag(); + } + + html.RenderBeginTag(HtmlTextWriterTag.Ul); + + if (!string.IsNullOrEmpty(conventionReport.ApprovedException)) + { + html.RenderBeginTag(HtmlTextWriterTag.Li); + html.WriteLine(conventionReport.ApprovedException); + html.RenderEndTag(); + } + + foreach (var conventionFailure in conventionReport.ConventionFailures) + { + html.RenderBeginTag(HtmlTextWriterTag.Li); + html.Write(conventionFailure.ToString()); + html.RenderEndTag(); + } + + html.RenderEndTag(); + html.RenderEndTag(); + html.RenderEndTag(); + } + + html.RenderEndTag(); // + html.RenderEndTag(); // + html.Flush(); + + File.WriteAllText(file, sb.ToString()); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 0b7edbe..d626be4 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -52,6 +52,7 @@ + @@ -62,6 +63,7 @@ + From ece13460fed847ffbe18f7e36be6476bdc170720 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 10 Aug 2013 08:39:25 +0100 Subject: [PATCH 6/9] Pulled out data formatters --- .../ConventionAssertionClassTests.cs | 6 +-- TestStack.ConventionTests/Convention.cs | 50 ++++++++++++++----- .../ConventionData/ProjectFiles.cs | 7 +-- .../ConventionData/ProjectReferences.cs | 11 +--- .../ConventionData/Types.cs | 13 +---- TestStack.ConventionTests/ConventionReport.cs | 30 ----------- .../IConventionReportRenderer.cs | 7 --- .../ConventionReportFailure.cs} | 32 ++++++------ .../Internal/ICreateReportLineFor.cs | 7 --- .../Internal/NoDataFormatterFoundException.cs | 27 ++++++++++ TestStack.ConventionTests/Internal/Result.cs | 8 --- .../Internal/ResultInfo.cs | 28 +++++++++++ .../ConventionReportTextRenderer.cs | 11 ++-- .../ConventionReportTraceRenderer.cs | 5 +- .../ConventionResultExceptionReporter.cs | 7 +-- .../{ => Reporting}/HtmlReportRenderer.cs | 5 +- .../Reporting/IConventionReportRenderer.cs | 9 ++++ .../Reporting/IReportDataFormatter.cs | 10 ++++ .../Reporting/MethodInfoDataFormatter.cs | 20 ++++++++ .../Reporting/ProjectFileFormatter.cs | 18 +++++++ .../Reporting/ProjectReferenceFormatter.cs | 18 +++++++ .../Reporting/StringDataFormatter.cs | 17 +++++++ .../Reporting/TestResult.cs | 8 +++ .../Reporting/TypeDataFormatter.cs | 18 +++++++ .../TestStack.ConventionTests.csproj | 24 +++++---- 25 files changed, 263 insertions(+), 133 deletions(-) delete mode 100644 TestStack.ConventionTests/ConventionReport.cs delete mode 100644 TestStack.ConventionTests/IConventionReportRenderer.cs rename TestStack.ConventionTests/{ConventionFailure.cs => Internal/ConventionReportFailure.cs} (55%) delete mode 100644 TestStack.ConventionTests/Internal/ICreateReportLineFor.cs create mode 100644 TestStack.ConventionTests/Internal/NoDataFormatterFoundException.cs delete mode 100644 TestStack.ConventionTests/Internal/Result.cs create mode 100644 TestStack.ConventionTests/Internal/ResultInfo.cs rename TestStack.ConventionTests/{Internal => Reporting}/ConventionReportTextRenderer.cs (78%) rename TestStack.ConventionTests/{Internal => Reporting}/ConventionReportTraceRenderer.cs (67%) rename TestStack.ConventionTests/{Internal => Reporting}/ConventionResultExceptionReporter.cs (61%) rename TestStack.ConventionTests/{ => Reporting}/HtmlReportRenderer.cs (92%) create mode 100644 TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs create mode 100644 TestStack.ConventionTests/Reporting/IReportDataFormatter.cs create mode 100644 TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs create mode 100644 TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs create mode 100644 TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs create mode 100644 TestStack.ConventionTests/Reporting/StringDataFormatter.cs create mode 100644 TestStack.ConventionTests/Reporting/TestResult.cs create mode 100644 TestStack.ConventionTests/Reporting/TypeDataFormatter.cs diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 5afa207..0430d1a 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -20,7 +20,7 @@ public void approval_mismatch() StringAssert.Contains("does not match approved file", ex.Message); } - public class FakeData : IConventionData, ICreateReportLineFor + public class FakeData : IConventionData { public string Description { get { return "Fake data"; } } @@ -28,9 +28,9 @@ public void EnsureHasNonEmptySource() { } - public ConventionFailure CreateReportLine(string failingData) + public ConventionReportFailure Format(string failingData) { - return new ConventionFailure(failingData); + return new ConventionReportFailure(failingData); } } diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 99f5d3d..6aa9763 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -9,22 +9,36 @@ using ApprovalTests.Core.Exceptions; using TestStack.ConventionTests.Conventions; using TestStack.ConventionTests.Internal; + using TestStack.ConventionTests.Reporting; public static class Convention { static readonly HtmlReportRenderer HtmlRenderer = new HtmlReportRenderer(AssemblyDirectory); - static readonly List Reports = new List(); + static readonly List Reports = new List(); - public static IEnumerable ConventionReports { get { return Reports; } } + static Convention() + { + Formatters = new List + { + new TypeDataFormatter(), + new ProjectReferenceFormatter(), + new ProjectFileFormatter(), + new MethodInfoDataFormatter(), + new StringDataFormatter() + }; + } + + public static IEnumerable ConventionReports { get { return Reports; } } + public static IList Formatters { get; private set; } public static void Is(IConvention convention, TDataSource data) - where TDataSource : IConventionData, ICreateReportLineFor + where TDataSource : IConventionData { Is(convention, data, new ConventionResultExceptionReporter()); } public static void Is(IConvention convention, TDataSource data, IConventionReportRenderer reporter) - where TDataSource : IConventionData, ICreateReportLineFor + where TDataSource : IConventionData { try { @@ -42,7 +56,7 @@ public static void Is(IConvention(IConvention convention, TDataSource data) - where TDataSource : IConventionData, ICreateReportLineFor + where TDataSource : IConventionData { var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); Reports.Add(conventionResult); @@ -69,13 +83,13 @@ public static void IsWithApprovedExeptions(IConvention(ISymmetricConvention convention, TDataSource data) - where TDataSource : IConventionData, ICreateReportLineFor + where TDataSource : IConventionData { Is(convention, data, new ConventionResultExceptionReporter()); } public static void Is(ISymmetricConvention convention, TDataSource data, IConventionReportRenderer reporter) - where TDataSource : IConventionData, ICreateReportLineFor + where TDataSource : IConventionData { try { @@ -95,7 +109,7 @@ public static void Is(ISymmetricConvention(ISymmetricConvention convention, TDataSource data) - where TDataSource : IConventionData, ICreateReportLineFor + where TDataSource : IConventionData { var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); @@ -130,20 +144,30 @@ public static void IsWithApprovedExeptions(ISymmetricCon } } - static ConventionReport GetConventionReport(string conventionTitle, TDataType[] failingData, TDataSource data) - where TDataSource : IConventionData, ICreateReportLineFor + static ResultInfo GetConventionReport(string conventionTitle, TDataType[] failingData, TDataSource data) + where TDataSource : IConventionData { data.EnsureHasNonEmptySource(); var passed = failingData.None(); - var conventionResult = new ConventionReport( - passed ? Result.Passed : Result.Failed, + var conventionResult = new ResultInfo( + passed ? TestResult.Passed : TestResult.Failed, conventionTitle, data.Description, - failingData.Select(data.CreateReportLine)); + failingData.Select(FormatData).ToArray()); return conventionResult; } + static ConventionReportFailure FormatData(T failingData) + { + var formatter = Formatters.FirstOrDefault(f => f.CanFormat(failingData)); + + if (formatter == null) + throw new NoDataFormatterFoundException(typeof(T).Name + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); + + return formatter.Format(failingData); + } + // http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917 static string AssemblyDirectory { diff --git a/TestStack.ConventionTests/ConventionData/ProjectFiles.cs b/TestStack.ConventionTests/ConventionData/ProjectFiles.cs index 6e3129c..71e45d8 100644 --- a/TestStack.ConventionTests/ConventionData/ProjectFiles.cs +++ b/TestStack.ConventionTests/ConventionData/ProjectFiles.cs @@ -5,7 +5,7 @@ using System.Xml.Linq; using TestStack.ConventionTests.Internal; - public class ProjectFiles : AbstractProjectData, ICreateReportLineFor + public class ProjectFiles : AbstractProjectData { public ProjectFiles(Assembly assembly, IProjectProvider projectProvider, IProjectLocator projectLocator) : base(assembly, projectProvider, projectLocator) @@ -31,10 +31,5 @@ public ProjectFile[] Files .ToArray(); } } - - public ConventionFailure CreateReportLine(ProjectFile failingData) - { - return new ConventionFailure(failingData.FilePath); - } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionData/ProjectReferences.cs b/TestStack.ConventionTests/ConventionData/ProjectReferences.cs index dfc97b0..eb83825 100644 --- a/TestStack.ConventionTests/ConventionData/ProjectReferences.cs +++ b/TestStack.ConventionTests/ConventionData/ProjectReferences.cs @@ -7,12 +7,11 @@ using System.Xml.Linq; using TestStack.ConventionTests.Internal; - public class ProjectReferences : AbstractProjectData, ICreateReportLineFor + public class ProjectReferences : AbstractProjectData { public ProjectReferences(Assembly assembly, IProjectProvider projectProvider, IProjectLocator projectLocator) : base(assembly, projectProvider, projectLocator) { - Items = PredicateHelpers.All(); } public ProjectReference[] References @@ -25,7 +24,6 @@ public ProjectReference[] References { ReferencedPath = r }) - .Where(Items) .ToArray(); } } @@ -41,12 +39,5 @@ static IEnumerable AllProjectReferences(XDocument projDefinition) .Select(refElem => refElem.Value); return references; } - - public Func Items { get; set; } - - public ConventionFailure CreateReportLine(ProjectReference failingData) - { - return new ConventionFailure(failingData.ReferencedPath); - } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionData/Types.cs b/TestStack.ConventionTests/ConventionData/Types.cs index ef87707..2df6157 100644 --- a/TestStack.ConventionTests/ConventionData/Types.cs +++ b/TestStack.ConventionTests/ConventionData/Types.cs @@ -1,14 +1,13 @@ namespace TestStack.ConventionTests.ConventionData { using System; - using System.Reflection; using TestStack.ConventionTests.Conventions; using TestStack.ConventionTests.Internal; /// /// This is where we set what our convention is all about. /// - public class Types : IConventionData, ICreateReportLineFor, ICreateReportLineFor + public class Types : IConventionData { public Types(string descriptionOfTypes) { @@ -24,15 +23,5 @@ public void EnsureHasNonEmptySource() if (TypesToVerify.None()) throw new ConventionSourceInvalidException("You must supply types to verify"); } - - public ConventionFailure CreateReportLine(Type failingData) - { - return new ConventionFailure(failingData.FullName); - } - - public ConventionFailure CreateReportLine(MethodInfo failingData) - { - return new ConventionFailure(failingData.DeclaringType + "." + failingData.Name); - } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionReport.cs b/TestStack.ConventionTests/ConventionReport.cs deleted file mode 100644 index d7bcd12..0000000 --- a/TestStack.ConventionTests/ConventionReport.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace TestStack.ConventionTests -{ - using System.Collections.Generic; - using System.Linq; - using TestStack.ConventionTests.Internal; - - public class ConventionReport - { - public Result Result { get; private set; } - public string ConventionTitle { get; private set; } - public string DataDescription { get; private set; } - public IEnumerable ConventionFailures { get; private set; } - public string ApprovedException { get; private set; } - - public ConventionReport(Result result, string conventionTitle, string dataDescription, IEnumerable conventionFailures) - { - Result = result; - ConventionTitle = conventionTitle; - DataDescription = dataDescription; - ConventionFailures = conventionFailures; - } - - public void WithApprovedException(string output) - { - ApprovedException = output; - Result = Result.Passed; - ConventionFailures = Enumerable.Empty(); - } - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/IConventionReportRenderer.cs b/TestStack.ConventionTests/IConventionReportRenderer.cs deleted file mode 100644 index e0ff8eb..0000000 --- a/TestStack.ConventionTests/IConventionReportRenderer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TestStack.ConventionTests -{ - public interface IConventionReportRenderer - { - void Render(params ConventionReport[] conventionResult); - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionFailure.cs b/TestStack.ConventionTests/Internal/ConventionReportFailure.cs similarity index 55% rename from TestStack.ConventionTests/ConventionFailure.cs rename to TestStack.ConventionTests/Internal/ConventionReportFailure.cs index 702e440..199b94c 100644 --- a/TestStack.ConventionTests/ConventionFailure.cs +++ b/TestStack.ConventionTests/Internal/ConventionReportFailure.cs @@ -1,17 +1,17 @@ -namespace TestStack.ConventionTests -{ - public class ConventionFailure - { - public string Failure { get; set; } - - public ConventionFailure(string failure) - { - Failure = failure; - } - - public override string ToString() - { - return Failure; - } - } +namespace TestStack.ConventionTests.Internal +{ + public class ConventionReportFailure + { + public string Failure { get; set; } + + public ConventionReportFailure(string failure) + { + Failure = failure; + } + + public override string ToString() + { + return Failure; + } + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ICreateReportLineFor.cs b/TestStack.ConventionTests/Internal/ICreateReportLineFor.cs deleted file mode 100644 index 3628b0b..0000000 --- a/TestStack.ConventionTests/Internal/ICreateReportLineFor.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TestStack.ConventionTests.Internal -{ - public interface ICreateReportLineFor - { - ConventionFailure CreateReportLine(T failingData); - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/NoDataFormatterFoundException.cs b/TestStack.ConventionTests/Internal/NoDataFormatterFoundException.cs new file mode 100644 index 0000000..6347ed1 --- /dev/null +++ b/TestStack.ConventionTests/Internal/NoDataFormatterFoundException.cs @@ -0,0 +1,27 @@ +namespace TestStack.ConventionTests.Internal +{ + using System; + using System.Runtime.Serialization; + + [Serializable] + public class NoDataFormatterFoundException : Exception + { + public NoDataFormatterFoundException() + { + } + + public NoDataFormatterFoundException(string message) : base(message) + { + } + + public NoDataFormatterFoundException(string message, Exception inner) : base(message, inner) + { + } + + protected NoDataFormatterFoundException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/Result.cs b/TestStack.ConventionTests/Internal/Result.cs deleted file mode 100644 index 99a054d..0000000 --- a/TestStack.ConventionTests/Internal/Result.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace TestStack.ConventionTests.Internal -{ - public enum Result - { - Passed, - Failed - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ResultInfo.cs b/TestStack.ConventionTests/Internal/ResultInfo.cs new file mode 100644 index 0000000..3b2828b --- /dev/null +++ b/TestStack.ConventionTests/Internal/ResultInfo.cs @@ -0,0 +1,28 @@ +namespace TestStack.ConventionTests.Internal +{ + using TestStack.ConventionTests.Reporting; + + public class ResultInfo + { + public TestResult Result { get; private set; } + public string ConventionTitle { get; private set; } + public string DataDescription { get; private set; } + public ConventionReportFailure[] ConventionFailures { get; private set; } + public string ApprovedException { get; private set; } + + public ResultInfo(TestResult result, string conventionTitle, string dataDescription, ConventionReportFailure[] conventionFailures) + { + Result = result; + ConventionTitle = conventionTitle; + DataDescription = dataDescription; + ConventionFailures = conventionFailures; + } + + public void WithApprovedException(string output) + { + ApprovedException = output; + Result = TestResult.Passed; + ConventionFailures = new ConventionReportFailure[0]; + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ConventionReportTextRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs similarity index 78% rename from TestStack.ConventionTests/Internal/ConventionReportTextRenderer.cs rename to TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs index 697b4de..3fda3d0 100644 --- a/TestStack.ConventionTests/Internal/ConventionReportTextRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs @@ -1,10 +1,11 @@ -namespace TestStack.ConventionTests.Internal +namespace TestStack.ConventionTests.Reporting { using System.Text; + using TestStack.ConventionTests.Internal; public class ConventionReportTextRenderer : IConventionReportRenderer { - public void Render(params ConventionReport[] conventionResult) + public void Render(params ResultInfo[] conventionResult) { var stringBuilder = new StringBuilder(); @@ -33,16 +34,16 @@ public void Render(params ConventionReport[] conventionResult) public string Output { get; private set; } - public void RenderItems(ConventionReport conventionResult) + public void RenderItems(ResultInfo conventionResult) { var stringBuilder = new StringBuilder(); RenderItems(conventionResult, stringBuilder); Output = stringBuilder.ToString(); } - static void RenderItems(ConventionReport conventionReport, StringBuilder stringBuilder) + static void RenderItems(ResultInfo resultInfo, StringBuilder stringBuilder) { - foreach (var conventionFailure in conventionReport.ConventionFailures) + foreach (var conventionFailure in resultInfo.ConventionFailures) { stringBuilder.Append("\t"); stringBuilder.AppendLine(conventionFailure.ToString()); diff --git a/TestStack.ConventionTests/Internal/ConventionReportTraceRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs similarity index 67% rename from TestStack.ConventionTests/Internal/ConventionReportTraceRenderer.cs rename to TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs index 7d0a3be..7c4d68d 100644 --- a/TestStack.ConventionTests/Internal/ConventionReportTraceRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs @@ -1,10 +1,11 @@ -namespace TestStack.ConventionTests.Internal +namespace TestStack.ConventionTests.Reporting { using System.Diagnostics; + using TestStack.ConventionTests.Internal; public class ConventionReportTraceRenderer : IConventionReportRenderer { - public void Render(params ConventionReport[] conventionResult) + public void Render(params ResultInfo[] conventionResult) { var conventionReportTextRenderer = new ConventionReportTextRenderer(); conventionReportTextRenderer.Render(conventionResult); diff --git a/TestStack.ConventionTests/Internal/ConventionResultExceptionReporter.cs b/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs similarity index 61% rename from TestStack.ConventionTests/Internal/ConventionResultExceptionReporter.cs rename to TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs index d9babfd..c4cc903 100644 --- a/TestStack.ConventionTests/Internal/ConventionResultExceptionReporter.cs +++ b/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs @@ -1,14 +1,15 @@ -namespace TestStack.ConventionTests.Internal +namespace TestStack.ConventionTests.Reporting { using System.Linq; + using TestStack.ConventionTests.Internal; public class ConventionResultExceptionReporter : IConventionReportRenderer { - public void Render(params ConventionReport[] conventionResult) + public void Render(params ResultInfo[] conventionResult) { var conventionReportTextRenderer = new ConventionReportTextRenderer(); conventionReportTextRenderer.Render(conventionResult); - if (conventionResult.Any(r => r.Result == Result.Failed)) + if (conventionResult.Any(r => r.Result == TestResult.Failed)) { throw new ConventionFailedException(conventionReportTextRenderer.Output); } diff --git a/TestStack.ConventionTests/HtmlReportRenderer.cs b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs similarity index 92% rename from TestStack.ConventionTests/HtmlReportRenderer.cs rename to TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs index b1dc540..2f646b3 100644 --- a/TestStack.ConventionTests/HtmlReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs @@ -1,8 +1,9 @@ -namespace TestStack.ConventionTests +namespace TestStack.ConventionTests.Reporting { using System.IO; using System.Text; using System.Web.UI; + using TestStack.ConventionTests.Internal; public class HtmlReportRenderer : IConventionReportRenderer { @@ -13,7 +14,7 @@ public HtmlReportRenderer(string assemblyDirectory) file = Path.Combine(assemblyDirectory, "Conventions.htm"); } - public void Render(params ConventionReport[] conventionResult) + public void Render(params ResultInfo[] conventionResult) { var sb = new StringBuilder(); var html = new HtmlTextWriter(new StringWriter(sb)); diff --git a/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs b/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs new file mode 100644 index 0000000..15ee9fc --- /dev/null +++ b/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs @@ -0,0 +1,9 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.Internal; + + public interface IConventionReportRenderer + { + void Render(params ResultInfo[] conventionResult); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs b/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs new file mode 100644 index 0000000..1cea26c --- /dev/null +++ b/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs @@ -0,0 +1,10 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.Internal; + + public interface IReportDataFormatter + { + bool CanFormat(object failingData); + ConventionReportFailure Format(object failingData); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs new file mode 100644 index 0000000..7bdd5a1 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs @@ -0,0 +1,20 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System.Reflection; + using TestStack.ConventionTests.Internal; + + public class MethodInfoDataFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return failingData is MethodInfo; + } + + public ConventionReportFailure Format(object failingData) + { + var methodInfo = (MethodInfo)failingData; + + return new ConventionReportFailure(methodInfo.DeclaringType + "." + methodInfo.Name); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs new file mode 100644 index 0000000..61667b2 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs @@ -0,0 +1,18 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.ConventionData; + using TestStack.ConventionTests.Internal; + + public class ProjectFileFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return failingData is ProjectFile; + } + + public ConventionReportFailure Format(object failingData) + { + return new ConventionReportFailure(((ProjectFile)failingData).FilePath); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs b/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs new file mode 100644 index 0000000..1481849 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs @@ -0,0 +1,18 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.ConventionData; + using TestStack.ConventionTests.Internal; + + public class ProjectReferenceFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return failingData is ProjectReference; + } + + public ConventionReportFailure Format(object failingData) + { + return new ConventionReportFailure(((ProjectReference)failingData).ReferencedPath); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/StringDataFormatter.cs b/TestStack.ConventionTests/Reporting/StringDataFormatter.cs new file mode 100644 index 0000000..ab70c55 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/StringDataFormatter.cs @@ -0,0 +1,17 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.Internal; + + public class StringDataFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return failingData is string; + } + + public ConventionReportFailure Format(object failingData) + { + return new ConventionReportFailure((string)failingData); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/TestResult.cs b/TestStack.ConventionTests/Reporting/TestResult.cs new file mode 100644 index 0000000..4090591 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/TestResult.cs @@ -0,0 +1,8 @@ +namespace TestStack.ConventionTests.Reporting +{ + public enum TestResult + { + Passed, + Failed + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs b/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs new file mode 100644 index 0000000..d1b2cd2 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs @@ -0,0 +1,18 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System; + using TestStack.ConventionTests.Internal; + + public class TypeDataFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return failingData is Type; + } + + public ConventionReportFailure Format(object failingData) + { + return new ConventionReportFailure(((Type)failingData).FullName); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index d626be4..46ec697 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -61,12 +61,13 @@ - - - - - - + + + + + + + @@ -78,8 +79,8 @@ - - + + @@ -94,7 +95,12 @@ - + + + + + + From ccc8237e00978f9658782aa4a8dfdc2f27999423 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 10 Aug 2013 08:42:43 +0100 Subject: [PATCH 7/9] Removed second type parameter on conventions --- .../ConventionAssertionClassTests.cs | 4 ++-- TestStack.ConventionTests/Convention.cs | 12 +++++----- .../AllClassesHaveDefaultConstructor.cs | 5 ++--- .../Conventions/AllMethodsAreVirtual.cs | 4 ++-- .../ClassTypeHasSpecificNamespace.cs | 6 ++--- .../Conventions/FilesAreEmbeddedResources.cs | 4 ++-- .../Conventions/ISymmetricConvention.cs | 22 +++++++++---------- ...NotReferenceDllsFromBinOrObjDirectories.cs | 4 ++-- TestStack.ConventionTests/IConvention.cs | 4 ++-- 9 files changed, 32 insertions(+), 33 deletions(-) diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 0430d1a..48d8d43 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -34,10 +34,10 @@ public ConventionReportFailure Format(string failingData) } } - public class FailingConvention : IConvention + public class FailingConvention : IConvention { public string ConventionTitle { get { return "Header"; } } - public IEnumerable GetFailingData(FakeData data) + public IEnumerable GetFailingData(FakeData data) { return new[] {"Different"}; } diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 6aa9763..5ffedbe 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -31,13 +31,13 @@ static Convention() public static IEnumerable ConventionReports { get { return Reports; } } public static IList Formatters { get; private set; } - public static void Is(IConvention convention, TDataSource data) + public static void Is(IConvention convention, TDataSource data) where TDataSource : IConventionData { Is(convention, data, new ConventionResultExceptionReporter()); } - public static void Is(IConvention convention, TDataSource data, IConventionReportRenderer reporter) + public static void Is(IConvention convention, TDataSource data, IConventionReportRenderer reporter) where TDataSource : IConventionData { try @@ -55,7 +55,7 @@ public static void Is(IConvention(IConvention convention, TDataSource data) + public static void IsWithApprovedExeptions(IConvention convention, TDataSource data) where TDataSource : IConventionData { var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); @@ -82,13 +82,13 @@ public static void IsWithApprovedExeptions(IConvention(ISymmetricConvention convention, TDataSource data) + public static void Is(ISymmetricConvention convention, TDataSource data) where TDataSource : IConventionData { Is(convention, data, new ConventionResultExceptionReporter()); } - public static void Is(ISymmetricConvention convention, TDataSource data, IConventionReportRenderer reporter) + public static void Is(ISymmetricConvention convention, TDataSource data, IConventionReportRenderer reporter) where TDataSource : IConventionData { try @@ -108,7 +108,7 @@ public static void Is(ISymmetricConvention(ISymmetricConvention convention, TDataSource data) + public static void IsWithApprovedExeptions(ISymmetricConvention convention, TDataSource data) where TDataSource : IConventionData { var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); diff --git a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs index 1ee0810..63ee4f8 100644 --- a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs +++ b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs @@ -1,16 +1,15 @@ namespace TestStack.ConventionTests.Conventions { - using System; using System.Collections.Generic; using System.Linq; using TestStack.ConventionTests.ConventionData; using TestStack.ConventionTests.Internal; - public class AllClassesHaveDefaultConstructor : IConvention + public class AllClassesHaveDefaultConstructor : IConvention { public string ConventionTitle { get { return "Types must have a default constructor"; } } - public IEnumerable GetFailingData(Types data) + public IEnumerable GetFailingData(Types data) { return data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false); } diff --git a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs index bd9a7b7..dcf659e 100644 --- a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs +++ b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs @@ -6,11 +6,11 @@ using TestStack.ConventionTests.ConventionData; using TestStack.ConventionTests.Internal; - public class AllMethodsAreVirtual : IConvention + public class AllMethodsAreVirtual : IConvention { public string ConventionTitle { get { return "Methods must be virtual"; } } - public IEnumerable GetFailingData(Types data) + public IEnumerable GetFailingData(Types data) { return data.TypesToVerify.SelectMany(t => t.NonVirtualMethods()); } diff --git a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs index fb7e9b9..d109d37 100644 --- a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs +++ b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs @@ -14,7 +14,7 @@ /// /// This is a Symmetric convention, and will verify all of a Class Type lives in the namespace, but also that only that class type is in that namespace /// - public class ClassTypeHasSpecificNamespace : ISymmetricConvention + public class ClassTypeHasSpecificNamespace : ISymmetricConvention { readonly Func classIsApplicable; readonly string namespaceToCheck; @@ -49,14 +49,14 @@ public string InverseTitle } } - public IEnumerable GetFailingData(Types data) + public IEnumerable GetFailingData(Types data) { return data.TypesToVerify .Where(classIsApplicable) .Where(t => t.Namespace == null || !t.Namespace.StartsWith(namespaceToCheck)); } - public IEnumerable GetFailingInverseData(Types data) + public IEnumerable GetFailingInverseData(Types data) { return data.TypesToVerify .Where(t => !classIsApplicable(t)) diff --git a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs index 8e23ae5..88fc915 100644 --- a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs +++ b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs @@ -4,7 +4,7 @@ using System.Linq; using TestStack.ConventionTests.ConventionData; - public class FilesAreEmbeddedResources : IConvention + public class FilesAreEmbeddedResources : IConvention { public FilesAreEmbeddedResources(string fileExtension) { @@ -21,7 +21,7 @@ public string ConventionTitle public string FileExtension { get; set; } - public IEnumerable GetFailingData(ProjectFiles data) + public IEnumerable GetFailingData(ProjectFiles data) { return data.Files.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource"); } diff --git a/TestStack.ConventionTests/Conventions/ISymmetricConvention.cs b/TestStack.ConventionTests/Conventions/ISymmetricConvention.cs index e33ede0..e7454bf 100644 --- a/TestStack.ConventionTests/Conventions/ISymmetricConvention.cs +++ b/TestStack.ConventionTests/Conventions/ISymmetricConvention.cs @@ -1,12 +1,12 @@ -namespace TestStack.ConventionTests.Conventions -{ - using System.Collections.Generic; - - public interface ISymmetricConvention where T : IConventionData - { - string ConventionTitle { get; } - string InverseTitle { get; } - IEnumerable GetFailingData(T data); - IEnumerable GetFailingInverseData(T data); - } +namespace TestStack.ConventionTests.Conventions +{ + using System.Collections.Generic; + + public interface ISymmetricConvention where T : IConventionData + { + string ConventionTitle { get; } + string InverseTitle { get; } + IEnumerable GetFailingData(T data); + IEnumerable GetFailingInverseData(T data); + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs index 92f144f..04d9fdb 100644 --- a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs +++ b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs @@ -5,7 +5,7 @@ using System.Text.RegularExpressions; using TestStack.ConventionTests.ConventionData; - public class ProjectDoesNotReferenceDllsFromBinOrObjDirectories : IConvention + public class ProjectDoesNotReferenceDllsFromBinOrObjDirectories : IConvention { const string AssemblyReferencingObjRegex = @"^(?.*?(obj|bin).*?)$"; @@ -16,7 +16,7 @@ static bool IsBinOrObjReference(ProjectReference reference) public string ConventionTitle { get { return "Project must not reference dlls from bin or obj directories"; } } - public IEnumerable GetFailingData(ProjectReferences data) + public IEnumerable GetFailingData(ProjectReferences data) { return data.References.Where(IsBinOrObjReference); } diff --git a/TestStack.ConventionTests/IConvention.cs b/TestStack.ConventionTests/IConvention.cs index d3c3a38..468fdf6 100644 --- a/TestStack.ConventionTests/IConvention.cs +++ b/TestStack.ConventionTests/IConvention.cs @@ -2,9 +2,9 @@ { using System.Collections.Generic; - public interface IConvention where T : IConventionData + public interface IConvention where T : IConventionData { string ConventionTitle { get; } - IEnumerable GetFailingData(T data); + IEnumerable GetFailingData(T data); } } \ No newline at end of file From 77662143612d1a8c5ee4e53722bc8e5b28b521b1 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 10 Aug 2013 08:56:40 +0100 Subject: [PATCH 8/9] Pulled out a executor class to simplify the ConventionClass --- TestStack.ConventionTests/Convention.cs | 54 ++++--------------- .../Internal/Executor.cs | 42 +++++++++++++++ .../TestStack.ConventionTests.csproj | 1 + 3 files changed, 52 insertions(+), 45 deletions(-) create mode 100644 TestStack.ConventionTests/Internal/Executor.cs diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 5ffedbe..606d671 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -29,7 +29,7 @@ static Convention() } public static IEnumerable ConventionReports { get { return Reports; } } - public static IList Formatters { get; private set; } + public static IList Formatters { get; set; } public static void Is(IConvention convention, TDataSource data) where TDataSource : IConventionData @@ -42,8 +42,7 @@ public static void Is(IConvention convention, TDataSou { try { - var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); - + var conventionResult = Executor.GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); Reports.Add(conventionResult); new ConventionReportTraceRenderer().Render(conventionResult); @@ -58,15 +57,12 @@ public static void Is(IConvention convention, TDataSou public static void IsWithApprovedExeptions(IConvention convention, TDataSource data) where TDataSource : IConventionData { - var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + var conventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); Reports.Add(conventionResult); try { var conventionReportTextRenderer = new ConventionReportTextRenderer(); - conventionReportTextRenderer.RenderItems(conventionResult); - conventionResult.WithApprovedException(conventionReportTextRenderer.Output); - conventionReportTextRenderer.Render(conventionResult); Approvals.Verify(conventionReportTextRenderer.Output); @@ -93,8 +89,8 @@ public static void Is(ISymmetricConvention convention, { try { - var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); - var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); + var conventionResult = Executor.GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + var inverseConventionResult = Executor.GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); Reports.Add(conventionResult); Reports.Add(inverseConventionResult); @@ -111,26 +107,18 @@ public static void Is(ISymmetricConvention convention, public static void IsWithApprovedExeptions(ISymmetricConvention convention, TDataSource data) where TDataSource : IConventionData { - var conventionResult = GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); - var inverseConventionResult = GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); + var conventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data); + var inverseConventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data); Reports.Add(conventionResult); Reports.Add(inverseConventionResult); try { - var conventionReportTextRenderer = new ConventionReportTextRenderer(); - // Add approved exceptions to report - conventionReportTextRenderer.RenderItems(conventionResult); - conventionResult.WithApprovedException(conventionReportTextRenderer.Output); - - // Add approved exceptions to inverse report - conventionReportTextRenderer.RenderItems(inverseConventionResult); - inverseConventionResult.WithApprovedException(conventionReportTextRenderer.Output); - //Render both, with approved exceptions included + var conventionReportTextRenderer = new ConventionReportTextRenderer(); conventionReportTextRenderer.Render(conventionResult, inverseConventionResult); Approvals.Verify(conventionReportTextRenderer.Output); - + // Trace on success new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult); } @@ -144,30 +132,6 @@ public static void IsWithApprovedExeptions(ISymmetricConvention(string conventionTitle, TDataType[] failingData, TDataSource data) - where TDataSource : IConventionData - { - data.EnsureHasNonEmptySource(); - var passed = failingData.None(); - - var conventionResult = new ResultInfo( - passed ? TestResult.Passed : TestResult.Failed, - conventionTitle, - data.Description, - failingData.Select(FormatData).ToArray()); - return conventionResult; - } - - static ConventionReportFailure FormatData(T failingData) - { - var formatter = Formatters.FirstOrDefault(f => f.CanFormat(failingData)); - - if (formatter == null) - throw new NoDataFormatterFoundException(typeof(T).Name + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); - - return formatter.Format(failingData); - } - // http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917 static string AssemblyDirectory { diff --git a/TestStack.ConventionTests/Internal/Executor.cs b/TestStack.ConventionTests/Internal/Executor.cs new file mode 100644 index 0000000..e7030bc --- /dev/null +++ b/TestStack.ConventionTests/Internal/Executor.cs @@ -0,0 +1,42 @@ +namespace TestStack.ConventionTests.Internal +{ + using System.Linq; + using TestStack.ConventionTests.Reporting; + + public static class Executor + { + public static ResultInfo GetConventionReport(string conventionTitle, object[] failingData, IConventionData data) + { + data.EnsureHasNonEmptySource(); + var passed = failingData.None(); + + var conventionResult = new ResultInfo( + passed ? TestResult.Passed : TestResult.Failed, + conventionTitle, + data.Description, + failingData.Select(FormatData).ToArray()); + return conventionResult; + } + + public static ResultInfo GetConventionReportWithApprovedExeptions(string conventionTitle, object[] failingData, IConventionData data) + { + var conventionResult = Executor.GetConventionReport(conventionTitle, failingData, data); + var conventionReportTextRenderer = new ConventionReportTextRenderer(); + // Add approved exceptions to report + conventionReportTextRenderer.RenderItems(conventionResult); + conventionResult.WithApprovedException(conventionReportTextRenderer.Output); + + return conventionResult; + } + + static ConventionReportFailure FormatData(T failingData) + { + var formatter = Convention.Formatters.FirstOrDefault(f => f.CanFormat(failingData)); + + if (formatter == null) + throw new NoDataFormatterFoundException(typeof(T).Name + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); + + return formatter.Format(failingData); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 46ec697..8235b14 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -62,6 +62,7 @@ + From c211004fe7e6376eba32eeaab0b29b7ad2f64797 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 10 Aug 2013 09:25:36 +0100 Subject: [PATCH 9/9] Removed EnsureHasNonEmptySource --- .../ConventionAssertionClassTests.cs | 6 +- .../ConventionData/AbstractProjectData.cs | 6 +- .../ConventionData/Types.cs | 9 +- TestStack.ConventionTests/IConventionData.cs | 2 +- .../Internal/Executor.cs | 85 ++++++++++--------- 5 files changed, 50 insertions(+), 58 deletions(-) diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 48d8d43..6fd3730 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -24,9 +24,7 @@ public class FakeData : IConventionData { public string Description { get { return "Fake data"; } } - public void EnsureHasNonEmptySource() - { - } + public bool HasData { get { return true; } } public ConventionReportFailure Format(string failingData) { @@ -39,7 +37,7 @@ public class FailingConvention : IConvention public string ConventionTitle { get { return "Header"; } } public IEnumerable GetFailingData(FakeData data) { - return new[] {"Different"}; + return new[] { "Different" }; } } } diff --git a/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs b/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs index 8f05bff..971779c 100644 --- a/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs +++ b/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs @@ -22,11 +22,7 @@ protected AbstractProjectData(Assembly assembly, IProjectProvider projectProvide public string Description { get { return Assembly.GetName().Name; } } - public void EnsureHasNonEmptySource() - { - if (ProjectLocator.ResolveProjectFilePath(Assembly) == null) - throw new ConventionSourceInvalidException("Cannot resolve project file for assembly {0}"); - } + public bool HasData { get { return ProjectLocator.ResolveProjectFilePath(Assembly) != null; } } protected XDocument GetProject() { diff --git a/TestStack.ConventionTests/ConventionData/Types.cs b/TestStack.ConventionTests/ConventionData/Types.cs index 2df6157..e491811 100644 --- a/TestStack.ConventionTests/ConventionData/Types.cs +++ b/TestStack.ConventionTests/ConventionData/Types.cs @@ -1,8 +1,7 @@ namespace TestStack.ConventionTests.ConventionData { using System; - using TestStack.ConventionTests.Conventions; - using TestStack.ConventionTests.Internal; + using System.Linq; /// /// This is where we set what our convention is all about. @@ -18,10 +17,6 @@ public Types(string descriptionOfTypes) public string Description { get; private set; } - public void EnsureHasNonEmptySource() - { - if (TypesToVerify.None()) - throw new ConventionSourceInvalidException("You must supply types to verify"); - } + public bool HasData {get { return TypesToVerify.Any(); }} } } \ No newline at end of file diff --git a/TestStack.ConventionTests/IConventionData.cs b/TestStack.ConventionTests/IConventionData.cs index 5cb17b8..03679d0 100644 --- a/TestStack.ConventionTests/IConventionData.cs +++ b/TestStack.ConventionTests/IConventionData.cs @@ -3,6 +3,6 @@ public interface IConventionData { string Description { get; } - void EnsureHasNonEmptySource(); + bool HasData { get; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/Executor.cs b/TestStack.ConventionTests/Internal/Executor.cs index e7030bc..c054e29 100644 --- a/TestStack.ConventionTests/Internal/Executor.cs +++ b/TestStack.ConventionTests/Internal/Executor.cs @@ -1,42 +1,45 @@ -namespace TestStack.ConventionTests.Internal -{ - using System.Linq; - using TestStack.ConventionTests.Reporting; - - public static class Executor - { - public static ResultInfo GetConventionReport(string conventionTitle, object[] failingData, IConventionData data) - { - data.EnsureHasNonEmptySource(); - var passed = failingData.None(); - - var conventionResult = new ResultInfo( - passed ? TestResult.Passed : TestResult.Failed, - conventionTitle, - data.Description, - failingData.Select(FormatData).ToArray()); - return conventionResult; - } - - public static ResultInfo GetConventionReportWithApprovedExeptions(string conventionTitle, object[] failingData, IConventionData data) - { - var conventionResult = Executor.GetConventionReport(conventionTitle, failingData, data); - var conventionReportTextRenderer = new ConventionReportTextRenderer(); - // Add approved exceptions to report - conventionReportTextRenderer.RenderItems(conventionResult); - conventionResult.WithApprovedException(conventionReportTextRenderer.Output); - - return conventionResult; - } - - static ConventionReportFailure FormatData(T failingData) - { - var formatter = Convention.Formatters.FirstOrDefault(f => f.CanFormat(failingData)); - - if (formatter == null) - throw new NoDataFormatterFoundException(typeof(T).Name + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); - - return formatter.Format(failingData); - } - } +namespace TestStack.ConventionTests.Internal +{ + using System.Linq; + using TestStack.ConventionTests.Conventions; + using TestStack.ConventionTests.Reporting; + + public static class Executor + { + public static ResultInfo GetConventionReport(string conventionTitle, object[] failingData, IConventionData data) + { + if (!data.HasData) + throw new ConventionSourceInvalidException(string.Format("{0} has no data", data.Description)); + + var passed = failingData.None(); + + var conventionResult = new ResultInfo( + passed ? TestResult.Passed : TestResult.Failed, + conventionTitle, + data.Description, + failingData.Select(FormatData).ToArray()); + return conventionResult; + } + + public static ResultInfo GetConventionReportWithApprovedExeptions(string conventionTitle, object[] failingData, IConventionData data) + { + var conventionResult = Executor.GetConventionReport(conventionTitle, failingData, data); + var conventionReportTextRenderer = new ConventionReportTextRenderer(); + // Add approved exceptions to report + conventionReportTextRenderer.RenderItems(conventionResult); + conventionResult.WithApprovedException(conventionReportTextRenderer.Output); + + return conventionResult; + } + + static ConventionReportFailure FormatData(T failingData) + { + var formatter = Convention.Formatters.FirstOrDefault(f => f.CanFormat(failingData)); + + if (formatter == null) + throw new NoDataFormatterFoundException(typeof(T).Name + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); + + return formatter.Format(failingData); + } + } } \ No newline at end of file