using SportsDivision.Application.Services; namespace SportsDivision.Application.Tests; public class ScoringServiceTests { private readonly ScoringService _service; public ScoringServiceTests() { // ScoringService is needed; CalculatePoints is a pure method so we can pass nulls for unused deps _service = new ScoringService(null!, null!); } // World Athletics scoring formula tests // Track: Points = A * (B - T)^C where T = time in seconds // Field/Jump: Points = A * (P - B)^C where P = performance (distance/height) [Fact] public void CalculatePoints_Track_BasicCalculation() { // Example: A=24.63, B=18.0, C=1.81, T=10.0 (100m time) // Points = 24.63 * (18.0 - 10.0)^1.81 decimal a = 24.63m; decimal b = 18.0m; decimal c = 1.81m; decimal time = 10.0m; var points = _service.CalculatePoints(time, a, b, c, isTrack: true); // (18.0 - 10.0) = 8.0 // 8.0^1.81 ≈ 49.33 // 24.63 * 49.33 ≈ 1215 Assert.True(points > 0); Assert.True(points > 1000, $"Expected > 1000 for elite 100m time, got {points}"); } [Fact] public void CalculatePoints_Track_SlowerTimeLowerPoints() { decimal a = 24.63m; decimal b = 18.0m; decimal c = 1.81m; var fastPoints = _service.CalculatePoints(10.0m, a, b, c, isTrack: true); var slowPoints = _service.CalculatePoints(12.0m, a, b, c, isTrack: true); Assert.True(fastPoints > slowPoints, $"Fast time ({fastPoints}) should score more than slow time ({slowPoints})"); } [Fact] public void CalculatePoints_Track_TimeEqualsB_ReturnsZero() { // When T = B, diff = 0, points should be 0 decimal a = 24.63m; decimal b = 18.0m; decimal c = 1.81m; var points = _service.CalculatePoints(18.0m, a, b, c, isTrack: true); Assert.Equal(0, points); } [Fact] public void CalculatePoints_Track_TimeExceedsB_ReturnsZero() { // When T > B, diff is negative, should return 0 decimal a = 24.63m; decimal b = 18.0m; decimal c = 1.81m; var points = _service.CalculatePoints(20.0m, a, b, c, isTrack: true); Assert.Equal(0, points); } [Fact] public void CalculatePoints_Field_BasicCalculation() { // Field: Points = A * (P - B)^C // Example: A=0.14354, B=220, C=1.4, P=800 (shot put in cm) decimal a = 0.14354m; decimal b = 220m; decimal c = 1.4m; decimal performance = 800m; var points = _service.CalculatePoints(performance, a, b, c, isTrack: false); Assert.True(points > 0); } [Fact] public void CalculatePoints_Field_HigherPerformanceMorePoints() { decimal a = 0.14354m; decimal b = 220m; decimal c = 1.4m; var highPoints = _service.CalculatePoints(800m, a, b, c, isTrack: false); var lowPoints = _service.CalculatePoints(600m, a, b, c, isTrack: false); Assert.True(highPoints > lowPoints, $"Higher performance ({highPoints}) should score more than lower ({lowPoints})"); } [Fact] public void CalculatePoints_Field_PerformanceEqualsB_ReturnsZero() { decimal a = 0.14354m; decimal b = 220m; decimal c = 1.4m; var points = _service.CalculatePoints(220m, a, b, c, isTrack: false); Assert.Equal(0, points); } [Fact] public void CalculatePoints_Field_PerformanceBelowB_ReturnsZero() { decimal a = 0.14354m; decimal b = 220m; decimal c = 1.4m; var points = _service.CalculatePoints(100m, a, b, c, isTrack: false); Assert.Equal(0, points); } [Fact] public void CalculatePoints_FloorsTruncatesDecimal() { // Use values that would produce a fractional result decimal a = 1.0m; decimal b = 10.0m; decimal c = 1.0m; decimal performance = 5.0m; // Track: Points = 1.0 * (10.0 - 5.0)^1.0 = 5.0 → Floor = 5 var points = _service.CalculatePoints(performance, a, b, c, isTrack: true); Assert.Equal(5, points); } [Fact] public void CalculatePoints_Track_KnownWorldAthleticsValues() { // Men's 100m: A=25.4347, B=18, C=1.81 // 10.00s should give ~1096 points decimal a = 25.4347m; decimal b = 18.0m; decimal c = 1.81m; var points = _service.CalculatePoints(10.0m, a, b, c, isTrack: true); // Expected approximately 1096 for 10.00s 100m Assert.InRange(points, 1050, 1150); } }