using Moq;
using NewLife.Studio.Core.DTOs;
using NewLife.Studio.Data;
using NewLife.Studio.Modules.DataStudio.ViewModels;
using NewLife.Studio.Store;
using Xunit;
namespace NewLife.Studio.Modules.DataStudio.Tests;
public class SqlEditorViewModelTests
{
private readonly Mock<IStoreService> _storeServiceMock;
private readonly SqlEditorViewModel _vm;
public SqlEditorViewModelTests()
{
_storeServiceMock = new Mock<IStoreService>();
_vm = new SqlEditorViewModel(_storeServiceMock.Object);
}
[Fact]
public void InitialState_HasEmptyTabs()
{
Assert.NotNull(_vm.Tabs);
Assert.Empty(_vm.Tabs);
}
[Fact]
public void InitialState_ActiveTab_IsNull()
{
Assert.Null(_vm.ActiveTab);
}
[Fact]
public void NewTabCommand_CreatesNewTab()
{
_vm.NewTabCommand.Execute(null);
Assert.Single(_vm.Tabs);
Assert.NotNull(_vm.Tabs[0]);
}
[Fact]
public void NewTabCommand_SetsActiveTab()
{
_vm.NewTabCommand.Execute(null);
Assert.NotNull(_vm.ActiveTab);
Assert.Same(_vm.Tabs[0], _vm.ActiveTab);
}
[Fact]
public void NewTabCommand_FirstTab_HasDefaultTitle()
{
_vm.NewTabCommand.Execute(null);
Assert.Equal("查询 1", _vm.Tabs[0].Title);
}
[Fact]
public void NewTabCommand_SecondTab_HasIncrementedTitle()
{
_vm.NewTabCommand.Execute(null); // "查询 1"
_vm.NewTabCommand.Execute(null); // "查询 2"
Assert.Equal(2, _vm.Tabs.Count);
Assert.Equal("查询 1", _vm.Tabs[0].Title);
Assert.Equal("查询 2", _vm.Tabs[1].Title);
}
[Fact]
public void NewTabCommand_ThirdTab_HasIncrementedTitle()
{
_vm.NewTabCommand.Execute(null);
_vm.NewTabCommand.Execute(null);
_vm.NewTabCommand.Execute(null);
Assert.Equal(3, _vm.Tabs.Count);
Assert.Equal("查询 3", _vm.Tabs[2].Title);
}
[Fact]
public void NewTabCommand_EachTabHasIndependentViewModel()
{
_vm.NewTabCommand.Execute(null);
_vm.NewTabCommand.Execute(null);
Assert.NotSame(_vm.Tabs[0].ResultGrid, _vm.Tabs[1].ResultGrid);
}
[Fact]
public void NewTabCommand_ActiveTabIsLastCreated()
{
_vm.NewTabCommand.Execute(null);
var first = _vm.ActiveTab;
_vm.NewTabCommand.Execute(null);
var second = _vm.ActiveTab;
Assert.NotSame(first, second);
Assert.Same(_vm.Tabs[1], _vm.ActiveTab);
}
[Fact]
public void CloseTabCommand_RemovesTab()
{
_vm.NewTabCommand.Execute(null);
var tab = _vm.Tabs[0];
_vm.CloseTabCommand.Execute(tab);
Assert.Empty(_vm.Tabs);
}
[Fact]
public void CloseTabCommand_WithNull_DoesNothing()
{
_vm.NewTabCommand.Execute(null);
_vm.CloseTabCommand.Execute(null);
Assert.Single(_vm.Tabs);
}
[Fact]
public void CloseTabCommand_RemovesMiddleTab_KeepsOthers()
{
_vm.NewTabCommand.Execute(null); // tabs[0]
_vm.NewTabCommand.Execute(null); // tabs[1]
_vm.NewTabCommand.Execute(null); // tabs[2]
_vm.CloseTabCommand.Execute(_vm.Tabs[1]);
Assert.Equal(2, _vm.Tabs.Count);
Assert.Equal("查询 1", _vm.Tabs[0].Title);
Assert.Equal("查询 3", _vm.Tabs[1].Title);
}
[Fact]
public async Task ExecuteAsync_WithNullActiveTab_DoesNothing()
{
var mockSession = new Mock<IDbSession>();
_vm.SetSession(mockSession.Object);
await _vm.ExecuteCommand.ExecuteAsync(null);
mockSession.Verify(
s => s.ExecuteQueryAsync(It.IsAny<QueryRequest>(), It.IsAny<CancellationToken>()),
Times.Never);
}
[Fact]
public async Task ExecuteAsync_WithNullSession_DoesNothing()
{
_vm.NewTabCommand.Execute(null);
await _vm.ExecuteCommand.ExecuteAsync(null);
// No session, no store calls either
_storeServiceMock.Verify(
s => s.AddQueryHistoryAsync(It.IsAny<QueryHistoryEntry>()),
Times.Never);
}
[Fact]
public async Task ExecuteAsync_ExecutesQuery_AndSetsResult()
{
_vm.NewTabCommand.Execute(null);
_vm.ActiveTab!.Sql = "SELECT * FROM users";
var mockSession = new Mock<IDbSession>();
var result = new QueryResult
{
Columns = new[] { new ColumnInfo { Name = "Id", DataType = "INTEGER" } },
Rows = new List<object?[]> { new object?[] { 1 } },
RowCount = 1,
ElapsedMs = 10
};
mockSession
.Setup(s => s.ExecuteQueryAsync(It.IsAny<QueryRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(result);
mockSession
.Setup(s => s.Connection)
.Returns(new ConnectionInfo { Name = "TestDB" });
_storeServiceMock
.Setup(s => s.AddQueryHistoryAsync(It.IsAny<QueryHistoryEntry>()))
.Returns(Task.CompletedTask);
_vm.SetSession(mockSession.Object);
await _vm.ExecuteCommand.ExecuteAsync(null);
Assert.NotNull(_vm.ActiveTab.Result);
Assert.Equal(1, _vm.ActiveTab.Result!.RowCount);
mockSession.Verify(
s => s.ExecuteQueryAsync(
It.Is<QueryRequest>(r => r.Sql == "SELECT * FROM users"),
It.IsAny<CancellationToken>()),
Times.Once);
}
[Fact]
public async Task ExecuteAsync_AddsQueryHistory()
{
_vm.NewTabCommand.Execute(null);
_vm.ActiveTab!.Sql = "SELECT 1";
var mockSession = new Mock<IDbSession>();
mockSession
.Setup(s => s.ExecuteQueryAsync(It.IsAny<QueryRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new QueryResult
{
Columns = [],
Rows = [],
RowCount = 0,
ElapsedMs = 5
});
mockSession
.Setup(s => s.Connection)
.Returns(new ConnectionInfo { Name = "HistoryDB" });
_storeServiceMock
.Setup(s => s.AddQueryHistoryAsync(It.IsAny<QueryHistoryEntry>()))
.Returns(Task.CompletedTask);
_vm.SetSession(mockSession.Object);
await _vm.ExecuteCommand.ExecuteAsync(null);
_storeServiceMock.Verify(
s => s.AddQueryHistoryAsync(It.Is<QueryHistoryEntry>(
h => h.Sql == "SELECT 1" && h.ConnectionName == "HistoryDB" && h.ElapsedMs == 5)),
Times.Once);
}
[Fact]
public async Task SetSession_StoresSessionInternally()
{
var mockSession = new Mock<IDbSession>();
_vm.SetSession(mockSession.Object);
// Can verify by running ExecuteAsync successfully
_vm.NewTabCommand.Execute(null);
mockSession
.Setup(s => s.ExecuteQueryAsync(It.IsAny<QueryRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new QueryResult { Columns = [], Rows = [] });
mockSession
.Setup(s => s.Connection)
.Returns(new ConnectionInfo { Name = "Test" });
_storeServiceMock
.Setup(s => s.AddQueryHistoryAsync(It.IsAny<QueryHistoryEntry>()))
.Returns(Task.CompletedTask);
// Should not throw
var exception = await Record.ExceptionAsync(() => _vm.ExecuteCommand.ExecuteAsync(null));
Assert.Null(exception);
}
[Fact]
public void Tabs_Collection_CanBeObservedExternally()
{
var addedTabs = new List<QueryTab>();
_vm.Tabs.CollectionChanged += (_, args) =>
{
if (args.NewItems != null)
foreach (QueryTab tab in args.NewItems)
addedTabs.Add(tab);
};
_vm.NewTabCommand.Execute(null);
Assert.Single(addedTabs);
}
}
|