Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/WindowController.App.Tests/HotkeyManagerLogicTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Windows.Input;
using WindowController.App;
using Xunit;

namespace WindowController.App.Tests;

public class HotkeyManagerLogicTests
{
[Theory]
[InlineData(Key.A, "A")]
[InlineData(Key.Z, "Z")]
[InlineData(Key.D0, "0")]
[InlineData(Key.D9, "9")]
[InlineData(Key.NumPad0, "NumPad0")]
[InlineData(Key.NumPad7, "NumPad7")]
[InlineData(Key.F13, "F13")]
[InlineData(Key.F24, "F24")]
[InlineData(Key.PageUp, "PageUp")]
[InlineData(Key.PageDown, "PageDown")]
[InlineData(Key.Escape, "Escape")]
public void GetKeyString_ReturnsExpected(Key key, string expected)
{
Assert.Equal(expected, HotkeyManager.GetKeyString(key));
}

[Theory]
[InlineData("ESC", 0x1B)]
[InlineData("Escape", 0x1B)]
[InlineData("PGUP", 0x21)]
[InlineData("PageDown", 0x22)]
[InlineData("DEL", 0x2E)]
[InlineData("Insert", 0x2D)]
[InlineData("PrtSc", 0x2C)]
[InlineData("Space", 0x20)]
public void GetVirtualKeyCode_SpecialStrings_ReturnExpected(string key, int expectedVk)
{
Assert.Equal(expectedVk, HotkeyManager.GetVirtualKeyCode(key));
}

[Theory]
[InlineData("", 0)]
[InlineData("[", 0)]
[InlineData("-", 0)]
public void GetVirtualKeyCode_UnsupportedCharacters_ReturnZero(string key, int expectedVk)
{
Assert.Equal(expectedVk, HotkeyManager.GetVirtualKeyCode(key));
}

[Theory]
[InlineData("F13", 0x7C)]
[InlineData("F24", 0x87)]
public void GetVirtualKeyCode_FunctionKeys_ReturnExpected(string key, int expectedVk)
{
Assert.Equal(expectedVk, HotkeyManager.GetVirtualKeyCode(key));
}
}
143 changes: 143 additions & 0 deletions src/WindowController.App.Tests/ProfileApplierTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using System.IO;
using Serilog;
using WindowController.App;
using WindowController.Core;
using WindowController.Core.Models;
using WindowController.Win32;
using Xunit;

namespace WindowController.App.Tests;

public class ProfileApplierTests
{
[Fact]
public async Task ApplyByIdAsync_ProfileMissing_ReturnsFailure_AndDoesNotScheduleRebuild()
{
var log = Serilog.Core.Logger.None;
var storePath = CreateTempProfilesJson(new ProfilesRoot { Profiles = new() });
var store = new ProfileStore(storePath, log);
store.Load();

var scheduled = 0;
var applier = CreateApplier(store, log, scheduleRebuild: () => scheduled++);

var result = await applier.ApplyByIdAsync("missing", launchMissing: false);

Assert.Equal(0, result.Applied);
Assert.Equal(0, result.Total);
Assert.False(result.Success);
Assert.Contains("プロファイルが見つかりません", result.Failures);
Assert.Equal(0, scheduled);
}

[Fact]
public async Task ApplyByNameAsync_ProfileMissing_ReturnsFailure_AndDoesNotScheduleRebuild()
{
var log = Serilog.Core.Logger.None;
var storePath = CreateTempProfilesJson(new ProfilesRoot { Profiles = new() });
var store = new ProfileStore(storePath, log);
store.Load();

var scheduled = 0;
var applier = CreateApplier(store, log, scheduleRebuild: () => scheduled++);

var result = await applier.ApplyByNameAsync("missing", launchMissing: false);

Assert.Equal(0, result.Applied);
Assert.Equal(0, result.Total);
Assert.False(result.Success);
Assert.Contains("プロファイルが見つかりません", result.Failures);
Assert.Equal(0, scheduled);
}

[Fact]
public async Task ApplyByIdAsync_InvalidWindowHandle_ReportsFailure_AndSchedulesRebuild()
{
var log = Serilog.Core.Logger.None;

var root = new ProfilesRoot
{
Settings = new Settings { SyncMinMax = 0, ShowGuiOnStartup = 1 },
Profiles = new()
{
new Profile
{
Id = "p1",
Name = "Profile1",
SyncMinMax = 0,
Windows = new()
{
new WindowEntry
{
Match = new MatchInfo
{
Exe = "notepad.exe",
Class = "",
Title = "Untitled - Notepad",
Url = "",
UrlKey = ""
},
Path = "",
Rect = new Rect { X = 0, Y = 0, W = 100, H = 100 },
MinMax = 0
}
}
}
}
};

var storePath = CreateTempProfilesJson(root);
var store = new ProfileStore(storePath, log);
store.Load();

var scheduled = 0;
var applier = CreateApplier(
store,
log,
scheduleRebuild: () => scheduled++,
candidatesProvider: () => new List<WindowCandidate>());

var result = await applier.ApplyByIdAsync("p1", launchMissing: false);

Assert.Equal(0, result.Applied);
Assert.Equal(1, result.Total);
Assert.False(result.Success);
Assert.Single(result.Failures);
Assert.Contains("見つかりません", result.Failures[0]);
Assert.Equal(1, scheduled);
}

private static ProfileApplier CreateApplier(
ProfileStore store,
ILogger log,
Action scheduleRebuild,
Func<List<WindowCandidate>>? candidatesProvider = null)
{
var enumerator = new WindowEnumerator(log);
var arranger = new WindowArranger(log);
return new ProfileApplier(
store,
enumerator,
arranger,
scheduleRebuild,
log,
candidatesProvider);
}

private static string CreateTempProfilesJson(ProfilesRoot root)
{
var dir = Path.Combine(Path.GetTempPath(), "WindowController.Tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(dir);
var path = Path.Combine(dir, "profiles.json");

var json = System.Text.Json.JsonSerializer.Serialize(root, new System.Text.Json.JsonSerializerOptions
{
WriteIndented = true,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = null
});

File.WriteAllText(path, json);
return path;
}
}
25 changes: 25 additions & 0 deletions src/WindowController.App.Tests/WindowController.App.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<UseWPF>true</UseWPF>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\WindowController.App\WindowController.App.csproj" />
</ItemGroup>

</Project>
Loading