Initial commit to new repository
This commit is contained in:
278
src/AxCopilot.Tests/Services/SettingsServiceTests.cs
Normal file
278
src/AxCopilot.Tests/Services/SettingsServiceTests.cs
Normal 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]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user