From 7f618128379c680ee09c891cafc23a4642024a50 Mon Sep 17 00:00:00 2001 From: Geoff Lamrock Date: Thu, 19 Dec 2024 18:50:53 +1100 Subject: [PATCH] Use proper Git repository for update stack tests (#156) --- .../Stack/UpdateStackCommandHandlerTests.cs | 306 ++++++++++-------- src/Stack.Tests/Helpers/Some.cs | 1 + .../Helpers/TestGitRepositoryBuilder.cs | 16 + src/Stack.Tests/Helpers/TestOutputProvider.cs | 47 +++ 4 files changed, 233 insertions(+), 137 deletions(-) create mode 100644 src/Stack.Tests/Helpers/TestOutputProvider.cs diff --git a/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs b/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs index 77144bb..b90042d 100644 --- a/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs +++ b/src/Stack.Tests/Commands/Stack/UpdateStackCommandHandlerTests.cs @@ -6,172 +6,171 @@ using Stack.Tests.Helpers; using Stack.Infrastructure; using Stack.Commands.Helpers; +using Xunit.Abstractions; namespace Stack.Tests.Commands.Stack; -public class UpdateStackCommandHandlerTests +public class UpdateStackCommandHandlerTests(ITestOutputHelper testOutputHelper) { [Fact] public async Task WhenMultipleBranchesExistInAStack_UpdatesAndMergesEachBranchInSequence() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10).PushToRemote()) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .WithNumberOfEmptyCommits(b => b.OnBranch(branch1).PushToRemote(), 3) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var tipOfBranch1 = repo.GetTipOfBranch(branch1); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - gitOperations.GetCurrentBranch().Returns("branch-1"); - - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); - var stack2 = new Config.Stack("Stack2", remoteUri, "branch-2", ["branch-4", "branch-5"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); + var stack2 = new Config.Stack("Stack2", repo.RemoteUri, sourceBranch, []); var stacks = new List([stack1, stack2]); stackConfig.Load().Returns(stacks); inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); inputProvider.Confirm(Questions.ConfirmUpdateStack).Returns(true); - gitOperations.DoesRemoteBranchExist(Arg.Any()).Returns(true); - // Act await handler.Handle(new UpdateStackCommandInputs(null, false)); // Assert - gitOperations.Received().UpdateBranch("branch-1"); - gitOperations.Received().UpdateBranch("branch-2"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-1"); - gitOperations.Received().PushBranch("branch-2"); - - gitOperations.Received().UpdateBranch("branch-2"); - gitOperations.Received().UpdateBranch("branch-3"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-2"); - gitOperations.Received().PushBranch("branch-3"); + repo.GetCommitsReachableFromBranch(branch1).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfBranch1); } [Fact] public async Task WhenABranchInTheStackNoLongerExistsOnTheRemote_SkipsOverUpdatingThatBranch() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10)) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - gitOperations.GetCurrentBranch().Returns("branch-1"); - - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); - var stack2 = new Config.Stack("Stack2", remoteUri, "branch-2", ["branch-4", "branch-5"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); + var stack2 = new Config.Stack("Stack2", repo.RemoteUri, sourceBranch, []); var stacks = new List([stack1, stack2]); stackConfig.Load().Returns(stacks); inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); inputProvider.Confirm(Questions.ConfirmUpdateStack).Returns(true); - var branchesThatExistInRemote = new List(["branch-1", "branch-3"]); - - gitOperations.DoesRemoteBranchExist(Arg.Is(b => branchesThatExistInRemote.Contains(b))).Returns(true); - // Act await handler.Handle(new UpdateStackCommandInputs(null, false)); // Assert - gitOperations.Received().UpdateBranch("branch-1"); - gitOperations.Received().UpdateBranch("branch-3"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-1"); - gitOperations.Received().PushBranch("branch-3"); - - gitOperations.DidNotReceive().UpdateBranch("branch-2"); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfSourceBranch); } [Fact] public async Task WhenABranchInTheStackExistsOnTheRemote_ButThePullRequestIsMerged_SkipsOverUpdatingThatBranch() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10).PushToRemote()) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - gitOperations.GetCurrentBranch().Returns("branch-1"); - - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); - var stack2 = new Config.Stack("Stack2", remoteUri, "branch-2", ["branch-4", "branch-5"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); + var stack2 = new Config.Stack("Stack2", repo.RemoteUri, sourceBranch, []); var stacks = new List([stack1, stack2]); stackConfig.Load().Returns(stacks); inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); inputProvider.Confirm(Questions.ConfirmUpdateStack).Returns(true); - var branchesThatExistInRemote = new List(["branch-1", "branch-2", "branch-3"]); - - gitOperations.DoesRemoteBranchExist(Arg.Is(b => branchesThatExistInRemote.Contains(b))).Returns(true); - gitHubOperations.GetPullRequest("branch-2").Returns(new GitHubPullRequest(1, Some.Name(), Some.Name(), GitHubPullRequestStates.Merged, Some.HttpsUri(), false)); + gitHubOperations.GetPullRequest(branch1).Returns(new GitHubPullRequest(1, Some.Name(), Some.Name(), GitHubPullRequestStates.Merged, Some.HttpsUri(), false)); // Act await handler.Handle(new UpdateStackCommandInputs(null, false)); // Assert - gitOperations.Received().UpdateBranch("branch-1"); - gitOperations.Received().UpdateBranch("branch-3"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-1"); - gitOperations.Received().PushBranch("branch-3"); - - gitOperations.DidNotReceive().UpdateBranch("branch-2"); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfSourceBranch); } [Fact] public async Task WhenNameIsProvided_DoesNotAskForName_UpdatesCorrectStack() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10).PushToRemote()) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .WithNumberOfEmptyCommits(b => b.OnBranch(branch1).PushToRemote(), 3) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var tipOfBranch1 = repo.GetTipOfBranch(branch1); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - gitOperations.GetCurrentBranch().Returns("branch-1"); - - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); - var stack2 = new Config.Stack("Stack2", remoteUri, "branch-2", ["branch-4", "branch-5"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); + var stack2 = new Config.Stack("Stack2", repo.RemoteUri, sourceBranch, []); var stacks = new List([stack1, stack2]); stackConfig.Load().Returns(stacks); inputProvider.Confirm(Questions.ConfirmUpdateStack).Returns(true); - gitOperations.DoesRemoteBranchExist(Arg.Any()).Returns(true); - // Act await handler.Handle(new UpdateStackCommandInputs("Stack1", false)); // Assert - gitOperations.Received().UpdateBranch("branch-1"); - gitOperations.Received().UpdateBranch("branch-2"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-1"); - gitOperations.Received().PushBranch("branch-2"); - - gitOperations.Received().UpdateBranch("branch-2"); - gitOperations.Received().UpdateBranch("branch-3"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-2"); - gitOperations.Received().PushBranch("branch-3"); - + repo.GetCommitsReachableFromBranch(branch1).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfBranch1); inputProvider.DidNotReceive().Select(Questions.SelectStack, Arg.Any()); } @@ -179,20 +178,29 @@ public async Task WhenNameIsProvided_DoesNotAskForName_UpdatesCorrectStack() public async Task WhenForceIsProvided_DoesNotAskForConfirmation() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10).PushToRemote()) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .WithNumberOfEmptyCommits(b => b.OnBranch(branch1).PushToRemote(), 3) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var tipOfBranch1 = repo.GetTipOfBranch(branch1); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - gitOperations.GetCurrentBranch().Returns("branch-1"); - - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); - var stack2 = new Config.Stack("Stack2", remoteUri, "branch-2", ["branch-4", "branch-5"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); + var stack2 = new Config.Stack("Stack2", repo.RemoteUri, sourceBranch, []); var stacks = new List([stack1, stack2]); stackConfig.Load().Returns(stacks); @@ -202,6 +210,9 @@ public async Task WhenForceIsProvided_DoesNotAskForConfirmation() await handler.Handle(new UpdateStackCommandInputs(null, true)); // Assert + repo.GetCommitsReachableFromBranch(branch1).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfBranch1); inputProvider.DidNotReceive().Confirm(Questions.ConfirmUpdateStack); } @@ -209,20 +220,29 @@ public async Task WhenForceIsProvided_DoesNotAskForConfirmation() public async Task WhenNameIsProvided_ButStackDoesNotExist_Throws() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10).PushToRemote()) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .WithNumberOfEmptyCommits(b => b.OnBranch(branch1).PushToRemote(), 3) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var tipOfBranch1 = repo.GetTipOfBranch(branch1); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - gitOperations.GetCurrentBranch().Returns("branch-1"); - - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); - var stack2 = new Config.Stack("Stack2", remoteUri, "branch-2", ["branch-4", "branch-5"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); + var stack2 = new Config.Stack("Stack2", repo.RemoteUri, sourceBranch, []); var stacks = new List([stack1, stack2]); stackConfig.Load().Returns(stacks); @@ -237,74 +257,86 @@ await handler.Invoking(async h => await h.Handle(new UpdateStackCommandInputs(in public async Task WhenOnASpecificBranchInTheStack_TheSameBranchIsSetAsCurrentAfterTheUpdate() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10).PushToRemote()) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .WithNumberOfEmptyCommits(b => b.OnBranch(branch1).PushToRemote(), 3) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var tipOfBranch1 = repo.GetTipOfBranch(branch1); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - // We are on a specific branch in the stack - gitOperations.GetCurrentBranch().Returns("branch-2"); + gitOperations.ChangeBranch(branch1); - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); - var stack2 = new Config.Stack("Stack2", remoteUri, "branch-2", ["branch-4", "branch-5"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); + var stack2 = new Config.Stack("Stack2", repo.RemoteUri, sourceBranch, []); var stacks = new List([stack1, stack2]); stackConfig.Load().Returns(stacks); inputProvider.Select(Questions.SelectStack, Arg.Any()).Returns("Stack1"); inputProvider.Confirm(Questions.ConfirmUpdateStack).Returns(true); - gitOperations.DoesRemoteBranchExist(Arg.Any()).Returns(true); - // Act await handler.Handle(new UpdateStackCommandInputs(null, false)); // Assert - gitOperations.Received().ChangeBranch("branch-2"); + repo.GetCommitsReachableFromBranch(branch1).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfBranch1); + gitOperations.GetCurrentBranch().Should().Be(branch1); } [Fact] public async Task WhenOnlyASingleStackExists_DoesNotAskForStackName_UpdatesStack() { // Arrange - var gitOperations = Substitute.For(); - var gitHubOperations = Substitute.For(); + var sourceBranch = Some.BranchName(); + var branch1 = Some.BranchName(); + var branch2 = Some.BranchName(); + using var repo = new TestGitRepositoryBuilder() + .WithBranch(builder => builder.WithName(sourceBranch).PushToRemote()) + .WithBranch(builder => builder.WithName(branch1).FromSourceBranch(sourceBranch).WithNumberOfEmptyCommits(10).PushToRemote()) + .WithBranch(builder => builder.WithName(branch2).FromSourceBranch(branch1).WithNumberOfEmptyCommits(1).PushToRemote()) + .WithNumberOfEmptyCommits(b => b.OnBranch(sourceBranch).PushToRemote(), 5) + .WithNumberOfEmptyCommits(b => b.OnBranch(branch1).PushToRemote(), 3) + .Build(); + + var tipOfSourceBranch = repo.GetTipOfBranch(sourceBranch); + var tipOfBranch1 = repo.GetTipOfBranch(branch1); + var stackConfig = Substitute.For(); var inputProvider = Substitute.For(); - var outputProvider = Substitute.For(); + var outputProvider = new TestOutputProvider(testOutputHelper); + var gitOperations = new GitOperations(outputProvider, repo.GitOperationSettings); + var gitHubOperations = Substitute.For(); var handler = new UpdateStackCommandHandler(inputProvider, outputProvider, gitOperations, gitHubOperations, stackConfig); - var remoteUri = Some.HttpsUri().ToString(); - - gitOperations.GetRemoteUri().Returns(remoteUri); - gitOperations.GetCurrentBranch().Returns("branch-1"); - - var stack1 = new Config.Stack("Stack1", remoteUri, "branch-1", ["branch-2", "branch-3"]); + var stack1 = new Config.Stack("Stack1", repo.RemoteUri, sourceBranch, [branch1, branch2]); var stacks = new List([stack1]); stackConfig.Load().Returns(stacks); inputProvider.Confirm(Questions.ConfirmUpdateStack).Returns(true); - gitOperations.DoesRemoteBranchExist(Arg.Any()).Returns(true); - // Act await handler.Handle(new UpdateStackCommandInputs(null, false)); // Assert - gitOperations.Received().UpdateBranch("branch-1"); - gitOperations.Received().UpdateBranch("branch-2"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-1"); - gitOperations.Received().PushBranch("branch-2"); - - gitOperations.Received().UpdateBranch("branch-2"); - gitOperations.Received().UpdateBranch("branch-3"); - gitOperations.Received().MergeFromLocalSourceBranch("branch-2"); - gitOperations.Received().PushBranch("branch-3"); + repo.GetCommitsReachableFromBranch(branch1).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfSourceBranch); + repo.GetCommitsReachableFromBranch(branch2).Should().Contain(tipOfBranch1); inputProvider.DidNotReceive().Select(Questions.SelectStack, Arg.Any()); } diff --git a/src/Stack.Tests/Helpers/Some.cs b/src/Stack.Tests/Helpers/Some.cs index 1991841..b28803f 100644 --- a/src/Stack.Tests/Helpers/Some.cs +++ b/src/Stack.Tests/Helpers/Some.cs @@ -8,4 +8,5 @@ public static class Some public static string ShortName() => Guid.NewGuid().ToString("N").Substring(0, 8); public static string BranchName() => $"branch-{ShortName()}"; public static Uri HttpsUri() => new($"https://{ShortName()}.com"); + public static string Email() => $"{ShortName()}@{ShortName()}.com"; } diff --git a/src/Stack.Tests/Helpers/TestGitRepositoryBuilder.cs b/src/Stack.Tests/Helpers/TestGitRepositoryBuilder.cs index e048dd4..14dfcf8 100644 --- a/src/Stack.Tests/Helpers/TestGitRepositoryBuilder.cs +++ b/src/Stack.Tests/Helpers/TestGitRepositoryBuilder.cs @@ -209,6 +209,12 @@ public TestGitRepository Build() var remoteRepo = new Repository(Repository.Init(remoteDirectory.DirectoryPath, true)); var localRepo = new Repository(Repository.Clone(remote, localDirectory.DirectoryPath)); + + // Ensure that we can commit to this repository when tests run + // in a context where the user's name and email are not set. + localRepo.Config.Add("user.name", Some.Name()); + localRepo.Config.Add("user.email", Some.Email()); + var defaultBranchName = Some.BranchName(); localRepo.Refs.UpdateTarget("HEAD", "refs/heads/" + defaultBranchName); @@ -246,6 +252,16 @@ public class TestGitRepository(TemporaryDirectory LocalDirectory, TemporaryDirec public string RemoteUri => RemoteDirectory.DirectoryPath; public GitOperationSettings GitOperationSettings => new GitOperationSettings(false, false, LocalDirectory.DirectoryPath); + public Commit GetTipOfBranch(string branchName) + { + return LocalRepository.Branches[branchName].Tip; + } + + public List GetCommitsReachableFromBranch(string branchName) + { + return [.. LocalRepository.Branches[branchName].Commits]; + } + public void Dispose() { GC.SuppressFinalize(this); diff --git a/src/Stack.Tests/Helpers/TestOutputProvider.cs b/src/Stack.Tests/Helpers/TestOutputProvider.cs new file mode 100644 index 0000000..89a7198 --- /dev/null +++ b/src/Stack.Tests/Helpers/TestOutputProvider.cs @@ -0,0 +1,47 @@ +using Stack.Infrastructure; +using Xunit.Abstractions; + +namespace Stack.Tests.Helpers; + +public class TestOutputProvider(ITestOutputHelper testOutputHelper) : IOutputProvider +{ + public void Debug(string message) + { + testOutputHelper.WriteLine($"DEBUG: {message}"); + } + + public void Error(string message) + { + testOutputHelper.WriteLine($"ERROR: {message}"); + } + + public void Information(string message) + { + testOutputHelper.WriteLine($"INFO: {message}"); + } + + public void Rule(string message) + { + testOutputHelper.WriteLine($"RULE: {message}"); + } + + public void Status(string message, Action action) + { + testOutputHelper.WriteLine($"STATUS: {message}"); + action(); + } + + public void Tree(string header, string[] items) + { + testOutputHelper.WriteLine($"TREE: {header}"); + foreach (var item in items) + { + testOutputHelper.WriteLine($" {item}"); + } + } + + public void Warning(string message) + { + testOutputHelper.WriteLine($"WARNING: {message}"); + } +}