Skip to content

Commit

Permalink
Merge pull request #368 from ssiko/ShouldHaveSingleItem
Browse files Browse the repository at this point in the history
Added ShouldHaveSingleItem for Enumerables.
  • Loading branch information
JakeGinnivan committed Apr 4, 2016
2 parents 029d702 + ae197af commit d941c6c
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var maggie = new Person() { Name = "Maggie" };
var homer = new Person() { Name = "Homer" };
var simpsonsBabies = new List<Person>() { homer, maggie };
simpsonsBabies.ShouldHaveSingleItem();
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
simpsonsBabies
should have single item but had
2
items and was
[Homer, Maggie]
1 change: 1 addition & 0 deletions src/DocumentationExamples/DocumentationExamples.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="EnumerableShouldHaveSingleItemExamples.cs" />
<Compile Include="ShouldSatisfyAllConditionsExamples.cs" />
<Compile Include="ShouldNotThrowExamples.cs" />
<Compile Include="ShouldCompleteInExamples.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Collections.Generic;
using Shouldly;
using Simpsons;
using Xunit;
using Xunit.Abstractions;

namespace DocumentationExamples
{
public class EnumerableShouldHaveSingleItemExamples
{
readonly ITestOutputHelper _testOutputHelper;

public EnumerableShouldHaveSingleItemExamples(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}

[Fact]
public void ShouldHaveSingleItem()
{
DocExampleWriter.Document(() =>
{
var maggie = new Person() { Name = "Maggie" };
var homer = new Person() { Name = "Homer" };
var simpsonsBabies = new List<Person>() { homer, maggie };
simpsonsBabies.ShouldHaveSingleItem();
}, _testOutputHelper);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using Shouldly.DifferenceHighlighting;
using System.Collections;
using System.Linq;

namespace Shouldly.MessageGenerators
{
internal class ShouldHaveSingleItemMessageGenerator : ShouldlyMessageGenerator
{
const string ShouldBeAssertion = "ShouldHaveSingleItem";

public override bool CanProcess(IShouldlyAssertionContext context)
{
return context.ShouldMethod.Equals(ShouldBeAssertion, StringComparison.OrdinalIgnoreCase);
}

public override string GenerateErrorMessage(IShouldlyAssertionContext context)
{
var codePart = context.CodePart;
var expected = context.Expected.ToStringAwesomely();
var count = (context.Expected ?? Enumerable.Empty<object>()).As<IEnumerable>().Cast<object>().Count();
if (codePart != "null")
{
return
$@"{codePart}
{context.ShouldMethod.PascalToSpaced()} but had
{count}
items and was
{expected}";
}
else
{
return
$@"{expected}
{context.ShouldMethod.PascalToSpaced()} but had
{count}
items";
}
}
}
}
1 change: 1 addition & 0 deletions src/Shouldly.Shared/Shouldly.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldBeNullOrEmptyMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldBeNullOrWhiteSpaceMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldBePositiveMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldHaveSingleItemMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldBeSubsetOfMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldBeTypeMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldBeUniqueMessageGenerator.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public static void ShouldBeEmpty<T>(this IEnumerable<T> actual, string customMes

public static void ShouldBeEmpty<T>(this IEnumerable<T> actual, [InstantHandle] Func<string> customMessage)
{
if (actual == null || (actual != null && actual.Count() != 0))
if (actual == null || actual.Any())
throw new ShouldAssertException(new ExpectedShouldlyMessage(actual, customMessage).ToString());
}

Expand All @@ -143,10 +143,28 @@ public static void ShouldNotBeEmpty<T>(this IEnumerable<T> actual, string custom

public static void ShouldNotBeEmpty<T>(this IEnumerable<T> actual, [InstantHandle] Func<string> customMessage)
{
if (actual == null || actual != null && !actual.Any())
if (actual == null || !actual.Any())
throw new ShouldAssertException(new ExpectedShouldlyMessage(actual, customMessage).ToString());
}

public static T ShouldHaveSingleItem<T>(this IEnumerable<T> actual)
{
return ShouldHaveSingleItem(actual, () => null);
}

public static T ShouldHaveSingleItem<T>(this IEnumerable<T> actual, string customMessage)
{
return ShouldHaveSingleItem(actual, () => customMessage);
}

public static T ShouldHaveSingleItem<T>(this IEnumerable<T> actual, [InstantHandle] Func<string> customMessage)
{
if (actual == null || actual.Count() != 1)
throw new ShouldAssertException(new ExpectedShouldlyMessage(actual, customMessage).ToString());

return actual.Single();
}

public static void ShouldContain(this IEnumerable<float> actual, float expected, double tolerance)
{
ShouldContain(actual, expected, tolerance, () => null);
Expand Down
1 change: 1 addition & 0 deletions src/Shouldly.Shared/ShouldlyMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ internal abstract class ShouldlyMessage
new ShouldBeIgnoringOrderMessageGenerator(),
new ShouldSatisfyAllConditionsMessageGenerator(),
new ShouldBeSubsetOfMessageGenerator(),
new ShouldHaveSingleItemMessageGenerator(),
new ShouldBeBooleanMessageGenerator(),
new ShouldNotThrowMessageGenerator(),
new ShouldNotMatchMessageGenerator(),
Expand Down
43 changes: 43 additions & 0 deletions src/Shouldly.Tests.Shared/ShouldHaveSingleItem/ArrayScenario.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Xunit;
using System.Collections.Generic;
using Shouldly.Tests.Strings;

namespace Shouldly.Tests.Shared.ShouldHaveSingleItem
{
public class ArrayScenario
{

[Fact]
public void ArrayScenarioShouldFail()
{
Verify.ShouldFail(() =>
new[] { 1, 2 }.ShouldHaveSingleItem("Some additional context"),

errorWithSource:
@"new[] { 1, 2 }
should have single item but had
2
items and was
[1, 2]
Additional Info:
Some additional context",

errorWithoutSource:
@"[1, 2]
should have single item but had
2
items
Additional Info:
Some additional context");
}

[Fact]
public void ShouldPass()
{
int result = new[] { 1 }.ShouldHaveSingleItem();
result.ShouldBe(1);
}
}
}
1 change: 1 addition & 0 deletions src/Shouldly.Tests.Shared/Shouldly.Tests.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ShouldBeSameAs\BasicScenario.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldBeSameAs\BoxedIntScenario.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldBeSameAs\SameListDifferentInstanceScenario.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldHaveSingleItem\ArrayScenario.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldBeSubsetOf\DecimalArrayScenario.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldBeSubsetOf\FloatArrayScenario.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldBeSubsetOf\IntegerArrayScenario.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute(@"Shouldly.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e3aa2a20de74f360af7742a2b21b409d570722b14ec3d14283a0d89e8147855d1097fbf084d7b3a8bbd1bfe50a589254ce50ee70bf530f23e280e13eeeff3813a6863a8dffa604f6a749628fc82f449e8a5717a4a70787a3f55547f1a2ad8fffafe8945f327dc7a66887b81c7bb5b8f06651f51a7e640e150a7c4cf1049041ca")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute(@"Shouldly.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e3aa2a20de74f360af7742a2b21b409d570722b14ec3d14283a0d89e8147855d1097fbf084d7b3a8bbd1bfe50a589254ce50ee70bf530f23e280e13eeeff3813a6863a8dffa604f6a749628fc82f449e8a5717a4a70787a3f55547f1a2ad8fffafe8945f327dc7a66887b81c7bb5b8f06651f51a7e640e150a7c4cf1049041ca")]
[assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.0", FrameworkDisplayName=".NET Framework 4")]

namespace Shouldly
Expand Down Expand Up @@ -181,6 +181,9 @@ public class static ShouldBeEnumerableTestExtensions
public static void ShouldContain(this System.Collections.Generic.IEnumerable<double> actual, double expected, double tolerance) { }
public static void ShouldContain(this System.Collections.Generic.IEnumerable<double> actual, double expected, double tolerance, string customMessage) { }
public static void ShouldContain(this System.Collections.Generic.IEnumerable<double> actual, double expected, double tolerance, [JetBrains.Annotations.InstantHandleAttribute()] System.Func<string> customMessage) { }
public static T ShouldHaveSingleItem<T>(this System.Collections.Generic.IEnumerable<T> actual) { }
public static T ShouldHaveSingleItem<T>(this System.Collections.Generic.IEnumerable<T> actual, string customMessage) { }
public static T ShouldHaveSingleItem<T>(this System.Collections.Generic.IEnumerable<T> actual, [JetBrains.Annotations.InstantHandleAttribute()] System.Func<string> customMessage) { }
public static void ShouldNotBeEmpty<T>(this System.Collections.Generic.IEnumerable<T> actual) { }
public static void ShouldNotBeEmpty<T>(this System.Collections.Generic.IEnumerable<T> actual, string customMessage) { }
public static void ShouldNotBeEmpty<T>(this System.Collections.Generic.IEnumerable<T> actual, [JetBrains.Annotations.InstantHandleAttribute()] System.Func<string> customMessage) { }
Expand Down

0 comments on commit d941c6c

Please sign in to comment.