diff options
Diffstat (limited to 'official_climb/aggregate_test.go')
| -rw-r--r-- | official_climb/aggregate_test.go | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/official_climb/aggregate_test.go b/official_climb/aggregate_test.go new file mode 100644 index 0000000..2e051ce --- /dev/null +++ b/official_climb/aggregate_test.go @@ -0,0 +1,76 @@ +package official_climb + +import ( + "testing" + "time" + + "github.com/martinlehoux/biking_home/climb" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMedianOddAndEven(t *testing.T) { + assert.Equal(t, 3.0, Median([]float64{5, 1, 3})) + assert.Equal(t, 2.5, Median([]float64{1, 2, 3, 4})) + assert.Equal(t, 0.0, Median(nil)) +} + +func TestAggregateAttemptsUsesMedians(t *testing.T) { + attempts := []Attempt{ + {DistanceM: 3000, ElevationGainM: 200, SlopePercent: 6.7, Cotacol: 80, StartedAt: time.Date(2026, 1, 1, 8, 0, 0, 0, time.UTC), EndedAt: time.Date(2026, 1, 1, 8, 20, 0, 0, time.UTC)}, + {DistanceM: 3200, ElevationGainM: 210, SlopePercent: 6.6, Cotacol: 84, StartedAt: time.Date(2026, 2, 1, 8, 0, 0, 0, time.UTC), EndedAt: time.Date(2026, 2, 1, 8, 15, 0, 0, time.UTC)}, + {DistanceM: 6000, ElevationGainM: 900, SlopePercent: 15, Cotacol: 400, StartedAt: time.Date(2026, 3, 1, 8, 0, 0, 0, time.UTC), EndedAt: time.Date(2026, 3, 1, 8, 40, 0, 0, time.UTC)}, + } + aggregate := AggregateAttempts(attempts) + assert.Equal(t, 3, aggregate.Attempts) + assert.Equal(t, 3200.0, aggregate.DistanceM) + assert.Equal(t, 210.0, aggregate.ElevationGainM) + assert.Equal(t, 6.7, aggregate.SlopePercent) + assert.Equal(t, 84.0, aggregate.Cotacol) + require.True(t, aggregate.HasBest) + assert.Equal(t, 15*time.Minute, aggregate.BestDuration) +} + +func TestAggregateAttemptsIgnoresBrokenDurations(t *testing.T) { + attempts := []Attempt{ + {DistanceM: 3000, StartedAt: time.Date(2026, 1, 1, 8, 0, 0, 0, time.UTC), EndedAt: time.Date(2026, 1, 1, 7, 0, 0, 0, time.UTC)}, + {DistanceM: 3200, StartedAt: time.Date(2026, 2, 1, 8, 0, 0, 0, time.UTC), EndedAt: time.Date(2026, 2, 1, 8, 15, 0, 0, time.UTC)}, + } + aggregate := AggregateAttempts(attempts) + require.True(t, aggregate.HasBest) + assert.Equal(t, 15*time.Minute, aggregate.BestDuration) +} + +func TestAggregateAttemptsEmpty(t *testing.T) { + aggregate := AggregateAttempts(nil) + assert.Equal(t, 0, aggregate.Attempts) + assert.False(t, aggregate.HasBest) + assert.Equal(t, climb.CategoryNo, aggregate.Category) +} + +func TestNormalizeProfileLinearSegment(t *testing.T) { + segment := climb.Climb{Route: climb.Route{ + Distances: []float64{0, 500, 1000}, + Elevations: []float64{100, 150, 200}, + }} + samples := NormalizeProfile(segment) + require.Len(t, samples, profileSteps) + assert.InDelta(t, 100, samples[0], 0.01) + assert.InDelta(t, 200, samples[profileSteps-1], 0.01) + assert.InDelta(t, 100+100*float64(profileSteps/2)/float64(profileSteps-1), samples[profileSteps/2], 0.01) +} + +func TestMedianProfileRobustToOutlier(t *testing.T) { + straight := make([]float64, profileSteps) + for i := range straight { + straight[i] = float64(i) + } + spiked := make([]float64, profileSteps) + for i := range spiked { + spiked[i] = float64(i) + 500 + } + median := MedianProfile([][]float64{straight, spiked, straight}) + require.Len(t, median, profileSteps) + assert.InDelta(t, 10, median[10], 0.01) + assert.InDelta(t, 49, median[49], 0.01) +} |
