From a19c0e08f5adf0b59833417245207e739461c501 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 31 Aug 2013 10:40:38 +0100 Subject: [PATCH 01/10] Changing the approval validation test to use QuietReporter --- .../ConventionAssertionClassTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 8b187f1..0fa1f0d 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -5,7 +5,7 @@ using TestStack.ConventionTests.Internal; [TestFixture] - [UseReporter(typeof(DiffReporter))] //NOTE: Can we take care of this in IsWithApprovedExceptions? + [UseReporter(typeof(QuietReporter))] //NOTE: Can we take care of this in IsWithApprovedExceptions? public class ConventionAssertionClassTests { [Test] From a0a30884e43edf1bc7ef43b46d642e32ce5b5c40 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 31 Aug 2013 10:53:06 +0100 Subject: [PATCH 02/10] Improved the generated convention title --- ...ns.api_controller_conventions.approved.txt | 8 +++---- ...ntions.controller_conventions.approved.txt | 8 +++---- ...ssemblies_referencing_bin_obj.approved.txt | 4 ++-- ..._obj_with_approved_exceptions.approved.txt | 4 ++-- .../ProjectBasedConventions.cs | 4 ++-- ...cripts_not_embedded_resources.approved.txt | 4 ++-- ...rces_with_approved_exceptions.approved.txt | 4 ++-- ...sses_have_default_constructor.approved.txt | 4 ++-- ...uctor_wth_approved_exceptions.approved.txt | 4 ++-- ...tions.all_methods_are_virtual.approved.txt | 4 ++-- ...rtual_wth_approved_exceptions.approved.txt | 4 ++-- ....dtos_exists_in_dto_namespace.approved.txt | 8 +++---- ...space_wth_approved_exceptions.approved.txt | 4 ++-- ...pace_wth_approved_exceptions1.approved.txt | 4 ++-- TestStack.ConventionTests/Convention.cs | 22 ++++++++++++------- .../ConventionData/AbstractProjectData.cs | 1 - .../{ProjectFile.cs => ProjectFileItem.cs} | 2 +- .../{ProjectFiles.cs => ProjectFileItems.cs} | 11 ++++++---- .../Conventions/FilesAreEmbeddedResources.cs | 6 ++--- .../Reporting/ProjectFileFormatter.cs | 4 ++-- .../TestStack.ConventionTests.csproj | 4 ++-- 21 files changed, 63 insertions(+), 55 deletions(-) rename TestStack.ConventionTests/ConventionData/{ProjectFile.cs => ProjectFileItem.cs} (83%) rename TestStack.ConventionTests/ConventionData/{ProjectFiles.cs => ProjectFileItems.cs} (70%) diff --git a/TestStack.ConventionTests.Tests/MvcConventions.api_controller_conventions.approved.txt b/TestStack.ConventionTests.Tests/MvcConventions.api_controller_conventions.approved.txt index 0983058..a58a53b 100644 --- a/TestStack.ConventionTests.Tests/MvcConventions.api_controller_conventions.approved.txt +++ b/TestStack.ConventionTests.Tests/MvcConventions.api_controller_conventions.approved.txt @@ -1,10 +1,10 @@ -'Api Controllers must be suffixed with Controller' for 'TestAssembly' ---------------------------------------------------------------------- +'Api Controllers must be suffixed with Controller' for 'Types in TestAssembly' +------------------------------------------------------------------------------ TestAssembly.Controllers.BarApiControler -'Types named *Controller must inherit from ApiController or Controller' for 'TestAssembly' ------------------------------------------------------------------------------------------- +'Types named *Controller must inherit from ApiController or Controller' for 'Types in TestAssembly' +--------------------------------------------------------------------------------------------------- TestAssembly.Controllers.TestApiController TestAssembly.Controllers.TestController diff --git a/TestStack.ConventionTests.Tests/MvcConventions.controller_conventions.approved.txt b/TestStack.ConventionTests.Tests/MvcConventions.controller_conventions.approved.txt index d564def..a445745 100644 --- a/TestStack.ConventionTests.Tests/MvcConventions.controller_conventions.approved.txt +++ b/TestStack.ConventionTests.Tests/MvcConventions.controller_conventions.approved.txt @@ -1,10 +1,10 @@ -'Mvc Controllers must be suffixed with Controller' for 'TestAssembly' ---------------------------------------------------------------------- +'Mvc Controllers must be suffixed with Controller' for 'Types in TestAssembly' +------------------------------------------------------------------------------ TestAssembly.Controllers.FooControler -'Types named *Controller must inherit from ApiController or Controller' for 'TestAssembly' ------------------------------------------------------------------------------------------- +'Types named *Controller must inherit from ApiController or Controller' for 'Types in TestAssembly' +--------------------------------------------------------------------------------------------------- TestAssembly.Controllers.TestApiController TestAssembly.Controllers.TestController 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 5e98f99..1e8871b 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 @@ -'Project must not reference dlls from bin or obj directories' for 'TestStack.ConventionTests.Tests' ---------------------------------------------------------------------------------------------------- +'Project must not reference dlls from bin or obj directories' for 'Project references in TestStack.ConventionTests.Tests' +------------------------------------------------------------------------------------------------------------------------- bin\Debug\ApprovalTests.dll 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 5e98f99..1e8871b 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,4 @@ -'Project must not reference dlls from bin or obj directories' for 'TestStack.ConventionTests.Tests' ---------------------------------------------------------------------------------------------------- +'Project must not reference dlls from bin or obj directories' for 'Project references in TestStack.ConventionTests.Tests' +------------------------------------------------------------------------------------------------------------------------- bin\Debug\ApprovalTests.dll diff --git a/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs b/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs index 45ee86e..d3066b2 100644 --- a/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs +++ b/TestStack.ConventionTests.Tests/ProjectBasedConventions.cs @@ -57,7 +57,7 @@ public void scripts_not_embedded_resources() .Returns(XDocument.Parse(Resources.ProjectFileWithInvalidSqlScriptFile)); var projectLocator = Substitute.For(); - var project = new ProjectFiles(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator); + var project = new ProjectFileItems(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator); var ex = Assert.Throws(() => Convention.Is(new FilesAreEmbeddedResources(".sql"), project)); Approvals.Verify(ex.Message); @@ -67,7 +67,7 @@ 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); + var project = new ProjectFileItems(typeof (ProjectBasedConventions).Assembly, projectProvider, projectLocator); projectProvider .LoadProjectDocument(Arg.Any()) .Returns(XDocument.Parse(Resources.ProjectFileWithInvalidSqlScriptFile)); 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 ef39646..3202fa8 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 @@ -'.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' ------------------------------------------------------------------------------ +'.sql Files must be embedded resources' for 'Project file items in TestStack.ConventionTests.Tests' +--------------------------------------------------------------------------------------------------- Scripts\Script2.sql 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 ef39646..3202fa8 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,4 @@ -'.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' ------------------------------------------------------------------------------ +'.sql Files must be embedded resources' for 'Project file items in TestStack.ConventionTests.Tests' +--------------------------------------------------------------------------------------------------- Scripts\Script2.sql 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 a0fc6e2..e3fd256 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 @@ -'Types must have a default constructor' for 'nHibernate Entitites' ------------------------------------------------------------------- +'Types must have a default constructor' for 'Types in nHibernate Entitites' +--------------------------------------------------------------------------- TestAssembly.ClassWithNoDefaultCtor TestAssembly.ClassWithPrivateDefaultCtor 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 a0fc6e2..e3fd256 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,5 @@ -'Types must have a default constructor' for 'nHibernate Entitites' ------------------------------------------------------------------- +'Types must have a default constructor' for 'Types in nHibernate Entitites' +--------------------------------------------------------------------------- TestAssembly.ClassWithNoDefaultCtor TestAssembly.ClassWithPrivateDefaultCtor 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 ec621b2..9081ea0 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 @@ -'Methods must be virtual' for 'nHibernate Entitites' ----------------------------------------------------- +'Methods must be virtual' for 'Types in nHibernate Entitites' +------------------------------------------------------------- TestAssembly.SampleDomainClass.TestNonVirtual 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 ec621b2..9081ea0 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,4 @@ -'Methods must be virtual' for 'nHibernate Entitites' ----------------------------------------------------- +'Methods must be virtual' for 'Types in nHibernate Entitites' +------------------------------------------------------------- TestAssembly.SampleDomainClass.TestNonVirtual 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 d0deea5..aab6589 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,9 +1,9 @@ -'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly' -------------------------------------------------------------------------- +'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'Types in TestAssembly' +---------------------------------------------------------------------------------- TestAssembly.SomeDto -'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly' ---------------------------------------------------------------------------------- +'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'Types in TestAssembly' +------------------------------------------------------------------------------------------ TestAssembly.Dtos.AnotherClass 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 547d592..0aa693d 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,4 +1,4 @@ -'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly' -------------------------------------------------------------------------- +'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'Types in TestAssembly' +---------------------------------------------------------------------------------- TestAssembly.SomeDto diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions1.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions1.approved.txt index faaec50..3995d97 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions1.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions1.approved.txt @@ -1,4 +1,4 @@ -'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly' ---------------------------------------------------------------------------------- +'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'Types in TestAssembly' +------------------------------------------------------------------------------------------ TestAssembly.Dtos.AnotherClass diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 447d520..14d6acb 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection; + using System.Text.RegularExpressions; using TestStack.ConventionTests.Internal; using TestStack.ConventionTests.Reporting; @@ -53,14 +54,6 @@ public static void Is(IConvention convention, TDataSou Execute(convention, data, processors.ToArray()); } - static void Execute(IConvention convention, TDataSource data, - IResultsProcessor[] processors) - where TDataSource : IConventionData - { - var context = new ConventionContext(data.Description, Formatters, processors); - context.Execute(convention, data); - } - public static void IsWithApprovedExeptions(IConvention convention, TDataSource data, params IResultsProcessor[] extraResultProcessors) where TDataSource : IConventionData @@ -74,5 +67,18 @@ public static void IsWithApprovedExeptions(IConvention }; Execute(convention, data, processors.ToArray()); } + + static void Execute(IConvention convention, TDataSource data, + IResultsProcessor[] processors) + where TDataSource : IConventionData + { + var context = new ConventionContext(string.Format("{0} in {1}", ToSentenceCase(data.GetType().Name), data.Description), Formatters, processors); + context.Execute(convention, data); + } + + static string ToSentenceCase(string str) + { + return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs b/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs index 48d8483..9a20974 100644 --- a/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs +++ b/TestStack.ConventionTests/ConventionData/AbstractProjectData.cs @@ -2,7 +2,6 @@ { using System.Reflection; using System.Xml.Linq; - using TestStack.ConventionTests.Conventions; using TestStack.ConventionTests.Internal; public abstract class AbstractProjectData : IConventionData diff --git a/TestStack.ConventionTests/ConventionData/ProjectFile.cs b/TestStack.ConventionTests/ConventionData/ProjectFileItem.cs similarity index 83% rename from TestStack.ConventionTests/ConventionData/ProjectFile.cs rename to TestStack.ConventionTests/ConventionData/ProjectFileItem.cs index 6537606..19f367f 100644 --- a/TestStack.ConventionTests/ConventionData/ProjectFile.cs +++ b/TestStack.ConventionTests/ConventionData/ProjectFileItem.cs @@ -1,6 +1,6 @@ namespace TestStack.ConventionTests.ConventionData { - public class ProjectFile + public class ProjectFileItem { public string FilePath { get; set; } public string ReferenceType { get; set; } diff --git a/TestStack.ConventionTests/ConventionData/ProjectFiles.cs b/TestStack.ConventionTests/ConventionData/ProjectFileItems.cs similarity index 70% rename from TestStack.ConventionTests/ConventionData/ProjectFiles.cs rename to TestStack.ConventionTests/ConventionData/ProjectFileItems.cs index bbaf6a2..53be220 100644 --- a/TestStack.ConventionTests/ConventionData/ProjectFiles.cs +++ b/TestStack.ConventionTests/ConventionData/ProjectFileItems.cs @@ -5,14 +5,17 @@ using System.Xml.Linq; using TestStack.ConventionTests.Internal; - public class ProjectFiles : AbstractProjectData + /// + /// Items/Files in a .*proj project file + /// + public class ProjectFileItems : AbstractProjectData { - public ProjectFiles(Assembly assembly, IProjectProvider projectProvider = null, IProjectLocator projectLocator = null) + public ProjectFilesItems(Assembly assembly, IProjectProvider projectProvider = null, IProjectLocator projectLocator = null) : base(assembly, projectProvider, projectLocator) { } - public ProjectFile[] Files + public ProjectFileItem[] Items { get { @@ -23,7 +26,7 @@ public ProjectFile[] Files .Elements(XName.Get("ItemGroup", msbuild)) .Elements() .Select(refElem => - new ProjectFile + new ProjectFileItem { ReferenceType = refElem.Name.LocalName, FilePath = refElem.Attribute("Include").Value diff --git a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs index 3d6becf..a6ecc11 100644 --- a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs +++ b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs @@ -3,7 +3,7 @@ using System.Linq; using TestStack.ConventionTests.ConventionData; - public class FilesAreEmbeddedResources : IConvention + public class FilesAreEmbeddedResources : IConvention { public FilesAreEmbeddedResources(string fileExtension) { @@ -12,11 +12,11 @@ public FilesAreEmbeddedResources(string fileExtension) public string FileExtension { get; private set; } - public void Execute(ProjectFiles data, IConventionResultContext result) + public void Execute(ProjectFileItems data, IConventionResultContext result) { result.Is( string.Format("{0} Files must be embedded resources", FileExtension), - data.Files.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource")); + data.Items.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource")); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs index 61667b2..06e6c56 100644 --- a/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs +++ b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs @@ -7,12 +7,12 @@ public class ProjectFileFormatter : IReportDataFormatter { public bool CanFormat(object failingData) { - return failingData is ProjectFile; + return failingData is ProjectFileItem; } public ConventionReportFailure Format(object failingData) { - return new ConventionReportFailure(((ProjectFile)failingData).FilePath); + return new ConventionReportFailure(((ProjectFileItem)failingData).FilePath); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 0f12072..8131eba 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -81,8 +81,8 @@ - - + + From d9d8abeb0ea7c3c6b0dd9853fd7695e2466935de Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 31 Aug 2013 10:56:40 +0100 Subject: [PATCH 03/10] Added equality and formatting members to ConventionResult --- .../Internal/ConventionResult.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index 91c635e..4a29718 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -31,5 +31,44 @@ public void WithFormattedResult(string formattedResult, string recommendedFileEx FormattedResult = formattedResult; RecommendedFileExtension = recommendedFileExtension; } + + protected bool Equals(ConventionResult other) + { + return DataType == other.DataType && string.Equals(ConventionTitle, other.ConventionTitle) && string.Equals(DataDescription, other.DataDescription); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((ConventionResult) obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = (DataType != null ? DataType.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (ConventionTitle != null ? ConventionTitle.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (DataDescription != null ? DataDescription.GetHashCode() : 0); + return hashCode; + } + } + + public static bool operator ==(ConventionResult left, ConventionResult right) + { + return Equals(left, right); + } + + public static bool operator !=(ConventionResult left, ConventionResult right) + { + return !Equals(left, right); + } + + public override string ToString() + { + return string.Format("FormattedResult: {0}, DataDescription: {1}, ConventionTitle: {2}, DataType: {3}, HasData: {4}, RecommendedFileExtension: {5}", FormattedResult, DataDescription, ConventionTitle, DataType, HasData, RecommendedFileExtension); + } } } \ No newline at end of file From 6c3a40ffa1c97a25d3ab95ca5ac0a393d4d298ab Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 31 Aug 2013 10:57:08 +0100 Subject: [PATCH 04/10] Introduced some base classes to help make the html reporter more understandable and introduced markdown reporter --- .../Reporting/AggregatedRenderer.cs | 23 ++++++++++++ .../GroupedByDataTypeRendererBase.cs | 16 ++++++++ .../Reporting/HtmlReportRenderer.cs | 34 +++++++++-------- .../Reporting/MarkdownReportRenderer.cs | 37 +++++++++++++++++++ .../TestStack.ConventionTests.csproj | 3 ++ 5 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 TestStack.ConventionTests/Reporting/AggregatedRenderer.cs create mode 100644 TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs create mode 100644 TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs diff --git a/TestStack.ConventionTests/Reporting/AggregatedRenderer.cs b/TestStack.ConventionTests/Reporting/AggregatedRenderer.cs new file mode 100644 index 0000000..ebc4526 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/AggregatedRenderer.cs @@ -0,0 +1,23 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System.Collections.Generic; + using System.Linq; + using TestStack.ConventionTests.Internal; + + /// + /// Aggregates all previous results + /// + public abstract class AggregatedRenderer : IResultsProcessor + { + static readonly List Reports = new List(); + public IEnumerable AggregatedReports { get { return Reports; } } + + public void Process(IConventionFormatContext context, params ConventionResult[] results) + { + Reports.AddRange(results.Except(Reports)); + Process(context); + } + + protected abstract void Process(IConventionFormatContext context); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs b/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs new file mode 100644 index 0000000..c4667ac --- /dev/null +++ b/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs @@ -0,0 +1,16 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System.Collections.Generic; + using System.Linq; + using TestStack.ConventionTests.Internal; + + public abstract class GroupedByDataTypeRendererBase : AggregatedRenderer + { + protected override void Process(IConventionFormatContext context) + { + Process(AggregatedReports.OrderBy(c => c.ConventionTitle).GroupBy(r => r.DataDescription)); + } + + protected abstract void Process(IEnumerable> resultsGroupedByDataType); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs index 23dbaca..7b9f73c 100644 --- a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs @@ -1,31 +1,38 @@ namespace TestStack.ConventionTests.Reporting { - using System; using System.Collections.Generic; using System.IO; + using System.Linq; using System.Text; using System.Web.UI; using TestStack.ConventionTests.Internal; - public class HtmlReportRenderer : IResultsProcessor + public class HtmlReportRenderer : GroupedByDataTypeRendererBase { readonly string file; - static readonly List Reports = new List(); - public static IEnumerable ConventionReports { get { return Reports; } } public HtmlReportRenderer(string assemblyDirectory) { file = Path.Combine(assemblyDirectory, "Conventions.htm"); } - public void Process(IConventionFormatContext context, params ConventionResult[] results) + protected override void Process(IEnumerable> resultsGroupedByDataType) { - Reports.AddRange(results); var sb = new StringBuilder(); var html = new HtmlTextWriter(new StringWriter(sb)); html.WriteLine(""); html.RenderBeginTag(HtmlTextWriterTag.Html); // html.RenderBeginTag(HtmlTextWriterTag.Head); // + html.Write(@" + "); html.RenderEndTag(); // html.WriteLine(); html.RenderBeginTag(HtmlTextWriterTag.Body); // @@ -34,25 +41,20 @@ public void Process(IConventionFormatContext context, params ConventionResult[] html.Write("Project Conventions"); html.RenderEndTag(); - foreach (var conventionReport in Reports) + foreach (var conventionReport in resultsGroupedByDataType) { html.RenderBeginTag(HtmlTextWriterTag.P); html.RenderBeginTag(HtmlTextWriterTag.Div); - html.RenderBeginTag(HtmlTextWriterTag.Strong); + html.RenderBeginTag(HtmlTextWriterTag.H2); + html.Write("Conventions for '{0}'", conventionReport.Key); html.RenderEndTag(); - var title = String.Format("{0} for {1}", conventionReport.ConventionTitle, conventionReport.DataDescription); - html.Write(title); - html.RenderBeginTag(HtmlTextWriterTag.Ul); - - - foreach (var conventionFailure in conventionReport.Data) + foreach (var conventionResult in conventionReport) { html.RenderBeginTag(HtmlTextWriterTag.Li); - html.Write(context.FormatData(conventionFailure).ToString()); + html.Write(conventionResult.ConventionTitle); html.RenderEndTag(); } - html.RenderEndTag(); html.RenderEndTag(); html.RenderEndTag(); diff --git a/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs b/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs new file mode 100644 index 0000000..31a2cfe --- /dev/null +++ b/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs @@ -0,0 +1,37 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text; + using TestStack.ConventionTests.Internal; + + public class MarkdownReportRenderer : GroupedByDataTypeRendererBase + { + readonly string file; + + public MarkdownReportRenderer(string assemblyDirectory) + { + file = Path.Combine(assemblyDirectory, "Conventions.md"); + } + + protected override void Process(IEnumerable> resultsGroupedByDataType) + { + var sb = new StringBuilder(); + sb.AppendLine("# Project Conventions"); + foreach (var conventionReport in resultsGroupedByDataType) + { + sb.Append("## "); + sb.AppendLine(conventionReport.Key); + + foreach (var conventionResult in conventionReport) + { + sb.Append(" - "); + sb.AppendLine(conventionResult.ConventionTitle); + } + } + + 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 8131eba..47a6d07 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -70,14 +70,17 @@ + + + From e26c93b5db83384cad164f3374f01b9fc3bbe1fb Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 31 Aug 2013 11:29:49 +0100 Subject: [PATCH 05/10] Introduced ITestResultProcessor because there can only be one of those and it simplifies a few things --- TestStack.ConventionTests/Convention.cs | 19 ++++++------ .../Internal/ConventionContext.cs | 23 ++++++++++----- .../Internal/ConventionResult.cs | 13 ++------- .../Internal/IConventionFormatContext.cs | 9 ++++-- .../Reporting/ApproveResultsProcessor.cs | 5 +++- .../Reporting/ConventionReportTextRenderer.cs | 29 ++++++++----------- .../ConventionReportTraceRenderer.cs | 2 +- .../Reporting/CsvReporter.cs | 14 +++------ .../Reporting/ITestResultProcessor.cs | 10 +++++++ .../ThrowOnFailureResultsProcessor.cs | 2 +- .../TestStack.ConventionTests.csproj | 1 + 11 files changed, 65 insertions(+), 62 deletions(-) create mode 100644 TestStack.ConventionTests/Reporting/ITestResultProcessor.cs diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 14d6acb..0bf4879 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -41,38 +41,37 @@ static string AssemblyDirectory } public static void Is(IConvention convention, TDataSource data, - params IResultsProcessor[] extraResultProcessors) + ITestResultProcessor resultProcessor = null) where TDataSource : IConventionData { - var processors = new List(extraResultProcessors) + var processors = new List { - new ConventionReportTextRenderer(), HtmlRenderer, new ConventionReportTraceRenderer(), new ThrowOnFailureResultsProcessor() }; - Execute(convention, data, processors.ToArray()); + Execute(convention, data, processors.ToArray(), resultProcessor ?? new ConventionReportTextRenderer()); } public static void IsWithApprovedExeptions(IConvention convention, TDataSource data, - params IResultsProcessor[] extraResultProcessors) + ITestResultProcessor resultProcessor = null) where TDataSource : IConventionData { - var processors = new List(extraResultProcessors) + var processors = new List { - new ConventionReportTextRenderer(), HtmlRenderer, new ConventionReportTraceRenderer(), new ApproveResultsProcessor() }; - Execute(convention, data, processors.ToArray()); + Execute(convention, data, processors.ToArray(), resultProcessor ?? new ConventionReportTextRenderer()); } static void Execute(IConvention convention, TDataSource data, - IResultsProcessor[] processors) + IResultsProcessor[] processors, ITestResultProcessor resultProcessor) where TDataSource : IConventionData { - var context = new ConventionContext(string.Format("{0} in {1}", ToSentenceCase(data.GetType().Name), data.Description), Formatters, processors); + var dataDescription = string.Format("{0} in {1}", ToSentenceCase(data.GetType().Name), data.Description); + var context = new ConventionContext(dataDescription, Formatters, processors, resultProcessor); context.Execute(convention, data); } diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index 2fdba19..dfadb4a 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -11,13 +11,15 @@ public class ConventionContext : IConventionResultContext, IConventionFormatCont readonly string dataDescription; readonly IList formatters; readonly IList processors; + readonly ITestResultProcessor testResultProcessor; readonly IList results = new List(); public ConventionContext(string dataDescription, IList formatters, - IList processors) + IList processors, ITestResultProcessor testResultProcessor) { this.formatters = formatters; this.processors = processors; + this.testResultProcessor = testResultProcessor; this.dataDescription = dataDescription; } @@ -26,9 +28,14 @@ public ConventionResult[] ConventionResults get { return results.ToArray(); } } + ITestResultProcessor IConventionFormatContext.TestResultProcessor + { + get { return testResultProcessor; } + } + ConventionReportFailure IConventionFormatContext.FormatData(object failingData) { - var formatter = formatters.FirstOrDefault(f => f.CanFormat(failingData)); + IReportDataFormatter formatter = formatters.FirstOrDefault(f => f.CanFormat(failingData)); if (formatter == null) { throw new NoDataFormatterFoundException( @@ -43,7 +50,7 @@ void IConventionResultContext.Is(string resultTitle, IEnumerable( string secondSetFailureTitle, IEnumerable secondSetFailureData) { results.Add(new ConventionResult( - typeof(TResult), firstSetFailureTitle, + typeof (TResult), firstSetFailureTitle, dataDescription, firstSetFailureData.ToObjectArray())); results.Add(new ConventionResult( - typeof(TResult), secondSetFailureTitle, + typeof (TResult), secondSetFailureTitle, dataDescription, secondSetFailureData.ToObjectArray())); } @@ -70,8 +77,8 @@ void IConventionResultContext.IsSymmetric( Func isPartOfSecondSet, IEnumerable allData) { - var firstSetFailingData = allData.Where(isPartOfFirstSet).Unless(isPartOfSecondSet); - var secondSetFailingData = allData.Where(isPartOfSecondSet).Unless(isPartOfFirstSet); + IEnumerable firstSetFailingData = allData.Where(isPartOfFirstSet).Unless(isPartOfSecondSet); + IEnumerable secondSetFailingData = allData.Where(isPartOfSecondSet).Unless(isPartOfFirstSet); (this as IConventionResultContext).IsSymmetric( firstSetFailureTitle, firstSetFailingData, @@ -85,7 +92,7 @@ public void Execute(IConvention convention, TDataSourc throw new ConventionSourceInvalidException(String.Format("{0} has no data", data.Description)); convention.Execute(data, this); - foreach (var resultsProcessor in processors) + foreach (IResultsProcessor resultsProcessor in processors) { resultsProcessor.Process(this, ConventionResults); } diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index 4a29718..0a833d4 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -13,7 +13,6 @@ public ConventionResult(Type dataType, string conventionTitle, string dataDescri Data = data; } - public string RecommendedFileExtension { get; private set; } public Type DataType { get; private set; } public string ConventionTitle { get; private set; } public string DataDescription { get; private set; } @@ -24,14 +23,6 @@ public bool HasData get { return Data.Any(); } } - public string FormattedResult { get; private set; } - - public void WithFormattedResult(string formattedResult, string recommendedFileExtension = "txt") - { - FormattedResult = formattedResult; - RecommendedFileExtension = recommendedFileExtension; - } - protected bool Equals(ConventionResult other) { return DataType == other.DataType && string.Equals(ConventionTitle, other.ConventionTitle) && string.Equals(DataDescription, other.DataDescription); @@ -41,7 +32,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ConventionResult) obj); } @@ -68,7 +59,7 @@ public override int GetHashCode() public override string ToString() { - return string.Format("FormattedResult: {0}, DataDescription: {1}, ConventionTitle: {2}, DataType: {3}, HasData: {4}, RecommendedFileExtension: {5}", FormattedResult, DataDescription, ConventionTitle, DataType, HasData, RecommendedFileExtension); + return string.Format("DataType: {0}, ConventionTitle: {1}, DataDescription: {2}, HasData: {3}", DataType, ConventionTitle, DataDescription, HasData); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/IConventionFormatContext.cs b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs index e3d024d..f069caf 100644 --- a/TestStack.ConventionTests/Internal/IConventionFormatContext.cs +++ b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs @@ -1,7 +1,10 @@ namespace TestStack.ConventionTests.Internal -{ +{ + using TestStack.ConventionTests.Reporting; + public interface IConventionFormatContext - { - ConventionReportFailure FormatData(object failingData); + { + ConventionReportFailure FormatData(object failingData); + ITestResultProcessor TestResultProcessor { get; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ApproveResultsProcessor.cs b/TestStack.ConventionTests/Reporting/ApproveResultsProcessor.cs index 43d53e8..06c809f 100644 --- a/TestStack.ConventionTests/Reporting/ApproveResultsProcessor.cs +++ b/TestStack.ConventionTests/Reporting/ApproveResultsProcessor.cs @@ -17,7 +17,10 @@ public void Process(IConventionFormatContext context, params ConventionResult[] var result = results[count]; try { - Approvals.Verify(new ConventionTestsApprovalTextWriter(result.FormattedResult, count,result.RecommendedFileExtension)); + //TODO Law of Demeter + var formattedResult = context.TestResultProcessor.Process(context, result); + var recommendedFileExtension = context.TestResultProcessor.RecommendedFileExtension; + Approvals.Verify(new ConventionTestsApprovalTextWriter(formattedResult, count, recommendedFileExtension)); } catch (ApprovalException ex) { diff --git a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs index 89197aa..849ff8d 100644 --- a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs @@ -3,26 +3,21 @@ using System.Text; using TestStack.ConventionTests.Internal; - public class ConventionReportTextRenderer : IResultsProcessor + public class ConventionReportTextRenderer : ITestResultProcessor { - public void Process(IConventionFormatContext context, params ConventionResult[] results) + public string RecommendedFileExtension { get { return "txt"; } } + + public string Process(IConventionFormatContext context, ConventionResult result) { - foreach (var result in results) - { - if (result.FormattedResult != null) - { - continue; - } - var description = new StringBuilder(); - var title = string.Format("'{0}' for '{1}'", result.ConventionTitle, - result.DataDescription); - description.AppendLine(title); - description.AppendLine(string.Empty.PadRight(title.Length, '-')); - description.AppendLine(); + var description = new StringBuilder(); + var title = string.Format("'{0}' for '{1}'", result.ConventionTitle, result.DataDescription); + description.AppendLine(title); + description.AppendLine(string.Empty.PadRight(title.Length, '-')); + description.AppendLine(); - RenderItems(result, description, context); - result.WithFormattedResult(description.ToString()); - } + RenderItems(result, description, context); + + return description.ToString(); } static void RenderItems(ConventionResult resultInfo, StringBuilder stringBuilder, IConventionFormatContext context) diff --git a/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs index 4d5b2fa..4bd776f 100644 --- a/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs @@ -9,7 +9,7 @@ public void Process(IConventionFormatContext context, params ConventionResult[] { foreach (var conventionResult in results) { - Trace.WriteLine(conventionResult.FormattedResult); + Trace.WriteLine(context.TestResultProcessor.Process(context, conventionResult)); } } } diff --git a/TestStack.ConventionTests/Reporting/CsvReporter.cs b/TestStack.ConventionTests/Reporting/CsvReporter.cs index 7dc529e..d311c4b 100644 --- a/TestStack.ConventionTests/Reporting/CsvReporter.cs +++ b/TestStack.ConventionTests/Reporting/CsvReporter.cs @@ -3,17 +3,9 @@ using System.Text; using TestStack.ConventionTests.Internal; - public class CsvReporter : IResultsProcessor + public class CsvReporter : ITestResultProcessor { - public void Process(IConventionFormatContext context, params ConventionResult[] results) - { - foreach (var result in results) - { - result.WithFormattedResult(Process(context, result), "csv"); - } - } - - string Process(IConventionFormatContext context, ConventionResult result) + public string Process(IConventionFormatContext context, ConventionResult result) { var formatter = new DefaultFormatter(result.DataType); var message = new StringBuilder(); @@ -24,5 +16,7 @@ string Process(IConventionFormatContext context, ConventionResult result) } return message.ToString(); } + + public string RecommendedFileExtension { get { return "csv"; } } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ITestResultProcessor.cs b/TestStack.ConventionTests/Reporting/ITestResultProcessor.cs new file mode 100644 index 0000000..9ba5206 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/ITestResultProcessor.cs @@ -0,0 +1,10 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.Internal; + + public interface ITestResultProcessor + { + string Process(IConventionFormatContext context, ConventionResult result); + string RecommendedFileExtension { get; } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ThrowOnFailureResultsProcessor.cs b/TestStack.ConventionTests/Reporting/ThrowOnFailureResultsProcessor.cs index f8d565a..2bae6cd 100644 --- a/TestStack.ConventionTests/Reporting/ThrowOnFailureResultsProcessor.cs +++ b/TestStack.ConventionTests/Reporting/ThrowOnFailureResultsProcessor.cs @@ -8,7 +8,7 @@ public class ThrowOnFailureResultsProcessor : IResultsProcessor { public void Process(IConventionFormatContext context, params ConventionResult[] results) { - var invalidResults = results.Where(r => r.HasData).Select(r => r.FormattedResult).ToArray(); + var invalidResults = results.Where(r => r.HasData).Select(r => context.TestResultProcessor.Process(context, r)).ToArray(); if (invalidResults.None()) { return; diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 47a6d07..2c3dbb4 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -80,6 +80,7 @@ + From 768b4446a7f9d9323e81089075590fa61a483c1c Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 31 Aug 2013 11:38:13 +0100 Subject: [PATCH 06/10] Got rid of ConventionReportFailure --- .../ConventionAssertionClassTests.cs | 10 ++---- .../Internal/ConventionContext.cs | 4 +-- .../Internal/ConventionReportFailure.cs | 17 ---------- .../Internal/IConventionFormatContext.cs | 2 +- .../Reporting/ConventionReportTextRenderer.cs | 2 +- .../Reporting/ConvertibleFormatter.cs | 5 ++- .../Reporting/DefaultFormatter.cs | 2 +- .../Reporting/FallbackFormatter.cs | 9 +++-- .../Reporting/IReportDataFormatter.cs | 4 +-- .../Reporting/MethodInfoDataFormatter.cs | 33 +++++++++---------- .../Reporting/ProjectFileFormatter.cs | 9 +++-- .../Reporting/ProjectReferenceFormatter.cs | 9 +++-- .../Reporting/StringDataFormatter.cs | 8 ++--- .../Reporting/TypeDataFormatter.cs | 9 +++-- .../TestStack.ConventionTests.csproj | 1 - 15 files changed, 44 insertions(+), 80 deletions(-) delete mode 100644 TestStack.ConventionTests/Internal/ConventionReportFailure.cs diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 0fa1f0d..0a733d4 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -2,7 +2,6 @@ { using ApprovalTests.Reporters; using NUnit.Framework; - using TestStack.ConventionTests.Internal; [TestFixture] [UseReporter(typeof(QuietReporter))] //NOTE: Can we take care of this in IsWithApprovedExceptions? @@ -19,19 +18,14 @@ public void approval_mismatch() StringAssert.Contains("does not match approved file", ex.Message); } - public class FakeData : IConventionData + class FakeData : IConventionData { public string Description { get { return "Fake data"; } } public bool HasData { get { return true; } } - - public ConventionReportFailure Format(string failingData) - { - return new ConventionReportFailure(failingData); - } } - public class FailingConvention : IConvention + class FailingConvention : IConvention { public void Execute(FakeData data, IConventionResultContext result) { diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index dfadb4a..0f05748 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -33,7 +33,7 @@ ITestResultProcessor IConventionFormatContext.TestResultProcessor get { return testResultProcessor; } } - ConventionReportFailure IConventionFormatContext.FormatData(object failingData) + string IConventionFormatContext.FormatDataAsString(object failingData) { IReportDataFormatter formatter = formatters.FirstOrDefault(f => f.CanFormat(failingData)); if (formatter == null) @@ -43,7 +43,7 @@ ConventionReportFailure IConventionFormatContext.FormatData(object failingData) " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); } - return formatter.Format(failingData); + return formatter.FormatString(failingData); } void IConventionResultContext.Is(string resultTitle, IEnumerable failingData) diff --git a/TestStack.ConventionTests/Internal/ConventionReportFailure.cs b/TestStack.ConventionTests/Internal/ConventionReportFailure.cs deleted file mode 100644 index 199b94c..0000000 --- a/TestStack.ConventionTests/Internal/ConventionReportFailure.cs +++ /dev/null @@ -1,17 +0,0 @@ -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/IConventionFormatContext.cs b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs index f069caf..96845fe 100644 --- a/TestStack.ConventionTests/Internal/IConventionFormatContext.cs +++ b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs @@ -4,7 +4,7 @@ public interface IConventionFormatContext { - ConventionReportFailure FormatData(object failingData); + string FormatDataAsString(object failingData); ITestResultProcessor TestResultProcessor { get; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs index 849ff8d..647e67b 100644 --- a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs @@ -25,7 +25,7 @@ static void RenderItems(ConventionResult resultInfo, StringBuilder stringBuilder foreach (var conventionFailure in resultInfo.Data) { stringBuilder.Append("\t"); - stringBuilder.AppendLine(context.FormatData(conventionFailure).ToString()); + stringBuilder.AppendLine(context.FormatDataAsString(conventionFailure)); } } } diff --git a/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs b/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs index 94a71a2..63fb750 100644 --- a/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs +++ b/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs @@ -3,7 +3,6 @@ namespace TestStack.ConventionTests.Reporting using System; using System.Diagnostics; using System.Globalization; - using TestStack.ConventionTests.Internal; public class ConvertibleFormatter : IReportDataFormatter { @@ -12,11 +11,11 @@ public bool CanFormat(object failingData) return failingData is IConvertible; } - public ConventionReportFailure Format(object failingData) + public string FormatString(object failingData) { var convertible = failingData as IConvertible; Debug.Assert(convertible != null, "convertible != null"); - return new ConventionReportFailure(convertible.ToString(CultureInfo.InvariantCulture)); + return convertible.ToString(CultureInfo.InvariantCulture); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/DefaultFormatter.cs b/TestStack.ConventionTests/Reporting/DefaultFormatter.cs index f5ea878..fcbb7ab 100644 --- a/TestStack.ConventionTests/Reporting/DefaultFormatter.cs +++ b/TestStack.ConventionTests/Reporting/DefaultFormatter.cs @@ -27,7 +27,7 @@ string Describe(PropertyInfo property) public string[] DesribeItem(object result, IConventionFormatContext context) { - return properties.Select(p => context.FormatData(p.GetValue(result, null)).ToString()).ToArray(); + return properties.Select(p => context.FormatDataAsString(p.GetValue(result, null)).ToString()).ToArray(); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/FallbackFormatter.cs b/TestStack.ConventionTests/Reporting/FallbackFormatter.cs index a7b89e5..30763b2 100644 --- a/TestStack.ConventionTests/Reporting/FallbackFormatter.cs +++ b/TestStack.ConventionTests/Reporting/FallbackFormatter.cs @@ -1,7 +1,5 @@ namespace TestStack.ConventionTests.Reporting { - using TestStack.ConventionTests.Internal; - public class FallbackFormatter : IReportDataFormatter { public bool CanFormat(object failingData) @@ -9,10 +7,11 @@ public bool CanFormat(object failingData) return true; } - public ConventionReportFailure Format(object failingData) + public string FormatString(object failingData) { - // TODO: for now - return new ConventionReportFailure(failingData.ToString()); + if (failingData == null) + return ""; + return failingData.ToString(); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs b/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs index 1cea26c..207d89f 100644 --- a/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs @@ -1,10 +1,8 @@ namespace TestStack.ConventionTests.Reporting { - using TestStack.ConventionTests.Internal; - public interface IReportDataFormatter { bool CanFormat(object failingData); - ConventionReportFailure Format(object failingData); + string FormatString(object failingData); } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs index 12de3e3..b468533 100644 --- a/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs @@ -1,22 +1,19 @@ -namespace TestStack.ConventionTests.Reporting +namespace TestStack.ConventionTests.Reporting { - using System.ComponentModel; using System.Reflection; - using ApprovalTests.Namers; - 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); - } - } + public class MethodInfoDataFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return failingData is MethodInfo; + } + + public string FormatString(object failingData) + { + var methodInfo = (MethodInfo)failingData; + + return methodInfo.DeclaringType + "." + methodInfo.Name; + } + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs index 06e6c56..92d199a 100644 --- a/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs +++ b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs @@ -1,8 +1,7 @@ namespace TestStack.ConventionTests.Reporting { - using TestStack.ConventionTests.ConventionData; - using TestStack.ConventionTests.Internal; - + using TestStack.ConventionTests.ConventionData; + public class ProjectFileFormatter : IReportDataFormatter { public bool CanFormat(object failingData) @@ -10,9 +9,9 @@ public bool CanFormat(object failingData) return failingData is ProjectFileItem; } - public ConventionReportFailure Format(object failingData) + public string FormatString(object failingData) { - return new ConventionReportFailure(((ProjectFileItem)failingData).FilePath); + return ((ProjectFileItem)failingData).FilePath; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs b/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs index 1481849..229b076 100644 --- a/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs +++ b/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs @@ -1,8 +1,7 @@ namespace TestStack.ConventionTests.Reporting { - using TestStack.ConventionTests.ConventionData; - using TestStack.ConventionTests.Internal; - + using TestStack.ConventionTests.ConventionData; + public class ProjectReferenceFormatter : IReportDataFormatter { public bool CanFormat(object failingData) @@ -10,9 +9,9 @@ public bool CanFormat(object failingData) return failingData is ProjectReference; } - public ConventionReportFailure Format(object failingData) + public string FormatString(object failingData) { - return new ConventionReportFailure(((ProjectReference)failingData).ReferencedPath); + return ((ProjectReference)failingData).ReferencedPath; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/StringDataFormatter.cs b/TestStack.ConventionTests/Reporting/StringDataFormatter.cs index ab70c55..035f5cf 100644 --- a/TestStack.ConventionTests/Reporting/StringDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/StringDataFormatter.cs @@ -1,7 +1,5 @@ namespace TestStack.ConventionTests.Reporting -{ - using TestStack.ConventionTests.Internal; - +{ public class StringDataFormatter : IReportDataFormatter { public bool CanFormat(object failingData) @@ -9,9 +7,9 @@ public bool CanFormat(object failingData) return failingData is string; } - public ConventionReportFailure Format(object failingData) + public string FormatString(object failingData) { - return new ConventionReportFailure((string)failingData); + return (string)failingData; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs b/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs index d1b2cd2..28783b0 100644 --- a/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs @@ -1,8 +1,7 @@ namespace TestStack.ConventionTests.Reporting { - using System; - using TestStack.ConventionTests.Internal; - + using System; + public class TypeDataFormatter : IReportDataFormatter { public bool CanFormat(object failingData) @@ -10,9 +9,9 @@ public bool CanFormat(object failingData) return failingData is Type; } - public ConventionReportFailure Format(object failingData) + public string FormatString(object failingData) { - return new ConventionReportFailure(((Type)failingData).FullName); + return ((Type)failingData).FullName; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 2c3dbb4..127dde1 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -64,7 +64,6 @@ - From 8093735a8ff1d26db1358ab1eb7ff94112c8746e Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sat, 31 Aug 2013 16:31:02 +0100 Subject: [PATCH 07/10] Example of rich formatting. Formatters also do not have to be formatting failing data, it can be conforming data too --- .../Internal/ConventionContext.cs | 23 +++- .../Internal/IConventionFormatContext.cs | 5 +- .../Reporting/ConvertibleFormatter.cs | 13 +- .../Reporting/FallbackFormatter.cs | 13 +- .../GroupedByDataTypeRendererBase.cs | 4 +- .../Reporting/HtmlReportRenderer.cs | 67 ++++++++--- .../Reporting/IReportDataFormatter.cs | 5 +- .../Reporting/MarkdownReportRenderer.cs | 2 +- .../Reporting/MethodInfoDataFormatter.cs | 112 +++++++++++++++++- .../Reporting/ProjectFileFormatter.cs | 15 ++- .../Reporting/ProjectReferenceFormatter.cs | 15 ++- .../Reporting/StringDataFormatter.cs | 15 ++- .../Reporting/TypeDataFormatter.cs | 19 ++- 13 files changed, 248 insertions(+), 60 deletions(-) diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index 0f05748..4a13938 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -28,22 +28,33 @@ public ConventionResult[] ConventionResults get { return results.ToArray(); } } + string IConventionFormatContext.FormatDataAsHtml(object data) + { + var formatter = GetReportDataFormatterFor(data); + return formatter.FormatHtml(data); + } + ITestResultProcessor IConventionFormatContext.TestResultProcessor { get { return testResultProcessor; } } - string IConventionFormatContext.FormatDataAsString(object failingData) + string IConventionFormatContext.FormatDataAsString(object data) + { + var formatter = GetReportDataFormatterFor(data); + + return formatter.FormatString(data); + } + + IReportDataFormatter GetReportDataFormatterFor(object data) { - IReportDataFormatter formatter = formatters.FirstOrDefault(f => f.CanFormat(failingData)); + IReportDataFormatter formatter = formatters.FirstOrDefault(f => f.CanFormat(data)); if (formatter == null) { throw new NoDataFormatterFoundException( - failingData.GetType().Name + - " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); + data.GetType().Name + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); } - - return formatter.FormatString(failingData); + return formatter; } void IConventionResultContext.Is(string resultTitle, IEnumerable failingData) diff --git a/TestStack.ConventionTests/Internal/IConventionFormatContext.cs b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs index 96845fe..7318057 100644 --- a/TestStack.ConventionTests/Internal/IConventionFormatContext.cs +++ b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs @@ -4,7 +4,8 @@ public interface IConventionFormatContext { - string FormatDataAsString(object failingData); - ITestResultProcessor TestResultProcessor { get; } + string FormatDataAsString(object data); + string FormatDataAsHtml(object data); + ITestResultProcessor TestResultProcessor { get; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs b/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs index 63fb750..cada564 100644 --- a/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs +++ b/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs @@ -6,16 +6,21 @@ namespace TestStack.ConventionTests.Reporting public class ConvertibleFormatter : IReportDataFormatter { - public bool CanFormat(object failingData) + public bool CanFormat(object data) { - return failingData is IConvertible; + return data is IConvertible; } - public string FormatString(object failingData) + public string FormatString(object data) { - var convertible = failingData as IConvertible; + var convertible = data as IConvertible; Debug.Assert(convertible != null, "convertible != null"); return convertible.ToString(CultureInfo.InvariantCulture); } + + public string FormatHtml(object data) + { + return FormatString(data); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/FallbackFormatter.cs b/TestStack.ConventionTests/Reporting/FallbackFormatter.cs index 30763b2..beafffa 100644 --- a/TestStack.ConventionTests/Reporting/FallbackFormatter.cs +++ b/TestStack.ConventionTests/Reporting/FallbackFormatter.cs @@ -2,16 +2,21 @@ { public class FallbackFormatter : IReportDataFormatter { - public bool CanFormat(object failingData) + public bool CanFormat(object data) { return true; } - public string FormatString(object failingData) + public string FormatString(object data) { - if (failingData == null) + if (data == null) return ""; - return failingData.ToString(); + return data.ToString(); + } + + public string FormatHtml(object data) + { + return FormatString(data); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs b/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs index c4667ac..e0a431d 100644 --- a/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs +++ b/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs @@ -8,9 +8,9 @@ public abstract class GroupedByDataTypeRendererBase : AggregatedRenderer { protected override void Process(IConventionFormatContext context) { - Process(AggregatedReports.OrderBy(c => c.ConventionTitle).GroupBy(r => r.DataDescription)); + Process(context, AggregatedReports.OrderBy(c => c.ConventionTitle).GroupBy(r => r.DataDescription)); } - protected abstract void Process(IEnumerable> resultsGroupedByDataType); + protected abstract void Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType); } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs index 7b9f73c..2aef682 100644 --- a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs @@ -16,25 +16,34 @@ public HtmlReportRenderer(string assemblyDirectory) file = Path.Combine(assemblyDirectory, "Conventions.htm"); } - protected override void Process(IEnumerable> resultsGroupedByDataType) + protected override void Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType) { var sb = new StringBuilder(); var html = new HtmlTextWriter(new StringWriter(sb)); html.WriteLine(""); html.RenderBeginTag(HtmlTextWriterTag.Html); // html.RenderBeginTag(HtmlTextWriterTag.Head); // + + + html.AddAttribute("href", "http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css"); + html.AddAttribute("rel", "stylesheet"); + html.RenderBeginTag(HtmlTextWriterTag.Link); + html.RenderEndTag(); + html.AddAttribute("href", "http://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css"); + html.AddAttribute("rel", "stylesheet"); + html.Write(@" - "); + + html.RenderBeginTag(HtmlTextWriterTag.Link); + html.RenderEndTag(); - h2 { - background: #f1f1f1; - } - "); html.RenderEndTag(); // - html.WriteLine(); html.RenderBeginTag(HtmlTextWriterTag.Body); // html.RenderBeginTag(HtmlTextWriterTag.H1); @@ -43,23 +52,51 @@ protected override void Process(IEnumerable> foreach (var conventionReport in resultsGroupedByDataType) { - html.RenderBeginTag(HtmlTextWriterTag.P); html.RenderBeginTag(HtmlTextWriterTag.Div); + html.AddAttribute("style", "margin-left:20px;border-bottom: 1px solid"); html.RenderBeginTag(HtmlTextWriterTag.H2); html.Write("Conventions for '{0}'", conventionReport.Key); html.RenderEndTag(); - html.RenderBeginTag(HtmlTextWriterTag.Ul); foreach (var conventionResult in conventionReport) { - html.RenderBeginTag(HtmlTextWriterTag.Li); + var targetId = + conventionResult.ConventionTitle.Replace("'", string.Empty).Replace(" ", string.Empty).Replace(".", string.Empty) + + conventionResult.DataDescription.Replace("'", string.Empty).Replace(" ", string.Empty).Replace(".", string.Empty); + html.AddAttribute("style", "margin-left:20px;"); + html.RenderBeginTag(HtmlTextWriterTag.H4); + + html.AddAttribute("class", "menu-toggle"); + html.AddAttribute("data-toggle", "collapse"); + html.AddAttribute("data-target", "." + targetId); + html.RenderBeginTag(HtmlTextWriterTag.A); + html.AddAttribute("class", "icon-angle-down"); + html.RenderBeginTag(HtmlTextWriterTag.I); + html.RenderEndTag(); + html.RenderEndTag(); html.Write(conventionResult.ConventionTitle); html.RenderEndTag(); + html.AddAttribute("class", targetId + " collapse"); + html.AddAttribute("style", "margin-left:20px;"); + html.RenderBeginTag(HtmlTextWriterTag.Div); + html.RenderBeginTag(HtmlTextWriterTag.Ul); + foreach (var o in conventionResult.Data) + { + html.RenderBeginTag(HtmlTextWriterTag.Li); + html.Write(context.FormatDataAsHtml(o)); + html.RenderEndTag(); + } + html.RenderEndTag(); + html.RenderEndTag(); } html.RenderEndTag(); - html.RenderEndTag(); - html.RenderEndTag(); } + html.AddAttribute("src", "http://code.jquery.com/jquery.js"); + html.RenderBeginTag(HtmlTextWriterTag.Script); + html.RenderEndTag(); + html.AddAttribute("src", "http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"); + html.RenderBeginTag(HtmlTextWriterTag.Script); + html.RenderEndTag(); html.RenderEndTag(); // html.RenderEndTag(); // html.Flush(); diff --git a/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs b/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs index 207d89f..a9be8a0 100644 --- a/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/IReportDataFormatter.cs @@ -2,7 +2,8 @@ { public interface IReportDataFormatter { - bool CanFormat(object failingData); - string FormatString(object failingData); + bool CanFormat(object data); + string FormatString(object data); + string FormatHtml(object data); } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs b/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs index 31a2cfe..3470414 100644 --- a/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs @@ -15,7 +15,7 @@ public MarkdownReportRenderer(string assemblyDirectory) file = Path.Combine(assemblyDirectory, "Conventions.md"); } - protected override void Process(IEnumerable> resultsGroupedByDataType) + protected override void Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType) { var sb = new StringBuilder(); sb.AppendLine("# Project Conventions"); diff --git a/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs index b468533..1a7f13a 100644 --- a/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs @@ -1,19 +1,123 @@ namespace TestStack.ConventionTests.Reporting { + using System; using System.Reflection; + using System.Text; public class MethodInfoDataFormatter : IReportDataFormatter { - public bool CanFormat(object failingData) + public bool CanFormat(object data) { - return failingData is MethodInfo; + return data is MethodInfo; } - public string FormatString(object failingData) + public string FormatString(object data) { - var methodInfo = (MethodInfo)failingData; + var methodInfo = (MethodInfo)data; return methodInfo.DeclaringType + "." + methodInfo.Name; } + + public string FormatHtml(object data) + { + const string keywordFormat = "{0}"; + const string typeFormat = "{0}"; + + var methodInfo = (MethodInfo)data; + var sb = new StringBuilder(); + var declaringType = methodInfo.DeclaringType; + sb.AppendFormat("{0} {1}.{2} {{ ", + string.Format(keywordFormat, "class"), + declaringType.Namespace, + string.Format(typeFormat, declaringType.Name)); + + AppendAccess(methodInfo, sb, keywordFormat); + + if (methodInfo.IsVirtual) + { + sb.AppendFormat(keywordFormat, "virtual"); + sb.Append(" "); + } + + AppendMethodName(methodInfo, sb); + sb.Append(" (...)"); + sb.Append("}}"); + + return sb.ToString(); + } + + void AppendMethodName(MethodInfo methodInfo, StringBuilder sb) + { + sb.Append(methodInfo.Name); + bool firstParam = true; + if (methodInfo.IsGenericMethod) + { + sb.Append("<"); + foreach (var g in methodInfo.GetGenericArguments()) + { + if (firstParam) + firstParam = false; + else + sb.Append(", "); + sb.Append(TypeName(g)); + } + sb.Append(">"); + } + } + + void AppendAccess(MethodInfo method, StringBuilder sb, string format = "{0}") + { + if (method.IsPublic) + sb.AppendFormat(format, "public "); + else if (method.IsPrivate) + sb.AppendFormat("private "); + else if (method.IsAssembly) + sb.AppendFormat("internal "); + if (method.IsFamily) + sb.AppendFormat("protected "); + if (method.IsStatic) + sb.AppendFormat("static "); + } + + static string TypeName(Type type) + { + var nullableType = Nullable.GetUnderlyingType(type); + if (nullableType != null) + return nullableType.Name + "?"; + + if (!type.IsGenericType) + switch (type.Name) + { + case "String": + return "string"; + case "Int32": + return "int"; + case "Decimal": + return "decimal"; + case "Object": + return "object"; + case "Void": + return "void"; + default: + { + return string.IsNullOrWhiteSpace(type.FullName) ? type.Name : type.FullName; + } + } + + var sb = new StringBuilder(type.Name.Substring(0, + type.Name.IndexOf('`')) + ); + sb.Append('<'); + var first = true; + foreach (var t in type.GetGenericArguments()) + { + if (!first) + sb.Append(','); + sb.Append(TypeName(t)); + first = false; + } + sb.Append('>'); + return sb.ToString(); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs index 92d199a..cf9d877 100644 --- a/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs +++ b/TestStack.ConventionTests/Reporting/ProjectFileFormatter.cs @@ -4,14 +4,19 @@ namespace TestStack.ConventionTests.Reporting public class ProjectFileFormatter : IReportDataFormatter { - public bool CanFormat(object failingData) + public bool CanFormat(object data) { - return failingData is ProjectFileItem; + return data is ProjectFileItem; } - public string FormatString(object failingData) + public string FormatString(object data) { - return ((ProjectFileItem)failingData).FilePath; - } + return ((ProjectFileItem)data).FilePath; + } + + public string FormatHtml(object data) + { + return ((ProjectFileItem) data).FilePath; + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs b/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs index 229b076..b41def6 100644 --- a/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs +++ b/TestStack.ConventionTests/Reporting/ProjectReferenceFormatter.cs @@ -4,14 +4,19 @@ namespace TestStack.ConventionTests.Reporting public class ProjectReferenceFormatter : IReportDataFormatter { - public bool CanFormat(object failingData) + public bool CanFormat(object data) { - return failingData is ProjectReference; + return data is ProjectReference; } - public string FormatString(object failingData) + public string FormatString(object data) { - return ((ProjectReference)failingData).ReferencedPath; - } + return ((ProjectReference)data).ReferencedPath; + } + + public string FormatHtml(object data) + { + return ((ProjectReference)data).ReferencedPath; + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/StringDataFormatter.cs b/TestStack.ConventionTests/Reporting/StringDataFormatter.cs index 035f5cf..f477cfb 100644 --- a/TestStack.ConventionTests/Reporting/StringDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/StringDataFormatter.cs @@ -2,14 +2,19 @@ { public class StringDataFormatter : IReportDataFormatter { - public bool CanFormat(object failingData) + public bool CanFormat(object data) { - return failingData is string; + return data is string; } - public string FormatString(object failingData) + public string FormatString(object data) { - return (string)failingData; - } + return (string)data; + } + + public string FormatHtml(object data) + { + return (string)data; + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs b/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs index 28783b0..49a3c76 100644 --- a/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/TypeDataFormatter.cs @@ -4,14 +4,23 @@ namespace TestStack.ConventionTests.Reporting public class TypeDataFormatter : IReportDataFormatter { - public bool CanFormat(object failingData) + public bool CanFormat(object data) { - return failingData is Type; + return data is Type; } - public string FormatString(object failingData) + public string FormatString(object data) { - return ((Type)failingData).FullName; - } + return ((Type)data).FullName; + } + + public string FormatHtml(object data) + { + var type = ((Type)data); + var ns = type.Namespace; + if (ns == null) + return type.Name; + return string.Format("{0}.{1}", ns, type.Name); + } } } \ No newline at end of file From b782207280430a15492ab11e0f2aac97745329ef Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sun, 1 Sep 2013 11:00:43 +0100 Subject: [PATCH 08/10] Allowed reporters to be specified by using the ConventionReporterAttribute in the assembly info. --- .../Properties/AssemblyInfo.cs | 7 ++- TestStack.ConventionTests/Convention.cs | 58 ++++++++++--------- .../ConventionReporterAttribute.cs | 18 ++++++ .../AggregatedConventionResultsReporter.cs | 46 +++++++++++++++ .../Reporting/AggregatedRenderer.cs | 23 -------- ...ByDataTypeConventionResultsReporterBase.cs | 20 +++++++ .../GroupedByDataTypeRendererBase.cs | 16 ----- ...er.cs => HtmlConventionResultsReporter.cs} | 12 ++-- ...s => MarkdownConventionResultsReporter.cs} | 12 ++-- .../TestStack.ConventionTests.csproj | 9 +-- 10 files changed, 133 insertions(+), 88 deletions(-) create mode 100644 TestStack.ConventionTests/ConventionReporterAttribute.cs create mode 100644 TestStack.ConventionTests/Reporting/AggregatedConventionResultsReporter.cs delete mode 100644 TestStack.ConventionTests/Reporting/AggregatedRenderer.cs create mode 100644 TestStack.ConventionTests/Reporting/GroupedByDataTypeConventionResultsReporterBase.cs delete mode 100644 TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs rename TestStack.ConventionTests/Reporting/{HtmlReportRenderer.cs => HtmlConventionResultsReporter.cs} (89%) rename TestStack.ConventionTests/Reporting/{MarkdownReportRenderer.cs => MarkdownConventionResultsReporter.cs} (59%) diff --git a/TestStack.ConventionTests.Tests/Properties/AssemblyInfo.cs b/TestStack.ConventionTests.Tests/Properties/AssemblyInfo.cs index 76836cd..7e55925 100644 --- a/TestStack.ConventionTests.Tests/Properties/AssemblyInfo.cs +++ b/TestStack.ConventionTests.Tests/Properties/AssemblyInfo.cs @@ -1,9 +1,11 @@ using System.Reflection; using System.Runtime.InteropServices; - // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. +using TestStack.ConventionTests; +using TestStack.ConventionTests.Reporting; + [assembly: AssemblyTitle("TestStack.ConventionTests.Tests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] @@ -33,3 +35,6 @@ // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: ConventionReporter(typeof(HtmlConventionResultsReporter))] +[assembly: ConventionReporter(typeof(MarkdownConventionResultsReporter))] \ No newline at end of file diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 0bf4879..9f93bdd 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -2,7 +2,6 @@ { using System; using System.Collections.Generic; - using System.IO; using System.Reflection; using System.Text.RegularExpressions; using TestStack.ConventionTests.Internal; @@ -10,7 +9,8 @@ public static class Convention { - static readonly HtmlReportRenderer HtmlRenderer = new HtmlReportRenderer(AssemblyDirectory); + static IResultsProcessor[] defaultProcessors; + static IResultsProcessor[] defaultApprovalProcessors; static Convention() { @@ -28,42 +28,22 @@ static Convention() public static IList Formatters { get; set; } - static string AssemblyDirectory - { - get - { - // http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917 - var codeBase = Assembly.GetExecutingAssembly().CodeBase; - var uri = new UriBuilder(codeBase); - var path = Uri.UnescapeDataString(uri.Path); - return Path.GetDirectoryName(path); - } - } - public static void Is(IConvention convention, TDataSource data, ITestResultProcessor resultProcessor = null) where TDataSource : IConventionData { - var processors = new List - { - HtmlRenderer, - new ConventionReportTraceRenderer(), - new ThrowOnFailureResultsProcessor() - }; - Execute(convention, data, processors.ToArray(), resultProcessor ?? new ConventionReportTextRenderer()); + if (defaultProcessors == null || defaultApprovalProcessors == null) + Init(Assembly.GetCallingAssembly()); + Execute(convention, data, defaultProcessors, resultProcessor ?? new ConventionReportTextRenderer()); } public static void IsWithApprovedExeptions(IConvention convention, TDataSource data, ITestResultProcessor resultProcessor = null) where TDataSource : IConventionData { - var processors = new List - { - HtmlRenderer, - new ConventionReportTraceRenderer(), - new ApproveResultsProcessor() - }; - Execute(convention, data, processors.ToArray(), resultProcessor ?? new ConventionReportTextRenderer()); + if (defaultProcessors == null || defaultApprovalProcessors == null) + Init(Assembly.GetCallingAssembly()); + Execute(convention, data, defaultApprovalProcessors, resultProcessor ?? new ConventionReportTextRenderer()); } static void Execute(IConvention convention, TDataSource data, @@ -75,6 +55,28 @@ static void Execute(IConvention convention, TDataSourc context.Execute(convention, data); } + static void Init(Assembly assembly) + { + var customReporters = assembly.GetCustomAttributes(typeof(ConventionReporterAttribute), false); + + defaultProcessors = new IResultsProcessor[customReporters.Length + 2]; + defaultApprovalProcessors = new IResultsProcessor[customReporters.Length + 2]; + + for (var index = 0; index < customReporters.Length; index++) + { + var customReporter = (ConventionReporterAttribute)customReporters[index]; + var resultsProcessor = (IResultsProcessor)Activator.CreateInstance(customReporter.ReporterType); + defaultProcessors[index] = resultsProcessor; + defaultApprovalProcessors[index] = resultsProcessor; + } + + var conventionReportTraceRenderer = new ConventionReportTraceRenderer(); + defaultProcessors[defaultProcessors.Length - 2] = conventionReportTraceRenderer; + defaultApprovalProcessors[defaultProcessors.Length - 2] = conventionReportTraceRenderer; + defaultProcessors[defaultProcessors.Length - 1] = new ThrowOnFailureResultsProcessor(); + defaultApprovalProcessors[defaultProcessors.Length - 1] = new ApproveResultsProcessor(); + } + static string ToSentenceCase(string str) { return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])); diff --git a/TestStack.ConventionTests/ConventionReporterAttribute.cs b/TestStack.ConventionTests/ConventionReporterAttribute.cs new file mode 100644 index 0000000..4466e51 --- /dev/null +++ b/TestStack.ConventionTests/ConventionReporterAttribute.cs @@ -0,0 +1,18 @@ +namespace TestStack.ConventionTests +{ + using System; + using TestStack.ConventionTests.Reporting; + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class ConventionReporterAttribute : Attribute + { + public ConventionReporterAttribute(Type reporterType) + { + ReporterType = reporterType; + if (!typeof(IResultsProcessor).IsAssignableFrom(reporterType)) + throw new ArgumentException("Reporters must inherit from IResultsProcessor", "reporterType"); + } + + public Type ReporterType { get; private set; } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/AggregatedConventionResultsReporter.cs b/TestStack.ConventionTests/Reporting/AggregatedConventionResultsReporter.cs new file mode 100644 index 0000000..d43cc7e --- /dev/null +++ b/TestStack.ConventionTests/Reporting/AggregatedConventionResultsReporter.cs @@ -0,0 +1,46 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Reflection; + using TestStack.ConventionTests.Internal; + + /// + /// Aggregates all previous results + /// + public abstract class AggregatedConventionResultsReporter : IResultsProcessor + { + static readonly List Reports = new List(); + readonly string output; + + protected AggregatedConventionResultsReporter(string outputFilename) + { + output = Path.Combine(AssemblyDirectory, outputFilename); + } + + static string AssemblyDirectory + { + get + { + // http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917 + var codeBase = Assembly.GetExecutingAssembly().CodeBase; + var uri = new UriBuilder(codeBase); + var path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path); + } + } + + public IEnumerable AggregatedReports { get { return Reports; } } + + public void Process(IConventionFormatContext context, params ConventionResult[] results) + { + Reports.AddRange(results.Except(Reports)); + var outputContent = Process(context); + File.WriteAllText(output, outputContent); + } + + protected abstract string Process(IConventionFormatContext context); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/AggregatedRenderer.cs b/TestStack.ConventionTests/Reporting/AggregatedRenderer.cs deleted file mode 100644 index ebc4526..0000000 --- a/TestStack.ConventionTests/Reporting/AggregatedRenderer.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace TestStack.ConventionTests.Reporting -{ - using System.Collections.Generic; - using System.Linq; - using TestStack.ConventionTests.Internal; - - /// - /// Aggregates all previous results - /// - public abstract class AggregatedRenderer : IResultsProcessor - { - static readonly List Reports = new List(); - public IEnumerable AggregatedReports { get { return Reports; } } - - public void Process(IConventionFormatContext context, params ConventionResult[] results) - { - Reports.AddRange(results.Except(Reports)); - Process(context); - } - - protected abstract void Process(IConventionFormatContext context); - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/GroupedByDataTypeConventionResultsReporterBase.cs b/TestStack.ConventionTests/Reporting/GroupedByDataTypeConventionResultsReporterBase.cs new file mode 100644 index 0000000..0b630a8 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/GroupedByDataTypeConventionResultsReporterBase.cs @@ -0,0 +1,20 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System.Collections.Generic; + using System.Linq; + using TestStack.ConventionTests.Internal; + + public abstract class GroupedByDataTypeConventionResultsReporterBase : AggregatedConventionResultsReporter + { + protected GroupedByDataTypeConventionResultsReporterBase(string outputFilename) : base(outputFilename) + { + } + + protected override string Process(IConventionFormatContext context) + { + return Process(context, AggregatedReports.OrderBy(c => c.ConventionTitle).GroupBy(r => r.DataDescription)); + } + + protected abstract string Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs b/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs deleted file mode 100644 index e0a431d..0000000 --- a/TestStack.ConventionTests/Reporting/GroupedByDataTypeRendererBase.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace TestStack.ConventionTests.Reporting -{ - using System.Collections.Generic; - using System.Linq; - using TestStack.ConventionTests.Internal; - - public abstract class GroupedByDataTypeRendererBase : AggregatedRenderer - { - protected override void Process(IConventionFormatContext context) - { - Process(context, AggregatedReports.OrderBy(c => c.ConventionTitle).GroupBy(r => r.DataDescription)); - } - - protected abstract void Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType); - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs b/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs similarity index 89% rename from TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs rename to TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs index 2aef682..5c73100 100644 --- a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs @@ -7,16 +7,13 @@ using System.Web.UI; using TestStack.ConventionTests.Internal; - public class HtmlReportRenderer : GroupedByDataTypeRendererBase + public class HtmlConventionResultsReporter : GroupedByDataTypeConventionResultsReporterBase { - readonly string file; - - public HtmlReportRenderer(string assemblyDirectory) + public HtmlConventionResultsReporter() : base("Conventions.htm") { - file = Path.Combine(assemblyDirectory, "Conventions.htm"); } - protected override void Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType) + protected override string Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType) { var sb = new StringBuilder(); var html = new HtmlTextWriter(new StringWriter(sb)); @@ -100,8 +97,7 @@ protected override void Process(IConventionFormatContext context, IEnumerable html.RenderEndTag(); // html.Flush(); - - File.WriteAllText(file, sb.ToString()); + return sb.ToString(); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs b/TestStack.ConventionTests/Reporting/MarkdownConventionResultsReporter.cs similarity index 59% rename from TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs rename to TestStack.ConventionTests/Reporting/MarkdownConventionResultsReporter.cs index 3470414..15697c6 100644 --- a/TestStack.ConventionTests/Reporting/MarkdownReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/MarkdownConventionResultsReporter.cs @@ -1,21 +1,17 @@ namespace TestStack.ConventionTests.Reporting { using System.Collections.Generic; - using System.IO; using System.Linq; using System.Text; using TestStack.ConventionTests.Internal; - public class MarkdownReportRenderer : GroupedByDataTypeRendererBase + public class MarkdownConventionResultsReporter : GroupedByDataTypeConventionResultsReporterBase { - readonly string file; - - public MarkdownReportRenderer(string assemblyDirectory) + public MarkdownConventionResultsReporter() : base("Conventions.md") { - file = Path.Combine(assemblyDirectory, "Conventions.md"); } - protected override void Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType) + protected override string Process(IConventionFormatContext context, IEnumerable> resultsGroupedByDataType) { var sb = new StringBuilder(); sb.AppendLine("# Project Conventions"); @@ -31,7 +27,7 @@ protected override void Process(IConventionFormatContext context, IEnumerable + @@ -69,18 +70,18 @@ - + - - + + - + From 1e9770d80b026e577cfd6addb7bf0e3cf25f8e01 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Sun, 1 Sep 2013 11:14:22 +0100 Subject: [PATCH 09/10] Improved Html reporting, much happier with this. Except the styles, they still blow --- TestStack.ConventionTests/Convention.cs | 8 +--- .../ConventionData/TypeExtensions.cs | 6 +++ .../HtmlConventionResultsReporter.cs | 42 +++++++++++-------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 9f93bdd..ba5d9aa 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; + using TestStack.ConventionTests.ConventionData; using TestStack.ConventionTests.Internal; using TestStack.ConventionTests.Reporting; @@ -50,7 +51,7 @@ static void Execute(IConvention convention, TDataSourc IResultsProcessor[] processors, ITestResultProcessor resultProcessor) where TDataSource : IConventionData { - var dataDescription = string.Format("{0} in {1}", ToSentenceCase(data.GetType().Name), data.Description); + var dataDescription = string.Format("{0} in {1}", data.GetType().GetSentenceCaseName(), data.Description); var context = new ConventionContext(dataDescription, Formatters, processors, resultProcessor); context.Execute(convention, data); } @@ -76,10 +77,5 @@ static void Init(Assembly assembly) defaultProcessors[defaultProcessors.Length - 1] = new ThrowOnFailureResultsProcessor(); defaultApprovalProcessors[defaultProcessors.Length - 1] = new ApproveResultsProcessor(); } - - static string ToSentenceCase(string str) - { - return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])); - } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/ConventionData/TypeExtensions.cs b/TestStack.ConventionTests/ConventionData/TypeExtensions.cs index 93a8ea8..9d22184 100644 --- a/TestStack.ConventionTests/ConventionData/TypeExtensions.cs +++ b/TestStack.ConventionTests/ConventionData/TypeExtensions.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; + using System.Text.RegularExpressions; public static class TypeExtensions { @@ -66,5 +67,10 @@ public static bool ClosesInterface(this Type t, Type openGeneric) { return t.GetClosedInterfacesOf(openGeneric).Any(); } + + internal static string GetSentenceCaseName(this Type type) + { + return Regex.Replace(type.Name, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs b/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs index 5c73100..2ad93dc 100644 --- a/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs +++ b/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Web.UI; + using TestStack.ConventionTests.ConventionData; using TestStack.ConventionTests.Internal; public class HtmlConventionResultsReporter : GroupedByDataTypeConventionResultsReporterBase @@ -61,28 +62,35 @@ protected override string Process(IConventionFormatContext context, IEnumerable< conventionResult.DataDescription.Replace("'", string.Empty).Replace(" ", string.Empty).Replace(".", string.Empty); html.AddAttribute("style", "margin-left:20px;"); html.RenderBeginTag(HtmlTextWriterTag.H4); - - html.AddAttribute("class", "menu-toggle"); - html.AddAttribute("data-toggle", "collapse"); - html.AddAttribute("data-target", "." + targetId); - html.RenderBeginTag(HtmlTextWriterTag.A); - html.AddAttribute("class", "icon-angle-down"); - html.RenderBeginTag(HtmlTextWriterTag.I); - html.RenderEndTag(); - html.RenderEndTag(); html.Write(conventionResult.ConventionTitle); html.RenderEndTag(); - html.AddAttribute("class", targetId + " collapse"); - html.AddAttribute("style", "margin-left:20px;"); - html.RenderBeginTag(HtmlTextWriterTag.Div); - html.RenderBeginTag(HtmlTextWriterTag.Ul); - foreach (var o in conventionResult.Data) + if (conventionResult.Data.Any()) { - html.RenderBeginTag(HtmlTextWriterTag.Li); - html.Write(context.FormatDataAsHtml(o)); + html.AddAttribute("style", "margin-left:20px;"); + html.RenderBeginTag(HtmlTextWriterTag.Div); + html.AddAttribute("class", "menu-toggle"); + html.AddAttribute("data-toggle", "collapse"); + html.AddAttribute("data-target", "." + targetId); + html.RenderBeginTag(HtmlTextWriterTag.A); + html.AddAttribute("class", "icon-angle-down"); + html.RenderBeginTag(HtmlTextWriterTag.I); + html.RenderEndTag(); + html.Write("With the exception of the following {0}: ", conventionResult.DataType.GetSentenceCaseName()); + html.RenderEndTag(); + html.AddAttribute("class", targetId + " collapse"); + html.AddAttribute("style", "margin-left:20px;"); + html.RenderBeginTag(HtmlTextWriterTag.Div); + html.RenderBeginTag(HtmlTextWriterTag.Ul); + foreach (var o in conventionResult.Data) + { + html.RenderBeginTag(HtmlTextWriterTag.Li); + html.Write(context.FormatDataAsHtml(o)); + html.RenderEndTag(); + } + html.RenderEndTag(); html.RenderEndTag(); } - html.RenderEndTag(); + html.RenderEndTag(); } html.RenderEndTag(); From 54b98efdf3c0e791e2390481d6ff56b28a52f1d5 Mon Sep 17 00:00:00 2001 From: Jake Ginnivan Date: Mon, 2 Sep 2013 07:13:19 +0100 Subject: [PATCH 10/10] Fixed compilation issues --- TestStack.ConventionTests/ConventionData/ProjectFileItems.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestStack.ConventionTests/ConventionData/ProjectFileItems.cs b/TestStack.ConventionTests/ConventionData/ProjectFileItems.cs index 53be220..4785818 100644 --- a/TestStack.ConventionTests/ConventionData/ProjectFileItems.cs +++ b/TestStack.ConventionTests/ConventionData/ProjectFileItems.cs @@ -10,7 +10,7 @@ /// public class ProjectFileItems : AbstractProjectData { - public ProjectFilesItems(Assembly assembly, IProjectProvider projectProvider = null, IProjectLocator projectLocator = null) + public ProjectFileItems(Assembly assembly, IProjectProvider projectProvider = null, IProjectLocator projectLocator = null) : base(assembly, projectProvider, projectLocator) { }