diff options
| author | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-09-27 11:41:08 +0200 |
|---|---|---|
| committer | Martin Kagamino Lehoux <martin@lehoux.net> | 2026-09-27 11:41:08 +0200 |
| commit | 36f0c229310a0527beaf24b4880b25f9afe437c2 (patch) | |
| tree | 4280768d1e7a5c8f66c3b8c957736956e196172c /ride/fit_test.go | |
| parent | 0eadc1fde03153ff4b60655f15ed86367dc6a3d3 (diff) | |
Parse FIT Course files as rides
Diffstat (limited to 'ride/fit_test.go')
| -rw-r--r-- | ride/fit_test.go | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/ride/fit_test.go b/ride/fit_test.go new file mode 100644 index 0000000..9e9e0a3 --- /dev/null +++ b/ride/fit_test.go @@ -0,0 +1,74 @@ +package ride_test + +import ( + "bytes" + "encoding/binary" + "testing" + "time" + + "github.com/martinlehoux/biking_home/ride" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tormoder/fit" +) + +func encodeFIT(t *testing.T, fileType fit.FileType, records []*fit.RecordMsg) []byte { + t.Helper() + file, err := fit.NewFile(fileType, fit.NewHeader(fit.V20, true)) + require.NoError(t, err) + file.FileId.Manufacturer = fit.ManufacturerGarmin + file.FileId.Type = fileType + file.FileId.TimeCreated = time.Date(2026, 8, 1, 7, 30, 0, 0, time.UTC) + switch fileType { + case fit.FileTypeCourse: + course, err := file.Course() + require.NoError(t, err) + course.Records = records + case fit.FileTypeActivity: + activity, err := file.Activity() + require.NoError(t, err) + activity.Records = records + } + var buf bytes.Buffer + require.NoError(t, fit.Encode(&buf, file, binary.LittleEndian)) + return buf.Bytes() +} + +func fitRecord(lat, lon, elevationM float64, ts time.Time) *fit.RecordMsg { + rec := fit.NewRecordMsg() + rec.Timestamp = ts + rec.PositionLat = fit.NewLatitudeDegrees(lat) + rec.PositionLong = fit.NewLongitudeDegrees(lon) + rec.Altitude = uint16((elevationM + 500) * 5) + rec.HeartRate = 0xFF + rec.Cadence = 0xFF + rec.Power = 0xFFFF + return rec +} + +func TestFITRideParserParsesCourseFile(t *testing.T) { + base := time.Date(2026, 8, 1, 7, 30, 0, 0, time.UTC) + data := encodeFIT(t, fit.FileTypeCourse, []*fit.RecordMsg{ + fitRecord(43.0, 5.0, 100, base), + fitRecord(43.0, 5.0, 101, base.Add(5*time.Second)), // stationary: skipped + fitRecord(43.001, 5.001, 200, base.Add(10*time.Second)), + }) + + parsed, err := (ride.FITRideParser{}).Parse(bytes.NewReader(data)) + require.NoError(t, err) + require.Equal(t, 2, parsed.Len()) + assert.Equal(t, 0.0, parsed.Distances[0]) + assert.Greater(t, parsed.Distances[1], 0.0) + assert.Equal(t, []float64{100, 200}, parsed.Elevations) + assert.Equal(t, []time.Time{base, base.Add(10 * time.Second)}, parsed.Timestamps()) + _, hasHR := parsed.HeartRates() + assert.False(t, hasHR, "course records carry no telemetry") +} + +func TestFITRideParserRejectsFileWithoutTrack(t *testing.T) { + data := encodeFIT(t, fit.FileTypeSettings, nil) + + _, err := (ride.FITRideParser{}).Parse(bytes.NewReader(data)) + require.Error(t, err) + assert.Equal(t, "fit file type is Settings, not Activity or Course", err.Error()) +} |
