diff --git a/Octokit.Reactive/Clients/IObservableNotificationsClient.cs b/Octokit.Reactive/Clients/IObservableNotificationsClient.cs index aa2df53e..709f902e 100644 --- a/Octokit.Reactive/Clients/IObservableNotificationsClient.cs +++ b/Octokit.Reactive/Clients/IObservableNotificationsClient.cs @@ -14,28 +14,74 @@ namespace Octokit.Reactive [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] IObservable GetAllForCurrent(); + /// + /// Retrieves all of the s for the current user. + /// + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + IObservable GetAllForCurrent(ApiOptions options); + /// /// Retrieves all of the s for the current user specific to the specified repository. /// + /// The owner of the repository. + /// The name of the repository. /// Thrown if the client is not authenticated. /// A of . IObservable GetAllForRepository(string owner, string name); + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + IObservable GetAllForRepository(string owner, string name, ApiOptions options); + /// /// Retrieves all of the s for the current user. /// + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] IObservable GetAllForCurrent(NotificationsRequest request); + /// + /// Retrieves all of the s for the current user. + /// + /// Specifies the parameters to filter notifications by + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + IObservable GetAllForCurrent(NotificationsRequest request, ApiOptions options); + /// /// Retrieves all of the s for the current user specific to the specified repository. /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . IObservable GetAllForRepository(string owner, string name, NotificationsRequest request); + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + IObservable GetAllForRepository(string owner, string name, NotificationsRequest request, ApiOptions options); + /// /// Marks all notifications as read. /// @@ -65,10 +111,10 @@ namespace Octokit.Reactive /// /// The owner of the repository /// The name of the repository - /// The parameter which specifies which notifications to mark. + /// The parameter which specifies which notifications to mark. /// http://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository /// - IObservable MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsRead); + IObservable MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsReadRequest); /// /// Retrives a single by Id. diff --git a/Octokit.Reactive/Clients/ObservableNotificationsClient.cs b/Octokit.Reactive/Clients/ObservableNotificationsClient.cs index 1ba1bf72..775c636e 100644 --- a/Octokit.Reactive/Clients/ObservableNotificationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableNotificationsClient.cs @@ -25,35 +25,88 @@ namespace Octokit.Reactive /// A of . public IObservable GetAllForCurrent() { - return _connection.GetAndFlattenAllPages(ApiUrls.Notifications()); + return GetAllForCurrent(ApiOptions.None); } - /// /// Retrieves all of the s for the current user. /// + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + public IObservable GetAllForCurrent(ApiOptions options) + { + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.Notifications(), options); + } + + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Thrown if the client is not authenticated. + /// A of . + public IObservable GetAllForRepository(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return GetAllForRepository(owner, name, ApiOptions.None); + } + + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + public IObservable GetAllForRepository(string owner, string name, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.Notifications(owner, name), options); + } + + /// + /// Retrieves all of the s for the current user. + /// + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . public IObservable GetAllForCurrent(NotificationsRequest request) { Ensure.ArgumentNotNull(request, "request"); - return _connection.GetAndFlattenAllPages(ApiUrls.Notifications(), request.ToParametersDictionary()); + return GetAllForCurrent(request, ApiOptions.None); } /// - /// Retrieves all of the s for the current user specific to the specified repository. + /// Retrieves all of the s for the current user. /// + /// Specifies the parameters to filter notifications by + /// Options for changing the API response /// Thrown if the client is not authenticated. - /// A of . - public IObservable GetAllForRepository(string owner, string name) + /// A of . + public IObservable GetAllForCurrent(NotificationsRequest request, ApiOptions options) { - return _connection.GetAndFlattenAllPages(ApiUrls.Notifications(owner, name)); + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.Notifications(), request.ToParametersDictionary(), options); } /// /// Retrieves all of the s for the current user specific to the specified repository. /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . public IObservable GetAllForRepository(string owner, string name, NotificationsRequest request) @@ -62,7 +115,26 @@ namespace Octokit.Reactive Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(request, "request"); - return _connection.GetAndFlattenAllPages(ApiUrls.Notifications(owner, name), request.ToParametersDictionary()); + return GetAllForRepository(owner, name, request, ApiOptions.None); + } + + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + public IObservable GetAllForRepository(string owner, string name, NotificationsRequest request, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.Notifications(owner, name), request.ToParametersDictionary(), options); } /// @@ -83,6 +155,8 @@ namespace Octokit.Reactive /// public IObservable MarkAsRead(MarkAsReadRequest markAsReadRequest) { + Ensure.ArgumentNotNull(markAsReadRequest, "markAsReadRequest"); + return _notificationsClient.MarkAsRead(markAsReadRequest).ToObservable(); } @@ -95,6 +169,9 @@ namespace Octokit.Reactive /// public IObservable MarkAsReadForRepository(string owner, string name) { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + return _notificationsClient.MarkAsReadForRepository(owner, name).ToObservable(); } @@ -103,12 +180,16 @@ namespace Octokit.Reactive /// /// The owner of the repository /// The name of the repository - /// The parameter which specifies which notifications to mark. + /// The parameter which specifies which notifications to mark. /// http://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository /// - public IObservable MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsRead) + public IObservable MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsReadRequest) { - return _notificationsClient.MarkAsReadForRepository(owner, name, markAsRead).ToObservable(); + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(markAsReadRequest, "markAsReadRequest"); + + return _notificationsClient.MarkAsReadForRepository(owner, name, markAsReadRequest).ToObservable(); } /// @@ -153,6 +234,8 @@ namespace Octokit.Reactive /// public IObservable SetThreadSubscription(int id, NewThreadSubscription threadSubscription) { + Ensure.ArgumentNotNull(threadSubscription, "threadSubscription"); + return _notificationsClient.SetThreadSubscription(id, threadSubscription).ToObservable(); } diff --git a/Octokit.Tests/Clients/NotificationsClientTests.cs b/Octokit.Tests/Clients/NotificationsClientTests.cs index 97a8dd13..43c8e10d 100644 --- a/Octokit.Tests/Clients/NotificationsClientTests.cs +++ b/Octokit.Tests/Clients/NotificationsClientTests.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Threading.Tasks; using NSubstitute; using Xunit; @@ -27,7 +29,72 @@ namespace Octokit.Tests.Clients client.GetAllForCurrent(); - connection.Received().GetAll(endpoint); + connection.Received().GetAll(endpoint, Args.ApiOptions); + } + + [Fact] + public void RequestsCorrectUrlApiOptions() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var client = new NotificationsClient(connection); + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForCurrent(options); + + connection.Received().GetAll(endpoint, options); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequest() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var client = new NotificationsClient(connection); + + var notificationsRequest = new NotificationsRequest { All = true }; + + client.GetAllForCurrent(notificationsRequest); + + connection.Received().GetAll(endpoint, Arg.Is>(d => d.Count == 2 + && d["all"] == "true" && d["participating"] == "false"), Args.ApiOptions); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequestWithApiOptions() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var client = new NotificationsClient(connection); + + var notificationsRequest = new NotificationsRequest { All = true }; + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForCurrent(notificationsRequest, options); + + connection.Received().GetAll(endpoint, Arg.Is>(d => d.Count == 2 + && d["all"] == "true" && d["participating"] == "false"), options); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new NotificationsClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAllForCurrent((ApiOptions)null)); + await Assert.ThrowsAsync(() => client.GetAllForCurrent((NotificationsRequest)null)); } } @@ -42,7 +109,87 @@ namespace Octokit.Tests.Clients client.GetAllForRepository("banana", "split"); - connection.Received().GetAll(endpoint); + connection.Received().GetAll(endpoint, Args.ApiOptions); + } + + [Fact] + public void RequestsCorrectUrlWithApiOptions() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var client = new NotificationsClient(connection); + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForRepository("banana", "split", options); + + connection.Received().GetAll(endpoint, options); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequest() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var client = new NotificationsClient(connection); + + var notificationsRequest = new NotificationsRequest { All = true }; + + client.GetAllForRepository("banana", "split", notificationsRequest); + + connection.Received().GetAll(endpoint, Arg.Is>( + d => d.Count == 2 && d["all"] == "true" && d["participating"] == "false"), + Args.ApiOptions); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequestWithApiOptions() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var client = new NotificationsClient(connection); + + var notificationsRequest = new NotificationsRequest { All = true }; + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForRepository("banana", "split", notificationsRequest, options); + + connection.Received().GetAll(endpoint, Arg.Is>( + d => d.Count == 2 && d["all"] == "true" && d["participating"] == "false"), + options); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new NotificationsClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAllForRepository(null, "name")); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", null)); + await Assert.ThrowsAsync(() => client.GetAllForRepository(null, "name", ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", null, ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "name", (ApiOptions)null)); + await Assert.ThrowsAsync(() => client.GetAllForRepository(null, "name", new NotificationsRequest())); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", null, new NotificationsRequest())); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "name", (NotificationsRequest)null)); + + await Assert.ThrowsAsync(() => client.GetAllForRepository("", "name")); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "")); + await Assert.ThrowsAsync(() => client.GetAllForRepository("", "name", ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "", ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAllForRepository("", "name", new NotificationsRequest())); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "", new NotificationsRequest())); } } @@ -74,6 +221,37 @@ namespace Octokit.Tests.Clients connection.Received().Put(endpoint); } + + [Fact] + public void RequestsCorrectUrlParameterized() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var client = new NotificationsClient(connection); + + var markAsReadRequest = new MarkAsReadRequest(); + + client.MarkAsReadForRepository("banana", "split", markAsReadRequest); + + connection.Received().Put(endpoint, markAsReadRequest); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new NotificationsClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository(null, "name")); + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository("owner", null)); + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository(null, "name", new MarkAsReadRequest())); + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository("owner", null, new MarkAsReadRequest())); + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository("owner", "name", null)); + + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository("", "name")); + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository("owner", "")); + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository("", "name", new MarkAsReadRequest())); + await Assert.ThrowsAsync(() => client.MarkAsReadForRepository("owner", "", new MarkAsReadRequest())); + } } public class TheGetNotification @@ -135,6 +313,14 @@ namespace Octokit.Tests.Clients connection.Received().Put(endpoint, data); } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new NotificationsClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.SetThreadSubscription(1, null)); + } } public class TheDeleteThreadSubscription diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 5e78e372..34824301 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -208,6 +208,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableNotificationsClientTests.cs b/Octokit.Tests/Reactive/ObservableNotificationsClientTests.cs new file mode 100644 index 00000000..7c83d83a --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableNotificationsClientTests.cs @@ -0,0 +1,360 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using NSubstitute; +using Octokit.Reactive; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableNotificationsClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws( + () => new ObservableNotificationsClient(null)); + } + } + + public class TheGetAllForCurrentMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.GetAllForCurrent(); + + connection.Received().Get>(endpoint, Args.EmptyDictionary, null); + } + + [Fact] + public void RequestsCorrectUrlApiOptions() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForCurrent(options); + + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 2), null); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequest() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + var notificationsRequest = new NotificationsRequest { All = true }; + + client.GetAllForCurrent(notificationsRequest); + + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 2 + && d["all"] == "true" && d["participating"] == "false"), null); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequestWithApiOptions() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + var notificationsRequest = new NotificationsRequest { All = true }; + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForCurrent(notificationsRequest, options); + + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 4 + && d["all"] == "true" && d["participating"] == "false" + && d["page"] == "1" && d["per_page"] == "1"), null); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableNotificationsClient(Substitute.For()); + + Assert.Throws(() => client.GetAllForCurrent((ApiOptions)null)); + Assert.Throws(() => client.GetAllForCurrent((NotificationsRequest)null)); + } + } + + public class TheGetAllForRepository + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.GetAllForRepository("banana", "split"); + + connection.Received().Get>(endpoint, Args.EmptyDictionary, null); + } + + [Fact] + public void RequestsCorrectUrlWithApiOptions() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForRepository("banana", "split", options); + + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 2), null); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequest() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + var notificationsRequest = new NotificationsRequest { All = true }; + + client.GetAllForRepository("banana", "split", notificationsRequest); + + connection.Received().Get>(endpoint, Arg.Is>( + d => d.Count == 2 && d["all"] == "true" && d["participating"] == "false"), + null); + } + + [Fact] + public void RequestsCorrectUrlNotificationRequestWithApiOptions() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + var notificationsRequest = new NotificationsRequest { All = true }; + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAllForRepository("banana", "split", notificationsRequest, options); + + connection.Received().Get>(endpoint, Arg.Is>( + d => d.Count == 4 && d["all"] == "true" && d["participating"] == "false" + && d["page"] == "1" && d["per_page"] == "1"), + null); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableNotificationsClient(Substitute.For()); + + Assert.Throws(() => client.GetAllForRepository(null, "name")); + Assert.Throws(() => client.GetAllForRepository("owner", null)); + Assert.Throws(() => client.GetAllForRepository(null, "name", ApiOptions.None)); + Assert.Throws(() => client.GetAllForRepository("owner", null, ApiOptions.None)); + Assert.Throws(() => client.GetAllForRepository("owner", "name", (ApiOptions)null)); + Assert.Throws(() => client.GetAllForRepository(null, "name", new NotificationsRequest())); + Assert.Throws(() => client.GetAllForRepository("owner", null, new NotificationsRequest())); + Assert.Throws(() => client.GetAllForRepository("owner", "name", (NotificationsRequest)null)); + + Assert.Throws(() => client.GetAllForRepository("", "name")); + Assert.Throws(() => client.GetAllForRepository("owner", "")); + Assert.Throws(() => client.GetAllForRepository("", "name", ApiOptions.None)); + Assert.Throws(() => client.GetAllForRepository("owner", "", ApiOptions.None)); + Assert.Throws(() => client.GetAllForRepository("", "name", new NotificationsRequest())); + Assert.Throws(() => client.GetAllForRepository("owner", "", new NotificationsRequest())); + } + } + + public class TheMarkAsRead + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.MarkAsRead(); + + connection.Received().Put(endpoint); + } + } + + public class TheMarkAsReadForRepository + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.MarkAsReadForRepository("banana", "split"); + + connection.Received().Put(endpoint); + } + + [Fact] + public void RequestsCorrectUrlParameterized() + { + var endpoint = new Uri("repos/banana/split/notifications", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + var markAsReadRequest = new MarkAsReadRequest(); + + client.MarkAsReadForRepository("banana", "split", markAsReadRequest); + + connection.Received().Put(endpoint, markAsReadRequest); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableNotificationsClient(Substitute.For()); + + Assert.Throws(() => client.MarkAsReadForRepository(null, "name")); + Assert.Throws(() => client.MarkAsReadForRepository("owner", null)); + Assert.Throws(() => client.MarkAsReadForRepository(null, "name", new MarkAsReadRequest())); + Assert.Throws(() => client.MarkAsReadForRepository("owner", null, new MarkAsReadRequest())); + Assert.Throws(() => client.MarkAsReadForRepository("owner", "name", null)); + + Assert.Throws(() => client.MarkAsReadForRepository("", "name")); + Assert.Throws(() => client.MarkAsReadForRepository("owner", "")); + Assert.Throws(() => client.MarkAsReadForRepository("", "name", new MarkAsReadRequest())); + Assert.Throws(() => client.MarkAsReadForRepository("owner", "", new MarkAsReadRequest())); + } + } + + public class TheGetNotification + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("notifications/threads/1", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.Get(1); + + connection.Received().Get(endpoint, null, null); + } + } + + public class TheMarkNotificationAsRead + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("notifications/threads/1", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.MarkAsRead(1); + + connection.Received().Patch(endpoint); + } + } + + public class TheGetThreadSubscription + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("notifications/threads/1/subscription", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.GetThreadSubscription(1); + + connection.Received().Get(endpoint, null, null); + } + } + + public class TheSetThreadSubscription + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("notifications/threads/1/subscription", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + var data = new NewThreadSubscription(); + + client.SetThreadSubscription(1, data); + + connection.Received().Put(endpoint, data); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableNotificationsClient(Substitute.For()); + + Assert.Throws(() => client.SetThreadSubscription(1, null)); + } + } + + public class TheDeleteThreadSubscription + { + [Fact] + public void RequestsCorrectUrl() + { + var endpoint = new Uri("notifications/threads/1/subscription", UriKind.Relative); + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableNotificationsClient(gitHubClient); + + client.DeleteThreadSubscription(1); + + connection.Received().Delete(endpoint); + } + } + } +} diff --git a/Octokit/Clients/INotificationsClient.cs b/Octokit/Clients/INotificationsClient.cs index eb92c15a..c40b55a1 100644 --- a/Octokit/Clients/INotificationsClient.cs +++ b/Octokit/Clients/INotificationsClient.cs @@ -23,14 +23,36 @@ namespace Octokit /// /// Retrieves all of the s for the current user. /// + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + Task> GetAllForCurrent(ApiOptions options); + + /// + /// Retrieves all of the s for the current user. + /// + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] Task> GetAllForCurrent(NotificationsRequest request); + /// + /// Retrieves all of the s for the current user. + /// + /// Specifies the parameters to filter notifications by + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + Task> GetAllForCurrent(NotificationsRequest request, ApiOptions options); + /// /// Retrieves all of the s for the current user specific to the specified repository. /// + /// The owner of the repository. + /// The name of the repository. /// Thrown if the client is not authenticated. /// A of . Task> GetAllForRepository(string owner, string name); @@ -38,10 +60,34 @@ namespace Octokit /// /// Retrieves all of the s for the current user specific to the specified repository. /// + /// The owner of the repository. + /// The name of the repository. + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + Task> GetAllForRepository(string owner, string name, ApiOptions options); + + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . Task> GetAllForRepository(string owner, string name, NotificationsRequest request); + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + Task> GetAllForRepository(string owner, string name, NotificationsRequest request, ApiOptions options); + /// /// Marks all notifications as read. /// @@ -71,10 +117,10 @@ namespace Octokit /// /// The owner of the repository /// The name of the repository - /// The parameter which specifies which notifications to mark. + /// The parameter which specifies which notifications to mark. /// http://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository /// - Task MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsRead); + Task MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsReadRequest); /// /// Retrives a single by Id. diff --git a/Octokit/Clients/NotificationsClient.cs b/Octokit/Clients/NotificationsClient.cs index 017e1311..b0c53c1e 100644 --- a/Octokit/Clients/NotificationsClient.cs +++ b/Octokit/Clients/NotificationsClient.cs @@ -26,24 +26,55 @@ namespace Octokit /// A of . public Task> GetAllForCurrent() { - return ApiConnection.GetAll(ApiUrls.Notifications()); + return GetAllForCurrent(ApiOptions.None); } /// /// Retrieves all of the s for the current user. /// + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + public Task> GetAllForCurrent(ApiOptions options) + { + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.Notifications(), options); + } + + /// + /// Retrieves all of the s for the current user. + /// + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . public Task> GetAllForCurrent(NotificationsRequest request) { Ensure.ArgumentNotNull(request, "request"); - return ApiConnection.GetAll(ApiUrls.Notifications(), request.ToParametersDictionary()); + return GetAllForCurrent(request, ApiOptions.None); + } + + /// + /// Retrieves all of the s for the current user. + /// + /// Specifies the parameters to filter notifications by + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + public Task> GetAllForCurrent(NotificationsRequest request, ApiOptions options) + { + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.Notifications(), request.ToParametersDictionary(), options); } /// /// Retrieves all of the s for the current user specific to the specified repository. /// + /// The owner of the repository. + /// The name of the repository. /// Thrown if the client is not authenticated. /// A of . public Task> GetAllForRepository(string owner, string name) @@ -51,12 +82,32 @@ namespace Octokit Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); - return ApiConnection.GetAll(ApiUrls.Notifications(owner, name)); + return GetAllForRepository(owner, name, ApiOptions.None); } /// /// Retrieves all of the s for the current user specific to the specified repository. /// + /// The owner of the repository. + /// The name of the repository. + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + public Task> GetAllForRepository(string owner, string name, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.Notifications(owner, name), options); + } + + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by /// Thrown if the client is not authenticated. /// A of . public Task> GetAllForRepository(string owner, string name, NotificationsRequest request) @@ -65,7 +116,26 @@ namespace Octokit Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(request, "request"); - return ApiConnection.GetAll(ApiUrls.Notifications(owner, name), request.ToParametersDictionary()); + return GetAllForRepository(owner, name, request, ApiOptions.None); + } + + /// + /// Retrieves all of the s for the current user specific to the specified repository. + /// + /// The owner of the repository. + /// The name of the repository. + /// Specifies the parameters to filter notifications by + /// Options for changing the API response + /// Thrown if the client is not authenticated. + /// A of . + public Task> GetAllForRepository(string owner, string name, NotificationsRequest request, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.Notifications(owner, name), request.ToParametersDictionary(), options); } /// @@ -86,6 +156,8 @@ namespace Octokit /// public Task MarkAsRead(MarkAsReadRequest markAsReadRequest) { + Ensure.ArgumentNotNull(markAsReadRequest, "markAsReadRequest"); + return ApiConnection.Put(ApiUrls.Notifications(), markAsReadRequest); } @@ -109,15 +181,16 @@ namespace Octokit /// /// The owner of the repository /// The name of the repository - /// The parameter which specifies which notifications to mark. + /// The parameter which specifies which notifications to mark. /// http://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository /// - public Task MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsRead) + public Task MarkAsReadForRepository(string owner, string name, MarkAsReadRequest markAsReadRequest) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(markAsReadRequest, "markAsRead"); - return ApiConnection.Put(ApiUrls.Notifications(owner, name), markAsRead); + return ApiConnection.Put(ApiUrls.Notifications(owner, name), markAsReadRequest); } ///