Skip to content

Commit

Permalink
Added TimeOnly support
Browse files Browse the repository at this point in the history
  • Loading branch information
aivascu committed Apr 14, 2024
1 parent 138e809 commit 33022aa
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 0 deletions.
1 change: 1 addition & 0 deletions Src/AutoFixture/DefaultPrimitiveBuilders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public virtual IEnumerator<ISpecimenBuilder> GetEnumerator()
yield return new RandomDateTimeSequenceGenerator();
#if NET6_0_OR_GREATER
yield return new RandomDateOnlySequenceGenerator();
yield return new RandomTimeOnlySequenceGenerator();
#endif
yield return new BooleanSwitch();
yield return new GuidGenerator();
Expand Down
71 changes: 71 additions & 0 deletions Src/AutoFixture/RandomTimeOnlySequenceGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#if NET6_0_OR_GREATER

using System;
using System.Reflection;
using AutoFixture.Kernel;

namespace AutoFixture;

/// <summary>
/// Creates random <see cref="TimeOnly"/> specimens.
/// </summary>
/// <remarks>
/// The generated <see cref="TimeOnly"/> values will be within
/// a range of ± six hours from noon,
/// unless a different range has been specified in the constructor.
/// </remarks>
public class RandomTimeOnlySequenceGenerator : ISpecimenBuilder
{
private static readonly TimeOnly Default = new(12, 0);
private readonly RandomNumericSequenceGenerator randomizer;

/// <summary>
/// Initializes a new instance of the <see cref="RandomTimeOnlySequenceGenerator"/> class.
/// </summary>
public RandomTimeOnlySequenceGenerator()
: this(Default.AddHours(-6), Default.AddHours(6))
{
}

/// <summary>
/// Initializes a new instance of the <see cref="RandomTimeOnlySequenceGenerator"/> class
/// for a specific range of time.
/// </summary>
/// <param name="minTime">The lower bound of the time range.</param>
/// <param name="maxTime">The upper bound of the time range.</param>
/// <exception cref="ArgumentException">
/// <paramref name="minTime"/> is greater than <paramref name="maxTime"/>.
/// </exception>
public RandomTimeOnlySequenceGenerator(TimeOnly minTime, TimeOnly maxTime)
{
if (minTime >= maxTime)
{
throw new ArgumentException("The 'minTime' argument must be less than the 'maxTime'.");
}

this.randomizer = new RandomNumericSequenceGenerator(minTime.Ticks, maxTime.Ticks);
}

/// <summary>
/// Creates a new <see cref="TimeOnly"/> specimen based on a request.
/// </summary>
/// <param name="request">The request that describes what to create.</param>
/// <param name="context">Not used.</param>
/// <returns>
/// A new <see cref="TimeOnly"/> specimen, if <paramref name="request"/> is a request for a
/// <see cref="TimeOnly"/> value; otherwise, a <see cref="NoSpecimen"/> instance.
/// </returns>
public object Create(object request, ISpecimenContext context)
{
if (context is null) throw new ArgumentNullException(nameof(context));

if (!typeof(TimeOnly).GetTypeInfo().IsAssignableFrom(request as Type))
{
return new NoSpecimen();
}

var ticks = (long)this.randomizer.Create(typeof(long), context);
return new TimeOnly(ticks);
}
}
#endif
1 change: 1 addition & 0 deletions Src/AutoFixtureUnitTest/DefaultPrimitiveBuildersTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public void SutHasCorrectContents()
typeof(RandomDateTimeSequenceGenerator),
#if NET6_0_OR_GREATER
typeof(RandomDateOnlySequenceGenerator),
typeof(RandomTimeOnlySequenceGenerator),
#endif
typeof(BooleanSwitch),
typeof(GuidGenerator),
Expand Down
168 changes: 168 additions & 0 deletions Src/AutoFixtureUnitTest/RandomTimeOnlySequenceGeneratorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#if NET6_0_OR_GREATER

using System;
using System.Linq;
using AutoFixture;
using AutoFixture.Kernel;
using AutoFixtureUnitTest.Kernel;
using Xunit;

namespace AutoFixtureUnitTest;

public class RandomTimeOnlySequenceGeneratorTest
{
[Fact]
public void SutIsSpecimenBuilder()
{
// Arrange & Act
var sut = new RandomTimeOnlySequenceGenerator();

// Assert
Assert.IsAssignableFrom<ISpecimenBuilder>(sut);
}

[Fact]
public void InitializeWithInvertedRangeThrowsArgumentException()
{
// Arrange
var minimum = new TimeOnly(12, 03, 21);
var maximum = minimum.AddHours(3);

// Act & assert
Assert.Throws<ArgumentException>(
() => new RandomTimeOnlySequenceGenerator(maximum, minimum));
}

[Fact]
public void InitializeWithEmptyRangeThrowsArgumentException()
{
// Arrange
var time = new TimeOnly(14, 13, 09);

// Act & assert
Assert.Throws<ArgumentException>(
() => new RandomTimeOnlySequenceGenerator(time, time));
}

[Fact]
public void CreateWithNullRequestReturnsNoSpecimen()
{
// Arrange
var sut = new RandomTimeOnlySequenceGenerator();
var dummyContainer = new DelegatingSpecimenContext();

// Act
var result = sut.Create(null, dummyContainer);

// Assert
Assert.Equal(new NoSpecimen(), result);
}

[Fact]
public void CreateWithNullContextThrowsArgumentNullException()
{
// Arrange
var sut = new RandomTimeOnlySequenceGenerator();

// Act & assert
Assert.Throws<ArgumentNullException>(
() => sut.Create(typeof(TimeOnly), null));
}

[Theory]
[InlineData("")]
[InlineData(default(int))]
[InlineData(default(bool))]
public void CreateWithNonTypeRequestReturnsNoSpecimen(object request)
{
// Arrange
var sut = new RandomTimeOnlySequenceGenerator();
var dummyContainer = new DelegatingSpecimenContext();

// Act
var result = sut.Create(request, dummyContainer);

// Assert
Assert.Equal(new NoSpecimen(), result);
}

[Theory]
[InlineData(typeof(string))]
[InlineData(typeof(object))]
[InlineData(typeof(int))]
[InlineData(typeof(bool))]
public void CreateWithNonTimeOnlyTypeRequestReturnsNoSpecimen(Type request)
{
// Arrange
var sut = new RandomTimeOnlySequenceGenerator();
var dummyContainer = new DelegatingSpecimenContext();

// Act
var result = sut.Create(request, dummyContainer);

// Assert
Assert.Equal(new NoSpecimen(), result);
}

[Fact]
public void CreateWithTimeOnlyRequestReturnsTimeOnlyValue()
{
// Arrange
var sut = new RandomTimeOnlySequenceGenerator();
var dummyContainer = new DelegatingSpecimenContext();

// Act
var result = sut.Create(typeof(TimeOnly), dummyContainer);

// Assert
Assert.IsAssignableFrom<TimeOnly>(result);
}

[Fact]
public void CreateWithTimeOnlyRequestReturnsADateWithinARangeOfPlusMinusTwoYearsFromNoon()
{
// Arrange
var current = new TimeOnly(12, 00);
var twoHoursAgo = current.AddHours(-6);
var twoHoursForward = current.AddHours(6);
var sut = new RandomTimeOnlySequenceGenerator();
// Act
var dummyContainer = new DelegatingSpecimenContext();
var result = (TimeOnly)sut.Create(typeof(TimeOnly), dummyContainer);
// Assert
Assert.InRange(result, twoHoursAgo, twoHoursForward);
}

[Fact]
public void CreateWithMultipleRequestsReturnsDifferentTimes()
{
// Arrange
const int requestCount = 10;
var times = Enumerable.Range(1, requestCount);
var sut = new RandomTimeOnlySequenceGenerator();
var dummyContainer = new DelegatingSpecimenContext();

// Act
var results = times
.Select(t => sut.Create(typeof(TimeOnly), dummyContainer))
.Cast<TimeOnly>();

// Assert
Assert.Equal(requestCount, results.Distinct().Count());
}

[Fact]
public void CreateWithTimeOnlyRequestAndTimeRangeReturnsValueWithinThatRange()
{
// Arrange
var minimum = new TimeOnly(13, 00);
var maximum = minimum.AddHours(3);
var sut = new RandomTimeOnlySequenceGenerator(minimum, maximum);
// Act
var dummyContainer = new DelegatingSpecimenContext();
var result = (TimeOnly)sut.Create(typeof(TimeOnly), dummyContainer);
// Assert
Assert.InRange(result, minimum, maximum);
}
}
#endif
1 change: 1 addition & 0 deletions Src/AutoFixtureUnitTest/SpecimenWithEverything.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public virtual bool PublicVirtualInstanceQueryMethod()
public DateTime? NullableDateTime { get; set; }
#if NET6_0_OR_GREATER
public DateOnly? NullableDateOnly { get; set; }
public TimeOnly? NullableTimeOnly { get; set; }
#endif
public decimal? NullableDecimal { get; set; }
public double? NullableDouble { get; set; }
Expand Down

0 comments on commit 33022aa

Please sign in to comment.