- Phase 2: MainWindow 3-section layout (sidebar/content/log bar), Dark/Light theme with ThemeHelper, MainViewModel with ObservableProperty/RelayCommand, tool card filtering by search + category - Phase 3: ToolEditWindow for add/edit tools, ProcessExecutionService (Process.Start + error handling), double-click + right-click context menu (run/edit), path browse dialog - Bugfix: ContextMenu commands now use PlacementTarget.Tag binding (ContextMenu in separate visual tree) - Bugfix: StaticResource converters moved to XAML before DataTemplate to fix XamlParseException on tool card render - Bugfix: Pure filenames (no path separators) treated as PATH commands, not marked invalid - Bugfix: RefreshData preserves SelectedCategory; Load() catches all exceptions; Save() wrapped in try-catch; auto-scroll log to newest entry - Tests: xUnit project with 55 tests covering models, services, converters, and view models
97 lines
2.6 KiB
C#
97 lines
2.6 KiB
C#
using PersonalToolBox.Models;
|
|
using PersonalToolBox.Services;
|
|
|
|
namespace PersonalToolBox.Tests.Services;
|
|
|
|
public class LogServiceTests
|
|
{
|
|
private readonly LogService _logService = new();
|
|
|
|
[Fact]
|
|
public void Info_AddsLogEntry()
|
|
{
|
|
_logService.Info("test message");
|
|
|
|
Assert.Single(_logService.Logs);
|
|
var entry = _logService.Logs[0];
|
|
Assert.Equal(LogLevel.Info, entry.Level);
|
|
Assert.Equal("test message", entry.Content);
|
|
Assert.True((DateTime.Now - entry.Timestamp).TotalSeconds < 2);
|
|
}
|
|
|
|
[Fact]
|
|
public void Warning_AddsLogEntry_WithWarningLevel()
|
|
{
|
|
_logService.Warning("disk full");
|
|
|
|
Assert.Single(_logService.Logs);
|
|
Assert.Equal(LogLevel.Warning, _logService.Logs[0].Level);
|
|
Assert.Equal("disk full", _logService.Logs[0].Content);
|
|
}
|
|
|
|
[Fact]
|
|
public void Error_AddsLogEntry_WithErrorLevel()
|
|
{
|
|
_logService.Error("crash detected");
|
|
|
|
Assert.Single(_logService.Logs);
|
|
Assert.Equal(LogLevel.Error, _logService.Logs[0].Level);
|
|
Assert.Equal("crash detected", _logService.Logs[0].Content);
|
|
}
|
|
|
|
[Fact]
|
|
public void MultipleLogs_AreAddedInOrder()
|
|
{
|
|
_logService.Info("first");
|
|
_logService.Warning("second");
|
|
_logService.Error("third");
|
|
|
|
Assert.Equal(3, _logService.Logs.Count);
|
|
Assert.Equal(LogLevel.Info, _logService.Logs[0].Level);
|
|
Assert.Equal(LogLevel.Warning, _logService.Logs[1].Level);
|
|
Assert.Equal(LogLevel.Error, _logService.Logs[2].Level);
|
|
}
|
|
|
|
[Fact]
|
|
public void Clear_RemovesAllEntries()
|
|
{
|
|
_logService.Info("msg");
|
|
_logService.Info("msg");
|
|
|
|
Assert.Equal(2, _logService.Logs.Count);
|
|
|
|
_logService.Clear();
|
|
|
|
Assert.Empty(_logService.Logs);
|
|
}
|
|
|
|
[Fact]
|
|
public void LogEntry_ToString_FormatsCorrectly()
|
|
{
|
|
var entry = new LogEntry
|
|
{
|
|
Timestamp = new DateTime(2026, 5, 9, 20, 0, 0),
|
|
Level = LogLevel.Warning,
|
|
Content = "path not found"
|
|
};
|
|
|
|
var str = entry.ToString();
|
|
|
|
Assert.Contains("[2026-05-09 20:00:00]", str);
|
|
Assert.Contains("[警告]", str);
|
|
Assert.Contains("path not found", str);
|
|
}
|
|
|
|
[Fact]
|
|
public void LogEntry_LevelText_ProducesChineseLabels()
|
|
{
|
|
var info = new LogEntry { Level = LogLevel.Info };
|
|
var warn = new LogEntry { Level = LogLevel.Warning };
|
|
var err = new LogEntry { Level = LogLevel.Error };
|
|
|
|
Assert.Equal("[信息]", info.LevelText);
|
|
Assert.Equal("[警告]", warn.LevelText);
|
|
Assert.Equal("[错误]", err.LevelText);
|
|
}
|
|
}
|