Phase 2-3: UI layout, theme switching, CRUD tools, process execution
- 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
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
using Moq;
|
||||
using PersonalToolBox.Models;
|
||||
using PersonalToolBox.Services;
|
||||
|
||||
namespace PersonalToolBox.Tests.Services;
|
||||
|
||||
public class ProcessExecutionServiceTests
|
||||
{
|
||||
private readonly Mock<ILogService> _logServiceMock = new();
|
||||
|
||||
[Fact]
|
||||
public void Execute_NullTool_LogsError()
|
||||
{
|
||||
var service = new ProcessExecutionService(_logServiceMock.Object);
|
||||
|
||||
service.Execute(null!);
|
||||
|
||||
_logServiceMock.Verify(x => x.Error(It.Is<string>(s => s.Contains("空工具项"))), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_InvalidTool_LogsWarning()
|
||||
{
|
||||
var tool = new ToolItem
|
||||
{
|
||||
Name = "BadTool",
|
||||
ExecutablePath = @"C:\nonexistent.exe",
|
||||
IsValid = false
|
||||
};
|
||||
var service = new ProcessExecutionService(_logServiceMock.Object);
|
||||
|
||||
service.Execute(tool);
|
||||
|
||||
_logServiceMock.Verify(x => x.Warning(It.Is<string>(s => s.Contains("无法运行") && s.Contains("BadTool"))), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_ProcessFails_LogsError()
|
||||
{
|
||||
var tool = new ToolItem
|
||||
{
|
||||
Name = "FailTool",
|
||||
ExecutablePath = @"Z:\impossible_path\not_really.exe",
|
||||
IsValid = true
|
||||
};
|
||||
var service = new ProcessExecutionService(_logServiceMock.Object);
|
||||
|
||||
service.Execute(tool);
|
||||
|
||||
// Opening a non-existent file should throw and be caught
|
||||
_logServiceMock.Verify(x => x.Error(It.Is<string>(s => s.Contains("FailTool") && s.Contains("失败"))), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_Success_LogsInfo()
|
||||
{
|
||||
// Use a command that definitely exists on Windows
|
||||
var tool = new ToolItem
|
||||
{
|
||||
Name = "记事本",
|
||||
ExecutablePath = "notepad.exe",
|
||||
IsValid = true
|
||||
};
|
||||
var service = new ProcessExecutionService(_logServiceMock.Object);
|
||||
|
||||
service.Execute(tool);
|
||||
|
||||
_logServiceMock.Verify(x => x.Info(It.Is<string>(s => s.Contains("成功启动") && s.Contains("记事本"))), Times.Once);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user