diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt index 11906c4..d965a0a 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.approval_mismatch.approved.txt @@ -1,5 +1,4 @@ -Passed: 'Header' for 'Fake data' --------------------------------- +'Header' for 'Fake data' +------------------------ -With approved exceptions: Approved Exception \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/CsvReportTests.Can_run_convention_with_simple_reporter.approved.csv b/TestStack.ConventionTests.Tests/CsvReportTests.Can_run_convention_with_simple_reporter.approved.csv new file mode 100644 index 0000000..07a98d3 --- /dev/null +++ b/TestStack.ConventionTests.Tests/CsvReportTests.Can_run_convention_with_simple_reporter.approved.csv @@ -0,0 +1,5 @@ +collection,item,can add,can remove +TestAssembly.Collections.Branch,TestAssembly.Collections.Leaf,False,False +TestAssembly.Collections.Forest,TestAssembly.Collections.Tree,True,True +TestAssembly.Collections.Tree,TestAssembly.Collections.Branch,True,False +TestAssembly.Collections.Tree,TestAssembly.Collections.Leaf,False,False diff --git a/TestStack.ConventionTests.Tests/CsvReportTests.cs b/TestStack.ConventionTests.Tests/CsvReportTests.cs index 729e1ee..e653fec 100644 --- a/TestStack.ConventionTests.Tests/CsvReportTests.cs +++ b/TestStack.ConventionTests.Tests/CsvReportTests.cs @@ -5,13 +5,13 @@ using NUnit.Framework; using TestAssembly.Collections; using TestStack.ConventionTests.ConventionData; + using TestStack.ConventionTests.Reporting; using TestStack.ConventionTests.Tests.TestConventions; [UseReporter(typeof(DiffReporter))] public class CsvReportTests { [Test] - [Explicit("This is work in progress so ignoring for now")] public void Can_run_convention_with_simple_reporter() { Convention.IsWithApprovedExeptions(new CollectionsRelationsConvention(), new Types("Entities") @@ -19,7 +19,7 @@ public void Can_run_convention_with_simple_reporter() TypesToVerify = typeof (Leaf).Assembly.GetExportedTypes() .Where(t => t.Namespace == typeof (Leaf).Namespace).ToArray() - }); + }, new CsvReporter()); } } } \ No newline at end of file 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 c1f4909..5e98f99 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 @@ -Failed: '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 'TestStack.ConventionTests.Tests' +--------------------------------------------------------------------------------------------------- - bin\Debug\ApprovalTests.dll \ No newline at end of file + 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 1b176e9..5e98f99 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,5 +1,4 @@ -Passed: '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 'TestStack.ConventionTests.Tests' +--------------------------------------------------------------------------------------------------- -With approved exceptions: - bin\Debug\ApprovalTests.dll \ No newline at end of file + bin\Debug\ApprovalTests.dll 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 4ce889e..ef39646 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 @@ -Failed: '.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' -------------------------------------------------------------------------------------- +'.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' +----------------------------------------------------------------------------- - Scripts\Script2.sql \ No newline at end of file + 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 0217788..ef39646 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,5 +1,4 @@ -Passed: '.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' -------------------------------------------------------------------------------------- +'.sql Files must be embedded resources' for 'TestStack.ConventionTests.Tests' +----------------------------------------------------------------------------- -With approved exceptions: - Scripts\Script2.sql \ No newline at end of file + 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 173a5a4..a0fc6e2 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 @@ -Failed: 'Types must have a default constructor' for 'nHibernate Entitites' --------------------------------------------------------------------------- +'Types must have a default constructor' for 'nHibernate Entitites' +------------------------------------------------------------------ TestAssembly.ClassWithNoDefaultCtor - TestAssembly.ClassWithPrivateDefaultCtor \ No newline at end of file + 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 3cad8d9..a0fc6e2 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,6 +1,5 @@ -Passed: 'Types must have a default constructor' for 'nHibernate Entitites' --------------------------------------------------------------------------- +'Types must have a default constructor' for 'nHibernate Entitites' +------------------------------------------------------------------ -With approved exceptions: TestAssembly.ClassWithNoDefaultCtor - TestAssembly.ClassWithPrivateDefaultCtor \ No newline at end of file + 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 ec20755..ec621b2 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 @@ -Failed: 'Methods must be virtual' for 'nHibernate Entitites' ------------------------------------------------------------- +'Methods must be virtual' for 'nHibernate Entitites' +---------------------------------------------------- - TestAssembly.SampleDomainClass.TestNonVirtual \ No newline at end of file + 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 c1902ad..ec621b2 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,5 +1,4 @@ -Passed: 'Methods must be virtual' for 'nHibernate Entitites' ------------------------------------------------------------- +'Methods must be virtual' for 'nHibernate Entitites' +---------------------------------------------------- -With approved exceptions: - TestAssembly.SampleDomainClass.TestNonVirtual \ No newline at end of file + 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 b864151..fc2936a 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace.approved.txt +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace.approved.txt @@ -1,10 +1,9 @@ -Failed: 'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' ---------------------------------------------------------------------------------------- +'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +------------------------------------------------------------------------------- TestAssembly.SomeDto +'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +--------------------------------------------------------------------------------------- -Failed: 'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' ------------------------------------------------------------------------------------------------ - - TestAssembly.Dtos.AnotherClass \ No newline at end of file + TestAssembly.Dtos.AnotherClass diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace1.approved.txt b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace1.approved.txt new file mode 100644 index 0000000..5a005e3 --- /dev/null +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace1.approved.txt @@ -0,0 +1,4 @@ +'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +--------------------------------------------------------------------------------------- + + 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 6d0ccc9..6281d35 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,14 +1,4 @@ -Passed: 'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' ---------------------------------------------------------------------------------------- +'Dtos must be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +------------------------------------------------------------------------------- -With approved exceptions: TestAssembly.SomeDto - - - - -Passed: 'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' ------------------------------------------------------------------------------------------------ - -With approved exceptions: - TestAssembly.Dtos.AnotherClass \ No newline at end of file diff --git a/TestStack.ConventionTests.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 new file mode 100644 index 0000000..5a005e3 --- /dev/null +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.dtos_exists_in_dto_namespace_wth_approved_exceptions1.approved.txt @@ -0,0 +1,4 @@ +'Non-Dtos must not be under the 'TestAssembly.Dtos' namespace' for 'TestAssembly types' +--------------------------------------------------------------------------------------- + + TestAssembly.Dtos.AnotherClass diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 86a85f9..447d520 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -4,15 +4,12 @@ using System.Collections.Generic; using System.IO; using System.Reflection; - using ApprovalTests; - using ApprovalTests.Core.Exceptions; using TestStack.ConventionTests.Internal; using TestStack.ConventionTests.Reporting; public static class Convention { static readonly HtmlReportRenderer HtmlRenderer = new HtmlReportRenderer(AssemblyDirectory); - static readonly List Reports = new List(); static Convention() { @@ -22,72 +19,60 @@ static Convention() new ProjectReferenceFormatter(), new ProjectFileFormatter(), new MethodInfoDataFormatter(), - new StringDataFormatter() + new StringDataFormatter(), + new ConvertibleFormatter(), + new FallbackFormatter() }; } - public static IEnumerable ConventionReports { get { return Reports; } } - public static IList Formatters { get; set; } + public static IList Formatters { get; set; } - public static void Is(IConvention convention, TDataSource data) - where TDataSource : IConventionData + static string AssemblyDirectory { - Is(convention, data, new ConventionResultExceptionReporter()); + 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, IConventionReportRenderer reporter) + public static void Is(IConvention convention, TDataSource data, + params IResultsProcessor[] extraResultProcessors) where TDataSource : IConventionData { - try + var processors = new List(extraResultProcessors) { - var context = new ConventionContext(data.Description, Formatters); - var conventionResult = context.GetConventionResults(convention, data); - Reports.AddRange(conventionResult); - - new ConventionReportTraceRenderer().Render(conventionResult); - reporter.Render(conventionResult); - } - finally - { - HtmlRenderer.Render(Reports.ToArray()); - } + new ConventionReportTextRenderer(), + HtmlRenderer, + new ConventionReportTraceRenderer(), + new ThrowOnFailureResultsProcessor() + }; + Execute(convention, data, processors.ToArray()); } - public static void IsWithApprovedExeptions(IConvention convention, TDataSource data) + static void Execute(IConvention convention, TDataSource data, + IResultsProcessor[] processors) where TDataSource : IConventionData { - var context = new ConventionContext(data.Description, Formatters); - var conventionResult = context.GetConventionResultsWithApprovedExeptions(convention, data); - Reports.AddRange(conventionResult); - - try - { - var conventionReportTextRenderer = new ConventionReportTextRenderer(); - conventionReportTextRenderer.Render(conventionResult); - Approvals.Verify(conventionReportTextRenderer.Output); - - new ConventionReportTraceRenderer().Render(conventionResult); - } - catch (ApprovalException ex) - { - throw new ConventionFailedException("Approved exceptions for convention differs\r\n\r\n"+ex.Message, ex); - } - finally - { - HtmlRenderer.Render(Reports.ToArray()); - } + var context = new ConventionContext(data.Description, Formatters, processors); + context.Execute(convention, data); } - // http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917 - static string AssemblyDirectory + public static void IsWithApprovedExeptions(IConvention convention, TDataSource data, + params IResultsProcessor[] extraResultProcessors) + where TDataSource : IConventionData { - get + var processors = new List(extraResultProcessors) { - string codeBase = Assembly.GetExecutingAssembly().CodeBase; - var uri = new UriBuilder(codeBase); - string path = Uri.UnescapeDataString(uri.Path); - return Path.GetDirectoryName(path); - } + new ConventionReportTextRenderer(), + HtmlRenderer, + new ConventionReportTraceRenderer(), + new ApproveResultsProcessor() + }; + Execute(convention, data, processors.ToArray()); } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index 028daec..2fdba19 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -6,15 +6,18 @@ using TestStack.ConventionTests.Conventions; using TestStack.ConventionTests.Reporting; - public class ConventionContext : IConventionResultContext + public class ConventionContext : IConventionResultContext, IConventionFormatContext { readonly string dataDescription; readonly IList formatters; + readonly IList processors; readonly IList results = new List(); - public ConventionContext(string dataDescription, IList formatters) + public ConventionContext(string dataDescription, IList formatters, + IList processors) { this.formatters = formatters; + this.processors = processors; this.dataDescription = dataDescription; } @@ -23,14 +26,27 @@ public ConventionResult[] ConventionResults get { return results.ToArray(); } } - void IConventionResultContext.Is(string resultTitle, IEnumerable failingData) + ConventionReportFailure IConventionFormatContext.FormatData(object failingData) + { + var formatter = formatters.FirstOrDefault(f => f.CanFormat(failingData)); + if (formatter == null) + { + throw new NoDataFormatterFoundException( + failingData.GetType().Name + + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); + } + + return formatter.Format(failingData); + } + + void IConventionResultContext.Is(string resultTitle, IEnumerable failingData) { // ReSharper disable PossibleMultipleEnumeration results.Add(new ConventionResult( - failingData.None() ? TestResult.Passed : TestResult.Failed, + typeof(TResult), resultTitle, dataDescription, - failingData.Select(FormatData).ToArray())); + failingData.ToObjectArray())); } void IConventionResultContext.IsSymmetric( @@ -38,15 +54,13 @@ void IConventionResultContext.IsSymmetric( string secondSetFailureTitle, IEnumerable secondSetFailureData) { results.Add(new ConventionResult( - firstSetFailureData.None() ? TestResult.Passed : TestResult.Failed, - firstSetFailureTitle, + typeof(TResult), firstSetFailureTitle, dataDescription, - firstSetFailureData.Select(FormatData).ToArray())); + firstSetFailureData.ToObjectArray())); results.Add(new ConventionResult( - secondSetFailureData.None() ? TestResult.Passed : TestResult.Failed, - secondSetFailureTitle, + typeof(TResult), secondSetFailureTitle, dataDescription, - secondSetFailureData.Select(FormatData).ToArray())); + secondSetFailureData.ToObjectArray())); } void IConventionResultContext.IsSymmetric( @@ -64,48 +78,17 @@ void IConventionResultContext.IsSymmetric( secondSetFailureTitle, secondSetFailingData); } - ConventionReportFailure FormatData(T failingData) - { - var formatter = formatters.FirstOrDefault(f => f.CanFormat(failingData)); - if (formatter == null) - { - throw new NoDataFormatterFoundException( - typeof (T).Name + - " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`"); - } - - return formatter.Format(failingData); - } - - public ConventionResult[] GetConventionResults(IConvention convention, - TDataSource data) + public void Execute(IConvention convention, TDataSource data) where TDataSource : IConventionData { if (!data.HasData) throw new ConventionSourceInvalidException(String.Format("{0} has no data", data.Description)); - convention.Execute(data, this); - return ConventionResults; - } - - public ConventionResult[] GetConventionResultsWithApprovedExeptions( - IConvention convention, TDataSource data) - where TDataSource : IConventionData - { - var conventionReportTextRenderer = new ConventionReportTextRenderer(); - // Add approved exceptions to report - if (!data.HasData) - throw new ConventionSourceInvalidException(String.Format("{0} has no data", data.Description)); - - convention.Execute(data, this); - foreach (var conventionResult in ConventionResults) + foreach (var resultsProcessor in processors) { - conventionReportTextRenderer.RenderItems(conventionResult); - conventionResult.WithApprovedException(conventionReportTextRenderer.Output); + resultsProcessor.Process(this, ConventionResults); } - - return ConventionResults; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index a9fc654..91c635e 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -1,28 +1,35 @@ -namespace TestStack.ConventionTests.Internal -{ - using TestStack.ConventionTests.Reporting; - - public class ConventionResult - { - public TestResult Result { get; private set; } - public string ConventionTitle { get; private set; } - public string DataDescription { get; private set; } - public ConventionReportFailure[] ConventionFailures { get; private set; } - public string ApprovedException { get; private set; } - - public ConventionResult(TestResult result, string conventionTitle, string dataDescription, ConventionReportFailure[] conventionFailures) - { - Result = result; - ConventionTitle = conventionTitle; - DataDescription = dataDescription; - ConventionFailures = conventionFailures; - } - - public void WithApprovedException(string output) - { - ApprovedException = output; - Result = TestResult.Passed; - ConventionFailures = new ConventionReportFailure[0]; - } - } +namespace TestStack.ConventionTests.Internal +{ + using System; + using System.Linq; + + public class ConventionResult + { + public ConventionResult(Type dataType, string conventionTitle, string dataDescription, object[] data) + { + DataType = dataType; + ConventionTitle = conventionTitle; + DataDescription = dataDescription; + 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; } + public object[] Data { get; private set; } + + 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; + } + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ConventionTestsApprovalTextWriter.cs b/TestStack.ConventionTests/Internal/ConventionTestsApprovalTextWriter.cs new file mode 100644 index 0000000..d2aa7be --- /dev/null +++ b/TestStack.ConventionTests/Internal/ConventionTestsApprovalTextWriter.cs @@ -0,0 +1,35 @@ +namespace TestStack.ConventionTests.Internal +{ + using ApprovalTests; + using ApprovalTests.Core; + + public class ConventionTestsApprovalTextWriter : ApprovalTextWriter, IApprovalWriter + { + readonly int count; + + + public ConventionTestsApprovalTextWriter(string formattedResult, int count, string extensionWithoutDot) + : base(formattedResult, extensionWithoutDot) + { + this.count = count; + } + + string IApprovalWriter.GetApprovalFilename(string basename) + { + if (count == 0) + { + return GetApprovalFilename(basename); + } + return GetApprovalFilename(basename + count); + } + + string IApprovalWriter.GetReceivedFilename(string basename) + { + if (count == 0) + { + return GetReceivedFilename(basename); + } + return GetReceivedFilename(basename + count); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/IConventionFormatContext.cs b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs new file mode 100644 index 0000000..e3d024d --- /dev/null +++ b/TestStack.ConventionTests/Internal/IConventionFormatContext.cs @@ -0,0 +1,7 @@ +namespace TestStack.ConventionTests.Internal +{ + public interface IConventionFormatContext + { + ConventionReportFailure FormatData(object failingData); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/LinqExtensions.cs b/TestStack.ConventionTests/Internal/LinqExtensions.cs index b2f7ee6..cb8ad12 100644 --- a/TestStack.ConventionTests/Internal/LinqExtensions.cs +++ b/TestStack.ConventionTests/Internal/LinqExtensions.cs @@ -16,10 +16,14 @@ public static bool None(this IEnumerable enumerable, Func predica return !enumerable.Any(predicate); } - public static IEnumerable Unless(this IEnumerable enumerable, Func predicate) { return enumerable.Where(i => predicate(i) == false); } + + public static object[] ToObjectArray(this IEnumerable enumerable) + { + return enumerable.Select(x => (object) x).ToArray(); + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ApproveResultsProcessor.cs b/TestStack.ConventionTests/Reporting/ApproveResultsProcessor.cs new file mode 100644 index 0000000..43d53e8 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/ApproveResultsProcessor.cs @@ -0,0 +1,47 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System; + using System.Collections.Generic; + using System.Linq; + using ApprovalTests; + using ApprovalTests.Core.Exceptions; + using TestStack.ConventionTests.Internal; + + public class ApproveResultsProcessor : IResultsProcessor + { + public void Process(IConventionFormatContext context, params ConventionResult[] results) + { + var failedApprovals = new List(); + for (var count = 0; count < results.Length; count++) + { + var result = results[count]; + try + { + Approvals.Verify(new ConventionTestsApprovalTextWriter(result.FormattedResult, count,result.RecommendedFileExtension)); + } + catch (ApprovalException ex) + { + failedApprovals.Add(ex); + } + } + if (failedApprovals.Count == 0) + { + return; + } + if (failedApprovals.Count == 1) + { + var ex = failedApprovals[0]; + throw new ConventionFailedException("Approved exceptions for convention differs" + + Environment.NewLine + + Environment.NewLine + + ex.Message, ex); + } + throw new ConventionFailedException("Approved exceptions for convention differs" + + Environment.NewLine + + Environment.NewLine + + string.Join(Environment.NewLine, + failedApprovals.Select(x => x.Message)), + new AggregateException(failedApprovals.ToArray())); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs index dc7f72e..89197aa 100644 --- a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs @@ -3,50 +3,34 @@ using System.Text; using TestStack.ConventionTests.Internal; - public class ConventionReportTextRenderer : IConventionReportRenderer + public class ConventionReportTextRenderer : IResultsProcessor { - public void Render(params ConventionResult[] conventionResult) + public void Process(IConventionFormatContext context, params ConventionResult[] results) { - var stringBuilder = new StringBuilder(); - - foreach (var conventionReport in conventionResult) + foreach (var result in results) { - var title = string.Format("{0}: '{1}' for '{2}'", conventionReport.Result, conventionReport.ConventionTitle, - conventionReport.DataDescription); - stringBuilder.AppendLine(title); - stringBuilder.AppendLine(string.Empty.PadRight(title.Length, '-')); - stringBuilder.AppendLine(); - - if (!string.IsNullOrEmpty(conventionReport.ApprovedException)) + if (result.FormattedResult != null) { - stringBuilder.AppendLine("With approved exceptions:"); - stringBuilder.AppendLine(conventionReport.ApprovedException); - stringBuilder.AppendLine(); + continue; } - - RenderItems(conventionReport, stringBuilder); - stringBuilder.AppendLine(); - stringBuilder.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()); } - - Output = stringBuilder.ToString().TrimEnd(); - } - - public string Output { get; private set; } - - public void RenderItems(ConventionResult conventionResult) - { - var stringBuilder = new StringBuilder(); - RenderItems(conventionResult, stringBuilder); - Output = stringBuilder.ToString(); } - static void RenderItems(ConventionResult resultInfo, StringBuilder stringBuilder) + static void RenderItems(ConventionResult resultInfo, StringBuilder stringBuilder, IConventionFormatContext context) { - foreach (var conventionFailure in resultInfo.ConventionFailures) + foreach (var conventionFailure in resultInfo.Data) { stringBuilder.Append("\t"); - stringBuilder.AppendLine(conventionFailure.ToString()); + stringBuilder.AppendLine(context.FormatData(conventionFailure).ToString()); } } } diff --git a/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs index d283562..4d5b2fa 100644 --- a/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs @@ -3,13 +3,14 @@ using System.Diagnostics; using TestStack.ConventionTests.Internal; - public class ConventionReportTraceRenderer : IConventionReportRenderer + public class ConventionReportTraceRenderer : IResultsProcessor { - public void Render(params ConventionResult[] conventionResult) + public void Process(IConventionFormatContext context, params ConventionResult[] results) { - var conventionReportTextRenderer = new ConventionReportTextRenderer(); - conventionReportTextRenderer.Render(conventionResult); - Trace.WriteLine(conventionReportTextRenderer.Output); + foreach (var conventionResult in results) + { + Trace.WriteLine(conventionResult.FormattedResult); + } } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs b/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs deleted file mode 100644 index e2d788b..0000000 --- a/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace TestStack.ConventionTests.Reporting -{ - using System.Linq; - using TestStack.ConventionTests.Internal; - - public class ConventionResultExceptionReporter : IConventionReportRenderer - { - public void Render(params ConventionResult[] conventionResult) - { - var conventionReportTextRenderer = new ConventionReportTextRenderer(); - conventionReportTextRenderer.Render(conventionResult); - if (conventionResult.Any(r => r.Result == TestResult.Failed)) - { - throw new ConventionFailedException(conventionReportTextRenderer.Output); - } - } - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs b/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs new file mode 100644 index 0000000..94a71a2 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/ConvertibleFormatter.cs @@ -0,0 +1,22 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System; + using System.Diagnostics; + using System.Globalization; + using TestStack.ConventionTests.Internal; + + public class ConvertibleFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return failingData is IConvertible; + } + + public ConventionReportFailure Format(object failingData) + { + var convertible = failingData as IConvertible; + Debug.Assert(convertible != null, "convertible != null"); + return new ConventionReportFailure(convertible.ToString(CultureInfo.InvariantCulture)); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/CsvReporter.cs b/TestStack.ConventionTests/Reporting/CsvReporter.cs index a8f57d7..7dc529e 100644 --- a/TestStack.ConventionTests/Reporting/CsvReporter.cs +++ b/TestStack.ConventionTests/Reporting/CsvReporter.cs @@ -1,17 +1,26 @@ namespace TestStack.ConventionTests.Reporting { - using System.Collections; using System.Text; + using TestStack.ConventionTests.Internal; - public class CsvReporter + public class CsvReporter : IResultsProcessor { - public string Build(IEnumerable results, string header, DefaultFormatter formatter) + 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) + { + var formatter = new DefaultFormatter(result.DataType); var message = new StringBuilder(); message.AppendLine(string.Join(",", formatter.DesribeType())); - foreach (var result in results) + foreach (var item in result.Data) { - message.AppendLine(string.Join(",", formatter.DesribeItem(result))); + message.AppendLine(string.Join(",", formatter.DesribeItem(item, context))); } return message.ToString(); } diff --git a/TestStack.ConventionTests/Reporting/DefaultFormatter.cs b/TestStack.ConventionTests/Reporting/DefaultFormatter.cs index eaf7fb7..f5ea878 100644 --- a/TestStack.ConventionTests/Reporting/DefaultFormatter.cs +++ b/TestStack.ConventionTests/Reporting/DefaultFormatter.cs @@ -3,15 +3,14 @@ using System; using System.Linq; using System.Reflection; + using TestStack.ConventionTests.Internal; public class DefaultFormatter { readonly PropertyInfo[] properties; - readonly Type type; public DefaultFormatter(Type type) { - this.type = type; properties = type.GetProperties(); } @@ -26,9 +25,9 @@ string Describe(PropertyInfo property) return property.Name.Replace('_', ' '); } - public string[] DesribeItem(object result) + public string[] DesribeItem(object result, IConventionFormatContext context) { - return properties.Select(p => p.GetValue(result, null).ToString()).ToArray(); + return properties.Select(p => context.FormatData(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 new file mode 100644 index 0000000..a7b89e5 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/FallbackFormatter.cs @@ -0,0 +1,18 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.Internal; + + public class FallbackFormatter : IReportDataFormatter + { + public bool CanFormat(object failingData) + { + return true; + } + + public ConventionReportFailure Format(object failingData) + { + // TODO: for now + return new ConventionReportFailure(failingData.ToString()); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs index 79ae3b9..23dbaca 100644 --- a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs @@ -1,21 +1,26 @@ namespace TestStack.ConventionTests.Reporting { + using System; + using System.Collections.Generic; using System.IO; using System.Text; using System.Web.UI; using TestStack.ConventionTests.Internal; - public class HtmlReportRenderer : IConventionReportRenderer + public class HtmlReportRenderer : IResultsProcessor { 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 Render(params ConventionResult[] conventionResult) + public void Process(IConventionFormatContext context, params ConventionResult[] results) { + Reports.AddRange(results); var sb = new StringBuilder(); var html = new HtmlTextWriter(new StringWriter(sb)); html.WriteLine(""); @@ -29,37 +34,22 @@ public void Render(params ConventionResult[] conventionResult) html.Write("Project Conventions"); html.RenderEndTag(); - foreach (var conventionReport in conventionResult) + foreach (var conventionReport in Reports) { html.RenderBeginTag(HtmlTextWriterTag.P); html.RenderBeginTag(HtmlTextWriterTag.Div); html.RenderBeginTag(HtmlTextWriterTag.Strong); - html.Write(conventionReport.Result+": "); html.RenderEndTag(); - var title = string.Format("{0} for {1}", conventionReport.ConventionTitle, conventionReport.DataDescription); + var title = String.Format("{0} for {1}", conventionReport.ConventionTitle, conventionReport.DataDescription); html.Write(title); - if (!string.IsNullOrEmpty(conventionReport.ApprovedException)) - { - html.RenderBeginTag(HtmlTextWriterTag.Div); - html.RenderBeginTag(HtmlTextWriterTag.Strong); - html.WriteLine("With approved exceptions:"); - html.RenderEndTag(); - html.RenderEndTag(); - } html.RenderBeginTag(HtmlTextWriterTag.Ul); - if (!string.IsNullOrEmpty(conventionReport.ApprovedException)) - { - html.RenderBeginTag(HtmlTextWriterTag.Li); - html.WriteLine(conventionReport.ApprovedException); - html.RenderEndTag(); - } - foreach (var conventionFailure in conventionReport.ConventionFailures) + foreach (var conventionFailure in conventionReport.Data) { html.RenderBeginTag(HtmlTextWriterTag.Li); - html.Write(conventionFailure.ToString()); + html.Write(context.FormatData(conventionFailure).ToString()); html.RenderEndTag(); } diff --git a/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs b/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs deleted file mode 100644 index c472036..0000000 --- a/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TestStack.ConventionTests.Reporting -{ - using TestStack.ConventionTests.Internal; - - public interface IConventionReportRenderer - { - void Render(params ConventionResult[] conventionResult); - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/IResultsProcessor.cs b/TestStack.ConventionTests/Reporting/IResultsProcessor.cs new file mode 100644 index 0000000..ab73623 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/IResultsProcessor.cs @@ -0,0 +1,9 @@ +namespace TestStack.ConventionTests.Reporting +{ + using TestStack.ConventionTests.Internal; + + public interface IResultsProcessor + { + void Process(IConventionFormatContext context, params ConventionResult[] results); + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs index 7bdd5a1..12de3e3 100644 --- a/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs +++ b/TestStack.ConventionTests/Reporting/MethodInfoDataFormatter.cs @@ -1,8 +1,10 @@ namespace TestStack.ConventionTests.Reporting -{ - using System.Reflection; - using TestStack.ConventionTests.Internal; - +{ + using System.ComponentModel; + using System.Reflection; + using ApprovalTests.Namers; + using TestStack.ConventionTests.Internal; + public class MethodInfoDataFormatter : IReportDataFormatter { public bool CanFormat(object failingData) diff --git a/TestStack.ConventionTests/Reporting/ThrowOnFailureResultsProcessor.cs b/TestStack.ConventionTests/Reporting/ThrowOnFailureResultsProcessor.cs new file mode 100644 index 0000000..f8d565a --- /dev/null +++ b/TestStack.ConventionTests/Reporting/ThrowOnFailureResultsProcessor.cs @@ -0,0 +1,19 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System; + using System.Linq; + using TestStack.ConventionTests.Internal; + + public class ThrowOnFailureResultsProcessor : IResultsProcessor + { + public void Process(IConventionFormatContext context, params ConventionResult[] results) + { + var invalidResults = results.Where(r => r.HasData).Select(r => r.FormattedResult).ToArray(); + if (invalidResults.None()) + { + return; + } + throw new ConventionFailedException(string.Join(Environment.NewLine, invalidResults)); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 460f584..24ea926 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -63,13 +63,18 @@ + + + + + - + @@ -80,7 +85,7 @@ - +