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

DateRange does not include time #1904 #1905

Merged
merged 7 commits into from
Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 29 additions & 29 deletions Octokit.Tests/Clients/SearchClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ public void TestingTheCreatedQualifier_GreaterThan()
client.SearchUsers(request);
connection.Received().Get<SearchUsersResult>(
Arg.Is<Uri>(u => u.ToString() == "search/users"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:>2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer the unit test actually tests the formatted string eg '2014-1-1'T'020406 1000' (or whatever it should be)

Otherwise these tests are susceptible to whatever formatting bug may exist inside DateRange class.

EG Im pretty sure the way you've implemented it at the moment isn't correctly formatting the string, yet all these tests pass (because you are using the DateRange class to test the DateRange class! 🤣

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @ryangribble
Has taken me a while to make these changes due to other commitments, however, they're now there.

Let me know what you think.

}

[Fact]
Expand All @@ -232,7 +232,7 @@ public void TestingTheCreatedQualifier_GreaterThanOrEqualTo()
client.SearchUsers(request);
connection.Received().Get<SearchUsersResult>(
Arg.Is<Uri>(u => u.ToString() == "search/users"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:>=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand All @@ -245,7 +245,7 @@ public void TestingTheCreatedQualifier_LessThanOrEqualTo()
client.SearchUsers(request);
connection.Received().Get<SearchUsersResult>(
Arg.Is<Uri>(u => u.ToString() == "search/users"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:<=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand All @@ -258,7 +258,7 @@ public void TestingTheCreatedQualifier_LessThan()
client.SearchUsers(request);
connection.Received().Get<SearchUsersResult>(
Arg.Is<Uri>(u => u.ToString() == "search/users"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:<2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand All @@ -271,7 +271,7 @@ public void TestingTheCreatedQualifier_Between()
client.SearchUsers(request);
connection.Received().Get<SearchUsersResult>(
Arg.Is<Uri>(u => u.ToString() == "search/users"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:2014-01-01..2014-02-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand Down Expand Up @@ -528,7 +528,7 @@ public void TestingTheCreatedQualifier()
request.Created = DateRange.GreaterThan(new DateTime(2011, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:>2011-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand All @@ -541,7 +541,7 @@ public void TestingTheCreatedQualifier_GreaterThanOrEquals()
request.Created = DateRange.GreaterThanOrEquals(new DateTime(2011, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:>=2011-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand All @@ -554,7 +554,7 @@ public void TestingTheCreatedQualifier_LessThan()
request.Created = DateRange.LessThan(new DateTime(2011, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:<2011-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}


Expand All @@ -568,7 +568,7 @@ public void TestingTheCreatedQualifier_LessThanOrEquals()
request.Created = DateRange.LessThanOrEquals(new DateTime(2011, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:<=2011-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand All @@ -580,7 +580,7 @@ public void TestingTheCreatedQualifier_Between()
request.Created = DateRange.Between(new DateTime(2011, 1, 1), new DateTime(2012, 11, 11));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+created:2011-01-01..2012-11-11"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+created:{request.Created}"));
}

[Fact]
Expand All @@ -593,7 +593,7 @@ public void TestingTheUpdatedQualifier()
request.Updated = DateRange.GreaterThan(new DateTime(2013, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+pushed:>2013-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+pushed:{request.Updated}"));
}

[Fact]
Expand All @@ -606,7 +606,7 @@ public void TestingTheUpdatedQualifier_GreaterThanOrEquals()
request.Updated = DateRange.GreaterThanOrEquals(new DateTime(2013, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+pushed:>=2013-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+pushed:{request.Updated}"));
}

[Fact]
Expand All @@ -619,7 +619,7 @@ public void TestingTheUpdatedQualifier_LessThan()
request.Updated = DateRange.LessThan(new DateTime(2013, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+pushed:<2013-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+pushed:{request.Updated}"));
}

[Fact]
Expand All @@ -632,7 +632,7 @@ public void TestingTheUpdatedQualifier_LessThanOrEquals()
request.Updated = DateRange.LessThanOrEquals(new DateTime(2013, 1, 1));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+pushed:<=2013-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+pushed:{request.Updated}"));
}

[Fact]
Expand All @@ -644,7 +644,7 @@ public void TestingTheUpdatedQualifier_Between()
request.Updated = DateRange.Between(new DateTime(2012, 4, 30), new DateTime(2012, 7, 4));
client.SearchRepo(request);
connection.Received().Get<SearchRepositoryResult>(Arg.Is<Uri>(u => u.ToString() == "search/repositories"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "github+pushed:2012-04-30..2012-07-04"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"github+pushed:{request.Updated}"));
}

[Fact]
Expand Down Expand Up @@ -995,7 +995,7 @@ public void TestingTheCreatedQualifier_GreaterThan()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+created:>2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+created:{request.Created}"));
}

[Fact]
Expand All @@ -1010,7 +1010,7 @@ public void TestingTheCreatedQualifier_GreaterThanOrEquals()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+created:>=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+created:{request.Created}"));
}

[Fact]
Expand All @@ -1025,7 +1025,7 @@ public void TestingTheCreatedQualifier_LessThan()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+created:<2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+created:{request.Created}"));
}

[Fact]
Expand All @@ -1040,7 +1040,7 @@ public void TestingTheCreatedQualifier_LessThanOrEquals()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+created:<=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+created:{request.Created}"));
}

[Fact]
Expand All @@ -1055,7 +1055,7 @@ public void TestingTheCreatedQualifier_Between()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+created:2014-01-01..2014-02-02"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+created:{request.Created}"));
}

[Fact]
Expand All @@ -1070,7 +1070,7 @@ public void TestingTheMergedQualifier_GreaterThan()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+merged:>2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+merged:{request.Merged}"));
}

[Fact]
Expand All @@ -1085,7 +1085,7 @@ public void TestingTheMergedQualifier_GreaterThanOrEquals()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+merged:>=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+merged:{request.Merged}"));
}

[Fact]
Expand All @@ -1100,7 +1100,7 @@ public void TestingTheMergedQualifier_LessThan()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+merged:<2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+merged:{request.Merged}"));
}

[Fact]
Expand All @@ -1115,7 +1115,7 @@ public void TestingTheMergedQualifier_LessThanOrEquals()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+merged:<=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+merged:{request.Merged}"));
}

[Fact]
Expand All @@ -1130,7 +1130,7 @@ public void TestingTheMergedQualifier_Between()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+merged:2014-01-01..2014-02-02"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+merged:{request.Merged}"));
}

[Fact]
Expand All @@ -1145,7 +1145,7 @@ public void TestingTheUpdatedQualifier_GreaterThan()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+updated:>2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+updated:{request.Updated}"));
}

[Fact]
Expand All @@ -1160,7 +1160,7 @@ public void TestingTheUpdatedQualifier_GreaterThanOrEquals()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+updated:>=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+updated:{request.Updated}"));
}

[Fact]
Expand All @@ -1175,7 +1175,7 @@ public void TestingTheUpdatedQualifier_LessThan()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+updated:<2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+updated:{request.Updated}"));
}

[Fact]
Expand All @@ -1190,7 +1190,7 @@ public void TestingTheUpdatedQualifier_LessThanOrEquals()

connection.Received().Get<SearchIssuesResult>(
Arg.Is<Uri>(u => u.ToString() == "search/issues"),
Arg.Is<Dictionary<string, string>>(d => d["q"] == "something+updated:<=2014-01-01"));
Arg.Is<Dictionary<string, string>>(d => d["q"] == $"something+updated:{request.Updated}"));
}

[Fact]
Expand Down
46 changes: 28 additions & 18 deletions Octokit/Models/Request/SearchRepositoriesRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,33 +304,43 @@ public class DateRange
/// Matches repositories with regards to the <param name="date"/>.
/// We will use the <param name="op"/> to see what operator will be applied to the date qualifier
/// </summary>
public DateRange(DateTime date, SearchQualifierOperator op)
[Obsolete("This ctor has been deprecated as GitHub API now supports date and time")]
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it worth pointing out the preferred API and why you'd use it? Something like

This constructor doesn't use the time component of the specified DateTime. Please use the overload accepting a DateTimeOffset, which also supports time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @khellang good pickup. Just made both changes and checked-in.

public DateRange(DateTime date, SearchQualifierOperator op) : this(new DateTimeOffset(date), op)
Copy link
Contributor

Choose a reason for hiding this comment

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

By forwarding these ctors to the new DateTimeOffset overloads, the behavior has changed by taking the time into account. That could be a breaking change.

I think the safest thing to do is to keep the existing logic (as @ryangribble noted in #1904) for these ctors and use the new (and improved) format for the new DateTimeOffset ctors.

{
}

/// <summary>
/// Matches repositories with regards to both the <param name="from"/> and <param name="to"/> dates.
/// </summary>
[Obsolete("This ctor has been deprecated as GitHub API now supports date and time")]
public DateRange(DateTime from, DateTime to) : this(new DateTimeOffset(from), new DateTimeOffset(to))
{
}

public DateRange(DateTimeOffset from, DateTimeOffset to)
{
query = string.Format(CultureInfo.InvariantCulture, "{0:yyyy-MM-dd'T'HH:mm:ss zzz}..{1:yyyy-MM-dd'T'HH:mm:ss zzz}", from.DateTime, to.DateTime);
Copy link
Contributor

Choose a reason for hiding this comment

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

What will the zzz component be here, given you're using the DateTime property and not the DateTimeOffset itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @khellang the zzz includes the timezone offset which I believe is correct.

However, you're right these changes affect the behaviour. I'll update and re-submit.

Copy link
Contributor

@khellang khellang Nov 5, 2018

Choose a reason for hiding this comment

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

But what is that offset? DateTime doesn't store a separate offset.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi sorry you are right @khellang. I was trying to do to code this while also doing my job which was a mistake. I'll fix in my next PR.

}

public DateRange(DateTimeOffset date, SearchQualifierOperator op)
{
switch (op)
{
case SearchQualifierOperator.GreaterThan:
query = string.Format(CultureInfo.InvariantCulture, ">{0:yyyy-MM-dd}", date);
query = string.Format(CultureInfo.InvariantCulture, ">{0:yyyy-MM-dd'T'HH:mm:ss zzz}", date);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd probably store this pattern in a constant and reuse it throughout.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @khellang I've included this suggestion aswell.

I've also updated the relevant unit tests to use a Theory which tests both the DateTime and DateTimeOffset strategies.

break;
case SearchQualifierOperator.LessThan:
query = string.Format(CultureInfo.InvariantCulture, "<{0:yyyy-MM-dd}", date);
query = string.Format(CultureInfo.InvariantCulture, "<{0:yyyy-MM-dd'T'HH:mm:ss zzz}", date);
break;
case SearchQualifierOperator.LessThanOrEqualTo:
query = string.Format(CultureInfo.InvariantCulture, "<={0:yyyy-MM-dd}", date);
query = string.Format(CultureInfo.InvariantCulture, "<={0:yyyy-MM-dd'T'HH:mm:ss zzz}", date);
break;
case SearchQualifierOperator.GreaterThanOrEqualTo:
query = string.Format(CultureInfo.InvariantCulture, ">={0:yyyy-MM-dd}", date);
query = string.Format(CultureInfo.InvariantCulture, ">={0:yyyy-MM-dd'T'HH:mm:ss zzz}", date);
break;
}
}

/// <summary>
/// Matches repositories with regards to both the <param name="from"/> and <param name="to"/> dates.
/// </summary>
public DateRange(DateTime from, DateTime to)
{
query = string.Format(CultureInfo.InvariantCulture, "{0:yyyy-MM-dd}..{1:yyyy-MM-dd}", from, to);
}

internal string DebuggerDisplay
{
get { return string.Format(CultureInfo.InvariantCulture, "Query: {0}", query); }
Expand All @@ -344,7 +354,7 @@ internal string DebuggerDisplay
/// <returns><see cref="DateRange"/></returns>
public static DateRange LessThan(DateTime date)
{
return new DateRange(date, SearchQualifierOperator.LessThan);
return new DateRange(new DateTimeOffset(date), SearchQualifierOperator.LessThan);
}

/// <summary>
Expand All @@ -355,7 +365,7 @@ public static DateRange LessThan(DateTime date)
/// <returns><see cref="DateRange"/></returns>
public static DateRange LessThanOrEquals(DateTime date)
{
return new DateRange(date, SearchQualifierOperator.LessThanOrEqualTo);
return new DateRange(new DateTimeOffset(date), SearchQualifierOperator.LessThanOrEqualTo);
}

/// <summary>
Expand All @@ -366,7 +376,7 @@ public static DateRange LessThanOrEquals(DateTime date)
/// <returns><see cref="DateRange"/></returns>
public static DateRange GreaterThan(DateTime date)
{
return new DateRange(date, SearchQualifierOperator.GreaterThan);
return new DateRange(new DateTimeOffset(date), SearchQualifierOperator.GreaterThan);
}

/// <summary>
Expand All @@ -377,7 +387,7 @@ public static DateRange GreaterThan(DateTime date)
/// <returns><see cref="DateRange"/></returns>
public static DateRange GreaterThanOrEquals(DateTime date)
{
return new DateRange(date, SearchQualifierOperator.GreaterThanOrEqualTo);
return new DateRange(new DateTimeOffset(date), SearchQualifierOperator.GreaterThanOrEqualTo);
}

/// <summary>
Expand All @@ -389,7 +399,7 @@ public static DateRange GreaterThanOrEquals(DateTime date)
/// <returns><see cref="DateRange"/></returns>
public static DateRange Between(DateTime from, DateTime to)
{
return new DateRange(from, to);
return new DateRange(new DateTimeOffset(from), new DateTimeOffset(to));
}

public override string ToString()
Expand Down