Show favorite nodes in --nodes

This commit is contained in:
David Andrzejewski
2026-01-08 18:13:03 -05:00
parent 2f44351945
commit 4f6d183ed1
2 changed files with 164 additions and 1 deletions

View File

@@ -250,6 +250,7 @@ class MeshInterface: # pylint: disable=R0902
"channel": "Channel",
"lastHeard": "LastHeard",
"since": "Since",
"isFavorite": "Fav",
}
@@ -297,7 +298,7 @@ class MeshInterface: # pylint: disable=R0902
showFields = ["N", "user.longName", "user.id", "user.shortName", "user.hwModel", "user.publicKey",
"user.role", "position.latitude", "position.longitude", "position.altitude",
"deviceMetrics.batteryLevel", "deviceMetrics.channelUtilization",
"deviceMetrics.airUtilTx", "snr", "hopsAway", "channel", "lastHeard", "since"]
"deviceMetrics.airUtilTx", "snr", "hopsAway", "channel", "isFavorite", "lastHeard", "since"]
else:
# Always at least include the row number.
showFields.insert(0, "N")
@@ -339,6 +340,8 @@ class MeshInterface: # pylint: disable=R0902
formatted_value = "Powered"
else:
formatted_value = formatFloat(raw_value, 0, "%")
elif field == "isFavorite":
formatted_value = "*" if raw_value else ""
elif field == "lastHeard":
formatted_value = getLH(raw_value)
elif field == "position.latitude":

View File

@@ -0,0 +1,160 @@
"""Meshtastic unit tests for showNodes favorite column feature"""
import pytest
from ..mesh_interface import MeshInterface
@pytest.fixture
def iface_with_favorite_nodes():
"""Fixture to setup nodes with favorite flags."""
nodesById = {
"!9388f81c": {
"num": 2475227164,
"user": {
"id": "!9388f81c",
"longName": "Favorite Node",
"shortName": "FAV1",
"macaddr": "RBeTiPgc",
"hwModel": "TBEAM",
},
"position": {},
"lastHeard": 1640204888,
"isFavorite": True,
},
"!12345678": {
"num": 305419896,
"user": {
"id": "!12345678",
"longName": "Regular Node",
"shortName": "REG1",
"macaddr": "ABCDEFGH",
"hwModel": "TLORA_V2",
},
"position": {},
"lastHeard": 1640204999,
"isFavorite": False,
},
}
nodesByNum = {
2475227164: {
"num": 2475227164,
"user": {
"id": "!9388f81c",
"longName": "Favorite Node",
"shortName": "FAV1",
"macaddr": "RBeTiPgc",
"hwModel": "TBEAM",
},
"position": {"time": 1640206266},
"lastHeard": 1640206266,
"isFavorite": True,
},
305419896: {
"num": 305419896,
"user": {
"id": "!12345678",
"longName": "Regular Node",
"shortName": "REG1",
"macaddr": "ABCDEFGH",
"hwModel": "TLORA_V2",
},
"position": {"time": 1640206200},
"lastHeard": 1640206200,
"isFavorite": False,
},
}
iface = MeshInterface(noProto=True)
iface.nodes = nodesById
iface.nodesByNum = nodesByNum
from unittest.mock import MagicMock
myInfo = MagicMock()
iface.myInfo = myInfo
iface.myInfo.my_node_num = 2475227164
return iface
@pytest.mark.unit
def test_showNodes_favorite_column_header(capsys, iface_with_favorite_nodes):
"""Test that 'Fav' column header appears in showNodes output"""
iface = iface_with_favorite_nodes
iface.showNodes()
out, err = capsys.readouterr()
assert "Fav" in out
assert err == ""
@pytest.mark.unit
def test_showNodes_favorite_asterisk_display(capsys, iface_with_favorite_nodes):
"""Test that favorite nodes show asterisk and non-favorites show empty"""
iface = iface_with_favorite_nodes
iface.showNodes()
out, err = capsys.readouterr()
# Check that the output contains the "Fav" column
assert "Fav" in out
# The favorite node should have an asterisk in the output
# We can't easily check the exact table cell, but we can verify
# the asterisk appears somewhere in the output
lines = out.split('\n')
# Find lines containing our nodes
favorite_line = None
regular_line = None
for line in lines:
if "Favorite Node" in line or "FAV1" in line:
favorite_line = line
if "Regular Node" in line or "REG1" in line:
regular_line = line
# Basic sanity check - if we found the lines, they should be present
assert favorite_line is not None or regular_line is not None
assert err == ""
@pytest.mark.unit
def test_showNodes_favorite_field_formatting():
"""Test the formatting logic for isFavorite field"""
# Test favorite node
raw_value = True
formatted_value = "*" if raw_value else ""
assert formatted_value == "*"
# Test non-favorite node
raw_value = False
formatted_value = "*" if raw_value else ""
assert formatted_value == ""
# Test None/missing value
raw_value = None
formatted_value = "*" if raw_value else ""
assert formatted_value == ""
@pytest.mark.unit
def test_showNodes_with_custom_fields_including_favorite(capsys, iface_with_favorite_nodes):
"""Test that isFavorite can be specified in custom showFields"""
iface = iface_with_favorite_nodes
custom_fields = ["user.longName", "isFavorite"]
iface.showNodes(showFields=custom_fields)
out, err = capsys.readouterr()
# Should still show the Fav column when explicitly requested
assert "Fav" in out
assert err == ""
@pytest.mark.unit
def test_showNodes_default_fields_includes_favorite(iface_with_favorite_nodes):
"""Test that isFavorite is included in default fields"""
iface = iface_with_favorite_nodes
# Call showNodes which uses default fields
result = iface.showNodes()
# The result should contain the formatted table as a string
assert "Fav" in result