Files
scripts/garmin-connect-export/gcexport_test.py
2024-10-14 00:11:55 +02:00

249 lines
9.4 KiB
Python

# -*- coding: utf-8 -*-
"""
Tests for gcexport.py; Call them with this command line:
py.test gcexport_test.py
"""
from gcexport import *
from io import StringIO
def test_pace_or_speed_raw_cycling():
# 10 m/s is 36 km/h
assert pace_or_speed_raw(2, 4, 10.0) == 36.0
def test_pace_or_speed_raw_running():
# 3.33 m/s is 12 km/h is 5 min/km
assert pace_or_speed_raw(1, 4, 10.0 / 3) == 5.0
def test_pace_or_speed_formatted_cycling():
# 10 m/s is 36 km/h
assert pace_or_speed_formatted(2, 4, 10.0) == '36.0'
def test_pace_or_speed_formatted_running():
# 3.33 m/s is 12 km/h is 5 min/km
assert pace_or_speed_formatted(1, 4, 10.0 / 3) == '05:00'
def test_trunc6_more():
assert trunc6(0.123456789) == '0.123456'
def test_trunc6_less():
assert trunc6(0.123) == '0.123000'
def test_offset_date_time():
assert offset_date_time("2018-03-08 12:23:22", "2018-03-08 11:23:22") == datetime(
2018, 3, 8, 12, 23, 22, 0, FixedOffset(60, "LCL")
)
assert offset_date_time("2018-03-08 12:23:22", "2018-03-08 12:23:22") == datetime(
2018, 3, 8, 12, 23, 22, 0, FixedOffset(0, "LCL")
)
def test_datetime_from_iso():
assert datetime_from_iso("2018-03-08 12:23:22") == datetime(2018, 3, 8, 12, 23, 22, 0)
assert datetime_from_iso("2018-03-08 12:23:22.0") == datetime(2018, 3, 8, 12, 23, 22, 0)
assert datetime_from_iso("2018-03-08T12:23:22") == datetime(2018, 3, 8, 12, 23, 22, 0)
assert datetime_from_iso("2018-03-08T12:23:22.0") == datetime(2018, 3, 8, 12, 23, 22, 0)
def test_epoch_seconds_from_summary():
# activity with a beginTimestamp
with open('json/activity_2541953812_overview.json') as json_timestamp:
summary = json.load(json_timestamp)
assert summary['beginTimestamp'] == 1520508202000
assert epoch_seconds_from_summary(summary) == 1520508202
# activity with a startTimeLocal without fractions
with open('json/activity_multisport_overview.json') as json_timestamp:
summary = json.load(json_timestamp)
assert summary['beginTimestamp'] == None
assert summary['startTimeLocal'] == '2021-04-11 11:50:49'
assert epoch_seconds_from_summary(summary) == 1618134649
# activity with a startTimeLocal with fractions
summary['startTimeLocal'] = '2021-04-11 11:50:50.3'
assert epoch_seconds_from_summary(summary) == 1618134650
def test_hhmmss_from_seconds():
# check/document that no rounding happens in hhmmss_from_seconds and the caller must round itself:
# 2969.6 s are 49 minutes and 29.6 seconds
assert hhmmss_from_seconds(2969.6) == "00:49:29"
assert hhmmss_from_seconds(round(2969.6)) == "00:49:30"
def test_sanitize_filename():
assert 'all_ascii' == sanitize_filename(u'all_ascii')
assert 'deja_funf' == sanitize_filename(u'déjà fünf')
assert 'deja_' == sanitize_filename(u'déjà fünf', 5)
assert '' == sanitize_filename(u'')
assert '' == sanitize_filename(None)
with open('json/activity_emoji.json') as json_data:
details = json.load(json_data)
assert 'Biel__Pavillon' == sanitize_filename(details['activityName'])
def test_load_properties_keys():
with open('csv_header_default.properties', 'r') as prop:
csv_header_props = prop.read()
csv_columns = []
csv_headers = load_properties(csv_header_props, keys=csv_columns)
assert csv_columns[0] == 'startTimeIso'
assert csv_headers['startTimeIso'] == "Start Time"
def test_csv_write_record():
with open('json/activitylist-service.json') as json_data_1:
activities = json.load(json_data_1)
with open('json/activity_emoji.json') as json_data_2:
details = json.load(json_data_2)
with open('json/activity_types.properties', 'r') as prop_1:
activity_type_props = prop_1.read()
activity_type_name = load_properties(activity_type_props)
with open('json/event_types.properties', 'r') as prop_2:
event_type_props = prop_2.read()
event_type_name = load_properties(event_type_props)
extract = {}
extract['start_time_with_offset'] = offset_date_time("2018-03-08 12:23:22", "2018-03-08 11:23:22")
extract['end_time_with_offset'] = offset_date_time("2018-03-08 12:23:22", "2018-03-08 12:23:22")
extract['elapsed_duration'] = 42.43
extract['elapsed_seconds'] = 42
extract['samples'] = None
extract['device'] = "some device"
extract['gear'] = "some gear"
extract['hrZones'] = HR_ZONES_EMPTY
extract['hrZones'][1] = json.loads('{ "secsInZone": 1689.269, "zoneLowBoundary": 138 }')
csv_file = StringIO()
csv_filter = CsvFilter(csv_file, 'csv_header_all.properties')
csv_write_record(csv_filter, extract, activities[0], details, activity_type_name, event_type_name)
expected = '"Biel 🏛 Pavillon"'
assert csv_file.getvalue()[69 : 69 + len(expected)] == expected
def write_to_file_mock(filename, content, mode, file_time=None):
pass
def http_req_mock_device(url, post=None, headers=None):
with open('json/device_856399.json') as json_device:
return json_device.read()
def test_extract_device():
args = parse_arguments([])
with open('json/activity_2541953812.json') as json_detail:
details = json.load(json_detail)
assert u'fēnix 5 10.0.0.0' == extract_device({}, details, None, args, http_req_mock_device, write_to_file_mock)
with open('json/activity_154105348_gpx_device_null.json') as json_detail:
details = json.load(json_detail)
assert None == extract_device({}, details, None, args, http_req_mock_device, write_to_file_mock)
with open('json/activity_995784118_gpx_device_0.json') as json_detail:
details = json.load(json_detail)
assert None == extract_device({}, details, None, args, http_req_mock_device, write_to_file_mock)
def http_req_mock_zones(url, post=None, headers=None):
with open('json/activity_2541953812_zones.json') as json_zones:
return json_zones.read()
def test_load_zones():
args = parse_arguments([])
zones = load_zones('2541953812', None, args, http_req_mock_zones, write_to_file_mock)
assert 5 == len(zones)
assert 100 == zones[0]['zoneLowBoundary']
assert 138 == zones[1]['zoneLowBoundary']
assert 148 == zones[2]['zoneLowBoundary']
assert 168 == zones[3]['zoneLowBoundary']
assert 182 == zones[4]['zoneLowBoundary']
assert 2462.848 == zones[0]['secsInZone']
def test_extract_display_name():
with open('html/profile_simple.html') as html:
profile_page = html.read()
assert 'John.Doe' == extract_display_name(profile_page)
# some users reported (issue #65) to have an email address as display name
with open('html/profile_email.html') as html:
profile_page = html.read()
assert 'john.doe@email.org' == extract_display_name(profile_page)
# some users reported to have a UUID as display name:
# https://github.com/moderation/garmin-connect-export/issues/31
with open('html/profile_uuid.html') as html:
profile_page = html.read()
assert '36e29d65-715c-456b-9115-84f0b9a0c0ba' == extract_display_name(profile_page)
def test_resolve_path():
assert resolve_path('root', 'sub/{YYYY}', '2018-03-08 12:23:22') == 'root/sub/2018'
assert resolve_path('root', 'sub/{MM}', '2018-03-08 12:23:22') == 'root/sub/03'
assert resolve_path('root', 'sub/{YYYY}/{MM}', '2018-03-08 12:23:22') == 'root/sub/2018/03'
assert resolve_path('root', 'sub/{yyyy}', '2018-03-08 12:23:22') == 'root/sub/{yyyy}'
assert resolve_path('root', 'sub/{YYYYMM}', '2018-03-08 12:23:22') == 'root/sub/{YYYYMM}'
assert resolve_path('root', 'sub/all', '2018-03-08 12:23:22') == 'root/sub/all'
mock_details_multi_counter = 0
def http_req_mock_details_multi(url, post=None, headers=None):
global mock_details_multi_counter
mock_details_multi_counter += 1
if mock_details_multi_counter == 1:
with open('json/activity_multisport_detail.json') as json_stream:
return json_stream.read()
elif mock_details_multi_counter >= 2 & mock_details_multi_counter <= 6:
with open('json/activity_multisport_child.json') as json_stream:
json_string = json_stream.read()
activity_id = url.split('/')[-1]
return json_string.replace('6588349076', activity_id)
else:
raise Exception('mock_details_multi_counter has invalid value ' + str(mock_details_multi_counter))
def test_fetch_multisports():
args = parse_arguments([])
with open('json/activities-list.json') as json_detail:
activity_summaries = json.load(json_detail)
# assert state before fetch_multisports
assert activity_summaries[0]['activityId'] == 6609987243
assert activity_summaries[1]['activityId'] == 6588349056
assert activity_summaries[2]['activityId'] == 6585943400
global mock_details_multi_counter
mock_details_multi_counter = 0
fetch_multisports(activity_summaries, http_req_mock_details_multi, args)
# the entries 0/1/2 from before are now 0/1/7
assert activity_summaries[0]['activityId'] == 6609987243
assert activity_summaries[1]['activityId'] == 6588349056
assert activity_summaries[7]['activityId'] == 6585943400
# at indexes 2..6 are now the five child activities
assert activity_summaries[2]['activityId'] == 6588349067
assert activity_summaries[3]['activityId'] == 6588349072
assert activity_summaries[4]['activityId'] == 6588349076
assert activity_summaries[5]['activityId'] == 6588349079
assert activity_summaries[6]['activityId'] == 6588349081