Add a persisted test suite
CI / check (push) Successful in 1m56s
CI / deploy (push) Successful in 2m56s

`bundle exec rake test` (minitest, a default gem but pinned in
Gemfile for reproducibility) now covers what ad-hoc scripts kept
re-verifying by hand during development: Gpx/Fit/TrackStats parsing,
GpxStore/LiveTrackStore file/TTL logic, LiveTrackClient's payload
parsing, and app.rb's routes end to end via Rack::MockRequest.

MAPTOOL_DATA_DIR (new, app.rb) lets the suite point GPX_STORE/
LIVETRACK_STORE at a throwaway directory instead of real data/ —
without it every run would leave uploaded test files behind. Each
lib file's old `if __FILE__ == $0` self-check is now redundant with
real tests covering the same ground, so removed rather than kept as
a second copy of the same assertions. Wired into ci.yml so it isn't
just a local convenience.
This commit is contained in:
randy committed 2026-09-07 12:46:35 +02:00
1 parent a3c31ace06
commit cd4eef342b
19 files changed
+706 -174

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
require_relative "test_helper"
require "maptool/fit"
class FitTest < Minitest::Test
def le32(n)
[n].pack("l<")
end
# A minimal hand-built FIT file: header + one definition message (local
# type 0, global mesg 20 "record", fields position_lat/position_long,
# both sint32) + data messages. Exercises the header/definition/data
# framing without needing an external fixture file.
def build_fit(records)
definition = [0, 0].pack("CC") + [20].pack("S<") + [2].pack("C") +
[0, 4, 0x85].pack("C3") + [1, 4, 0x85].pack("C3")
definition_header = [0b01000000].pack("C")
data = records.map { |lat, lon| [0b00000000].pack("C") + le32(lat) + le32(lon) }.join
body = definition_header + definition + data
header = [12, 16, 0, 0].pack("C2S<") + le32(body.bytesize) + ".FIT"
header + body + "\x00\x00"
end
def write_fit(records)
path = File.join(Dir.mktmpdir, "test.fit")
File.binwrite(path, build_fit(records))
path
end
def test_parses_coordinates_from_record_messages
path = write_fit([[100_000_000, 200_000_000], [100_000_100, 200_000_100]])
geojson = Maptool::Fit.to_geojson(path)
coords = geojson["features"][0]["geometry"]["coordinates"][0]
assert_equal 2, coords.size
expected_lat = 100_000_000 * Maptool::Fit::SEMICIRCLE_TO_DEGREES
expected_lon = 200_000_000 * Maptool::Fit::SEMICIRCLE_TO_DEGREES
assert_in_delta expected_lat, coords[0][1], 1e-9
assert_in_delta expected_lon, coords[0][0], 1e-9
end
def test_kinds_is_track_when_positioned
assert_equal ["track"], Maptool::Fit.kinds(write_fit([[100_000_000, 200_000_000]]))
end
def test_a_file_with_no_positioned_records_has_no_features_or_kinds
path = write_fit([])
assert_empty Maptool::Fit.to_geojson(path)["features"]
assert_empty Maptool::Fit.kinds(path)
end
def test_garbage_input_raises_parse_error
path = File.join(Dir.mktmpdir, "garbage.fit")
File.binwrite(path, "not a fit file at all")
assert_raises(Maptool::Fit::ParseError) { Maptool::Fit.to_geojson(path) }
end
end