diff --git a/Octokit.Reactive/Clients/IObservableMilestonesClient.cs b/Octokit.Reactive/Clients/IObservableMilestonesClient.cs new file mode 100644 index 0000000000..321790a128 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableMilestonesClient.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reactive; + +namespace Octokit +{ + public interface IObservableMilestonesClient + { + /// + /// Gets a single Milestone by number. + /// + /// + /// http://developer.github.com/v3/issues/milestones/#get-a-single-milestone + /// + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", + Justification = "Method makes a network request")] + IObservable Get(string owner, string name, int number); + + /// + /// Gets all open milestones for the repository. + /// + /// + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository + /// + /// The owner of the repository + /// The name of the repository + /// + IObservable GetForRepository(string owner, string name); + + /// + /// Gets all open milestones for the repository. + /// + /// + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository + /// + /// The owner of the repository + /// The name of the repository + /// Used to filter and sort the list of Milestones returned + /// + IObservable GetForRepository(string owner, string name, MilestoneRequest request); + + /// + /// Creates a milestone for the specified repository. Any user with pull access to a repository can create an + /// Milestone. + /// + /// http://developer.github.com/v3/issues/milestones/#create-a-milestone + /// The owner of the repository + /// The name of the repository + /// A instance describing the new Milestone to create + /// + IObservable Create(string owner, string name, NewMilestone newMilestone); + + /// + /// Creates a milestone for the specified repository. Any user with pull access to a repository can create an + /// Milestone. + /// + /// http://developer.github.com/v3/issues/milestones/#update-a-milestone + /// The owner of the repository + /// The name of the repository + /// The Milestone number + /// An instance describing the changes to make to the Milestone + /// + /// + IObservable Update(string owner, string name, int number, MilestoneUpdate milestoneUpdate); + + /// + /// Deletes a milestone for the specified repository. Any user with pull access to a repository can create an + /// Milestone. + /// + /// http://developer.github.com/v3/issues/milestones/#delete-a-milestone + /// The owner of the repository + /// The name of the repository + /// The milestone number + /// + IObservable Delete(string owner, string name, int number); + } +} diff --git a/Octokit.Reactive/Clients/ObservableMilestonesClient.cs b/Octokit.Reactive/Clients/ObservableMilestonesClient.cs new file mode 100644 index 0000000000..bd33ad53eb --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableMilestonesClient.cs @@ -0,0 +1,125 @@ +using System; +using System.Reactive; +using System.Reactive.Threading.Tasks; +using Octokit.Reactive.Internal; + +namespace Octokit.Reactive.Clients +{ + public class ObservableMilestonesClient : IObservableMilestonesClient + { + readonly IMilestonesClient _client; + readonly IConnection _connection; + + public ObservableMilestonesClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Issue.Milestone; + _connection = client.Connection; + } + + /// + /// Gets a single Milestone by number. + /// + /// + /// http://developer.github.com/v3/issues/milestones/#get-a-single-milestone + /// + /// + public IObservable Get(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.Get(owner, name, number).ToObservable(); + } + + /// + /// Gets all open milestones for the repository. + /// + /// + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository + /// + /// The owner of the repository + /// The name of the repository + /// + public IObservable GetForRepository(string owner, string name) + { + return _connection.GetAndFlattenAllPages(ApiUrls.Milestones(owner, name)); + } + + /// + /// Gets all open milestones for the repository. + /// + /// + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository + /// + /// The owner of the repository + /// The name of the repository + /// Used to filter and sort the list of Milestones returned + /// + public IObservable GetForRepository(string owner, string name, MilestoneRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(request, "request"); + + return _connection.GetAndFlattenAllPages(ApiUrls.Milestones(owner, name), + request.ToParametersDictionary()); + } + + /// + /// Creates an Milestone for the specified repository. Any user with pull access to a repository can create an + /// Milestone. + /// + /// http://developer.github.com/v3/issues/milestones/#create-a-milestone + /// The owner of the repository + /// The name of the repository + /// A instance describing the new Milestone to create + /// + public IObservable Create(string owner, string name, NewMilestone newMilestone) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(newMilestone, "newMilestone"); + + return _client.Create(owner, name, newMilestone).ToObservable(); + } + + /// + /// Creates an Milestone for the specified repository. Any user with pull access to a repository can create an + /// Milestone. + /// + /// http://developer.github.com/v3/issues/milestones/#create-a-milestone + /// The owner of the repository + /// The name of the repository + /// The Milestone number + /// An instance describing the changes to make to the Milestone + /// + /// + public IObservable Update(string owner, string name, int number, MilestoneUpdate milestoneUpdate) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(milestoneUpdate, "milestoneUpdate"); + + return _client.Update(owner, name, number, milestoneUpdate).ToObservable(); + } + + /// + /// Deletes a milestone for the specified repository. Any user with pull access to a repository can create an + /// Milestone. + /// + /// http://developer.github.com/v3/issues/milestones/#delete-a-milestone + /// The owner of the repository + /// The name of the repository + /// The milestone number + /// + public IObservable Delete(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.Delete(owner, name, number).ToObservable(); + } + } +} \ No newline at end of file diff --git a/Octokit.Reactive/Helpers/ConnectionExtensions.cs b/Octokit.Reactive/Helpers/ConnectionExtensions.cs index 91d6b30c1d..2a0fa79c85 100644 --- a/Octokit.Reactive/Helpers/ConnectionExtensions.cs +++ b/Octokit.Reactive/Helpers/ConnectionExtensions.cs @@ -7,20 +7,20 @@ namespace Octokit.Reactive.Internal { internal static class ConnectionExtensions { - public static IObservable GetAndFlattenAllPages(this IConnection connection, Uri url) + public static IObservable GetAndFlattenAllPages(this IConnection connection, Uri url, IDictionary parameters = null, string accepts = null) { - return GetPages(url, nextPageUrl => connection.GetAsync>(nextPageUrl).ToObservable()); + return GetPages(url, parameters, (pageUrl, pageParams) => connection.GetAsync>(pageUrl, pageParams, accepts).ToObservable()); } - static IObservable GetPages(Uri uri, - Func>>> getPageFunc) + static IObservable GetPages(Uri uri, IDictionary parameters, + Func, IObservable>>> getPageFunc) { - return getPageFunc(uri).Expand(resp => + return getPageFunc(uri, parameters).Expand(resp => { var nextPageUrl = resp.ApiInfo.GetNextPageUrl(); return nextPageUrl == null ? Observable.Empty>>() - : Observable.Defer(() => getPageFunc(nextPageUrl)); + : Observable.Defer(() => getPageFunc(nextPageUrl, null)); }) .Where(resp => resp != null) .SelectMany(resp => resp.BodyAsObject); diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index bfe5da0a47..7a0e66084d 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -71,6 +71,8 @@ Properties\SolutionInfo.cs + + diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index c0b63d6777..51a5a58f31 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -61,6 +61,7 @@ + diff --git a/Octokit.Tests.Integration/Reactive/ObservableMilestonesClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableMilestonesClientTests.cs new file mode 100644 index 0000000000..2b28cd6fdc --- /dev/null +++ b/Octokit.Tests.Integration/Reactive/ObservableMilestonesClientTests.cs @@ -0,0 +1,45 @@ +using System.Linq; +using System.Net.Http.Headers; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Octokit.Reactive.Clients; +using Xunit; + +namespace Octokit.Tests.Integration +{ + public class ObservableMilestonesClientTests + { + public class TheGetMethod + { + [IntegrationTest] + public async Task ReturnsSpecifiedMilestone() + { + var github = new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = Helper.Credentials + }; + var client = new ObservableMilestonesClient(github); + var observable = client.Get("libgit2", "libgit2sharp", 1); + var milestone = await observable; + + Assert.Equal(1, milestone.Number); + Assert.Equal("v0.4.0", milestone.Title); + Assert.Equal(7, milestone.ClosedIssues); + } + + [IntegrationTest] + public void ReturnsAllMilestones() + { + var github = new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = Helper.Credentials + }; + var client = new ObservableMilestonesClient(github); + var milestones = client.GetForRepository("libgit2", "libgit2sharp", new MilestoneRequest { State = ItemState.Closed }).ToList().Wait(); + + Assert.NotEmpty(milestones); + Assert.True(milestones.All(m => m.State == ItemState.Closed)); + } + } + } +} diff --git a/Octokit.Tests/Clients/AssigneesClientTests.cs b/Octokit.Tests/Clients/AssigneesClientTests.cs index d571ea5e65..443a059b3f 100644 --- a/Octokit.Tests/Clients/AssigneesClientTests.cs +++ b/Octokit.Tests/Clients/AssigneesClientTests.cs @@ -9,89 +9,92 @@ using Xunit; using Xunit.Extensions; -public class AssignessClientTests +namespace Octokit.Tests.Clients { - public class TheGetForRepositoryMethod + public class AssignessClientTests { - [Fact] - public void RequestsCorrectUrl() + public class TheGetForRepositoryMethod { - var connection = Substitute.For(); - var client = new AssigneesClient(connection); + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new AssigneesClient(connection); - client.GetForRepository("fake", "repo"); + client.GetForRepository("fake", "repo"); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/assignees")); - } + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/assignees")); + } - [Fact] - public async Task EnsuresNonNullArguments() - { - var client = new AssigneesClient(Substitute.For()); + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new AssigneesClient(Substitute.For()); - await AssertEx.Throws(async () => await client.GetForRepository(null, "name")); - await AssertEx.Throws(async () => await client.GetForRepository(null, "")); - await AssertEx.Throws(async () => await client.GetForRepository("owner", null)); - await AssertEx.Throws(async () => await client.GetForRepository("", null)); + await AssertEx.Throws(async () => await client.GetForRepository(null, "name")); + await AssertEx.Throws(async () => await client.GetForRepository(null, "")); + await AssertEx.Throws(async () => await client.GetForRepository("owner", null)); + await AssertEx.Throws(async () => await client.GetForRepository("", null)); + } } - } - public class TheCheckAssigneeMethod - { - [Theory] - [InlineData(HttpStatusCode.NoContent, true)] - [InlineData(HttpStatusCode.NotFound, false)] - public async Task RequestsCorrectValueForStatusCode(HttpStatusCode status, bool expected) + public class TheCheckAssigneeMethod { - var response = Task.Factory.StartNew>(() => - new ApiResponse { StatusCode = status }); - var connection = Substitute.For(); - connection.GetAsync(Arg.Is(u => u.ToString() == "repos/foo/bar/assignees/cody"), - null, null).Returns(response); - var apiConnection = Substitute.For(); - apiConnection.Connection.Returns(connection); - var client = new AssigneesClient(apiConnection); + [Theory] + [InlineData(HttpStatusCode.NoContent, true)] + [InlineData(HttpStatusCode.NotFound, false)] + public async Task RequestsCorrectValueForStatusCode(HttpStatusCode status, bool expected) + { + var response = Task.Factory.StartNew>(() => + new ApiResponse { StatusCode = status }); + var connection = Substitute.For(); + connection.GetAsync(Arg.Is(u => u.ToString() == "repos/foo/bar/assignees/cody"), + null, null).Returns(response); + var apiConnection = Substitute.For(); + apiConnection.Connection.Returns(connection); + var client = new AssigneesClient(apiConnection); - var result = await client.CheckAssignee("foo", "bar", "cody"); + var result = await client.CheckAssignee("foo", "bar", "cody"); - Assert.Equal(expected, result); - } + Assert.Equal(expected, result); + } - [Fact] - public async Task ThrowsExceptionForInvalidStatusCode() - { - var response = Task.Factory.StartNew>(() => - new ApiResponse { StatusCode = HttpStatusCode.Conflict }); - var connection = Substitute.For(); - connection.GetAsync(Arg.Is(u => u.ToString() == "repos/foo/bar/assignees/cody"), - null, null).Returns(response); - var apiConnection = Substitute.For(); - apiConnection.Connection.Returns(connection); - var client = new AssigneesClient(apiConnection); + [Fact] + public async Task ThrowsExceptionForInvalidStatusCode() + { + var response = Task.Factory.StartNew>(() => + new ApiResponse { StatusCode = HttpStatusCode.Conflict }); + var connection = Substitute.For(); + connection.GetAsync(Arg.Is(u => u.ToString() == "repos/foo/bar/assignees/cody"), + null, null).Returns(response); + var apiConnection = Substitute.For(); + apiConnection.Connection.Returns(connection); + var client = new AssigneesClient(apiConnection); - AssertEx.Throws(async () => await client.CheckAssignee("foo", "bar", "cody")); - } + AssertEx.Throws(async () => await client.CheckAssignee("foo", "bar", "cody")); + } - [Fact] - public async Task EnsuresNonNullArguments() - { - var client = new AssigneesClient(Substitute.For()); + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new AssigneesClient(Substitute.For()); - await AssertEx.Throws(async () => await client.CheckAssignee(null, "name", "tweety")); - await AssertEx.Throws(async () => await client.CheckAssignee(null, "", "tweety")); - await AssertEx.Throws(async () => await client.CheckAssignee("owner", null, "tweety")); - await AssertEx.Throws(async () => await client.CheckAssignee("", null, "tweety")); - await AssertEx.Throws(async () => await client.CheckAssignee("owner", "name", null)); - await AssertEx.Throws(async () => await client.CheckAssignee("owner", "name", "")); + await AssertEx.Throws(async () => await client.CheckAssignee(null, "name", "tweety")); + await AssertEx.Throws(async () => await client.CheckAssignee(null, "", "tweety")); + await AssertEx.Throws(async () => await client.CheckAssignee("owner", null, "tweety")); + await AssertEx.Throws(async () => await client.CheckAssignee("", null, "tweety")); + await AssertEx.Throws(async () => await client.CheckAssignee("owner", "name", null)); + await AssertEx.Throws(async () => await client.CheckAssignee("owner", "name", "")); + } } - } - public class TheCtor - { - [Fact] - public void EnsuresArgument() + public class TheCtor { - Assert.Throws(() => new AssigneesClient(null)); + [Fact] + public void EnsuresArgument() + { + Assert.Throws(() => new AssigneesClient(null)); + } } } -} +} \ No newline at end of file diff --git a/Octokit.Tests/Clients/IssuesClientTests.cs b/Octokit.Tests/Clients/IssuesClientTests.cs index 4f0c4a4145..9646ca8d77 100644 --- a/Octokit.Tests/Clients/IssuesClientTests.cs +++ b/Octokit.Tests/Clients/IssuesClientTests.cs @@ -8,242 +8,245 @@ using Octokit.Tests.Helpers; using Xunit; -public class IssuesClientTests +namespace Octokit.Tests.Clients { - public class TheGetMethod + public class IssuesClientTests { - [Fact] - public void RequestsCorrectUrl() + public class TheGetMethod { - var connection = Substitute.For(); - var client = new IssuesClient(connection); - - client.Get("fake", "repo", 42); - - connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42"), - null); - } + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); - [Fact] - public async Task EnsuresNonNullArguments() - { - var client = new IssuesClient(Substitute.For()); + client.Get("fake", "repo", 42); - await AssertEx.Throws(async () => await client.Get(null, "name", 1)); - await AssertEx.Throws(async () => await client.Get("owner", null, 1)); - } + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42"), + null); + } - } - - public class TheGetAllForCurrentMethod - { - [Fact] - public void RequestsCorrectUrl() - { - var connection = Substitute.For(); - var client = new IssuesClient(connection); + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new IssuesClient(Substitute.For()); - client.GetAllForCurrent(); + await AssertEx.Throws(async () => await client.Get(null, "name", 1)); + await AssertEx.Throws(async () => await client.Get("owner", null, 1)); + } - connection.Received().GetAll(Arg.Is(u => u.ToString() == "issues"), - Arg.Any>()); } - [Fact] - public void SendsAppropriateParameters() + public class TheGetAllForCurrentMethod { - var connection = Substitute.For(); - var client = new IssuesClient(connection); + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); + + client.GetAllForCurrent(); - client.GetAllForCurrent(new IssueRequest { SortDirection = SortDirection.Ascending }); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "issues"), + Arg.Any>()); + } - connection.Received().GetAll(Arg.Is(u => u.ToString() == "issues"), - Arg.Is>(d => d.Count == 4 - && d["filter"] == "assigned" - && d["sort"] == "created" - && d["state"] == "open" - && d["direction"] == "asc")); + [Fact] + public void SendsAppropriateParameters() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); + + client.GetAllForCurrent(new IssueRequest { SortDirection = SortDirection.Ascending }); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "issues"), + Arg.Is>(d => d.Count == 4 + && d["filter"] == "assigned" + && d["sort"] == "created" + && d["state"] == "open" + && d["direction"] == "asc")); + } } - } - public class TheGetAllForOwnedAndMemberRepositoriesMethod - { - [Fact] - public void RequestsCorrectUrl() + public class TheGetAllForOwnedAndMemberRepositoriesMethod { - var connection = Substitute.For(); - var client = new IssuesClient(connection); + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); - client.GetAllForOwnedAndMemberRepositories(); + client.GetAllForOwnedAndMemberRepositories(); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "user/issues"), - Arg.Any>()); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "user/issues"), + Arg.Any>()); + } } - } - public class TheGetForRepositoryMethod - { - [Fact] - public void RequestsCorrectUrl() + public class TheGetForRepositoryMethod { - var connection = Substitute.For(); - var client = new IssuesClient(connection); - - client.GetForRepository("fake", "repo"); + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), - Arg.Any>()); - } + client.GetForRepository("fake", "repo"); - [Fact] - public void SendsAppropriateParameters() - { - var connection = Substitute.For(); - var client = new IssuesClient(connection); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), + Arg.Any>()); + } - client.GetForRepository("fake", "repo", new RepositoryIssueRequest + [Fact] + public void SendsAppropriateParameters() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); + + client.GetForRepository("fake", "repo", new RepositoryIssueRequest + { + SortDirection = SortDirection.Ascending + }); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), + Arg.Is>(d => d.Count == 4 + && d["state"] == "open" + && d["direction"] == "asc" + && d["sort"] == "created" + && d["filter"] == "assigned")); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() { - SortDirection = SortDirection.Ascending - }); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), - Arg.Is>(d => d.Count == 4 - && d["state"] == "open" - && d["direction"] == "asc" - && d["sort"] == "created" - && d["filter"] == "assigned")); + var connection = Substitute.For(); + var client = new IssuesClient(connection); + + AssertEx.Throws(async () => await + client.GetForRepository(null, "name", new RepositoryIssueRequest())); + AssertEx.Throws(async () => await + client.GetForRepository("", "name", new RepositoryIssueRequest())); + AssertEx.Throws(async () => await + client.GetForRepository("owner", null, new RepositoryIssueRequest())); + AssertEx.Throws(async () => await + client.GetForRepository("owner", "", new RepositoryIssueRequest())); + AssertEx.Throws(async () => await + client.GetForRepository("owner", "name", null)); + } } - [Fact] - public async Task EnsuresArgumentsNotNull() + public class TheCreateMethod { - var connection = Substitute.For(); - var client = new IssuesClient(connection); - - AssertEx.Throws(async () => await - client.GetForRepository(null, "name", new RepositoryIssueRequest())); - AssertEx.Throws(async () => await - client.GetForRepository("", "name", new RepositoryIssueRequest())); - AssertEx.Throws(async () => await - client.GetForRepository("owner", null, new RepositoryIssueRequest())); - AssertEx.Throws(async () => await - client.GetForRepository("owner", "", new RepositoryIssueRequest())); - AssertEx.Throws(async () => await - client.GetForRepository("owner", "name", null)); - } - } + [Fact] + public void PostsToCorrectUrl() + { + var newIssue = new NewIssue("some title"); + var connection = Substitute.For(); + var client = new IssuesClient(connection); - public class TheCreateMethod - { - [Fact] - public void PostsToCorrectUrl() - { - var newIssue = new NewIssue("some title"); - var connection = Substitute.For(); - var client = new IssuesClient(connection); + client.Create("fake", "repo", newIssue); - client.Create("fake", "repo", newIssue); + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), + newIssue); + } - connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), - newIssue); + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); + + AssertEx.Throws(async () => await + client.Create(null, "name", new NewIssue("title"))); + AssertEx.Throws(async () => await + client.Create("", "name", new NewIssue("x"))); + AssertEx.Throws(async () => await + client.Create("owner", null, new NewIssue("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "", new NewIssue("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "name", null)); + } } - [Fact] - public async Task EnsuresArgumentsNotNull() + public class TheUpdateMethod { - var connection = Substitute.For(); - var client = new IssuesClient(connection); - - AssertEx.Throws(async () => await - client.Create(null, "name", new NewIssue("title"))); - AssertEx.Throws(async () => await - client.Create("", "name", new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", null, new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "", new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "name", null)); - } - } + [Fact] + public void PostsToCorrectUrl() + { + var issueUpdate = new IssueUpdate(); + var connection = Substitute.For(); + var client = new IssuesClient(connection); - public class TheUpdateMethod - { - [Fact] - public void PostsToCorrectUrl() - { - var issueUpdate = new IssueUpdate(); - var connection = Substitute.For(); - var client = new IssuesClient(connection); + client.Update("fake", "repo", 42, issueUpdate); - client.Update("fake", "repo", 42, issueUpdate); + connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42"), + issueUpdate); + } - connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42"), - issueUpdate); + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new IssuesClient(connection); + + AssertEx.Throws(async () => await + client.Create(null, "name", new NewIssue("title"))); + AssertEx.Throws(async () => await + client.Create("", "name", new NewIssue("x"))); + AssertEx.Throws(async () => await + client.Create("owner", null, new NewIssue("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "", new NewIssue("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "name", null)); + } } - [Fact] - public async Task EnsuresArgumentsNotNull() + public class TheCtor { - var connection = Substitute.For(); - var client = new IssuesClient(connection); - - AssertEx.Throws(async () => await - client.Create(null, "name", new NewIssue("title"))); - AssertEx.Throws(async () => await - client.Create("", "name", new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", null, new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "", new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "name", null)); + [Fact] + public void EnsuresArgument() + { + Assert.Throws(() => new IssuesClient(null)); + } } - } - public class TheCtor - { [Fact] - public void EnsuresArgument() + public void CanDeserializeIssue() { - Assert.Throws(() => new IssuesClient(null)); - } - } - - [Fact] - public void CanDeserializeIssue() - { - const string issueResponseJson = "{\"url\":\"https://api.github.com/repos/octokit-net-test/public-repo-" + - "20131022050247078/issues/1\",\"labels_url\":\"https://api.github.com/repos/octokit-net-test/publ" + - "ic-repo-20131022050247078/issues/1/labels{/name}\",\"comments_url\":\"https://api.github.com/rep" + - "os/octokit-net-test/public-repo-20131022050247078/issues/1/comments\",\"events_url\":\"https://a" + - "pi.github.com/repos/octokit-net-test/public-repo-20131022050247078/issues/1/events\",\"html_url" + - "\":\"https://github.com/octokit-net-test/public-repo-20131022050247078/issues/1\",\"id\":2139915" + - "4,\"number\":1,\"title\":\"A test issue\",\"user\":{\"login\":\"octokit-net-test\",\"id\":558045" + - "0,\"avatar_url\":\"https://2.gravatar.com/avatar/20724e5085dcbe92e660a61d282f665c?d=https%3A%2F%" + - "2Fidenticons.github.com%2Fb21d03168ecd65836d6407e4cdd61e0c.png\",\"gravatar_id\":\"20724e5085dcb" + - "e92e660a61d282f665c\",\"url\":\"https://api.github.com/users/octokit-net-test\",\"html_url\":\"h" + - "ttps://github.com/octokit-net-test\",\"followers_url\":\"https://api.github.com/users/octokit-ne" + - "t-test/followers\",\"following_url\":\"https://api.github.com/users/octokit-net-test/following{/" + - "other_user}\",\"gists_url\":\"https://api.github.com/users/octokit-net-test/gists{/gist_id}\",\"" + - "starred_url\":\"https://api.github.com/users/octokit-net-test/starred{/owner}{/repo}\",\"subscri" + - "ptions_url\":\"https://api.github.com/users/octokit-net-test/subscriptions\",\"organizations_url" + - "\":\"https://api.github.com/users/octokit-net-test/orgs\",\"repos_url\":\"https://api.github.com" + - "/users/octokit-net-test/repos\",\"events_url\":\"https://api.github.com/users/octokit-net-test/e" + - "vents{/privacy}\",\"received_events_url\":\"https://api.github.com/users/octokit-net-test/receiv" + - "ed_events\",\"type\":\"User\",\"site_admin\":false},\"labels\":[],\"state\":\"open\",\"assignee" + - "\":null,\"milestone\":null,\"comments\":0,\"created_at\":\"2013-10-22T17:02:48Z\",\"updated_at\"" + - ":\"2013-10-22T17:02:48Z\",\"closed_at\":null,\"body\":\"A new unassigned issue\",\"closed_by\":null}"; - var response = new ApiResponse - { - Body = issueResponseJson, - ContentType = "application/json" - }; - var jsonPipeline = new JsonHttpPipeline(); + const string issueResponseJson = "{\"url\":\"https://api.github.com/repos/octokit-net-test/public-repo-" + + "20131022050247078/issues/1\",\"labels_url\":\"https://api.github.com/repos/octokit-net-test/publ" + + "ic-repo-20131022050247078/issues/1/labels{/name}\",\"comments_url\":\"https://api.github.com/rep" + + "os/octokit-net-test/public-repo-20131022050247078/issues/1/comments\",\"events_url\":\"https://a" + + "pi.github.com/repos/octokit-net-test/public-repo-20131022050247078/issues/1/events\",\"html_url" + + "\":\"https://github.com/octokit-net-test/public-repo-20131022050247078/issues/1\",\"id\":2139915" + + "4,\"number\":1,\"title\":\"A test issue\",\"user\":{\"login\":\"octokit-net-test\",\"id\":558045" + + "0,\"avatar_url\":\"https://2.gravatar.com/avatar/20724e5085dcbe92e660a61d282f665c?d=https%3A%2F%" + + "2Fidenticons.github.com%2Fb21d03168ecd65836d6407e4cdd61e0c.png\",\"gravatar_id\":\"20724e5085dcb" + + "e92e660a61d282f665c\",\"url\":\"https://api.github.com/users/octokit-net-test\",\"html_url\":\"h" + + "ttps://github.com/octokit-net-test\",\"followers_url\":\"https://api.github.com/users/octokit-ne" + + "t-test/followers\",\"following_url\":\"https://api.github.com/users/octokit-net-test/following{/" + + "other_user}\",\"gists_url\":\"https://api.github.com/users/octokit-net-test/gists{/gist_id}\",\"" + + "starred_url\":\"https://api.github.com/users/octokit-net-test/starred{/owner}{/repo}\",\"subscri" + + "ptions_url\":\"https://api.github.com/users/octokit-net-test/subscriptions\",\"organizations_url" + + "\":\"https://api.github.com/users/octokit-net-test/orgs\",\"repos_url\":\"https://api.github.com" + + "/users/octokit-net-test/repos\",\"events_url\":\"https://api.github.com/users/octokit-net-test/e" + + "vents{/privacy}\",\"received_events_url\":\"https://api.github.com/users/octokit-net-test/receiv" + + "ed_events\",\"type\":\"User\",\"site_admin\":false},\"labels\":[],\"state\":\"open\",\"assignee" + + "\":null,\"milestone\":null,\"comments\":0,\"created_at\":\"2013-10-22T17:02:48Z\",\"updated_at\"" + + ":\"2013-10-22T17:02:48Z\",\"closed_at\":null,\"body\":\"A new unassigned issue\",\"closed_by\":null}"; + var response = new ApiResponse + { + Body = issueResponseJson, + ContentType = "application/json" + }; + var jsonPipeline = new JsonHttpPipeline(); - jsonPipeline.DeserializeResponse(response); + jsonPipeline.DeserializeResponse(response); - Assert.NotNull(response.BodyAsObject); - Assert.Equal(issueResponseJson, response.Body); + Assert.NotNull(response.BodyAsObject); + Assert.Equal(issueResponseJson, response.Body); + } } -} +} \ No newline at end of file diff --git a/Octokit.Tests/Clients/MilestonesClientTests.cs b/Octokit.Tests/Clients/MilestonesClientTests.cs index f2a3dd2f3e..9b27b71571 100644 --- a/Octokit.Tests/Clients/MilestonesClientTests.cs +++ b/Octokit.Tests/Clients/MilestonesClientTests.cs @@ -6,168 +6,171 @@ using Octokit.Tests.Helpers; using Xunit; -public class MilestonesClientTests +namespace Octokit.Tests.Clients { - public class TheGetMethod + public class MilestonesClientTests { - [Fact] - public void RequestsCorrectUrl() + public class TheGetMethod { - var connection = Substitute.For(); - var client = new MilestonesClient(connection); - - client.Get("fake", "repo", 42); - - connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones/42"), - null); - } - - [Fact] - public async Task EnsuresNonNullArguments() - { - var client = new MilestonesClient(Substitute.For()); - - await AssertEx.Throws(async () => await client.Get(null, "name", 1)); - await AssertEx.Throws(async () => await client.Get("owner", null, 1)); - await AssertEx.Throws(async () => await client.Get(null, "", 1)); - await AssertEx.Throws(async () => await client.Get("", null, 1)); - } - } - - public class TheGetForRepositoryMethod - { - [Fact] - public async Task RequestsCorrectUrl() - { - var connection = Substitute.For(); - var client = new MilestonesClient(connection); - - await client.GetForRepository("fake", "repo"); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones"), - Arg.Any>()); - } - - [Fact] - public void SendsAppropriateParameters() - { - var connection = Substitute.For(); - var client = new MilestonesClient(connection); - - client.GetForRepository("fake", "repo", new MilestoneRequest { SortDirection = SortDirection.Descending }); - - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones"), - Arg.Is>(d => d.Count == 3 - && d["direction"] == "desc" - && d["state"] == "open" - && d["sort"] == "due_date")); - } - } - - public class TheCreateMethod - { - [Fact] - public void PostsToCorrectUrl() - { - var newIssue = new NewIssue("some title"); - var connection = Substitute.For(); - var client = new IssuesClient(connection); - - client.Create("fake", "repo", newIssue); - - connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), - newIssue); + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + client.Get("fake", "repo", 42); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones/42"), + null); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new MilestonesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Get(null, "name", 1)); + await AssertEx.Throws(async () => await client.Get("owner", null, 1)); + await AssertEx.Throws(async () => await client.Get(null, "", 1)); + await AssertEx.Throws(async () => await client.Get("", null, 1)); + } } - [Fact] - public async Task EnsuresArgumentsNotNull() + public class TheGetForRepositoryMethod { - var connection = Substitute.For(); - var client = new IssuesClient(connection); - - AssertEx.Throws(async () => await - client.Create(null, "name", new NewIssue("title"))); - AssertEx.Throws(async () => await - client.Create("", "name", new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", null, new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "", new NewIssue("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "name", null)); + [Fact] + public async Task RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + await client.GetForRepository("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones"), + Arg.Any>()); + } + + [Fact] + public void SendsAppropriateParameters() + { + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + client.GetForRepository("fake", "repo", new MilestoneRequest { SortDirection = SortDirection.Descending }); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones"), + Arg.Is>(d => d.Count == 3 + && d["direction"] == "desc" + && d["state"] == "open" + && d["sort"] == "due_date")); + } } - } - public class TheUpdateMethod - { - [Fact] - public void PostsToCorrectUrl() + public class TheCreateMethod { - var milestoneUpdate = new MilestoneUpdate(); - var connection = Substitute.For(); - var client = new MilestonesClient(connection); - - client.Update("fake", "repo", 42, milestoneUpdate); - - connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones/42"), - milestoneUpdate); + [Fact] + public void PostsToCorrectUrl() + { + var newMilestone = new NewMilestone("some title"); + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + client.Create("fake", "repo", newMilestone); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones"), + newMilestone); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + AssertEx.Throws(async () => await + client.Create(null, "name", new NewMilestone("title"))); + AssertEx.Throws(async () => await + client.Create("", "name", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", null, new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "name", null)); + } } - [Fact] - public async Task EnsuresArgumentsNotNull() + public class TheUpdateMethod { - var connection = Substitute.For(); - var client = new MilestonesClient(connection); - - AssertEx.Throws(async () => await - client.Create(null, "name", new NewMilestone("title"))); - AssertEx.Throws(async () => await - client.Create("", "name", new NewMilestone("x"))); - AssertEx.Throws(async () => await - client.Create("owner", null, new NewMilestone("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "", new NewMilestone("x"))); - AssertEx.Throws(async () => await - client.Create("owner", "name", null)); + [Fact] + public void PostsToCorrectUrl() + { + var milestoneUpdate = new MilestoneUpdate(); + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + client.Update("fake", "repo", 42, milestoneUpdate); + + connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones/42"), + milestoneUpdate); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + AssertEx.Throws(async () => await + client.Create(null, "name", new NewMilestone("title"))); + AssertEx.Throws(async () => await + client.Create("", "name", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", null, new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "name", null)); + } } - } - public class TheDeleteMethod - { - [Fact] - public void PostsToCorrectUrl() + public class TheDeleteMethod { - var connection = Substitute.For(); - var client = new MilestonesClient(connection); - - client.Delete("fake", "repo", 42); - - connection.Received().Delete(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones/42")); + [Fact] + public void PostsToCorrectUrl() + { + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + client.Delete("fake", "repo", 42); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "repos/fake/repo/milestones/42")); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new MilestonesClient(connection); + + AssertEx.Throws(async () => await + client.Delete(null, "name", 42)); + AssertEx.Throws(async () => await + client.Delete("", "name", 42)); + AssertEx.Throws(async () => await + client.Delete("owner", null, 42)); + AssertEx.Throws(async () => await + client.Delete("owner", "", 42)); + } } - [Fact] - public async Task EnsuresArgumentsNotNull() - { - var connection = Substitute.For(); - var client = new MilestonesClient(connection); - - AssertEx.Throws(async () => await - client.Delete(null, "name", 42)); - AssertEx.Throws(async () => await - client.Delete("", "name", 42)); - AssertEx.Throws(async () => await - client.Delete("owner", null, 42)); - AssertEx.Throws(async () => await - client.Delete("owner", "", 42)); - } - } - - public class TheCtor - { - [Fact] - public void EnsuresArgument() + public class TheCtor { - Assert.Throws(() => new MilestonesClient(null)); + [Fact] + public void EnsuresArgument() + { + Assert.Throws(() => new MilestonesClient(null)); + } } } } diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index af4759db16..1b1e35de52 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -104,6 +104,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableMilestonesClientTests.cs b/Octokit.Tests/Reactive/ObservableMilestonesClientTests.cs new file mode 100644 index 0000000000..baa18f3098 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableMilestonesClientTests.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.Reactive.Linq; +using System.Threading.Tasks; +using NSubstitute; +using Octokit; +using Octokit.Internal; +using Octokit.Reactive.Clients; +using Octokit.Tests.Helpers; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableMilestonesClientTests + { + public class TheGetMethod + { + [Fact] + public void GetsFromClientIssueMilestone() + { + var gitHubClient = Substitute.For(); + var client = new ObservableMilestonesClient(gitHubClient); + + client.Get("fake", "repo", 42); + + gitHubClient.Issue.Milestone.Received().Get("fake", "repo", 42); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableMilestonesClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Get(null, "name", 1)); + await AssertEx.Throws(async () => await client.Get("owner", null, 1)); + await AssertEx.Throws(async () => await client.Get(null, "", 1)); + await AssertEx.Throws(async () => await client.Get("", null, 1)); + } + } + + public class TheGetForRepositoryMethod + { + [Fact] + public void ReturnsEveryPageOfMilestones() + { + var firstPageUrl = new Uri("repos/fake/repo/milestones", UriKind.Relative); + var secondPageUrl = new Uri("https://example.com/page/2"); + var firstPageLinks = new Dictionary {{"next", secondPageUrl}}; + var firstPageResponse = new ApiResponse> + { + BodyAsObject = new List + { + new Milestone {Number = 1}, + new Milestone {Number = 2}, + new Milestone {Number = 3}, + }, + ApiInfo = CreateApiInfo(firstPageLinks) + }; + var thirdPageUrl = new Uri("https://example.com/page/3"); + var secondPageLinks = new Dictionary {{"next", thirdPageUrl}}; + var secondPageResponse = new ApiResponse> + { + BodyAsObject = new List + { + new Milestone {Number = 4}, + new Milestone {Number = 5}, + new Milestone {Number = 6}, + }, + ApiInfo = CreateApiInfo(secondPageLinks) + }; + var lastPageResponse = new ApiResponse> + { + BodyAsObject = new List + { + new Milestone {Number = 7}, + }, + ApiInfo = CreateApiInfo(new Dictionary()) + }; + var gitHubClient = Substitute.For(); + gitHubClient.Connection.GetAsync>(firstPageUrl, null, null) + .Returns(Task.Factory.StartNew>>(() => firstPageResponse)); + gitHubClient.Connection.GetAsync>(secondPageUrl, null, null) + .Returns(Task.Factory.StartNew>>(() => secondPageResponse)); + gitHubClient.Connection.GetAsync>(thirdPageUrl, null, null) + .Returns(Task.Factory.StartNew>>(() => lastPageResponse)); + var client = new ObservableMilestonesClient(gitHubClient); + + var results = client.GetForRepository("fake", "repo").ToArray().Wait(); + + Assert.Equal(7, results.Length); + Assert.Equal(firstPageResponse.BodyAsObject[0].Number, results[0].Number); + Assert.Equal(secondPageResponse.BodyAsObject[1].Number, results[4].Number); + Assert.Equal(lastPageResponse.BodyAsObject[0].Number, results[6].Number); + } + + [Fact] + public void SendsAppropriateParameters() + { + var firstPageUrl = new Uri("repos/fake/repo/milestones", UriKind.Relative); + var secondPageUrl = new Uri("https://example.com/page/2"); + var firstPageLinks = new Dictionary {{"next", secondPageUrl}}; + var firstPageResponse = new ApiResponse> + { + BodyAsObject = new List + { + new Milestone {Number = 1}, + new Milestone {Number = 2}, + new Milestone {Number = 3}, + }, + ApiInfo = CreateApiInfo(firstPageLinks) + }; + var thirdPageUrl = new Uri("https://example.com/page/3"); + var secondPageLinks = new Dictionary {{"next", thirdPageUrl}}; + var secondPageResponse = new ApiResponse> + { + BodyAsObject = new List + { + new Milestone {Number = 4}, + new Milestone {Number = 5}, + new Milestone {Number = 6}, + }, + ApiInfo = CreateApiInfo(secondPageLinks) + }; + var lastPageResponse = new ApiResponse> + { + BodyAsObject = new List + { + new Milestone {Number = 7}, + }, + ApiInfo = CreateApiInfo(new Dictionary()) + }; + var gitHubClient = Substitute.For(); + gitHubClient.Connection.GetAsync>(Arg.Is(firstPageUrl), + Arg.Is>(d => d.Count == 3 + && d["direction"] == "desc" + && d["state"] == "open" + && d["sort"] == "due_date"), Arg.Any()) + .Returns(Task.Factory.StartNew>>(() => firstPageResponse)); + gitHubClient.Connection.GetAsync>(secondPageUrl, null, null) + .Returns(Task.Factory.StartNew>>(() => secondPageResponse)); + gitHubClient.Connection.GetAsync>(thirdPageUrl, null, null) + .Returns(Task.Factory.StartNew>>(() => lastPageResponse)); + var client = new ObservableMilestonesClient(gitHubClient); + + var results = client.GetForRepository("fake", "repo", new MilestoneRequest { SortDirection = SortDirection.Descending }).ToArray().Wait(); + + Assert.Equal(7, results.Length); + Assert.Equal(firstPageResponse.BodyAsObject[0].Number, results[0].Number); + Assert.Equal(secondPageResponse.BodyAsObject[1].Number, results[4].Number); + Assert.Equal(lastPageResponse.BodyAsObject[0].Number, results[6].Number); + } + } + + public class TheCreateMethod + { + [Fact] + public void CreatesFromClientIssueMilestone() + { + var newMilestone = new NewMilestone("some title"); + var gitHubClient = Substitute.For(); + var client = new ObservableMilestonesClient(gitHubClient); + + client.Create("fake", "repo", newMilestone); + + gitHubClient.Issue.Milestone.Received().Create("fake", "repo", newMilestone); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var gitHubClient = Substitute.For(); + var client = new ObservableMilestonesClient(gitHubClient); + + AssertEx.Throws(async () => await + client.Create(null, "name", new NewMilestone("title"))); + AssertEx.Throws(async () => await + client.Create("", "name", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", null, new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "name", null)); + } + } + + public class TheUpdateMethod + { + [Fact] + public void UpdatesClientIssueMilestone() + { + var milestoneUpdate = new MilestoneUpdate(); + var gitHubClient = Substitute.For(); + var client = new ObservableMilestonesClient(gitHubClient); + + client.Update("fake", "repo", 42, milestoneUpdate); + + gitHubClient.Issue.Milestone.Received().Update("fake", "repo", 42, milestoneUpdate); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var gitHubClient = Substitute.For(); + var client = new ObservableMilestonesClient(gitHubClient); + + AssertEx.Throws(async () => await + client.Create(null, "name", new NewMilestone("title"))); + AssertEx.Throws(async () => await + client.Create("", "name", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", null, new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "", new NewMilestone("x"))); + AssertEx.Throws(async () => await + client.Create("owner", "name", null)); + } + } + + public class TheDeleteMethod + { + [Fact] + public void DeletesFromClientIssueMilestone() + { + var gitHubClient = Substitute.For(); + var client = new ObservableMilestonesClient(gitHubClient); + + client.Delete("fake", "repo", 42); + + gitHubClient.Issue.Milestone.Received().Delete("fake", "repo", 42); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var gitHubClient = Substitute.For(); + var client = new ObservableMilestonesClient(gitHubClient); + + AssertEx.Throws(async () => await + client.Delete(null, "name", 42)); + AssertEx.Throws(async () => await + client.Delete("", "name", 42)); + AssertEx.Throws(async () => await + client.Delete("owner", null, 42)); + AssertEx.Throws(async () => await + client.Delete("owner", "", 42)); + } + } + + public class TheCtor + { + [Fact] + public void EnsuresArgument() + { + Assert.Throws(() => new MilestonesClient(null)); + } + } + + static ApiInfo CreateApiInfo(IDictionary links) + { + return new ApiInfo(links, new List(), new List(), "etag", new RateLimit(new Dictionary())); + } + } +} diff --git a/Octokit/Clients/IMilestonesClient.cs b/Octokit/Clients/IMilestonesClient.cs index d73c643c0a..b633e198de 100644 --- a/Octokit/Clients/IMilestonesClient.cs +++ b/Octokit/Clients/IMilestonesClient.cs @@ -7,11 +7,10 @@ namespace Octokit public interface IMilestonesClient { /// - /// Gets all Milestones across all the authenticated user’s visible repositories including owned repositories, - /// member repositories, and organization repositories. + /// Gets a single Milestone by number. /// /// - /// http://developer.github.com/v3/Milestones/#get-a-single-Milestone + /// http://developer.github.com/v3/issues/milestones/#get-a-single-milestone /// /// [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", @@ -22,7 +21,7 @@ public interface IMilestonesClient /// Gets all open milestones for the repository. /// /// - /// http://developer.github.com/v3/Milestones/#list-Milestones-for-a-repository + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository /// /// The owner of the repository /// The name of the repository @@ -33,7 +32,7 @@ public interface IMilestonesClient /// Gets all open milestones for the repository. /// /// - /// http://developer.github.com/v3/Milestones/#list-Milestones-for-a-repository + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository /// /// The owner of the repository /// The name of the repository @@ -45,7 +44,7 @@ public interface IMilestonesClient /// Creates a milestone for the specified repository. Any user with pull access to a repository can create an /// Milestone. /// - /// http://developer.github.com/v3/Milestones/#create-an-Milestone + /// http://developer.github.com/v3/issues/milestones/#create-a-milestone /// The owner of the repository /// The name of the repository /// A instance describing the new Milestone to create @@ -56,7 +55,7 @@ public interface IMilestonesClient /// Creates a milestone for the specified repository. Any user with pull access to a repository can create an /// Milestone. /// - /// http://developer.github.com/v3/Milestones/#update-a-milestone + /// http://developer.github.com/v3/issues/milestones/#update-a-milestone /// The owner of the repository /// The name of the repository /// The Milestone number @@ -69,7 +68,7 @@ public interface IMilestonesClient /// Deletes a milestone for the specified repository. Any user with pull access to a repository can create an /// Milestone. /// - /// http://developer.github.com/v3/Milestones/#delete-a-milestone + /// http://developer.github.com/v3/issues/milestones/#delete-a-milestone /// The owner of the repository /// The name of the repository /// The milestone number diff --git a/Octokit/Clients/MilestonesClient.cs b/Octokit/Clients/MilestonesClient.cs index d30c3e284e..65b127dc90 100644 --- a/Octokit/Clients/MilestonesClient.cs +++ b/Octokit/Clients/MilestonesClient.cs @@ -11,11 +11,10 @@ public MilestonesClient(IApiConnection apiConnection) : base(apiConnection) } /// - /// Gets all Milestones across all the authenticated user’s visible repositories including owned repositories, - /// member repositories, and organization repositories. + /// Gets a single Milestone by number. /// /// - /// http://developer.github.com/v3/Milestones/#get-a-single-Milestone + /// http://developer.github.com/v3/issues/milestones/#get-a-single-Milestone /// /// public Task Get(string owner, string name, int number) @@ -30,7 +29,7 @@ public Task Get(string owner, string name, int number) /// Gets all open milestones for the repository. /// /// - /// http://developer.github.com/v3/Milestones/#list-Milestones-for-a-repository + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository /// /// The owner of the repository /// The name of the repository @@ -44,7 +43,7 @@ public Task> GetForRepository(string owner, string name /// Gets all open milestones for the repository. /// /// - /// http://developer.github.com/v3/Milestones/#list-Milestones-for-a-repository + /// http://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository /// /// The owner of the repository /// The name of the repository @@ -64,7 +63,7 @@ public Task> GetForRepository(string owner, string name /// Creates an Milestone for the specified repository. Any user with pull access to a repository can create an /// Milestone. /// - /// http://developer.github.com/v3/Milestones/#create-an-Milestone + /// http://developer.github.com/v3/issues/milestones/#create-a-milestone /// The owner of the repository /// The name of the repository /// A instance describing the new Milestone to create @@ -82,7 +81,7 @@ public Task Create(string owner, string name, NewMilestone newMilesto /// Creates an Milestone for the specified repository. Any user with pull access to a repository can create an /// Milestone. /// - /// http://developer.github.com/v3/Milestones/#create-an-Milestone + /// http://developer.github.com/v3/issues/milestones/#create-a-milestone /// The owner of the repository /// The name of the repository /// The Milestone number @@ -102,7 +101,7 @@ public Task Update(string owner, string name, int number, MilestoneUp /// Deletes a milestone for the specified repository. Any user with pull access to a repository can create an /// Milestone. /// - /// http://developer.github.com/v3/Milestones/#delete-a-milestone + /// http://developer.github.com/v3/issues/milestones/#delete-a-milestone /// The owner of the repository /// The name of the repository /// The milestone number