Files
tooll3--t3/Core.Tests/CurveSampleCacheTests.cs
2026-07-13 13:13:17 +08:00

209 lines
8.4 KiB
C#

using T3.Core.Animation;
using T3.Core.DataTypes;
using Xunit;
namespace Core.Tests;
public class CurveSampleCacheTests
{
[Fact]
public void LinearSegment_ProducesMinimalPoints()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition
{
Value = 0.0,
InInterpolation = VDefinition.KeyInterpolation.Linear,
OutInterpolation = VDefinition.KeyInterpolation.Linear,
});
curve.AddOrUpdateV(10.0, new VDefinition
{
Value = 10.0,
InInterpolation = VDefinition.KeyInterpolation.Linear,
OutInterpolation = VDefinition.KeyInterpolation.Linear,
});
curve.SampleCache.Update(curve, 0.0, 10.0, 100.0);
// Linear segment should produce just 2 points (endpoints)
Assert.True(curve.SampleCache.PointCount <= 4,
$"Linear segment should be sparse, got {curve.SampleCache.PointCount} points");
}
[Fact]
public void ConstantSegment_ProducesStepPoints()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition
{
Value = 5.0,
InInterpolation = VDefinition.KeyInterpolation.Constant,
OutInterpolation = VDefinition.KeyInterpolation.Constant,
});
curve.AddOrUpdateV(10.0, new VDefinition
{
Value = 8.0,
InInterpolation = VDefinition.KeyInterpolation.Constant,
OutInterpolation = VDefinition.KeyInterpolation.Constant,
});
curve.SampleCache.Update(curve, 0.0, 10.0, 100.0);
// Constant: should have step-pair points, minimal count
Assert.True(curve.SampleCache.PointCount <= 6,
$"Constant segment should be sparse, got {curve.SampleCache.PointCount} points");
}
[Fact]
public void SmoothSegment_ProducesAdaptivePoints()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition
{
Value = 0.0,
InInterpolation = VDefinition.KeyInterpolation.Smooth,
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
});
curve.AddOrUpdateV(10.0, new VDefinition
{
Value = 10.0,
InInterpolation = VDefinition.KeyInterpolation.Smooth,
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
});
// At 100 pixels/unit, 10 units = 1000px, target 5px spacing → ~200 points
curve.SampleCache.Update(curve, 0.0, 10.0, 100.0);
Assert.True(curve.SampleCache.PointCount > 10,
$"Smooth segment should have many points, got {curve.SampleCache.PointCount}");
}
[Fact]
public void CacheIsReusedWhenUnchanged()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition { Value = 0.0 });
curve.AddOrUpdateV(1.0, new VDefinition { Value = 1.0 });
curve.SampleCache.Update(curve, 0.0, 1.0, 100.0);
var firstCount = curve.SampleCache.PointCount;
// Second call with same params should reuse cache
curve.SampleCache.Update(curve, 0.0, 1.0, 100.0);
Assert.Equal(firstCount, curve.SampleCache.PointCount);
}
[Fact]
public void CacheInvalidatesOnEdit()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition { Value = 0.0 });
curve.AddOrUpdateV(1.0, new VDefinition { Value = 1.0 });
curve.SampleCache.Update(curve, 0.0, 1.0, 100.0);
var firstCount = curve.SampleCache.PointCount;
// Edit: add a new keyframe
curve.AddOrUpdateV(0.5, new VDefinition
{
Value = 5.0,
InInterpolation = VDefinition.KeyInterpolation.Smooth,
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
});
curve.SampleCache.Update(curve, 0.0, 1.0, 100.0);
// Cache should rebuild with different point count
Assert.NotEqual(firstCount, curve.SampleCache.PointCount);
}
[Fact]
public void CacheInvalidatesOnZoomChange()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition
{
Value = 0.0,
InInterpolation = VDefinition.KeyInterpolation.Smooth,
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
});
curve.AddOrUpdateV(10.0, new VDefinition
{
Value = 10.0,
InInterpolation = VDefinition.KeyInterpolation.Smooth,
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
});
curve.SampleCache.Update(curve, 0.0, 10.0, 50.0);
var lowZoomCount = curve.SampleCache.PointCount;
// Double zoom → should rebuild with more points
curve.SampleCache.Update(curve, 0.0, 10.0, 200.0);
var highZoomCount = curve.SampleCache.PointCount;
Assert.True(highZoomCount > lowZoomCount,
$"Higher zoom should produce more points: low={lowZoomCount}, high={highZoomCount}");
}
[Fact]
public void CacheSurvivesSmallPan()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition { Value = 0.0 });
curve.AddOrUpdateV(10.0, new VDefinition { Value = 10.0 });
curve.SampleCache.Update(curve, 2.0, 8.0, 100.0);
var firstCount = curve.SampleCache.PointCount;
// Small pan within margin — cache should be reused (same PointCount)
curve.SampleCache.Update(curve, 2.5, 8.5, 100.0);
Assert.Equal(firstCount, curve.SampleCache.PointCount);
}
[Fact]
public void GetPointsInRange_ReturnsSubset()
{
var curve = new Curve();
curve.AddOrUpdateV(0.0, new VDefinition
{
Value = 0.0,
InInterpolation = VDefinition.KeyInterpolation.Smooth,
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
});
curve.AddOrUpdateV(10.0, new VDefinition
{
Value = 10.0,
InInterpolation = VDefinition.KeyInterpolation.Smooth,
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
});
curve.SampleCache.Update(curve, 0.0, 10.0, 100.0);
var fullRange = curve.SampleCache.GetPointsInRange(0.0, 10.0);
var halfRange = curve.SampleCache.GetPointsInRange(3.0, 7.0);
Assert.True(halfRange.Length < fullRange.Length,
$"Half range ({halfRange.Length}) should be smaller than full ({fullRange.Length})");
Assert.True(halfRange.Length > 0);
}
[Fact]
public void EmptyCurve_ProducesNoPoints()
{
var curve = new Curve();
curve.SampleCache.Update(curve, 0.0, 10.0, 100.0);
Assert.Equal(0, curve.SampleCache.PointCount);
}
[Fact]
public void SingleKey_ProducesPoints()
{
var curve = new Curve();
curve.AddOrUpdateV(5.0, new VDefinition { Value = 42.0 });
curve.SampleCache.Update(curve, 0.0, 10.0, 100.0);
Assert.True(curve.SampleCache.PointCount > 0);
}
}