mirror of
https://github.com/nicolargo/glances.git
synced 2026-09-15 14:50:17 -04:00
207 lines
8.6 KiB
JavaScript
207 lines
8.6 KiB
JavaScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { formatBytes, formatRate, formatPercent, formatCount, toFahrenheit, formatSeconds, toFixedHalfEven, formatNetworkRate, formatFixed0, formatAutoUnit, formatAutoHz } from "../../glances/outputs/static/js/v5/format.js";
|
|
|
|
test("formatBytes uses binary units", () => {
|
|
assert.equal(formatBytes(0), "0B");
|
|
assert.equal(formatBytes(1023), "1023B");
|
|
assert.equal(formatBytes(1024), "1.0K");
|
|
assert.equal(formatBytes(16417853440), "15.3G");
|
|
});
|
|
|
|
test("formatBytes survives what the API can actually send", () => {
|
|
// A rate field is null until its second cycle -- see the v5 base plugin.
|
|
assert.equal(formatBytes(null), "-");
|
|
assert.equal(formatBytes(undefined), "-");
|
|
});
|
|
|
|
test("formatRate marks per-second values", () => {
|
|
assert.equal(formatRate(1024), "1.0K/s");
|
|
assert.equal(formatRate(null), "-");
|
|
});
|
|
|
|
test("formatPercent keeps one decimal", () => {
|
|
assert.equal(formatPercent(52.5), "52.5%");
|
|
assert.equal(formatPercent(0), "0.0%");
|
|
assert.equal(formatPercent(null), "-");
|
|
});
|
|
|
|
test("formatCount is a plain integer below 1024 and K-scaled at or above it", () => {
|
|
// The TUI is the authority here: _ctx_sw_value_cell()
|
|
// (glances/plugins/cpu/render_curses_v5.py:52-70) scales at >= 1024, not
|
|
// >= 1000, matching v4's auto_unit. Counting in powers of two is odd, but
|
|
// the two outputs agreeing matters more than either being tidy.
|
|
assert.equal(formatCount(0), "0");
|
|
assert.equal(formatCount(42), "42");
|
|
assert.equal(formatCount(1023), "1023");
|
|
assert.equal(formatCount(1024), "1.0K");
|
|
assert.equal(formatCount(6860), "6.7K");
|
|
assert.equal(formatCount(1048576), "1.0M");
|
|
});
|
|
|
|
test("formatCount truncates below 1024, like the TUI's int()", () => {
|
|
// These fields are `rate`s, so the values are floats, and an idle
|
|
// machine's interrupts/s is routinely under 1024 -- i.e. this is the
|
|
// common path, not an edge case. `_ctx_sw_value_cell()`
|
|
// (glances/plugins/cpu/render_curses_v5.py) formats an unscaled counter
|
|
// with `f"{int(value)}"`, which truncates: 855.6 reads 855 there, so
|
|
// Math.round would have shown 856 in the browser for the same tick.
|
|
assert.equal(formatCount(855.6), "855");
|
|
assert.equal(formatCount(1023.9), "1023");
|
|
// At or above 1024 both sides go through one decimal and already agree.
|
|
assert.equal(formatCount(1024.9), "1.0K");
|
|
});
|
|
|
|
test("formatCount returns the missing marker for a non-number", () => {
|
|
// `rate` fields are null until their second cycle -- null IS a value the
|
|
// API sends, so this is a live path, not defensive padding.
|
|
assert.equal(formatCount(null), "-");
|
|
assert.equal(formatCount(undefined), "-");
|
|
assert.equal(formatCount("12"), "-");
|
|
});
|
|
|
|
test("toFahrenheit mirrors glances.globals.to_fahrenheit", () => {
|
|
// celsius * 1.8 + 32, and nothing else -- no rounding, no unit. The
|
|
// caller decides how to render, because gpu's missing marker is "N/A"
|
|
// while every other v5 formatter uses "-".
|
|
assert.equal(toFahrenheit(0), 32);
|
|
assert.equal(toFahrenheit(100), 212);
|
|
assert.equal(toFahrenheit(55), 131);
|
|
});
|
|
|
|
test("formatSeconds mirrors the TUI's format_seconds exactly", () => {
|
|
// glances/outputs/curses_formatters_v5.py:66-80. Each boundary on both
|
|
// sides: the unit changes at 60, 3600 and 86400.
|
|
assert.equal(formatSeconds(0), "0s");
|
|
assert.equal(formatSeconds(59), "59s");
|
|
assert.equal(formatSeconds(60), "1m00s");
|
|
assert.equal(formatSeconds(3599), "59m59s");
|
|
assert.equal(formatSeconds(3600), "1h00m");
|
|
assert.equal(formatSeconds(86399), "23h59m");
|
|
assert.equal(formatSeconds(86400), "1d00h");
|
|
assert.equal(formatSeconds(273600), "3d04h");
|
|
});
|
|
|
|
test("formatSeconds truncates like int(float(value))", () => {
|
|
assert.equal(formatSeconds(61.9), "1m01s");
|
|
assert.equal(formatSeconds("61.9"), "1m01s");
|
|
});
|
|
|
|
test("formatSeconds returns the TUI's empty string for what it cannot parse", () => {
|
|
// NOT this module's "-": format_seconds() catches TypeError/ValueError and
|
|
// returns "", and the TUI then renders nothing.
|
|
assert.equal(formatSeconds(null), "");
|
|
assert.equal(formatSeconds(undefined), "");
|
|
assert.equal(formatSeconds(""), "");
|
|
assert.equal(formatSeconds("abc"), "");
|
|
});
|
|
|
|
test("toFixedHalfEven matches CPython's float formatting, exact ties included", () => {
|
|
// Expected strings are CPython's f"{value:.{digits}f}". JS toFixed agrees
|
|
// everywhere except on an EXACT tie, which it rounds away from zero.
|
|
const cases = [
|
|
[0.15, 1, "0.1"], // stored as 0.1499999..., no tie -- a detector using value * 10 would call it one
|
|
[1.25, 1, "1.2"],
|
|
[1.35, 1, "1.4"], // stored above 1.35, no tie
|
|
[0.75, 1, "0.8"],
|
|
[42.5, 0, "42"],
|
|
[43.5, 0, "44"],
|
|
[0.5, 0, "0"],
|
|
[-54.5, 0, "-54"],
|
|
[-54.4, 0, "-54"],
|
|
[108.5, 0, "108"], // 42.5 C in Fahrenheit: 42.5 * 1.8 + 32 is exactly 108.5
|
|
];
|
|
for (const [value, digits, expected] of cases) {
|
|
assert.equal(toFixedHalfEven(value, digits), expected, `${value} at ${digits} digit(s)`);
|
|
}
|
|
});
|
|
|
|
test("formatBytes truncates below 1K like the TUI's int()", () => {
|
|
// _auto_unit() in curses_formatters_v5.py prints int(value) below 1024.
|
|
assert.equal(formatBytes(855.6), "855B");
|
|
assert.equal(formatBytes(1023.9), "1023B");
|
|
});
|
|
|
|
test("formatBytes breaks an exact one-decimal tie to even, like the TUI", () => {
|
|
assert.equal(formatBytes(1280), "1.2K"); // 1.25K exactly
|
|
assert.equal(formatBytes(1792), "1.8K"); // 1.75K exactly
|
|
});
|
|
|
|
test("formatRate inherits the TUI's sub-K truncation", () => {
|
|
assert.equal(formatRate(855.6), "855B/s"); // format_bytespers(855.6)
|
|
});
|
|
|
|
test("formatNetworkRate mirrors network's _format_rate: bits, or bytes under --byte", () => {
|
|
assert.equal(formatNetworkRate(100, false), "800b");
|
|
assert.equal(formatNetworkRate(1048576, false), "8.0Mb");
|
|
assert.equal(formatNetworkRate(524288, false), "4.0Mb");
|
|
assert.equal(formatNetworkRate(100, true), "100");
|
|
assert.equal(formatNetworkRate(1048576, true), "1.0M");
|
|
assert.equal(formatNetworkRate(524288, true), "512.0K");
|
|
assert.equal(formatNetworkRate(null, false), "-");
|
|
assert.equal(formatNetworkRate(null, true), "-");
|
|
});
|
|
|
|
test("formatFixed0 is Python's :.0f, and the usual missing marker", () => {
|
|
assert.equal(formatFixed0(42.5), "42");
|
|
assert.equal(formatFixed0(-71.2), "-71");
|
|
assert.equal(formatFixed0(1200), "1200");
|
|
assert.equal(formatFixed0(null), "-");
|
|
assert.equal(formatFixed0("ERR"), "-");
|
|
});
|
|
|
|
// The cases are auto_unit()'s own docstring (glances/globals.py:431-447) --
|
|
// the one place the v4 algorithm is specified by example.
|
|
test("formatAutoUnit mirrors v4 auto_unit", () => {
|
|
assert.equal(formatAutoUnit(613421788), "585M");
|
|
assert.equal(formatAutoUnit(5307033647), "4.94G");
|
|
assert.equal(formatAutoUnit(44968414685), "41.9G");
|
|
assert.equal(formatAutoUnit(838471403472), "781G");
|
|
assert.equal(formatAutoUnit(9683209690677), "8.81T");
|
|
// A quotient of exactly 1024 stays in the smaller unit: the loop takes the
|
|
// largest prefix whose quotient is > 1, so 1G is "1024M", not "1.0G".
|
|
assert.equal(formatAutoUnit(1073741824), "1024M");
|
|
// The trailing zero is part of the contract: a fixed-decimal string, never
|
|
// a Number round-trip that would print "1.1G".
|
|
assert.equal(formatAutoUnit(1181116006), "1.10G");
|
|
});
|
|
|
|
test("formatAutoUnit below 1K, at zero and on a missing value", () => {
|
|
// Python: `if number == 0: return '0'` -- before any division.
|
|
assert.equal(formatAutoUnit(0), "0");
|
|
// No prefix quotient is > 1, so the fallthrough formats the number itself:
|
|
// 0 decimals for an integer, 2 for a float (Python's isinstance check).
|
|
assert.equal(formatAutoUnit(500), "500");
|
|
assert.equal(formatAutoUnit(500.5), "500.50");
|
|
assert.equal(formatAutoUnit(1024), "1024");
|
|
assert.equal(formatAutoUnit(null), "-");
|
|
assert.equal(formatAutoUnit(undefined), "-");
|
|
});
|
|
|
|
// Mirrors npu/render_curses_v5.py::_auto_hz() -- base 1000, one decimal once
|
|
// scaled, a plain truncated integer below 1K.
|
|
test("formatAutoHz mirrors npu's _auto_hz: base 1000, one decimal", () => {
|
|
assert.equal(formatAutoHz(1000000000), "1.0G");
|
|
assert.equal(formatAutoHz(2000000000), "2.0G");
|
|
assert.equal(formatAutoHz(1500000000), "1.5G");
|
|
assert.equal(formatAutoHz(1000000), "1.0M");
|
|
assert.equal(formatAutoHz(1000), "1.0K");
|
|
assert.equal(formatAutoHz(999), "999");
|
|
assert.equal(formatAutoHz(0), "0");
|
|
});
|
|
|
|
test("formatAutoHz accepts a numeric string, like Python's float()", () => {
|
|
assert.equal(formatAutoHz("1"), "1");
|
|
assert.equal(formatAutoHz("2000000000"), "2.0G");
|
|
});
|
|
|
|
test('formatAutoHz returns "?" for whatever it cannot parse', () => {
|
|
// _auto_hz() catches TypeError/ValueError from float(hz) and returns "?" --
|
|
// NOT this module's usual "-" missing marker.
|
|
assert.equal(formatAutoHz(null), "?");
|
|
assert.equal(formatAutoHz(undefined), "?");
|
|
assert.equal(formatAutoHz("abc"), "?");
|
|
assert.equal(formatAutoHz(""), "?");
|
|
assert.equal(formatAutoHz(NaN), "?");
|
|
});
|