TSeries
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
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.
|
||||
Reference in New Issue
Block a user