aboutsummaryrefslogtreecommitdiff
path: root/ride/elevation_outlier_test.go
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-09-01 15:32:38 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-09-01 15:32:38 +0200
commit7b6bd3ae858c5d7877f9ef137a3ff3d6f71ce1fc (patch)
tree28a54e79a6d3c124adca760a38844187bc84e21b /ride/elevation_outlier_test.go
parent793d2032041335004427c10f2edb7002df20a990 (diff)
feat: Analyse and fix elevation issues
Diffstat (limited to 'ride/elevation_outlier_test.go')
-rw-r--r--ride/elevation_outlier_test.go58
1 files changed, 58 insertions, 0 deletions
diff --git a/ride/elevation_outlier_test.go b/ride/elevation_outlier_test.go
new file mode 100644
index 0000000..870be08
--- /dev/null
+++ b/ride/elevation_outlier_test.go
@@ -0,0 +1,58 @@
+package ride_test
+
+import (
+ "testing"
+
+ "github.com/martinlehoux/biking_home/ride"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestDetectElevationOutliers_TunnelSpike(t *testing.T) {
+ // Simulate ride 754 tunnel: steady then spike 46m over 7m (grade 657%), then normal.
+ distances := []float64{0, 10, 20, 27, 34} // 7m gap at idx 3
+ elevations := []float64{100, 101, 102, 148, 149}
+ outliers := ride.DetectElevationOutliers(distances, elevations, 0.5)
+ require.Len(t, outliers, 1)
+ assert.Equal(t, 2, outliers[0].StartIdx) // expanded by 1
+ assert.Equal(t, 4, outliers[0].EndIdx)
+ assert.Greater(t, outliers[0].MaxGrade, 5.0)
+}
+
+func TestDetectElevationOutliers_IgnoresSmallJitter(t *testing.T) {
+ distances := []float64{0, 0.5, 1.0, 1.5}
+ elevations := []float64{100, 100.3, 100.6, 100.9} // 0.3m over 0.5m =60% but abs de <1.5
+ outliers := ride.DetectElevationOutliers(distances, elevations, 0.5)
+ assert.Empty(t, outliers)
+}
+
+func TestDetectElevationOutliers_IgnoresGentleSlope(t *testing.T) {
+ distances := []float64{0, 10, 20, 30}
+ elevations := []float64{100, 102, 104, 106} // 20% grade
+ outliers := ride.DetectElevationOutliers(distances, elevations, 0.5)
+ assert.Empty(t, outliers)
+}
+
+func TestLinearFix_Interpolates(t *testing.T) {
+ distances := []float64{0, 10, 20, 30, 40}
+ elevations := []float64{100, 110, 999, 130, 140}
+ zones := []ride.FixZone{{StartIdx: 1, EndIdx: 3, StartKm: 0.01, EndKm: 0.03}}
+ n := ride.LinearFix(distances, elevations, zones)
+ assert.Equal(t, 1, n)
+ assert.InDelta(t, 120, elevations[2], 0.01)
+}
+
+func TestResolveIndex_ByKm(t *testing.T) {
+ distances := []float64{0, 1000, 2000, 3000}
+ idx, err := ride.ResolveIndex(distances, "1.5km")
+ require.NoError(t, err)
+ // nearest to 1500 is idx 1 or 2 (both 500 away, picks first)
+ assert.Contains(t, []int{1, 2}, idx)
+}
+
+func TestResolveIndex_ByIndex(t *testing.T) {
+ distances := []float64{0, 1000, 2000}
+ idx, err := ride.ResolveIndex(distances, "2")
+ require.NoError(t, err)
+ assert.Equal(t, 2, idx)
+}