From a22006950a370972eee381f4ea7df0084253e2c7 Mon Sep 17 00:00:00 2001 From: Peter MacNaughton Date: Tue, 21 Jan 2014 10:26:09 -0700 Subject: [PATCH] Implemented ObservableDeploymentsClient and... unit tests. --- .../Clients/IObservableDeploymentsClient.cs | 32 ++++ .../Clients/ObservableDeploymentsClient.cs | 55 +++++++ Octokit.Reactive/Octokit.Reactive-Mono.csproj | 2 + .../Octokit.Reactive-MonoAndroid.csproj | 2 + .../Octokit.Reactive-Monotouch.csproj | 2 + Octokit.Reactive/Octokit.Reactive.csproj | 2 + Octokit.Tests/Helpers/AssertEx.cs | 10 ++ Octokit.Tests/Octokit.Tests.csproj | 1 + .../ObservableDeploymentsClientTests.cs | 140 ++++++++++++++++++ 9 files changed, 246 insertions(+) create mode 100644 Octokit.Reactive/Clients/IObservableDeploymentsClient.cs create mode 100644 Octokit.Reactive/Clients/ObservableDeploymentsClient.cs create mode 100644 Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs diff --git a/Octokit.Reactive/Clients/IObservableDeploymentsClient.cs b/Octokit.Reactive/Clients/IObservableDeploymentsClient.cs new file mode 100644 index 00000000..f103a05d --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableDeploymentsClient.cs @@ -0,0 +1,32 @@ +using System; + +namespace Octokit.Reactive.Clients +{ + public interface IObservableDeploymentsClient + { + /// + /// Gets all the deployments for the specified repository. Any user with pull access + /// to a repository can view deployments. + /// + /// + /// http://developer.github.com/v3/repos/deployments/#list-deployments + /// + /// The owner of the repository + /// The name of the repository + /// All the s for the specified repository. + IObservable GetAll(string owner, string name); + + /// + /// Creates a new deployment for the specified repository. + /// Users with push access can create a deployment for a given ref. + /// + /// + /// http://developer.github.com/v3/repos/deployments/#create-a-deployment + /// + /// The owner of the repository + /// The name of the repository + /// A instance describing the new deployment to create + /// The created + IObservable Create(string owner, string name, NewDeployment newDeployment); + } +} \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableDeploymentsClient.cs b/Octokit.Reactive/Clients/ObservableDeploymentsClient.cs new file mode 100644 index 00000000..12ba812f --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableDeploymentsClient.cs @@ -0,0 +1,55 @@ +using Octokit.Reactive.Internal; +using System; +using System.Reactive.Threading.Tasks; + +namespace Octokit.Reactive.Clients +{ + public class ObservableDeploymentsClient : IObservableDeploymentsClient + { + readonly IDeploymentsClient _client; + readonly IConnection _connection; + + public ObservableDeploymentsClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Deployment; + _connection = client.Connection; + } + + /// + /// Gets all the deployments for the specified repository. Any user with pull access + /// to a repository can view deployments. + /// + /// + /// http://developer.github.com/v3/repos/deployments/#list-deployments + /// + /// The owner of the repository + /// The name of the repository + /// All the s for the specified repository. + public IObservable GetAll(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _connection.GetAndFlattenAllPages(ApiUrls.Deployments(owner, name), null, + "application/vnd.github.cannonball-preview+json"); + } + + /// + /// Creates a new deployment for the specified repository. + /// Users with push access can create a deployment for a given ref. + /// + /// + /// http://developer.github.com/v3/repos/deployments/#create-a-deployment + /// + /// The owner of the repository + /// The name of the repository + /// A instance describing the new deployment to create + /// The created + public IObservable Create(string owner, string name, NewDeployment newDeployment) + { + return _client.Create(owner, name, newDeployment).ToObservable(); + } + } +} \ No newline at end of file diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index 5e79557a..93e07216 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -118,6 +118,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index 670df6dc..0f1bff01 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -127,6 +127,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index 4cdfd18c..4186eb1e 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -122,6 +122,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 3c9f97fd..34d4e8ea 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -73,6 +73,8 @@ Properties\SolutionInfo.cs + + diff --git a/Octokit.Tests/Helpers/AssertEx.cs b/Octokit.Tests/Helpers/AssertEx.cs index cbb8d888..2275b3d7 100644 --- a/Octokit.Tests/Helpers/AssertEx.cs +++ b/Octokit.Tests/Helpers/AssertEx.cs @@ -21,5 +21,15 @@ namespace Octokit.Tests.Helpers // Assert.Throws above will always throw. return null; } + + static readonly string[] whitespaceArguments = { " ", "\t", "\n", "\n\r", " " }; + + public static async void ThrowsWhenGivenWhitespaceArgument(Func action) + { + foreach (var argument in whitespaceArguments) + { + await Throws(async () => await action(argument)); + } + } } } diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 9b1db587..413468bd 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -131,6 +131,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs b/Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs new file mode 100644 index 00000000..9e095ab5 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs @@ -0,0 +1,140 @@ +using NSubstitute; +using Octokit.Reactive.Clients; +using Octokit.Tests.Helpers; +using System; +using System.Collections.Generic; +using System.Reactive.Linq; +using System.Threading.Tasks; +using Xunit; +using System.Linq; + +namespace Octokit.Tests.Reactive +{ + public class ObservableDeploymentsClientTests + { + const string ExpectedAcceptHeader = "application/vnd.github.cannonball-preview+json"; + + public class TheGetAllMethod + { + readonly IGitHubClient _githubClient; + readonly ObservableDeploymentsClient _client; + + public TheGetAllMethod() + { + _githubClient = Substitute.For(); + _client = new ObservableDeploymentsClient(_githubClient); + } + + [Fact] + public void EnsuresNonNullArguments() + { + AssertEx.Throws( + async () => await _client.GetAll(null, "repo")); + AssertEx.Throws( + async () => await _client.GetAll("owner", null)); + } + + [Fact] + public void EnsuresNonEmptyArguments() + { + AssertEx.Throws( + async () => await _client.GetAll("", "repo")); + AssertEx.Throws( + async () => await _client.GetAll("owner", "")); + } + + [Fact] + public void EnsuresNonWhitespaceArguments() + { + AssertEx.ThrowsWhenGivenWhitespaceArgument( + async whitespace => await _client.GetAll(whitespace, "repo")); + AssertEx.ThrowsWhenGivenWhitespaceArgument( + async whitespace => await _client.GetAll("owner", whitespace)); + } + + [Fact] + public void CallsDeploymentsUrl() + { + var expectedUri = ApiUrls.Deployments("owner", "repo"); + + _client.GetAll("owner", "repo"); + _githubClient.Connection + .Received(1) + .GetAsync>(Arg.Is(expectedUri), + Arg.Any>(), + Arg.Any()); + } + + [Fact] + public void UsesPreviewAcceptHeader() + { + _client.GetAll("owner", "repo"); + _githubClient.Connection + .Received(1) + .GetAsync>(Arg.Any(), + Arg.Any>(), + ExpectedAcceptHeader); + } + } + + public class TheCreateMethod + { + IGitHubClient _githubClient; + ObservableDeploymentsClient _client; + + public TheCreateMethod() + { + _githubClient = Substitute.For(); + _client = new ObservableDeploymentsClient(_githubClient); + } + + [Fact] + public void EnsuresNonNullArguments() + { + AssertEx.Throws( + async () => await _client.Create(null, "repo", new NewDeployment())); + AssertEx.Throws( + async () => await _client.Create("owner", null, new NewDeployment())); + AssertEx.Throws( + async () => await _client.Create("owner", "repo", null)); + } + + [Fact] + public void EnsuresNonEmptyArguments() + { + AssertEx.Throws( + async () => await _client.Create("", "repo", new NewDeployment())); + AssertEx.Throws( + async () => await _client.Create("owner", "", new NewDeployment())); + } + + [Fact] + public void EnsuresNonWhitespaceArguments() + { + AssertEx.ThrowsWhenGivenWhitespaceArgument( + async whitespace => await _client.Create(whitespace, "repo", new NewDeployment())); + AssertEx.ThrowsWhenGivenWhitespaceArgument( + async whitespace => await _client.Create("owner", whitespace, new NewDeployment())); + } + + [Fact] + public void CallsCreateOnRegularDeploymentsClient() + { + var newDeployment = new NewDeployment(); + _client.Create("owner", "repo", newDeployment); + _githubClient.Deployment.Received(1).Create(Arg.Is("owner"), + Arg.Is("repo"), + Arg.Is(newDeployment)); + } + } + + public class TheCtor + { + public void EnsuresArguments() + { + Assert.Throws( + () => new ObservableDeploymentsClient(null)); + } + } + } +} \ No newline at end of file