From fb9d400cfbc272a2943776669fae2419a71a90ea Mon Sep 17 00:00:00 2001 From: Will Froese Date: Sat, 22 Feb 2014 22:56:22 -0500 Subject: [PATCH 01/46] Add interface and required entities for Commit Comments. --- Octokit/Clients/IRepositoryCommentsClient.cs | 78 ++++++++++++++++++++ Octokit/Models/Request/NewCommitComment.cs | 43 +++++++++++ Octokit/Models/Response/CommitComment.cs | 77 +++++++++++++++++++ Octokit/Octokit.csproj | 3 + 4 files changed, 201 insertions(+) create mode 100644 Octokit/Clients/IRepositoryCommentsClient.cs create mode 100644 Octokit/Models/Request/NewCommitComment.cs create mode 100644 Octokit/Models/Response/CommitComment.cs diff --git a/Octokit/Clients/IRepositoryCommentsClient.cs b/Octokit/Clients/IRepositoryCommentsClient.cs new file mode 100644 index 00000000..ff4257c9 --- /dev/null +++ b/Octokit/Clients/IRepositoryCommentsClient.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + public interface IRepositoryCommentsClient + { + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", + Justification = "Method makes a network request")] + Task Get(string owner, string name, int number); + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + Task> GetForRepository(string owner, string name); + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The commit id + /// + Task> GetForCommit(string owner, string name, int number); + + /// + /// Creates a new Commit Comment for a specified Issue. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + Task Create(string owner, string name, string reference, NewCommitComment newCommitComment); + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + Task Update(string owner, string name, int number, string commentUpdate); + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + Task Delete(string owner, string name, int number); + } +} diff --git a/Octokit/Models/Request/NewCommitComment.cs b/Octokit/Models/Request/NewCommitComment.cs new file mode 100644 index 00000000..3c312704 --- /dev/null +++ b/Octokit/Models/Request/NewCommitComment.cs @@ -0,0 +1,43 @@ +using System; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Describes a new commit comment to create via the method. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class NewCommitComment + { + public NewCommitComment(string body) + { + Ensure.ArgumentNotNull(body, "body"); + + Body = body; + } + + /// + /// The contents of the comment (required) + /// + public string Body { get; private set; } + + /// + /// Relative path of the file to comment on + /// + public string Path { get; set; } + + /// + /// Line index in the diff to comment on + /// + public int? Position { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Path: {0}, Body: {1}", Path, Body); + } + } + } +} diff --git a/Octokit/Models/Response/CommitComment.cs b/Octokit/Models/Response/CommitComment.cs new file mode 100644 index 00000000..b961f2a4 --- /dev/null +++ b/Octokit/Models/Response/CommitComment.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class CommitComment + { + /// + /// The issue comment Id. + /// + public int Id { get; set; } + + /// + /// The URL for this repository comment. + /// + public Uri Url { get; set; } + + /// + /// The html URL for this repository comment. + /// + public Uri HtmlUrl { get; set; } + + /// + /// Details about the repository comment. + /// + public string Body { get; set; } + + /// + /// Relative path of the file that was commented on. + /// + public string Path { get; set; } + + /// + /// Line index in the diff that was commented on. + /// + public int Position { get; set; } + + /// + /// The line number in the file that was commented on. + /// + public int Line { get; set; } + + /// + /// The commit + /// + public string CommitId { get; set; } + + /// + /// The user that created the repository comment. + /// + public User User { get; set; } + + /// + /// The date the repository comment was created. + /// + public DateTimeOffset CreatedAt { get; set; } + + /// + /// The date the repository comment was last updated. + /// + public DateTimeOffset? UpdatedAt { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "Id: {0}, Commit Id: {1}, CreatedAt: {2}", Id, CommitId, CreatedAt); + } + } + } +} diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 5d0559fc..8a29a0e0 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -54,11 +54,14 @@ Properties\SolutionInfo.cs + + + From 50f65370c4f9c6040e451a5d16b391d7fb5c307c Mon Sep 17 00:00:00 2001 From: Will Froese Date: Thu, 27 Feb 2014 20:29:27 -0500 Subject: [PATCH 02/46] Implement RepositoryCommentsClient --- Octokit/Clients/IRepositoryCommentsClient.cs | 8 +- Octokit/Clients/RepositoryCommentsClient.cs | 125 +++++++++++++++++++ Octokit/Helpers/ApiUrls.cs | 35 ++++++ Octokit/Octokit.csproj | 1 + 4 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 Octokit/Clients/RepositoryCommentsClient.cs diff --git a/Octokit/Clients/IRepositoryCommentsClient.cs b/Octokit/Clients/IRepositoryCommentsClient.cs index ff4257c9..2ffa9649 100644 --- a/Octokit/Clients/IRepositoryCommentsClient.cs +++ b/Octokit/Clients/IRepositoryCommentsClient.cs @@ -39,9 +39,9 @@ namespace Octokit /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit /// The owner of the repository /// The name of the repository - /// The commit id + /// The sha of the commit /// - Task> GetForCommit(string owner, string name, int number); + Task> GetForCommit(string owner, string name, string sha); /// /// Creates a new Commit Comment for a specified Issue. @@ -49,10 +49,10 @@ namespace Octokit /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment /// The owner of the repository /// The name of the repository - /// The sha reference of commit + /// The sha reference of commit /// The new comment to add to the commit /// - Task Create(string owner, string name, string reference, NewCommitComment newCommitComment); + Task Create(string owner, string name, string sha, NewCommitComment newCommitComment); /// /// Updates a specified Commit Comment. diff --git a/Octokit/Clients/RepositoryCommentsClient.cs b/Octokit/Clients/RepositoryCommentsClient.cs new file mode 100644 index 00000000..b5138b0b --- /dev/null +++ b/Octokit/Clients/RepositoryCommentsClient.cs @@ -0,0 +1,125 @@ + +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + public class RepositoryCommentsClient : ApiClient, IRepositoryCommentsClient + { + /// + /// Instantiates a new GitHub Repository Comments API client. + /// + /// An API connection + public RepositoryCommentsClient(IApiConnection apiConnection) + : base(apiConnection) + { + } + + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public Task Get(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.Get(ApiUrls.CommitComment(owner, name, number)); + } + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + public Task> GetForRepository(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.GetAll(ApiUrls.CommitComments(owner, name)); + } + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + public Task> GetForCommit(string owner, string name, string sha) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + + return ApiConnection.GetAll(ApiUrls.CommitComments(owner, name, sha)); + } + + /// + /// Creates a new Commit Comment for a specified Issue. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + public Task Create(string owner, string name, string sha, NewCommitComment newCommitComment) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + Ensure.ArgumentNotNull(newCommitComment, "newCommitComment"); + + return ApiConnection.Post(ApiUrls.CommitComments(owner, name, sha), newCommitComment); + } + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + public Task Update(string owner, string name, int number, string commentUpdate) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(commentUpdate, "commentUpdate"); + + return ApiConnection.Patch(ApiUrls.CommitComment(owner, name, number), new BodyWrapper(commentUpdate)); + } + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public Task Delete(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return ApiConnection.Delete(ApiUrls.CommitComment(owner, name, number)); + } + } +} diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index d7dd4a54..6a650ec6 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -274,6 +274,41 @@ namespace Octokit return "repos/{0}/{1}/issues/comments/{2}".FormatUri(owner, name, number); } + /// + /// Returns the for the specified comment. + /// + /// The owner of the repository + /// The name of the repository + /// The comment number + /// + public static Uri CommitComment(string owner, string name, int number) + { + return "repos/{0}/{1}/comments/{2}".FormatUri(owner, name, number); + } + + /// + /// Returns the for the comments of a specified commit. + /// + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + public static Uri CommitComments(string owner, string name, string sha) + { + return "repos/{0}/{1}/commits/{2}/comments".FormatUri(owner, name, sha); + } + + /// + /// Returns the for the comments of a specified commit. + /// + /// The owner of the repository + /// The name of the repository + /// + public static Uri CommitComments(string owner, string name) + { + return "repos/{0}/{1}/comments".FormatUri(owner, name); + } + /// /// Returns the that returns all of the assignees to which issues may be assigned. /// diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 8a29a0e0..669d29a1 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -54,6 +54,7 @@ Properties\SolutionInfo.cs + From be2423956438f67399719038546539420dbe6ad6 Mon Sep 17 00:00:00 2001 From: Will Froese Date: Thu, 27 Feb 2014 21:02:17 -0500 Subject: [PATCH 03/46] Add Repository Comments stuff to additional assemblies --- Octokit/Octokit-Mono.csproj | 4 ++++ Octokit/Octokit-MonoAndroid.csproj | 4 ++++ Octokit/Octokit-Monotouch.csproj | 4 ++++ Octokit/Octokit-netcore45.csproj | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 62434eae..684a9c19 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -297,6 +297,10 @@ + + + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 2f28263d..60d4440c 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -308,6 +308,10 @@ + + + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 96608bc0..ce61d884 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -303,6 +303,10 @@ + + + + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 09841236..d0e91ee1 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -295,6 +295,10 @@ + + + + From 082658083c5b139fd52d6f79e843cdd1a5eff679 Mon Sep 17 00:00:00 2001 From: Will Froese Date: Thu, 27 Feb 2014 22:04:26 -0500 Subject: [PATCH 04/46] Add IObservableRepositoryCommentsClient as well as an implementation --- .../Clients/IObservableRepositoriesClient.cs | 8 ++ .../IObservableRepositoryCommentsClient.cs | 72 +++++++++++ .../Clients/ObservableRepositoriesClient.cs | 3 + .../ObservableRepositoryCommentsClient.cs | 122 ++++++++++++++++++ Octokit.Reactive/Octokit.Reactive-Mono.csproj | 2 + .../Octokit.Reactive-MonoAndroid.csproj | 2 + .../Octokit.Reactive-Monotouch.csproj | 2 + Octokit.Reactive/Octokit.Reactive.csproj | 2 + Octokit/Clients/IRepositoriesClient.cs | 8 ++ Octokit/Clients/IRepositoryCommentsClient.cs | 2 +- Octokit/Clients/RepositoriesClient.cs | 9 ++ Octokit/Clients/RepositoryCommentsClient.cs | 2 +- 12 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 Octokit.Reactive/Clients/IObservableRepositoryCommentsClient.cs create mode 100644 Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs diff --git a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs index 3888b188..639acde1 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs @@ -116,6 +116,14 @@ namespace Octokit.Reactive /// IObservableStatisticsClient Statistics { get; } + /// + /// Client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + IObservableRepositoryCommentsClient RepositoryComments { get; } + /// /// Gets all the branches for the specified repository. /// diff --git a/Octokit.Reactive/Clients/IObservableRepositoryCommentsClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryCommentsClient.cs new file mode 100644 index 00000000..2a1faef4 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableRepositoryCommentsClient.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reactive; + +namespace Octokit.Reactive +{ + public interface IObservableRepositoryCommentsClient + { + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", + Justification = "Method makes a network request")] + IObservable Get(string owner, string name, int number); + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + IObservable GetForRepository(string owner, string name); + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + IObservable GetForCommit(string owner, string name, string sha); + + /// + /// Creates a new Commit Comment for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + IObservable Create(string owner, string name, string sha, NewCommitComment newCommitComment); + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + IObservable Update(string owner, string name, int number, string commentUpdate); + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + IObservable Delete(string owner, string name, int number); + } +} diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs index 63a5b254..f05c9ddb 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs @@ -24,6 +24,7 @@ namespace Octokit.Reactive Deployment = new ObservableDeploymentsClient(client); Statistics = new ObservableStatisticsClient(client); PullRequest = new ObservablePullRequestsClient(client); + RepositoryComments = new ObservableRepositoryCommentsClient(client); } /// @@ -180,6 +181,8 @@ namespace Octokit.Reactive /// public IObservableStatisticsClient Statistics { get; private set; } + public IObservableRepositoryCommentsClient RepositoryComments { get; private set; } + /// /// Gets all the branches for the specified repository. /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs new file mode 100644 index 00000000..492792e8 --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs @@ -0,0 +1,122 @@ +using System; +using System.Reactive; +using System.Reactive.Threading.Tasks; +using Octokit.Reactive.Internal; + +namespace Octokit.Reactive +{ + public class ObservableRepositoryCommentsClient : IObservableRepositoryCommentsClient + { + readonly IRepositoryCommentsClient _client; + readonly IConnection _connection; + + public ObservableRepositoryCommentsClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, "client"); + + _client = client.Repository.RepositoryComments; + _connection = client.Connection; + } + + /// + /// Gets a single Repository Comment by number. + /// + /// http://developer.github.com/v3/repos/comments/#get-a-single-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public IObservable Get(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.Get(owner, name, number).ToObservable(); + } + + /// + /// Gets Commit Comments for a repository. + /// + /// http://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository + /// The owner of the repository + /// The name of the repository + /// + public IObservable GetForRepository(string owner, string name) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _connection.GetAndFlattenAllPages(ApiUrls.CommitComments(owner, name)); + } + + /// + /// Gets Commit Comments for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit + /// The owner of the repository + /// The name of the repository + /// The sha of the commit + /// + public IObservable GetForCommit(string owner, string name, string sha) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + + return _connection.GetAndFlattenAllPages(ApiUrls.CommitComments(owner, name, sha)); + } + + /// + /// Creates a new Commit Comment for a specified Commit. + /// + /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The sha reference of commit + /// The new comment to add to the commit + /// + public IObservable Create(string owner, string name, string sha, NewCommitComment newCommitComment) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); + Ensure.ArgumentNotNull(newCommitComment, "newCommitComment"); + + return _client.Create(owner, name, sha, newCommitComment).ToObservable(); + } + + /// + /// Updates a specified Commit Comment. + /// + /// http://developer.github.com/v3/repos/comments/#update-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment number + /// The modified comment + /// + public IObservable Update(string owner, string name, int number, string commentUpdate) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(commentUpdate, "commentUpdate"); + + return _client.Update(owner, name, number, commentUpdate).ToObservable(); + } + + /// + /// Deletes the specified Commit Comment + /// + /// http://developer.github.com/v3/repos/comments/#delete-a-commit-comment + /// The owner of the repository + /// The name of the repository + /// The comment id + /// + public IObservable Delete(string owner, string name, int number) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + return _client.Delete(owner, name, number).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj index d3c9a130..5dc511fd 100644 --- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj @@ -139,6 +139,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj index 885d6aa1..cd53c5a2 100644 --- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj +++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj @@ -148,6 +148,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj index f571279c..c8657d7f 100644 --- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj +++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj @@ -143,6 +143,8 @@ + + diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 5bd37f71..33216b99 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -73,6 +73,8 @@ Properties\SolutionInfo.cs + + diff --git a/Octokit/Clients/IRepositoriesClient.cs b/Octokit/Clients/IRepositoriesClient.cs index 8c700b5e..2989c610 100644 --- a/Octokit/Clients/IRepositoriesClient.cs +++ b/Octokit/Clients/IRepositoriesClient.cs @@ -22,6 +22,14 @@ namespace Octokit /// IPullRequestsClient PullRequest { get; } + /// + /// Client for managing commit comments in a repository. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + IRepositoryCommentsClient RepositoryComments { get; } + /// /// Creates a new repository for the current user. /// diff --git a/Octokit/Clients/IRepositoryCommentsClient.cs b/Octokit/Clients/IRepositoryCommentsClient.cs index 2ffa9649..cd47654b 100644 --- a/Octokit/Clients/IRepositoryCommentsClient.cs +++ b/Octokit/Clients/IRepositoryCommentsClient.cs @@ -44,7 +44,7 @@ namespace Octokit Task> GetForCommit(string owner, string name, string sha); /// - /// Creates a new Commit Comment for a specified Issue. + /// Creates a new Commit Comment for a specified Commit. /// /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment /// The owner of the repository diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index 38c3f920..f46e65bd 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -27,6 +27,7 @@ namespace Octokit Statistics = new StatisticsClient(apiConnection); Deployment = new DeploymentsClient(apiConnection); PullRequest = new PullRequestsClient(apiConnection); + RepositoryComments = new RepositoryCommentsClient(apiConnection); } /// @@ -286,6 +287,14 @@ namespace Octokit /// public IPullRequestsClient PullRequest { get; private set; } + /// + /// Client for managing commit comments in a repository. + /// + /// + /// See the Repository Comments API documentation for more information. + /// + public IRepositoryCommentsClient RepositoryComments { get; private set; } + /// /// Gets all the branches for the specified repository. /// diff --git a/Octokit/Clients/RepositoryCommentsClient.cs b/Octokit/Clients/RepositoryCommentsClient.cs index b5138b0b..8f7ccac4 100644 --- a/Octokit/Clients/RepositoryCommentsClient.cs +++ b/Octokit/Clients/RepositoryCommentsClient.cs @@ -70,7 +70,7 @@ namespace Octokit } /// - /// Creates a new Commit Comment for a specified Issue. + /// Creates a new Commit Comment for a specified Commit. /// /// http://developer.github.com/v3/repos/comments/#create-a-commit-comment /// The owner of the repository From 11b4e90792c46a4fe4ef394c5c63f39ae04d2e04 Mon Sep 17 00:00:00 2001 From: Will Froese Date: Fri, 28 Feb 2014 19:56:15 -0500 Subject: [PATCH 05/46] Add tests for RepositoryCommentsClient --- .../Clients/RepositoryCommentsClientTests.cs | 222 ++++++++++++++++++ Octokit.Tests/Octokit.Tests.csproj | 1 + 2 files changed, 223 insertions(+) create mode 100644 Octokit.Tests/Clients/RepositoryCommentsClientTests.cs diff --git a/Octokit.Tests/Clients/RepositoryCommentsClientTests.cs b/Octokit.Tests/Clients/RepositoryCommentsClientTests.cs new file mode 100644 index 00000000..a073da85 --- /dev/null +++ b/Octokit.Tests/Clients/RepositoryCommentsClientTests.cs @@ -0,0 +1,222 @@ +using System; +using System.Threading.Tasks; +using NSubstitute; +using Octokit; +using Octokit.Internal; +using Octokit.Tests.Helpers; +using Xunit; + +public class RepositoryCommentsClientTests +{ + public class TheGetMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Get("fake", "repo", 42); + + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/comments/42"), + null); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryCommentsClient(Substitute.For()); + + await AssertEx.Throws(async () => await client.Get(null, "name", 1)); + await AssertEx.Throws(async () => await client.Get("", "name", 1)); + await AssertEx.Throws(async () => await client.Get("owner", null, 1)); + await AssertEx.Throws(async () => await client.Get("owner", "", 1)); + } + + } + + public class TheGetForRepositoryMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.GetForRepository("fake", "repo"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/comments")); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.GetForRepository(null, "name")); + await AssertEx.Throws(async () => await client.GetForRepository("", "name")); + await AssertEx.Throws(async () => await client.GetForRepository("owner", null)); + await AssertEx.Throws(async () => await client.GetForRepository("owner", "")); + } + } + + public class TheGetForCommitMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.GetForCommit("fake", "repo", "sha"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/commits/sha/comments")); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.GetForCommit(null, "name", "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("", "name", "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("owner", null, "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("owner", "", "sha")); + await AssertEx.Throws(async () => await client.GetForCommit("owner", "name", null)); + await AssertEx.Throws(async () => await client.GetForCommit("owner", "name", "")); + } + } + + public class TheCreateMethod + { + [Fact] + public void PostsToCorrectUrl() + { + NewCommitComment newComment = new NewCommitComment("body"); + + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Create("fake", "repo", "sha", newComment); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/commits/sha/comments"), Arg.Any()); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.Create(null, "name", "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("", "name", "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", null, "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "", "sha", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "name", null, new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "name", "", new NewCommitComment("body"))); + await AssertEx.Throws(async () => await client.Create("owner", "name", "sha", null)); + } + } + + public class TheUpdateMethod + { + [Fact] + public void PostsToCorrectUrl() + { + const string issueCommentUpdate = "updated comment"; + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Update("fake", "repo", 42, issueCommentUpdate); + + connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/comments/42"), Arg.Any()); + } + + [Fact] + public async Task EnsuresArgumentsNotNull() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.Update(null, "name", 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("", "name", 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("owner", null, 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("owner", "", 42, "updated comment")); + await AssertEx.Throws(async () => await client.Update("owner", "name", 42, null)); + } + } + + public class TheDeleteMethod + { + [Fact] + public void DeletesCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + client.Delete("fake", "repo", 42); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "repos/fake/repo/comments/42")); + } + + [Fact] + public async Task EnsuresArgumentsNotNullOrEmpty() + { + var connection = Substitute.For(); + var client = new RepositoryCommentsClient(connection); + + await AssertEx.Throws(async () => await client.Delete(null, "name", 42)); + await AssertEx.Throws(async () => await client.Delete("", "name", 42)); + await AssertEx.Throws(async () => await client.Delete("owner", null, 42)); + await AssertEx.Throws(async () => await client.Delete("owner", "", 42)); + } + } + + public class TheCtor + { + [Fact] + public void EnsuresArgument() + { + Assert.Throws(() => new RepositoryCommentsClient(null)); + } + } + + [Fact] + public void CanDeserializeCommitComment() + { + const string commitCommentResponseJson = + "{\"html_url\": \"https://github.com/octocat/Hello-World/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e#commitcomment-1\"," + + "\"url\": \"https://api.github.com/repos/octocat/Hello-World/comments/1\"," + + "\"id\": 1," + + "\"body\": \"Me too\"," + + "\"path\": \"file1.txt\"," + + "\"position\": 4," + + "\"line\": 14," + + "\"commit_id\": \"6dcb09b5b57875f334f61aebed695e2e4193db5e\"," + + "\"user\": {" + + "\"login\": \"octocat\"," + + "\"id\": 1," + + "\"avatar_url\": \"https://github.com/images/error/octocat_happy.gif\"," + + "\"gravatar_id\": \"somehexcode\"," + + "\"url\": \"https://api.github.com/users/octocat\"" + + "}," + + "\"created_at\": \"2011-04-14T16:00:49Z\"," + + "\"updated_at\": \"2011-04-14T16:00:49Z\"" + + "}"; + + var response = new ApiResponse + { + Body = commitCommentResponseJson, + ContentType = "application/json" + }; + var jsonPipeline = new JsonHttpPipeline(); + + jsonPipeline.DeserializeResponse(response); + + Assert.NotNull(response.BodyAsObject); + Assert.Equal(commitCommentResponseJson, response.Body); + Assert.Equal(1, response.BodyAsObject.Id); + } +} diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index d60624e7..4be426d4 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -62,6 +62,7 @@ + From bd4b1bcc17a0e3f87c4aad1294b1b8241e3165c3 Mon Sep 17 00:00:00 2001 From: Will Froese Date: Sat, 1 Mar 2014 12:21:36 -0500 Subject: [PATCH 06/46] Updated comments --- Octokit.Reactive/Clients/ObservableRepositoriesClient.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs index f05c9ddb..13749739 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs @@ -181,6 +181,12 @@ namespace Octokit.Reactive /// public IObservableStatisticsClient Statistics { get; private set; } + /// + /// Client for GitHub's Repository Comments API. + /// + /// + /// See the Repository Comments API documentation for more information. + /// public IObservableRepositoryCommentsClient RepositoryComments { get; private set; } /// From 4f1f7e6629c1ae6abdc3429238cfee4527c580d4 Mon Sep 17 00:00:00 2001 From: Amy Palamountain Date: Mon, 3 Mar 2014 15:23:41 +1300 Subject: [PATCH 07/46] Extension method for IHttpClient To not require cancellation token --- Octokit/Helpers/HttpClientExtensions.cs | 17 +++++++++++++++++ Octokit/Octokit.csproj | 1 + 2 files changed, 18 insertions(+) create mode 100644 Octokit/Helpers/HttpClientExtensions.cs diff --git a/Octokit/Helpers/HttpClientExtensions.cs b/Octokit/Helpers/HttpClientExtensions.cs new file mode 100644 index 00000000..bb62925d --- /dev/null +++ b/Octokit/Helpers/HttpClientExtensions.cs @@ -0,0 +1,17 @@ +using System.Threading; +using System.Threading.Tasks; +using Octokit.Internal; + +namespace Octokit +{ + public static class HttpClientExtensions + { + public static Task> Send(this IHttpClient httpClient, IRequest request) + { + Ensure.ArgumentNotNull(httpClient, "httpClient"); + Ensure.ArgumentNotNull(request, "request"); + + return httpClient.Send(request, CancellationToken.None); + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 69ecd508..6fe2ef8d 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -58,6 +58,7 @@ + From 596c4df39a2a48f35930b6c4d358e2bfdb1107e1 Mon Sep 17 00:00:00 2001 From: Amy Palamountain Date: Mon, 3 Mar 2014 15:23:41 +1300 Subject: [PATCH 08/46] Extension method for IHttpClient To not require cancellation token --- Octokit/Helpers/HttpClientExtensions.cs | 17 +++++++++++++++++ Octokit/Octokit.csproj | 1 + 2 files changed, 18 insertions(+) create mode 100644 Octokit/Helpers/HttpClientExtensions.cs diff --git a/Octokit/Helpers/HttpClientExtensions.cs b/Octokit/Helpers/HttpClientExtensions.cs new file mode 100644 index 00000000..bb62925d --- /dev/null +++ b/Octokit/Helpers/HttpClientExtensions.cs @@ -0,0 +1,17 @@ +using System.Threading; +using System.Threading.Tasks; +using Octokit.Internal; + +namespace Octokit +{ + public static class HttpClientExtensions + { + public static Task> Send(this IHttpClient httpClient, IRequest request) + { + Ensure.ArgumentNotNull(httpClient, "httpClient"); + Ensure.ArgumentNotNull(request, "request"); + + return httpClient.Send(request, CancellationToken.None); + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 69ecd508..6fe2ef8d 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -58,6 +58,7 @@ + From 143721993441b51e4f85d91096430da338557411 Mon Sep 17 00:00:00 2001 From: Will Froese Date: Mon, 3 Mar 2014 20:14:50 -0500 Subject: [PATCH 09/46] Run FixProjects --- Octokit/Octokit-Mono.csproj | 1 + Octokit/Octokit-MonoAndroid.csproj | 1 + Octokit/Octokit-Monotouch.csproj | 1 + Octokit/Octokit-netcore45.csproj | 1 + 4 files changed, 4 insertions(+) diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index d2306513..6959dd58 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -305,6 +305,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index a71d0331..3c293bfc 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -316,6 +316,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index ce5a4085..1d5461fc 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -311,6 +311,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index ab5c2a54..9d2fa2d3 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -303,6 +303,7 @@ + From 11514473f9b7b20639af31a14d2486df816cd53c Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Tue, 4 Mar 2014 22:10:37 +1100 Subject: [PATCH 10/46] added a simple integration test and got it passing --- .../Clients/SearchClientTests.cs | 26 +++++++++++++++++++ .../Octokit.Tests.Integration.csproj | 1 + Octokit/Clients/ISearchClient.cs | 2 +- Octokit/Clients/SearchClient.cs | 4 +-- .../Models/Response/SearchRepositoryResult.cs | 11 ++++++++ Octokit/Octokit-Mono.csproj | 2 ++ Octokit/Octokit-MonoAndroid.csproj | 2 ++ Octokit/Octokit-Monotouch.csproj | 2 ++ Octokit/Octokit-netcore45.csproj | 2 ++ Octokit/Octokit.csproj | 1 + 10 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 Octokit.Tests.Integration/Clients/SearchClientTests.cs create mode 100644 Octokit/Models/Response/SearchRepositoryResult.cs diff --git a/Octokit.Tests.Integration/Clients/SearchClientTests.cs b/Octokit.Tests.Integration/Clients/SearchClientTests.cs new file mode 100644 index 00000000..8c2640b5 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/SearchClientTests.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Octokit; +using Octokit.Tests.Integration; +using Xunit; + +public class SearchClientTests +{ + readonly IGitHubClient _gitHubClient; + + public SearchClientTests() + { + _gitHubClient = new GitHubClient(new ProductHeaderValue("OctokitTests")) + { + Credentials = Helper.Credentials + }; + } + + [Fact] + public async Task SearchForCSharpRepositories() + { + var request = new SearchRepositoriesRequest("csharp"); + var repos = await _gitHubClient.Search.SearchRepo(request); + + Assert.NotEmpty(repos.Items); + } +} diff --git a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj index 274abe0e..24eb70c1 100644 --- a/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj +++ b/Octokit.Tests.Integration/Octokit.Tests.Integration.csproj @@ -71,6 +71,7 @@ + diff --git a/Octokit/Clients/ISearchClient.cs b/Octokit/Clients/ISearchClient.cs index 4ad5d09c..f562d239 100644 --- a/Octokit/Clients/ISearchClient.cs +++ b/Octokit/Clients/ISearchClient.cs @@ -16,7 +16,7 @@ namespace Octokit /// /// /// List of repos - Task> SearchRepo(SearchRepositoriesRequest search); + Task SearchRepo(SearchRepositoriesRequest search); /// /// search users diff --git a/Octokit/Clients/SearchClient.cs b/Octokit/Clients/SearchClient.cs index 2c079c85..c8ee5391 100644 --- a/Octokit/Clients/SearchClient.cs +++ b/Octokit/Clients/SearchClient.cs @@ -25,10 +25,10 @@ namespace Octokit /// /// /// List of repos - public Task> SearchRepo(SearchRepositoriesRequest search) + public Task SearchRepo(SearchRepositoriesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchRepositories(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchRepositories(), search.Parameters); } /// diff --git a/Octokit/Models/Response/SearchRepositoryResult.cs b/Octokit/Models/Response/SearchRepositoryResult.cs new file mode 100644 index 00000000..8c7776b6 --- /dev/null +++ b/Octokit/Models/Response/SearchRepositoryResult.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Octokit +{ + public class SearchRepositoryResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IList Items { get; set; } + } +} diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index a0dbce03..0e552df4 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -301,6 +301,8 @@ + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 9edf8da4..d4380bb3 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -312,6 +312,8 @@ + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index ed79d019..54655baf 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -307,6 +307,8 @@ + + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 5757e82d..729fccba 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -243,6 +243,7 @@ + @@ -299,6 +300,7 @@ + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 6fe2ef8d..a8312055 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -136,6 +136,7 @@ + From 5991f5a792468e42188f352a429bc9807c3702ba Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Tue, 4 Mar 2014 22:14:47 +1100 Subject: [PATCH 11/46] updated impacted tests --- Octokit.Tests/Clients/SearchClientTests.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index e081161f..5a18c57b 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -336,7 +336,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchRepo(new SearchRepositoriesRequest("something")); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -357,7 +357,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -371,7 +371,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -385,7 +385,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -399,7 +399,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -413,7 +413,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -426,7 +426,7 @@ namespace Octokit.Tests.Clients request.In = new[] { InQualifier.Description }; client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -440,7 +440,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -454,7 +454,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -468,7 +468,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } [Fact] @@ -482,7 +482,7 @@ namespace Octokit.Tests.Clients client.SearchRepo(request); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/repositories"), Arg.Any>()); } } From 4ca19e52bd43d2353bf16ee02f4713dd93bd4033 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Tue, 4 Mar 2014 22:20:41 +1100 Subject: [PATCH 12/46] updated convention tests --- .../Clients/IObservableSearchClient.cs | 4 +--- Octokit.Reactive/Clients/ObservableSearchClient.cs | 6 ++++-- Octokit/Models/Response/SearchRepositoryResult.cs | 14 +++++++++++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservableSearchClient.cs b/Octokit.Reactive/Clients/IObservableSearchClient.cs index b4273750..821c1d7f 100644 --- a/Octokit.Reactive/Clients/IObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/IObservableSearchClient.cs @@ -1,6 +1,4 @@ using System; -using System.Diagnostics.CodeAnalysis; -using System.Reactive; namespace Octokit.Reactive { @@ -15,7 +13,7 @@ namespace Octokit.Reactive /// /// /// List of repositories - IObservable SearchRepo(SearchRepositoriesRequest search); + IObservable SearchRepo(SearchRepositoriesRequest search); /// /// search users diff --git a/Octokit.Reactive/Clients/ObservableSearchClient.cs b/Octokit.Reactive/Clients/ObservableSearchClient.cs index c34e4525..c30b757a 100644 --- a/Octokit.Reactive/Clients/ObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/ObservableSearchClient.cs @@ -11,11 +11,13 @@ namespace Octokit.Reactive public class ObservableSearchClient : IObservableSearchClient { readonly IConnection _connection; + readonly IGitHubClient _client; public ObservableSearchClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); + _client = client; _connection = client.Connection; } @@ -25,10 +27,10 @@ namespace Octokit.Reactive /// /// /// List of repositories - public IObservable SearchRepo(SearchRepositoriesRequest search) + public IObservable SearchRepo(SearchRepositoriesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchRepositories(), search.Parameters); + return _client.Search.SearchRepo(search).ToObservable(); } /// diff --git a/Octokit/Models/Response/SearchRepositoryResult.cs b/Octokit/Models/Response/SearchRepositoryResult.cs index 8c7776b6..0450add0 100644 --- a/Octokit/Models/Response/SearchRepositoryResult.cs +++ b/Octokit/Models/Response/SearchRepositoryResult.cs @@ -1,11 +1,23 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; namespace Octokit { + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class SearchRepositoryResult { public int TotalCount { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public IList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } } } From 5a6df4afb4defb60a9ba02a67a90cf2d03ec3881 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 21:48:42 +1100 Subject: [PATCH 13/46] updated SimpleJson to v0.34 --- Octokit/SimpleJson.cs | 94 +++++++++++++----- Octokit/packages.config | 2 +- .../SimpleJson.0.30.0/SimpleJson.0.30.0.nupkg | Bin 30756 -> 0 bytes .../SimpleJson.0.30.0.nuspec | 15 --- .../SimpleJson.0.34.0/SimpleJson.0.34.0.nupkg | Bin 0 -> 31698 bytes .../SimpleJson.psm1 | 87 ++++++++++++---- .../content/SimpleJson.cs.pp | 85 ++++++++++++---- 7 files changed, 201 insertions(+), 82 deletions(-) delete mode 100644 packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nupkg delete mode 100644 packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nuspec create mode 100644 packages/SimpleJson.0.34.0/SimpleJson.0.34.0.nupkg rename packages/{SimpleJson.0.30.0 => SimpleJson.0.34.0}/SimpleJson.psm1 (97%) rename packages/{SimpleJson.0.30.0 => SimpleJson.0.34.0}/content/SimpleJson.cs.pp (97%) diff --git a/Octokit/SimpleJson.cs b/Octokit/SimpleJson.cs index b8300f34..9266c3dc 100644 --- a/Octokit/SimpleJson.cs +++ b/Octokit/SimpleJson.cs @@ -17,7 +17,7 @@ // https://github.com/facebook-csharp-sdk/simple-json //----------------------------------------------------------------------- -// VERSION: 0.30.0 +// VERSION: 0.34.0 // NOTE: uncomment the following line to make SimpleJson class internal. //#define SIMPLE_JSON_INTERNAL @@ -31,6 +31,9 @@ // NOTE: uncomment the following line to enable DataContract support. //#define SIMPLE_JSON_DATACONTRACT +// NOTE: uncomment the following line to enable IReadOnlyCollection and IReadOnlyList support. +//#define SIMPLE_JSON_READONLY_COLLECTIONS + // NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke(). // define if you are using .net framework <= 3.0 or < WP7.5 //#define SIMPLE_JSON_NO_LINQ_EXPRESSION @@ -51,7 +54,6 @@ using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; -using System.Linq; #if !SIMPLE_JSON_NO_LINQ_EXPRESSION using System.Linq.Expressions; #endif @@ -513,6 +515,22 @@ namespace Octokit private const int TOKEN_NULL = 11; private const int BUILDER_CAPACITY = 2000; + private static readonly char[] EscapeTable; + private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' }; + private static readonly string EscapeCharactersString = new string(EscapeCharacters); + + static SimpleJson() + { + EscapeTable = new char[93]; + EscapeTable['"'] = '"'; + EscapeTable['\\'] = '\\'; + EscapeTable['\b'] = 'b'; + EscapeTable['\f'] = 'f'; + EscapeTable['\n'] = 'n'; + EscapeTable['\r'] = 'r'; + EscapeTable['\t'] = 't'; + } + /// /// Parses the string json into a value /// @@ -1074,29 +1092,50 @@ namespace Octokit static bool SerializeString(string aString, StringBuilder builder) { - builder.Append("\""); + // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged) + if (aString.IndexOfAny(EscapeCharacters) == -1) + { + builder.Append('"'); + builder.Append(aString); + builder.Append('"'); + + return true; + } + + builder.Append('"'); + int safeCharacterCount = 0; char[] charArray = aString.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) { char c = charArray[i]; - if (c == '"') - builder.Append("\\\""); - else if (c == '\\') - builder.Append("\\\\"); - else if (c == '\b') - builder.Append("\\b"); - else if (c == '\f') - builder.Append("\\f"); - else if (c == '\n') - builder.Append("\\n"); - else if (c == '\r') - builder.Append("\\r"); - else if (c == '\t') - builder.Append("\\t"); + + // Non ascii characters are fine, buffer them up and send them to the builder + // in larger chunks if possible. The escape table is a 1:1 translation table + // with \0 [default(char)] denoting a safe character. + if (c >= EscapeTable.Length || EscapeTable[c] == default(char)) + { + safeCharacterCount++; + } else - builder.Append(c); + { + if (safeCharacterCount > 0) + { + builder.Append(charArray, i - safeCharacterCount, safeCharacterCount); + safeCharacterCount = 0; + } + + builder.Append('\\'); + builder.Append(EscapeTable[c]); + } } - builder.Append("\""); + + if (safeCharacterCount > 0) + { + builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount); + } + + builder.Append('"'); return true; } @@ -1647,7 +1686,14 @@ namespace Octokit Type genericDefinition = type.GetGenericTypeDefinition(); - return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>)); + return (genericDefinition == typeof(IList<>) + || genericDefinition == typeof(ICollection<>) + || genericDefinition == typeof(IEnumerable<>) +#if SIMPLE_JSON_READONLY_COLLECTIONS + || genericDefinition == typeof(IReadOnlyCollection<>) + || genericDefinition == typeof(IReadOnlyList<>) +#endif + ); } public static bool IsAssignableFrom(Type type1, Type type2) @@ -1727,13 +1773,7 @@ namespace Octokit public static IEnumerable GetProperties(Type type) { #if SIMPLE_JSON_TYPEINFO - var info = type.GetTypeInfo(); - - var baseProperties = info.BaseType != null && info.BaseType != typeof(Object) - ? GetProperties(info.BaseType) - : new PropertyInfo[0]; - - return info.DeclaredProperties.Concat(baseProperties); + return type.GetTypeInfo().DeclaredProperties; #else return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); #endif diff --git a/Octokit/packages.config b/Octokit/packages.config index fe57a08e..3771b8bf 100644 --- a/Octokit/packages.config +++ b/Octokit/packages.config @@ -6,5 +6,5 @@ - + \ No newline at end of file diff --git a/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nupkg b/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nupkg deleted file mode 100644 index b35a0ddab6a62313faacf3a93457bfc32d1fed67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30756 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 F{tt|SZcqRK diff --git a/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nuspec b/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nuspec deleted file mode 100644 index bfc5f00d..00000000 --- a/packages/SimpleJson.0.30.0/SimpleJson.0.30.0.nuspec +++ /dev/null @@ -1,15 +0,0 @@ - - - - SimpleJson - 0.30.0 - Jim Zimmerman, Nathan Totten, Prabir Shrestha - Jim Zimmerman, Nathan Totten, Prabir Shrestha - https://raw.github.com/facebook-csharp-sdk/simple-json/master/LICENSE.txt - https://raw.github.com/facebook-csharp-sdk/simple-json - false - Super lightweight Json library for .NET 2.0+/SL4+/WP7/WindowsStore Apps/Portable Class Libraries along with dynamic and DataContract support - en-US - json - - \ No newline at end of file diff --git a/packages/SimpleJson.0.34.0/SimpleJson.0.34.0.nupkg b/packages/SimpleJson.0.34.0/SimpleJson.0.34.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..3dbe14c4ac55b229998ace8a5c2d662200752c1f GIT binary patch literal 31698 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 aAb&NYWyB$&epG{cd9}O@d{EaPrT+&P<-9Hc literal 0 HcmV?d00001 diff --git a/packages/SimpleJson.0.30.0/SimpleJson.psm1 b/packages/SimpleJson.0.34.0/SimpleJson.psm1 similarity index 97% rename from packages/SimpleJson.0.30.0/SimpleJson.psm1 rename to packages/SimpleJson.0.34.0/SimpleJson.psm1 index d34066dd..7cfbf98b 100644 --- a/packages/SimpleJson.0.30.0/SimpleJson.psm1 +++ b/packages/SimpleJson.0.34.0/SimpleJson.psm1 @@ -1,6 +1,6 @@ # SimpleJson https://github.com/facebook-csharp-sdk/simple-json # License: MIT License -# Version: 0.30.0 +# Version: 0.34.0 function ConvertFrom-Json { @@ -87,7 +87,7 @@ $source = @" // https://github.com/facebook-csharp-sdk/simple-json //----------------------------------------------------------------------- -// VERSION: 0.30.0 +// VERSION: 0.34.0 // NOTE: uncomment the following line to make SimpleJson class internal. //#define SIMPLE_JSON_INTERNAL @@ -101,6 +101,9 @@ $source = @" // NOTE: uncomment the following line to enable DataContract support. //#define SIMPLE_JSON_DATACONTRACT +// NOTE: uncomment the following line to enable IReadOnlyCollection and IReadOnlyList support. +//#define SIMPLE_JSON_READONLY_COLLECTIONS + // NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke(). // define if you are using .net framework <= 3.0 or < WP7.5 //#define SIMPLE_JSON_NO_LINQ_EXPRESSION @@ -582,6 +585,22 @@ namespace SimpleJson private const int TOKEN_NULL = 11; private const int BUILDER_CAPACITY = 2000; + private static readonly char[] EscapeTable; + private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' }; + private static readonly string EscapeCharactersString = new string(EscapeCharacters); + + static SimpleJson() + { + EscapeTable = new char[93]; + EscapeTable['"'] = '"'; + EscapeTable['\\'] = '\\'; + EscapeTable['\b'] = 'b'; + EscapeTable['\f'] = 'f'; + EscapeTable['\n'] = 'n'; + EscapeTable['\r'] = 'r'; + EscapeTable['\t'] = 't'; + } + /// /// Parses the string json into a value /// @@ -1143,29 +1162,50 @@ namespace SimpleJson static bool SerializeString(string aString, StringBuilder builder) { - builder.Append("\""); + // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged) + if (aString.IndexOfAny(EscapeCharacters) == -1) + { + builder.Append('"'); + builder.Append(aString); + builder.Append('"'); + + return true; + } + + builder.Append('"'); + int safeCharacterCount = 0; char[] charArray = aString.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) { char c = charArray[i]; - if (c == '"') - builder.Append("\\\""); - else if (c == '\\') - builder.Append("\\\\"); - else if (c == '\b') - builder.Append("\\b"); - else if (c == '\f') - builder.Append("\\f"); - else if (c == '\n') - builder.Append("\\n"); - else if (c == '\r') - builder.Append("\\r"); - else if (c == '\t') - builder.Append("\\t"); + + // Non ascii characters are fine, buffer them up and send them to the builder + // in larger chunks if possible. The escape table is a 1:1 translation table + // with \0 [default(char)] denoting a safe character. + if (c >= EscapeTable.Length || EscapeTable[c] == default(char)) + { + safeCharacterCount++; + } else - builder.Append(c); + { + if (safeCharacterCount > 0) + { + builder.Append(charArray, i - safeCharacterCount, safeCharacterCount); + safeCharacterCount = 0; + } + + builder.Append('\\'); + builder.Append(EscapeTable[c]); + } } - builder.Append("\""); + + if (safeCharacterCount > 0) + { + builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount); + } + + builder.Append('"'); return true; } @@ -1716,7 +1756,14 @@ namespace SimpleJson Type genericDefinition = type.GetGenericTypeDefinition(); - return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>)); + return (genericDefinition == typeof(IList<>) + || genericDefinition == typeof(ICollection<>) + || genericDefinition == typeof(IEnumerable<>) +#if SIMPLE_JSON_READONLY_COLLECTIONS + || genericDefinition == typeof(IReadOnlyCollection<>) + || genericDefinition == typeof(IReadOnlyList<>) +#endif + ); } public static bool IsAssignableFrom(Type type1, Type type2) diff --git a/packages/SimpleJson.0.30.0/content/SimpleJson.cs.pp b/packages/SimpleJson.0.34.0/content/SimpleJson.cs.pp similarity index 97% rename from packages/SimpleJson.0.30.0/content/SimpleJson.cs.pp rename to packages/SimpleJson.0.34.0/content/SimpleJson.cs.pp index 47dbe189..b7c86642 100644 --- a/packages/SimpleJson.0.30.0/content/SimpleJson.cs.pp +++ b/packages/SimpleJson.0.34.0/content/SimpleJson.cs.pp @@ -17,7 +17,7 @@ // https://github.com/facebook-csharp-sdk/simple-json //----------------------------------------------------------------------- -// VERSION: 0.30.0 +// VERSION: 0.34.0 // NOTE: uncomment the following line to make SimpleJson class internal. //#define SIMPLE_JSON_INTERNAL @@ -31,6 +31,9 @@ // NOTE: uncomment the following line to enable DataContract support. //#define SIMPLE_JSON_DATACONTRACT +// NOTE: uncomment the following line to enable IReadOnlyCollection and IReadOnlyList support. +//#define SIMPLE_JSON_READONLY_COLLECTIONS + // NOTE: uncomment the following line to disable linq expressions/compiled lambda (better performance) instead of method.invoke(). // define if you are using .net framework <= 3.0 or < WP7.5 //#define SIMPLE_JSON_NO_LINQ_EXPRESSION @@ -512,6 +515,22 @@ namespace $rootnamespace$ private const int TOKEN_NULL = 11; private const int BUILDER_CAPACITY = 2000; + private static readonly char[] EscapeTable; + private static readonly char[] EscapeCharacters = new char[] { '"', '\\', '\b', '\f', '\n', '\r', '\t' }; + private static readonly string EscapeCharactersString = new string(EscapeCharacters); + + static SimpleJson() + { + EscapeTable = new char[93]; + EscapeTable['"'] = '"'; + EscapeTable['\\'] = '\\'; + EscapeTable['\b'] = 'b'; + EscapeTable['\f'] = 'f'; + EscapeTable['\n'] = 'n'; + EscapeTable['\r'] = 'r'; + EscapeTable['\t'] = 't'; + } + /// /// Parses the string json into a value /// @@ -1073,29 +1092,50 @@ namespace $rootnamespace$ static bool SerializeString(string aString, StringBuilder builder) { - builder.Append("\""); + // Happy path if there's nothing to be escaped. IndexOfAny is highly optimized (and unmanaged) + if (aString.IndexOfAny(EscapeCharacters) == -1) + { + builder.Append('"'); + builder.Append(aString); + builder.Append('"'); + + return true; + } + + builder.Append('"'); + int safeCharacterCount = 0; char[] charArray = aString.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) { char c = charArray[i]; - if (c == '"') - builder.Append("\\\""); - else if (c == '\\') - builder.Append("\\\\"); - else if (c == '\b') - builder.Append("\\b"); - else if (c == '\f') - builder.Append("\\f"); - else if (c == '\n') - builder.Append("\\n"); - else if (c == '\r') - builder.Append("\\r"); - else if (c == '\t') - builder.Append("\\t"); + + // Non ascii characters are fine, buffer them up and send them to the builder + // in larger chunks if possible. The escape table is a 1:1 translation table + // with \0 [default(char)] denoting a safe character. + if (c >= EscapeTable.Length || EscapeTable[c] == default(char)) + { + safeCharacterCount++; + } else - builder.Append(c); + { + if (safeCharacterCount > 0) + { + builder.Append(charArray, i - safeCharacterCount, safeCharacterCount); + safeCharacterCount = 0; + } + + builder.Append('\\'); + builder.Append(EscapeTable[c]); + } } - builder.Append("\""); + + if (safeCharacterCount > 0) + { + builder.Append(charArray, charArray.Length - safeCharacterCount, safeCharacterCount); + } + + builder.Append('"'); return true; } @@ -1646,7 +1686,14 @@ namespace $rootnamespace$ Type genericDefinition = type.GetGenericTypeDefinition(); - return (genericDefinition == typeof(IList<>) || genericDefinition == typeof(ICollection<>) || genericDefinition == typeof(IEnumerable<>)); + return (genericDefinition == typeof(IList<>) + || genericDefinition == typeof(ICollection<>) + || genericDefinition == typeof(IEnumerable<>) +#if SIMPLE_JSON_READONLY_COLLECTIONS + || genericDefinition == typeof(IReadOnlyCollection<>) + || genericDefinition == typeof(IReadOnlyList<>) +#endif + ); } public static bool IsAssignableFrom(Type type1, Type type2) From f9f2c816bf59cbe7e673f909c709fad2371128ce Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 21:49:15 +1100 Subject: [PATCH 14/46] added hotfix to serialize base classes --- Octokit/SimpleJson.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Octokit/SimpleJson.cs b/Octokit/SimpleJson.cs index 9266c3dc..36a1688f 100644 --- a/Octokit/SimpleJson.cs +++ b/Octokit/SimpleJson.cs @@ -1773,7 +1773,17 @@ namespace Octokit public static IEnumerable GetProperties(Type type) { #if SIMPLE_JSON_TYPEINFO - return type.GetTypeInfo().DeclaredProperties; + var typeInfo = type.GetTypeInfo(); + var properties = typeInfo.DeclaredProperties; + + if (typeInfo.BaseType == null) + return properties; + + if (typeInfo.BaseType.FullName == typeof (Object).FullName) + return properties; + + var baseProperties = GetProperties(typeInfo.BaseType); + return System.Linq.Enumerable.Concat(properties, baseProperties); #else return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); #endif From 8ae7943c1a7c1f72c3b3fffaf4a6170b5ed53739 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 21:59:46 +1100 Subject: [PATCH 15/46] enabled readonly collections support in builds --- Octokit.Reactive/Octokit.Reactive.csproj | 4 ++-- Octokit/Octokit.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 5a9d0d03..98cc86c4 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -19,7 +19,7 @@ false obj\Debug\Net40 bin\Debug\Net45\ - DEBUG;TRACE;CODE_ANALYSIS;NET_45 + TRACE;DEBUG;CODE_ANALYSIS;CODE_ANALYSIS;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 true @@ -32,7 +32,7 @@ true obj\Release\Net40 bin\Release\Net45\ - TRACE;NET_45 + TRACE;CODE_ANALYSIS;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 false diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index a8312055..86e4d97b 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -19,7 +19,7 @@ false obj\Debug\Net45 bin\Debug\Net45 - TRACE;DEBUG;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45 + TRACE;DEBUG;CODE_ANALYSIS;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 true @@ -33,7 +33,7 @@ true obj\Release\Net45 bin\Release\Net45\ - TRACE;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45 + TRACE;CODE_ANALYSIS;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 false From 12b82687ca1a08335b2c1036fd8caa91355e6891 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 22:01:08 +1100 Subject: [PATCH 16/46] enabled readonly collection --- Octokit/Models/Response/SearchRepositoryResult.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit/Models/Response/SearchRepositoryResult.cs b/Octokit/Models/Response/SearchRepositoryResult.cs index 0450add0..6ee9bc07 100644 --- a/Octokit/Models/Response/SearchRepositoryResult.cs +++ b/Octokit/Models/Response/SearchRepositoryResult.cs @@ -10,7 +10,7 @@ namespace Octokit { public int TotalCount { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] - public IList Items { get; set; } + public IReadOnlyList Items { get; set; } internal string DebuggerDisplay { From 55d0e997752842a6541ed68d5b3c25395994fe15 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 22:04:40 +1100 Subject: [PATCH 17/46] cleanup of constants --- Octokit.Reactive/Octokit.Reactive.csproj | 2 +- Octokit/Octokit.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj index 5caf20db..f08540c7 100644 --- a/Octokit.Reactive/Octokit.Reactive.csproj +++ b/Octokit.Reactive/Octokit.Reactive.csproj @@ -19,7 +19,7 @@ false obj\Debug\Net40 bin\Debug\Net45\ - TRACE;DEBUG;CODE_ANALYSIS;CODE_ANALYSIS;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS + TRACE;DEBUG;CODE_ANALYSIS;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 true diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 72a03874..c2dc3fd9 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -19,7 +19,7 @@ false obj\Debug\Net45 bin\Debug\Net45 - TRACE;DEBUG;CODE_ANALYSIS;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS + TRACE;DEBUG;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 true @@ -33,7 +33,7 @@ true obj\Release\Net45 bin\Release\Net45\ - TRACE;CODE_ANALYSIS;CODE_ANALYSIS;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS + TRACE;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 false From 433e9249a917dc806d9f1a88e3b68a860bd4e919 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 22:22:10 +1100 Subject: [PATCH 18/46] updated SearchUsers to match correct response shape --- .../Clients/IObservableSearchClient.cs | 2 +- .../Clients/ObservableSearchClient.cs | 4 +- .../Clients/SearchClientTests.cs | 9 ++++ Octokit.Tests/Clients/SearchClientTests.cs | 46 +++++++++---------- Octokit/Clients/ISearchClient.cs | 3 +- Octokit/Clients/SearchClient.cs | 4 +- Octokit/Models/Response/SearchUsersResult.cs | 23 ++++++++++ Octokit/Octokit-Mono.csproj | 1 + Octokit/Octokit-MonoAndroid.csproj | 1 + Octokit/Octokit-Monotouch.csproj | 1 + Octokit/Octokit-netcore45.csproj | 1 + Octokit/Octokit.csproj | 1 + 12 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 Octokit/Models/Response/SearchUsersResult.cs diff --git a/Octokit.Reactive/Clients/IObservableSearchClient.cs b/Octokit.Reactive/Clients/IObservableSearchClient.cs index 821c1d7f..37a75825 100644 --- a/Octokit.Reactive/Clients/IObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/IObservableSearchClient.cs @@ -21,7 +21,7 @@ namespace Octokit.Reactive /// /// /// List of users - IObservable SearchUsers(SearchUsersRequest search); + IObservable SearchUsers(SearchUsersRequest search); /// /// search issues diff --git a/Octokit.Reactive/Clients/ObservableSearchClient.cs b/Octokit.Reactive/Clients/ObservableSearchClient.cs index c30b757a..220cc48e 100644 --- a/Octokit.Reactive/Clients/ObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/ObservableSearchClient.cs @@ -39,10 +39,10 @@ namespace Octokit.Reactive /// /// /// List of users - public IObservable SearchUsers(SearchUsersRequest search) + public IObservable SearchUsers(SearchUsersRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchUsers(), search.Parameters); + return _client.Search.SearchUsers(search).ToObservable(); } /// diff --git a/Octokit.Tests.Integration/Clients/SearchClientTests.cs b/Octokit.Tests.Integration/Clients/SearchClientTests.cs index 8c2640b5..da5204e7 100644 --- a/Octokit.Tests.Integration/Clients/SearchClientTests.cs +++ b/Octokit.Tests.Integration/Clients/SearchClientTests.cs @@ -23,4 +23,13 @@ public class SearchClientTests Assert.NotEmpty(repos.Items); } + + [Fact] + public async Task SearchForGitHub() + { + var request = new SearchUsersRequest("github"); + var repos = await _gitHubClient.Search.SearchUsers(request); + + Assert.NotEmpty(repos.Items); + } } diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 5a18c57b..2aac476c 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -30,7 +30,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchUsers(new SearchUsersRequest("something")); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/users"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/users"), Arg.Any>()); } [Fact] @@ -47,7 +47,7 @@ namespace Octokit.Tests.Clients var client = new SearchClient(connection); var request = new SearchUsersRequest("github"); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github")); } @@ -60,7 +60,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.AccountType = AccountType.User; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+type:User")); } @@ -73,7 +73,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.AccountType = AccountType.Org; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+type:Org")); } @@ -87,7 +87,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Fullname }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Fullname")); } @@ -100,7 +100,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Email }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Email")); } @@ -113,7 +113,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Username }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Username")); } @@ -126,7 +126,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.In = new[] { UserInQualifier.Username, UserInQualifier.Fullname, UserInQualifier.Email }; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+in:Username,Fullname,Email")); } @@ -139,7 +139,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.GreaterThan(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:>5")); } @@ -152,7 +152,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.GreaterThanOrEquals(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:>=5")); } @@ -165,7 +165,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.LessThanOrEquals(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:<=5")); } @@ -178,7 +178,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Repositories = Range.LessThan(5); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+repos:<5")); } @@ -191,7 +191,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Location = "San Francisco"; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+location:San Francisco")); } @@ -205,7 +205,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Language = Language.Ruby; client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+language:Ruby")); } @@ -218,7 +218,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.GreaterThan(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:>2014-01-01")); } @@ -231,7 +231,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.GreaterThanOrEquals(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:>=2014-01-01")); } @@ -244,7 +244,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.LessThanOrEquals(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:<=2014-01-01")); } @@ -257,7 +257,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Created = DateRange.LessThan(new DateTime(2014, 1, 1)); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+created:<2014-01-01")); } @@ -270,7 +270,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.GreaterThan(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:>1")); } @@ -283,7 +283,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.GreaterThanOrEquals(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:>=1")); } @@ -296,7 +296,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.LessThan(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:<1")); } @@ -309,7 +309,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = Range.LessThanOrEquals(1); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:<=1")); } @@ -322,7 +322,7 @@ namespace Octokit.Tests.Clients var request = new SearchUsersRequest("github"); request.Followers = new Range(1, 1000); client.SearchUsers(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/users"), Arg.Is>(d => d["q"] == "github+followers:1..1000")); } diff --git a/Octokit/Clients/ISearchClient.cs b/Octokit/Clients/ISearchClient.cs index f562d239..8119aa37 100644 --- a/Octokit/Clients/ISearchClient.cs +++ b/Octokit/Clients/ISearchClient.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit { - /// /// GitHub Search Api Client /// @@ -24,7 +23,7 @@ namespace Octokit /// /// /// List of users - Task> SearchUsers(SearchUsersRequest search); + Task SearchUsers(SearchUsersRequest search); /// /// search issues diff --git a/Octokit/Clients/SearchClient.cs b/Octokit/Clients/SearchClient.cs index c8ee5391..9cfb6041 100644 --- a/Octokit/Clients/SearchClient.cs +++ b/Octokit/Clients/SearchClient.cs @@ -37,10 +37,10 @@ namespace Octokit /// /// /// List of users - public Task> SearchUsers(SearchUsersRequest search) + public Task SearchUsers(SearchUsersRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchUsers(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchUsers(), search.Parameters); } /// diff --git a/Octokit/Models/Response/SearchUsersResult.cs b/Octokit/Models/Response/SearchUsersResult.cs new file mode 100644 index 00000000..4e5a4f9c --- /dev/null +++ b/Octokit/Models/Response/SearchUsersResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchUsersResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IReadOnlyList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 782c2aa3..bb7803d3 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -307,6 +307,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 64bed0ac..19b956e7 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -318,6 +318,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 33815ea8..24c46fcf 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -313,6 +313,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 1b037257..f7b3c62e 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -305,6 +305,7 @@ + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index c2dc3fd9..a284967b 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -141,6 +141,7 @@ + From b64527ec9231110664777ea3dffe4d22ca68be6d Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 22:42:10 +1100 Subject: [PATCH 19/46] updated SearchCode to match correct response shape --- .../Clients/IObservableSearchClient.cs | 2 +- .../Clients/ObservableSearchClient.cs | 4 +- .../Clients/SearchClientTests.cs | 10 +++++ Octokit.Tests/Clients/SearchClientTests.cs | 38 +++++++++---------- Octokit/Clients/ISearchClient.cs | 2 +- Octokit/Clients/SearchClient.cs | 4 +- Octokit/Models/Response/SearchCodeResult.cs | 23 +++++++++++ Octokit/Octokit-Mono.csproj | 1 + Octokit/Octokit-MonoAndroid.csproj | 1 + Octokit/Octokit-Monotouch.csproj | 1 + Octokit/Octokit-netcore45.csproj | 1 + Octokit/Octokit.csproj | 1 + 12 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 Octokit/Models/Response/SearchCodeResult.cs diff --git a/Octokit.Reactive/Clients/IObservableSearchClient.cs b/Octokit.Reactive/Clients/IObservableSearchClient.cs index 37a75825..5e8ef92e 100644 --- a/Octokit.Reactive/Clients/IObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/IObservableSearchClient.cs @@ -37,6 +37,6 @@ namespace Octokit.Reactive /// /// /// List of files - IObservable SearchCode(SearchCodeRequest search); + IObservable SearchCode(SearchCodeRequest search); } } \ No newline at end of file diff --git a/Octokit.Reactive/Clients/ObservableSearchClient.cs b/Octokit.Reactive/Clients/ObservableSearchClient.cs index 220cc48e..029afaa7 100644 --- a/Octokit.Reactive/Clients/ObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/ObservableSearchClient.cs @@ -63,10 +63,10 @@ namespace Octokit.Reactive /// /// /// List of files - public IObservable SearchCode(SearchCodeRequest search) + public IObservable SearchCode(SearchCodeRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchCode(), search.Parameters); + return _client.Search.SearchCode(search).ToObservable(); } } } \ No newline at end of file diff --git a/Octokit.Tests.Integration/Clients/SearchClientTests.cs b/Octokit.Tests.Integration/Clients/SearchClientTests.cs index da5204e7..55559cb0 100644 --- a/Octokit.Tests.Integration/Clients/SearchClientTests.cs +++ b/Octokit.Tests.Integration/Clients/SearchClientTests.cs @@ -32,4 +32,14 @@ public class SearchClientTests Assert.NotEmpty(repos.Items); } + + [Fact] + public async Task SearchForFunctionInCode() + { + var request = new SearchCodeRequest("addClass"); + request.Repo = "jquery/jquery"; + var repos = await _gitHubClient.Search.SearchCode(request); + + Assert.NotEmpty(repos.Items); + } } diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 2aac476c..0ffa0e85 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -1029,7 +1029,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchCode(new SearchCodeRequest("something")); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Any>()); } @@ -1050,7 +1050,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something")); } @@ -1065,7 +1065,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["sort"] == "indexed")); } @@ -1081,7 +1081,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["sort"] == "indexed" && @@ -1097,7 +1097,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["order"] == "desc")); } @@ -1113,7 +1113,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+in:file")); } @@ -1128,7 +1128,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+in:file,path")); } @@ -1143,7 +1143,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+language:C#")); } @@ -1158,7 +1158,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+fork:true")); } @@ -1173,7 +1173,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:>10")); } @@ -1188,7 +1188,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:>=10")); } @@ -1203,7 +1203,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:<10")); } @@ -1218,7 +1218,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:<=10")); } @@ -1233,7 +1233,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+size:10..100")); } @@ -1248,7 +1248,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+path:app/public")); } @@ -1263,7 +1263,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+extension:cs")); } @@ -1278,7 +1278,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+user:alfhenrik")); } @@ -1293,7 +1293,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+repo:octokit.net")); } @@ -1310,7 +1310,7 @@ namespace Octokit.Tests.Clients client.SearchCode(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/code"), Arg.Is>(d => d["q"] == "something+path:tools/FAKE.core+extension:fs+repo:octokit.net")); diff --git a/Octokit/Clients/ISearchClient.cs b/Octokit/Clients/ISearchClient.cs index 8119aa37..d6729ad5 100644 --- a/Octokit/Clients/ISearchClient.cs +++ b/Octokit/Clients/ISearchClient.cs @@ -39,6 +39,6 @@ namespace Octokit /// /// /// List of files - Task> SearchCode(SearchCodeRequest search); + Task SearchCode(SearchCodeRequest search); } } \ No newline at end of file diff --git a/Octokit/Clients/SearchClient.cs b/Octokit/Clients/SearchClient.cs index 9cfb6041..269fc44c 100644 --- a/Octokit/Clients/SearchClient.cs +++ b/Octokit/Clients/SearchClient.cs @@ -61,10 +61,10 @@ namespace Octokit /// /// /// List of files - public Task> SearchCode(SearchCodeRequest search) + public Task SearchCode(SearchCodeRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchCode(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchCode(), search.Parameters); } } } \ No newline at end of file diff --git a/Octokit/Models/Response/SearchCodeResult.cs b/Octokit/Models/Response/SearchCodeResult.cs new file mode 100644 index 00000000..3ca65183 --- /dev/null +++ b/Octokit/Models/Response/SearchCodeResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchCodeResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IReadOnlyList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index bb7803d3..3283b1a4 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -308,6 +308,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 19b956e7..71f33175 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -319,6 +319,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 24c46fcf..c92023a3 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -314,6 +314,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index f7b3c62e..8d9e466f 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -306,6 +306,7 @@ + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index a284967b..1c058fdd 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -140,6 +140,7 @@ + From 7da2cd04ac3dd86d39038deba4f2482710b56ad8 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Wed, 5 Mar 2014 22:58:52 +1100 Subject: [PATCH 20/46] updated SearchIssues to match correct response shape --- .../Clients/IObservableSearchClient.cs | 2 +- .../Clients/ObservableSearchClient.cs | 18 ++--- .../Clients/SearchClientTests.cs | 12 ++++ Octokit.Tests/Clients/SearchClientTests.cs | 70 +++++++++---------- Octokit/Clients/ISearchClient.cs | 8 +-- Octokit/Clients/SearchClient.cs | 10 ++- Octokit/Models/Response/SearchIssuesResult.cs | 23 ++++++ Octokit/Octokit-Mono.csproj | 1 + Octokit/Octokit-MonoAndroid.csproj | 1 + Octokit/Octokit-Monotouch.csproj | 1 + Octokit/Octokit-netcore45.csproj | 1 + Octokit/Octokit.csproj | 1 + 12 files changed, 90 insertions(+), 58 deletions(-) create mode 100644 Octokit/Models/Response/SearchIssuesResult.cs diff --git a/Octokit.Reactive/Clients/IObservableSearchClient.cs b/Octokit.Reactive/Clients/IObservableSearchClient.cs index 5e8ef92e..d3eb6135 100644 --- a/Octokit.Reactive/Clients/IObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/IObservableSearchClient.cs @@ -29,7 +29,7 @@ namespace Octokit.Reactive /// /// /// List of issues - IObservable SearchIssues(SearchIssuesRequest search); + IObservable SearchIssues(SearchIssuesRequest search); /// /// search code diff --git a/Octokit.Reactive/Clients/ObservableSearchClient.cs b/Octokit.Reactive/Clients/ObservableSearchClient.cs index 029afaa7..1bdf0045 100644 --- a/Octokit.Reactive/Clients/ObservableSearchClient.cs +++ b/Octokit.Reactive/Clients/ObservableSearchClient.cs @@ -1,7 +1,5 @@ using System; -using System.Reactive; using System.Reactive.Threading.Tasks; -using Octokit.Reactive.Internal; namespace Octokit.Reactive { @@ -10,15 +8,13 @@ namespace Octokit.Reactive /// public class ObservableSearchClient : IObservableSearchClient { - readonly IConnection _connection; - readonly IGitHubClient _client; + readonly ISearchClient _client; public ObservableSearchClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); - _client = client; - _connection = client.Connection; + _client = client.Search; } /// @@ -30,7 +26,7 @@ namespace Octokit.Reactive public IObservable SearchRepo(SearchRepositoriesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _client.Search.SearchRepo(search).ToObservable(); + return _client.SearchRepo(search).ToObservable(); } /// @@ -42,7 +38,7 @@ namespace Octokit.Reactive public IObservable SearchUsers(SearchUsersRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _client.Search.SearchUsers(search).ToObservable(); + return _client.SearchUsers(search).ToObservable(); } /// @@ -51,10 +47,10 @@ namespace Octokit.Reactive /// /// /// List of issues - public IObservable SearchIssues(SearchIssuesRequest search) + public IObservable SearchIssues(SearchIssuesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _connection.GetAndFlattenAllPages(ApiUrls.SearchIssues(), search.Parameters); + return _client.SearchIssues(search).ToObservable(); } /// @@ -66,7 +62,7 @@ namespace Octokit.Reactive public IObservable SearchCode(SearchCodeRequest search) { Ensure.ArgumentNotNull(search, "search"); - return _client.Search.SearchCode(search).ToObservable(); + return _client.SearchCode(search).ToObservable(); } } } \ No newline at end of file diff --git a/Octokit.Tests.Integration/Clients/SearchClientTests.cs b/Octokit.Tests.Integration/Clients/SearchClientTests.cs index 55559cb0..8a4363b5 100644 --- a/Octokit.Tests.Integration/Clients/SearchClientTests.cs +++ b/Octokit.Tests.Integration/Clients/SearchClientTests.cs @@ -42,4 +42,16 @@ public class SearchClientTests Assert.NotEmpty(repos.Items); } + + [Fact] + public async Task SearchForWordInCode() + { + var request = new SearchIssuesRequest("windows"); + request.SortField = IssueSearchSort.Created; + request.Order = SortDirection.Descending; + + var repos = await _gitHubClient.Search.SearchIssues(request); + + Assert.NotEmpty(repos.Items); + } } diff --git a/Octokit.Tests/Clients/SearchClientTests.cs b/Octokit.Tests/Clients/SearchClientTests.cs index 0ffa0e85..114ca5c7 100644 --- a/Octokit.Tests/Clients/SearchClientTests.cs +++ b/Octokit.Tests/Clients/SearchClientTests.cs @@ -494,7 +494,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); var client = new SearchClient(connection); client.SearchIssues(new SearchIssuesRequest("something")); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "search/issues"), Arg.Any>()); + connection.Received().Get(Arg.Is(u => u.ToString() == "search/issues"), Arg.Any>()); } [Fact] @@ -513,7 +513,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "pub")); } @@ -528,7 +528,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["sort"] == "comments")); @@ -545,7 +545,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["sort"] == "updated" && @@ -561,7 +561,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["order"] == "desc")); @@ -577,7 +577,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+in:comment")); } @@ -592,7 +592,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+in:body,title")); } @@ -607,7 +607,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+type:issue")); } @@ -622,7 +622,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+type:pr")); } @@ -637,7 +637,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+author:alfhenrik")); } @@ -652,7 +652,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+assignee:alfhenrik")); } @@ -667,7 +667,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+mentions:alfhenrik")); } @@ -682,7 +682,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+commenter:alfhenrik")); } @@ -697,7 +697,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+involves:alfhenrik")); } @@ -712,7 +712,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+state:Open")); } @@ -727,7 +727,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+state:Closed")); } @@ -742,7 +742,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+label:bug")); } @@ -757,7 +757,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+label:bug+label:feature")); } @@ -772,7 +772,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+language:CSharp")); } @@ -787,7 +787,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:>2014-01-01")); } @@ -802,7 +802,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:>=2014-01-01")); } @@ -817,7 +817,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:<2014-01-01")); } @@ -832,7 +832,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+created:<=2014-01-01")); } @@ -847,7 +847,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:>2014-01-01")); } @@ -862,7 +862,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:>=2014-01-01")); } @@ -877,7 +877,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:<2014-01-01")); } @@ -892,7 +892,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+updated:<=2014-01-01")); } @@ -907,7 +907,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:>10")); } @@ -922,7 +922,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:>=10")); } @@ -937,7 +937,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:<10")); } @@ -952,7 +952,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:<=10")); } @@ -967,7 +967,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+comments:10..20")); } @@ -982,7 +982,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+user:alfhenrik")); } @@ -997,7 +997,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+repo:octokit.net")); } @@ -1014,7 +1014,7 @@ namespace Octokit.Tests.Clients client.SearchIssues(request); - connection.Received().GetAll( + connection.Received().Get( Arg.Is(u => u.ToString() == "search/issues"), Arg.Is>(d => d["q"] == "something+label:bug+user:alfhenrik+repo:octokit.net")); diff --git a/Octokit/Clients/ISearchClient.cs b/Octokit/Clients/ISearchClient.cs index d6729ad5..2754e1b6 100644 --- a/Octokit/Clients/ISearchClient.cs +++ b/Octokit/Clients/ISearchClient.cs @@ -1,7 +1,5 @@ -#if NET_45 -using System.Collections.Generic; -#endif -using System.Threading.Tasks; +using System.Threading.Tasks; + namespace Octokit { /// @@ -31,7 +29,7 @@ namespace Octokit /// /// /// List of issues - Task> SearchIssues(SearchIssuesRequest search); + Task SearchIssues(SearchIssuesRequest search); /// /// search code diff --git a/Octokit/Clients/SearchClient.cs b/Octokit/Clients/SearchClient.cs index 269fc44c..343eab56 100644 --- a/Octokit/Clients/SearchClient.cs +++ b/Octokit/Clients/SearchClient.cs @@ -1,7 +1,5 @@ -#if NET_45 -using System.Collections.Generic; -#endif -using System.Threading.Tasks; +using System.Threading.Tasks; + namespace Octokit { /// @@ -49,10 +47,10 @@ namespace Octokit /// /// /// List of issues - public Task> SearchIssues(SearchIssuesRequest search) + public Task SearchIssues(SearchIssuesRequest search) { Ensure.ArgumentNotNull(search, "search"); - return ApiConnection.GetAll(ApiUrls.SearchIssues(), search.Parameters); + return ApiConnection.Get(ApiUrls.SearchIssues(), search.Parameters); } /// diff --git a/Octokit/Models/Response/SearchIssuesResult.cs b/Octokit/Models/Response/SearchIssuesResult.cs new file mode 100644 index 00000000..651f5404 --- /dev/null +++ b/Octokit/Models/Response/SearchIssuesResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class SearchIssuesResult + { + public int TotalCount { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IReadOnlyList Items { get; set; } + + internal string DebuggerDisplay + { + get + { + return String.Format(CultureInfo.InvariantCulture, "TotalCount: {0}", TotalCount); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 3283b1a4..9fbca9f5 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -309,6 +309,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 71f33175..cb66cd52 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -320,6 +320,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index c92023a3..5a1d9522 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -315,6 +315,7 @@ + \ No newline at end of file diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 8d9e466f..aba7eb5d 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -307,6 +307,7 @@ + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 1c058fdd..51c1de2d 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -141,6 +141,7 @@ + From e8326f610f655f5df0be6564f442cb3bca81f67a Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 09:54:14 +1100 Subject: [PATCH 21/46] payload can be any JSON object, relaxed deserialized POCO --- Octokit/Models/Response/Deployment.cs | 2 +- Octokit/Models/Response/DeploymentStatus.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Octokit/Models/Response/Deployment.cs b/Octokit/Models/Response/Deployment.cs index dee40fbe..541a4862 100644 --- a/Octokit/Models/Response/Deployment.cs +++ b/Octokit/Models/Response/Deployment.cs @@ -33,7 +33,7 @@ namespace Octokit /// /// JSON payload with extra information about the deployment. /// - public string Payload { get; set; } + public object Payload { get; set; } /// /// Date and time that the deployment was created. diff --git a/Octokit/Models/Response/DeploymentStatus.cs b/Octokit/Models/Response/DeploymentStatus.cs index c5578cf5..133c92fc 100644 --- a/Octokit/Models/Response/DeploymentStatus.cs +++ b/Octokit/Models/Response/DeploymentStatus.cs @@ -30,7 +30,7 @@ namespace Octokit /// /// JSON payload with extra information about the deployment. /// - public string Payload { get; set; } + public object Payload { get; set; } /// /// The target URL of this deployment status. This URL should contain From 8d1bda2172614b30fa5aeb8741546bc61a8d87c3 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 10:30:25 +1100 Subject: [PATCH 22/46] updated deployment payload to support custom JSON --- Octokit.Tests/Models/DeploymentStatusTests.cs | 18 ++++++++++++++---- Octokit.Tests/Models/DeploymentTests.cs | 18 ++++++++++++++---- Octokit/Models/Response/Deployment.cs | 4 +++- Octokit/Models/Response/DeploymentStatus.cs | 10 +++++++++- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/Octokit.Tests/Models/DeploymentStatusTests.cs b/Octokit.Tests/Models/DeploymentStatusTests.cs index 5a8b295d..c904d6b8 100644 --- a/Octokit.Tests/Models/DeploymentStatusTests.cs +++ b/Octokit.Tests/Models/DeploymentStatusTests.cs @@ -1,4 +1,5 @@ -using Octokit.Internal; +using System.Linq; +using Octokit.Internal; using System; using System.Collections.Generic; using Xunit; @@ -15,7 +16,7 @@ namespace Octokit.Tests.Models Id = 1, Url = "https://api.github.com/repos/octocat/example/deployments/1/statuses/42", State = DeploymentState.Success, - Payload = "{\"environment\":\"production\"}", + Payload = new Dictionary { { "environment", "production" } }, TargetUrl = "https://gist.github.com/628b2736d379f", CreatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), UpdatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), @@ -46,7 +47,7 @@ namespace Octokit.Tests.Models ""type"": ""User"", ""site_admin"": false }, - ""payload"": ""{\""environment\"":\""production\""}"", + ""payload"": { ""environment"":""production""}, ""target_url"": ""https://gist.github.com/628b2736d379f"", ""created_at"": ""2012-07-20T01:19:13Z"", ""updated_at"": ""2012-07-20T01:19:13Z"", @@ -68,10 +69,19 @@ namespace Octokit.Tests.Models if (x == null || y == null) return false; + if (x.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + + if (y.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + return x.Id == y.Id && x.Url == y.Url && x.State == y.State && - x.Payload == y.Payload && x.TargetUrl == y.TargetUrl && x.CreatedAt == y.CreatedAt && x.UpdatedAt == y.UpdatedAt && diff --git a/Octokit.Tests/Models/DeploymentTests.cs b/Octokit.Tests/Models/DeploymentTests.cs index c408c759..824b3c4e 100644 --- a/Octokit.Tests/Models/DeploymentTests.cs +++ b/Octokit.Tests/Models/DeploymentTests.cs @@ -1,4 +1,5 @@ -using Octokit.Internal; +using System.Linq; +using Octokit.Internal; using System; using System.Collections.Generic; using Xunit; @@ -14,7 +15,7 @@ namespace Octokit.Tests.Models Id = 1, Sha = "topic-branch", Url = "https://api.github.com/repos/octocat/example/deployments/1", - Payload = "{\"environment\":\"production\"}", + Payload = new Dictionary{{ "environment", "production"}}, CreatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), UpdatedAt = DateTimeOffset.Parse("2012-07-20T01:19:13Z"), Description = "Deploy request from hubot", @@ -45,7 +46,7 @@ namespace Octokit.Tests.Models ""type"": ""User"", ""site_admin"": false }, - ""payload"": ""{\""environment\"":\""production\""}"", + ""payload"": { ""environment"":""production""}, ""created_at"": ""2012-07-20T01:19:13Z"", ""updated_at"": ""2012-07-20T01:19:13Z"", ""description"": ""Deploy request from hubot"", @@ -71,10 +72,19 @@ namespace Octokit.Tests.Models if (x == null || y == null) return false; + if (x.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + + if (y.Payload.Keys.Any(key => x.Payload[key] != y.Payload[key])) + { + return false; + } + return x.Id == y.Id && x.Sha == y .Sha && x.Url == y.Url && - x.Payload == y.Payload && x.CreatedAt == y.CreatedAt && x.UpdatedAt == y.UpdatedAt && x.Description == y.Description && diff --git a/Octokit/Models/Response/Deployment.cs b/Octokit/Models/Response/Deployment.cs index 541a4862..fd99b3b4 100644 --- a/Octokit/Models/Response/Deployment.cs +++ b/Octokit/Models/Response/Deployment.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -33,7 +34,8 @@ namespace Octokit /// /// JSON payload with extra information about the deployment. /// - public object Payload { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IDictionary Payload { get; set; } /// /// Date and time that the deployment was created. diff --git a/Octokit/Models/Response/DeploymentStatus.cs b/Octokit/Models/Response/DeploymentStatus.cs index 133c92fc..f361074c 100644 --- a/Octokit/Models/Response/DeploymentStatus.cs +++ b/Octokit/Models/Response/DeploymentStatus.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -7,6 +9,11 @@ namespace Octokit [DebuggerDisplay("{DebuggerDisplay,nq}")] public class DeploymentStatus { + public DeploymentStatus() + { + Payload = new Dictionary(); + } + /// /// Id of this deployment status. /// @@ -30,7 +37,8 @@ namespace Octokit /// /// JSON payload with extra information about the deployment. /// - public object Payload { get; set; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IDictionary Payload { get; set; } /// /// The target URL of this deployment status. This URL should contain From 66e5673e94b0486c0cd1ec9251f509fb489fb6b3 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 10:50:02 +1100 Subject: [PATCH 23/46] added release notes --- ReleaseNotes.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 44aaa3ef..e7856422 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,17 @@ +### New in 0.2.2 (Released 2014/03/06) +* Added convention tests to ensure Task-based and Observable-based APIs are consistent - #361 #376 #378 via @shiftkey and @ammeep +* "_links" JSON field serialization convention fix - #387 via @haacked +* Added Feeds client - #386 via @sgwill +* Added support for creating Gists - #391 via @Therzok and @rgmills +* Tidying up async/await tests - #392 via @pmacn +* Updating projects to use Docplagiarizer - #396 via @pmacn +* Make readonly collections truly readonly - #394 #399 via @Haacked +* Set doc plagiarizer as a dev dependency - #398 via @Haacked +* Internalize ProductHeaderValue - #406 via @trsneed +* HttpClient.Send without cancellation token - #410 via @ammeep +* Implement Repository Comments API - #413 via @Haacked @wfroese +* Corrected Search response to match API - #412 #417 #419 #420 via @shiftkey + ### New in 0.2.1 (Released 2014/02/19) * Reverted the dependency on Reactive Extensions 2.2.2 which introduced breaking changes From d6437f7bdda07597bb77e5ce985297256db3e7f4 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 10:51:16 +1100 Subject: [PATCH 24/46] version bump --- SolutionInfo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SolutionInfo.cs b/SolutionInfo.cs index ccd2aa84..da6155a7 100644 --- a/SolutionInfo.cs +++ b/SolutionInfo.cs @@ -3,11 +3,11 @@ using System.Reflection; using System.Runtime.InteropServices; [assembly: AssemblyProductAttribute("Octokit")] -[assembly: AssemblyVersionAttribute("0.2.1")] -[assembly: AssemblyFileVersionAttribute("0.2.1")] +[assembly: AssemblyVersionAttribute("0.2.2")] +[assembly: AssemblyFileVersionAttribute("0.2.2")] [assembly: ComVisibleAttribute(false)] namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "0.2.1"; + internal const string Version = "0.2.2"; } } From bf2797afe086d506753479340d3e97044fbf6a33 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 10:57:17 +1100 Subject: [PATCH 25/46] muting this test because it appears to be flaky --- Octokit.Tests.Integration/Clients/GistsClientTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit.Tests.Integration/Clients/GistsClientTests.cs b/Octokit.Tests.Integration/Clients/GistsClientTests.cs index 53c96392..ab04d5fc 100644 --- a/Octokit.Tests.Integration/Clients/GistsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/GistsClientTests.cs @@ -62,7 +62,7 @@ public class GistsClientTests Assert.DoesNotThrow(async () => { await _fixture.Delete(createdGist.Id); }); } - [IntegrationTest] + [IntegrationTest(Skip="Why do you hate freedom?")] public async Task CanStarAndUnstarAGist() { Assert.DoesNotThrow(async () => { await _fixture.Star(testGistId); }); From 5b9e4c1149514329194114b36e660ebc78baf5e7 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 11:16:17 +1100 Subject: [PATCH 26/46] this field is case-sensitive --- Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs index cceb0cca..e80ca018 100644 --- a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs @@ -245,7 +245,7 @@ public class RepositoriesClientTests { Name = repoName, AutoInit = true, - GitignoreTemplate = "visualstudio" + GitignoreTemplate = "VisualStudio" }); try From 8e9ba4e1010b8c76522ef81efc2a677cda919789 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 11:20:46 +1100 Subject: [PATCH 27/46] moving this out to a proper issue --- Octokit.Tests.Integration/Clients/GistsClientTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Octokit.Tests.Integration/Clients/GistsClientTests.cs b/Octokit.Tests.Integration/Clients/GistsClientTests.cs index ab04d5fc..3df84b68 100644 --- a/Octokit.Tests.Integration/Clients/GistsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/GistsClientTests.cs @@ -62,7 +62,7 @@ public class GistsClientTests Assert.DoesNotThrow(async () => { await _fixture.Delete(createdGist.Id); }); } - [IntegrationTest(Skip="Why do you hate freedom?")] + [IntegrationTest(Skip = "See https://github.com/octokit/octokit.net/issues/424 for an explanation of the issue")] public async Task CanStarAndUnstarAGist() { Assert.DoesNotThrow(async () => { await _fixture.Star(testGistId); }); From 3c2dd0b213484d0747e2cbc8f0ee6e8edbed7ef5 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 6 Mar 2014 11:26:31 +1100 Subject: [PATCH 28/46] removed items which were internal changes --- ReleaseNotes.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index e7856422..b5ff3913 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,12 +1,9 @@ ### New in 0.2.2 (Released 2014/03/06) -* Added convention tests to ensure Task-based and Observable-based APIs are consistent - #361 #376 #378 via @shiftkey and @ammeep +* Task-based and Observable-based APIs are now consistent - #361 #376 #378 via @shiftkey and @ammeep * "_links" JSON field serialization convention fix - #387 via @haacked * Added Feeds client - #386 via @sgwill * Added support for creating Gists - #391 via @Therzok and @rgmills -* Tidying up async/await tests - #392 via @pmacn -* Updating projects to use Docplagiarizer - #396 via @pmacn * Make readonly collections truly readonly - #394 #399 via @Haacked -* Set doc plagiarizer as a dev dependency - #398 via @Haacked * Internalize ProductHeaderValue - #406 via @trsneed * HttpClient.Send without cancellation token - #410 via @ammeep * Implement Repository Comments API - #413 via @Haacked @wfroese From 945672e8cfdc51648a1c14895304cdedcd8674f7 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sat, 8 Mar 2014 09:45:14 +0930 Subject: [PATCH 29/46] set code analysis culture to en-US to prevent violations on en-(other) machines --- Octokit/Octokit-netcore45.csproj | 1 + Octokit/Octokit.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index aba7eb5d..7130e509 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -13,6 +13,7 @@ Octokit v4.5 512 + en-US true diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 51c1de2d..4cffe396 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -12,6 +12,7 @@ v4.5 512 + en-US true From f286d9d3c3ec9538119f9b15bd2252fbf9e7423f Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 11:25:51 +1100 Subject: [PATCH 30/46] add support for filtering issues based on assigned name --- .../Clients/IssuesClientTests.cs | 27 +++++++++++++++++++ .../Models/Request/RepositoryIssueRequest.cs | 8 ++++++ 2 files changed, 35 insertions(+) diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs index 2a224262..e24ea89a 100644 --- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs @@ -159,6 +159,33 @@ public class IssuesClientTests : IDisposable Assert.True(retrieved.Any(i => i.Number == issue2.Number)); } + [IntegrationTest] + public async Task CanFilterByAssigned() + { + var owner = _repository.Owner.Login; + var newIssue1 = new NewIssue("An assigned issue") { Body = "Assigning this to myself", Assignee = owner }; + var newIssue2 = new NewIssue("An unassigned issue") { Body = "A new unassigned issue" }; + await _issuesClient.Create(owner, _repository.Name, newIssue1); + await _issuesClient.Create(owner, _repository.Name, newIssue2); + + var allIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest()); + + Assert.Equal(2, allIssues.Count); + + var assignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Assignee = owner }); + + Assert.Equal(1, assignedIssues.Count); + Assert.Equal("An assigned issue", assignedIssues[0].Title); + + var unassignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Assignee = "none" }); + + Assert.Equal(1, unassignedIssues.Count); + Assert.Equal("An unassigned issue", unassignedIssues[0].Title); + } + public void Dispose() { Helper.DeleteRepo(_repository); diff --git a/Octokit/Models/Request/RepositoryIssueRequest.cs b/Octokit/Models/Request/RepositoryIssueRequest.cs index 9ee3cda2..e6a50cfd 100644 --- a/Octokit/Models/Request/RepositoryIssueRequest.cs +++ b/Octokit/Models/Request/RepositoryIssueRequest.cs @@ -10,5 +10,13 @@ namespace Octokit /// Use the milestone number for a specific milestone. Use the value "none" for issues with any milestones. /// public string Milestone { get; set; } + + /// + /// Filter on the user assigned for the request + /// + /// + /// Specify "none" for issues with no assigned user + /// + public string Assignee { get; set; } } } From 33c39545997454d83942abe3182ca3f91b7699e1 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 11:58:19 +1100 Subject: [PATCH 31/46] added support for filtering by creator --- .../Clients/IssuesClientTests.cs | 27 +++++++++++++++++++ .../Models/Request/RepositoryIssueRequest.cs | 8 ++++++ 2 files changed, 35 insertions(+) diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs index e24ea89a..8e2bf9c4 100644 --- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs @@ -186,6 +186,33 @@ public class IssuesClientTests : IDisposable Assert.Equal("An unassigned issue", unassignedIssues[0].Title); } + [IntegrationTest] + public async Task CanFilterByCreator() + { + var owner = _repository.Owner.Login; + var newIssue1 = new NewIssue("An issue") { Body = "words words words" }; + var newIssue2 = new NewIssue("Another issue") { Body = "some other words" }; + await _issuesClient.Create(owner, _repository.Name, newIssue1); + await _issuesClient.Create(owner, _repository.Name, newIssue2); + + var allIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest()); + + Assert.Equal(2, allIssues.Count); + + var assignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Creator = owner }); + + Assert.Equal(2, assignedIssues.Count); + + var unassignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Creator = "shiftkey" }); + + Assert.Equal(0, unassignedIssues.Count); + } + + + public void Dispose() { Helper.DeleteRepo(_repository); diff --git a/Octokit/Models/Request/RepositoryIssueRequest.cs b/Octokit/Models/Request/RepositoryIssueRequest.cs index e6a50cfd..e1008e02 100644 --- a/Octokit/Models/Request/RepositoryIssueRequest.cs +++ b/Octokit/Models/Request/RepositoryIssueRequest.cs @@ -18,5 +18,13 @@ namespace Octokit /// Specify "none" for issues with no assigned user /// public string Assignee { get; set; } + + /// + /// The user that created the issue + /// + /// + /// Specify "none" for issues with no assigned user + /// + public string Creator { get; set; } } } From 5a468c35c9a0aae35c93c47c6b6ead27eb838f85 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 11:58:32 +1100 Subject: [PATCH 32/46] added test for API throwing errors --- .../Clients/IssuesClientTests.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs index 8e2bf9c4..d274d4bb 100644 --- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Octokit; +using Octokit.Tests.Helpers; using Octokit.Tests.Integration; using Xunit; @@ -211,7 +212,19 @@ public class IssuesClientTests : IDisposable Assert.Equal(0, unassignedIssues.Count); } + [IntegrationTest] + public async Task FilteringByInvalidAccountThrowsError() + { + var owner = _repository.Owner.Login; + AssertEx.Throws( + () => _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Creator = "some-random-account" })); + + AssertEx.Throws( + () => _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Assignee = "some-random-account" })); + } public void Dispose() { From fdbe330cee56086f41e433a4a1600cbd5ddcae25 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 12:13:34 +1100 Subject: [PATCH 33/46] :lipstick: test variable names --- Octokit.Tests.Integration/Clients/IssuesClientTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs index d274d4bb..ad02ff1b 100644 --- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs @@ -201,15 +201,15 @@ public class IssuesClientTests : IDisposable Assert.Equal(2, allIssues.Count); - var assignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + var issuesCreatedByOwner = await _issuesClient.GetForRepository(owner, _repository.Name, new RepositoryIssueRequest { Creator = owner }); - Assert.Equal(2, assignedIssues.Count); + Assert.Equal(2, issuesCreatedByOwner.Count); - var unassignedIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + var issuesCreatedByExternalUser = await _issuesClient.GetForRepository(owner, _repository.Name, new RepositoryIssueRequest { Creator = "shiftkey" }); - Assert.Equal(0, unassignedIssues.Count); + Assert.Equal(0, issuesCreatedByExternalUser.Count); } [IntegrationTest] From b8cc3d65a90da47e70393eb936dec9bd4db307da Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 12:14:20 +1100 Subject: [PATCH 34/46] added support for searching by mentions --- .../Clients/IssuesClientTests.cs | 25 +++++++++++++++++++ .../Models/Request/RepositoryIssueRequest.cs | 5 ++++ 2 files changed, 30 insertions(+) diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs index ad02ff1b..41e2016d 100644 --- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs @@ -212,6 +212,31 @@ public class IssuesClientTests : IDisposable Assert.Equal(0, issuesCreatedByExternalUser.Count); } + [IntegrationTest] + public async Task CanFilterByMentioned() + { + var owner = _repository.Owner.Login; + var newIssue1 = new NewIssue("An issue") { Body = "words words words hello there @shiftkey" }; + var newIssue2 = new NewIssue("Another issue") { Body = "some other words" }; + await _issuesClient.Create(owner, _repository.Name, newIssue1); + await _issuesClient.Create(owner, _repository.Name, newIssue2); + + var allIssues = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest()); + + Assert.Equal(2, allIssues.Count); + + var mentionsWithShiftkey = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Mentioned = "shiftkey" }); + + Assert.Equal(1, mentionsWithShiftkey.Count); + + var mentionsWithHaacked = await _issuesClient.GetForRepository(owner, _repository.Name, + new RepositoryIssueRequest { Mentioned = "haacked" }); + + Assert.Equal(0, mentionsWithHaacked.Count); + } + [IntegrationTest] public async Task FilteringByInvalidAccountThrowsError() { diff --git a/Octokit/Models/Request/RepositoryIssueRequest.cs b/Octokit/Models/Request/RepositoryIssueRequest.cs index e1008e02..f125afd4 100644 --- a/Octokit/Models/Request/RepositoryIssueRequest.cs +++ b/Octokit/Models/Request/RepositoryIssueRequest.cs @@ -26,5 +26,10 @@ namespace Octokit /// Specify "none" for issues with no assigned user /// public string Creator { get; set; } + + /// + /// A user that’s mentioned in the issue + /// + public string Mentioned { get; set; } } } From 7bfd4bdbefcf0ea1c3ef757b333f9f855ef3f864 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 16:14:19 +1100 Subject: [PATCH 35/46] fixing some janky xml-docs --- Octokit/Helpers/ApiUrls.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index d334c34f..832de1c4 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -1009,7 +1009,7 @@ namespace Octokit /// Returns the for repository contributors. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryContributors(string owner, string name) { @@ -1020,7 +1020,7 @@ namespace Octokit /// Returns the for repository languages. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryLanguages(string owner, string name) { @@ -1031,7 +1031,7 @@ namespace Octokit /// Returns the for repository teams. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryTeams(string owner, string name) { @@ -1042,7 +1042,7 @@ namespace Octokit /// Returns the for repository tags. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri RepositoryTags(string owner, string name) { @@ -1065,13 +1065,14 @@ namespace Octokit /// Returns the for a repository. /// /// The owner of the repository - /// The name of the repository + /// The name of the repository /// public static Uri Repository(string owner, string name) { return "repos/{0}/{1}".FormatUri(owner, name); } + /// /// Returns the for the Deployments API for the given repository. /// /// Owner of the repository From 7dc70a2192d85494b3ec6435e9726d8882710599 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 16:33:46 +1100 Subject: [PATCH 36/46] :lipstick: using statements, incorrect docs, deprecated Octokit.Response namespace --- Octokit.Reactive/Clients/IObservableStatisticsClient.cs | 1 - Octokit.Reactive/Clients/ObservableStatisticsClient.cs | 1 - Octokit.Tests/Models/PunchCardTests.cs | 3 +-- Octokit.sln.DotSettings | 2 +- Octokit/Clients/ApiPagination.cs | 2 +- Octokit/Clients/AuthorizationsClient.cs | 3 +-- Octokit/Clients/DeploymentStatusClient.cs | 3 +-- Octokit/Clients/DeploymentsClient.cs | 2 +- Octokit/Clients/FeedsClient.cs | 4 +--- Octokit/Clients/FollowersClient.cs | 5 +---- Octokit/Clients/IDeploymentsClient.cs | 2 +- Octokit/Clients/IFeedsClient.cs | 3 +-- Octokit/Clients/IGistsClient.cs | 2 +- Octokit/Clients/IMiscellaneousClient.cs | 3 +-- Octokit/Clients/IRepoCollaboratorsClient.cs | 1 - Octokit/Clients/IStatisticsClient.cs | 1 - Octokit/Clients/ITeamsClient.cs | 1 - Octokit/Clients/IUsersClient.cs | 3 +-- Octokit/Clients/IssueCommentsClient.cs | 3 +-- Octokit/Clients/IssuesEventsClient.cs | 3 +-- Octokit/Clients/IssuesLabelsClient.cs | 1 - Octokit/Clients/NotificationsClient.cs | 3 +-- Octokit/Clients/OrganizationsClient.cs | 3 +-- Octokit/Clients/RepoCollaboratorsClient.cs | 1 - Octokit/Clients/SshKeysClient.cs | 3 +-- Octokit/Clients/StarredClient.cs | 3 +-- Octokit/Clients/StatisticsClient.cs | 1 - Octokit/Clients/TeamsClient.cs | 1 - Octokit/Clients/UsersClient.cs | 4 ---- Octokit/Clients/WatchedClient.cs | 3 +-- Octokit/Models/Response/PunchCard.cs | 2 +- Octokit/Models/Response/PunchCardPoint.cs | 2 +- 32 files changed, 22 insertions(+), 53 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservableStatisticsClient.cs b/Octokit.Reactive/Clients/IObservableStatisticsClient.cs index 551189a2..5bb9a8bc 100644 --- a/Octokit.Reactive/Clients/IObservableStatisticsClient.cs +++ b/Octokit.Reactive/Clients/IObservableStatisticsClient.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Octokit.Response; namespace Octokit.Reactive { diff --git a/Octokit.Reactive/Clients/ObservableStatisticsClient.cs b/Octokit.Reactive/Clients/ObservableStatisticsClient.cs index 9905de1f..74acaa64 100644 --- a/Octokit.Reactive/Clients/ObservableStatisticsClient.cs +++ b/Octokit.Reactive/Clients/ObservableStatisticsClient.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Reactive.Threading.Tasks; -using Octokit.Response; namespace Octokit.Reactive { diff --git a/Octokit.Tests/Models/PunchCardTests.cs b/Octokit.Tests/Models/PunchCardTests.cs index b83efb34..2e6493ba 100644 --- a/Octokit.Tests/Models/PunchCardTests.cs +++ b/Octokit.Tests/Models/PunchCardTests.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using Octokit.Response; +using Octokit; using Octokit.Tests.Helpers; using Xunit; diff --git a/Octokit.sln.DotSettings b/Octokit.sln.DotSettings index 202116c9..0992e585 100644 --- a/Octokit.sln.DotSettings +++ b/Octokit.sln.DotSettings @@ -258,7 +258,7 @@ II.2.12 <HandlesEvent /> </Patterns> - <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> diff --git a/Octokit/Clients/ApiPagination.cs b/Octokit/Clients/ApiPagination.cs index 2eb51484..64d7cd03 100644 --- a/Octokit/Clients/ApiPagination.cs +++ b/Octokit/Clients/ApiPagination.cs @@ -34,7 +34,7 @@ namespace Octokit catch (NotFoundException) { throw new NotFoundException( - new ApiResponse() + new ApiResponse { StatusCode = HttpStatusCode.NotFound, Body = string.Format("{0} was not found.", uri.OriginalString) diff --git a/Octokit/Clients/AuthorizationsClient.cs b/Octokit/Clients/AuthorizationsClient.cs index a991f253..29cb8957 100644 --- a/Octokit/Clients/AuthorizationsClient.cs +++ b/Octokit/Clients/AuthorizationsClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/DeploymentStatusClient.cs b/Octokit/Clients/DeploymentStatusClient.cs index fea3812c..6c329ef9 100644 --- a/Octokit/Clients/DeploymentStatusClient.cs +++ b/Octokit/Clients/DeploymentStatusClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/DeploymentsClient.cs b/Octokit/Clients/DeploymentsClient.cs index 226f3952..bb13b62b 100644 --- a/Octokit/Clients/DeploymentsClient.cs +++ b/Octokit/Clients/DeploymentsClient.cs @@ -53,7 +53,7 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// A instance describing the new deployment to create - /// The created + /// The created public Task Create(string owner, string name, NewDeployment newDeployment) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); diff --git a/Octokit/Clients/FeedsClient.cs b/Octokit/Clients/FeedsClient.cs index 0580f5c6..b9d2531b 100644 --- a/Octokit/Clients/FeedsClient.cs +++ b/Octokit/Clients/FeedsClient.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Octokit { diff --git a/Octokit/Clients/FollowersClient.cs b/Octokit/Clients/FollowersClient.cs index 76f1851d..8c11aae0 100644 --- a/Octokit/Clients/FollowersClient.cs +++ b/Octokit/Clients/FollowersClient.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Net; -using System.Text; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IDeploymentsClient.cs b/Octokit/Clients/IDeploymentsClient.cs index df577ff4..66115d48 100644 --- a/Octokit/Clients/IDeploymentsClient.cs +++ b/Octokit/Clients/IDeploymentsClient.cs @@ -34,7 +34,7 @@ namespace Octokit /// The owner of the repository /// The name of the repository /// A instance describing the new deployment to create - /// The created + /// The created Task Create(string owner, string name, NewDeployment newDeployment); /// diff --git a/Octokit/Clients/IFeedsClient.cs b/Octokit/Clients/IFeedsClient.cs index 245c2245..7bb6ea09 100644 --- a/Octokit/Clients/IFeedsClient.cs +++ b/Octokit/Clients/IFeedsClient.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Threading.Tasks; +using System.Threading.Tasks; namespace Octokit { diff --git a/Octokit/Clients/IGistsClient.cs b/Octokit/Clients/IGistsClient.cs index 9ffdfbb5..c344c576 100644 --- a/Octokit/Clients/IGistsClient.cs +++ b/Octokit/Clients/IGistsClient.cs @@ -151,7 +151,7 @@ namespace Octokit /// http://developer.github.com/v3/gists/#unstar-a-gist /// /// The id of the gist - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unstar")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unstar")] Task Unstar(string id); /// diff --git a/Octokit/Clients/IMiscellaneousClient.cs b/Octokit/Clients/IMiscellaneousClient.cs index a8440d68..a7cb34eb 100644 --- a/Octokit/Clients/IMiscellaneousClient.cs +++ b/Octokit/Clients/IMiscellaneousClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Diagnostics.CodeAnalysis; diff --git a/Octokit/Clients/IRepoCollaboratorsClient.cs b/Octokit/Clients/IRepoCollaboratorsClient.cs index 3c379ba0..cbe73f60 100644 --- a/Octokit/Clients/IRepoCollaboratorsClient.cs +++ b/Octokit/Clients/IRepoCollaboratorsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IStatisticsClient.cs b/Octokit/Clients/IStatisticsClient.cs index 24ce787b..ce5f83e3 100644 --- a/Octokit/Clients/IStatisticsClient.cs +++ b/Octokit/Clients/IStatisticsClient.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Octokit.Response; namespace Octokit { diff --git a/Octokit/Clients/ITeamsClient.cs b/Octokit/Clients/ITeamsClient.cs index a2abafab..d944bb45 100644 --- a/Octokit/Clients/ITeamsClient.cs +++ b/Octokit/Clients/ITeamsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IUsersClient.cs b/Octokit/Clients/IUsersClient.cs index 646373c2..607e849b 100644 --- a/Octokit/Clients/IUsersClient.cs +++ b/Octokit/Clients/IUsersClient.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IssueCommentsClient.cs b/Octokit/Clients/IssueCommentsClient.cs index dc0c8846..72bdfbf9 100644 --- a/Octokit/Clients/IssueCommentsClient.cs +++ b/Octokit/Clients/IssueCommentsClient.cs @@ -1,5 +1,4 @@ - -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/IssuesEventsClient.cs b/Octokit/Clients/IssuesEventsClient.cs index 53de9af9..c476683b 100644 --- a/Octokit/Clients/IssuesEventsClient.cs +++ b/Octokit/Clients/IssuesEventsClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/IssuesLabelsClient.cs b/Octokit/Clients/IssuesLabelsClient.cs index ef80c7e2..ee640419 100644 --- a/Octokit/Clients/IssuesLabelsClient.cs +++ b/Octokit/Clients/IssuesLabelsClient.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Threading.Tasks; -using System.Linq; namespace Octokit { diff --git a/Octokit/Clients/NotificationsClient.cs b/Octokit/Clients/NotificationsClient.cs index b0bdc5ce..a1b339ea 100644 --- a/Octokit/Clients/NotificationsClient.cs +++ b/Octokit/Clients/NotificationsClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs index b04ffb04..d1949bd9 100644 --- a/Octokit/Clients/OrganizationsClient.cs +++ b/Octokit/Clients/OrganizationsClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/RepoCollaboratorsClient.cs b/Octokit/Clients/RepoCollaboratorsClient.cs index 6b508b98..9cd9304e 100644 --- a/Octokit/Clients/RepoCollaboratorsClient.cs +++ b/Octokit/Clients/RepoCollaboratorsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using System.Net; diff --git a/Octokit/Clients/SshKeysClient.cs b/Octokit/Clients/SshKeysClient.cs index 48f50feb..64bccf26 100644 --- a/Octokit/Clients/SshKeysClient.cs +++ b/Octokit/Clients/SshKeysClient.cs @@ -1,5 +1,4 @@ -using System; -#if NET_45 +#if NET_45 using System.Collections.Generic; #endif using System.Threading.Tasks; diff --git a/Octokit/Clients/StarredClient.cs b/Octokit/Clients/StarredClient.cs index 5f3b9d27..892ccfde 100644 --- a/Octokit/Clients/StarredClient.cs +++ b/Octokit/Clients/StarredClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; using System.Threading.Tasks; diff --git a/Octokit/Clients/StatisticsClient.cs b/Octokit/Clients/StatisticsClient.cs index 1b326001..848c8db9 100644 --- a/Octokit/Clients/StatisticsClient.cs +++ b/Octokit/Clients/StatisticsClient.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Octokit.Response; namespace Octokit { diff --git a/Octokit/Clients/TeamsClient.cs b/Octokit/Clients/TeamsClient.cs index 0af67320..dc347e01 100644 --- a/Octokit/Clients/TeamsClient.cs +++ b/Octokit/Clients/TeamsClient.cs @@ -1,7 +1,6 @@ #if NET_45 using System.Collections.Generic; #endif -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/UsersClient.cs b/Octokit/Clients/UsersClient.cs index 494cb84e..54e185d3 100644 --- a/Octokit/Clients/UsersClient.cs +++ b/Octokit/Clients/UsersClient.cs @@ -1,8 +1,4 @@ using System; -#if NET_45 -using System.Collections.Generic; -using System.Collections.ObjectModel; -#endif using System.Threading.Tasks; namespace Octokit diff --git a/Octokit/Clients/WatchedClient.cs b/Octokit/Clients/WatchedClient.cs index 45fcfc89..c564e9d0 100644 --- a/Octokit/Clients/WatchedClient.cs +++ b/Octokit/Clients/WatchedClient.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Net; using System.Threading.Tasks; diff --git a/Octokit/Models/Response/PunchCard.cs b/Octokit/Models/Response/PunchCard.cs index 7180478d..af280163 100644 --- a/Octokit/Models/Response/PunchCard.cs +++ b/Octokit/Models/Response/PunchCard.cs @@ -5,7 +5,7 @@ using System.Diagnostics; using System.Globalization; using System.Linq; -namespace Octokit.Response +namespace Octokit { [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PunchCard diff --git a/Octokit/Models/Response/PunchCardPoint.cs b/Octokit/Models/Response/PunchCardPoint.cs index fe3d3f56..05e832d2 100644 --- a/Octokit/Models/Response/PunchCardPoint.cs +++ b/Octokit/Models/Response/PunchCardPoint.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -namespace Octokit.Response +namespace Octokit { [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PunchCardPoint From 14de4a6edf86aae8e62e4e08eb13828ecfe68646 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 21:35:53 +1100 Subject: [PATCH 37/46] include convention tests in CI script --- script/cibuild.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/script/cibuild.ps1 b/script/cibuild.ps1 index 7c42cb11..27d82ad0 100644 --- a/script/cibuild.ps1 +++ b/script/cibuild.ps1 @@ -100,6 +100,14 @@ if ($LastExitCode -ne 0) { Dump-Error($output) } + +Write-Output "Running convention tests..." +Write-Output "" +$output = & .\tools\FAKE.Core\tools\Fake.exe "build.fsx" "target=ConventionTests" "buildMode=Release" +if ($LastExitCode -ne 0) { + Dump-Error($output) +} + Write-Output "Running integration tests..." Write-Output "" $output = & .\tools\FAKE.Core\tools\Fake.exe "build.fsx" "target=IntegrationTests" "buildMode=Release" From 87638fc41db09b6f4f05e7085c4adc72207ca9de Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 22:11:02 +1100 Subject: [PATCH 38/46] throw more detailed exceptions for type not found and interface mismatches --- .../InterfaceHasAdditionalMethodsException.cs | 25 +++++++++++++++++ .../InterfaceMissingMethodsException.cs | 25 +++++++++++++++++ .../Exception/InterfaceNotFoundException.cs | 25 +++++++++++++++++ .../Octokit.Tests.Conventions.csproj | 3 +++ .../SyncObservableClients.cs | 27 ++++++++++++------- Octokit.Tests.Conventions/TypeExtensions.cs | 2 +- 6 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs create mode 100644 Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs create mode 100644 Octokit.Tests.Conventions/Exception/InterfaceNotFoundException.cs diff --git a/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs b/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs new file mode 100644 index 00000000..4bccc557 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceHasAdditionalMethodsException : Exception + { + public InterfaceHasAdditionalMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient) + : base(CreateMessage(type, methodsMissingOnReactiveClient)) { } + + public InterfaceHasAdditionalMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient, Exception innerException) + : base(CreateMessage(type, methodsMissingOnReactiveClient), innerException) { } + + protected InterfaceHasAdditionalMethodsException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(Type type, IEnumerable methods) + { + var methodsFormatted = String.Join("\r\n", methods.Select(m => String.Format(" - {0}", m))); + return String.Format("Methods found on type {0} which should be removed:\r\n{1}", type.Name, methodsFormatted); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs b/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs new file mode 100644 index 00000000..65fc8c76 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceMissingMethodsException : Exception + { + public InterfaceMissingMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient) + : base(CreateMessage(type, methodsMissingOnReactiveClient)) { } + + public InterfaceMissingMethodsException(Type type, IEnumerable methodsMissingOnReactiveClient, Exception innerException) + : base(CreateMessage(type, methodsMissingOnReactiveClient), innerException) { } + + protected InterfaceMissingMethodsException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(Type type, IEnumerable methods) + { + var methodsFormatted = String.Join("\r\n", methods.Select(m => String.Format(" - {0}", m))); + return String.Format("Methods not found on interface {0} which are required:\r\n{1}", type.Name, methodsFormatted); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/InterfaceNotFoundException.cs b/Octokit.Tests.Conventions/Exception/InterfaceNotFoundException.cs new file mode 100644 index 00000000..3a428331 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceNotFoundException.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceNotFoundException : Exception + { + public InterfaceNotFoundException() { } + + public InterfaceNotFoundException(string type) + : base(CreateMessage(type)) { } + + public InterfaceNotFoundException(string type, Exception innerException) + : base(CreateMessage(type), innerException) { } + + protected InterfaceNotFoundException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(string type) + { + return String.Format("Could not find the interface {0}. Add this to the Octokit.Reactive project", type); + } + + } +} diff --git a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj index 7b378297..8979df85 100644 --- a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj +++ b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj @@ -50,6 +50,9 @@ + + + diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index 376750ac..c78e5a47 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -13,23 +13,30 @@ namespace Octokit.Tests.Conventions { public class SyncObservableClients { - [Fact] - private void CheckObservableClientExample() - { - CheckObservableClients(typeof(ISearchClient)); - } - [Theory] [ClassData(typeof(ClientInterfaces))] - private void CheckObservableClients(Type clientInterface) + public void CheckObservableClients(Type clientInterface) { var observableClient = clientInterface.GetObservableClientInterface(); var mainMethods = clientInterface.GetMethodsOrdered(); var observableMethods = observableClient.GetMethodsOrdered(); var mainNames = Array.ConvertAll(mainMethods, m => m.Name); var observableNames = Array.ConvertAll(observableMethods, m => m.Name); - AssertEx.Empty(observableNames.Except(mainNames), "Extra observable methods"); - AssertEx.Empty(mainNames.Except(observableNames), "Missing observable methods"); + + var methodsMissingOnReactiveClient = mainNames.Except(observableNames); + + if (methodsMissingOnReactiveClient.Any()) + { + throw new InterfaceMissingMethodsException(observableClient, methodsMissingOnReactiveClient); + } + + var additionalMethodsOnReactiveClient = observableNames.Except(mainNames); + + if (additionalMethodsOnReactiveClient.Any()) + { + throw new InterfaceHasAdditionalMethodsException(observableClient, additionalMethodsOnReactiveClient); + } + int index = 0; foreach(var mainMethod in mainMethods) { @@ -88,7 +95,7 @@ namespace Octokit.Tests.Conventions { var observableParameter = observableParameters[index]; Assert.Equal(mainParameter.Name, observableParameter.Name); - var mainType = mainParameter.ParameterType; + var mainType = mainParameter.ParameterType; var typeInfo = mainType.GetTypeInfo(); var expectedType = GetObservableExpectedType(mainType); Assert.Equal(expectedType, observableParameter.ParameterType); diff --git a/Octokit.Tests.Conventions/TypeExtensions.cs b/Octokit.Tests.Conventions/TypeExtensions.cs index ea7900a9..4028b26e 100644 --- a/Octokit.Tests.Conventions/TypeExtensions.cs +++ b/Octokit.Tests.Conventions/TypeExtensions.cs @@ -80,7 +80,7 @@ namespace Octokit.Tests.Conventions var observableInterface = observableClient.Assembly.GetType(observableClientName); if(observableInterface == null) { - throw new Exception("Cannot find observable interface "+observableClientName); + throw new InterfaceNotFoundException(observableClientName); } return observableInterface; } From 235ac7d4f3d3d2472d5830f804f1ac2e71347f6f Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 22:28:59 +1100 Subject: [PATCH 39/46] added exception for return value mismatch --- .../Exception/ReturnValueMismatchException.cs | 23 +++++++++++++++++++ .../Octokit.Tests.Conventions.csproj | 1 + .../SyncObservableClients.cs | 6 ++++- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs diff --git a/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs b/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs new file mode 100644 index 00000000..121751d7 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs @@ -0,0 +1,23 @@ +using System; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class ReturnValueMismatchException : Exception + { + public ReturnValueMismatchException(MethodInfo method, Type expected, Type actual) + : base(CreateMessage(method, expected, actual)) { } + + public ReturnValueMismatchException(MethodInfo method, Type expected, Type actual, Exception innerException) + : base(CreateMessage(method, expected, actual), innerException) { } + + protected ReturnValueMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMessage(MethodInfo method, Type expected, Type actual) + { + return String.Format("Return value for {0}.{1} must be {2} but is {3}", method.DeclaringType.Name, method.Name, expected, actual); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj index 8979df85..8caa28f7 100644 --- a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj +++ b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj @@ -53,6 +53,7 @@ + diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index c78e5a47..c78eb4cd 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -59,7 +59,11 @@ namespace Octokit.Tests.Conventions var mainReturnType = mainMethod.ReturnType; var observableReturnType = observableMethod.ReturnType; var expectedType = GetObservableExpectedType(mainReturnType); - Assert.Equal(expectedType, observableReturnType); + + if (expectedType != observableReturnType) + { + throw new ReturnValueMismatchException(observableMethod, expectedType, observableReturnType); + } } private static Type GetObservableExpectedType(Type mainType) From 0ec9953cb8370f2b1b459074f688c750989d727f Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 22:39:19 +1100 Subject: [PATCH 40/46] added better message for parameter mismatch count --- .../ParameterCountMismatchException.cs | 33 +++++++++++++++++++ .../Octokit.Tests.Conventions.csproj | 1 + .../SyncObservableClients.cs | 7 +++- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs diff --git a/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs b/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs new file mode 100644 index 00000000..331673d9 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class ParameterCountMismatchException : Exception + { + public ParameterCountMismatchException(MethodInfo method, IEnumerable expected, IEnumerable actual) + : base(CreateMessage(method, expected, actual)) { } + + public ParameterCountMismatchException(MethodInfo method, IEnumerable expected, IEnumerable actual, Exception innerException) + : base(CreateMessage(method, expected, actual), innerException) { } + + protected ParameterCountMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateMethodSignature(IEnumerable parameters) + { + return String.Join(",", parameters.Select(p => String.Format("{0} {1}", p.ParameterType.Name, p.Name))); + } + + static string CreateMessage(MethodInfo method, IEnumerable expected, IEnumerable actual) + { + var expectedMethodSignature = CreateMethodSignature(expected); + var actualMethodSignature = CreateMethodSignature(actual); + + return String.Format("Method signature for {0}.{1} must be ({2}) but is ({3})", method.DeclaringType.Name, method.Name, expectedMethodSignature, actualMethodSignature); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj index 8caa28f7..65a39e82 100644 --- a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj +++ b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj @@ -53,6 +53,7 @@ + diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index c78eb4cd..17d4a451 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -93,7 +93,12 @@ namespace Octokit.Tests.Conventions { var mainParameters = mainMethod.GetParametersOrdered(); var observableParameters = observableMethod.GetParametersOrdered(); - Assert.Equal(mainParameters.Length, observableParameters.Length); + + if (mainParameters.Length != observableParameters.Length) + { + throw new ParameterCountMismatchException(observableMethod, mainParameters, observableParameters); + } + int index = 0; foreach(var mainParameter in mainParameters) { From 029e27b03b4fad0a699ebe243140c9cdfeb293b4 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 22:43:44 +1100 Subject: [PATCH 41/46] :lipstick: tidy up --- Octokit.Tests.Conventions/SyncObservableClients.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index 17d4a451..98fa5ccf 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -7,7 +7,6 @@ using System.Reflection; using Octokit.Tests.Helpers; using Xunit; using Xunit.Extensions; -using Xunit.Sdk; namespace Octokit.Tests.Conventions { @@ -24,14 +23,12 @@ namespace Octokit.Tests.Conventions var observableNames = Array.ConvertAll(observableMethods, m => m.Name); var methodsMissingOnReactiveClient = mainNames.Except(observableNames); - if (methodsMissingOnReactiveClient.Any()) { throw new InterfaceMissingMethodsException(observableClient, methodsMissingOnReactiveClient); } var additionalMethodsOnReactiveClient = observableNames.Except(mainNames); - if (additionalMethodsOnReactiveClient.Any()) { throw new InterfaceHasAdditionalMethodsException(observableClient, additionalMethodsOnReactiveClient); @@ -105,7 +102,6 @@ namespace Octokit.Tests.Conventions var observableParameter = observableParameters[index]; Assert.Equal(mainParameter.Name, observableParameter.Name); var mainType = mainParameter.ParameterType; - var typeInfo = mainType.GetTypeInfo(); var expectedType = GetObservableExpectedType(mainType); Assert.Equal(expectedType, observableParameter.ParameterType); index++; From 71a7f0c370f82e69fe9091a64ca77778ac7738e4 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 22:55:56 +1100 Subject: [PATCH 42/46] added better message for when parameters are different --- .../Exception/ParameterMismatchException.cs | 31 +++++++++++++++++++ .../Octokit.Tests.Conventions.csproj | 1 + .../SyncObservableClients.cs | 11 ++++++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Octokit.Tests.Conventions/Exception/ParameterMismatchException.cs diff --git a/Octokit.Tests.Conventions/Exception/ParameterMismatchException.cs b/Octokit.Tests.Conventions/Exception/ParameterMismatchException.cs new file mode 100644 index 00000000..88009960 --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/ParameterMismatchException.cs @@ -0,0 +1,31 @@ +using System; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class ParameterMismatchException : Exception + { + public ParameterMismatchException(MethodInfo method, int position, ParameterInfo expected, ParameterInfo actual) + : base(CreateMessage(method, position, expected, actual)) { } + + public ParameterMismatchException(MethodInfo method, int position, ParameterInfo expected, ParameterInfo actual, Exception innerException) + : base(CreateMessage(method, position, expected, actual), innerException) { } + + protected ParameterMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string CreateParameterSignature(ParameterInfo parameter) + { + return String.Format("{0} {1}", parameter.ParameterType.Name, parameter.Name); + } + + static string CreateMessage(MethodInfo method, int position, ParameterInfo expected, ParameterInfo actual) + { + var expectedMethodSignature = CreateParameterSignature(expected); + var actualMethodSignature = CreateParameterSignature(actual); + + return String.Format("Parameter {0} for method {1}.{2} must be \"{3}\" but is \"{4}\"", position, method.DeclaringType.Name, method.Name, expectedMethodSignature, actualMethodSignature); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj index 65a39e82..f50961d5 100644 --- a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj +++ b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj @@ -54,6 +54,7 @@ + diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index 98fa5ccf..c3e75d16 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -100,10 +100,19 @@ namespace Octokit.Tests.Conventions foreach(var mainParameter in mainParameters) { var observableParameter = observableParameters[index]; - Assert.Equal(mainParameter.Name, observableParameter.Name); + if (mainParameter.Name != observableParameter.Name) + { + throw new ParameterMismatchException(observableMethod, index, mainParameter, observableParameter); + } + var mainType = mainParameter.ParameterType; var expectedType = GetObservableExpectedType(mainType); Assert.Equal(expectedType, observableParameter.ParameterType); + + if (expectedType != observableParameter.ParameterType) + { + throw new ParameterMismatchException(observableMethod, index, mainParameter, observableParameter); + } index++; } } From c732e24f3295c214d09f9534245e2213227ca55c Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 22:56:22 +1100 Subject: [PATCH 43/46] :lipstick: highlight expected and actual values --- .../Exception/ParameterCountMismatchException.cs | 2 +- .../Exception/ReturnValueMismatchException.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs b/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs index 331673d9..24b165f3 100644 --- a/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs +++ b/Octokit.Tests.Conventions/Exception/ParameterCountMismatchException.cs @@ -27,7 +27,7 @@ namespace Octokit.Tests.Conventions var expectedMethodSignature = CreateMethodSignature(expected); var actualMethodSignature = CreateMethodSignature(actual); - return String.Format("Method signature for {0}.{1} must be ({2}) but is ({3})", method.DeclaringType.Name, method.Name, expectedMethodSignature, actualMethodSignature); + return String.Format("Method signature for {0}.{1} must be \"({2})\" but is \"({3})\"", method.DeclaringType.Name, method.Name, expectedMethodSignature, actualMethodSignature); } } } \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs b/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs index 121751d7..3bc97e4e 100644 --- a/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs +++ b/Octokit.Tests.Conventions/Exception/ReturnValueMismatchException.cs @@ -17,7 +17,7 @@ namespace Octokit.Tests.Conventions static string CreateMessage(MethodInfo method, Type expected, Type actual) { - return String.Format("Return value for {0}.{1} must be {2} but is {3}", method.DeclaringType.Name, method.Name, expected, actual); + return String.Format("Return value for {0}.{1} must be \"{2}\" but is \"{3}\"", method.DeclaringType.Name, method.Name, expected, actual); } } } \ No newline at end of file From 276a47d8e4040475042fda5b08430ba14a3cd9c8 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Thu, 20 Feb 2014 22:59:02 +1100 Subject: [PATCH 44/46] redundant check is redundant --- Octokit.Tests.Conventions/SyncObservableClients.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index c3e75d16..4c296f64 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -107,8 +107,6 @@ namespace Octokit.Tests.Conventions var mainType = mainParameter.ParameterType; var expectedType = GetObservableExpectedType(mainType); - Assert.Equal(expectedType, observableParameter.ParameterType); - if (expectedType != observableParameter.ParameterType) { throw new ParameterMismatchException(observableMethod, index, mainParameter, observableParameter); From 5c662cdc80273aee402058944654f8191fdced1d Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 17:18:04 +1100 Subject: [PATCH 45/46] throw a wobbly when you're doing overloads wrong --- .../InterfaceMethodsMismatchException.cs | 42 +++++++++++++++++++ .../Octokit.Tests.Conventions.csproj | 1 + .../SyncObservableClients.cs | 5 +++ 3 files changed, 48 insertions(+) create mode 100644 Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs diff --git a/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs b/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs new file mode 100644 index 00000000..dad28aee --- /dev/null +++ b/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs @@ -0,0 +1,42 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +namespace Octokit.Tests.Conventions +{ + public class InterfaceMethodsMismatchException : Exception + { + public InterfaceMethodsMismatchException(Type observableType, Type clientInterface) + : base(CreateMessage(observableType, clientInterface)) { } + + public InterfaceMethodsMismatchException(Type type,Type clientInterface, Exception innerException) + : base(CreateMessage(type, clientInterface), innerException) { } + + protected InterfaceMethodsMismatchException(SerializationInfo info, StreamingContext context) + : base(info, context) { } + + static string Format(ParameterInfo parameterInfo) + { + return String.Format("{0} {1}", parameterInfo.ParameterType.Name, parameterInfo.Name); + } + + static string Format(MethodInfo methodInfo) + { + var parameters = methodInfo.GetParameters().Select(Format); + + return String.Format("{0} {1}({2})", methodInfo.ReturnType, methodInfo.Name, String.Join(", ", parameters)); + } + + static string CreateMessage(Type observableInterface, Type clientInterface) + { + var mainMethods = clientInterface.GetMethodsOrdered(); + var observableMethods = observableInterface.GetMethodsOrdered(); + + var formattedMainMethods = String.Join("\r\n", mainMethods.Select(Format).Select(m => String.Format(" - {0}", m))); + var formattedObservableMethods = String.Join("\r\n", observableMethods.Select(Format).Select(m => String.Format(" - {0}", m))); + + return String.Format("There are some overloads which are confusing the convention tests. Check everything is okay in these types:\r\n{0}\r\n{2}\r\n{1}\r\n{3}", clientInterface.Name, observableInterface.Name, formattedMainMethods, formattedObservableMethods); + } + } +} \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj index f50961d5..096592b4 100644 --- a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj +++ b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj @@ -51,6 +51,7 @@ + diff --git a/Octokit.Tests.Conventions/SyncObservableClients.cs b/Octokit.Tests.Conventions/SyncObservableClients.cs index 4c296f64..2302f0f5 100644 --- a/Octokit.Tests.Conventions/SyncObservableClients.cs +++ b/Octokit.Tests.Conventions/SyncObservableClients.cs @@ -34,6 +34,11 @@ namespace Octokit.Tests.Conventions throw new InterfaceHasAdditionalMethodsException(observableClient, additionalMethodsOnReactiveClient); } + if (mainNames.Count() != observableNames.Count()) + { + throw new InterfaceMethodsMismatchException(observableClient, clientInterface); + } + int index = 0; foreach(var mainMethod in mainMethods) { From f2064786116e7fe9b747147bbaa1c85ec9675af5 Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Sat, 8 Mar 2014 17:30:30 +1100 Subject: [PATCH 46/46] string formatting because lolwindows --- .../InterfaceHasAdditionalMethodsException.cs | 5 ++++- .../InterfaceMethodsMismatchException.cs | 8 +++++++- .../InterfaceMissingMethodsException.cs | 3 ++- .../Octokit.Tests.Conventions.csproj | 1 + Octokit.Tests.Conventions/StringExtensions.cs | 16 ++++++++++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 Octokit.Tests.Conventions/StringExtensions.cs diff --git a/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs b/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs index 4bccc557..78ea2daa 100644 --- a/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs +++ b/Octokit.Tests.Conventions/Exception/InterfaceHasAdditionalMethodsException.cs @@ -19,7 +19,10 @@ namespace Octokit.Tests.Conventions static string CreateMessage(Type type, IEnumerable methods) { var methodsFormatted = String.Join("\r\n", methods.Select(m => String.Format(" - {0}", m))); - return String.Format("Methods found on type {0} which should be removed:\r\n{1}", type.Name, methodsFormatted); + return "Methods found on type {0} which should be removed:\r\n{1}" + .FormatWithNewLine( + type.Name, + methodsFormatted); } } } \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs b/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs index dad28aee..7a422d49 100644 --- a/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs +++ b/Octokit.Tests.Conventions/Exception/InterfaceMethodsMismatchException.cs @@ -36,7 +36,13 @@ namespace Octokit.Tests.Conventions var formattedMainMethods = String.Join("\r\n", mainMethods.Select(Format).Select(m => String.Format(" - {0}", m))); var formattedObservableMethods = String.Join("\r\n", observableMethods.Select(Format).Select(m => String.Format(" - {0}", m))); - return String.Format("There are some overloads which are confusing the convention tests. Check everything is okay in these types:\r\n{0}\r\n{2}\r\n{1}\r\n{3}", clientInterface.Name, observableInterface.Name, formattedMainMethods, formattedObservableMethods); + return + "There are some overloads which are confusing the convention tests. Check everything is okay in these types:\r\n{0}\r\n{1}\r\n{2}\r\n{3}" + .FormatWithNewLine( + clientInterface.Name, + formattedMainMethods, + observableInterface.Name, + formattedObservableMethods); } } } \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs b/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs index 65fc8c76..4d16288a 100644 --- a/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs +++ b/Octokit.Tests.Conventions/Exception/InterfaceMissingMethodsException.cs @@ -19,7 +19,8 @@ namespace Octokit.Tests.Conventions static string CreateMessage(Type type, IEnumerable methods) { var methodsFormatted = String.Join("\r\n", methods.Select(m => String.Format(" - {0}", m))); - return String.Format("Methods not found on interface {0} which are required:\r\n{1}", type.Name, methodsFormatted); + return "Methods not found on interface {0} which are required:\r\n{1}" + .FormatWithNewLine(type.Name, methodsFormatted); } } } \ No newline at end of file diff --git a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj index 096592b4..dd3aa159 100644 --- a/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj +++ b/Octokit.Tests.Conventions/Octokit.Tests.Conventions.csproj @@ -58,6 +58,7 @@ + diff --git a/Octokit.Tests.Conventions/StringExtensions.cs b/Octokit.Tests.Conventions/StringExtensions.cs new file mode 100644 index 00000000..0fdc64a3 --- /dev/null +++ b/Octokit.Tests.Conventions/StringExtensions.cs @@ -0,0 +1,16 @@ +using System; + +namespace Octokit.Tests.Conventions +{ + internal static class StringExtensions + { + public static string FormatWithNewLine(this string s, params object[] args) + { + var template = Environment.NewLine == "\r\n" + ? s + : s.Replace("\r\n", Environment.NewLine); + + return String.Format(template, args); + } + } +}