Skip to content

Commit 14f1a6e

Browse files
author
Jake Ginnivan
committed
Added better IsSymmetric overload thanks to @kkozmic
1 parent c1514c8 commit 14f1a6e

File tree

3 files changed

+68
-24
lines changed

3 files changed

+68
-24
lines changed

TestStack.ConventionTests/Conventions/ClassTypeHasSpecificNamespace.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
namespace TestStack.ConventionTests.Conventions
22
{
33
using System;
4-
using System.Linq;
54
using TestStack.ConventionTests.ConventionData;
65

76
/// <summary>
@@ -34,18 +33,17 @@ public ClassTypeHasSpecificNamespace(Func<Type, bool> classIsApplicable, string
3433

3534
public void Execute(Types data, IConventionResult result)
3635
{
37-
var failingData = data.TypesToVerify
38-
.Where(classIsApplicable)
39-
.Where(t => t.Namespace == null || !t.Namespace.StartsWith(namespaceToCheck));
40-
var inverseFailingData = data.TypesToVerify
41-
.Where(t => !classIsApplicable(t))
42-
.Where(t => t.Namespace != null && t.Namespace.StartsWith(namespaceToCheck));
43-
4436
result.IsSymmetric(
4537
string.Format("{0}s must be under the '{1}' namespace", classType, namespaceToCheck),
46-
failingData,
4738
string.Format("Non-{0}s must not be under the '{1}' namespace", classType, namespaceToCheck),
48-
inverseFailingData);
39+
classIsApplicable,
40+
TypeLivesInSpecifiedNamespace,
41+
data.TypesToVerify);
42+
}
43+
44+
bool TypeLivesInSpecifiedNamespace(Type t)
45+
{
46+
return t.Namespace == null || t.Namespace.StartsWith(namespaceToCheck);
4947
}
5048
}
5149
}

TestStack.ConventionTests/IConventionResult.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,37 @@
66
public interface IConventionResult
77
{
88
void Is<T>(string resultTitle, IEnumerable<T> failingData);
9-
void IsSymmetric<T>(
10-
string firstResultTitle, IEnumerable<T> firstFailingData,
11-
string secondResultTitle, IEnumerable<T> secondFailingData);
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+
/// </summary>
31+
/// <typeparam name="TResult">The data type the convention is applied to</typeparam>
32+
/// <param name="conventionResultTitle">Title of the convention, i.e Dto's must live in Project.Dto namespace</param>
33+
/// <param name="inverseResultTitle">The inverse scenario title, i.e Non-dtos must not live inside Project.Dto namespace</param>
34+
/// <param name="isInclusiveData">Predicate describing if the data is included, for example, t => t.Name.EndsWith("Dto")</param>
35+
/// <param name="dataConformsToConvention">
36+
/// Predicate describing the convention, for example, t =>
37+
/// t.NameSpace.StartsWith("Project.Dto")
38+
/// </param>
39+
/// <param name="allData">All data, for dto example, all types in the project, not just dto's</param>
40+
void IsSymmetric<TResult>(string conventionResultTitle, string inverseResultTitle, Func<TResult, bool> isInclusiveData, Func<TResult, bool> dataConformsToConvention, IEnumerable<TResult> allData);
1241
}
1342
}

TestStack.ConventionTests/Internal/ConventionResult.cs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
namespace TestStack.ConventionTests.Internal
22
{
3+
using System;
34
using System.Collections.Generic;
45
using System.Linq;
56
using TestStack.ConventionTests.Reporting;
67

78
public class ConventionResult : IConventionResult
89
{
9-
readonly string dataDescription;
1010
readonly List<ResultInfo> conventionResults;
11+
readonly string dataDescription;
1112

1213
public ConventionResult(string dataDescription)
1314
{
@@ -30,28 +31,44 @@ public void Is<T>(string resultTitle, IEnumerable<T> failingData)
3031
failingData.Select(FormatData).ToArray()));
3132
}
3233

33-
public void IsSymmetric<T>(
34-
string firstResultTitle, IEnumerable<T> firstFailingData,
35-
string secondResultTitle, IEnumerable<T> secondFailingData)
34+
public void IsSymmetric<TResult>(
35+
string conventionResultTitle, IEnumerable<TResult> conventionFailingData,
36+
string inverseResultTitle, IEnumerable<TResult> inverseFailingData)
3637
{
3738
conventionResults.Add(new ResultInfo(
38-
firstFailingData.None() ? TestResult.Passed : TestResult.Failed,
39-
firstResultTitle,
39+
conventionFailingData.None() ? TestResult.Passed : TestResult.Failed,
40+
conventionResultTitle,
4041
dataDescription,
41-
firstFailingData.Select(FormatData).ToArray()));
42+
conventionFailingData.Select(FormatData).ToArray()));
4243
conventionResults.Add(new ResultInfo(
43-
secondFailingData.None() ? TestResult.Passed : TestResult.Failed,
44-
secondResultTitle,
44+
inverseFailingData.None() ? TestResult.Passed : TestResult.Failed,
45+
inverseResultTitle,
4546
dataDescription,
46-
secondFailingData.Select(FormatData).ToArray()));
47+
inverseFailingData.Select(FormatData).ToArray()));
48+
}
49+
50+
public void IsSymmetric<TResult>(string conventionResultTitle, string inverseResultTitle,
51+
Func<TResult, bool> isInclusiveData, Func<TResult, bool> dataConformsToConvention,
52+
IEnumerable<TResult> allData)
53+
{
54+
var conventionFailingData = allData.Where(isInclusiveData).Where(d => !dataConformsToConvention(d));
55+
var inverseFailingData = allData.Where(d => !isInclusiveData(d)).Where(dataConformsToConvention);
56+
57+
IsSymmetric(
58+
conventionResultTitle, conventionFailingData,
59+
inverseResultTitle, inverseFailingData);
4760
}
4861

4962
static ConventionReportFailure FormatData<T>(T failingData)
5063
{
5164
var formatter = Convention.Formatters.FirstOrDefault(f => f.CanFormat(failingData));
5265

5366
if (formatter == null)
54-
throw new NoDataFormatterFoundException(typeof(T).Name + " has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`");
67+
{
68+
throw new NoDataFormatterFoundException(
69+
typeof (T).Name +
70+
" has no formatter, add one with `Convention.Formatters.Add(new MyDataFormatter());`");
71+
}
5572

5673
return formatter.Format(failingData);
5774
}

0 commit comments

Comments
 (0)