From 4cd2e6557723382e0078fdaf987c380e37c4c905 Mon Sep 17 00:00:00 2001 From: Coen van den Munckhof Date: Sun, 15 Jan 2023 17:37:03 +0100 Subject: [PATCH 1/3] wip --- RepoM.sln | 23 +++++++++ .../Explorer/IWindowsExplorerHandler.cs | 8 ++++ .../Explorer/WindowsExplorerHandler.cs | 3 +- .../PInvoke/WindowPath.cs | 2 +- .../WindowExplorerBarGitInfoModule.cs | 4 +- ...le.cs => WindowsExplorerGitInfoPackage.cs} | 4 +- ...Plugin.WindowsExplorerGitInfo.Tests.csproj | 38 +++++++++++++++ .../TestFramework/VerifierInitializer.cs | 15 ++++++ .../WindowExplorerBarGitInfoModuleTest.cs | 42 ++++++++++++++++ .../WindowsExplorerGitInfoPackageTests.cs | 48 +++++++++++++++++++ 10 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/IWindowsExplorerHandler.cs rename src/RepoM.Plugin.WindowsExplorerGitInfo/{WindowsExplorerGitInfoModule.cs => WindowsExplorerGitInfoPackage.cs} (72%) create mode 100644 tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests.csproj create mode 100644 tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/TestFramework/VerifierInitializer.cs create mode 100644 tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs create mode 100644 tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowsExplorerGitInfoPackageTests.cs diff --git a/RepoM.sln b/RepoM.sln index 6adf8a62..fa5cb397 100644 --- a/RepoM.sln +++ b/RepoM.sln @@ -47,6 +47,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoM.Plugin.Clipboard.Test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoM.Plugin.EverythingFileSearch.Tests", "tests\RepoM.Plugin.EverythingFileSearch.Tests\RepoM.Plugin.EverythingFileSearch.Tests.csproj", "{89D96078-2951-44C2-B5B1-1DA0D5E94C0C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoM.Plugin.WindowsExplorerGitInfo.Tests", "tests\RepoM.Plugin.WindowsExplorerGitInfo.Tests\RepoM.Plugin.WindowsExplorerGitInfo.Tests.csproj", "{99DFA130-C0F4-4D1F-8428-5CACA481B688}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -481,6 +483,26 @@ Global {89D96078-2951-44C2-B5B1-1DA0D5E94C0C}.Release|x64.Build.0 = Release|Any CPU {89D96078-2951-44C2-B5B1-1DA0D5E94C0C}.Release|x86.ActiveCfg = Release|Any CPU {89D96078-2951-44C2-B5B1-1DA0D5E94C0C}.Release|x86.Build.0 = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|ARM.ActiveCfg = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|ARM.Build.0 = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|ARM64.Build.0 = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|x64.ActiveCfg = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|x64.Build.0 = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|x86.ActiveCfg = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Debug|x86.Build.0 = Debug|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|Any CPU.Build.0 = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|ARM.ActiveCfg = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|ARM.Build.0 = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|ARM64.ActiveCfg = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|ARM64.Build.0 = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|x64.ActiveCfg = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|x64.Build.0 = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|x86.ActiveCfg = Release|Any CPU + {99DFA130-C0F4-4D1F-8428-5CACA481B688}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -501,6 +523,7 @@ Global {8F87B73D-8A5D-4335-96E9-97EE0495B671} = {D6E372DC-10D3-4997-9DFC-568B4666635A} {A26EF3E9-C267-499C-B5AB-E4FB3C7AB6E1} = {D6E372DC-10D3-4997-9DFC-568B4666635A} {89D96078-2951-44C2-B5B1-1DA0D5E94C0C} = {D6E372DC-10D3-4997-9DFC-568B4666635A} + {99DFA130-C0F4-4D1F-8428-5CACA481B688} = {D6E372DC-10D3-4997-9DFC-568B4666635A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1765ABAA-0652-4DA5-ABBF-05396F2957D7} diff --git a/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/IWindowsExplorerHandler.cs b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/IWindowsExplorerHandler.cs new file mode 100644 index 00000000..f01ed223 --- /dev/null +++ b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/IWindowsExplorerHandler.cs @@ -0,0 +1,8 @@ +namespace RepoM.Plugin.WindowsExplorerGitInfo.PInvoke.Explorer; + +internal interface IWindowsExplorerHandler +{ + void UpdateTitles(); + + void CleanTitles(); +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs index 44bc01c2..a3e4529d 100644 --- a/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs +++ b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs @@ -3,7 +3,7 @@ namespace RepoM.Plugin.WindowsExplorerGitInfo.PInvoke.Explorer; using JetBrains.Annotations; using RepoM.Api.Git; -internal class WindowsExplorerHandler +internal class WindowsExplorerHandler : IWindowsExplorerHandler { private readonly IRepositoryInformationAggregator _repositoryInfoAggregator; @@ -18,7 +18,6 @@ public void UpdateTitles() actor.Pulse(); } - [PublicAPI] public void CleanTitles() { var actor = new CleanWindowTitleActor(); diff --git a/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/WindowPath.cs b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/WindowPath.cs index 85909056..d733d845 100644 --- a/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/WindowPath.cs +++ b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/WindowPath.cs @@ -2,7 +2,7 @@ namespace RepoM.Plugin.WindowsExplorerGitInfo.PInvoke; using System; -public class WindowPath +internal class WindowPath { public WindowPath(IntPtr handle, string path) { diff --git a/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowExplorerBarGitInfoModule.cs b/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowExplorerBarGitInfoModule.cs index 404aab45..c8fc1de3 100644 --- a/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowExplorerBarGitInfoModule.cs +++ b/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowExplorerBarGitInfoModule.cs @@ -11,9 +11,9 @@ namespace RepoM.Plugin.WindowsExplorerGitInfo; internal class WindowExplorerBarGitInfoModule : IModule { private readonly Timer _explorerUpdateTimer; - private readonly WindowsExplorerHandler _explorerHandler; + private readonly IWindowsExplorerHandler _explorerHandler; - public WindowExplorerBarGitInfoModule(WindowsExplorerHandler explorerHandler) + public WindowExplorerBarGitInfoModule(IWindowsExplorerHandler explorerHandler) { _explorerHandler = explorerHandler ?? throw new ArgumentNullException(nameof(explorerHandler)); _explorerUpdateTimer = new Timer(RefreshTimerCallback, null, Timeout.Infinite, Timeout.Infinite); diff --git a/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowsExplorerGitInfoModule.cs b/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowsExplorerGitInfoPackage.cs similarity index 72% rename from src/RepoM.Plugin.WindowsExplorerGitInfo/WindowsExplorerGitInfoModule.cs rename to src/RepoM.Plugin.WindowsExplorerGitInfo/WindowsExplorerGitInfoPackage.cs index d46628bf..ac5cafd2 100644 --- a/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowsExplorerGitInfoModule.cs +++ b/src/RepoM.Plugin.WindowsExplorerGitInfo/WindowsExplorerGitInfoPackage.cs @@ -7,11 +7,11 @@ namespace RepoM.Plugin.WindowsExplorerGitInfo; using SimpleInjector.Packaging; [UsedImplicitly] -public class WindowsExplorerGitInfoModule : IPackage +public class WindowsExplorerGitInfoPackage : IPackage { public void RegisterServices(Container container) { - container.Register(Lifestyle.Singleton); + container.Register(Lifestyle.Singleton); container.Collection.Append(Lifestyle.Singleton); } } \ No newline at end of file diff --git a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests.csproj b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests.csproj new file mode 100644 index 00000000..0f971316 --- /dev/null +++ b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests.csproj @@ -0,0 +1,38 @@ + + + + net6.0-windows + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/TestFramework/VerifierInitializer.cs b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/TestFramework/VerifierInitializer.cs new file mode 100644 index 00000000..b48df2c9 --- /dev/null +++ b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/TestFramework/VerifierInitializer.cs @@ -0,0 +1,15 @@ +namespace RepoM.Plugin.WindowsExplorerGitInfo.Tests.TestFramework; + +using System.Runtime.CompilerServices; +using Argon; +using VerifyTests; + +public static class VerifierInitializer +{ + [ModuleInitializer] + public static void Initialize() + { + VerifierSettings.DisableRequireUniquePrefix(); + VerifierSettings.AddExtraSettings(serializerSettings => serializerSettings.TypeNameHandling = TypeNameHandling.Auto); + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs new file mode 100644 index 00000000..98efdb53 --- /dev/null +++ b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs @@ -0,0 +1,42 @@ +namespace RepoM.Plugin.WindowsExplorerGitInfo.Tests; + +using System; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; +using System.Threading.Tasks; +using FakeItEasy; +using FluentAssertions; +using Microsoft.Extensions.Logging; +using RepoM.Core.Plugin.Common; +using RepoM.Plugin.WindowsExplorerGitInfo.PInvoke.Explorer; +using Xunit; + +public class WindowExplorerBarGitInfoModuleTest +{ + [Fact] + public void Ctor_ShouldThrow_WhenArgumentIsNull() + { + // arrange + + // act + Action act = () => _ = new WindowExplorerBarGitInfoModule(null!); + + // assert + act.Should().ThrowExactly(); + } + + + [Fact] + public async Task StopAsync_ShouldCleanTitles() + { + // arrange + var explorerHandler = A.Fake(); + var sut = new WindowExplorerBarGitInfoModule(explorerHandler); + + // act + await sut.StopAsync(); + + // assert + A.CallTo(() => explorerHandler.CleanTitles()).MustHaveHappenedOnceExactly(); + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowsExplorerGitInfoPackageTests.cs b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowsExplorerGitInfoPackageTests.cs new file mode 100644 index 00000000..47c79fc0 --- /dev/null +++ b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowsExplorerGitInfoPackageTests.cs @@ -0,0 +1,48 @@ +namespace RepoM.Plugin.WindowsExplorerGitInfo.Tests; + +using System; +using System.IO.Abstractions; +using FakeItEasy; +using Microsoft.Extensions.Logging; +using RepoM.Api.Git; +using RepoM.Core.Plugin.Common; +using SimpleInjector; +using Xunit; + +public class WindowsExplorerGitInfoPackageTests +{ + [Fact] + public void RegisterServices_ShouldBeSuccessful_WhenExternalDependenciesAreRegistered() + { + // arrange + var container = new Container(); + RegisterExternals(container); + var sut = new WindowsExplorerGitInfoPackage(); + + // act + sut.RegisterServices(container); + + // assert + // implicit, Verify throws when container is not valid. + container.Verify(VerificationOption.VerifyAndDiagnose); + } + + [Fact] + public void RegisterServices_ShouldFail_WhenExternalDependenciesAreNotRegistered() + { + // arrange + var container = new Container(); + var sut = new WindowsExplorerGitInfoPackage(); + + // act + sut.RegisterServices(container); + + // assert + Assert.Throws(() => container.Verify(VerificationOption.VerifyAndDiagnose)); + } + + private static void RegisterExternals(Container container) + { + container.RegisterSingleton(A.Dummy); + } +} \ No newline at end of file From b9cbd581f7709542287aa71da9201fc7e2f72c7d Mon Sep 17 00:00:00 2001 From: Coen van den Munckhof Date: Sun, 15 Jan 2023 17:39:32 +0100 Subject: [PATCH 2/3] update --- .../WindowExplorerBarGitInfoModuleTest.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs index 98efdb53..a2bdb645 100644 --- a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs +++ b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs @@ -13,6 +13,15 @@ namespace RepoM.Plugin.WindowsExplorerGitInfo.Tests; public class WindowExplorerBarGitInfoModuleTest { + private readonly IWindowsExplorerHandler _explorerHandler; + private readonly WindowExplorerBarGitInfoModule _sut; + + public WindowExplorerBarGitInfoModuleTest() + { + _explorerHandler = A.Fake(); + _sut = new WindowExplorerBarGitInfoModule(_explorerHandler); + } + [Fact] public void Ctor_ShouldThrow_WhenArgumentIsNull() { @@ -25,18 +34,15 @@ public void Ctor_ShouldThrow_WhenArgumentIsNull() act.Should().ThrowExactly(); } - [Fact] public async Task StopAsync_ShouldCleanTitles() { // arrange - var explorerHandler = A.Fake(); - var sut = new WindowExplorerBarGitInfoModule(explorerHandler); - + // act - await sut.StopAsync(); + await _sut.StopAsync(); // assert - A.CallTo(() => explorerHandler.CleanTitles()).MustHaveHappenedOnceExactly(); + A.CallTo(() => _explorerHandler.CleanTitles()).MustHaveHappenedOnceExactly(); } } \ No newline at end of file From d5bcdcb3acef6ae4913b33356e646142bd20b724 Mon Sep 17 00:00:00 2001 From: Coen van den Munckhof Date: Mon, 16 Jan 2023 20:18:03 +0100 Subject: [PATCH 3/3] update --- .../Explorer/WindowsExplorerHandler.cs | 1 - .../WindowExplorerBarGitInfoModuleTest.cs | 65 +++++++++++++++++-- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs index a3e4529d..5b5feeba 100644 --- a/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs +++ b/src/RepoM.Plugin.WindowsExplorerGitInfo/PInvoke/Explorer/WindowsExplorerHandler.cs @@ -1,6 +1,5 @@ namespace RepoM.Plugin.WindowsExplorerGitInfo.PInvoke.Explorer; -using JetBrains.Annotations; using RepoM.Api.Git; internal class WindowsExplorerHandler : IWindowsExplorerHandler diff --git a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs index a2bdb645..2129be18 100644 --- a/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs +++ b/tests/RepoM.Plugin.WindowsExplorerGitInfo.Tests/WindowExplorerBarGitInfoModuleTest.cs @@ -1,13 +1,10 @@ namespace RepoM.Plugin.WindowsExplorerGitInfo.Tests; using System; -using System.IO.Abstractions; -using System.IO.Abstractions.TestingHelpers; +using System.Threading; using System.Threading.Tasks; using FakeItEasy; using FluentAssertions; -using Microsoft.Extensions.Logging; -using RepoM.Core.Plugin.Common; using RepoM.Plugin.WindowsExplorerGitInfo.PInvoke.Explorer; using Xunit; @@ -45,4 +42,64 @@ public async Task StopAsync_ShouldCleanTitles() // assert A.CallTo(() => _explorerHandler.CleanTitles()).MustHaveHappenedOnceExactly(); } + + [Fact] + public async Task StartAsync_ShouldCallUpdateTitlesUntilStopped() + { + // arrange + var count = 0; + var mre = new ManualResetEvent(false); + A.CallTo(() => _explorerHandler.UpdateTitles()). + Invokes(_ => + { + var currentCount = Interlocked.Increment(ref count); + if (currentCount == 3) + { + mre.Set(); + } + }); + + // act + await _sut.StartAsync(); + _ = mre.WaitOne(TimeSpan.FromSeconds(5)); + + // assert + A.CallTo(() => _explorerHandler.UpdateTitles()).MustHaveHappened(3, Times.Exactly); + A.CallTo(() => _explorerHandler.CleanTitles()).MustNotHaveHappened(); + } + + [Fact] + public async Task StopAsync_ShouldCancelTimerExecution_WhenStarted() + { + // arrange + var count = 0; + var mreAfterStart = new ManualResetEvent(false); + var mreAfterStop = new ManualResetEvent(false); + A.CallTo(() => _explorerHandler.UpdateTitles()). + Invokes(_ => + { + var currentCount = Interlocked.Increment(ref count); + if (currentCount == 2) + { + mreAfterStart.Set(); + return; + } + + if (currentCount > 2) + { + mreAfterStop.Set(); + } + }); + + await _sut.StartAsync(); + _ = mreAfterStart.WaitOne(TimeSpan.FromSeconds(2)); + + // act + await _sut.StopAsync(); + _ = mreAfterStop.WaitOne(TimeSpan.FromSeconds(2)); + + // assert + A.CallTo(() => _explorerHandler.UpdateTitles()).MustHaveHappened(2, Times.Exactly); + A.CallTo(() => _explorerHandler.CleanTitles()).MustHaveHappenedOnceExactly(); + } } \ No newline at end of file