Skip to content

Commit

Permalink
Adding support for .NET6 TimeOnly struct
Browse files Browse the repository at this point in the history
  • Loading branch information
iliashkolyar committed Mar 13, 2022
1 parent b66f77d commit 9d66732
Show file tree
Hide file tree
Showing 8 changed files with 1,659 additions and 0 deletions.
28 changes: 28 additions & 0 deletions Src/FluentAssertions/AssertionExtensions.cs
Expand Up @@ -456,6 +456,26 @@ public static NullableDateOnlyAssertions Should(this DateOnly? actualValue)
return new NullableDateOnlyAssertions(actualValue);
}

/// <summary>
/// Returns an <see cref="TimeOnlyAssertions"/> object that can be used to assert the
/// current <see cref="TimeOnly"/>.
/// </summary>
[Pure]
public static TimeOnlyAssertions Should(this TimeOnly actualValue)
{
return new TimeOnlyAssertions(actualValue);
}

/// <summary>
/// Returns an <see cref="NullableTimeOnlyAssertions"/> object that can be used to assert the
/// current nullable <see cref="TimeOnly"/>.
/// </summary>
[Pure]
public static NullableTimeOnlyAssertions Should(this TimeOnly? actualValue)
{
return new NullableTimeOnlyAssertions(actualValue);
}

#endif

/// <summary>
Expand Down Expand Up @@ -926,6 +946,14 @@ public static void Should<TAssertions>(this DateOnlyAssertions<TAssertions> _)
InvalidShouldCall();
}

/// <inheritdoc cref="Should(ExecutionTimeAssertions)" />
[Obsolete("You are asserting the 'AndConstraint' itself. Remove the 'Should()' method directly following 'And'", error: true)]
public static void Should<TAssertions>(this TimeOnlyAssertions<TAssertions> _)
where TAssertions : TimeOnlyAssertions<TAssertions>
{
InvalidShouldCall();
}

#endif

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions Src/FluentAssertions/Formatting/Formatter.cs
Expand Up @@ -33,6 +33,7 @@ public static class Formatter
new DateTimeOffsetValueFormatter(),
#if NET6_0_OR_GREATER
new DateOnlyValueFormatter(),
new TimeOnlyValueFormatter(),
#endif
new TimeSpanValueFormatter(),
new Int32ValueFormatter(),
Expand Down
30 changes: 30 additions & 0 deletions Src/FluentAssertions/Formatting/TimeOnlyValueFormatter.cs
@@ -0,0 +1,30 @@
using System;
using System.Globalization;

#if NET6_0_OR_GREATER

namespace FluentAssertions.Formatting
{
public class TimeOnlyValueFormatter : IValueFormatter
{
/// <summary>
/// Indicates whether the current <see cref="IValueFormatter"/> can handle the specified <paramref name="value"/>.
/// </summary>
/// <param name="value">The value for which to create a <see cref="string"/>.</param>
/// <returns>
/// <c>true</c> if the current <see cref="IValueFormatter"/> can handle the specified value; otherwise, <c>false</c>.
/// </returns>
public bool CanHandle(object value)
{
return value is TimeOnly;
}

public void Format(object value, FormattedObjectGraph formattedGraph, FormattingContext context, FormatChild formatChild)
{
var timeOnly = (TimeOnly)value;
formattedGraph.AddFragment(timeOnly.ToString("<HH:mm:ss.fff>", CultureInfo.InvariantCulture));
}
}
}

#endif
105 changes: 105 additions & 0 deletions Src/FluentAssertions/Primitives/NullableTimeOnlyAssertions.cs
@@ -0,0 +1,105 @@
using System;
using System.Diagnostics;
using FluentAssertions.Execution;

#if NET6_0_OR_GREATER

namespace FluentAssertions.Primitives
{
/// <summary>
/// Contains a number of methods to assert that a nullable <see cref="TimeOnly"/> or
/// </summary>
[DebuggerNonUserCode]
public class NullableTimeOnlyAssertions : NullableTimeOnlyAssertions<NullableTimeOnlyAssertions>
{
public NullableTimeOnlyAssertions(TimeOnly? value)
: base(value)
{
}
}

/// <summary>
/// Contains a number of methods to assert that a nullable <see cref="TimeOnly"/> or
/// </summary>
[DebuggerNonUserCode]
public class NullableTimeOnlyAssertions<TAssertions> : TimeOnlyAssertions<TAssertions>
where TAssertions : NullableTimeOnlyAssertions<TAssertions>
{
public NullableTimeOnlyAssertions(TimeOnly? value)
: base(value)
{
}

/// <summary>
/// Asserts that a nullable <see cref="TimeOnly"/> value is not <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> HaveValue(string because = "", params object[] becauseArgs)
{
Execute.Assertion
.ForCondition(Subject.HasValue)
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:nullable time} to have a value{reason}, but found {0}.", Subject);

return new AndConstraint<TAssertions>((TAssertions)this);
}

/// <summary>
/// Asserts that a nullable <see cref="TimeOnly"/> value is not <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> NotBeNull(string because = "", params object[] becauseArgs)
{
return HaveValue(because, becauseArgs);
}

/// <summary>
/// Asserts that a nullable <see cref="TimeOnly"/> value is <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> NotHaveValue(string because = "", params object[] becauseArgs)
{
Execute.Assertion
.ForCondition(!Subject.HasValue)
.BecauseOf(because, becauseArgs)
.FailWith("Did not expect {context:nullable time} to have a value{reason}, but found {0}.", Subject);

return new AndConstraint<TAssertions>((TAssertions)this);
}

/// <summary>
/// Asserts that a nullable <see cref="TimeOnly"/> value is <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> BeNull(string because = "", params object[] becauseArgs)
{
return NotHaveValue(because, becauseArgs);
}
}
}

#endif

0 comments on commit 9d66732

Please sign in to comment.