213 lines
6.9 KiB
C#
213 lines
6.9 KiB
C#
using Moq;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Windows.Threading;
|
|
using Xunit;
|
|
using XP.Common.Logging.Interfaces;
|
|
using XplorePlane.Models;
|
|
using XplorePlane.Services.AppState;
|
|
using XplorePlane.ViewModels.Debug;
|
|
|
|
namespace XplorePlane.Tests.ViewModels
|
|
{
|
|
/// <summary>
|
|
/// EventLogViewModel 单元测试
|
|
/// Unit tests for EventLogViewModel
|
|
/// </summary>
|
|
public class EventLogViewModelTests
|
|
{
|
|
private readonly Mock<IAppStateService> _mockAppStateService;
|
|
private readonly Mock<ILoggerService> _mockLoggerService;
|
|
private readonly Dispatcher _dispatcher;
|
|
|
|
public EventLogViewModelTests()
|
|
{
|
|
_mockAppStateService = new Mock<IAppStateService>();
|
|
_mockLoggerService = new Mock<ILoggerService>();
|
|
|
|
// 创建 Dispatcher(需要在 STA 线程上)
|
|
// Create Dispatcher (needs to be on STA thread)
|
|
_dispatcher = Dispatcher.CurrentDispatcher;
|
|
|
|
// 设置 logger mock 返回自身(链式调用)
|
|
// Setup logger mock to return itself (method chaining)
|
|
_mockLoggerService.Setup(l => l.ForModule<EventLogViewModel>())
|
|
.Returns(_mockLoggerService.Object);
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_InitializesFilterOptionsWithAllStatesEnabled()
|
|
{
|
|
// Arrange & Act
|
|
var viewModel = new EventLogViewModel(
|
|
_mockAppStateService.Object,
|
|
_mockLoggerService.Object,
|
|
_dispatcher);
|
|
|
|
// Assert
|
|
Assert.Equal(8, viewModel.FilterOptions.Count);
|
|
Assert.True(viewModel.FilterOptions["MotionState"]);
|
|
Assert.True(viewModel.FilterOptions["RaySourceState"]);
|
|
Assert.True(viewModel.FilterOptions["DetectorState"]);
|
|
Assert.True(viewModel.FilterOptions["SystemState"]);
|
|
Assert.True(viewModel.FilterOptions["CameraState"]);
|
|
Assert.True(viewModel.FilterOptions["LinkedViewState"]);
|
|
Assert.True(viewModel.FilterOptions["RecipeExecutionState"]);
|
|
Assert.True(viewModel.FilterOptions["CalibrationMatrix"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void ToggleFilterCommand_TogglesFilterState()
|
|
{
|
|
// Arrange
|
|
var viewModel = new EventLogViewModel(
|
|
_mockAppStateService.Object,
|
|
_mockLoggerService.Object,
|
|
_dispatcher);
|
|
|
|
var initialState = viewModel.FilterOptions["MotionState"];
|
|
|
|
// Act
|
|
viewModel.ToggleFilterCommand.Execute("MotionState");
|
|
|
|
// Assert
|
|
Assert.Equal(!initialState, viewModel.FilterOptions["MotionState"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void SelectAllFiltersCommand_EnablesAllFilters()
|
|
{
|
|
// Arrange
|
|
var viewModel = new EventLogViewModel(
|
|
_mockAppStateService.Object,
|
|
_mockLoggerService.Object,
|
|
_dispatcher);
|
|
|
|
// 先禁用所有过滤器
|
|
// First disable all filters
|
|
viewModel.ClearAllFiltersCommand.Execute();
|
|
|
|
// Act
|
|
viewModel.SelectAllFiltersCommand.Execute();
|
|
|
|
// Assert
|
|
Assert.All(viewModel.FilterOptions.Values, value => Assert.True(value));
|
|
}
|
|
|
|
[Fact]
|
|
public void ClearAllFiltersCommand_DisablesAllFilters()
|
|
{
|
|
// Arrange
|
|
var viewModel = new EventLogViewModel(
|
|
_mockAppStateService.Object,
|
|
_mockLoggerService.Object,
|
|
_dispatcher);
|
|
|
|
// Act
|
|
viewModel.ClearAllFiltersCommand.Execute();
|
|
|
|
// Assert
|
|
Assert.All(viewModel.FilterOptions.Values, value => Assert.False(value));
|
|
}
|
|
|
|
[Fact]
|
|
public void ApplyFilter_FiltersEventLogCorrectly()
|
|
{
|
|
// Arrange
|
|
var viewModel = new EventLogViewModel(
|
|
_mockAppStateService.Object,
|
|
_mockLoggerService.Object,
|
|
_dispatcher);
|
|
|
|
// 添加测试数据
|
|
// Add test data
|
|
viewModel.EventLog.Add(new EventLogEntry
|
|
{
|
|
Timestamp = DateTime.Now,
|
|
EventType = "MotionStateChanged",
|
|
FieldName = "StageX",
|
|
OldValue = "0",
|
|
NewValue = "100",
|
|
Category = "MotionState"
|
|
});
|
|
|
|
viewModel.EventLog.Add(new EventLogEntry
|
|
{
|
|
Timestamp = DateTime.Now,
|
|
EventType = "RaySourceStateChanged",
|
|
FieldName = "IsOn",
|
|
OldValue = "False",
|
|
NewValue = "True",
|
|
Category = "RaySourceState"
|
|
});
|
|
|
|
// 禁用 RaySourceState 过滤器
|
|
// Disable RaySourceState filter
|
|
viewModel.FilterOptions["RaySourceState"] = false;
|
|
|
|
// Act
|
|
viewModel.ToggleFilterCommand.Execute("MotionState"); // 触发过滤器应用
|
|
viewModel.ToggleFilterCommand.Execute("MotionState"); // 恢复状态
|
|
|
|
// Assert
|
|
Assert.Single(viewModel.FilteredEventLog);
|
|
Assert.Equal("MotionState", viewModel.FilteredEventLog[0].Category);
|
|
}
|
|
|
|
[Fact]
|
|
public void EventLog_LimitsTo1000Records()
|
|
{
|
|
// Arrange
|
|
var viewModel = new EventLogViewModel(
|
|
_mockAppStateService.Object,
|
|
_mockLoggerService.Object,
|
|
_dispatcher);
|
|
|
|
// Act - 添加 1001 条记录
|
|
// Act - Add 1001 records
|
|
for (int i = 0; i < 1001; i++)
|
|
{
|
|
viewModel.EventLog.Add(new EventLogEntry
|
|
{
|
|
Timestamp = DateTime.Now,
|
|
EventType = "MotionStateChanged",
|
|
FieldName = "StageX",
|
|
OldValue = i.ToString(),
|
|
NewValue = (i + 1).ToString(),
|
|
Category = "MotionState"
|
|
});
|
|
}
|
|
|
|
// Assert
|
|
Assert.Equal(1000, viewModel.EventLog.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Dispose_ClearsCollections()
|
|
{
|
|
// Arrange
|
|
var viewModel = new EventLogViewModel(
|
|
_mockAppStateService.Object,
|
|
_mockLoggerService.Object,
|
|
_dispatcher);
|
|
|
|
viewModel.EventLog.Add(new EventLogEntry
|
|
{
|
|
Timestamp = DateTime.Now,
|
|
EventType = "MotionStateChanged",
|
|
FieldName = "StageX",
|
|
OldValue = "0",
|
|
NewValue = "100",
|
|
Category = "MotionState"
|
|
});
|
|
|
|
// Act
|
|
viewModel.Dispose();
|
|
|
|
// Assert
|
|
Assert.Empty(viewModel.EventLog);
|
|
Assert.Empty(viewModel.FilteredEventLog);
|
|
}
|
|
}
|
|
}
|