async Task <PullRequestSession> CreateTarget(FakeDiffService diffService)
            {
                var baseContents = @"Line 1
Line 2
Line 3
Line 4";
                var headContents = @"Line 1
Line 2
Line 3 with comment
Line 4";

                var pullRequest = CreatePullRequest();
                var service     = CreateService(diffService);

                diffService.AddFile(FilePath, baseContents);

                var target = new PullRequestSession(
                    service,
                    Substitute.For <IAccount>(),
                    pullRequest,
                    Substitute.For <ILocalRepositoryModel>(),
                    "owner",
                    true);

                var editor = new FakeEditorContentSource(headContents);
                var file   = await target.GetFile(FilePath, editor);

                return(target);
            }
            public async Task CommitShaIsSetIfUnmodified()
            {
                var baseContents = @"Line 1
Line 2
Line 3
Line 4";
                var headContents = @"Line 1
Line 2
Line 3 with comment
Line 4";

                using (var diffService = new FakeDiffService())
                {
                    var pullRequest = CreatePullRequest();
                    var service     = CreateService(diffService);

                    diffService.AddFile(FilePath, baseContents);
                    service.IsUnmodifiedAndPushed(Arg.Any <ILocalRepositoryModel>(), FilePath, Arg.Any <byte[]>()).Returns(true);

                    var target = new PullRequestSession(
                        service,
                        Substitute.For <IAccount>(),
                        pullRequest,
                        Substitute.For <ILocalRepositoryModel>(),
                        true);

                    var editor = new FakeEditorContentSource(headContents);
                    var file   = await target.GetFile(FilePath, editor);

                    Assert.Equal("BRANCH_TIP", file.CommitSha);
                }
            }
            public async Task CommitShaIsReadFromPullRequestModelIfBranchNotCheckedOut()
            {
                var baseContents = @"Line 1
Line 2
Line 3
Line 4";
                var headContents = @"Line 1
Line 2
Line 3 with comment
Line 4";

                using (var diffService = new FakeDiffService())
                {
                    var pullRequest = CreatePullRequest();
                    var service     = CreateService(diffService);

                    diffService.AddFile(FilePath, baseContents);
                    service.IsUnmodifiedAndPushed(Arg.Any <ILocalRepositoryModel>(), FilePath, Arg.Any <byte[]>()).Returns(false);

                    var target = new PullRequestSession(
                        service,
                        Substitute.For <IAccount>(),
                        pullRequest,
                        Substitute.For <ILocalRepositoryModel>(),
                        "owner",
                        isCheckedOut: false);

                    var editor = new FakeEditorContentSource(headContents);
                    var file   = await target.GetFile(FilePath, editor);

                    Assert.Equal("HEAD_SHA", file.CommitSha);
                }
            }
            public async Task AddsNewReviewCommentToThread()
            {
                var baseContents   = @"Line 1
Line 2
Line 3
Line 4";
                var editorContents = @"Line 1
Line 2
Line 3 with comment
Line 4";

                var comment1 = CreateComment(@"@@ -1,4 +1,4 @@
 Line 1
 Line 2
-Line 3
+Line 3 with comment", "Comment1");

                var comment2 = CreateComment(@"@@ -1,4 +1,4 @@
 Line 1
 Line 2
-Line 3
+Line 3 with comment", "Comment2");


                using (var diffService = new FakeDiffService())
                {
                    var pullRequest = CreatePullRequest(comment1);
                    var service     = CreateService(diffService);

                    diffService.AddFile(FilePath, baseContents);

                    var target = new PullRequestSession(
                        service,
                        Substitute.For <IAccount>(),
                        pullRequest,
                        Substitute.For <ILocalRepositoryModel>(),
                        "owner",
                        true);

                    var editor = new FakeEditorContentSource(editorContents);
                    var file   = await target.GetFile(FilePath, editor);

                    var thread = file.InlineCommentThreads.Single();

                    Assert.Equal("Comment1", thread.Comments.Single().Body);
                    Assert.Equal(2, thread.LineNumber);

                    pullRequest = CreatePullRequest(comment1, comment2);
                    await target.Update(pullRequest);

                    thread = file.InlineCommentThreads.Single();

                    Assert.Equal(2, thread.Comments.Count);
                    Assert.Equal(new[] { "Comment1", "Comment2" }, thread.Comments.Select(x => x.Body).ToArray());
                    Assert.Equal(2, thread.LineNumber);
                }
            }
            public async Task UpdatesReviewCommentWithNewBody()
            {
                var baseContents   = @"Line 1
Line 2
Line 3
Line 4";
                var editorContents = @"Line 1
Line 2
Line 3 with comment
Line 4";

                var originalComment = CreateComment(@"@@ -1,4 +1,4 @@
 Line 1
 Line 2
-Line 3
+Line 3 with comment", "Original Comment");

                var updatedComment = CreateComment(@"@@ -1,4 +1,4 @@
 Line 1
 Line 2
-Line 3
+Line 3 with comment", "Updated Comment");


                using (var diffService = new FakeDiffService())
                {
                    var pullRequest = CreatePullRequest(originalComment);
                    var service     = CreateService(diffService);

                    diffService.AddFile(FilePath, baseContents);

                    var target = new PullRequestSession(
                        service,
                        Substitute.For <IAccount>(),
                        pullRequest,
                        Substitute.For <ILocalRepositoryModel>(),
                        "owner",
                        true);

                    var editor = new FakeEditorContentSource(editorContents);
                    var file   = await target.GetFile(FilePath, editor);

                    var thread = file.InlineCommentThreads.Single();

                    Assert.Equal("Original Comment", thread.Comments.Single().Body);
                    Assert.Equal(2, thread.LineNumber);

                    pullRequest = CreatePullRequest(updatedComment);
                    await target.Update(pullRequest);

                    thread = file.InlineCommentThreads.Single();

                    Assert.Equal("Updated Comment", thread.Comments.Single().Body);
                    Assert.Equal(2, thread.LineNumber);
                }
            }
            public async Task UpdatesReviewCommentWithEditorContents()
            {
                var baseContents   = @"Line 1
Line 2
Line 3
Line 4";
                var diskContents   = @"Line 1
Line 2
Line 3 with comment
Line 4";
                var editorContents = @"New Line 1
New Line 2
Line 1
Line 2
Line 3 with comment
Line 4";

                var comment = CreateComment(@"@@ -1,4 +1,4 @@
 Line 1
 Line 2
-Line 3
+Line 3 with comment");

                using (var diffService = new FakeDiffService())
                {
                    var pullRequest = CreatePullRequest(comment);
                    var service     = CreateService(diffService);

                    diffService.AddFile(FilePath, baseContents);

                    var target = new PullRequestSession(
                        service,
                        Substitute.For <IAccount>(),
                        pullRequest,
                        Substitute.For <ILocalRepositoryModel>(),
                        "owner",
                        true);

                    var editor = new FakeEditorContentSource(diskContents);
                    var file   = await target.GetFile(FilePath, editor);

                    var thread = file.InlineCommentThreads.First();

                    Assert.Equal(2, thread.LineNumber);
                    editor.SetContent(editorContents);

                    await target.UpdateEditorContent(FilePath);

                    Assert.Equal(4, thread.LineNumber);
                }
            }
            public async Task UpdatesReviewCommentWithContentsFromGitWhenBranchNotCheckedOut()
            {
                var baseContents   = @"Line 1
Line 2
Line 3
Line 4";
                var gitContents    = Encoding.UTF8.GetBytes(@"Line 1
Line 2
Line 3 with comment
Line 4");
                var editorContents = @"Editor content";

                var comment = CreateComment(@"@@ -1,4 +1,4 @@
 Line 1
 Line 2
-Line 3
+Line 3 with comment");

                using (var diffService = new FakeDiffService())
                {
                    var pullRequest = CreatePullRequest(comment);
                    var service     = CreateService(diffService);

                    diffService.AddFile(FilePath, baseContents);

                    // Because the PR branch isn't checked out, the file contents should be read
                    // from git and not the editor or disk.
                    service.ExtractFileFromGit(Arg.Any <ILocalRepositoryModel>(), PullRequestNumber, "HEAD_SHA", FilePath)
                    .Returns(Task.FromResult(gitContents));

                    var target = new PullRequestSession(
                        service,
                        Substitute.For <IAccount>(),
                        pullRequest,
                        Substitute.For <ILocalRepositoryModel>(),
                        "owner",
                        isCheckedOut: false);

                    var editor = new FakeEditorContentSource(editorContents);
                    var file   = await target.GetFile(FilePath, editor);

                    var thread = file.InlineCommentThreads.First();

                    Assert.Equal(2, thread.LineNumber);
                }
            }
            public async Task CommitShaIsNullWhenChangedToModified()
            {
                var baseContents   = @"Line 1
Line 2
Line 3
Line 4";
                var headContents   = Encoding.UTF8.GetBytes(@"Line 1
Line 2
Line 3 with comment
Line 4");
                var editorContents = Encoding.UTF8.GetBytes(@"Line 1
Line 2
Line 3 with comment
Line 4 with comment");

                using (var diffService = new FakeDiffService())
                {
                    var pullRequest = CreatePullRequest();
                    var service     = CreateService(diffService);

                    diffService.AddFile(FilePath, baseContents);
                    service.IsUnmodifiedAndPushed(Arg.Any <ILocalRepositoryModel>(), FilePath, headContents).Returns(true);
                    service.IsUnmodifiedAndPushed(Arg.Any <ILocalRepositoryModel>(), FilePath, editorContents).Returns(false);

                    var target = new PullRequestSession(
                        service,
                        Substitute.For <IAccount>(),
                        pullRequest,
                        Substitute.For <ILocalRepositoryModel>(),
                        "owner",
                        true);

                    var editor = new FakeEditorContentSource(headContents);
                    var file   = await target.GetFile(FilePath, editor);

                    Assert.Equal("BRANCH_TIP", file.CommitSha);

                    editor.SetContent(editorContents);
                    await target.UpdateEditorContent(FilePath);

                    Assert.Null(file.CommitSha);
                }
            }