Files
MycLib/Src/Myc.Test.Trade.DataPoint.pas
T
Michael Schimmel 7f6672db24 TSeries
2025-06-11 13:33:46 +02:00

265 lines
8.5 KiB
ObjectPascal

unit Myc.Test.Trade.DataPoint;
interface
uses
System.SysUtils,
System.Classes,
DUnitX.TestFramework,
Myc.Trade.DataPoint;
type
[TestFixture]
TTestTDataSeries = class(TObject)
private
FSeries: TDataSeries<TAskBidItem>;
procedure SetupSeriesWithData;
public
[Setup]
procedure Setup;
[Teardown]
procedure Teardown;
[Test]
procedure TestSetupSeriesWithDataVerification;
[Test]
procedure TestAddAndCount;
[Test]
[IgnoreMemoryLeaks]
procedure TestAddOrderAssertion;
[Test]
procedure TestGetItemsIndexing;
[Test]
procedure TestIndexOfExistingTimeStamp;
[Test]
procedure TestIndexOfNonExistingBetween;
[Test]
procedure TestIndexOfBeforeFirstItem;
[Test]
procedure TestIndexOfAfterLastItem;
[Test]
procedure TestIndexOfExactOldestItem;
[Test]
procedure TestIndexOfExactNewestItem;
[Test]
procedure TestIndexOfEmptySeries;
[Test]
procedure TestIndexOfSingleItemSeries;
end;
implementation
{ TTestTDataSeries }
procedure TTestTDataSeries.Setup;
begin
// Managed record is implicitly initialized.
end;
procedure TTestTDataSeries.Teardown;
begin
// Ensure managed record is finalized to prevent false leak reports.
FSeries := Default(TDataSeries<TAskBidItem>);
end;
procedure TTestTDataSeries.SetupSeriesWithData;
var
i: Integer;
DataPoint: TDataPoint<TAskBidItem>;
baseTime: TDateTime;
begin
FSeries := Default(TDataSeries<TAskBidItem>);
baseTime := EncodeDate(2020, 7, 7);
// Add 10 data points with increasing timestamps.
for i := 0 to 9 do
begin
DataPoint := TDataPoint<TAskBidItem>.Create(baseTime + i, TAskBidItem.Create(i * 1.0, i * 1.0 + 0.1));
FSeries.Add(DataPoint);
end;
// Resulting state:
// Newest item: Time = baseTime + 9, Logical Index = 0
// Oldest item: Time = baseTime + 0, Logical Index = 9
end;
// Verifies that the test data setup helper works as expected.
procedure TTestTDataSeries.TestSetupSeriesWithDataVerification;
var
i: Integer;
baseTime, expectedTime: TDateTime;
expectedAsk: Single;
begin
SetupSeriesWithData;
baseTime := EncodeDate(2020, 7, 7);
Assert.AreEqual(Int64(10), FSeries.Count, 'Setup should create exactly 10 items');
// Check all items to ensure correct reverse chronological order.
for i := 0 to FSeries.Count - 1 do
begin
expectedTime := baseTime + (9 - i);
expectedAsk := Single(9 - i);
Assert.AreEqual(expectedTime, FSeries[i].Time, 'Item at logical index should have correct reversed timestamp');
Assert.AreEqual(expectedAsk, FSeries[i].Data.Ask, 'Item at logical index should have correct reversed data');
end;
end;
// Tests adding new items and the resulting count.
procedure TTestTDataSeries.TestAddAndCount;
var
DataPoint: TDataPoint<TAskBidItem>;
newTime: TDateTime;
begin
SetupSeriesWithData;
newTime := EncodeDate(2020, 7, 17);
Assert.AreEqual(Int64(10), FSeries.Count, 'Initial count should be 10');
DataPoint := TDataPoint<TAskBidItem>.Create(newTime, TAskBidItem.Create(100.0, 100.1));
FSeries.Add(DataPoint);
Assert.AreEqual(Int64(11), FSeries.Count, 'Count should be 11 after adding one more');
Assert.AreEqual(newTime, FSeries.Items[0].Time, 'Newest item should be at index 0');
end;
// Ensures that adding an item with an older timestamp raises an assertion.
procedure TTestTDataSeries.TestAddOrderAssertion;
var
olderTime: TDateTime;
begin
SetupSeriesWithData; // Newest item is at 2020-07-16
olderTime := EncodeDate(2020, 7, 15);
Assert.WillRaise(
procedure
begin
var DataPoint := TDataPoint<TAskBidItem>.Create(olderTime, TAskBidItem.Create(0.0, 0.0));
FSeries.Add(DataPoint);
end,
EAssertionFailed,
'Adding item with older timestamp should raise an assert error'
);
end;
// Verifies that the logical-to-physical index mapping is correct.
procedure TTestTDataSeries.TestGetItemsIndexing;
var
i: Integer;
expectedTime: TDateTime;
baseTime: TDateTime;
begin
SetupSeriesWithData;
baseTime := EncodeDate(2020, 7, 7);
for i := 0 to 9 do
begin
expectedTime := baseTime + (9 - i);
Assert.AreEqual(expectedTime, FSeries.Items[i].Time, 'Item at logical index should have reversed chronological time');
Assert.AreEqual(Single(9 - i), FSeries.Items[i].Data.Ask, 'Item data at logical index should match reversed insertion order');
end;
end;
// Tests finding an existing item (in this case, the oldest).
procedure TTestTDataSeries.TestIndexOfExistingTimeStamp;
var
ATimeStamp: TDateTime;
expectedIndex: Int64;
begin
SetupSeriesWithData;
ATimeStamp := EncodeDate(2020, 7, 7); // Oldest item
expectedIndex := 9;
Assert.AreEqual(expectedIndex, FSeries.IndexOf(ATimeStamp), 'IndexOf for the oldest existing item timestamp should return its correct index');
end;
// Tests finding the index for a timestamp that falls between two existing items.
procedure TTestTDataSeries.TestIndexOfNonExistingBetween;
var
ATimeStamp: TDateTime;
expectedIndex: Int64;
begin
SetupSeriesWithData;
ATimeStamp := EncodeDate(2020, 7, 7) + 0.5; // 12:00 on the day of the oldest item
expectedIndex := Int64(9); // Should find the item from 00:00
Assert.AreEqual(expectedIndex, FSeries.IndexOf(ATimeStamp), 'IndexOf for a non-existing timestamp should return the index of the immediately preceding item');
end;
// Tests finding a timestamp that is older than any item in the series.
procedure TTestTDataSeries.TestIndexOfBeforeFirstItem;
var
ATimeStamp: TDateTime;
baseTime: TDateTime;
begin
SetupSeriesWithData;
baseTime := EncodeDate(2020, 7, 7);
ATimeStamp := baseTime - 1; // A day before the oldest item
Assert.AreEqual(Int64(-1), FSeries.IndexOf(ATimeStamp), 'IndexOf for a timestamp before the oldest item should return -1');
end;
// Tests finding a timestamp that is newer than any item in the series.
procedure TTestTDataSeries.TestIndexOfAfterLastItem;
var
ATimeStamp: TDateTime;
baseTime: TDateTime;
begin
SetupSeriesWithData;
baseTime := EncodeDate(2020, 7, 7);
ATimeStamp := baseTime + 10; // A day after the newest item
Assert.AreEqual(Int64(0), FSeries.IndexOf(ATimeStamp), 'IndexOf for a timestamp after the newest item should return the index of the newest item');
end;
// Specifically tests finding the exact oldest item.
procedure TTestTDataSeries.TestIndexOfExactOldestItem;
var
ATimeStamp: TDateTime;
begin
SetupSeriesWithData;
ATimeStamp := EncodeDate(2020, 7, 7);
Assert.AreEqual(Int64(9), FSeries.IndexOf(ATimeStamp), 'IndexOf for the exact oldest timestamp should return the last index');
end;
// Specifically tests finding the exact newest item.
procedure TTestTDataSeries.TestIndexOfExactNewestItem;
var
ATimeStamp: TDateTime;
begin
SetupSeriesWithData;
ATimeStamp := EncodeDate(2020, 7, 16);
Assert.AreEqual(Int64(0), FSeries.IndexOf(ATimeStamp), 'IndexOf for the exact newest timestamp should return index 0');
end;
// Tests IndexOf on an empty series.
procedure TTestTDataSeries.TestIndexOfEmptySeries;
begin
FSeries := Default(TDataSeries<TAskBidItem>);
Assert.AreEqual(Int64(0), FSeries.Count);
Assert.AreEqual(Int64(-1), FSeries.IndexOf(Now), 'IndexOf on empty series should return -1');
end;
// Tests IndexOf on a series with only one item.
procedure TTestTDataSeries.TestIndexOfSingleItemSeries;
var
DataPoint: TDataPoint<TAskBidItem>;
testTime: TDateTime;
begin
FSeries := Default(TDataSeries<TAskBidItem>);
testTime := EncodeDate(2025, 1, 1);
DataPoint := TDataPoint<TAskBidItem>.Create(testTime, TAskBidItem.Create(1.0, 2.0));
FSeries.Add(DataPoint);
Assert.AreEqual(Int64(1), FSeries.Count);
Assert.AreEqual(Int64(0), FSeries.IndexOf(testTime), 'IndexOf for exact single item should be 0');
Assert.AreEqual(Int64(0), FSeries.IndexOf(testTime + 0.5), 'IndexOf for time after single item should be 0');
Assert.AreEqual(Int64(-1), FSeries.IndexOf(testTime - 1), 'IndexOf for time before single item should be -1');
end;
initialization
TDUnitX.RegisterTestFixture(TTestTDataSeries);
end.