UNPKG

@sports-alliance/sports-lib

Version:

A Library to for importing / exporting and processing GPX, TCX, FIT and JSON files from services such as Strava, Movescount, Garmin, Polar etc

164 lines (163 loc) 7.15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SpecUtils = void 0; class Time { /** * Converts seconds to military time (HH:MM:SS) */ static secToMilitary(secondsParam, trimZeros = false) { const hours = Math.floor(secondsParam / 3600); const minutes = Math.floor(secondsParam / 60) % 60; const seconds = Math.round(secondsParam % 60); const resultAsArray = [hours, minutes, seconds]; const militaryTime = resultAsArray .map(value => (value < 10 ? '0' + value : value)) .filter((value, index) => value !== '00' || index > 0) .join(':'); if (trimZeros && militaryTime[0] === '0') { return militaryTime.slice(1); } return militaryTime; } /** * Converts military time (HH:MM:SS) to seconds */ static militaryToSec(hhMmSs) { const p = hhMmSs.split(':'); let s = 0; let m = 1; while (p.length > 0) { s += m * parseInt(p.pop(), 10); m *= 60; } return s; } } function round(value, decimals = 1) { const decimalsFactor = Math.pow(10, decimals); return Math.round(value * decimalsFactor) / decimalsFactor; } class SpecUtils { static assertEqual(actual, expected, decimals = 0) { return this.assertNearEqual(actual, expected, decimals, 0); } static assertNearEqual(actual, expected, decimals = 0, tolerancePercentage = 1) { if (actual === null || actual === undefined) { throw new Error('actual cannot be null or undefined'); } const actualRounded = round(actual, decimals); const expectedRounded = round(expected, decimals); if (!Number.isFinite(actualRounded)) { const message = `Actual is not a number. Can't compare with expected value of "${expectedRounded}"`; if (SpecUtils.THROW_ON_ERROR) { throw new Error(message); } else { console.error(message); } SpecUtils.FAILED_ASSERTS.push(new Error(message)); return; } if (actualRounded !== expectedRounded) { if (tolerancePercentage === 0) { throw new Error(`Actual "${actualRounded}" don't comply with expected "${expectedRounded}"`); } else { const tolerance = (expected * tolerancePercentage) / 100; const minExpected = round(expected - tolerance, decimals); const maxExpected = round(expected + tolerance, decimals); if (actualRounded < minExpected) { const message = `Actual "${actualRounded}" BELOW MIN expected value: "${minExpected}" for an expected value of "${expectedRounded}"`; if (SpecUtils.THROW_ON_ERROR) { throw new Error(message); } else { console.error(message); } SpecUtils.FAILED_ASSERTS.push(new Error(message)); return; } if (actualRounded > maxExpected) { const message = `Actual "${actualRounded}" ABOVE MAX expected value: "${maxExpected}" for an expected value of "${expectedRounded}"`; if (SpecUtils.THROW_ON_ERROR) { throw new Error(message); } else { console.error(message); } SpecUtils.FAILED_ASSERTS.push(new Error(message)); return; } if (SpecUtils.DEBUG_ENABLED) { console.log(`[PASS] Actual "${actualRounded}" complies expected "${expectedRounded}" with "${minExpected} < ${actualRounded} < ${maxExpected}" and tolerance "${tolerance}"`); } } } else { if (SpecUtils.DEBUG_ENABLED) { console.log(`[PASS] Actual "${actual}" complies expected "${expected}"`); } } } static assertNearEqualTime(actualTime, expectedTime, tolerancePercentage = 0.5) { if (actualTime === null || actualTime === undefined) { throw new Error('actual cannot be null or undefined'); } const expectedSeconds = typeof expectedTime === 'string' ? Time.militaryToSec(expectedTime) : expectedTime; const actualSeconds = typeof actualTime === 'string' ? Time.militaryToSec(actualTime) : actualTime; const deltaTolerance = (expectedSeconds * tolerancePercentage) / 100; const lowerTolerance = expectedSeconds - deltaTolerance; if (actualSeconds < lowerTolerance) { const message = `Actual time of "${Time.secToMilitary(actualSeconds)}" (or ${actualSeconds}s) IS LOWER THAN "${Time.secToMilitary(expectedSeconds)}" Min possible value: "${Time.secToMilitary(lowerTolerance)}" (or ${lowerTolerance}s); Delta seconds: ${deltaTolerance}`; if (SpecUtils.THROW_ON_ERROR) { throw new Error(message); } else { console.error(message); } SpecUtils.FAILED_ASSERTS.push(new Error(message)); } const highTolerance = expectedSeconds + deltaTolerance; if (actualSeconds > highTolerance) { const message = `Actual time of "${Time.secToMilitary(actualSeconds)}" (or ${actualSeconds}s) IS HIGHER THAN "${Time.secToMilitary(expectedSeconds)}". Max possible value: "${Time.secToMilitary(highTolerance)}" (or ${highTolerance}s); Delta seconds: ${deltaTolerance}`; if (SpecUtils.THROW_ON_ERROR) { throw new Error(message); } else { console.error(message); } SpecUtils.FAILED_ASSERTS.push(new Error(message)); } if (SpecUtils.DEBUG_ENABLED) { console.log(`[PASS] Actual time matches expected time tolerance (${tolerancePercentage}%) : "${Time.secToMilitary(lowerTolerance)}" < "${Time.secToMilitary(actualSeconds)}" < "${Time.secToMilitary(highTolerance)}". Expected was "${Time.secToMilitary(expectedSeconds)}"`); } } /** * Converts m/s to seconds/100m swim pace */ static speedToSwimPace(mps) { // then to s/100m return mps > 0 ? 100 / mps : null; } static startTrackAssertFailed() { SpecUtils.FAILED_ASSERTS = []; } /** * Converts mps to seconds/km */ static speedToPace(mps) { return Number.isFinite(mps) && mps > 0 ? (1 / mps) * 1000 : null; } static endTrackAssertFailed() { if (SpecUtils.DEBUG_ENABLED) { console.error(`FAILED_ASSERTS count: ${SpecUtils.FAILED_ASSERTS.length}`); } SpecUtils.FAILED_ASSERTS = []; } } exports.SpecUtils = SpecUtils; // Must be committed as "false" SpecUtils.DEBUG_ENABLED = false; // Must be committed as "true" SpecUtils.THROW_ON_ERROR = true; SpecUtils.FAILED_ASSERTS = [];