using System; using System.Collections.Generic; using System.Net; using System.Text; using System.Threading.Tasks; using NSubstitute; using Octokit; using Octokit.Tests.Helpers; using Xunit; namespace Octokit.Tests.Clients { /// /// Client tests mostly just need to make sure they call the IApiConnection with the correct /// relative Uri. No need to fake up the response. All *those* tests are in ApiConnectionTests.cs. /// public class RepositoriesClientTests { public class TheConstructor { [Fact] public void EnsuresNonNullArguments() { Assert.Throws(() => new RepositoriesClient(null)); } } public class TheCreateMethodForUser { [Fact] public async Task EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); await AssertEx.Throws(async () => await client.Create(null)); await AssertEx.Throws(async () => await client.Create(new NewRepository { Name = null })); } [Fact] public void UsesTheUserReposUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.Create(new NewRepository { Name = "aName" }); connection.Received().Post(Arg.Is(u => u.ToString() == "user/repos"), Arg.Any()); } [Fact] public void TheNewRepositoryDescription() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); var newRepository = new NewRepository { Name = "aName" }; client.Create(newRepository); connection.Received().Post(Args.Uri, newRepository); } [Fact] public async Task ThrowsRepositoryExistsExceptionWhenRepositoryExistsForCurrentUser() { var newRepository = new NewRepository { Name = "aName" }; var response = Substitute.For(); response.StatusCode.Returns((HttpStatusCode)422); response.Body.Returns(@"{""message"":""Validation Failed"",""documentation_url"":" + @"""http://developer.github.com/v3/repos/#create"",""errors"":[{""resource"":""Repository""," + @"""code"":""custom"",""field"":""name"",""message"":""name already exists on this account""}]}"); var credentials = new Credentials("haacked", "pwd"); var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl); connection.Connection.Credentials.Returns(credentials); connection.Post(Args.Uri, newRepository) .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); var exception = await AssertEx.Throws(async () => await client.Create(newRepository)); Assert.False(exception.OwnerIsOrganization); Assert.Equal("haacked", exception.Owner); Assert.Equal("aName", exception.RepositoryName); Assert.Equal(new Uri("https://github.com/haacked/aName"), exception.ExistingRepositoryWebUrl); } } public class TheCreateMethodForOrganization { [Fact] public async Task EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); await AssertEx.Throws(async () => await client.Create(null, new NewRepository { Name = "aName" })); await AssertEx.Throws(async () => await client.Create("aLogin", null)); await AssertEx.Throws(async () => await client.Create("aLogin", new NewRepository { Name = null })); } [Fact] public async Task UsesTheOrganizatinosReposUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); await client.Create("theLogin", new NewRepository { Name = "aName" }); connection.Received().Post( Arg.Is(u => u.ToString() == "orgs/theLogin/repos"), Args.NewRepository); } [Fact] public async Task TheNewRepositoryDescription() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); var newRepository = new NewRepository { Name = "aName" }; await client.Create("aLogin", newRepository); connection.Received().Post(Args.Uri, newRepository); } [Fact] public async Task ThrowsRepositoryExistsExceptionWhenRepositoryExistsForSpecifiedOrg() { var newRepository = new NewRepository { Name = "aName" }; var response = Substitute.For(); response.StatusCode.Returns((HttpStatusCode)422); response.Body.Returns(@"{""message"":""Validation Failed"",""documentation_url"":" + @"""http://developer.github.com/v3/repos/#create"",""errors"":[{""resource"":""Repository""," + @"""code"":""custom"",""field"":""name"",""message"":""name already exists on this account""}]}"); var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl); connection.Post(Args.Uri, newRepository) .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); var exception = await AssertEx.Throws( async () => await client.Create("illuminati", newRepository)); Assert.True(exception.OwnerIsOrganization); Assert.Equal("illuminati", exception.Owner); Assert.Equal("aName", exception.RepositoryName); Assert.Equal(new Uri("https://github.com/illuminati/aName"), exception.ExistingRepositoryWebUrl); Assert.Equal("There is already a repository named 'aName' in the organization 'illuminati'", exception.Message); } [Fact] public async Task ThrowsValidationException() { var newRepository = new NewRepository { Name = "aName" }; var response = Substitute.For(); response.StatusCode.Returns((HttpStatusCode)422); response.Body.Returns(@"{""message"":""Validation Failed"",""documentation_url"":" + @"""http://developer.github.com/v3/repos/#create"",""errors"":[]}"); var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl); connection.Post(Args.Uri, newRepository) .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); var exception = await AssertEx.Throws( async () => await client.Create("illuminati", newRepository)); Assert.Null(exception as RepositoryExistsException); } [Fact] public async Task ThrowsRepositoryExistsExceptionForEnterpriseInstance() { var newRepository = new NewRepository { Name = "aName" }; var response = Substitute.For(); response.StatusCode.Returns((HttpStatusCode)422); response.Body.Returns(@"{""message"":""Validation Failed"",""documentation_url"":" + @"""http://developer.github.com/v3/repos/#create"",""errors"":[{""resource"":""Repository""," + @"""code"":""custom"",""field"":""name"",""message"":""name already exists on this account""}]}"); var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(new Uri("https://example.com")); connection.Post(Args.Uri, newRepository) .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); var exception = await AssertEx.Throws( async () => await client.Create("illuminati", newRepository)); Assert.Equal("aName", exception.RepositoryName); Assert.Equal(new Uri("https://example.com/illuminati/aName"), exception.ExistingRepositoryWebUrl); } } public class TheDeleteMethod { [Fact] public async Task EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); await AssertEx.Throws(async () => await client.Delete(null, "aRepoName")); await AssertEx.Throws(async () => await client.Delete("anOwner", null)); } [Fact] public async Task RequestsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); await client.Delete("theOwner", "theRepoName"); connection.Received().Delete(Arg.Is(u => u.ToString() == "repos/theOwner/theRepoName")); } } public class TheGetMethod { [Fact] public void RequestsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.Get("fake", "repo"); connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo"), null); } [Fact] public async Task EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); await AssertEx.Throws(async () => await client.Get(null, "name")); await AssertEx.Throws(async () => await client.Get("owner", null)); } } public class TheGetAllForCurrentMethod { [Fact] public void RequestsTheCorrectUrlAndReturnsOrganizations() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllForCurrent(); connection.Received() .GetAll(Arg.Is(u => u.ToString() == "user/repos")); } } public class TheGetAllForUserMethod { [Fact] public void RequestsTheCorrectUrlAndReturnsOrganizations() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllForUser("username"); connection.Received() .GetAll(Arg.Is(u => u.ToString() == "users/username/repos")); } [Fact] public void EnsuresNonNullArguments() { var reposEndpoint = new RepositoriesClient(Substitute.For()); Assert.Throws(() => reposEndpoint.GetAllForUser(null)); } } public class TheGetAllForOrgMethod { [Fact] public void RequestsTheCorrectUrlAndReturnsOrganizations() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllForOrg("orgname"); connection.Received() .GetAll(Arg.Is(u => u.ToString() == "orgs/orgname/repos")); } [Fact] public void EnsuresNonNullArguments() { var reposEndpoint = new RepositoriesClient(Substitute.For()); Assert.Throws(() => reposEndpoint.GetAllForOrg(null)); } } public class TheGetReadmeMethod { [Fact] public async Task ReturnsReadme() { string encodedContent = Convert.ToBase64String(Encoding.UTF8.GetBytes("Hello world")); var readmeInfo = new ReadmeResponse { Content = encodedContent, Encoding = "base64", Name = "README.md", Url = "https://github.example.com/readme.md", HtmlUrl = "https://github.example.com/readme" }; var connection = Substitute.For(); connection.Get(Args.Uri, null).Returns(Task.FromResult(readmeInfo)); connection.GetHtml(Args.Uri, null).Returns(Task.FromResult("README")); var reposEndpoint = new RepositoriesClient(connection); var readme = await reposEndpoint.GetReadme("fake", "repo"); Assert.Equal("README.md", readme.Name); connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/readme"), null); connection.DidNotReceive().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme"), null); var htmlReadme = await readme.GetHtmlContent(); Assert.Equal("README", htmlReadme); connection.Received().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme"), null); } } public class TheGetReadmeHtmlMethod { [Fact] public async Task ReturnsReadmeHtml() { var connection = Substitute.For(); connection.GetHtml(Args.Uri, null).Returns(Task.FromResult("README")); var reposEndpoint = new RepositoriesClient(connection); var readme = await reposEndpoint.GetReadmeHtml("fake", "repo"); connection.Received().GetHtml(Arg.Is(u => u.ToString() == "repos/fake/repo/readme"), null); Assert.Equal("README", readme); } } public class TheGetAllBranchesMethod { [Fact] public void ReturnsBranches() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllBranches("owner", "name"); connection.Received() .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/branches")); } [Fact] public void EnsuresArguments() { var client = new RepositoriesClient(Substitute.For()); Assert.Throws(() => client.GetAllBranches(null, "repo")); Assert.Throws(() => client.GetAllBranches("owner", null)); Assert.Throws(() => client.GetAllBranches("", "repo")); Assert.Throws(() => client.GetAllBranches("owner", "")); } } public class TheGetAllContributorsMethod { [Fact] public void GetsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllContributors("owner", "name"); connection.Received() .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/contributors"), Arg.Any>()); } [Fact] public void EnsuresArguments() { var client = new RepositoriesClient(Substitute.For()); Assert.Throws(() => client.GetAllContributors(null, "repo")); Assert.Throws(() => client.GetAllContributors("owner", null)); Assert.Throws(() => client.GetAllContributors("", "repo")); Assert.Throws(() => client.GetAllContributors("owner", "")); } } public class TheGetAllLanguagesMethod { [Fact] public void GetsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllLanguages("owner", "name"); connection.Received() .Get>(Arg.Is(u => u.ToString() == "repos/owner/name/languages"), null); } [Fact] public void EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); Assert.Throws(() => client.GetAllLanguages(null, "repo")); Assert.Throws(() => client.GetAllLanguages("owner", null)); Assert.Throws(() => client.GetAllLanguages("", "repo")); Assert.Throws(() => client.GetAllLanguages("owner", "")); } } public class TheGetAllTeamsMethod { [Fact] public void GetsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllTeams("owner", "name"); connection.Received() .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/teams")); } [Fact] public void EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); Assert.Throws(() => client.GetAllTeams(null, "repo")); Assert.Throws(() => client.GetAllTeams("owner", null)); Assert.Throws(() => client.GetAllTeams("", "repo")); Assert.Throws(() => client.GetAllTeams("owner", "")); } } public class TheGetAllTagsMethod { [Fact] public void GetsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetAllTags("owner", "name"); connection.Received() .GetAll(Arg.Is(u => u.ToString() == "repos/owner/name/tags")); } [Fact] public void EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); Assert.Throws(() => client.GetAllTags(null, "repo")); Assert.Throws(() => client.GetAllTags("owner", null)); Assert.Throws(() => client.GetAllTags("", "repo")); Assert.Throws(() => client.GetAllTags("owner", "")); } } public class TheGetBranchMethod { [Fact] public void GetsCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); client.GetBranch("owner", "repo", "branch"); connection.Received() .Get(Arg.Is(u => u.ToString() == "repos/owner/repo/branches/branch"), null); } [Fact] public void EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); Assert.Throws(() => client.GetBranch(null, "repo", "branch")); Assert.Throws(() => client.GetBranch("owner", null, "branch")); Assert.Throws(() => client.GetBranch("owner", "repo", null)); Assert.Throws(() => client.GetBranch("", "repo", "branch")); Assert.Throws(() => client.GetBranch("owner", "", "branch")); Assert.Throws(() => client.GetBranch("owner", "repo", "")); } } public class TheEditMethod { [Fact] public void PatchesCorrectUrl() { var connection = Substitute.For(); var client = new RepositoriesClient(connection); var update = new RepositoryUpdate(); client.Edit("owner", "repo", update); connection.Received() .Patch(Arg.Is(u => u.ToString() == "repos/owner/repo"), Arg.Any()); } [Fact] public void EnsuresNonNullArguments() { var client = new RepositoriesClient(Substitute.For()); var update = new RepositoryUpdate(); Assert.Throws(() => client.Edit(null, "repo", update)); Assert.Throws(() => client.Edit("owner", null, update)); Assert.Throws(() => client.Edit("owner", "repo", null)); Assert.Throws(() => client.Edit("", "repo", update)); Assert.Throws(() => client.Edit("owner", "", update)); } } } }