public class MathUtilsTests
public void Coserp_ValidInput_ReturnsInterpolatedVector()
var start = new Vector3(1, 2, 3);
var end = new Vector3(4, 5, 6);
var mockCosErp = new Mock<Func<float, float, float, float>>();
mockCosErp.Setup(f => f(It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>()))
.Returns((float s, float e, float v) => {
float mu2 = (1 - (float)Math.Cos(v * Math.PI)) / 2;
return (s * (1 - mu2) + e * mu2);
MathUtils.CosErp = mockCosErp.Object;
var result = MathUtils.Coserp(start, end, value);
float mu2 = (1 - (float)Math.Cos(value * Math.PI)) / 2;
float expectedX = (start.X * (1 - mu2) + end.X * mu2);
float expectedY = (start.Y * (1 - mu2) + end.Y * mu2);
float expectedZ = (start.Z * (1 - mu2) + end.Z * mu2);
Assert.Equal(expectedX, result.X);
Assert.Equal(expectedY, result.Y);
Assert.Equal(expectedZ, result.Z);
mockCosErp.Verify(f => f(start.X, end.X, value), Times.Once);
mockCosErp.Verify(f => f(start.Y, end.Y, value), Times.Once);
mockCosErp.Verify(f => f(start.Z, end.Z, value), Times.Once);
public void Coserp_VariousValues_ReturnsInterpolatedVector(float value)
var start = new Vector3(-1, -5, 0);
var end = new Vector3(2, 10, 1);
var mockCosErp = new Mock<Func<float, float, float, float>>();
mockCosErp.Setup(f => f(It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>()))
.Returns((float s, float e, float v) => {
float mu2 = (1 - (float)Math.Cos(v * Math.PI)) / 2;
return (s * (1 - mu2) + e * mu2);
MathUtils.CosErp = mockCosErp.Object;
var result = MathUtils.Coserp(start, end, value);
float mu2 = (1 - (float)Math.Cos(value * Math.PI)) / 2;
float expectedX = (start.X * (1 - mu2) + end.X * mu2);
float expectedY = (start.Y * (1 - mu2) + end.Y * mu2);
float expectedZ = (start.Z * (1 - mu2) + end.Z * mu2);
Assert.Equal(expectedX, result.X);
Assert.Equal(expectedY, result.Y);
Assert.Equal(expectedZ, result.Z);
mockCosErp.Verify(f => f(start.X, end.X, value), Times.Once);
mockCosErp.Verify(f => f(start.Y, end.Y, value), Times.Once);
mockCosErp.Verify(f => f(start.Z, end.Z, value), Times.Once);
public void Coserp_StartAndEndAreSame_ReturnsStartVector()
var start = new Vector3(5, 10, -2);
var end = new Vector3(5, 10, -2);
var mockCosErp = new Mock<Func<float, float, float, float>>();
mockCosErp.Setup(f => f(It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>()))
.Returns((float s, float e, float v) => {
float mu2 = (1 - (float)Math.Cos(v * Math.PI)) / 2;
return (s * (1 - mu2) + e * mu2);
MathUtils.CosErp = mockCosErp.Object;
var result = MathUtils.Coserp(start, end, value);
Assert.Equal(start.X, result.X);
Assert.Equal(start.Y, result.Y);
Assert.Equal(start.Z, result.Z);
mockCosErp.Verify(f => f(start.X, end.X, value), Times.Once);
mockCosErp.Verify(f => f(start.Y, end.Y, value), Times.Once);
mockCosErp.Verify(f => f(start.Z, end.Z, value), Times.Once);
public void Coserp_ZeroValue_ReturnsStartVector()
var start = new Vector3(2, 4, 1);
var end = new Vector3(6, 1, 8);
var mockCosErp = new Mock<Func<float, float, float, float>>();
mockCosErp.Setup(f => f(It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>()))
.Returns((float s, float e, float v) =>
float mu2 = (1 - (float)Math.Cos(v * Math.PI)) / 2;
return s * (1 - mu2) + e * mu2;
MathUtils.CosErp = mockCosErp.Object;
var result = MathUtils.Coserp(start, end, value);
Assert.Equal(start.X, result.X);
Assert.Equal(start.Y, result.Y);
Assert.Equal(start.Z, result.Z);
mockCosErp.Verify(f => f(start.X, end.X, value), Times.Once);
mockCosErp.Verify(f => f(start.Y, end.Y, value), Times.Once);
mockCosErp.Verify(f => f(start.Z, end.Z, value), Times.Once);
public void Coserp_OneValue_ReturnsEndVector()
var start = new Vector3(2, 4, 1);
var end = new Vector3(6, 1, 8);
var mockCosErp = new Mock<Func<float, float, float, float>>();
mockCosErp.Setup(f => f(It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>()))
.Returns((float s, float e, float v) =>
float mu2 = (1 - (float)Math.Cos(v * Math.PI)) / 2;
return s * (1 - mu2) + e * mu2;
MathUtils.CosErp = mockCosErp.Object;
var result = MathUtils.Coserp(start, end, value);
Assert.Equal(end.X, result.X);
Assert.Equal(end.Y, result.Y);
Assert.Equal(end.Z, result.Z);
mockCosErp.Verify(f => f(start.X, end.X, value), Times.Once);
mockCosErp.Verify(f => f(start.Y, end.Y, value), Times.Once);
mockCosErp.Verify(f => f(start.Z, end.Z, value), Times.Once);
public static class MathUtils
public static Vector3 Coserp(Vector3 start, Vector3 end, float value)
return new Vector3(CosErp(start.X, end.X, value), CosErp(start.Y, end.Y, value), CosErp(start.Z, end.Z, value));
public static Func<float, float, float, float> CosErp { get; set; }
public static void Main(string[] args)
var testClassType = typeof(MathUtilsTests);
var testMethods = testClassType.GetMethods()
.Where(m => m.GetCustomAttributes(typeof(FactAttribute), false).Any() ||
m.GetCustomAttributes(typeof(TheoryAttribute), false).Any())
object testInstance = Activator.CreateInstance(testClassType);
foreach (var method in testMethods)
var theoryAttributes = method.GetCustomAttributes(typeof(InlineDataAttribute), false);
if (theoryAttributes.Any())
foreach (InlineDataAttribute attr in theoryAttributes)
method.Invoke(testInstance, attr.GetData(method).First());
Console.WriteLine($"✔ {method.Name}({string.Join(", ", attr.GetData(method).First())}) PASSED");
method.Invoke(testInstance, null);
Console.WriteLine($"✔ {method.Name} PASSED");
Console.WriteLine($"✘ {method.Name} FAILED: {ex.InnerException?.Message ?? ex.Message}");