unit TestDataArray; interface uses System.SysUtils, DUnitX.TestFramework, Myc.Data.Series; type [TestFixture] TMyTestObject = class private function GenerateData(Count: Integer): TArray; public [Test] [TestCase('Small_NoSlide', '100, -1')] [TestCase('Small_WithSlide', '100, 50')] [TestCase('Medium_NoSlide_CrossChunk', '1500, -1')] [TestCase('Medium_WithSlide_CrossChunk', '2500, 1500')] [TestCase('Large_ExactSlide', '5000, 1024')] procedure TestChunkArray_CreateFromArray(const DataSize, MaxCount: Integer); [Test] procedure TestChunkArray_Add_And_Slide; [Test] procedure TestChunkArray_Copy_IsIndependent; [Test] procedure TestSeries_CreationAndIndexing; [Test] procedure TestSeries_Add_And_Copy; end; implementation uses System.Generics.Collections; { TMyTestObject } function TMyTestObject.GenerateData(Count: Integer): TArray; var i: Integer; begin SetLength(Result, Count); for i := 0 to Count - 1 do Result[i] := i; end; procedure TMyTestObject.TestChunkArray_Add_And_Slide; var arr: TChunkArray; newData: TArray; begin // Test sliding with single additions arr := TChunkArray.CreateFromArray([], 5); // MaxCount = 5 arr.Add(10, 5); // arr = [10] Assert.AreEqual(1, arr.Count); Assert.AreEqual(10, arr[0]); arr.Add(20, 5); // arr = [10, 20] arr.Add(30, 5); // arr = [10, 20, 30] arr.Add(40, 5); // arr = [10, 20, 30, 40] arr.Add(50, 5); // arr = [10, 20, 30, 40, 50] Assert.AreEqual(5, arr.Count); Assert.AreEqual(10, arr[0]); Assert.AreEqual(50, arr[4]); // Now, slide the window arr.Add(60, 5); // arr becomes [20, 30, 40, 50, 60] Assert.AreEqual(5, arr.Count, 'Count should remain at MaxCount'); Assert.AreEqual(20, arr[0], 'First item should be slided out'); Assert.AreEqual(60, arr[4], 'Last item should be the new one'); // Test sliding with array addition arr := TChunkArray.CreateFromArray([1, 2, 3], 5); // arr = [1, 2, 3], MaxCount = 5 newData := [4, 5, 6, 7]; arr.Add(newData, 5); // arr becomes [3, 4, 5, 6, 7] Assert.AreEqual(5, arr.Count, 'Count should be MaxCount after adding array'); Assert.AreEqual(3, arr[0]); Assert.AreEqual(7, arr[4]); end; procedure TMyTestObject.TestChunkArray_Copy_IsIndependent; const DATA_SIZE = 3000; // Approx 3 chunks MAX_COUNT_COPY = 1500; // Partial copy var original, fullCopy, partialCopy: TChunkArray; data: TArray; i: Integer; begin data := GenerateData(DATA_SIZE); original := TChunkArray.CreateFromArray(data, -1); // 1. Test full copy fullCopy := original.Copy(-1); Assert.AreEqual(original.Count, fullCopy.Count, 'Full copy count should match original'); for i := 0 to original.Count - 1 do Assert.AreEqual(original[i], fullCopy[i], 'Full copy item should match original'); // 2. Test partial copy partialCopy := original.Copy(MAX_COUNT_COPY); Assert.AreEqual(MAX_COUNT_COPY, partialCopy.Count, 'Partial copy should have MaxCount items'); for i := 0 to partialCopy.Count - 1 do // The partial copy contains the LAST items of the original Assert.AreEqual(original[i + (DATA_SIZE - MAX_COUNT_COPY)], partialCopy[i], 'Partial copy item should match last part of original'); // 3. Test independence after modification // Add an item to original. This modifies its last chunk. original.Add(9999, -1); Assert.AreEqual(DATA_SIZE + 1, original.Count, 'Original count should increment'); // Verify the full copy is unchanged. Assert.AreEqual(DATA_SIZE, fullCopy.Count, 'Full copy count should NOT change'); Assert.AreNotEqual(9999, fullCopy[fullCopy.Count - 1], 'Last item of full copy should NOT be the new item'); Assert.AreEqual(data[DATA_SIZE - 1], fullCopy[fullCopy.Count - 1], 'Last item of full copy should be original last item'); // Verify the partial copy is unchanged. Assert.AreEqual(MAX_COUNT_COPY, partialCopy.Count, 'Partial copy count should NOT change'); end; procedure TMyTestObject.TestChunkArray_CreateFromArray(const DataSize, MaxCount: Integer); var data, expectedData: TArray; arr: TChunkArray; effectiveCount: Integer; i: Integer; begin data := GenerateData(DataSize); arr := TChunkArray.CreateFromArray(data, MaxCount); if (MaxCount < 0) or (MaxCount >= DataSize) then effectiveCount := DataSize else effectiveCount := MaxCount; Assert.AreEqual(effectiveCount, arr.Count, 'Count should match effective count'); if effectiveCount = 0 then exit; // We only expect the last 'effectiveCount' items from the original data SetLength(expectedData, effectiveCount); TArray.Copy(data, expectedData, DataSize - effectiveCount, 0, effectiveCount); for i := 0 to effectiveCount - 1 do Assert.AreEqual(expectedData[i], arr.Items[i], 'Item at index should be correct'); end; procedure TMyTestObject.TestSeries_Add_And_Copy; var original, copy: TSeries; begin // 1. Create and add original := TSeries.CreateFromArray([1, 2, 3], 5); // Lookback = 5 Assert.AreEqual(Int64(3), original.TotalCount); original.Add(4, 5); // Series: [4, 3, 2, 1] original.Add(5, 5); // Series: [5, 4, 3, 2, 1] Assert.AreEqual(5, original.Count, 'Count should be 5'); Assert.AreEqual(Int64(5), original.TotalCount, 'TotalCount should be 5'); Assert.AreEqual(5, original[0], 'Index 0 should be 5'); // 2. Test sliding original.Add(6, 5); // Series: [6, 5, 4, 3, 2] Assert.AreEqual(5, original.Count, 'Count should remain 5 after slide'); Assert.AreEqual(Int64(6), original.TotalCount, 'TotalCount should be 6'); Assert.AreEqual(6, original[0], 'Index 0 should be 6'); Assert.AreEqual(2, original[4], 'Last item should be 2'); // 3. Test copy copy := original.Copy(); Assert.AreEqual(5, copy.Count, 'Copy count should match original count'); Assert.AreEqual(Int64(5), copy.TotalCount, 'Copy TotalCount should match its own count, not original TotalCount'); Assert.AreEqual(6, copy[0], 'Copy should have same data'); // 4. Test independence original.Add(7, 5); Assert.AreEqual(7, original[0], 'Original should be updated'); Assert.AreEqual(6, copy[0], 'Copy should NOT be updated'); end; procedure TMyTestObject.TestSeries_CreationAndIndexing; var series: TSeries; data: TArray; begin data := [10, 20, 30, 40, 50]; series := TSeries.CreateFromArray(data, -1); Assert.AreEqual(5, series.Count, 'Series count should be 5'); Assert.AreEqual(Int64(5), series.TotalCount, 'Series total count should be 5'); // Test reversed indexing Assert.AreEqual(50, series[0], 'Index 0 should be the last element'); Assert.AreEqual(40, series[1], 'Index 1 should be the second to last element'); Assert.AreEqual(30, series[2]); Assert.AreEqual(20, series[3]); Assert.AreEqual(10, series[4], 'Last index should be the first element'); end; initialization TDUnitX.RegisterTestFixture(TMyTestObject); end.