Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DateTime ranged relay #1162

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 65 additions & 0 deletions Src/AutoFixture/DataAnnotations/DateTimeRangedRequestRelay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Globalization;
using AutoFixture.Kernel;

namespace AutoFixture.DataAnnotations
{
/// <summary>
/// Handles <see cref="RangedRequest"/> of DateTime type by forwarding requests
/// to the <see cref="RangedNumberRequest"/> with min and max DateTime as ticks values.
/// </summary>
public class DateTimeRangedRequestRelay : ISpecimenBuilder
{
/// <inheritdoc />
public object Create(object request, ISpecimenContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));

var rangedRequest = request as RangedRequest;

if (rangedRequest == null)
return new NoSpecimen();

if (rangedRequest.MemberType != typeof(DateTime))
return new NoSpecimen();

return CreateDateTimeSpecimen(rangedRequest, context);
}

private static object CreateDateTimeSpecimen(RangedRequest rangedRequest, ISpecimenContext context)
{
if (!(rangedRequest.Minimum is string) || !(rangedRequest.Maximum is string))
return new NoSpecimen();

var range = ParseTimeSpanRange(rangedRequest);
return RandomizeDateTimeInRange(range, context);
}

private static DateTimeRange ParseTimeSpanRange(RangedRequest rangedRequest)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ParseDateTimeRange, right?

{
return new DateTimeRange
{
Min = DateTime.Parse((string)rangedRequest.Minimum, CultureInfo.CurrentCulture),
Max = DateTime.Parse((string)rangedRequest.Maximum, CultureInfo.CurrentCulture)
};
}

private static object RandomizeDateTimeInRange(DateTimeRange range, ISpecimenContext context)
{
var ticksInRange = context.Resolve(
new RangedNumberRequest(typeof(long), range.Min.Ticks, range.Max.Ticks));

if (ticksInRange is NoSpecimen)
return new NoSpecimen();

return new DateTime((long)ticksInRange);
}

private struct DateTimeRange
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We could also make it a readonly struct, as it's not supposed to be mutated.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the TimeSpanRange also need to be updated?

{
public DateTime Min { get; set; }

public DateTime Max { get; set; }
}
}
}
1 change: 1 addition & 0 deletions Src/AutoFixture/Fixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public Fixture(ISpecimenBuilder engine, MultipleRelay multiple)
new RangeAttributeRelay(),
new NumericRangedRequestRelay(),
new EnumRangedRequestRelay(),
new DateTimeRangedRequestRelay(),
new TimeSpanRangedRequestRelay(),
new StringLengthAttributeRelay(),
new MinAndMaxLengthAttributeRelay(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using AutoFixture.DataAnnotations;
using AutoFixture.Kernel;
using AutoFixtureUnitTest.Kernel;
using Xunit;

namespace AutoFixtureUnitTest.DataAnnotations
{
public class DateTimeRangedRequestRelayTest
{
[Fact]
public void SutShouldBeASpecimenBuilder()
{
// Arrange
var sut = new DateTimeRangedRequestRelay();

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

[Fact]
public void ShouldFailForNullContext()
{
// Arrange
var sut = new DateTimeRangedRequestRelay();
var request = new object();

// Act & Assert
Assert.ThrowsAny<ArgumentNullException>(() =>
sut.Create(request, null));
}

[Fact]
public void ShouldNotHandleRequestIfMemberTypeIsNotDateTime()
{
// Arrange
var sut = new DateTimeRangedRequestRelay();
var request =
new RangedRequest(memberType: typeof(object), operandType: typeof(object), minimum: 0, maximum: 1);
var context = new DelegatingSpecimenContext();

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

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

[Fact]
public void ShouldHandleRequestOfDateTimeType()
{
// Arrange
var sut = new DateTimeRangedRequestRelay();
var request =
new RangedRequest(memberType: typeof(DateTime), operandType: typeof(DateTime), minimum: "2020-01-01 00:00:00",
maximum: "2020-12-31 23:59:59");

var context = new DelegatingSpecimenContext
{
OnResolve = _ => new DateTime(2020, 06, 15, 12, 30, 30).Ticks
};

// Act
var actualResult = sut.Create(request, context);

// Assert
Assert.Equal(new DateTime(2020, 06, 15, 12, 30, 30), actualResult);
}

[Fact]
public void ShouldReturnNoSpecimenIfUnableToSatisfyRangedRequest()
{
// Arrange
var sut = new DateTimeRangedRequestRelay();
var request =
new RangedRequest(memberType: typeof(DateTime), operandType: typeof(DateTime), minimum: "2020-01-01 00:00:00",
maximum: "2020-12-31 23:59:59");

var context = new DelegatingSpecimenContext
{
OnResolve = _ => new NoSpecimen()
};

// Act
var actualResult = sut.Create(request, context);

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

[Fact]
public void ShouldCorrectPassMinimumAndMaximumAsTicks()
{
// Arrange
var sut = new DateTimeRangedRequestRelay();

var request = new RangedRequest(typeof(DateTime), typeof(DateTime), "2020-01-01 00:00:00", "2020-12-31 23:59:59");
RangedNumberRequest capturedNumericRequest = null;

var context = new DelegatingSpecimenContext
{
OnResolve = r =>
{
capturedNumericRequest = (RangedNumberRequest)r;
return new NoSpecimen();
}
};

// Act
sut.Create(request, context);

// Assert
Assert.NotNull(capturedNumericRequest);
Assert.Equal(new DateTime(2020, 1, 1, 0, 0, 0).Ticks, capturedNumericRequest.Minimum);
Assert.Equal(new DateTime(2020, 12, 31, 23, 59, 59).Ticks, capturedNumericRequest.Maximum);
}
}
}