diff --git a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs index f36bb44a..fb9efd7f 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs @@ -32,6 +32,15 @@ namespace Octokit.Reactive Justification = "Method makes a network request")] IObservable GetAllForCurrent(); + /// + /// Returns all the organizations for the current user. + /// + /// Options for changing the API response + /// + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", + Justification = "Method makes a network request")] + IObservable GetAllForCurrent(ApiOptions options); + /// /// Returns all the organizations for the specified user /// @@ -39,6 +48,14 @@ namespace Octokit.Reactive /// IObservable GetAll(string user); + /// + /// Returns all the organizations for the specified user + /// + /// The login for the user + /// Options for changing the API response + /// + IObservable GetAll(string user, ApiOptions options); + /// /// Update the specified organization with data from . /// diff --git a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs index 64afff9d..ff5b3101 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs @@ -52,6 +52,18 @@ namespace Octokit.Reactive /// public IObservable GetAllForCurrent() { + return GetAllForCurrent(ApiOptions.None); + } + + /// + /// Returns all the organizations for the current user. + /// + /// Options for changing the API response + /// + public IObservable GetAllForCurrent(ApiOptions options) + { + Ensure.ArgumentNotNull(options, "options"); + return _connection.GetAndFlattenAllPages(ApiUrls.Organizations()); } @@ -67,6 +79,20 @@ namespace Octokit.Reactive return _connection.GetAndFlattenAllPages(ApiUrls.Organizations(user)); } + /// + /// Returns all the organizations for the specified user + /// + /// The login for the user + /// Options for changing the API response + /// + public IObservable GetAll(string user, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(user, "user"); + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.Organizations(user), options); + } + /// /// Update the specified organization with data from . /// @@ -76,6 +102,9 @@ namespace Octokit.Reactive /// A public IObservable Update(string organizationName, OrganizationUpdate updateRequest) { + Ensure.ArgumentNotNullOrEmptyString(organizationName, "organizationName"); + Ensure.ArgumentNotNull(updateRequest, "updateRequest"); + return _client.Update(organizationName, updateRequest).ToObservable(); } } diff --git a/Octokit.Tests.Integration/Clients/OrganizationClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationClientTests.cs new file mode 100644 index 00000000..5577f154 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/OrganizationClientTests.cs @@ -0,0 +1,124 @@ +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Integration.Clients +{ + public class OrganizationClientTests + { + public class TheGetAllMethod + { + readonly IGitHubClient _github; + readonly IOrganizationsClient _organizationsClient; + + public TheGetAllMethod() + { + _github = EnterpriseHelper.GetAuthenticatedClient(); + + _organizationsClient = _github.Organization; + } + + [GitHubEnterpriseTest] + public async Task CanListOrganizations() + { + string orgLogin = Helper.MakeNameWithTimestamp("MyOrganization"); + string orgName = string.Concat(orgLogin, " Display Name"); + + var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.UserName, orgName); + var organization = await + _github.Enterprise.Organization.Create(newOrganization); + + Assert.NotNull(organization); + + var milestones = await _organizationsClient.GetAllForCurrent(); + + Assert.NotEmpty(milestones); + } + + [GitHubEnterpriseTest] + public async Task ReturnsCorrectCountOfOrganizationsWithoutStart() + { + string orgLogin1 = Helper.MakeNameWithTimestamp("MyOrganization1"); + string orgName1 = string.Concat(orgLogin1, " Display Name 1"); + string orgLogin2 = Helper.MakeNameWithTimestamp("MyOrganization2"); + string orgName2 = string.Concat(orgLogin2, " Display Name 2"); + + var newOrganization1 = new NewOrganization(orgLogin1, EnterpriseHelper.UserName, orgName1); + var newOrganization2 = new NewOrganization(orgLogin2, EnterpriseHelper.UserName, orgName2); + await _github.Enterprise.Organization.Create(newOrganization1); + await _github.Enterprise.Organization.Create(newOrganization2); + + var options = new ApiOptions + { + PageSize = 2, + PageCount = 1 + }; + + var organizations = await _organizationsClient.GetAllForCurrent(options); + + Assert.Equal(2, organizations.Count); + } + + [GitHubEnterpriseTest] + public async Task ReturnsCorrectCountOfOrganizationsWithStart() + { + string orgLogin1 = Helper.MakeNameWithTimestamp("MyOrganization1"); + string orgName1 = string.Concat(orgLogin1, " Display Name 1"); + string orgLogin2 = Helper.MakeNameWithTimestamp("MyOrganization2"); + string orgName2 = string.Concat(orgLogin2, " Display Name 2"); + + var newOrganization1 = new NewOrganization(orgLogin1, EnterpriseHelper.UserName, orgName1); + var newOrganization2 = new NewOrganization(orgLogin2, EnterpriseHelper.UserName, orgName2); + await _github.Enterprise.Organization.Create(newOrganization1); + await _github.Enterprise.Organization.Create(newOrganization2); + + var options = new ApiOptions + { + PageSize = 1, + PageCount = 1, + StartPage = 2, + }; + + var organizations = await _organizationsClient.GetAllForCurrent(options); + + Assert.Equal(1, organizations.Count); + } + + [GitHubEnterpriseTest] + public async Task ReturnsDistinctResultsBasedOnStartPage() + { + string orgLogin1 = Helper.MakeNameWithTimestamp("MyOrganization1"); + string orgName1 = string.Concat(orgLogin1, " Display Name 1"); + string orgLogin2 = Helper.MakeNameWithTimestamp("MyOrganization2"); + string orgName2 = string.Concat(orgLogin2, " Display Name 2"); + string orgLogin3 = Helper.MakeNameWithTimestamp("MyOrganization3"); + string orgName3 = string.Concat(orgLogin3, " Display Name 3"); + + var newOrganization1 = new NewOrganization(orgLogin1, EnterpriseHelper.UserName, orgName1); + var newOrganization2 = new NewOrganization(orgLogin2, EnterpriseHelper.UserName, orgName2); + var newOrganization3 = new NewOrganization(orgLogin3, EnterpriseHelper.UserName, orgName3); + await _github.Enterprise.Organization.Create(newOrganization1); + await _github.Enterprise.Organization.Create(newOrganization2); + await _github.Enterprise.Organization.Create(newOrganization3); + + var startOptions = new ApiOptions + { + PageSize = 1, + PageCount = 1 + }; + + var firstPage = await _organizationsClient.GetAllForCurrent(startOptions); + + var skipStartOptions = new ApiOptions + { + PageSize = 1, + PageCount = 1, + StartPage = 2 + }; + + var secondPage = await _organizationsClient.GetAllForCurrent(skipStartOptions); + + Assert.NotEqual(firstPage[0].Login, secondPage[0].Login); + } + } + } +} diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index d5adfaaf..be61279e 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -94,6 +94,7 @@ + diff --git a/Octokit.Tests/Clients/OrganizationsClientTests.cs b/Octokit.Tests/Clients/OrganizationsClientTests.cs index 518de8cc..ec5b1584 100644 --- a/Octokit.Tests/Clients/OrganizationsClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationsClientTests.cs @@ -23,72 +23,137 @@ namespace Octokit.Tests.Clients public class TheGetMethod { [Fact] - public void RequestsCorrectUrl() + public async Task RequestsCorrectUrl() { - var client = Substitute.For(); - var orgsClient = new OrganizationsClient(client); + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); - orgsClient.Get("orgName"); + await client.Get("orgName"); - client.Received().Get(Arg.Is(u => u.ToString() == "orgs/orgName")); + connection.Received().Get(Arg.Is(u => u.ToString() == "orgs/orgName")); } [Fact] public async Task EnsuresNonNullArguments() { - var orgs = new OrganizationsClient(Substitute.For()); + var client = new OrganizationsClient(Substitute.For()); - await Assert.ThrowsAsync(() => orgs.Get(null)); + await Assert.ThrowsAsync(() => client.Get(null)); + + await Assert.ThrowsAsync(() => client.Get("")); } } public class TheGetAllMethod { [Fact] - public void RequestsTheCorrectUrl() + public async Task RequestsTheCorrectUrl() { - var client = Substitute.For(); - var orgs = new OrganizationsClient(client); + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); - orgs.GetAll("username"); + await client.GetAll("username"); - client.Received().GetAll(Arg.Is(u => u.ToString() == "users/username/orgs")); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/username/orgs"), Args.ApiOptions); + } + + [Fact] + public async Task RequestsTheCorrectUrlWithApiOptions() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + var options = new ApiOptions + { + StartPage = 1, + PageCount = 1, + PageSize = 1 + }; + + await client.GetAll("username", options); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/username/orgs"), options); } [Fact] public async Task EnsuresNonNullArguments() { - var orgs = new OrganizationsClient(Substitute.For()); + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); - await Assert.ThrowsAsync(() => orgs.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll(null, ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAll("username", null)); + + await Assert.ThrowsAsync(() => client.GetAll("")); + await Assert.ThrowsAsync(() => client.GetAll("", ApiOptions.None)); } } public class TheGetAllForCurrentMethod { [Fact] - public void RequestsTheCorrectUrl() + public async Task RequestsTheCorrectUrl() { - var client = Substitute.For(); - var orgs = new OrganizationsClient(client); + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); - orgs.GetAllForCurrent(); + await client.GetAllForCurrent(); - client.Received().GetAll(Arg.Is(u => u.ToString() == "user/orgs")); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "user/orgs"), Args.ApiOptions); + } + + [Fact] + public async Task RequestsTheCorrectUrlWithApiOptions() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + var options = new ApiOptions + { + StartPage = 1, + PageCount = 1, + PageSize = 1 + }; + + await client.GetAllForCurrent(options); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "user/orgs"), options); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + await Assert.ThrowsAsync(() => client.GetAllForCurrent(null)); } } public class TheUpdateMethod { [Fact] - public void RequestsTheCorrectUrl() + public async Task RequestsTheCorrectUrl() { - var client = Substitute.For(); - var orgs = new OrganizationsClient(client); + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); - orgs.Update("initrode", new OrganizationUpdate()); + await client.Update("initrode", new OrganizationUpdate()); - client.Received().Patch(Arg.Is(u => u.ToString() == "orgs/initrode"), Args.OrganizationUpdate); + connection.Received().Patch(Arg.Is(u => u.ToString() == "orgs/initrode"), Args.OrganizationUpdate); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + await Assert.ThrowsAsync(() => client.Update(null, new OrganizationUpdate())); + await Assert.ThrowsAsync(() => client.Update("org", null)); + + await Assert.ThrowsAsync(() => client.Update("", new OrganizationUpdate())); } } } diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 87cd858a..5e78e372 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -207,6 +207,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableOrganizationsClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationsClientTests.cs new file mode 100644 index 00000000..4889a4e5 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableOrganizationsClientTests.cs @@ -0,0 +1,157 @@ +using System; +using NSubstitute; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableOrganizationsClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new ObservableOrganizationsClient(null)); + } + } + + public class TheGetMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + client.Get("orgName"); + + gitHubClient.Received().Organization.Get("orgName"); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var client = new ObservableOrganizationsClient(Substitute.For()); + + Assert.Throws(() => client.Get(null)); + + Assert.Throws(() => client.Get("")); + } + } + + public class TheGetAllMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + client.GetAll("username"); + + gitHubClient.Received().Organization.GetAll("username"); + } + + [Fact] + public void RequestsTheCorrectUrlWithApiOptions() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + var options = new ApiOptions + { + StartPage = 1, + PageCount = 1, + PageSize = 1 + }; + + client.GetAll("username", options); + + gitHubClient.Received().Organization.GetAll("username", options); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + Assert.Throws(() => client.GetAll(null)); + Assert.Throws(() => client.GetAll(null, ApiOptions.None)); + Assert.Throws(() => client.GetAll("username", null)); + + Assert.Throws(() => client.GetAll("")); + Assert.Throws(() => client.GetAll("", ApiOptions.None)); + } + } + + public class TheGetAllForCurrentMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + client.GetAllForCurrent(); + + gitHubClient.Received().Organization.GetAllForCurrent(); + } + + [Fact] + public void RequestsTheCorrectUrlWithApiOptions() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + var options = new ApiOptions + { + StartPage = 1, + PageCount = 1, + PageSize = 1 + }; + + client.GetAllForCurrent(options); + + gitHubClient.Received().Organization.GetAllForCurrent(options); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + Assert.Throws(() => client.GetAllForCurrent(null)); + } + } + + public class TheUpdateMethod + { + [Fact] + public void RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + var organizationUpdate = new OrganizationUpdate(); + client.Update("initrode", organizationUpdate); + + gitHubClient.Received().Organization.Update("initrode", organizationUpdate); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationsClient(gitHubClient); + + Assert.Throws(() => client.Update(null, new OrganizationUpdate())); + Assert.Throws(() => client.Update("org", null)); + + Assert.Throws(() => client.Update("", new OrganizationUpdate())); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Clients/IOrganizationsClient.cs b/Octokit/Clients/IOrganizationsClient.cs index 9d5cf337..fea9ab0a 100644 --- a/Octokit/Clients/IOrganizationsClient.cs +++ b/Octokit/Clients/IOrganizationsClient.cs @@ -43,6 +43,16 @@ namespace Octokit Justification = "Method makes a network request")] Task> GetAllForCurrent(); + /// + /// Returns all s for the current user. + /// + /// Options for changing the API response + /// Thrown when a general API error occurs. + /// A list of the current user's s. + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", + Justification = "Method makes a network request")] + Task> GetAllForCurrent(ApiOptions options); + /// /// Returns all s for the specified user. /// @@ -50,6 +60,15 @@ namespace Octokit /// A list of the specified user's s. Task> GetAll(string user); + /// + /// Returns all s for the specified user. + /// + /// The login of the user + /// Options for changing the API response + /// Thrown when a general API error occurs. + /// A list of the specified user's s. + Task> GetAll(string user, ApiOptions options); + /// /// Update the specified organization with data from . /// diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs index 113247c1..32fa827c 100644 --- a/Octokit/Clients/OrganizationsClient.cs +++ b/Octokit/Clients/OrganizationsClient.cs @@ -54,19 +54,48 @@ namespace Octokit /// A list of the current user's s. public Task> GetAllForCurrent() { - return ApiConnection.GetAll(ApiUrls.Organizations()); + return GetAllForCurrent(ApiOptions.None); + } + + /// + /// Returns all s for the current user. + /// + /// Options for changing the API response + /// Thrown when a general API error occurs. + /// A list of the current user's s. + public Task> GetAllForCurrent(ApiOptions options) + { + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.Organizations(), options); } /// /// Returns all s for the specified user. /// + /// The login of the user /// Thrown when a general API error occurs. /// A list of the specified user's s. public Task> GetAll(string user) { Ensure.ArgumentNotNullOrEmptyString(user, "user"); - return ApiConnection.GetAll(ApiUrls.Organizations(user)); + return GetAll(user, ApiOptions.None); + } + + /// + /// Returns all s for the specified user. + /// + /// The login of the user + /// Options for changing the API response + /// Thrown when a general API error occurs. + /// A list of the specified user's s. + public Task> GetAll(string user, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(user, "user"); + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.Organizations(user), options); } ///