Skip to content

Commit

Permalink
Merge pull request #361 from JosephWoodward/master
Browse files Browse the repository at this point in the history
Merged pull request #355 from bangsholt:AddEnumHaveFlag
  • Loading branch information
josephwoodward committed Feb 11, 2016
2 parents f61e5f5 + b601851 commit bc1b830
Show file tree
Hide file tree
Showing 21 changed files with 432 additions and 0 deletions.
26 changes: 26 additions & 0 deletions docs/assertions/shouldHaveFlagNotHaveFlag.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
ShouldHaveFlag/NotHaveFlag
===========

``ShouldHaveFlag`` allows you to assert whether an object is an enum and has a flag specified.

Conversely ``ShouldNotHaveFlag`` allows you to assert the opposite; that an object is an enum but does not have a flag specified.

ShouldHaveFlag
-------

.. literalinclude:: /../src/DocumentationExamples/CodeExamples/ShouldHaveFlagNotHaveFlagExamples/ShouldHaveFlag.codeSample.approved.txt
:language: c#

**Exception**

.. literalinclude:: /../src/DocumentationExamples/CodeExamples/ShouldHaveFlagNotHaveFlagExamples/ShouldHaveFlag.exceptionText.approved.txt

ShouldNotHaveFlag
-------

.. literalinclude:: /../src/DocumentationExamples/CodeExamples/ShouldHaveFlagNotHaveFlagExamples/ShouldNotHaveFlag.codeSample.approved.txt
:language: c#

**Exception**

.. literalinclude:: /../src/DocumentationExamples/CodeExamples/ShouldHaveFlagNotHaveFlagExamples/ShouldNotHaveFlag.exceptionText.approved.txt
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Shouldly has plenty of different assertions, have a look under the assertions fo
assertions/shouldMatchApproved
assertions/shouldBeTrueFalse
assertions/shouldBeNullShouldNotBeNull
assertions/shouldHaveFlagNotHaveFlag
exampleClasses
contributing
configuration
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var actual = TestEnum.FlagTwo;
var value = TestEnum.FlagOne;
actual.ShouldHaveFlag(value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
shouldMethod
should have flag
TestEnum.FlagOne
but had
TestEnum.FlagTwo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var actual = TestEnum.FlagTwo;
var value = TestEnum.FlagOne;
actual.ShouldHaveFlag(value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
shouldMethod
should have flag
TestEnum.FlagOne
but had
TestEnum.FlagTwo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var actual = TestEnum.FlagOne;
var value = TestEnum.FlagOne;
actual.ShouldNotHaveFlag(value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
shouldMethod
should not have flag
TestEnum.FlagOne
but it had
TestEnum.FlagOne
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var actual = TestEnum.FlagOne;
var value = TestEnum.FlagOne;
actual.ShouldNotHaveFlag(value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
shouldMethod
should not have flag
TestEnum.FlagOne
but it had
TestEnum.FlagOne
1 change: 1 addition & 0 deletions src/DocumentationExamples/DocumentationExamples.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<Compile Include="DocExampleWriter.cs" />
<Compile Include="ShouldBeNullNotNullExamples.cs" />
<Compile Include="ShouldBeTrueFalseExamples.cs" />
<Compile Include="ShouldHaveFlagNotHaveFlagExamples.cs" />
<Compile Include="ShouldMatchApprovedExamples.cs" />
<Compile Include="ShouldNotBeExamples.cs" />
<Compile Include="ShouldBeExamples.cs" />
Expand Down
55 changes: 55 additions & 0 deletions src/DocumentationExamples/ShouldHaveFlagNotHaveFlagExamples.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using Shouldly.ShouldlyExtensionMethods;
using Xunit;
using Xunit.Abstractions;

namespace DocumentationExamples
{
public class ShouldHaveFlagNotHaveFlagExamples
{
readonly ITestOutputHelper _testOutputHelper;

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

[Fact]
public void ShouldHaveFlag()
{
DocExampleWriter.Document(() =>
{
var actual = TestEnum.FlagTwo;
var value = TestEnum.FlagOne;
actual.ShouldHaveFlag(value);
}, _testOutputHelper);
}


[Fact]
public void ShouldNotHaveFlag()
{
DocExampleWriter.Document(() =>
{
var actual = TestEnum.FlagOne;
var value = TestEnum.FlagOne;
actual.ShouldNotHaveFlag(value);
}, _testOutputHelper);
}

[Flags]
public enum TestEnum
{
FlagOne = 1,
FlagTwo = 2,
FlagThree = 4
}

public enum TestEnumWithoutFlagAttribute
{
FlagOne,
FlagTwo,
FlagThree
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Shouldly.MessageGenerators
{
internal class ShouldHaveFlagMessageGenerator : ShouldlyMessageGenerator
{
public override bool CanProcess(IShouldlyAssertionContext context)
{
return context.ShouldMethod == "ShouldHaveFlag";
}

public override string GenerateErrorMessage(IShouldlyAssertionContext context)
{
var codePart = context.CodePart;
var expectedValue = context.Expected.ToStringAwesomely();

var actual = context.Actual.ToStringAwesomely();
var actualString = codePart == actual ? " did not" : $@" had
{actual}";

return $@"{codePart}
should have flag
{expectedValue}
but{actualString}";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Shouldly.MessageGenerators
{
internal class ShouldNotHaveFlagMessageGenerator : ShouldlyMessageGenerator
{
public override bool CanProcess(IShouldlyAssertionContext context)
{
return context.ShouldMethod == "ShouldNotHaveFlag";
}

public override string GenerateErrorMessage(IShouldlyAssertionContext context)
{
var codePart = context.CodePart;
var expectedValue = context.Expected.ToStringAwesomely();

var actual = context.Actual.ToStringAwesomely();
var actualString = codePart == actual ? " had" : $@" it had
{actual}";

return $@"{codePart}
should not have flag
{expectedValue}
but{actualString}";
}
}
}
3 changes: 3 additions & 0 deletions src/Shouldly.Shared/Shouldly.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldContainMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldContainPredicateMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldContainWithinRangeMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldHaveFlagMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldlyMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldNotHaveFlagMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldNotMatchMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldNotThrowMessageGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MessageGenerators\ShouldSatisfyAllConditionsMessageGenerator.cs" />
Expand All @@ -89,6 +91,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ShouldlyExtensionMethods\ShouldBeBooleanExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldlyExtensionMethods\ShouldBeDictionaryTestExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldlyExtensionMethods\ShouldBeEnumerableTestExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldlyExtensionMethods\ShouldBeEnumExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldlyExtensionMethods\ShouldBeGtLtTestExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldlyExtensionMethods\ShouldBeNullExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShouldlyExtensionMethods\ShouldBePositiveNegativeTestExtensions.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using JetBrains.Annotations;

#if PORTABLE
using System.Reflection;
#endif

namespace Shouldly.ShouldlyExtensionMethods
{
public static class ShouldHaveEnumExtensions
{
public static void ShouldHaveFlag(this Enum actual, Enum expectedFlag)
=> ShouldHaveFlag(actual, expectedFlag, () => null);

public static void ShouldHaveFlag(this Enum actual, Enum expectedFlag, string customMessage)
=> ShouldHaveFlag(actual, expectedFlag, () => customMessage);

public static void ShouldHaveFlag(this Enum actual, Enum expectedFlag, [InstantHandle] Func<string> customMessage)
{
CheckEnumHasFlagAttribute(actual);
if (!actual.HasFlag(expectedFlag))
{
throw new ShouldAssertException(new ExpectedActualShouldlyMessage(expectedFlag, actual, customMessage).ToString());
}
}

public static void ShouldNotHaveFlag(this Enum actual, Enum expectedFlag)
=> ShouldNotHaveFlag(actual, expectedFlag, () => null);

public static void ShouldNotHaveFlag(this Enum actual, Enum expectedFlag, string customMessage)
=> ShouldNotHaveFlag(actual, expectedFlag, () => customMessage);

public static void ShouldNotHaveFlag(this Enum actual, Enum expectedFlag,
[InstantHandle] Func<string> customMessage)
{
CheckEnumHasFlagAttribute(actual);
if (actual.HasFlag(expectedFlag))
{
throw new ShouldAssertException(new ExpectedActualShouldlyMessage(expectedFlag, actual, customMessage).ToString());
}
}

static void CheckEnumHasFlagAttribute(Enum actual)
{
#if PORTABLE
if (!actual.GetType().GetTypeInfo().IsDefined(typeof(FlagsAttribute), false))
#else
if (!actual.GetType().IsDefined(typeof(FlagsAttribute), false))
#endif
{
throw new ArgumentException("Enum doesn't have Flags attribute", nameof(actual));
}
}

#if net35
/* If the .NET Framework doesn't have a HasFlag, patch in our own version.
Made by decompiling the HasFlag function on enum in .NET Framework version 4.5.1 */
static bool HasFlag(this Enum enumeration, Enum value)
{
if (enumeration == null)
{
return false;
}

if (value == null)
{
throw new ArgumentException(nameof(value));
}

if (!Enum.IsDefined(enumeration.GetType(), value))
{
throw new ArgumentException($"Enumeration type mismatch. The flag is of type '{value.GetType()}', was expecting {enumeration.GetType()}");
}

var longValue = Convert.ToUInt64(value);

return (Convert.ToUInt64(enumeration) & longValue) == longValue;
}
#endif
}
}
2 changes: 2 additions & 0 deletions src/Shouldly.Shared/ShouldlyMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ internal abstract class ShouldlyMessage
{
static readonly IEnumerable<ShouldlyMessageGenerator> ShouldlyMessageGenerators = new ShouldlyMessageGenerator[]
{
new ShouldHaveFlagMessageGenerator(),
new ShouldNotHaveFlagMessageGenerator(),
new ShouldBeNullOrEmptyMessageGenerator(),
new ShouldBeEmptyMessageGenerator(),
new ShouldAllBeMessageGenerator(),
Expand Down
78 changes: 78 additions & 0 deletions src/Shouldly.Tests.Shared/ShouldHaveFlag/ShouldHaveFlagScenario.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using Shouldly.ShouldlyExtensionMethods;
using Shouldly.Tests.Strings;
using Xunit;

namespace Shouldly.Tests.Shared.ShouldHaveFlag
{
public class ShouldHaveFlagScenario
{
[Fact]
public void FlagScenarioShouldFail()
{
var actual = TestEnum.FlagTwo;
var value = TestEnum.FlagOne;

Verify.ShouldFail(() => actual.ShouldHaveFlag(value, "Some additional context"),
errorWithSource:
@"Verify
should have flag
TestEnum.FlagOne
but had
TestEnum.FlagTwo
Additional Info:
Some additional context",
errorWithoutSource:
@"TestEnum.FlagTwo
should have flag
TestEnum.FlagOne
but did not
Additional Info:
Some additional context");
}

[Fact]
public void ShouldThrowException()
{
var actual = TestEnumWithoutFlagAttribute.FlagOne;
var value = TestEnumWithoutFlagAttribute.FlagOne;

Should.Throw<ArgumentException>(() => actual.ShouldHaveFlag(value));
}

[Fact]
public void ShouldPassOneFlagSet()
{
var actual = TestEnum.FlagOne;
var value = TestEnum.FlagOne;

actual.ShouldHaveFlag(value);
}

[Fact]
public void ShouldPassTwoFlagsSet()
{
var actual = TestEnum.FlagOne | TestEnum.FlagTwo;
var value = TestEnum.FlagTwo;

actual.ShouldHaveFlag(value);
}
}

[Flags]
public enum TestEnum
{
FlagOne = 1,
FlagTwo = 2,
FlagThree = 4
}

public enum TestEnumWithoutFlagAttribute
{
FlagOne,
FlagTwo,
FlagThree
}
}

0 comments on commit bc1b830

Please sign in to comment.