265 lines
8.5 KiB
ObjectPascal
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.
|