diff --git a/Burr.Tests.Integration/Burr.Tests.Integration.csproj b/Burr.Tests.Integration/Burr.Tests.Integration.csproj index bb2a679e..8927112d 100644 --- a/Burr.Tests.Integration/Burr.Tests.Integration.csproj +++ b/Burr.Tests.Integration/Burr.Tests.Integration.csproj @@ -47,6 +47,7 @@ + diff --git a/Burr.Tests.Integration/Readme.cs b/Burr.Tests.Integration/Readme.cs index 191211db..7587c690 100644 --- a/Burr.Tests.Integration/Readme.cs +++ b/Burr.Tests.Integration/Readme.cs @@ -21,13 +21,13 @@ namespace Burr.Tests var github = new GitHubClient { Login = "xapitestaccountx", Password = "octocat11" }; // Get the authenticated user - var user = await github.Users.GetAsync(); + var user = await github.User.Current(); // Get a user by username - user = await github.Users.GetAsync("tclem"); + user = await github.User.Get("tclem"); // Update a user - user = await github.Users.UpdateAsync(new UserUpdate { Name = "octolish" }); + user = await github.User.Update(new UserUpdate { Name = "octolish" }); } public async Task AuthorizationsApi() @@ -35,19 +35,19 @@ namespace Burr.Tests var github = new GitHubClient { Login = "xapitestaccountx", Password = "octocat11" }; // create a new auth - var auth = await github.Authorizations.CreateAsync(new AuthorizationUpdate { Note = "integration test", NoteUrl = "http://example.com", Scopes = new[] { "public_repo" } }); + var auth = await github.Authorization.CreateAsync(new AuthorizationUpdate { Note = "integration test", NoteUrl = "http://example.com", Scopes = new[] { "public_repo" } }); // list all authorizations for the authenticated user - var auths = await github.Authorizations.GetAllAsync(); + var auths = await github.Authorization.GetAllAsync(); // get a specific auth - auth = await github.Authorizations.GetAsync(auth.Id); + auth = await github.Authorization.GetAsync(auth.Id); // update an auth - auth = await github.Authorizations.UpdateAsync(auth.Id, new AuthorizationUpdate { Note = "integration test update" }); + auth = await github.Authorization.UpdateAsync(auth.Id, new AuthorizationUpdate { Note = "integration test update" }); // delete a specific auth - await github.Authorizations.DeleteAsync(auth.Id); + await github.Authorization.DeleteAsync(auth.Id); } public async Task ReposApi() @@ -55,7 +55,7 @@ namespace Burr.Tests var github = new GitHubClient { Token = "945c6aa4194a6916c9eb1d845d2ff9f357dfe43e" }; // list all repos for the authenticated user - var repos = await github.Repositories.GetAllAsync(); + var repos = await github.Repository.GetAllAsync(); // list repos for a user //github.Repositories.GetAllAsync(new RepositoryQuery { Login = "tclem" }); diff --git a/Burr.Tests.Integration/UsersEndpointTests.cs b/Burr.Tests.Integration/UsersEndpointTests.cs new file mode 100644 index 00000000..98a4f617 --- /dev/null +++ b/Burr.Tests.Integration/UsersEndpointTests.cs @@ -0,0 +1,52 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Burr.Tests.Integration +{ + public class UsersEndpointTests + { + public class TheGetUserAsyncMethod + { + [Fact] + public async Task ReturnsSpecifiedUser() + { + var github = new GitHubClient { Login = "xapitestaccountx", Password = "octocat11" }; + + // Get a user by username + var user = await github.User.Get("tclem"); + + + Assert.Equal("GitHub", user.Company); + } + } + + public class TheGetAuthenticatedUserAsyncMethod + { + [Fact] + public async Task ReturnsSpecifiedUser() + { + var github = new GitHubClient { Login = "xapitestaccountx", Password = "octocat11" }; + + // Get a user by username + var user = await github.User.Current(); + + Assert.Equal("xapitestaccountx", user.Login); + } + } + + public class TheGetUsersAsyncMethod + { + [Fact] + public async Task ReturnsAllUsers() + { + var github = new GitHubClient(); + + // Get a user by username + var users = await github.User.GetAll(); + + Console.WriteLine(users); + } + } + } +} diff --git a/Burr.Tests/AuthorizationsEndpointTests.cs b/Burr.Tests/AuthorizationsEndpointTests.cs index f4ab04cb..4b2b2dc5 100644 --- a/Burr.Tests/AuthorizationsEndpointTests.cs +++ b/Burr.Tests/AuthorizationsEndpointTests.cs @@ -76,7 +76,7 @@ namespace Burr.Tests Connection = c.Object }; - var auths = await client.Authorizations.GetAllAsync(); + var auths = await client.Authorization.GetAllAsync(); auths.Should().NotBeNull(); auths.Count().Should().Be(1); @@ -123,7 +123,7 @@ namespace Burr.Tests Connection = c.Object }; - var auth = await client.Authorizations.GetAsync(1); + var auth = await client.Authorization.GetAsync(1); auth.Should().NotBeNull(); c.Verify(x => x.GetAsync(endpoint)); @@ -169,7 +169,7 @@ namespace Burr.Tests Connection = c.Object }; - var auth = await client.Authorizations.UpdateAsync(1, new AuthorizationUpdate()); + var auth = await client.Authorization.UpdateAsync(1, new AuthorizationUpdate()); auth.Should().NotBeNull(); c.Verify(x => x.PatchAsync(endpoint, It.IsAny())); @@ -215,7 +215,7 @@ namespace Burr.Tests Connection = c.Object }; - var auth = await client.Authorizations.CreateAsync(new AuthorizationUpdate()); + var auth = await client.Authorization.CreateAsync(new AuthorizationUpdate()); auth.Should().NotBeNull(); c.Verify(x => x.PostAsync(endpoint, It.IsAny())); @@ -261,7 +261,7 @@ namespace Burr.Tests Connection = c.Object }; - await client.Authorizations.DeleteAsync(1); + await client.Authorization.DeleteAsync(1); c.Verify(x => x.DeleteAsync(endpoint)); } diff --git a/Burr.Tests/RepositoriesEndpointTests.cs b/Burr.Tests/RepositoriesEndpointTests.cs index d3ab3fe1..3fcac9e5 100644 --- a/Burr.Tests/RepositoriesEndpointTests.cs +++ b/Burr.Tests/RepositoriesEndpointTests.cs @@ -41,7 +41,7 @@ namespace Burr.Tests Connection = c.Object }; - var repos = await client.Repositories.GetAllAsync(); + var repos = await client.Repository.GetAllAsync(); repos.Should().NotBeNull(); repos.Items.Count.Should().Be(1); diff --git a/Burr.Tests/UsersEndpointTests.cs b/Burr.Tests/UsersEndpointTests.cs index e9a45721..b5c4af9d 100644 --- a/Burr.Tests/UsersEndpointTests.cs +++ b/Burr.Tests/UsersEndpointTests.cs @@ -41,7 +41,7 @@ namespace Burr.Tests Connection = c.Object }; - var user = await client.Users.GetAsync(); + var user = await client.User.Current(); user.Should().NotBeNull(); c.Verify(x => x.GetAsync(endpoint)); @@ -59,7 +59,7 @@ namespace Burr.Tests Connection = c.Object }; - var user = await client.Users.GetAsync(); + var user = await client.User.Current(); user.Should().NotBeNull(); c.Verify(x => x.GetAsync(endpoint)); @@ -70,7 +70,7 @@ namespace Burr.Tests { try { - var user = await (new GitHubClient { Token = "axy" }).Users.UpdateAsync(null); + var user = await (new GitHubClient { Token = "axy" }).User.Update(null); Assert.True(false, "ArgumentNullException was not thrown"); } @@ -84,7 +84,7 @@ namespace Burr.Tests { try { - var user = await new GitHubClient().Users.GetAsync(); + var user = await new GitHubClient().User.Current(); Assert.True(false, "AuthenticationException was not thrown"); } @@ -109,7 +109,7 @@ namespace Burr.Tests Connection = c.Object }; - var user = await client.Users.UpdateAsync(new UserUpdate { Name = "Tim" }); + var user = await client.User.Update(new UserUpdate { Name = "Tim" }); user.Should().NotBeNull(); c.Verify(x => x.PatchAsync(endpoint, It.IsAny())); @@ -127,7 +127,7 @@ namespace Burr.Tests Connection = c.Object }; - var user = await client.Users.UpdateAsync(new UserUpdate { Name = "Tim" }); + var user = await client.User.Update(new UserUpdate { Name = "Tim" }); user.Should().NotBeNull(); c.Verify(x => x.PatchAsync(endpoint, It.IsAny())); @@ -138,7 +138,7 @@ namespace Burr.Tests { try { - var user = await new GitHubClient().Users.UpdateAsync(new UserUpdate()); + var user = await new GitHubClient().User.Update(new UserUpdate()); Assert.True(false, "AuthenticationException was not thrown"); } diff --git a/Burr.sln.DotSettings b/Burr.sln.DotSettings new file mode 100644 index 00000000..9e85119b --- /dev/null +++ b/Burr.sln.DotSettings @@ -0,0 +1,261 @@ + + True + DO_NOT_SHOW + <?xml version="1.0" encoding="utf-16"?><Profile name="CodeReformat"><JsReformatCode>True</JsReformatCode><CSReformatCode>True</CSReformatCode><CSUseVar><BehavourStyle>DISABLED</BehavourStyle><LocalVariableStyle>IMPLICIT_WHEN_INITIALIZER_HAS_TYPE</LocalVariableStyle><ForeachVariableStyle>IMPLICIT_EXCEPT_SIMPLE_TYPES</ForeachVariableStyle></CSUseVar><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseAutoProperty>True</CSUseAutoProperty><HtmlReformatCode>True</HtmlReformatCode><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><CssReformatCode>True</CssReformatCode><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings></Profile> + CodeReformat + False + False + False + False + False + False + False + False + False + False + False + NEXT_LINE + NEXT_LINE + 1 + False + False + False + NEXT_LINE + 1 + 1 + True + False + False + False + True + True + False + False + <?xml version="1.0" encoding="utf-8"?> + +<!-- +II. Available match operands + +Each operand may have Weight="..." attribute. This weight will be added to the match weight if the operand is evaluated to 'true'. +The default weight is 1 + +II.1 Boolean functions: +II.1.1 <And>....</And> +II.1.2 <Or>....</Or> +II.1.3 <Not>....</Not> + +II.2 Operands +II.2.1 <Kind Is="..."/>. Kinds are: class, struct, interface, enum, delegate, type, constructor, destructor, property, indexer, method, operator, field, constant, event, member +II.2.2 <Name Is="..." [IgnoreCase="true/false"] />. The 'Is' attribute contains regular expression +II.2.3 <HasAttribute CLRName="..." [Inherit="true/false"] />. The 'CLRName' attribute contains regular expression +II.2.4 <Access Is="..."/>. The 'Is' values are: public, protected, internal, protected internal, private +II.2.5 <Static/> +II.2.6 <Abstract/> +II.2.7 <Virtual/> +II.2.8 <Override/> +II.2.9 <Sealed/> +II.2.10 <Readonly/> +II.2.11 <ImplementsInterface CLRName="..."/>. The 'CLRName' attribute contains regular expression +II.2.12 <HandlesEvent /> +--> + +<Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns"> + + <!--Do not reorder COM interfaces and structs marked by StructLayout attribute--> + <Pattern> + <Match> + <Or Weight="100"> + <And> + <Kind Is="interface"/> + <Or> + <HasAttribute CLRName="System.Runtime.InteropServices.InterfaceTypeAttribute"/> + <HasAttribute CLRName="System.Runtime.InteropServices.ComImport"/> + </Or> + </And> + <HasAttribute CLRName="System.Runtime.InteropServices.StructLayoutAttribute"/> + </Or> + </Match> + </Pattern> + + <!--Special formatting of NUnit test fixture--> + <Pattern RemoveAllRegions="true"> + <Match> + <And Weight="100"> + <Kind Is="class"/> + <HasAttribute CLRName="NUnit.Framework.TestFixtureAttribute" Inherit="true"/> + </And> + </Match> + + <!--Setup/Teardown--> + <Entry> + <Match> + <And> + <Kind Is="method"/> + <Or> + <HasAttribute CLRName="NUnit.Framework.SetUpAttribute" Inherit="true"/> + <HasAttribute CLRName="NUnit.Framework.TearDownAttribute" Inherit="true"/> + <HasAttribute CLRName="NUnit.Framework.TestFixtureSetUpAttribute" Inherit="true"/> + <HasAttribute CLRName="NUnit.Framework.TestFixtureTearDownAttribute" Inherit="true"/> + </Or> + </And> + </Match> + <Group Region="Setup/Teardown"/> + </Entry> + + <!--Test methods--> + <Entry> + <Match> + <And Weight="100"> + <Kind Is="method"/> + <HasAttribute CLRName="NUnit.Framework.TestAttribute" Inherit="false"/> + </And> + </Match> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--All other members--> + <Entry> + <Group Region="Supporting Code"/> + </Entry> + + </Pattern> + + <!--Default pattern--> + <Pattern> + + <!--public delegate--> + <Entry> + <Match> + <And Weight="100"> + <Access Is="public"/> + <Kind Is="delegate"/> + </And> + </Match> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--public enum--> + <Entry> + <Match> + <And Weight="100"> + <Access Is="public"/> + <Kind Is="enum"/> + </And> + </Match> + <Sort> + <Name/> + </Sort> + <Group> + <Name/> + </Group> + </Entry> + + <!--static fields and constants--> + <Entry> + <Match> + <Or> + <Kind Is="constant"/> + <And> + <Kind Is="field"/> + <Static/> + </And> + </Or> + </Match> + <Sort> + <Kind Order="constant field"/> + </Sort> + </Entry> + + <!--instance fields--> + <Entry> + <Match> + <And> + <Kind Is="field"/> + <Not> + <Static/> + </Not> + </And> + </Match> + <Sort> + <Readonly/> + <Name/> + </Sort> + </Entry> + + <!--Constructors. Place static one first--> + <Entry> + <Match> + <Kind Is="constructor"/> + </Match> + <Sort> + <Static/> + </Sort> + </Entry> + + <!--properties, indexers--> + <Entry> + <Match> + <Or> + <Kind Is="property"/> + <Kind Is="indexer"/> + </Or> + </Match> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--interface implementations--> + <Entry> + <Match> + <And Weight="100"> + <Kind Is="member"/> + <ImplementsInterface/> + </And> + </Match> + <Sort> + <ImplementsInterface Immediate="true"/> + </Sort> + </Entry> + + <!--public methods--> + <Entry> + <Match> + <And> + <Kind Is="method"/> + <Access Is="public"/> + </And> + </Match> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--all other members--> + <Entry> + <Sort> + <Name/> + </Sort> + </Entry> + + <!--nested types--> + <Entry> + <Match> + <Kind Is="type"/> + </Match> + <Sort> + <Name/> + </Sort> + <Group> + <Name/> + </Group> + </Entry> + </Pattern> + +</Patterns> + + \ No newline at end of file diff --git a/Burr/GitHubClient.cs b/Burr/GitHubClient.cs index afb035de..5d4e598c 100644 --- a/Burr/GitHubClient.cs +++ b/Burr/GitHubClient.cs @@ -140,7 +140,7 @@ namespace Burr /// Supports the ability to get and update users. /// http://developer.github.com/v3/users/ /// - public IUsersEndpoint Users + public IUsersEndpoint User { get { return users ?? (users = new UsersEndpoint(this)); } } @@ -151,14 +151,14 @@ namespace Burr /// Supports the ability to list, get, update and create oauth application authorizations. /// http://developer.github.com/v3/oauth/#oauth-authorizations-api /// - public IAuthorizationsEndpoint Authorizations + public IAuthorizationsEndpoint Authorization { get { return authorizations ?? (authorizations = new AuthorizationsEndpoint(this)); } } IRepositoriesEndpoint repositories; - public IRepositoriesEndpoint Repositories + public IRepositoriesEndpoint Repository { get { return repositories ?? (repositories = new RepositoriesEndpoint(this)); } } diff --git a/Burr/Http/IConnection.cs b/Burr/Http/IConnection.cs index df80f85f..5307991b 100644 --- a/Burr/Http/IConnection.cs +++ b/Burr/Http/IConnection.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Burr.Http @@ -9,7 +10,7 @@ namespace Burr.Http Task> GetAsync(string endpoint); Task> PatchAsync(string endpoint, object body); Task> PostAsync(string endpoint, object body); - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] Task DeleteAsync(string endpoint); } } diff --git a/Burr/IUsersEndpoint.cs b/Burr/IUsersEndpoint.cs index 47cadb14..d3b6bdc5 100644 --- a/Burr/IUsersEndpoint.cs +++ b/Burr/IUsersEndpoint.cs @@ -1,10 +1,35 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; namespace Burr { public interface IUsersEndpoint { - Task GetAsync(string login = null); - Task UpdateAsync(UserUpdate user); + /// + /// Returns the user specified by the login. + /// + /// The login name for the user + Task Get(string login); + + /// + /// Returns a for the current authenticated user. + /// + /// Thrown if the client is not authenticated. + /// A + Task Current(); + + /// + /// Update the specified . + /// + /// + /// Thrown if the client is not authenticated. + /// A + Task Update(UserUpdate user); + + /// + /// Returns a list of public s on GitHub.com. + /// + /// A + Task> GetAll(); } } diff --git a/Burr/UsersEndpoint.cs b/Burr/UsersEndpoint.cs index 251dca31..64d047f4 100644 --- a/Burr/UsersEndpoint.cs +++ b/Burr/UsersEndpoint.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Burr.Helpers; namespace Burr @@ -9,7 +10,7 @@ namespace Burr /// public class UsersEndpoint : IUsersEndpoint { - IGitHubClient client; + readonly IGitHubClient client; public UsersEndpoint(IGitHubClient client) { @@ -24,16 +25,28 @@ namespace Burr /// /// Optional GitHub login (username) /// A - public async Task GetAsync(string login = null) + public async Task Get(string login) { - if (login.IsBlank() && client.AuthenticationType == AuthenticationType.Anonymous) + Ensure.ArgumentNotNull(login, "login"); + + var res = await client.Connection.GetAsync(string.Format("/users/{0}", login)); + + return res.BodyAsObject; + } + + /// + /// Returns a for the current authenticated user. + /// + /// Thrown if the client is not authenticated. + /// A + public async Task Current() + { + if (client.AuthenticationType == AuthenticationType.Anonymous) { throw new AuthenticationException("You must be authenticated to call this method. Either supply a login/password or an oauth token."); } - var endpoint = login.IsBlank() ? "/user" : string.Format("/users/{0}", login); - var res = await client.Connection.GetAsync(endpoint); - + var res = await client.Connection.GetAsync("/user"); return res.BodyAsObject; } @@ -41,8 +54,9 @@ namespace Burr /// Update the specified . /// /// + /// Thrown if the client is not authenticated. /// A - public async Task UpdateAsync(UserUpdate user) + public async Task Update(UserUpdate user) { Ensure.ArgumentNotNull(user, "user"); @@ -55,5 +69,16 @@ namespace Burr return res.BodyAsObject; } + + /// + /// Returns a list of public s on GitHub.com. + /// + /// A + public async Task> GetAll() + { + var res = await client.Connection.GetAsync>(string.Format("/users")); + + return res.BodyAsObject; + } } }