Toggle a Diagnostics panel with i, built on the Activity readout. It swaps in for the Drive pane and shows the decoded critical_warning, power-on hours, power cycles, unsafe shutdowns, media errors and available spare with their change over the selection, and per-hour (Day) or per-day (History) temperature min/avg/max, active/idle/powered-off/unknown split and coverage. History bars draw reads beside writes while it is open, and a set critical_warning shows as a badge in the endurance outlook without affecting the projection. Counter deltas are withheld across a controller segment change.
75 lines
3.3 KiB
Python
75 lines
3.3 KiB
Python
"""Visible geometry and evidence boundaries of the terminal volume plot."""
|
|
from fenris.activity_plot import VolumePoint, volume_plot
|
|
from fenris.themes import get_graph_colors
|
|
|
|
|
|
def plot(points, selected=-1, width=48, height=10):
|
|
return volume_plot(points, width, height, selected, get_graph_colors("chalktone"))
|
|
|
|
|
|
def test_trace_fits_viewport_and_uses_time_not_sample_index():
|
|
points = [VolumePoint(t, v, str(t)) for t, v in ((0, 0), (3, 50), (30, 100))]
|
|
text, columns, unit = plot(points)
|
|
assert unit == "B"
|
|
assert len(text.plain.splitlines()) == 10
|
|
assert all(len(line) <= 48 for line in text.plain.splitlines())
|
|
assert columns[1] - columns[0] < (columns[2] - columns[0]) / 5
|
|
assert any(0x2801 <= ord(c) <= 0x28ff for c in text.plain)
|
|
assert not any(c in text.plain for c in "█▒░")
|
|
assert "100.00" in text.plain and "0.00" in text.plain
|
|
|
|
|
|
def test_gap_breaks_trace_while_measured_zero_stays_on_axis():
|
|
text, columns, _ = plot([
|
|
VolumePoint(0, 0, "00:00"), VolumePoint(1, None, "00:03", "gap"),
|
|
VolumePoint(2, 100, "00:06"),
|
|
])
|
|
rows = text.plain.splitlines()
|
|
assert "?" in rows[-2]
|
|
# No invented intermediate dots on either side of the missing measurement.
|
|
for row in rows[:-2]:
|
|
assert all(c == " " for c in row[columns[0] + 1:columns[-1]])
|
|
assert 0x2801 <= ord(rows[-3][columns[0]]) <= 0x28ff
|
|
|
|
|
|
def test_partial_and_unallocated_totals_are_isolated_and_labelled():
|
|
text, columns, unit = plot([
|
|
VolumePoint(0, 1_000_000, "01", "partial"),
|
|
VolumePoint(1, 2_000_000, "02", "unallocated"),
|
|
VolumePoint(2, 3_000_000, "03"),
|
|
])
|
|
assert unit == "MB"
|
|
assert "~" in text.plain and "u" in text.plain
|
|
for row in text.plain.splitlines()[:-2]:
|
|
assert all(c == " " for c in row[columns[0] + 1:columns[1]])
|
|
|
|
|
|
def test_many_intervals_and_selection_fit_small_plot_without_losing_points():
|
|
points = [VolumePoint(i, i % 9 * 1_000_000, str(i)) for i in range(180)]
|
|
text, columns, _ = plot(points, selected=100, width=32, height=6)
|
|
assert len(columns) == len(points)
|
|
assert text.plain.splitlines()[-2][columns[100]] == "▼"
|
|
assert all(len(row) == 32 for row in text.plain.splitlines())
|
|
|
|
|
|
def test_secondary_series_shares_the_axis_and_colours_its_own_dots():
|
|
colors = get_graph_colors("chalktone")
|
|
writes = [VolumePoint(t, v, str(t)) for t, v in ((0, 10), (1, 10), (2, 10))]
|
|
reads = [VolumePoint(t, v, str(t)) for t, v in ((0, 100), (1, 100), (2, 100))]
|
|
text, columns, unit = volume_plot(
|
|
writes, 48, 10, -1, colors, secondary=reads)
|
|
assert "100.00" in text.plain # the larger read volume sets the ceiling
|
|
styles = {span.style for span in text.spans}
|
|
assert colors["allocated"] in styles and colors["secondary"] in styles
|
|
|
|
|
|
def test_secondary_gap_does_not_draw_or_connect():
|
|
colors = get_graph_colors("chalktone")
|
|
points = [VolumePoint(t, 5, str(t)) for t in range(3)]
|
|
reads = [VolumePoint(0, 9, "0"), VolumePoint(1, None, "1", "gap"),
|
|
VolumePoint(2, 9, "2")]
|
|
text, columns, _ = volume_plot(points, 48, 10, -1, colors, secondary=reads)
|
|
rows = text.plain.splitlines()[:-2]
|
|
top = next(r for r in rows if any(0x2801 <= ord(c) <= 0x28ff for c in r))
|
|
assert all(c == " " for c in top[columns[0] + 1:columns[-1]])
|