Files
textual/tests/test_widget_navigation.py
2024-10-24 14:25:31 +01:00

155 lines
4.3 KiB
Python

from __future__ import annotations
import pytest
from textual._widget_navigation import (
find_first_enabled,
find_last_enabled,
find_next_enabled,
find_next_enabled_no_wrap,
get_directed_distance,
)
class _D:
def __init__(self, disabled):
self.disabled = disabled
# Represent disabled/enabled objects that are compact to write in tests.
D = _D(True)
E = _D(False)
@pytest.mark.parametrize(
["index", "start", "direction", "wrap_at", "dist"],
[
(2, 8, 1, 10, 4),
(2, 8, -1, 10, 6),
(8, 2, -1, 10, 4),
(8, 2, 1, 10, 6),
(8, 2, 1, 1234123512, 6),
(2, 8, 1, 11, 5),
(2, 8, 1, 12, 6),
(5, 5, 1, 10, 0),
],
)
def test_distance(index, start, direction, wrap_at, dist):
assert (
get_directed_distance(
index=index,
start=start,
direction=direction,
wrap_at=wrap_at,
)
== dist
)
@pytest.mark.parametrize(
"function",
[
find_first_enabled,
find_last_enabled,
],
)
def test_find_enabled_returns_none_on_empty(function):
assert function([]) is None
@pytest.mark.parametrize(
["candidates", "anchor", "direction", "result"],
[
# No anchor & no candidates -> no next
([], None, 1, None),
([], None, -1, None),
# No anchor but candidates -> get first/last one
([E], None, 1, 0),
([E, D], None, 1, 0),
([E, E], None, 1, 0),
([D, E], None, 1, 1),
([D, D, E], None, 1, 2),
([E], None, -1, 0),
([E, E], None, -1, 1),
([E, D], None, -1, 0),
([E, D, D], None, -1, 0),
# No enabled candidates -> return the anchor
([D, D, D], 0, 1, 0),
([D, D, D], 1, 1, 1),
([D, D, D], 1, -1, 1),
([D, D, D], None, -1, None),
# General case
# 0 1 2 3 4 5
([E, D, D, E, E, D], 0, 1, 3),
([E, D, D, E, E, D], 0, -1, 4),
([E, D, D, E, E, D], 1, 1, 3),
([E, D, D, E, E, D], 1, -1, 0),
([E, D, D, E, E, D], 2, 1, 3),
([E, D, D, E, E, D], 2, -1, 0),
([E, D, D, E, E, D], 3, 1, 4),
([E, D, D, E, E, D], 3, -1, 0),
([E, D, D, E, E, D], 4, 1, 0),
([E, D, D, E, E, D], 4, -1, 3),
([E, D, D, E, E, D], 5, 1, 0),
([E, D, D, E, E, D], 5, -1, 4),
],
)
def test_find_next_enabled(candidates, anchor, direction, result):
assert find_next_enabled(candidates, anchor, direction) == result
@pytest.mark.parametrize(
["candidates", "anchor", "direction", "result"],
[
# No anchor & no candidates -> no next
([], None, 1, None),
([], None, -1, None),
# No anchor but candidates -> get first/last one
([E], None, 1, 0),
([E, D], None, 1, 0),
([E, E], None, 1, 0),
([D, E], None, 1, 1),
([D, D, E], None, 1, 2),
([E], None, -1, 0),
([E, E], None, -1, 1),
([E, D], None, -1, 0),
([E, D, D], None, -1, 0),
# No enabled candidates -> return None
([D, D, D], 0, 1, None),
([D, D, D], 1, 1, None),
([D, D, D], 1, -1, None),
([D, D, D], None, -1, None),
# General case
# 0 1 2 3 4 5
([E, D, D, E, E, D], 0, 1, 3),
([E, D, D, E, E, D], 0, -1, None),
([E, D, D, E, E, D], 1, 1, 3),
([E, D, D, E, E, D], 1, -1, 0),
([E, D, D, E, E, D], 2, 1, 3),
([E, D, D, E, E, D], 2, -1, 0),
([E, D, D, E, E, D], 3, 1, 4),
([E, D, D, E, E, D], 3, -1, 0),
([E, D, D, E, E, D], 4, 1, None),
([E, D, D, E, E, D], 4, -1, 3),
([E, D, D, E, E, D], 5, 1, None),
([E, D, D, E, E, D], 5, -1, 4),
],
)
def test_find_next_enabled_no_wrap(candidates, anchor, direction, result):
assert find_next_enabled_no_wrap(candidates, anchor, direction) == result
@pytest.mark.parametrize(
["function", "start", "direction"],
[
(find_next_enabled_no_wrap, 0, 1),
(find_next_enabled_no_wrap, 0, -1),
(find_next_enabled_no_wrap, 1, 1),
(find_next_enabled_no_wrap, 1, -1),
(find_next_enabled_no_wrap, 2, 1),
(find_next_enabled_no_wrap, 2, -1),
],
)
def test_find_next_with_anchor(function, start, direction):
assert function([E, E, E], start, direction, True) == start