Files
python/meshtastic/tests/test_showNodes_favorite.py
2026-01-08 19:08:18 -05:00

222 lines
6.9 KiB
Python

"""Meshtastic unit tests for showNodes favorite column feature"""
from unittest.mock import MagicMock
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,
},
"!abcdef00": {
"num": 2882400000,
"user": {
"id": "!abcdef00",
"longName": "Legacy Node",
"shortName": "LEG1",
"macaddr": "XYZABC00",
"hwModel": "HELTEC_V3",
},
"position": {},
"lastHeard": 1640205000,
# Note: No isFavorite field - testing backward compatibility
},
}
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,
},
2882400000: {
"num": 2882400000,
"user": {
"id": "!abcdef00",
"longName": "Legacy Node",
"shortName": "LEG1",
"macaddr": "XYZABC00",
"hwModel": "HELTEC_V3",
},
"position": {"time": 1640206100},
"lastHeard": 1640206100,
# Note: No isFavorite field - testing backward compatibility
},
}
iface = MeshInterface(noProto=True)
iface.nodes = nodesById
iface.nodesByNum = nodesByNum
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
# Find lines containing our nodes
lines = out.split('\n')
favorite_line = None
regular_line = None
legacy_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
if "Legacy Node" in line or "LEG1" in line:
legacy_line = line
# Verify all nodes are present in the output
assert favorite_line is not None, "Favorite node should be in output"
assert regular_line is not None, "Regular node should be in output"
assert legacy_line is not None, "Legacy node should be in output"
# Verify the favorite node has an asterisk in its row
assert "*" in favorite_line, "Favorite node should have an asterisk"
# Verify the regular (non-favorite) node does NOT have an asterisk
assert regular_line.count("*") == 0, "Non-favorite node should not have an asterisk"
# Verify the legacy node (without isFavorite field) does NOT have an asterisk
assert legacy_line.count("*") == 0, "Legacy node without isFavorite field should not have an asterisk"
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
@pytest.mark.unit
def test_showNodes_backward_compatibility_missing_field(capsys, _iface_with_favorite_nodes):
"""Test that nodes without isFavorite field are handled gracefully"""
iface = _iface_with_favorite_nodes
iface.showNodes()
out, err = capsys.readouterr()
# Find the legacy node line
lines = out.split('\n')
legacy_line = None
for line in lines:
if "Legacy Node" in line or "LEG1" in line:
legacy_line = line
break
# Verify the legacy node appears in output
assert legacy_line is not None, "Legacy node without isFavorite field should appear in output"
# Verify it doesn't have an asterisk (should be treated as non-favorite)
assert legacy_line.count("*") == 0, "Legacy node should not have asterisk (treated as non-favorite)"
assert err == ""