diff --git a/TestStack.ConventionTests.Autofac/CanResolveAllRegisteredServices.cs b/TestStack.ConventionTests.Autofac/CanResolveAllRegisteredServices.cs index e917611..d946bc3 100644 --- a/TestStack.ConventionTests.Autofac/CanResolveAllRegisteredServices.cs +++ b/TestStack.ConventionTests.Autofac/CanResolveAllRegisteredServices.cs @@ -1,10 +1,10 @@ namespace TestStack.ConventionTests.Autofac { + using global::Autofac; + using global::Autofac.Core; using System; using System.Collections.Generic; using System.Linq; - using global::Autofac; - using global::Autofac.Core; public class CanResolveAllRegisteredServices : IConvention { @@ -37,6 +37,14 @@ public void Execute(AutofacRegistrations data, IConventionResultContext result) result.Is("Can resolve all types registered with Autofac", failingTypes); } + public string ConventionReason + { + get + { + return "Container resolution failings are runtime exceptions, this convention allows you to detect missing registrations faster!"; + } + } + private IEnumerable GetGenericFactoryTypes(AutofacRegistrations data, IComponentRegistration componentRegistration) { return from ctorParameter in data.GetRegistrationCtorParameters(componentRegistration) diff --git a/TestStack.ConventionTests.Autofac/ServicesShouldOnlyHaveDependenciesWithLesserLifetime.cs b/TestStack.ConventionTests.Autofac/ServicesShouldOnlyHaveDependenciesWithLesserLifetime.cs index bcb5286..77b207c 100644 --- a/TestStack.ConventionTests.Autofac/ServicesShouldOnlyHaveDependenciesWithLesserLifetime.cs +++ b/TestStack.ConventionTests.Autofac/ServicesShouldOnlyHaveDependenciesWithLesserLifetime.cs @@ -1,7 +1,7 @@ namespace TestStack.ConventionTests.Autofac { - using System.Collections.Generic; using global::Autofac.Core; + using System.Collections.Generic; using TestStack.ConventionTests.ConventionData; public class ServicesShouldOnlyHaveDependenciesWithLesserLifetime : IConvention @@ -37,5 +37,10 @@ public void Execute(AutofacRegistrations data, IConventionResultContext result) result.Is("Components should not depend on with greater lifetimes", exceptions); } + + public string ConventionReason + { + get { return @"When classes with larger lifetimes depend on classes with smaller lifetimes this often indicates an error and can lead to subtle bugs"; } + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs index 0a733d4..fa011cd 100644 --- a/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs +++ b/TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs @@ -31,6 +31,11 @@ public void Execute(FakeData data, IConventionResultContext result) { result.Is("Header", new[] {"Different"}); } + + public string ConventionReason + { + get { return "Because fail.."; } + } } } } \ No newline at end of file diff --git a/TestStack.ConventionTests.Tests/ConventionFixture.cs b/TestStack.ConventionTests.Tests/ConventionFixture.cs index e28b262..84130b7 100644 --- a/TestStack.ConventionTests.Tests/ConventionFixture.cs +++ b/TestStack.ConventionTests.Tests/ConventionFixture.cs @@ -25,6 +25,8 @@ public void Execute(Types data, IConventionResultContext result) // Oops, I forgot to set the result } + public string ConventionReason { get { return "Convention does not set result for testing"; } } + bool IsBroken(Type type) { return true; diff --git a/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs b/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs index cf49baf..77161ac 100644 --- a/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs +++ b/TestStack.ConventionTests.Tests/TestConventions/CollectionsRelationsConvention.cs @@ -29,6 +29,11 @@ from item in GetItemTypes(collection) result.Is("Some title", collectionToItemLookup); } + public string ConventionReason + { + get { return "Test convention"; } + } + IEnumerable GetItemTypes(Type type) { return from @interface in type.GetInterfaces() diff --git a/TestStack.ConventionTests/Convention.cs b/TestStack.ConventionTests/Convention.cs index ba5d9aa..5056730 100644 --- a/TestStack.ConventionTests/Convention.cs +++ b/TestStack.ConventionTests/Convention.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Reflection; - using System.Text.RegularExpressions; using TestStack.ConventionTests.ConventionData; using TestStack.ConventionTests.Internal; using TestStack.ConventionTests.Reporting; diff --git a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs index 28edb3c..42a6493 100644 --- a/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs +++ b/TestStack.ConventionTests/Conventions/AllClassesHaveDefaultConstructor.cs @@ -10,5 +10,10 @@ public void Execute(Types data, IConventionResultContext result) result.Is("Types must have a default constructor", data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false)); } + + public string ConventionReason + { + get { return "This convention is useful when classes need to be proxied (nHibernate/Entity Framework entities), which need a public or protected constructor"; } + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs index 4dbd3c2..cda9916 100644 --- a/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs +++ b/TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs @@ -9,5 +9,10 @@ public void Execute(Types data, IConventionResultContext result) { result.Is("Methods must be virtual", data.TypesToVerify.SelectMany(t => t.NonVirtualMethods())); } + + public string ConventionReason + { + get { return "This convention is useful when classes need to be proxied (nHibernate entities), which need members to be virtual"; } + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs index 104c013..5fa263a 100644 --- a/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs +++ b/TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs @@ -41,6 +41,11 @@ public void Execute(Types data, IConventionResultContext result) data.TypesToVerify); } + public string ConventionReason + { + get { return "To simplify project structure and allow developers to know where this type of class should live in the project"; } + } + bool TypeLivesInSpecifiedNamespace(Type t) { return t.Namespace == null || t.Namespace.StartsWith(namespaceToCheck); diff --git a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs index a6ecc11..6394af7 100644 --- a/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs +++ b/TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs @@ -18,5 +18,7 @@ public void Execute(ProjectFileItems data, IConventionResultContext result) string.Format("{0} Files must be embedded resources", FileExtension), data.Items.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource")); } + + public string ConventionReason { get { return "Many files are added as 'Content' to visual studio projects, this convention enforces files with an extension are correctly set as Embedded Resources"; } } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Conventions/MvcControllerNameAndBaseClassConvention.cs b/TestStack.ConventionTests/Conventions/MvcControllerNameAndBaseClassConvention.cs index 4546082..781028f 100644 --- a/TestStack.ConventionTests/Conventions/MvcControllerNameAndBaseClassConvention.cs +++ b/TestStack.ConventionTests/Conventions/MvcControllerNameAndBaseClassConvention.cs @@ -20,8 +20,10 @@ public void Execute(Types data, IConventionResultContext result) GetControllerTypeName() + "s must be suffixed with Controller", typesWhichDoNotEndInController, "Types named *Controller must inherit from ApiController or Controller", controllersWhichDoNotInheritFromController); - } - + } + + public string ConventionReason { get { return "This convention detects when Mvc Controllers are likely misconfigured and do not follow Mvc conventions"; } } + protected virtual string GetControllerTypeName() { return "Mvc Controller"; diff --git a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs index 5247982..b7f29ee 100644 --- a/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs +++ b/TestStack.ConventionTests/Conventions/ProjectDoesNotReferenceDllsFromBinOrObjDirectories.cs @@ -14,6 +14,8 @@ public void Execute(ProjectReferences data, IConventionResultContext result) data.References.Where(IsBinOrObjReference)); } + public string ConventionReason { get { return "Referencing assemblies from the bin/obj folder is normally due to a broken reference, this convention detects these issues"; } } + static bool IsBinOrObjReference(ProjectReference reference) { return Regex.IsMatch(reference.ReferencedPath, AssemblyReferencingObjRegex, RegexOptions.IgnoreCase); diff --git a/TestStack.ConventionTests/Conventions/ViewModelShouldInheritFromINotifyPropertyChanged.cs b/TestStack.ConventionTests/Conventions/ViewModelShouldInheritFromINotifyPropertyChanged.cs index 7358582..26fd443 100644 --- a/TestStack.ConventionTests/Conventions/ViewModelShouldInheritFromINotifyPropertyChanged.cs +++ b/TestStack.ConventionTests/Conventions/ViewModelShouldInheritFromINotifyPropertyChanged.cs @@ -23,5 +23,13 @@ public void Execute(Types data, IConventionResultContext result) result.Is("ViewModels (types named *{0}) should inherit from INotifyPropertyChanged", failingData); } + + public string ConventionReason + { + get + { + return "In different scenarios, WPF can hold onto ViewModels if they do not inherit from INotifyPropertyChanged"; + } + } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/IConvention.cs b/TestStack.ConventionTests/IConvention.cs index 2c7621e..3a24044 100644 --- a/TestStack.ConventionTests/IConvention.cs +++ b/TestStack.ConventionTests/IConvention.cs @@ -3,5 +3,6 @@ public interface IConvention where T : IConventionData { void Execute(T data, IConventionResultContext result); + string ConventionReason { get; } } } \ No newline at end of file diff --git a/TestStack.ConventionTests/Internal/ConventionContext.cs b/TestStack.ConventionTests/Internal/ConventionContext.cs index e14d395..ed16572 100644 --- a/TestStack.ConventionTests/Internal/ConventionContext.cs +++ b/TestStack.ConventionTests/Internal/ConventionContext.cs @@ -13,6 +13,7 @@ public class ConventionContext : IConventionResultContext, IConventionFormatCont readonly IList processors; readonly ITestResultProcessor testResultProcessor; readonly IList results = new List(); + string conventionReason; bool resultSet; public ConventionContext(string dataDescription, IList formatters, @@ -65,6 +66,7 @@ void IConventionResultContext.Is(string resultTitle, IEnumerable( resultSet = true; results.Add(new ConventionResult( typeof (TResult), firstSetFailureTitle, - dataDescription, + conventionReason, dataDescription, firstSetFailureData.ToObjectArray())); results.Add(new ConventionResult( typeof (TResult), secondSetFailureTitle, - dataDescription, + conventionReason, dataDescription, secondSetFailureData.ToObjectArray())); } @@ -102,6 +104,7 @@ void IConventionResultContext.IsSymmetric( public void Execute(IConvention convention, TDataSource data) where TDataSource : IConventionData { + conventionReason = convention.ConventionReason; if (!data.HasData) throw new ConventionSourceInvalidException(String.Format("{0} has no data", data.Description)); convention.Execute(data, this); diff --git a/TestStack.ConventionTests/Internal/ConventionResult.cs b/TestStack.ConventionTests/Internal/ConventionResult.cs index 0a833d4..3a9caef 100644 --- a/TestStack.ConventionTests/Internal/ConventionResult.cs +++ b/TestStack.ConventionTests/Internal/ConventionResult.cs @@ -5,8 +5,9 @@ public class ConventionResult { - public ConventionResult(Type dataType, string conventionTitle, string dataDescription, object[] data) + public ConventionResult(Type dataType, string conventionTitle, string conventionReason, string dataDescription, object[] data) { + ConventionReason = conventionReason; DataType = dataType; ConventionTitle = conventionTitle; DataDescription = dataDescription; @@ -15,6 +16,7 @@ public ConventionResult(Type dataType, string conventionTitle, string dataDescri public Type DataType { get; private set; } public string ConventionTitle { get; private set; } + public string ConventionReason { get; private set; } public string DataDescription { get; private set; } public object[] Data { get; private set; } @@ -23,6 +25,7 @@ public bool HasData get { return Data.Any(); } } + protected bool Equals(ConventionResult other) { return DataType == other.DataType && string.Equals(ConventionTitle, other.ConventionTitle) && string.Equals(DataDescription, other.DataDescription); diff --git a/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs b/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs index 9d4a2b2..54f8a8f 100644 --- a/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs +++ b/TestStack.ConventionTests/Reporting/HtmlConventionResultsReporter.cs @@ -66,6 +66,10 @@ protected override string Process(IConventionFormatContext context, IEnumerable< html.RenderBeginTag(HtmlTextWriterTag.H4); html.Write(conventionResult.ConventionTitle); html.RenderEndTag(); + html.AddAttribute("style", "margin-left:20px;"); + html.RenderBeginTag(HtmlTextWriterTag.Div); + html.Write(conventionResult.ConventionReason); + html.RenderEndTag(); if (conventionResult.Data.Any()) { html.AddAttribute("style", "margin-left:20px;"); diff --git a/TestStack.ConventionTests/Reporting/MarkdownConventionResultsReporter.cs b/TestStack.ConventionTests/Reporting/MarkdownConventionResultsReporter.cs index 15697c6..63433aa 100644 --- a/TestStack.ConventionTests/Reporting/MarkdownConventionResultsReporter.cs +++ b/TestStack.ConventionTests/Reporting/MarkdownConventionResultsReporter.cs @@ -22,8 +22,10 @@ protected override string Process(IConventionFormatContext context, IEnumerable< foreach (var conventionResult in conventionReport) { - sb.Append(" - "); - sb.AppendLine(conventionResult.ConventionTitle); + sb.Append(" - **"); + sb.Append(conventionResult.ConventionTitle); + sb.AppendLine("** "); + sb.AppendLine(conventionResult.ConventionReason); } }