Skip to content
Closed
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
20 changes: 20 additions & 0 deletions TestAssembly/Collections/Branch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace TestAssembly.Collections
{
using System.Collections;
using System.Collections.Generic;

public class Branch : IEnumerable<Leaf>
{
readonly List<Leaf> items = new List<Leaf>();

public IEnumerator<Leaf> GetEnumerator()
{
return items.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
30 changes: 30 additions & 0 deletions TestAssembly/Collections/Forest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace TestAssembly.Collections
{
using System.Collections;
using System.Collections.Generic;

public class Forest : ICanAdd<Tree>, ICanRemove<Tree>
{
readonly List<Tree> items = new List<Tree>();

public void Add(Tree item)
{
items.Add(item);
}

IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable) items).GetEnumerator();
}

public IEnumerator<Tree> GetEnumerator()
{
return items.GetEnumerator();
}

public bool Remove(Tree item)
{
return items.Remove(item);
}
}
}
9 changes: 9 additions & 0 deletions TestAssembly/Collections/ICanAdd.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace TestAssembly.Collections
{
using System.Collections.Generic;

public interface ICanAdd<T> : IEnumerable<T>
{
void Add(T item);
}
}
9 changes: 9 additions & 0 deletions TestAssembly/Collections/ICanRemove.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace TestAssembly.Collections
{
using System.Collections.Generic;

public interface ICanRemove<T> : IEnumerable<T>
{
bool Remove(T item);
}
}
6 changes: 6 additions & 0 deletions TestAssembly/Collections/Leaf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TestAssembly.Collections
{
public class Leaf
{
}
}
31 changes: 31 additions & 0 deletions TestAssembly/Collections/Tree.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace TestAssembly.Collections
{
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class Tree : ICanAdd<Branch>, IEnumerable<Leaf>
{
readonly List<Branch> items = new List<Branch>();

public void Add(Branch item)
{
items.Add(item);
}

public IEnumerator<Branch> GetEnumerator()
{
return items.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

IEnumerator<Leaf> IEnumerable<Leaf>.GetEnumerator()
{
return items.SelectMany(i => i).GetEnumerator();
}
}
}
6 changes: 6 additions & 0 deletions TestAssembly/TestAssembly.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
<Compile Include="ClassWithPrivateDefaultCtor.cs" />
<Compile Include="ClassWithProtectedDefaultCtor.cs" />
<Compile Include="ClassWithPublicDefaultCtor.cs" />
<Compile Include="Collections\Branch.cs" />
<Compile Include="Collections\Forest.cs" />
<Compile Include="Collections\ICanAdd.cs" />
<Compile Include="Collections\ICanRemove.cs" />
<Compile Include="Collections\Leaf.cs" />
<Compile Include="Collections\Tree.cs" />
<Compile Include="Dtos\AnotherClass.cs" />
<Compile Include="Dtos\BlahDto.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions TestStack.ConventionTests.Tests/CsvReportTests.cs
Original file line number Diff line number Diff line change
@@ -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
{
TypesToVerify =
typeof (Leaf).Assembly.GetExportedTypes()
.Where(t => t.Namespace == typeof (Leaf).Namespace).ToArray()
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace TestStack.ConventionTests.Tests.TestConventions
{
using System;
using System.Collections.Generic;
using System.Linq;
using TestAssembly.Collections;
using TestStack.ConventionTests.ConventionData;
using TestStack.ConventionTests.Internal;

public class CollectionsRelationsConvention : IConvention<Types>
{
public ConventionResult Execute(Types data)
{
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)
};

// I feel so badass for using an anonymous type as generic parameter here :)
return ConventionResult.For(collectionToItemLookup, "well, does the header apply here all across the board? How would that work for CSV?");
}

IEnumerable<Type> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,15 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ConventionAssertionClassTests.cs" />
<Compile Include="CsvReportTests.cs" />
<Compile Include="ProjectBasedConventions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="TestConventions\CollectionsRelationsConvention.cs" />
<Compile Include="TypeBasedConventions.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
5 changes: 4 additions & 1 deletion TestStack.ConventionTests.Tests/TypeBasedConventions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace TestStack.ConventionTests.Tests
{
using System.Linq;
using ApprovalTests;
using ApprovalTests.Reporters;
using NUnit.Framework;
Expand All @@ -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
{
TypesToVerify = itemsToVerify
Expand Down
25 changes: 20 additions & 5 deletions TestStack.ConventionTests/Convention.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
namespace TestStack.ConventionTests
{
using System;
using System.Diagnostics;
using ApprovalTests;
using ApprovalTests.Core.Exceptions;
using TestStack.ConventionTests.Internal;

public static class Convention
{
public static void Is<TData>(IConvention<TData> convention, TData data) where TData : IConventionData
{
data.EnsureHasNonEmptySource();
var result = convention.Execute(data);
var result = Execute(convention, data);

if (result.Failed)
throw new ConventionFailedException(result.Message);
}

public static void IsWithApprovedExeptions<TData>(IConvention<TData> convention, TData data) where TData : IConventionData
static ConventionResult Execute<TData>(IConvention<TData> convention, TData data) where TData : IConventionData
{
data.EnsureHasNonEmptySource();
var result = convention.Execute(data);
return result;
}

public static void IsWithApprovedExeptions<TData>(IConvention<TData> convention, TData data)
where TData : IConventionData
{
var result = Execute(convention, data);

// should we encapsulate Approvals behind Settings?
try
{
Approvals.Verify(result.Message);

Trace.WriteLine(string.Format("{0} has approved exceptions:\r\n\r\n{1}", convention.GetType().Name, result.Message));
Trace.WriteLine(string.Format("{0} has approved exceptions:{2}{2}{1}",
convention.GetType().Name,
result.Message,
Environment.NewLine));
}
catch (ApprovalException ex)
{
throw new ConventionFailedException("Approved exceptions for convention differs\r\n\r\n"+ex.Message, ex);
throw new ConventionFailedException(
"Approved exceptions for convention differs" +
Environment.NewLine +
Environment.NewLine +
ex.Message, ex);
}
}
}
Expand Down
70 changes: 67 additions & 3 deletions TestStack.ConventionTests/Internal/ConventionResult.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
namespace TestStack.ConventionTests.Internal
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

public class ConventionResult
Expand All @@ -18,6 +20,26 @@ public bool Failed
get { return !string.IsNullOrEmpty(Message); }
}

public static ConventionResult For<TResult>(
IEnumerable<TResult> items,
string header)
{

var array = items.ToArray();
var result = new ConventionResult();
if (array.None())
{
return result;
}
// ROUGHSKETCH: We split the job between formatter and reporter. Formatter provides the data, reporter provides the structure
var formatter = new DefaultFormatter(typeof (TResult));
var reporter = new CsvReporter();
return new ConventionResult
{
Message = reporter.Build(array, header, formatter)
};
}

public static ConventionResult For<TResult>(
IEnumerable<TResult> items,
string header,
Expand Down Expand Up @@ -74,7 +96,7 @@ public static ConventionResult ForSymmetric<TResult>(
if (firstArray.Any())
{
message.AppendLine();
message.AppendLine();
message.AppendLine();
}
message.AppendLine(secondHeader);
message.AppendLine(string.Empty.PadRight(secondHeader.Length, '-'));
Expand All @@ -92,8 +114,50 @@ public static ConventionResult ForSymmetric<TResult>(
{
return ForSymmetric(
firstHeader, firstResults, secondHeader,
secondResults,
(item, message) => message.AppendLine(itemDescriptor(item)));
secondResults,
(item, message) => message.AppendLine(itemDescriptor(item)));
}
}

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();
}
}

public class DefaultFormatter
{
readonly Type type;
readonly PropertyInfo[] properties;

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();
}
}
}