aboutsummaryrefslogtreecommitdiff
path: root/official_climb/attempt_test.go
blob: 147c80ba20578c1aed3f19849a684e4662ff8d12 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

package official_climb_test

import (
	"database/sql"
	"testing"
	"time"

	"github.com/jftuga/geodist"
	"github.com/martinlehoux/biking_home/internal/dbtest"
	"github.com/martinlehoux/biking_home/official_climb"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func coord(lat, lon float64) geodist.Coord {
	return geodist.Coord{Lat: lat, Lon: lon}
}

func insertRide(t *testing.T, db *sql.DB, opts ...func(*rideInsert)) int64 {
	t.Helper()
	insert := rideInsert{startDate: "2026-09-01T08:00:00Z"}
	for _, opt := range opts {
		opt(&insert)
	}
	result, err := db.Exec(`
		INSERT INTO rides (external_id, gpx_path, name, external_sport_type, start_date, distance_m, external_moving_time_s, elapsed_time_s, total_elevation_gain_m, average_speed_mps)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
	`, "strava:test-ride-"+insert.startDate, "missing.gpx", "Test Ride", "Ride", insert.startDate, 20_000, 0, 0, 0, 0)
	require.NoError(t, err)
	id, err := result.LastInsertId()
	require.NoError(t, err)
	return id
}

type rideInsert struct {
	startDate string
}

func withStartDate(startDate string) func(*rideInsert) {
	return func(r *rideInsert) { r.startDate = startDate }
}

func attemptFixture(rideID, climbID int64, occurrence int) official_climb.Attempt {
	return official_climb.Attempt{
		RideID:             rideID,
		ClimbID:            climbID,
		Occurrence:         occurrence,
		DistanceM:          3200,
		ElevationGainM:     210,
		SlopePercent:       6.5,
		Cotacol:            84.2,
		CotacolAlgoVersion: "v1",
		StartedAt:          time.Date(2026, 9, 1, 10, 0, 0, 0, time.UTC),
		EndedAt:            time.Date(2026, 9, 1, 10, 18, 30, 0, time.UTC),
	}
}

func TestReplaceRideAttemptsRoundTrip(t *testing.T) {
	db := dbtest.New(t)
	created, err := official_climb.Create(db, official_climb.OfficialClimb{Name: "Col de Test", StartCoord: coord(43.6, 5.4), EndCoord: coord(43.62, 5.42)})
	require.NoError(t, err)
	rideID := insertRide(t, db)

	require.NoError(t, official_climb.ReplaceRideAttempts(db, rideID, []official_climb.Attempt{
		attemptFixture(rideID, created.ID, 0),
		attemptFixture(rideID, created.ID, 1),
	}))

	attempts, err := official_climb.AttemptsForClimb(db, created.ID)
	require.NoError(t, err)
	require.Len(t, attempts, 2)
	assert.Equal(t, 0, attempts[0].Occurrence)
	assert.Equal(t, 1, attempts[1].Occurrence)
	assert.Equal(t, 3200.0, attempts[0].DistanceM)
	assert.Equal(t, "v1", attempts[0].CotacolAlgoVersion)
	assert.Equal(t, time.Date(2026, 9, 1, 10, 18, 30, 0, time.UTC), attempts[0].EndedAt)

	rideAttempts, err := official_climb.AttemptsForRide(db, rideID)
	require.NoError(t, err)
	require.Len(t, rideAttempts, 2)
}

func TestReplaceRideAttemptsDropsStaleRows(t *testing.T) {
	db := dbtest.New(t)
	first, err := official_climb.Create(db, official_climb.OfficialClimb{Name: "Col A", StartCoord: coord(43.6, 5.4), EndCoord: coord(43.62, 5.42)})
	require.NoError(t, err)
	second, err := official_climb.Create(db, official_climb.OfficialClimb{Name: "Col B", StartCoord: coord(43.7, 5.5), EndCoord: coord(43.72, 5.52)})
	require.NoError(t, err)
	rideID := insertRide(t, db)

	require.NoError(t, official_climb.ReplaceRideAttempts(db, rideID, []official_climb.Attempt{attemptFixture(rideID, first.ID, 0)}))
	require.NoError(t, official_climb.ReplaceRideAttempts(db, rideID, []official_climb.Attempt{attemptFixture(rideID, second.ID, 0)}))

	attempts, err := official_climb.AttemptsForClimb(db, first.ID)
	require.NoError(t, err)
	assert.Empty(t, attempts)
	attempts, err = official_climb.AttemptsForClimb(db, second.ID)
	require.NoError(t, err)
	require.Len(t, attempts, 1)
}

func TestReplaceRideAttemptsRejectsForeignRide(t *testing.T) {
	db := dbtest.New(t)
	created, err := official_climb.Create(db, official_climb.OfficialClimb{Name: "Col de Test", StartCoord: coord(43.6, 5.4), EndCoord: coord(43.62, 5.42)})
	require.NoError(t, err)
	rideID := insertRide(t, db)

	attempt := attemptFixture(rideID+1, created.ID, 0)
	err = official_climb.ReplaceRideAttempts(db, rideID, []official_climb.Attempt{attempt})
	assert.Error(t, err)
}

func TestAttemptsForClimbOrdersByRideDate(t *testing.T) {
	db := dbtest.New(t)
	created, err := official_climb.Create(db, official_climb.OfficialClimb{Name: "Col de Test", StartCoord: coord(43.6, 5.4), EndCoord: coord(43.62, 5.42)})
	require.NoError(t, err)
	newer := insertRide(t, db, withStartDate("2026-09-10T08:00:00Z"))
	older := insertRide(t, db, withStartDate("2026-09-02T08:00:00Z"))

	require.NoError(t, official_climb.ReplaceRideAttempts(db, newer, []official_climb.Attempt{attemptFixture(newer, created.ID, 0)}))
	require.NoError(t, official_climb.ReplaceRideAttempts(db, older, []official_climb.Attempt{attemptFixture(older, created.ID, 0)}))

	attempts, err := official_climb.AttemptsForClimb(db, created.ID)
	require.NoError(t, err)
	require.Len(t, attempts, 2)
	assert.Equal(t, older, attempts[0].RideID)
	assert.Equal(t, newer, attempts[1].RideID)
}