From 75d5efdb03d82c5dfeef2ebcfc0daa0155bc1674 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 11:21:39 +1000 Subject: [PATCH 1/9] brought back the test for CSV report --- TestAssembly/Collections/Branch.cs | 20 +++++++++ TestAssembly/Collections/Forest.cs | 30 +++++++++++++ TestAssembly/Collections/ICanAdd.cs | 9 ++++ TestAssembly/Collections/ICanRemove.cs | 9 ++++ TestAssembly/Collections/Leaf.cs | 6 +++ TestAssembly/Collections/Tree.cs | 31 ++++++++++++++ TestAssembly/TestAssembly.csproj | 6 +++ ...nvention_with_simple_reporter.approved.txt | 5 +++ .../CsvReportTests.cs | 24 +++++++++++ .../CollectionsRelationsConvention.cs | 42 +++++++++++++++++++ .../TestStack.ConventionTests.Tests.csproj | 2 + .../TypeBasedConventions.cs | 7 +++- .../Internal/Executor.cs | 1 - 13 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 TestAssembly/Collections/Branch.cs create mode 100644 TestAssembly/Collections/Forest.cs create mode 100644 TestAssembly/Collections/ICanAdd.cs create mode 100644 TestAssembly/Collections/ICanRemove.cs create mode 100644 TestAssembly/Collections/Leaf.cs create mode 100644 TestAssembly/Collections/Tree.cs create mode 100644 TestStack.ConventionTests.Tests/CsvReportTests.Can_run_convention_with_simple_reporter.approved.txt create mode 100644 TestStack.ConventionTests.Tests/CsvReportTests.cs create mode 100644 TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs diff --git a/TestAssembly/Collections/Branch.cs b/TestAssembly/Collections/Branch.cs new file mode 100644 index 0000000..0530072 --- /dev/null +++ b/TestAssembly/Collections/Branch.cs @@ -0,0 +1,20 @@ +namespace TestAssembly.Collections +{ + using System.Collections; + using System.Collections.Generic; + + public class Branch : IEnumerable + { + readonly List items = new List(); + + public IEnumerator GetEnumerator() + { + return items.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/TestAssembly/Collections/Forest.cs b/TestAssembly/Collections/Forest.cs new file mode 100644 index 0000000..cff3c49 --- /dev/null +++ b/TestAssembly/Collections/Forest.cs @@ -0,0 +1,30 @@ +namespace TestAssembly.Collections +{ + using System.Collections; + using System.Collections.Generic; + + public class Forest : ICanAdd, ICanRemove + { + readonly List items = new List(); + + public void Add(Tree item) + { + items.Add(item); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable) items).GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return items.GetEnumerator(); + } + + public bool Remove(Tree item) + { + return items.Remove(item); + } + } +} \ No newline at end of file diff --git a/TestAssembly/Collections/ICanAdd.cs b/TestAssembly/Collections/ICanAdd.cs new file mode 100644 index 0000000..1115878 --- /dev/null +++ b/TestAssembly/Collections/ICanAdd.cs @@ -0,0 +1,9 @@ +namespace TestAssembly.Collections +{ + using System.Collections.Generic; + + public interface ICanAdd : IEnumerable + { + void Add(T item); + } +} \ No newline at end of file diff --git a/TestAssembly/Collections/ICanRemove.cs b/TestAssembly/Collections/ICanRemove.cs new file mode 100644 index 0000000..23cd643 --- /dev/null +++ b/TestAssembly/Collections/ICanRemove.cs @@ -0,0 +1,9 @@ +namespace TestAssembly.Collections +{ + using System.Collections.Generic; + + public interface ICanRemove : IEnumerable + { + bool Remove(T item); + } +} \ No newline at end of file diff --git a/TestAssembly/Collections/Leaf.cs b/TestAssembly/Collections/Leaf.cs new file mode 100644 index 0000000..42dfd08 --- /dev/null +++ b/TestAssembly/Collections/Leaf.cs @@ -0,0 +1,6 @@ +namespace TestAssembly.Collections +{ + public class Leaf + { + } +} \ No newline at end of file diff --git a/TestAssembly/Collections/Tree.cs b/TestAssembly/Collections/Tree.cs new file mode 100644 index 0000000..e8da998 --- /dev/null +++ b/TestAssembly/Collections/Tree.cs @@ -0,0 +1,31 @@ +namespace TestAssembly.Collections +{ + using System.Collections; + using System.Collections.Generic; + using System.Linq; + + public class Tree : ICanAdd, IEnumerable + { + readonly List items = new List(); + + public void Add(Branch item) + { + items.Add(item); + } + + public IEnumerator GetEnumerator() + { + return items.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return items.SelectMany(i => i).GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/TestAssembly/TestAssembly.csproj b/TestAssembly/TestAssembly.csproj index 253435e..7be1ca1 100644 --- a/TestAssembly/TestAssembly.csproj +++ b/TestAssembly/TestAssembly.csproj @@ -44,6 +44,12 @@ + + + + + + diff --git a/TestStack.ConventionTests.Tests/CsvReportTests.Can_run_convention_with_simple_reporter.approved.txt b/TestStack.ConventionTests.Tests/CsvReportTests.Can_run_convention_with_simple_reporter.approved.txt new file mode 100644 index 0000000..07a98d3 --- /dev/null +++ b/TestStack.ConventionTests.Tests/CsvReportTests.Can_run_convention_with_simple_reporter.approved.txt @@ -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 new file mode 100644 index 0000000..f9d98c3 --- /dev/null +++ b/TestStack.ConventionTests.Tests/CsvReportTests.cs @@ -0,0 +1,24 @@ +namespace TestStack.ConventionTests.Tests +{ + using System.Linq; + using ApprovalTests.Reporters; + using NUnit.Framework; + using TestAssembly.Collections; + using TestStack.ConventionTests.ConventionData; + using TestStack.ConventionTests.Tests.TestConventions; + + [UseReporter(typeof(DiffReporter))] + public class CsvReportTests + { + [Test] + public void Can_run_convention_with_simple_reporter() + { + Convention.IsWithApprovedExeptions(new CollectionsRelationsConvention(), new Types("Entities") + { + TypesToVerify = + typeof (Leaf).Assembly.GetExportedTypes() + .Where(t => t.Namespace == typeof (Leaf).Namespace).ToArray() + }); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs b/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs new file mode 100644 index 0000000..1e34afa --- /dev/null +++ b/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs @@ -0,0 +1,42 @@ +namespace TestStack.ConventionTests.Tests.TestConventions +{ + using System; + using System.Collections.Generic; + using System.Linq; + using TestAssembly.Collections; + using TestStack.ConventionTests.ConventionData; + + public class CollectionsRelationsConvention : IConvention + { + public string ConventionTitle { get; private set; } + + public void Execute(Types data, IConventionResult result) + { + ConventionTitle = "well, does the header apply here all across the board? How would that work for CSV?"; + var types = data.TypesToVerify; + var collectionToItemLookup = from collection in types + where collection.IsClass + orderby collection.FullName + from item in GetItemTypes(collection) + select new + { + collection, + item, + can_add = typeof (ICanAdd<>).MakeGenericType(item).IsAssignableFrom(collection), + can_remove = typeof (ICanRemove<>).MakeGenericType(item).IsAssignableFrom(collection) + }; + + result.Is("Some title", collectionToItemLookup); + } + + IEnumerable GetItemTypes(Type type) + { + return from @interface in type.GetInterfaces() + where @interface.IsGenericType + where @interface.GetGenericTypeDefinition() == typeof (IEnumerable<>) + let item = @interface.GetGenericArguments().Single() + orderby item.FullName + select item; + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/TestStack.ConventionTests.Tests.csproj b/TestStack.ConventionTests.Tests/TestStack.ConventionTests.Tests.csproj index 5736818..43afb54 100644 --- a/TestStack.ConventionTests.Tests/TestStack.ConventionTests.Tests.csproj +++ b/TestStack.ConventionTests.Tests/TestStack.ConventionTests.Tests.csproj @@ -52,6 +52,7 @@ + @@ -59,6 +60,7 @@ True Resources.resx + diff --git a/TestStack.ConventionTests.Tests/TypeBasedConventions.cs b/TestStack.ConventionTests.Tests/TypeBasedConventions.cs index 5f3c2d4..27d0aa5 100644 --- a/TestStack.ConventionTests.Tests/TypeBasedConventions.cs +++ b/TestStack.ConventionTests.Tests/TypeBasedConventions.cs @@ -1,5 +1,6 @@ namespace TestStack.ConventionTests.Tests { + using System.Linq; using ApprovalTests; using ApprovalTests.Reporters; using NUnit.Framework; @@ -16,7 +17,9 @@ public class TypeBasedConventions public TypeBasedConventions() { - var itemsToVerify = typeof (SampleDomainClass).Assembly.GetTypes(); + var itemsToVerify = typeof (SampleDomainClass).Assembly.GetTypes() + .Where(t => t.IsClass && t.Namespace == typeof (SampleDomainClass).Namespace) + .ToArray(); nhibernateEntities = new Types("nHibernate Entitites") { TypesToVerify = itemsToVerify @@ -76,4 +79,4 @@ public void dtos_exists_in_dto_namespace_wth_approved_exceptions() Convention.IsWithApprovedExeptions(convention, types); } } -} \ No newline at end of file +} diff --git a/TestStack.ConventionTests/Internal/Executor.cs b/TestStack.ConventionTests/Internal/Executor.cs index a39c3cf..e665800 100644 --- a/TestStack.ConventionTests/Internal/Executor.cs +++ b/TestStack.ConventionTests/Internal/Executor.cs @@ -1,6 +1,5 @@ namespace TestStack.ConventionTests.Internal { - using System; using TestStack.ConventionTests.Conventions; using TestStack.ConventionTests.Reporting; From 603f628ce531942b82adf6a36a3d00cb1787f445 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 11:25:25 +1000 Subject: [PATCH 2/9] brought back the original reporter/formatter for CSV --- .../Reporting/CsvReporter.cs | 19 +++++++++++ .../Reporting/DefaultFormatter.cs | 34 +++++++++++++++++++ .../TestStack.ConventionTests.csproj | 2 ++ 3 files changed, 55 insertions(+) create mode 100644 TestStack.ConventionTests/Reporting/CsvReporter.cs create mode 100644 TestStack.ConventionTests/Reporting/DefaultFormatter.cs diff --git a/TestStack.ConventionTests/Reporting/CsvReporter.cs b/TestStack.ConventionTests/Reporting/CsvReporter.cs new file mode 100644 index 0000000..a8f57d7 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/CsvReporter.cs @@ -0,0 +1,19 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System.Collections; + using System.Text; + + public class CsvReporter + { + public string Build(IEnumerable results, string header, DefaultFormatter formatter) + { + var message = new StringBuilder(); + message.AppendLine(string.Join(",", formatter.DesribeType())); + foreach (var result in results) + { + message.AppendLine(string.Join(",", formatter.DesribeItem(result))); + } + return message.ToString(); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/Reporting/DefaultFormatter.cs b/TestStack.ConventionTests/Reporting/DefaultFormatter.cs new file mode 100644 index 0000000..eaf7fb7 --- /dev/null +++ b/TestStack.ConventionTests/Reporting/DefaultFormatter.cs @@ -0,0 +1,34 @@ +namespace TestStack.ConventionTests.Reporting +{ + using System; + using System.Linq; + using System.Reflection; + + public class DefaultFormatter + { + readonly PropertyInfo[] properties; + readonly Type type; + + public DefaultFormatter(Type type) + { + this.type = type; + properties = type.GetProperties(); + } + + // TODO: this is a very crappy name for a method + public string[] DesribeType() + { + return properties.Select(Describe).ToArray(); + } + + string Describe(PropertyInfo property) + { + return property.Name.Replace('_', ' '); + } + + public string[] DesribeItem(object result) + { + return properties.Select(p => p.GetValue(result, null).ToString()).ToArray(); + } + } +} \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 3e8b083..0e061c4 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -67,6 +67,8 @@ + + From cee195347ca91c458f87bb09596cbba618952a67 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 11:32:16 +1000 Subject: [PATCH 3/9] unified parameters in symmetric convention method --- TestStack.ConventionTests/IConventionResult.cs | 12 ++++++------ .../Internal/ConventionResult.cs | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/TestStack.ConventionTests/IConventionResult.cs b/TestStack.ConventionTests/IConventionResult.cs index 9442528..7cd0033 100644 --- a/TestStack.ConventionTests/IConventionResult.cs +++ b/TestStack.ConventionTests/IConventionResult.cs @@ -14,13 +14,13 @@ public interface IConventionResult /// and if a non-dto is in Project.Dto the test will also fail /// /// The data type the convention is applied to - /// Title of the convention, i.e Dto's must live in Project.Dto namespace - /// Data failing to conform to the convention - /// The inverse scenario title, i.e Non-dtos must not live inside Project.Dto namespace - /// Data failing to conform to the inverse of the convention + /// Title of the convention, i.e Dto's must live in Project.Dto namespace + /// Data failing to conform to the convention + /// The inverse scenario title, i.e Non-dtos must not live inside Project.Dto namespace + /// Data failing to conform to the inverse of the convention void IsSymmetric( - string conventionResultTitle, IEnumerable conventionFailingData, - string inverseResultTitle, IEnumerable inverseFailingData); + string firstSetFailureTitle, IEnumerable firstSetFailureData, + string secondSetFailureTitle, IEnumerable secondSetFailureData); /// /// A symmetric convention is a convention which also can be applied in reverse. For example diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index 53d1112..fd2c6ba 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -32,19 +32,19 @@ public void Is(string resultTitle, IEnumerable failingData) } public void IsSymmetric( - string conventionResultTitle, IEnumerable conventionFailingData, - string inverseResultTitle, IEnumerable inverseFailingData) + string firstSetFailureTitle, IEnumerable firstSetFailureData, + string secondSetFailureTitle, IEnumerable secondSetFailureData) { conventionResults.Add(new ResultInfo( - conventionFailingData.None() ? TestResult.Passed : TestResult.Failed, - conventionResultTitle, + firstSetFailureData.None() ? TestResult.Passed : TestResult.Failed, + firstSetFailureTitle, dataDescription, - conventionFailingData.Select(FormatData).ToArray())); + firstSetFailureData.Select(FormatData).ToArray())); conventionResults.Add(new ResultInfo( - inverseFailingData.None() ? TestResult.Passed : TestResult.Failed, - inverseResultTitle, + secondSetFailureData.None() ? TestResult.Passed : TestResult.Failed, + secondSetFailureTitle, dataDescription, - inverseFailingData.Select(FormatData).ToArray())); + secondSetFailureData.Select(FormatData).ToArray())); } public void IsSymmetric( From abebf0ece7dc99049ca57af338fde52c77f69ff9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 11:41:12 +1000 Subject: [PATCH 4/9] added .Unless extension method some refactoring to make the code a bit more readable --- TestStack.ConventionTests/Internal/ConventionResult.cs | 4 ++-- TestStack.ConventionTests/Internal/LinqExtensions.cs | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index fd2c6ba..21d29f1 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -54,8 +54,8 @@ public void IsSymmetric( Func isPartOfSecondSet, IEnumerable allData) { - var firstSetFailingData = allData.Where(isPartOfFirstSet).Where(d => !isPartOfSecondSet(d)); - var secondSetFailingData = allData.Where(d => !isPartOfFirstSet(d)).Where(isPartOfSecondSet); + var firstSetFailingData = allData.Where(isPartOfFirstSet).Unless(isPartOfSecondSet); + var secondSetFailingData = allData.Where(isPartOfSecondSet).Unless(isPartOfFirstSet); IsSymmetric( firstSetFailureTitle, firstSetFailingData, diff --git a/TestStack.ConventionTests/Internal/LinqExtensions.cs b/TestStack.ConventionTests/Internal/LinqExtensions.cs index 920e4e5..b2f7ee6 100644 --- a/TestStack.ConventionTests/Internal/LinqExtensions.cs +++ b/TestStack.ConventionTests/Internal/LinqExtensions.cs @@ -1,6 +1,4 @@ -// ReSharper disable once CheckNamespace - -namespace TestStack.ConventionTests.Internal +namespace TestStack.ConventionTests.Internal { using System; using System.Collections.Generic; @@ -17,5 +15,11 @@ 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); + } } } \ No newline at end of file From faaa40f09e73238fc214b95f13287c37e9a0fac7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 15:23:43 +1000 Subject: [PATCH 5/9] starting to refactor formatters. step one - removing static dependency --- TestStack.ConventionTests/Internal/ConventionResult.cs | 9 +++++---- TestStack.ConventionTests/Internal/Executor.cs | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index 21d29f1..b622c33 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -9,9 +9,11 @@ public class ConventionResult : IConventionResult { readonly List conventionResults; readonly string dataDescription; + readonly IList formatters; - public ConventionResult(string dataDescription) + public ConventionResult(string dataDescription, IList formatters) { + this.formatters = formatters; this.dataDescription = dataDescription; conventionResults = new List(); } @@ -62,10 +64,9 @@ public void IsSymmetric( secondSetFailureTitle, secondSetFailingData); } - static ConventionReportFailure FormatData(T failingData) + ConventionReportFailure FormatData(T failingData) { - var formatter = Convention.Formatters.FirstOrDefault(f => f.CanFormat(failingData)); - + var formatter = formatters.FirstOrDefault(f => f.CanFormat(failingData)); if (formatter == null) { throw new NoDataFormatterFoundException( diff --git a/TestStack.ConventionTests/Internal/Executor.cs b/TestStack.ConventionTests/Internal/Executor.cs index e665800..4730ebb 100644 --- a/TestStack.ConventionTests/Internal/Executor.cs +++ b/TestStack.ConventionTests/Internal/Executor.cs @@ -11,7 +11,7 @@ public static ResultInfo[] GetConventionResults(IConvention Date: Wed, 14 Aug 2013 15:36:55 +1000 Subject: [PATCH 6/9] renames, renames everywhere So we're shifting the balance a bit here. ConventionResult is really becoming a conventionContext which will act as a context object gluing together all various pieces of the pipeline, isolating all the statics etc. Kind of like HttpContext or OperationContext in WCF we're changing the interface to IConventionResultContext. While it's not the best name it's the best I could come up with, without calling it factory (which it's not, since it doesn't return anything) or calling it provider which is just wrong --- .../ConventionAssertionClassTests.cs | 2 +- .../TestConventions/CollectionsRelationsConvention.cs | 2 +- .../Conventions/AllClassesHaveDefaultConstructor.cs | 2 +- TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs | 2 +- .../Conventions/ClassTypeHasSpecificNamespace.cs | 2 +- .../Conventions/FilesAreEmbeddedResources.cs | 2 +- .../ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs | 2 +- TestStack.ConventionTests/IConvention.cs | 2 +- .../{IConventionResult.cs => IConventionResultContext.cs} | 2 +- .../Internal/{ConventionResult.cs => ConventionContext.cs} | 4 ++-- TestStack.ConventionTests/Internal/Executor.cs | 4 ++-- TestStack.ConventionTests/TestStack.ConventionTests.csproj | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) rename TestStack.ConventionTests/{IConventionResult.cs => IConventionResultContext.cs} (96%) rename TestStack.ConventionTests/Internal/{ConventionResult.cs => ConventionContext.cs} (92%) diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index a72203d..8b187f1 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -33,7 +33,7 @@ public ConventionReportFailure Format(string failingData) public class FailingConvention : IConvention { - public void Execute(FakeData data, IConventionResult result) + public void Execute(FakeData data, IConventionResultContext result) { result.Is("Header", new[] {"Different"}); } diff --git a/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs b/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs index 1e34afa..cf49baf 100644 --- a/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs +++ b/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs @@ -10,7 +10,7 @@ public class CollectionsRelationsConvention : IConvention { public string ConventionTitle { get; private set; } - public void Execute(Types data, IConventionResult result) + public void Execute(Types data, IConventionResultContext result) { ConventionTitle = "well, does the header apply here all across the board? How would that work for CSV?"; var types = data.TypesToVerify; diff --git a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs index ed8647f..4de15e4 100644 --- a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs +++ b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs @@ -6,7 +6,7 @@ public class AllClassesHaveDefaultConstructor : IConvention { - public void Execute(Types data, IConventionResult result) + public void Execute(Types data, IConventionResultContext result) { result.Is("Types must have a default constructor", data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false)); diff --git a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs index b6d7d1e..70d7fd9 100644 --- a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs +++ b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs @@ -6,7 +6,7 @@ public class AllMethodsAreVirtual : IConvention { - public void Execute(Types data, IConventionResult result) + public void Execute(Types data, IConventionResultContext result) { result.Is("Methods must be virtual", data.TypesToVerify.SelectMany(t => t.NonVirtualMethods())); } diff --git a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs index 25da3af..104c013 100644 --- a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs +++ b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs @@ -31,7 +31,7 @@ public ClassTypeHasSpecificNamespace(Func classIsApplicable, string this.classType = classType; } - public void Execute(Types data, IConventionResult result) + public void Execute(Types data, IConventionResultContext result) { result.IsSymmetric( string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck), diff --git a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs index 53f83af..3d6becf 100644 --- a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs +++ b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs @@ -12,7 +12,7 @@ public FilesAreEmbeddedResources(string fileExtension) public string FileExtension { get; private set; } - public void Execute(ProjectFiles data, IConventionResult result) + public void Execute(ProjectFiles data, IConventionResultContext result) { result.Is( string.Format("{0} Files must be embedded resources", FileExtension), diff --git a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs index 29eab34..5247982 100644 --- a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs +++ b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs @@ -8,7 +8,7 @@ public class ProjectDoesNotReferenceDllsFromBinOrObjDirectories : IConvention.*?(obj|bin).*?)$"; - public void Execute(ProjectReferences data, IConventionResult result) + public void Execute(ProjectReferences data, IConventionResultContext result) { result.Is("Project must not reference dlls from bin or obj directories", data.References.Where(IsBinOrObjReference)); diff --git a/TestStack.ConventionTests/IConvention.cs b/TestStack.ConventionTests/IConvention.cs index 641dc53..2c7621e 100644 --- a/TestStack.ConventionTests/IConvention.cs +++ b/TestStack.ConventionTests/IConvention.cs @@ -2,6 +2,6 @@ { public interface IConvention where T : IConventionData { - void Execute(T data, IConventionResult result); + void Execute(T data, IConventionResultContext result); } } \ No newline at end of file diff --git a/TestStack.ConventionTests/IConventionResult.cs b/TestStack.ConventionTests/IConventionResultContext.cs similarity index 96% rename from TestStack.ConventionTests/IConventionResult.cs rename to TestStack.ConventionTests/IConventionResultContext.cs index 7cd0033..c40023e 100644 --- a/TestStack.ConventionTests/IConventionResult.cs +++ b/TestStack.ConventionTests/IConventionResultContext.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; - public interface IConventionResult + public interface IConventionResultContext { void Is(string resultTitle, IEnumerable failingData); diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs similarity index 92% rename from TestStack.ConventionTests/Internal/ConventionResult.cs rename to TestStack.ConventionTests/Internal/ConventionContext.cs index b622c33..5630258 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -5,13 +5,13 @@ using System.Linq; using TestStack.ConventionTests.Reporting; - public class ConventionResult : IConventionResult + public class ConventionContext : IConventionResultContext { readonly List conventionResults; readonly string dataDescription; readonly IList formatters; - public ConventionResult(string dataDescription, IList formatters) + public ConventionContext(string dataDescription, IList formatters) { this.formatters = formatters; this.dataDescription = dataDescription; diff --git a/TestStack.ConventionTests/Internal/Executor.cs b/TestStack.ConventionTests/Internal/Executor.cs index 4730ebb..e0453f0 100644 --- a/TestStack.ConventionTests/Internal/Executor.cs +++ b/TestStack.ConventionTests/Internal/Executor.cs @@ -11,7 +11,7 @@ public static ResultInfo[] GetConventionResults(IConvention - + - + From ceec835767fc80d5eb90f82dc6938365671758c4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 15:39:51 +1000 Subject: [PATCH 7/9] more renames. This makes more sense now IMO --- TestStack.ConventionTests/Convention.cs | 4 +- .../Internal/ConventionContext.cs | 13 +++-- .../{ResultInfo.cs => ConventionResult.cs} | 54 +++++++++---------- .../Internal/Executor.cs | 4 +- .../Reporting/ConventionReportTextRenderer.cs | 6 +-- .../ConventionReportTraceRenderer.cs | 2 +- .../ConventionResultExceptionReporter.cs | 2 +- .../Reporting/HtmlReportRenderer.cs | 2 +- .../Reporting/IConventionReportRenderer.cs | 2 +- .../TestStack.ConventionTests.csproj | 2 +- 10 files changed, 45 insertions(+), 46 deletions(-) rename TestStack.ConventionTests/Internal/{ResultInfo.cs => ConventionResult.cs} (81%) diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index f4439af..8b76b7b 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -12,7 +12,7 @@ public static class Convention { static readonly HtmlReportRenderer HtmlRenderer = new HtmlReportRenderer(AssemblyDirectory); - static readonly List Reports = new List(); + static readonly List Reports = new List(); static Convention() { @@ -26,7 +26,7 @@ static Convention() }; } - public static IEnumerable ConventionReports { get { return Reports; } } + public static IEnumerable ConventionReports { get { return Reports; } } public static IList Formatters { get; set; } public static void Is(IConvention convention, TDataSource data) diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index 5630258..2a14535 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -7,26 +7,25 @@ public class ConventionContext : IConventionResultContext { - readonly List conventionResults; readonly string dataDescription; readonly IList formatters; + readonly IList results = new List(); public ConventionContext(string dataDescription, IList formatters) { this.formatters = formatters; this.dataDescription = dataDescription; - conventionResults = new List(); } - public ResultInfo[] ConventionResults + public ConventionResult[] ConventionResults { - get { return conventionResults.ToArray(); } + get { return results.ToArray(); } } public void Is(string resultTitle, IEnumerable failingData) { // ReSharper disable PossibleMultipleEnumeration - conventionResults.Add(new ResultInfo( + results.Add(new ConventionResult( failingData.None() ? TestResult.Passed : TestResult.Failed, resultTitle, dataDescription, @@ -37,12 +36,12 @@ public void IsSymmetric( string firstSetFailureTitle, IEnumerable firstSetFailureData, string secondSetFailureTitle, IEnumerable secondSetFailureData) { - conventionResults.Add(new ResultInfo( + results.Add(new ConventionResult( firstSetFailureData.None() ? TestResult.Passed : TestResult.Failed, firstSetFailureTitle, dataDescription, firstSetFailureData.Select(FormatData).ToArray())); - conventionResults.Add(new ResultInfo( + results.Add(new ConventionResult( secondSetFailureData.None() ? TestResult.Passed : TestResult.Failed, secondSetFailureTitle, dataDescription, diff --git a/TestStack.ConventionTests/Internal/ResultInfo.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs similarity index 81% rename from TestStack.ConventionTests/Internal/ResultInfo.cs rename to TestStack.ConventionTests/Internal/ConventionResult.cs index 3b2828b..a9fc654 100644 --- a/TestStack.ConventionTests/Internal/ResultInfo.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -1,28 +1,28 @@ -namespace TestStack.ConventionTests.Internal -{ - using TestStack.ConventionTests.Reporting; - - public class ResultInfo - { - public TestResult Result { get; private set; } - public string ConventionTitle { get; private set; } - public string DataDescription { get; private set; } - public ConventionReportFailure[] ConventionFailures { get; private set; } - public string ApprovedException { get; private set; } - - public ResultInfo(TestResult result, string conventionTitle, string dataDescription, ConventionReportFailure[] conventionFailures) - { - Result = result; - ConventionTitle = conventionTitle; - DataDescription = dataDescription; - ConventionFailures = conventionFailures; - } - - public void WithApprovedException(string output) - { - ApprovedException = output; - Result = TestResult.Passed; - ConventionFailures = new ConventionReportFailure[0]; - } - } +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]; + } + } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/Executor.cs b/TestStack.ConventionTests/Internal/Executor.cs index e0453f0..41c613e 100644 --- a/TestStack.ConventionTests/Internal/Executor.cs +++ b/TestStack.ConventionTests/Internal/Executor.cs @@ -5,7 +5,7 @@ public static class Executor { - public static ResultInfo[] GetConventionResults(IConvention convention, TDataSource data) + public static ConventionResult[] GetConventionResults(IConvention convention, TDataSource data) where TDataSource : IConventionData { if (!data.HasData) @@ -17,7 +17,7 @@ public static ResultInfo[] GetConventionResults(IConvention( + public static ConventionResult[] GetConventionResultsWithApprovedExeptions( IConvention convention, TDataSource data) where TDataSource : IConventionData { diff --git a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs index 3fda3d0..dc7f72e 100644 --- a/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTextRenderer.cs @@ -5,7 +5,7 @@ public class ConventionReportTextRenderer : IConventionReportRenderer { - public void Render(params ResultInfo[] conventionResult) + public void Render(params ConventionResult[] conventionResult) { var stringBuilder = new StringBuilder(); @@ -34,14 +34,14 @@ public void Render(params ResultInfo[] conventionResult) public string Output { get; private set; } - public void RenderItems(ResultInfo conventionResult) + public void RenderItems(ConventionResult conventionResult) { var stringBuilder = new StringBuilder(); RenderItems(conventionResult, stringBuilder); Output = stringBuilder.ToString(); } - static void RenderItems(ResultInfo resultInfo, StringBuilder stringBuilder) + static void RenderItems(ConventionResult resultInfo, StringBuilder stringBuilder) { foreach (var conventionFailure in resultInfo.ConventionFailures) { diff --git a/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs index 7c4d68d..d283562 100644 --- a/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs +++ b/TestStack.ConventionTests/Reporting/ConventionReportTraceRenderer.cs @@ -5,7 +5,7 @@ public class ConventionReportTraceRenderer : IConventionReportRenderer { - public void Render(params ResultInfo[] conventionResult) + public void Render(params ConventionResult[] conventionResult) { var conventionReportTextRenderer = new ConventionReportTextRenderer(); conventionReportTextRenderer.Render(conventionResult); diff --git a/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs b/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs index c4cc903..e2d788b 100644 --- a/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs +++ b/TestStack.ConventionTests/Reporting/ConventionResultExceptionReporter.cs @@ -5,7 +5,7 @@ public class ConventionResultExceptionReporter : IConventionReportRenderer { - public void Render(params ResultInfo[] conventionResult) + public void Render(params ConventionResult[] conventionResult) { var conventionReportTextRenderer = new ConventionReportTextRenderer(); conventionReportTextRenderer.Render(conventionResult); diff --git a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs index 2f646b3..79ae3b9 100644 --- a/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/HtmlReportRenderer.cs @@ -14,7 +14,7 @@ public HtmlReportRenderer(string assemblyDirectory) file = Path.Combine(assemblyDirectory, "Conventions.htm"); } - public void Render(params ResultInfo[] conventionResult) + public void Render(params ConventionResult[] conventionResult) { var sb = new StringBuilder(); var html = new HtmlTextWriter(new StringWriter(sb)); diff --git a/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs b/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs index 15ee9fc..c472036 100644 --- a/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs +++ b/TestStack.ConventionTests/Reporting/IConventionReportRenderer.cs @@ -4,6 +4,6 @@ public interface IConventionReportRenderer { - void Render(params ResultInfo[] conventionResult); + void Render(params ConventionResult[] conventionResult); } } \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index d396d80..9393923 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -65,7 +65,7 @@ - + From 84e448fc192d5a5359d2f6b4d1487d8ea0cf4e64 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 16:15:13 +1000 Subject: [PATCH 8/9] removed Executor, sidenote - Resharper is the bee's knees All it took was two refactorings: - move method to another type - make method non-static that's it - no extra manual work, it even folded the ConventionContext parameter and replaced it with 'this' where required. Respect --- TestStack.ConventionTests/Convention.cs | 6 ++- .../Internal/ConventionContext.cs | 31 ++++++++++++++ .../Internal/Executor.cs | 40 ------------------- .../TestStack.ConventionTests.csproj | 1 - 4 files changed, 35 insertions(+), 43 deletions(-) delete mode 100644 TestStack.ConventionTests/Internal/Executor.cs diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index 8b76b7b..86a85f9 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -40,7 +40,8 @@ public static void Is(IConvention convention, TDataSou { try { - var conventionResult = Executor.GetConventionResults(convention, data); + var context = new ConventionContext(data.Description, Formatters); + var conventionResult = context.GetConventionResults(convention, data); Reports.AddRange(conventionResult); new ConventionReportTraceRenderer().Render(conventionResult); @@ -55,7 +56,8 @@ public static void Is(IConvention convention, TDataSou public static void IsWithApprovedExeptions(IConvention convention, TDataSource data) where TDataSource : IConventionData { - var conventionResult = Executor.GetConventionResultsWithApprovedExeptions(convention, data); + var context = new ConventionContext(data.Description, Formatters); + var conventionResult = context.GetConventionResultsWithApprovedExeptions(convention, data); Reports.AddRange(conventionResult); try diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index 2a14535..5f4c94c 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; + using TestStack.ConventionTests.Conventions; using TestStack.ConventionTests.Reporting; public class ConventionContext : IConventionResultContext @@ -75,5 +76,35 @@ ConventionReportFailure FormatData(T failingData) return formatter.Format(failingData); } + + public ConventionResult[] GetConventionResults(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) + { + conventionReportTextRenderer.RenderItems(conventionResult); + conventionResult.WithApprovedException(conventionReportTextRenderer.Output); + } + + return ConventionResults; + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/Executor.cs b/TestStack.ConventionTests/Internal/Executor.cs deleted file mode 100644 index 41c613e..0000000 --- a/TestStack.ConventionTests/Internal/Executor.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace TestStack.ConventionTests.Internal -{ - using TestStack.ConventionTests.Conventions; - using TestStack.ConventionTests.Reporting; - - public static class Executor - { - public static ConventionResult[] GetConventionResults(IConvention convention, TDataSource data) - where TDataSource : IConventionData - { - if (!data.HasData) - throw new ConventionSourceInvalidException(string.Format("{0} has no data", data.Description)); - - var resultGatherer = new ConventionContext(data.Description, Convention.Formatters); - convention.Execute(data, resultGatherer); - - return resultGatherer.ConventionResults; - } - - public static 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)); - - var resultGatherer = new ConventionContext(data.Description, Convention.Formatters); - convention.Execute(data, resultGatherer); - foreach (var conventionResult in resultGatherer.ConventionResults) - { - conventionReportTextRenderer.RenderItems(conventionResult); - conventionResult.WithApprovedException(conventionReportTextRenderer.Output); - } - - return resultGatherer.ConventionResults; - } - } -} \ No newline at end of file diff --git a/TestStack.ConventionTests/TestStack.ConventionTests.csproj b/TestStack.ConventionTests/TestStack.ConventionTests.csproj index 9393923..dae9795 100644 --- a/TestStack.ConventionTests/TestStack.ConventionTests.csproj +++ b/TestStack.ConventionTests/TestStack.ConventionTests.csproj @@ -64,7 +64,6 @@ - From dd0667d02bfdb556405f7041ddf5b273a893621e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozmic Date: Wed, 14 Aug 2013 16:23:34 +1000 Subject: [PATCH 9/9] made the IConventionResultContext explicitly implemented so we keep them separate and don't pollute the Intellisense --- .../Internal/ConventionContext.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index 5f4c94c..028daec 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -23,7 +23,7 @@ public ConventionResult[] ConventionResults get { return results.ToArray(); } } - public void Is(string resultTitle, IEnumerable failingData) + void IConventionResultContext.Is(string resultTitle, IEnumerable failingData) { // ReSharper disable PossibleMultipleEnumeration results.Add(new ConventionResult( @@ -33,7 +33,7 @@ public void Is(string resultTitle, IEnumerable failingData) failingData.Select(FormatData).ToArray())); } - public void IsSymmetric( + void IConventionResultContext.IsSymmetric( string firstSetFailureTitle, IEnumerable firstSetFailureData, string secondSetFailureTitle, IEnumerable secondSetFailureData) { @@ -49,7 +49,7 @@ public void IsSymmetric( secondSetFailureData.Select(FormatData).ToArray())); } - public void IsSymmetric( + void IConventionResultContext.IsSymmetric( string firstSetFailureTitle, string secondSetFailureTitle, Func isPartOfFirstSet, @@ -59,7 +59,7 @@ public void IsSymmetric( var firstSetFailingData = allData.Where(isPartOfFirstSet).Unless(isPartOfSecondSet); var secondSetFailingData = allData.Where(isPartOfSecondSet).Unless(isPartOfFirstSet); - IsSymmetric( + (this as IConventionResultContext).IsSymmetric( firstSetFailureTitle, firstSetFailingData, secondSetFailureTitle, secondSetFailingData); } @@ -77,7 +77,8 @@ ConventionReportFailure FormatData(T failingData) return formatter.Format(failingData); } - public ConventionResult[] GetConventionResults(IConvention convention, TDataSource data) + public ConventionResult[] GetConventionResults(IConvention convention, + TDataSource data) where TDataSource : IConventionData { if (!data.HasData)