Initial commit to new repository

This commit is contained in:
2026-04-03 18:22:19 +09:00
commit 4458bb0f52
7672 changed files with 452440 additions and 0 deletions

View File

@@ -0,0 +1,278 @@
using System.Text.Json;
using FluentAssertions;
using AxCopilot.Models;
using Xunit;
namespace AxCopilot.Tests.Services;
public class SettingsServiceTests
{
// ─── AppSettings 기본값 ──────────────────────────────────────────────────
[Fact]
public void AppSettings_DefaultHotkey_IsAltSpace()
{
new AppSettings().Hotkey.Should().Be("Alt+Space");
}
[Fact]
public void LauncherSettings_DefaultMaxResults_IsSeven()
{
new LauncherSettings().MaxResults.Should().Be(7);
}
[Fact]
public void LauncherSettings_DefaultTheme_IsSystem()
{
new LauncherSettings().Theme.Should().Be("system");
}
[Fact]
public void LauncherSettings_DefaultOpacity_IsValid()
{
var opacity = new LauncherSettings().Opacity;
opacity.Should().BeInRange(0.0, 1.0);
}
[Fact]
public void AppSettings_DefaultMonitorMismatch_IsWarn()
{
new AppSettings().MonitorMismatch.Should().Be("warn");
}
[Fact]
public void AppSettings_DefaultCleanupPeriodDays_IsThirty()
{
new AppSettings().CleanupPeriodDays.Should().Be(30);
}
[Fact]
public void AppSettings_DefaultIndexPaths_NotEmpty()
{
new AppSettings().IndexPaths.Should().NotBeEmpty();
}
// ─── LauncherSettings 테마 ───────────────────────────────────────────────
[Theory]
[InlineData("system")]
[InlineData("dark")]
[InlineData("light")]
public void LauncherSettings_Theme_AcceptsValidValues(string theme)
{
var settings = new LauncherSettings { Theme = theme };
settings.Theme.Should().Be(theme);
}
// ─── JSON 직렬화 라운드트립 ──────────────────────────────────────────────
[Fact]
public void AppSettings_Serialization_PreservesHotkey()
{
var original = new AppSettings { Hotkey = "Ctrl+Space" };
var restored = RoundTrip(original);
restored.Hotkey.Should().Be("Ctrl+Space");
}
[Fact]
public void AppSettings_Serialization_PreservesTheme()
{
var original = new AppSettings
{
Launcher = new LauncherSettings { Theme = "dark" }
};
var restored = RoundTrip(original);
restored.Launcher.Theme.Should().Be("dark");
}
[Fact]
public void AppSettings_Serialization_PreservesMaxResults()
{
var original = new AppSettings
{
Launcher = new LauncherSettings { MaxResults = 15 }
};
var restored = RoundTrip(original);
restored.Launcher.MaxResults.Should().Be(15);
}
[Fact]
public void AppSettings_Serialization_PreservesAliases()
{
var original = new AppSettings
{
Aliases =
[
new() { Key = "@test", Type = "url", Target = "https://example.com" }
]
};
var restored = RoundTrip(original);
restored.Aliases.Should().HaveCount(1);
restored.Aliases[0].Key.Should().Be("@test");
restored.Aliases[0].Target.Should().Be("https://example.com");
}
[Fact]
public void AppSettings_Serialization_PreservesCleanupPeriodDays()
{
var original = new AppSettings { CleanupPeriodDays = 14 };
var restored = RoundTrip(original);
restored.CleanupPeriodDays.Should().Be(14);
}
// ─── AliasEntry ──────────────────────────────────────────────────────────
[Fact]
public void AliasEntry_DefaultShowWindow_IsFalse()
{
new AliasEntry().ShowWindow.Should().BeFalse();
}
[Theory]
[InlineData("url")]
[InlineData("folder")]
[InlineData("app")]
[InlineData("batch")]
[InlineData("api")]
[InlineData("clipboard")]
public void AliasEntry_Type_AcceptsAllTypes(string type)
{
var entry = new AliasEntry { Type = type };
entry.Type.Should().Be(type);
}
// ─── WorkspaceProfile / WindowSnapshot ───────────────────────────────────
[Fact]
public void WorkspaceProfile_DefaultWindows_IsEmpty()
{
new WorkspaceProfile().Windows.Should().BeEmpty();
}
[Fact]
public void WindowSnapshot_DefaultShowCmd_IsNormal()
{
new WindowSnapshot().ShowCmd.Should().Be("Normal");
}
[Fact]
public void WindowSnapshot_DefaultMonitor_IsZero()
{
new WindowSnapshot().Monitor.Should().Be(0);
}
[Fact]
public void WindowRect_DefaultValues_AreZero()
{
var rect = new WindowRect();
rect.X.Should().Be(0);
rect.Y.Should().Be(0);
rect.Width.Should().Be(0);
rect.Height.Should().Be(0);
}
[Fact]
public void WorkspaceProfile_Serialization_RoundTrip()
{
var profile = new WorkspaceProfile
{
Name = "작업 프로필",
Windows =
[
new() { Exe = "notepad.exe", ShowCmd = "Maximized", Monitor = 1 }
]
};
var json = JsonSerializer.Serialize(profile, JsonOptions);
var restored = JsonSerializer.Deserialize<WorkspaceProfile>(json, JsonOptions)!;
restored.Name.Should().Be("작업 프로필");
restored.Windows.Should().HaveCount(1);
restored.Windows[0].Exe.Should().Be("notepad.exe");
restored.Windows[0].ShowCmd.Should().Be("Maximized");
restored.Windows[0].Monitor.Should().Be(1);
}
// ─── ClipboardTransformer ────────────────────────────────────────────────
[Fact]
public void ClipboardTransformer_DefaultTimeout_IsFiveSeconds()
{
new ClipboardTransformer().Timeout.Should().Be(5000);
}
[Fact]
public void ClipboardTransformer_DefaultType_IsRegex()
{
new ClipboardTransformer().Type.Should().Be("regex");
}
[Fact]
public void NormalizeLlmThresholds_ClampsConfiguredValues()
{
var llm = new LlmSettings
{
ReadOnlySignatureLoopThreshold = 1,
ReadOnlyStagnationThreshold = 99,
NoProgressRecoveryThreshold = 2,
NoProgressAbortThreshold = 200,
NoProgressRecoveryMaxRetries = 9,
ToolExecutionTimeoutMs = 1000
};
InvokeNormalizeLlmThresholds(llm);
llm.ReadOnlySignatureLoopThreshold.Should().Be(2);
llm.ReadOnlyStagnationThreshold.Should().Be(20);
llm.NoProgressRecoveryThreshold.Should().Be(4);
llm.NoProgressAbortThreshold.Should().Be(50);
llm.NoProgressRecoveryMaxRetries.Should().Be(5);
llm.ToolExecutionTimeoutMs.Should().Be(5000);
}
[Fact]
public void NormalizeLlmThresholds_PreservesZeroAsUnset()
{
var llm = new LlmSettings
{
ReadOnlySignatureLoopThreshold = 0,
ReadOnlyStagnationThreshold = 0,
NoProgressRecoveryThreshold = 0,
NoProgressAbortThreshold = 0,
NoProgressRecoveryMaxRetries = 0,
ToolExecutionTimeoutMs = 0
};
InvokeNormalizeLlmThresholds(llm);
llm.ReadOnlySignatureLoopThreshold.Should().Be(0);
llm.ReadOnlyStagnationThreshold.Should().Be(0);
llm.NoProgressRecoveryThreshold.Should().Be(0);
llm.NoProgressAbortThreshold.Should().Be(0);
llm.NoProgressRecoveryMaxRetries.Should().Be(0);
llm.ToolExecutionTimeoutMs.Should().Be(0);
}
// ─── Helpers ─────────────────────────────────────────────────────────────
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = false,
PropertyNameCaseInsensitive = true
};
private static AppSettings RoundTrip(AppSettings original)
{
var json = JsonSerializer.Serialize(original, JsonOptions);
return JsonSerializer.Deserialize<AppSettings>(json, JsonOptions)!;
}
private static void InvokeNormalizeLlmThresholds(LlmSettings llm)
{
var method = typeof(AxCopilot.Services.SettingsService)
.GetMethod("NormalizeLlmThresholds", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
method.Should().NotBeNull();
method!.Invoke(null, [llm]);
}
}