VEU.WathBody/3-app/5-watch/FenixDataField/test-source/CoreTests.mc

140 lines
5.2 KiB
MonkeyC
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Toybox.System;
// Юнит-тесты ядра (спека api_specs/02-core.md): зоны, метрики подхода,
// таймер отдыха, гистерезис вибрации, клампы настроек, форматирование.
// Запуск — TestEntry (watch-app) в симуляторе; проверки — CoreChecks.
// Поле данных нельзя стартовать как приложение, поэтому тестовая сборка
// — отдельный манифест test-manifest.xml c watch-app-входом.
// ---------- ZoneCalc ----------
function zoneTanakaTest(c) {
var z = new ZoneCalc();
// возраст 45: (2080 − 315)/10 = 176,5 — используется точное значение ×10
c.eq(z.maxBpm10For(0, 45), 1765, "Tanaka age 45 -> 1765 (x10)");
c.eq(z.maxBpm10For(180, 45), 1800, "manual max has priority");
c.eq(z.maxBpm10For(0, 5), 1765, "age out of range -> default 45");
c.eq(z.maxBpm10For(null, null), 1765, "nulls -> default 45");
}
function zoneBoundariesTest(c) {
var z = new ZoneCalc();
// maxBpm 180 (maxBpm10 1800): 50 % = 90, 70 % = 126, 85 % = 153
c.eq(z.zoneFor(89, 1800), z.ZONE_BLUE, "89 -> blue");
c.eq(z.zoneFor(90, 1800), z.ZONE_GREEN, "90 -> green");
c.eq(z.zoneFor(125, 1800), z.ZONE_GREEN, "125 -> green");
c.eq(z.zoneFor(126, 1800), z.ZONE_YELLOW, "126 -> yellow");
c.eq(z.zoneFor(152, 1800), z.ZONE_YELLOW, "152 -> yellow");
c.eq(z.zoneFor(153, 1800), z.ZONE_RED, "153 -> red");
c.eq(z.zoneFor(null, 1800), z.ZONE_NONE, "null hr -> none");
c.eq(z.zoneFor(0, 1800), z.ZONE_NONE, "zero hr -> none");
}
// ---------- SetTracker ----------
function setAvgRoundingTest(c) {
var s = new SetTracker();
s.onSample(100);
s.onSample(101);
s.onSample(101);
c.eq(s.avgBpm(), 101, "100+101+101 -> 101 (round nearest)");
}
function setNullSkippedTest(c) {
var s = new SetTracker();
s.onSample(100);
s.onSample(null);
s.onSample(102);
c.eq(s.avgBpm(), 101, "null samples skipped -> 101");
}
function setLapResetsTest(c) {
var s = new SetTracker();
s.onSample(150);
c.eq(s.avgBpm(), 150, "before lap avg 150");
s.onLap(60000);
c.isNull(s.avgBpm(), "lap resets samples");
s.onSample(120);
c.eq(s.avgBpm(), 120, "after lap only new sample counted");
}
function setElapsedTest(c) {
var s = new SetTracker();
s.onLap(60000);
c.eq(s.elapsedMs(75500), 15500, "elapsed from lap border");
}
// ---------- RestTimer ----------
function restCountdownTest(c) {
var r = new RestTimer();
c.eq(r.isResting(60000), false, "before start not active -> false");
r.start(60000, 120);
c.eq(r.remainingMs(60000), 120000, "just started: full 120 s");
c.eq(r.remainingMs(120000), 60000, "half-way: 60 s left");
c.eq(r.remainingMs(180000), 0, "at end: 0");
c.eq(r.isResting(179999), true, "resting while remaining > 0");
c.eq(r.isResting(180000), false, "not resting at 0");
}
function restEndFiresOnceTest(c) {
var r = new RestTimer();
r.start(0, 120);
c.eq(r.onEnd(119000), false, "not ended yet");
c.eq(r.onEnd(120000), true, "fires at end");
c.eq(r.onEnd(121000), false, "fires only once");
r.start(130000, 60);
c.eq(r.onEnd(190000), true, "new start re-arms");
}
// ---------- Vibe (гистерезис красной зоны) ----------
function vibeRedHysteresisTest(c) {
var v = new Vibe();
c.eq(v.onZone(true, 0), true, "enter red -> vibrate");
c.eq(v.onZone(true, 30000), false, "still red <60 s -> no");
c.eq(v.onZone(true, 59999), false, "still red <60 s -> no");
c.eq(v.onZone(true, 61000), true, "still red >=60 s -> vibrate");
}
function vibeRedResetTest(c) {
var v = new Vibe();
c.eq(v.onZone(true, 0), true, "enter red -> vibrate");
c.eq(v.onZone(false, 10000), false, "leave red -> no vibrate");
c.eq(v.onZone(true, 20000), true, "re-enter red -> vibrate (reset)");
}
// ---------- Format ----------
function mmssTest(c) {
var f = new Format();
c.eq(f.mmss(0), "0:00", "0 -> 0:00");
c.eq(f.mmss(59999), "0:59", "59999 -> 0:59");
c.eq(f.mmss(60000), "1:00", "60000 -> 1:00");
c.eq(f.mmss(65000), "1:05", "65000 -> 1:05");
c.eq(f.mmss(600000), "10:00", "600000 -> 10:00");
c.eq(f.mmss(null), "0:00", "null -> 0:00");
c.eq(f.mmss(-5), "0:00", "negative -> 0:00");
}
function divTest(c) {
var f = new Format();
c.eq(f.div(5, 2), 2, "5/2 floor = 2");
c.eq(f.div(1, 2), 0, "1/2 floor = 0");
c.eq(f.div(600000, 1000), 600, "600000/1000 = 600");
}
// ---------- FieldSettings (клампы) ----------
function clampTest(c) {
var s = new FieldSettings();
c.eq(s.clamp(10, 30, 600, 120), 120, "rest below min -> default");
c.eq(s.clamp(600, 30, 600, 120), 600, "rest max ok");
c.eq(s.clamp(30, 30, 600, 120), 30, "rest min ok");
c.eq(s.clamp(null, 30, 600, 120), 120, "null -> default");
c.eq(s.clamp("120", 30, 600, 120), 120, "string -> default");
c.eq(s.clamp(-5, 0, 250, 0), 0, "hr below min -> default 0");
c.eq(s.clamp(250, 0, 250, 0), 250, "hr max ok");
c.eq(s.clamp(200, 14, 100, 45), 45, "age above max -> default");
c.eq(s.clamp(14, 14, 100, 45), 14, "age min ok");
}