Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
namespace TestStack.ConventionTests.Tests
{
using System.Collections.Generic;
using ApprovalTests.Reporters;
using NUnit.Framework;
using TestStack.ConventionTests.Internal;
Expand Down Expand Up @@ -34,10 +33,9 @@ public ConventionReportFailure Format(string failingData)

public class FailingConvention : IConvention<FakeData>
{
public string ConventionTitle { get { return "Header"; } }
public IEnumerable<object> GetFailingData(FakeData data)
public void Execute(FakeData data, IConventionResult result)
{
return new[] { "Different" };
result.Is("Header", new[] {"Different"});
}
}
}
Expand Down
64 changes: 4 additions & 60 deletions TestStack.ConventionTests/Convention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using ApprovalTests;
using ApprovalTests.Core.Exceptions;
using TestStack.ConventionTests.Conventions;
using TestStack.ConventionTests.Internal;
using TestStack.ConventionTests.Reporting;

Expand Down Expand Up @@ -42,8 +40,8 @@ public static void Is<TDataSource>(IConvention<TDataSource> convention, TDataSou
{
try
{
var conventionResult = Executor.GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
Reports.Add(conventionResult);
var conventionResult = Executor.GetConventionResults(convention, data);
Reports.AddRange(conventionResult);

new ConventionReportTraceRenderer().Render(conventionResult);
reporter.Render(conventionResult);
Expand All @@ -57,8 +55,8 @@ public static void Is<TDataSource>(IConvention<TDataSource> convention, TDataSou
public static void IsWithApprovedExeptions<TDataSource>(IConvention<TDataSource> convention, TDataSource data)
where TDataSource : IConventionData
{
var conventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
Reports.Add(conventionResult);
var conventionResult = Executor.GetConventionResultsWithApprovedExeptions(convention, data);
Reports.AddRange(conventionResult);

try
{
Expand All @@ -78,60 +76,6 @@ public static void IsWithApprovedExeptions<TDataSource>(IConvention<TDataSource>
}
}

public static void Is<TDataSource>(ISymmetricConvention<TDataSource> convention, TDataSource data)
where TDataSource : IConventionData
{
Is(convention, data, new ConventionResultExceptionReporter());
}

public static void Is<TDataSource>(ISymmetricConvention<TDataSource> convention, TDataSource data, IConventionReportRenderer reporter)
where TDataSource : IConventionData
{
try
{
var conventionResult = Executor.GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
var inverseConventionResult = Executor.GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data);

Reports.Add(conventionResult);
Reports.Add(inverseConventionResult);

new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult);
reporter.Render(conventionResult, inverseConventionResult);
}
finally
{
HtmlRenderer.Render(Reports.ToArray());
}
}

public static void IsWithApprovedExeptions<TDataSource>(ISymmetricConvention<TDataSource> convention, TDataSource data)
where TDataSource : IConventionData
{
var conventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
var inverseConventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data);
Reports.Add(conventionResult);
Reports.Add(inverseConventionResult);

try
{
//Render both, with approved exceptions included
var conventionReportTextRenderer = new ConventionReportTextRenderer();
conventionReportTextRenderer.Render(conventionResult, inverseConventionResult);
Approvals.Verify(conventionReportTextRenderer.Output);

// Trace on success
new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult);
}
catch (ApprovalException ex)
{
throw new ConventionFailedException("Approved exceptions for convention differs\r\n\r\n" + ex.Message, ex);
}
finally
{
HtmlRenderer.Render(Reports.ToArray());
}
}

// http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917
static string AssemblyDirectory
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
namespace TestStack.ConventionTests.Conventions
{
using System.Collections.Generic;
using System.Linq;
using TestStack.ConventionTests.ConventionData;
using TestStack.ConventionTests.Internal;

public class AllClassesHaveDefaultConstructor : IConvention<Types>
{
public string ConventionTitle { get { return "Types must have a default constructor"; } }

public IEnumerable<object> GetFailingData(Types data)
public void Execute(Types data, IConventionResult result)
{
return data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false);
result.Is("Types must have a default constructor",
data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false));
}
}
}
8 changes: 2 additions & 6 deletions TestStack.ConventionTests/Conventions/AllMethodsAreVirtual.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
namespace TestStack.ConventionTests.Conventions
{
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TestStack.ConventionTests.ConventionData;
using TestStack.ConventionTests.Internal;

public class AllMethodsAreVirtual : IConvention<Types>
{
public string ConventionTitle { get { return "Methods must be virtual"; } }

public IEnumerable<object> GetFailingData(Types data)
public void Execute(Types data, IConventionResult result)
{
return data.TypesToVerify.SelectMany(t => t.NonVirtualMethods());
result.Is("Methods must be virtual", data.TypesToVerify.SelectMany(t => t.NonVirtualMethods()));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
namespace TestStack.ConventionTests.Conventions
{
using System;
using System.Collections.Generic;
using System.Linq;
using TestStack.ConventionTests.ConventionData;

/// <summary>
Expand All @@ -14,7 +12,7 @@
///
/// This is a Symmetric convention, and will verify all of a Class Type lives in the namespace, but also that only that class type is in that namespace
/// </summary>
public class ClassTypeHasSpecificNamespace : ISymmetricConvention<Types>
public class ClassTypeHasSpecificNamespace : IConvention<Types>
{
readonly Func<Type, bool> classIsApplicable;
readonly string namespaceToCheck;
Expand All @@ -33,34 +31,19 @@ public ClassTypeHasSpecificNamespace(Func<Type, bool> classIsApplicable, string
this.classType = classType;
}

public string ConventionTitle
public void Execute(Types data, IConventionResult result)
{
get
{
return string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck);
}
result.IsSymmetric(
string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck),
string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck),
classIsApplicable,
TypeLivesInSpecifiedNamespace,
data.TypesToVerify);
}

public string InverseTitle
bool TypeLivesInSpecifiedNamespace(Type t)
{
get
{
return string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck);
}
}

public IEnumerable<object> GetFailingData(Types data)
{
return data.TypesToVerify
.Where(classIsApplicable)
.Where(t => t.Namespace == null || !t.Namespace.StartsWith(namespaceToCheck));
}

public IEnumerable<object> GetFailingInverseData(Types data)
{
return data.TypesToVerify
.Where(t => !classIsApplicable(t))
.Where(t => t.Namespace != null && t.Namespace.StartsWith(namespaceToCheck));
return t.Namespace == null || t.Namespace.StartsWith(namespaceToCheck);
}
}
}
17 changes: 5 additions & 12 deletions TestStack.ConventionTests/Conventions/FilesAreEmbeddedResources.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
namespace TestStack.ConventionTests.Conventions
{
using System.Collections.Generic;
using System.Linq;
using TestStack.ConventionTests.ConventionData;

Expand All @@ -11,19 +10,13 @@ public FilesAreEmbeddedResources(string fileExtension)
FileExtension = fileExtension;
}

public string ConventionTitle
{
get
{
return string.Format("{0} Files must be embedded resources", FileExtension);
}
}

public string FileExtension { get; set; }
public string FileExtension { get; private set; }

public IEnumerable<object> GetFailingData(ProjectFiles data)
public void Execute(ProjectFiles data, IConventionResult result)
{
return data.Files.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource");
result.Is(
string.Format("{0} Files must be embedded resources", FileExtension),
data.Files.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource"));
}
}
}
12 changes: 0 additions & 12 deletions TestStack.ConventionTests/Conventions/ISymmetricConvention.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
namespace TestStack.ConventionTests.Conventions
{
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using TestStack.ConventionTests.ConventionData;
Expand All @@ -9,16 +8,15 @@ public class ProjectDoesNotReferenceDllsFromBinOrObjDirectories : IConvention<Pr
{
const string AssemblyReferencingObjRegex = @"^(?<assembly>.*?(obj|bin).*?)$";

static bool IsBinOrObjReference(ProjectReference reference)
public void Execute(ProjectReferences data, IConventionResult result)
{
return Regex.IsMatch(reference.ReferencedPath, AssemblyReferencingObjRegex, RegexOptions.IgnoreCase);
result.Is("Project must not reference dlls from bin or obj directories",
data.References.Where(IsBinOrObjReference));
}

public string ConventionTitle { get { return "Project must not reference dlls from bin or obj directories"; } }

public IEnumerable<object> GetFailingData(ProjectReferences data)
static bool IsBinOrObjReference(ProjectReference reference)
{
return data.References.Where(IsBinOrObjReference);
return Regex.IsMatch(reference.ReferencedPath, AssemblyReferencingObjRegex, RegexOptions.IgnoreCase);
}
}
}
5 changes: 1 addition & 4 deletions TestStack.ConventionTests/IConvention.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
namespace TestStack.ConventionTests
{
using System.Collections.Generic;

public interface IConvention<in T> where T : IConventionData
{
string ConventionTitle { get; }
IEnumerable<object> GetFailingData(T data);
void Execute(T data, IConventionResult result);
}
}
46 changes: 46 additions & 0 deletions TestStack.ConventionTests/IConventionResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
namespace TestStack.ConventionTests
{
using System;
using System.Collections.Generic;

public interface IConventionResult
{
void Is<T>(string resultTitle, IEnumerable<T> failingData);

/// <summary>
/// A symmetric convention is a convention which also can be applied in reverse. For example
/// All dto's live in Project.Dto namespace AND Only dto's live in Project.Dto
/// This means if a DTO is outside of Project.Dto, the test will fail,
/// and if a non-dto is in Project.Dto the test will also fail
/// </summary>
/// <typeparam name="TResult">The data type the convention is applied to</typeparam>
/// <param name="conventionResultTitle">Title of the convention, i.e Dto's must live in Project.Dto namespace</param>
/// <param name="conventionFailingData">Data failing to conform to the convention</param>
/// <param name="inverseResultTitle">The inverse scenario title, i.e Non-dtos must not live inside Project.Dto namespace</param>
/// <param name="inverseFailingData">Data failing to conform to the inverse of the convention</param>
void IsSymmetric<TResult>(
string conventionResultTitle, IEnumerable<TResult> conventionFailingData,
string inverseResultTitle, IEnumerable<TResult> inverseFailingData);

/// <summary>
/// A symmetric convention is a convention which also can be applied in reverse. For example
/// All dto's live in Project.Dto namespace AND Only dto's live in Project.Dto
/// This means if a DTO is outside of Project.Dto, the test will fail,
/// and if a non-dto is in Project.Dto the test will also fail
///
/// This overload allows you to work with sets, see ....
/// </summary>
/// <typeparam name="TResult">The data type the convention is applied to</typeparam>
/// <param name="firstSetFailureTitle">Title of the convention, i.e Dto's must live in Project.Dto namespace</param>
/// <param name="secondSetFailureTitle">The inverse scenario title, i.e Non-dtos must not live inside Project.Dto namespace</param>
/// <param name="allData">All data, for dto example, all types in the project, not just dto's</param>
/// <param name="isPartOfFirstSet">Predicate defining data which is in the first set</param>
/// <param name="isPartOfSecondSet">Predicate defining data which is in the second set</param>
void IsSymmetric<TResult>(
string firstSetFailureTitle,
string secondSetFailureTitle,
Func<TResult, bool> isPartOfFirstSet,
Func<TResult, bool> isPartOfSecondSet,
IEnumerable<TResult> allData);
}
}
Loading