981 lines
32 KiB
C#
981 lines
32 KiB
C#
using System.Collections;
|
||
using AyCode.Core.Enums;
|
||
using AyCode.Core.Extensions;
|
||
using AyCode.Core.Helpers;
|
||
using AyCode.Core.Serializers.Jsons;
|
||
using AyCode.Core.Tests.TestModels;
|
||
using AyCode.Services.Server.SignalRs;
|
||
using AyCode.Services.SignalRs;
|
||
namespace AyCode.Services.Server.Tests.SignalRs.SignalRDatasources;
|
||
|
||
#region Abstract Test Base
|
||
/// <summary>
|
||
/// Base class for SignalR DataSource tests with full round-trip coverage.
|
||
/// Tests the complete path: DataSource -> SignalRClient -> SignalRHub -> Service -> Response -> SignalRClient -> DataSource
|
||
/// Derived classes specify the serializer type and collection type.
|
||
/// </summary>
|
||
/// <typeparam name="TDataSource">The concrete DataSource type</typeparam>
|
||
/// <typeparam name="TIList">The inner list type (List or AcObservableCollection)</typeparam>
|
||
public abstract class SignalRDataSourceTestBase<TDataSource, TIList>
|
||
where TDataSource : AcSignalRDataSource<TestOrderItem, int, TIList>
|
||
where TIList : class, IList<TestOrderItem>
|
||
{
|
||
protected abstract AcSerializerOptions SerializerOption { get; }
|
||
protected abstract TDataSource CreateDataSource(TestableSignalRClient2 client, SignalRCrudTags crudTags);
|
||
protected TestLogger _logger = null!;
|
||
protected TestableSignalRHub2 _hub = null!;
|
||
protected TestableSignalRClient2 _client = null!;
|
||
protected TestSignalRService2 _service = null!;
|
||
protected SignalRCrudTags _crudTags = null!;
|
||
[TestInitialize]
|
||
public void Setup()
|
||
{
|
||
_logger = new TestLogger();
|
||
|
||
_hub = new TestableSignalRHub2();
|
||
_service = new TestSignalRService2();
|
||
_client = new TestableSignalRClient2(_hub, _logger);
|
||
|
||
_hub.SetSerializerType(SerializerOption);
|
||
_hub.RegisterService(_service, _client);
|
||
|
||
_crudTags = new SignalRCrudTags(
|
||
TestSignalRTags.DataSourceGetAll,
|
||
TestSignalRTags.DataSourceGetItem,
|
||
TestSignalRTags.DataSourceAdd,
|
||
TestSignalRTags.DataSourceUpdate,
|
||
TestSignalRTags.DataSourceRemove
|
||
);
|
||
}
|
||
|
||
#region LoadDataSource Tests
|
||
[TestMethod]
|
||
public virtual async Task LoadDataSource_ReturnsAllItems()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
Assert.AreEqual("Product A", dataSource[0].ProductName);
|
||
Assert.AreEqual("Product B", dataSource[1].ProductName);
|
||
Assert.AreEqual("Product C", dataSource[2].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadDataSource_ClearsChangeTracking_ByDefault()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
dataSource.Add(new TestOrderItem { Id = 999, ProductName = "Tracked" });
|
||
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
|
||
await dataSource.LoadDataSource();
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadDataSource_PreservesChangeTracking_WhenFalse()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 999, ProductName = "Tracked" });
|
||
await dataSource.LoadDataSource(clearChangeTracking: false);
|
||
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadDataSource_InvokesOnDataSourceLoaded()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var callbackInvoked = false;
|
||
dataSource.OnDataSourceLoaded = () => { callbackInvoked = true; return Task.CompletedTask; };
|
||
await dataSource.LoadDataSource();
|
||
|
||
Assert.IsTrue(callbackInvoked);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadDataSource_MultipleCalls_RefreshesData()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
await dataSource.LoadDataSource();
|
||
var firstCount = dataSource.Count;
|
||
|
||
await dataSource.LoadDataSource();
|
||
var secondCount = dataSource.Count;
|
||
|
||
Assert.AreEqual(firstCount, secondCount);
|
||
Assert.AreEqual(3, secondCount);
|
||
}
|
||
|
||
#endregion
|
||
#region LoadDataSourceAsync Tests
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadDataSourceAsync_LoadsDataViaCallback()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var loadCompleted = false;
|
||
dataSource.OnDataSourceLoaded = () =>
|
||
{
|
||
loadCompleted = true;
|
||
return Task.CompletedTask;
|
||
};
|
||
|
||
await dataSource.LoadDataSourceAsync();
|
||
|
||
Assert.IsTrue(TaskHelper.WaitTo(() => loadCompleted, 5000));
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
}
|
||
|
||
#endregion
|
||
#region LoadItem Tests
|
||
[TestMethod]
|
||
public virtual async Task LoadItem_ReturnsSingleItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var result = await dataSource.LoadItem(2);
|
||
|
||
Assert.IsNotNull(result);
|
||
Assert.AreEqual(2, result.Id);
|
||
Assert.AreEqual("Product B", result.ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadItem_AddsToDataSource_WhenNotExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
Assert.AreEqual(0, dataSource.Count);
|
||
|
||
await dataSource.LoadItem(1);
|
||
|
||
Assert.AreEqual(1, dataSource.Count);
|
||
Assert.AreEqual("Product A", dataSource[0].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadItem_UpdatesExisting_WhenAlreadyLoaded()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var originalItem = dataSource[0];
|
||
var reloaded = await dataSource.LoadItem(originalItem.Id);
|
||
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
Assert.IsNotNull(reloaded);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadItem_InvokesOnDataSourceItemChanged()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
ItemChangedEventArgs<TestOrderItem>? eventArgs = null;
|
||
|
||
dataSource.OnDataSourceItemChanged = args => { eventArgs = args; return Task.CompletedTask; };
|
||
await dataSource.LoadItem(1);
|
||
|
||
Assert.IsNotNull(eventArgs);
|
||
Assert.AreEqual(TrackingState.Get, eventArgs.TrackingState);
|
||
Assert.AreEqual(1, eventArgs.Item.Id);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task LoadItem_ReturnsNull_WhenNotFound()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var result = await dataSource.LoadItem(9999);
|
||
|
||
Assert.IsNull(result);
|
||
}
|
||
#endregion
|
||
#region Add Tests
|
||
[TestMethod]
|
||
public virtual async Task Add_WithAutoSave_AddsItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var newItem = new TestOrderItem { Id = 100, ProductName = "New Product", Quantity = 5, UnitPrice = 50m };
|
||
var result = await dataSource.Add(newItem, autoSave: true);
|
||
|
||
Assert.AreEqual(1, dataSource.Count);
|
||
Assert.AreEqual("New Product", result.ProductName);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Add_WithoutAutoSave_AddsToTrackingOnly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var newItem = new TestOrderItem { Id = 100, ProductName = "New Product" };
|
||
dataSource.Add(newItem);
|
||
|
||
Assert.AreEqual(1, dataSource.Count);
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
Assert.AreEqual(TrackingState.Add, dataSource.GetTrackingItems()[0].TrackingState);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Add_DuplicateId_ThrowsException()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
dataSource.Add(new TestOrderItem { Id = 100, ProductName = "First" });
|
||
|
||
Assert.ThrowsExactly<ArgumentException>(() =>
|
||
{
|
||
dataSource.Add(new TestOrderItem { Id = 100, ProductName = "Duplicate" });
|
||
});
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Add_DefaultId_ThrowsException()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
Assert.ThrowsExactly<ArgumentNullException>(() =>
|
||
{
|
||
dataSource.Add(new TestOrderItem { Id = 0, ProductName = "Invalid" });
|
||
});
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void AddRange_AddsMultipleItems()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var items = new[]
|
||
{
|
||
new TestOrderItem { Id = 101, ProductName = "Item 1" },
|
||
new TestOrderItem { Id = 102, ProductName = "Item 2" },
|
||
new TestOrderItem { Id = 103, ProductName = "Item 3" }
|
||
};
|
||
dataSource.AddRange(items);
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
}
|
||
#endregion
|
||
#region AddOrUpdate Tests
|
||
[TestMethod]
|
||
public virtual async Task AddOrUpdate_AddsNew_WhenNotExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var newItem = new TestOrderItem { Id = 200, ProductName = "Brand New" };
|
||
var result = await dataSource.AddOrUpdate(newItem, autoSave: true);
|
||
|
||
Assert.AreEqual(1, dataSource.Count);
|
||
Assert.AreEqual("Brand New", result.ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task AddOrUpdate_UpdatesExisting_WhenExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var existingId = dataSource[0].Id;
|
||
var updatedItem = new TestOrderItem { Id = existingId, ProductName = "Updated Name", Quantity = 999 };
|
||
_ = await dataSource.AddOrUpdate(updatedItem, autoSave: true);
|
||
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
Assert.AreEqual("Updated Name", dataSource[0].ProductName);
|
||
}
|
||
#endregion
|
||
#region Insert Tests
|
||
[TestMethod]
|
||
public virtual void Insert_AtIndex_InsertsCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "First" });
|
||
dataSource.Add(new TestOrderItem { Id = 3, ProductName = "Third" });
|
||
dataSource.Insert(1, new TestOrderItem { Id = 2, ProductName = "Second" });
|
||
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
Assert.AreEqual("Second", dataSource[1].ProductName);
|
||
Assert.AreEqual(3, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task Insert_WithAutoSave_SavesImmediately()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var newItem = new TestOrderItem { Id = 500, ProductName = "Inserted" };
|
||
_ = await dataSource.Insert(0, newItem, autoSave: true);
|
||
|
||
Assert.AreEqual(1, dataSource.Count);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
#endregion
|
||
#region Update Tests
|
||
[TestMethod]
|
||
public virtual async Task Update_ByIndex_UpdatesCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var updatedItem = new TestOrderItem
|
||
{
|
||
Id = dataSource[0].Id,
|
||
ProductName = "Updated Product",
|
||
Quantity = 100
|
||
};
|
||
|
||
_ = await dataSource.Update(0, updatedItem, autoSave: true);
|
||
|
||
Assert.AreEqual("Updated Product", dataSource[0].ProductName);
|
||
Assert.AreEqual(100, dataSource[0].Quantity);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task Update_ByItem_UpdatesCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var updatedItem = new TestOrderItem
|
||
{
|
||
Id = dataSource[1].Id,
|
||
ProductName = "Updated B",
|
||
Quantity = 50
|
||
};
|
||
|
||
_ = await dataSource.Update(updatedItem, autoSave: true);
|
||
|
||
Assert.AreEqual("Updated B", dataSource[1].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Indexer_Set_TracksUpdate()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Original" });
|
||
dataSource[0] = new TestOrderItem { Id = 1, ProductName = "Modified" };
|
||
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
Assert.AreEqual(TrackingState.Add, dataSource.GetTrackingItems()[0].TrackingState);
|
||
}
|
||
|
||
#endregion
|
||
#region Remove Tests
|
||
[TestMethod]
|
||
public virtual async Task Remove_ById_RemovesItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var idToRemove = dataSource[0].Id;
|
||
var result = await dataSource.Remove(idToRemove, autoSave: true);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.AreEqual(2, dataSource.Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task Remove_ByItem_RemovesItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var itemToRemove = dataSource[1];
|
||
var result = await dataSource.Remove(itemToRemove, autoSave: true);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.AreEqual(2, dataSource.Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Remove_WithoutAutoSave_TracksRemoval()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "ToRemove" });
|
||
|
||
dataSource.GetTrackingItems().Clear();
|
||
dataSource.Remove(dataSource[0]);
|
||
|
||
Assert.AreEqual(0, dataSource.Count);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
Assert.AreEqual(TrackingState.Remove, dataSource.GetTrackingItems()[0].TrackingState);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void RemoveAt_RemovesCorrectItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "First" });
|
||
dataSource.Add(new TestOrderItem { Id = 2, ProductName = "Second" });
|
||
dataSource.Add(new TestOrderItem { Id = 3, ProductName = "Third" });
|
||
|
||
dataSource.GetTrackingItems().Clear();
|
||
dataSource.RemoveAt(1);
|
||
|
||
Assert.AreEqual(2, dataSource.Count);
|
||
Assert.AreEqual("First", dataSource[0].ProductName);
|
||
Assert.AreEqual("Third", dataSource[1].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task RemoveAt_WithAutoSave_SavesImmediately()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
await dataSource.LoadDataSource();
|
||
await dataSource.RemoveAt(0, autoSave: true);
|
||
|
||
Assert.AreEqual(2, dataSource.Count);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void TryRemove_ReturnsTrue_WhenExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Test" });
|
||
var result = dataSource.TryRemove(1, out var removedItem);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.IsNotNull(removedItem);
|
||
Assert.AreEqual("Test", removedItem.ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void TryRemove_ReturnsFalse_WhenNotExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var result = dataSource.TryRemove(9999, out var removedItem);
|
||
|
||
Assert.IsFalse(result);
|
||
Assert.IsNull(removedItem);
|
||
}
|
||
#endregion
|
||
#region SaveChanges Tests
|
||
[TestMethod]
|
||
public virtual async Task SaveChanges_SavesTrackedItems()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 101, ProductName = "Item 1" });
|
||
dataSource.Add(new TestOrderItem { Id = 102, ProductName = "Item 2" });
|
||
|
||
var unsaved = await dataSource.SaveChanges();
|
||
|
||
Assert.AreEqual(0, unsaved.Count);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task SaveChangesAsync_ClearsTracking()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
dataSource.Add(new TestOrderItem { Id = 103, ProductName = "Item 3" });
|
||
|
||
await dataSource.SaveChangesAsync();
|
||
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task SaveItem_ById_SavesSpecificItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 201, ProductName = "Specific" });
|
||
var result = await dataSource.SaveItem(201);
|
||
|
||
Assert.AreEqual("Specific", result.ProductName);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task SaveItem_WithTrackingState_SavesCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var item = dataSource[0];
|
||
var result = await dataSource.SaveItem(item, TrackingState.Update);
|
||
|
||
Assert.IsNotNull(result);
|
||
}
|
||
#endregion
|
||
#region Tracking Tests
|
||
[TestMethod]
|
||
public virtual void SetTrackingStateToUpdate_MarksItemForUpdate()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Test" });
|
||
//await dataSource.SaveChanges(); // El<45>bb ments<74>k el, hogy ne Add legyen a tracking state
|
||
|
||
dataSource.SetTrackingStateToUpdate(dataSource[0]);
|
||
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
Assert.AreEqual(TrackingState.Update, dataSource.GetTrackingItems()[0].TrackingState);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void SetTrackingStateToUpdate_DoesNotChangeAddState()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "New Item" });
|
||
dataSource.SetTrackingStateToUpdate(dataSource[0]);
|
||
|
||
Assert.AreEqual(TrackingState.Add, dataSource.GetTrackingItems()[0].TrackingState);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void TryGetTrackingItem_ReturnsTrue_WhenTracked()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Tracked" });
|
||
var result = dataSource.TryGetTrackingItem(1, out var trackingItem);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.IsNotNull(trackingItem);
|
||
Assert.AreEqual(TrackingState.Add, trackingItem.TrackingState);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void TryGetTrackingItem_ReturnsFalse_WhenNotTracked()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var result = dataSource.TryGetTrackingItem(9999, out var trackingItem);
|
||
|
||
Assert.IsFalse(result);
|
||
Assert.IsNull(trackingItem);
|
||
}
|
||
#endregion
|
||
#region Rollback Tests
|
||
[TestMethod]
|
||
public virtual void TryRollbackItem_RevertsAddedItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Added" });
|
||
var result = dataSource.TryRollbackItem(1, out var originalValue);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.AreEqual(0, dataSource.Count);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task TryRollbackItem_RevertsUpdatedItem()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var originalName = dataSource[0].ProductName;
|
||
dataSource[0] = new TestOrderItem { Id = dataSource[0].Id, ProductName = "Changed" };
|
||
var result = dataSource.TryRollbackItem(dataSource[0].Id, out var originalValue);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.IsNotNull(originalValue);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Rollback_RevertsAllChanges()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Item1" });
|
||
dataSource.Add(new TestOrderItem { Id = 2, ProductName = "Item2" });
|
||
dataSource.Rollback();
|
||
|
||
Assert.AreEqual(0, dataSource.Count);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
#endregion
|
||
#region Collection Operations Tests
|
||
[TestMethod]
|
||
public virtual async Task Count_ReturnsCorrectValue()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Clear_RemovesAllItems()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Item1" });
|
||
dataSource.Add(new TestOrderItem { Id = 2, ProductName = "Item2" });
|
||
dataSource.Clear();
|
||
|
||
Assert.AreEqual(0, dataSource.Count);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Clear_WithoutClearingTracking_PreservesTracking()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Item1" });
|
||
dataSource.Clear(clearChangeTracking: false);
|
||
|
||
Assert.AreEqual(0, dataSource.Count);
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task Contains_ReturnsTrue_WhenItemExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
Assert.IsTrue(dataSource.Contains(dataSource[0]));
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Contains_ReturnsFalse_WhenItemNotExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
Assert.IsFalse(dataSource.Contains(new TestOrderItem { Id = 9999 }));
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task IndexOf_ReturnsCorrectIndex()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
Assert.AreEqual(0, dataSource.IndexOf(dataSource[0]));
|
||
Assert.AreEqual(1, dataSource.IndexOf(dataSource[1]));
|
||
Assert.AreEqual(2, dataSource.IndexOf(dataSource[2]));
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IndexOf_ById_ReturnsCorrectIndex()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 5, ProductName = "Item5" });
|
||
Assert.AreEqual(0, dataSource.IndexOf(5));
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void TryGetIndex_ReturnsTrue_WhenExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 10, ProductName = "Test" });
|
||
var result = dataSource.TryGetIndex(10, out var index);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.AreEqual(0, index);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task TryGetValue_ReturnsItem_WhenExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
await dataSource.LoadDataSource();
|
||
var result = dataSource.TryGetValue(1, out var item);
|
||
|
||
Assert.IsTrue(result);
|
||
Assert.IsNotNull(item);
|
||
Assert.AreEqual("Product A", item.ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void TryGetValue_ReturnsFalse_WhenNotExists()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var result = dataSource.TryGetValue(9999, out var item);
|
||
|
||
Assert.IsFalse(result);
|
||
Assert.IsNull(item);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task CopyTo_CopiesAllItems()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
await dataSource.LoadDataSource();
|
||
var array = new TestOrderItem[3];
|
||
dataSource.CopyTo(array);
|
||
|
||
Assert.AreEqual("Product A", array[0].ProductName);
|
||
Assert.AreEqual("Product B", array[1].ProductName);
|
||
Assert.AreEqual("Product C", array[2].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task GetEnumerator_EnumeratesAllItems()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var count = dataSource.Count();
|
||
|
||
Assert.AreEqual(3, count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task AsReadOnly_ReturnsReadOnlyCollection()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
await dataSource.LoadDataSource();
|
||
var readOnly = dataSource.AsReadOnly();
|
||
|
||
Assert.AreEqual(3, readOnly.Count);
|
||
Assert.IsInstanceOfType(readOnly, typeof(System.Collections.ObjectModel.ReadOnlyCollection<TestOrderItem>));
|
||
}
|
||
#endregion
|
||
#region Working Reference List Tests
|
||
[TestMethod]
|
||
public virtual async Task SetWorkingReferenceList_SetsNewInnerList()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
var externalList = Activator.CreateInstance<TIList>();
|
||
dataSource.SetWorkingReferenceList(externalList);
|
||
|
||
Assert.IsTrue(dataSource.HasWorkingReferenceList);
|
||
Assert.AreEqual(3, dataSource.Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task GetReferenceInnerList_ReturnsInnerList()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
await dataSource.LoadDataSource();
|
||
var innerList = dataSource.GetReferenceInnerList();
|
||
|
||
Assert.IsNotNull(innerList);
|
||
Assert.AreEqual(3, innerList.Count);
|
||
}
|
||
#endregion
|
||
#region Sync State Tests
|
||
[TestMethod]
|
||
public virtual void IsSyncing_IsFalse_Initially()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
Assert.IsFalse(dataSource.IsSyncing);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task OnSyncingStateChanged_Fires_DuringLoad()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var syncStarted = false;
|
||
var syncEnded = false;
|
||
|
||
dataSource.OnSyncingStateChanged += isSyncing =>
|
||
{
|
||
if (isSyncing) syncStarted = true;
|
||
else syncEnded = true;
|
||
};
|
||
|
||
await dataSource.LoadDataSource();
|
||
|
||
Assert.IsTrue(syncStarted);
|
||
Assert.IsTrue(syncEnded);
|
||
}
|
||
#endregion
|
||
#region Context and Filter Tests
|
||
[TestMethod]
|
||
public virtual void ContextIds_CanBeSetAndRetrieved()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var contextIds = new object[] { 1, "test", Guid.NewGuid() };
|
||
dataSource.ContextIds = contextIds;
|
||
|
||
Assert.AreEqual(3, dataSource.ContextIds?.Length);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void FilterText_CanBeSetAndRetrieved()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
dataSource.FilterText = "search term";
|
||
|
||
Assert.AreEqual("search term", dataSource.FilterText);
|
||
}
|
||
#endregion
|
||
#region IList Interface Tests
|
||
[TestMethod]
|
||
public virtual void IList_Add_ReturnsCorrectIndex()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var item = new TestOrderItem { Id = 1, ProductName = "Test" };
|
||
var index = ((IList)dataSource).Add(item);
|
||
|
||
Assert.AreEqual(0, index);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IList_Contains_WorksCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var item = new TestOrderItem { Id = 1, ProductName = "Test" };
|
||
dataSource.Add(item);
|
||
|
||
Assert.IsTrue(((IList)dataSource).Contains(item));
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IList_IndexOf_WorksCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var item = new TestOrderItem { Id = 1, ProductName = "Test" };
|
||
dataSource.Add(item);
|
||
|
||
Assert.AreEqual(0, ((IList)dataSource).IndexOf(item));
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IList_Insert_WorksCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "First" });
|
||
var newItem = new TestOrderItem { Id = 2, ProductName = "Inserted" };
|
||
|
||
((IList)dataSource).Insert(0, newItem);
|
||
|
||
Assert.AreEqual("Inserted", dataSource[0].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IList_Remove_WorksCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
var item = new TestOrderItem { Id = 1, ProductName = "Test" };
|
||
dataSource.Add(item);
|
||
|
||
((IList)dataSource).Remove(item);
|
||
Assert.AreEqual(0, dataSource.Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IList_Indexer_GetSet_WorksCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Original" });
|
||
((IList)dataSource)[0] = new TestOrderItem { Id = 1, ProductName = "Modified" };
|
||
|
||
Assert.AreEqual("Modified", dataSource[0].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void ICollection_CopyTo_WorksCorrectly()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Item1" });
|
||
dataSource.Add(new TestOrderItem { Id = 2, ProductName = "Item2" });
|
||
|
||
var array = new TestOrderItem[2];
|
||
((ICollection)dataSource).CopyTo(array, 0);
|
||
|
||
Assert.AreEqual("Item1", array[0].ProductName);
|
||
Assert.AreEqual("Item2", array[1].ProductName);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IsSynchronized_ReturnsTrue()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
Assert.IsTrue(dataSource.IsSynchronized);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void SyncRoot_IsNotNull()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
Assert.IsNotNull(dataSource.SyncRoot);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IsFixedSize_ReturnsFalse()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
Assert.IsFalse(dataSource.IsFixedSize);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void IsReadOnly_ReturnsFalse()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
Assert.IsFalse(((IList)dataSource).IsReadOnly);
|
||
}
|
||
#endregion
|
||
#region Edge Cases
|
||
[TestMethod]
|
||
public virtual async Task Indexer_OutOfRange_ThrowsException()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
await dataSource.LoadDataSource();
|
||
|
||
Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => _ = dataSource[999]);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual void Add_ThenRemove_ClearsTracking()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
var item = new TestOrderItem { Id = 1, ProductName = "Temporary" };
|
||
|
||
dataSource.Add(item);
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
|
||
dataSource.Remove(item);
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
}
|
||
|
||
[TestMethod]
|
||
public virtual async Task ComplexWorkflow_AddUpdateRemoveSave()
|
||
{
|
||
var dataSource = CreateDataSource(_client, _crudTags);
|
||
|
||
// Add items
|
||
dataSource.Add(new TestOrderItem { Id = 1, ProductName = "Item1", Quantity = 10 });
|
||
dataSource.Add(new TestOrderItem { Id = 2, ProductName = "Item2", Quantity = 20 });
|
||
Assert.AreEqual(2, dataSource.GetTrackingItems().Count);
|
||
|
||
// Save
|
||
await dataSource.SaveChanges();
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
|
||
// Update
|
||
dataSource[0] = new TestOrderItem { Id = 1, ProductName = "Updated1", Quantity = 100 };
|
||
Assert.AreEqual(1, dataSource.GetTrackingItems().Count);
|
||
Assert.AreEqual(TrackingState.Update, dataSource.GetTrackingItems()[0].TrackingState);
|
||
|
||
// Remove
|
||
dataSource.Remove(dataSource[1]);
|
||
Assert.AreEqual(2, dataSource.GetTrackingItems().Count);
|
||
|
||
// Save all changes
|
||
await dataSource.SaveChanges();
|
||
Assert.AreEqual(0, dataSource.GetTrackingItems().Count);
|
||
Assert.AreEqual(1, dataSource.Count);
|
||
}
|
||
#endregion
|
||
}
|
||
#endregion |