aboutsummaryrefslogtreecommitdiff
path: root/web/climbs_test.go
blob: 3b30c07502d53f7bfa52cb36f54deaeeb8220bad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

package web

import (
	"database/sql"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"testing"

	"github.com/martinlehoux/biking_home/official_climb"
	"github.com/martinlehoux/biking_home/ride"
	"github.com/martinlehoux/biking_home/rideanalysis"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func recordFixtureAttempts(t *testing.T, server *Server, rideID int64, climb official_climb.OfficialClimb) {
	t.Helper()
	parsed, _ := testRideForClimb(t)
	analysis := rideanalysis.Analyze(parsed, nil, []official_climb.OfficialClimb{climb}, official_climb.DefaultMatchPolicy())
	server.recordOfficialClimbAttempts(rideID, parsed, analysis)
}
func storeRideFixtureFile(t *testing.T, db *sql.DB, rideID int64) {
	t.Helper()
	parsed, _ := testRideForClimb(t)
	fitPath := filepath.Join(t.TempDir(), "ride.fit")
	fitFile, err := os.Create(fitPath)
	require.NoError(t, err)
	require.NoError(t, ride.EncodeFIT(parsed, fitFile))
	require.NoError(t, fitFile.Close())
	_, err = db.Exec("UPDATE rides SET fit_path = ? WHERE id = ?", fitPath, rideID)
	require.NoError(t, err)
}

func TestHandleClimbRendersAttemptsAndProfile(t *testing.T) {
	server, db := newWebTestServer(t)
	_, climbFixture := testRideForClimb(t)
	created, err := official_climb.Create(db, climbFixture)
	require.NoError(t, err)
	rideID := insertTestRide(t, db)
	storeRideFixtureFile(t, db, rideID)
	recordFixtureAttempts(t, server, rideID, created)

	recorder := httptest.NewRecorder()
	server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, climbDetailURL(created.ID), nil))
	require.Equal(t, http.StatusOK, recorder.Code)
	body := recorder.Body.String()
	assert.Contains(t, body, "Col de Test")
	assert.Contains(t, body, "climb-profile-data")
	assert.Contains(t, body, "Test Ride")
}

func TestHandleClimbNotFound(t *testing.T) {
	server, _ := newWebTestServer(t)
	recorder := httptest.NewRecorder()
	server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/climbs/999", nil))
	assert.Equal(t, http.StatusNotFound, recorder.Code)
}

func TestBuildClimbProfileMediansAcrossRides(t *testing.T) {
	server, db := newWebTestServer(t)
	_, climbFixture := testRideForClimb(t)
	created, err := official_climb.Create(db, climbFixture)
	require.NoError(t, err)
	rideID := insertTestRide(t, db)
	storeRideFixtureFile(t, db, rideID)
	parsed, _ := testRideForClimb(t)
	analysis := rideanalysis.Analyze(parsed, nil, []official_climb.OfficialClimb{created}, official_climb.DefaultMatchPolicy())
	attempts := rideanalysis.Attempts(rideID, analysis, parsed)

	profile := server.buildClimbProfile(created, official_climb.AggregateAttempts(attempts), attempts)
	assert.InDelta(t, 1.0, profile.DistanceKm, 0.01)
	require.Len(t, profile.Elevations, 50)
	assert.InDelta(t, 300, profile.Elevations[0], 1)
	assert.InDelta(t, 447, profile.Elevations[49], 2)
}

func TestBuildClimbProfileRouteKeepsRecordedPoints(t *testing.T) {
	server, db := newWebTestServer(t)
	parsed, climbFixture := testRideForClimb(t)
	created, err := official_climb.Create(db, climbFixture)
	require.NoError(t, err)
	rideID := insertTestRide(t, db)
	storeRideFixtureFile(t, db, rideID)
	analysis := rideanalysis.Analyze(parsed, nil, []official_climb.OfficialClimb{created}, official_climb.DefaultMatchPolicy())
	attempts := rideanalysis.Attempts(rideID, analysis, parsed)

	profile := server.buildClimbProfile(created, official_climb.AggregateAttempts(attempts), attempts)
	require.NotEmpty(t, profile.Route)
	// Full recorded precision: every matched segment point is present, not a fixed resample.
	assert.InDelta(t, parsed.Coords[0].Lon, profile.Route[0][0], 1e-6)
	assert.InDelta(t, parsed.Coords[0].Lat, profile.Route[0][1], 1e-6)
	assert.InDelta(t, parsed.Coords[1].Lon, profile.Route[1][0], 1e-6)
	assert.InDelta(t, parsed.Coords[1].Lat, profile.Route[1][1], 1e-6)
}