Skip to content

Commit

Permalink
feat: union docs and tests [ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
bmazzarol committed Oct 11, 2023
1 parent 86788eb commit 29b1eac
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 10 deletions.
2 changes: 2 additions & 0 deletions Eon.Docs/articles/components/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
href: from.md
- name: Linear
href: linear.md
- name: Union (|)
href: union.md
18 changes: 18 additions & 0 deletions Eon.Docs/articles/components/union.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Union (|)

@Eon.Schedule.Union* returns the union of two @Eon.Schedule.
As long as any of the two @Eon.Schedule are still running it will return the
minimum @Eon.Duration of either.

Using the @Eon.Schedule.Union* method,

[!code-csharp[Example1](../../../Eon.Tests/Examples/UnionTests.cs#Example1)]

Using the @Eon.Schedule.op_BitwiseOr*,

[!code-csharp[Example2](../../../Eon.Tests/Examples/UnionTests.cs#Example2)]

The returned @Eon.Schedule will run as long as the longest of the two
@Eon.Schedule

[!code-csharp[Example3](../../../Eon.Tests/Examples/UnionTests.cs#Example3)]
65 changes: 65 additions & 0 deletions Eon.Tests/Examples/UnionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
namespace Eon.Tests.Examples;

public static class UnionTests
{
[Fact(DisplayName = "Union returns the min duration of either schedule")]
public static void Case1()
{
#region Example1
Schedule union = Schedule
.Linear(TimeSpan.FromSeconds(1))
.Union(Schedule.Spaced(TimeSpan.FromSeconds(3)));

using var enumerator = union.GetEnumerator();
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(1));
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(2));
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(3));
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(3));

#endregion
}

[Fact(DisplayName = "Union operator returns the min duration of either schedule")]
public static void Case2()
{
#region Example2
Schedule union =
Schedule.Spaced(TimeSpan.FromSeconds(4))
| Schedule.Linear(TimeSpan.FromSeconds(1), factor: 2);

using var enumerator = union.GetEnumerator();
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(1));
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(3));
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(4));
enumerator.MoveNext().Should().BeTrue();
enumerator.Current.Should().Be(TimeSpan.FromSeconds(4));

#endregion
}

[Fact(DisplayName = "Union operator returns the longest of the 2 schedules")]
public static void Case3()
{
#region Example3
Schedule leftSideLonger =
Schedule.Spaced(TimeSpan.FromSeconds(4)).Take(4)
| Schedule.Linear(TimeSpan.FromSeconds(1), factor: 2).Take(2);

leftSideLonger.Should().HaveCount(4);

Schedule rightSideLonger =
Schedule.Spaced(TimeSpan.FromSeconds(4)).Take(2)
| Schedule.Linear(TimeSpan.FromSeconds(1), factor: 2).Take(3);

rightSideLonger.Should().HaveCount(3);

#endregion
}
}
52 changes: 44 additions & 8 deletions Eon/Duration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ namespace Eon;
/// Period of time (duration) in milliseconds.
/// It differs from <see cref="TimeSpan"/> in that it can never be negative
/// </summary>
public readonly record struct Duration : IComparable<Duration>
public readonly struct Duration : IEquatable<Duration>, IComparable<Duration>
{
private readonly double _milliseconds;
/// <summary>
/// Number of milliseconds the duration constitutes
/// </summary>
public readonly double Milliseconds;

/// <summary>
/// Duration constructor
Expand All @@ -25,7 +28,7 @@ public Duration(double milliseconds)
nameof(milliseconds)
);
}
_milliseconds = milliseconds;
Milliseconds = milliseconds;
}

/// <summary>
Expand Down Expand Up @@ -55,7 +58,7 @@ public Duration(double milliseconds)
/// <param name="duration">duration</param>
/// <returns>milliseconds</returns>
[Pure]
public static implicit operator double(in Duration duration) => duration._milliseconds;
public static implicit operator double(in Duration duration) => duration.Milliseconds;

/// <summary>
/// Converts a <see cref="Duration"/> to a <see cref="TimeSpan"/>
Expand All @@ -64,7 +67,7 @@ public Duration(double milliseconds)
/// <returns>timespan</returns>
[Pure]
public static explicit operator TimeSpan(in Duration duration) =>
TimeSpan.FromMilliseconds(duration._milliseconds);
TimeSpan.FromMilliseconds(duration.Milliseconds);

/// <summary>
/// Compares this instance to a specified <see cref="Duration"/> and returns
Expand All @@ -74,7 +77,7 @@ public static explicit operator TimeSpan(in Duration duration) =>
/// <param name="other">other <see cref="Duration"/></param>
/// <returns>integer which is either less than 0, 0 or greater than 0</returns>
[Pure]
private int CompareToInternal(in Duration other) => _milliseconds.CompareTo(other);
private int CompareToInternal(in Duration other) => Milliseconds.CompareTo(other);

/// <inheritdoc />
[Pure]
Expand Down Expand Up @@ -120,12 +123,45 @@ public static explicit operator TimeSpan(in Duration duration) =>
public static bool operator <=(in Duration first, in Duration second) =>
first.CompareToInternal(second) <= 0;

/// <summary>
/// Returns true if the `first` <see cref="Duration"/> equals the `second` <see cref="Duration"/>
/// </summary>
/// <param name="first">first <see cref="Duration"/></param>
/// <param name="second">second <see cref="Duration"/></param>
/// <returns>true if the `first` is equal to the `second`</returns>
[Pure]
public static bool operator ==(Duration first, Duration second) =>
first.Milliseconds.Equals(second.Milliseconds);

/// <summary>
/// Returns true if the `first` <see cref="Duration"/> does not equal the `second` <see cref="Duration"/>
/// </summary>
/// <param name="first">first <see cref="Duration"/></param>
/// <param name="second">second <see cref="Duration"/></param>
/// <returns>true if the `first` is not equal to the `second`</returns>
[Pure]
public static bool operator !=(Duration first, Duration second) =>
!first.Milliseconds.Equals(second.Milliseconds);

/// <inheritdoc />
[Pure]
public bool Equals(Duration other) => Milliseconds.Equals(other);

/// <inheritdoc />
[Pure]
public override bool Equals(object? obj) => obj is Duration other && Equals(other);

/// <inheritdoc />
[Pure]
public override int GetHashCode() => Milliseconds.GetHashCode();

/// <summary>
/// Exposes an awaiter from <see cref="Task.Delay(int)"/> to allow direct await on a <see cref="Duration"/>
/// </summary>
/// <returns><see cref="Task.Delay(int)"/> awaiter</returns>
public TaskAwaiter GetAwaiter() => Task.Delay((int)_milliseconds).GetAwaiter();
public TaskAwaiter GetAwaiter() => Task.Delay((int)Milliseconds).GetAwaiter();

/// <inheritdoc />
public override string ToString() => ((TimeSpan)this).ToString();
[Pure]
public override string ToString() => $"{nameof(Duration)}({(TimeSpan)this})";
}
4 changes: 2 additions & 2 deletions Eon/Eon.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<Title>Eon</Title>
<Description>Simple Schedule builder</Description>
<PackageTags>C#, Schedule</PackageTags>
<PackageProjectUrl>https://bmazzarol.github.io/Schedule.BuildR</PackageProjectUrl>
<RepositoryUrl>https://github.com/bmazzarol/Schedule.BuildR</RepositoryUrl>
<PackageProjectUrl>https://bmazzarol.github.io/Eon</PackageProjectUrl>
<RepositoryUrl>https://github.com/bmazzarol/Eon</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Copyright>Copyright (c) Ben Mazzarol. All rights reserved.</Copyright>
<ProjectGuid>6c1d4fd7-fb66-4192-8c0f-d514fe0d5a20</ProjectGuid>
Expand Down

0 comments on commit 29b1eac

Please sign in to comment.