Skip to content

Commit 820ded8

Browse files
committed
Merge pull request #25 from JakeGinnivan/ConventionResultInterface
Introduced a IConventionResult to clean things up
2 parents 9fb7126 + 7e89f52 commit 820ded8

13 files changed

+178
-161
lines changed

TestStack.ConventionTests.Tests/ConventionAssertionClassTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
namespace TestStack.ConventionTests.Tests
22
{
3-
using System.Collections.Generic;
43
using ApprovalTests.Reporters;
54
using NUnit.Framework;
65
using TestStack.ConventionTests.Internal;
@@ -34,10 +33,9 @@ public ConventionReportFailure Format(string failingData)
3433

3534
public class FailingConvention : IConvention<FakeData>
3635
{
37-
public string ConventionTitle { get { return "Header"; } }
38-
public IEnumerable<object> GetFailingData(FakeData data)
36+
public void Execute(FakeData data, IConventionResult result)
3937
{
40-
return new[] { "Different" };
38+
result.Is("Header", new[] {"Different"});
4139
}
4240
}
4341
}

TestStack.ConventionTests/Convention.cs

Lines changed: 4 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
using System;
44
using System.Collections.Generic;
55
using System.IO;
6-
using System.Linq;
76
using System.Reflection;
87
using ApprovalTests;
98
using ApprovalTests.Core.Exceptions;
10-
using TestStack.ConventionTests.Conventions;
119
using TestStack.ConventionTests.Internal;
1210
using TestStack.ConventionTests.Reporting;
1311

@@ -42,8 +40,8 @@ public static void Is<TDataSource>(IConvention<TDataSource> convention, TDataSou
4240
{
4341
try
4442
{
45-
var conventionResult = Executor.GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
46-
Reports.Add(conventionResult);
43+
var conventionResult = Executor.GetConventionResults(convention, data);
44+
Reports.AddRange(conventionResult);
4745

4846
new ConventionReportTraceRenderer().Render(conventionResult);
4947
reporter.Render(conventionResult);
@@ -57,8 +55,8 @@ public static void Is<TDataSource>(IConvention<TDataSource> convention, TDataSou
5755
public static void IsWithApprovedExeptions<TDataSource>(IConvention<TDataSource> convention, TDataSource data)
5856
where TDataSource : IConventionData
5957
{
60-
var conventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
61-
Reports.Add(conventionResult);
58+
var conventionResult = Executor.GetConventionResultsWithApprovedExeptions(convention, data);
59+
Reports.AddRange(conventionResult);
6260

6361
try
6462
{
@@ -78,60 +76,6 @@ public static void IsWithApprovedExeptions<TDataSource>(IConvention<TDataSource>
7876
}
7977
}
8078

81-
public static void Is<TDataSource>(ISymmetricConvention<TDataSource> convention, TDataSource data)
82-
where TDataSource : IConventionData
83-
{
84-
Is(convention, data, new ConventionResultExceptionReporter());
85-
}
86-
87-
public static void Is<TDataSource>(ISymmetricConvention<TDataSource> convention, TDataSource data, IConventionReportRenderer reporter)
88-
where TDataSource : IConventionData
89-
{
90-
try
91-
{
92-
var conventionResult = Executor.GetConventionReport(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
93-
var inverseConventionResult = Executor.GetConventionReport(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data);
94-
95-
Reports.Add(conventionResult);
96-
Reports.Add(inverseConventionResult);
97-
98-
new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult);
99-
reporter.Render(conventionResult, inverseConventionResult);
100-
}
101-
finally
102-
{
103-
HtmlRenderer.Render(Reports.ToArray());
104-
}
105-
}
106-
107-
public static void IsWithApprovedExeptions<TDataSource>(ISymmetricConvention<TDataSource> convention, TDataSource data)
108-
where TDataSource : IConventionData
109-
{
110-
var conventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.ConventionTitle, convention.GetFailingData(data).ToArray(), data);
111-
var inverseConventionResult = Executor.GetConventionReportWithApprovedExeptions(convention.InverseTitle, convention.GetFailingInverseData(data).ToArray(), data);
112-
Reports.Add(conventionResult);
113-
Reports.Add(inverseConventionResult);
114-
115-
try
116-
{
117-
//Render both, with approved exceptions included
118-
var conventionReportTextRenderer = new ConventionReportTextRenderer();
119-
conventionReportTextRenderer.Render(conventionResult, inverseConventionResult);
120-
Approvals.Verify(conventionReportTextRenderer.Output);
121-
122-
// Trace on success
123-
new ConventionReportTraceRenderer().Render(conventionResult, inverseConventionResult);
124-
}
125-
catch (ApprovalException ex)
126-
{
127-
throw new ConventionFailedException("Approved exceptions for convention differs\r\n\r\n" + ex.Message, ex);
128-
}
129-
finally
130-
{
131-
HtmlRenderer.Render(Reports.ToArray());
132-
}
133-
}
134-
13579
// http://stackoverflow.com/questions/52797/c-how-do-i-get-the-path-of-the-assembly-the-code-is-in#answer-283917
13680
static string AssemblyDirectory
13781
{
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
namespace TestStack.ConventionTests.Conventions
22
{
3-
using System.Collections.Generic;
43
using System.Linq;
54
using TestStack.ConventionTests.ConventionData;
65
using TestStack.ConventionTests.Internal;
76

87
public class AllClassesHaveDefaultConstructor : IConvention<Types>
98
{
10-
public string ConventionTitle { get { return "Types must have a default constructor"; } }
11-
12-
public IEnumerable<object> GetFailingData(Types data)
9+
public void Execute(Types data, IConventionResult result)
1310
{
14-
return data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false);
11+
result.Is("Types must have a default constructor",
12+
data.TypesToVerify.Where(t => t.HasDefaultConstructor() == false));
1513
}
1614
}
1715
}
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
namespace TestStack.ConventionTests.Conventions
22
{
3-
using System.Collections.Generic;
43
using System.Linq;
5-
using System.Reflection;
64
using TestStack.ConventionTests.ConventionData;
75
using TestStack.ConventionTests.Internal;
86

97
public class AllMethodsAreVirtual : IConvention<Types>
108
{
11-
public string ConventionTitle { get { return "Methods must be virtual"; } }
12-
13-
public IEnumerable<object> GetFailingData(Types data)
9+
public void Execute(Types data, IConventionResult result)
1410
{
15-
return data.TypesToVerify.SelectMany(t => t.NonVirtualMethods());
11+
result.Is("Methods must be virtual", data.TypesToVerify.SelectMany(t => t.NonVirtualMethods()));
1612
}
1713
}
1814
}
Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
namespace TestStack.ConventionTests.Conventions
22
{
33
using System;
4-
using System.Collections.Generic;
5-
using System.Linq;
64
using TestStack.ConventionTests.ConventionData;
75

86
/// <summary>
@@ -14,7 +12,7 @@
1412
///
1513
/// 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
1614
/// </summary>
17-
public class ClassTypeHasSpecificNamespace : ISymmetricConvention<Types>
15+
public class ClassTypeHasSpecificNamespace : IConvention<Types>
1816
{
1917
readonly Func<Type, bool> classIsApplicable;
2018
readonly string namespaceToCheck;
@@ -33,34 +31,19 @@ public ClassTypeHasSpecificNamespace(Func<Type, bool> classIsApplicable, string
3331
this.classType = classType;
3432
}
3533

36-
public string ConventionTitle
34+
public void Execute(Types data, IConventionResult result)
3735
{
38-
get
39-
{
40-
return string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck);
41-
}
36+
result.IsSymmetric(
37+
string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck),
38+
string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck),
39+
classIsApplicable,
40+
TypeLivesInSpecifiedNamespace,
41+
data.TypesToVerify);
4242
}
4343

44-
public string InverseTitle
44+
bool TypeLivesInSpecifiedNamespace(Type t)
4545
{
46-
get
47-
{
48-
return string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck);
49-
}
50-
}
51-
52-
public IEnumerable<object> GetFailingData(Types data)
53-
{
54-
return data.TypesToVerify
55-
.Where(classIsApplicable)
56-
.Where(t => t.Namespace == null || !t.Namespace.StartsWith(namespaceToCheck));
57-
}
58-
59-
public IEnumerable<object> GetFailingInverseData(Types data)
60-
{
61-
return data.TypesToVerify
62-
.Where(t => !classIsApplicable(t))
63-
.Where(t => t.Namespace != null && t.Namespace.StartsWith(namespaceToCheck));
46+
return t.Namespace == null || t.Namespace.StartsWith(namespaceToCheck);
6447
}
6548
}
6649
}
Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
namespace TestStack.ConventionTests.Conventions
22
{
3-
using System.Collections.Generic;
43
using System.Linq;
54
using TestStack.ConventionTests.ConventionData;
65

@@ -11,19 +10,13 @@ public FilesAreEmbeddedResources(string fileExtension)
1110
FileExtension = fileExtension;
1211
}
1312

14-
public string ConventionTitle
15-
{
16-
get
17-
{
18-
return string.Format("{0} Files must be embedded resources", FileExtension);
19-
}
20-
}
21-
22-
public string FileExtension { get; set; }
13+
public string FileExtension { get; private set; }
2314

24-
public IEnumerable<object> GetFailingData(ProjectFiles data)
15+
public void Execute(ProjectFiles data, IConventionResult result)
2516
{
26-
return data.Files.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource");
17+
result.Is(
18+
string.Format("{0} Files must be embedded resources", FileExtension),
19+
data.Files.Where(s => s.FilePath.EndsWith(FileExtension) && s.ReferenceType != "EmbeddedResource"));
2720
}
2821
}
2922
}

TestStack.ConventionTests/Conventions/ISymmetricConvention.cs

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
namespace TestStack.ConventionTests.Conventions
22
{
3-
using System.Collections.Generic;
43
using System.Linq;
54
using System.Text.RegularExpressions;
65
using TestStack.ConventionTests.ConventionData;
@@ -9,16 +8,15 @@ public class ProjectDoesNotReferenceDllsFromBinOrObjDirectories : IConvention<Pr
98
{
109
const string AssemblyReferencingObjRegex = @"^(?<assembly>.*?(obj|bin).*?)$";
1110

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

17-
public string ConventionTitle { get { return "Project must not reference dlls from bin or obj directories"; } }
18-
19-
public IEnumerable<object> GetFailingData(ProjectReferences data)
17+
static bool IsBinOrObjReference(ProjectReference reference)
2018
{
21-
return data.References.Where(IsBinOrObjReference);
19+
return Regex.IsMatch(reference.ReferencedPath, AssemblyReferencingObjRegex, RegexOptions.IgnoreCase);
2220
}
2321
}
2422
}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
namespace TestStack.ConventionTests
22
{
3-
using System.Collections.Generic;
4-
53
public interface IConvention<in T> where T : IConventionData
64
{
7-
string ConventionTitle { get; }
8-
IEnumerable<object> GetFailingData(T data);
5+
void Execute(T data, IConventionResult result);
96
}
107
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
namespace TestStack.ConventionTests
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
6+
public interface IConventionResult
7+
{
8+
void Is<T>(string resultTitle, IEnumerable<T> failingData);
9+
10+
/// <summary>
11+
/// A symmetric convention is a convention which also can be applied in reverse. For example
12+
/// All dto's live in Project.Dto namespace AND Only dto's live in Project.Dto
13+
/// This means if a DTO is outside of Project.Dto, the test will fail,
14+
/// and if a non-dto is in Project.Dto the test will also fail
15+
/// </summary>
16+
/// <typeparam name="TResult">The data type the convention is applied to</typeparam>
17+
/// <param name="conventionResultTitle">Title of the convention, i.e Dto's must live in Project.Dto namespace</param>
18+
/// <param name="conventionFailingData">Data failing to conform to the convention</param>
19+
/// <param name="inverseResultTitle">The inverse scenario title, i.e Non-dtos must not live inside Project.Dto namespace</param>
20+
/// <param name="inverseFailingData">Data failing to conform to the inverse of the convention</param>
21+
void IsSymmetric<TResult>(
22+
string conventionResultTitle, IEnumerable<TResult> conventionFailingData,
23+
string inverseResultTitle, IEnumerable<TResult> inverseFailingData);
24+
25+
/// <summary>
26+
/// A symmetric convention is a convention which also can be applied in reverse. For example
27+
/// All dto's live in Project.Dto namespace AND Only dto's live in Project.Dto
28+
/// This means if a DTO is outside of Project.Dto, the test will fail,
29+
/// and if a non-dto is in Project.Dto the test will also fail
30+
///
31+
/// This overload allows you to work with sets, see ....
32+
/// </summary>
33+
/// <typeparam name="TResult">The data type the convention is applied to</typeparam>
34+
/// <param name="firstSetFailureTitle">Title of the convention, i.e Dto's must live in Project.Dto namespace</param>
35+
/// <param name="secondSetFailureTitle">The inverse scenario title, i.e Non-dtos must not live inside Project.Dto namespace</param>
36+
/// <param name="allData">All data, for dto example, all types in the project, not just dto's</param>
37+
/// <param name="isPartOfFirstSet">Predicate defining data which is in the first set</param>
38+
/// <param name="isPartOfSecondSet">Predicate defining data which is in the second set</param>
39+
void IsSymmetric<TResult>(
40+
string firstSetFailureTitle,
41+
string secondSetFailureTitle,
42+
Func<TResult, bool> isPartOfFirstSet,
43+
Func<TResult, bool> isPartOfSecondSet,
44+
IEnumerable<TResult> allData);
45+
}
46+
}

0 commit comments

Comments
 (0)