Merge branch 'main' into review-styles-reference

This commit is contained in:
Rodrigo Girão Serrão
2023-01-09 16:19:24 +00:00
17 changed files with 706 additions and 154 deletions

53
tests/test_concurrency.py Normal file
View File

@@ -0,0 +1,53 @@
import pytest
from threading import Thread
from textual.app import App, ComposeResult
from textual.widgets import TextLog
def test_call_from_thread_app_not_running():
app = App()
# Should fail if app is not running
with pytest.raises(RuntimeError):
app.call_from_thread(print)
def test_call_from_thread():
"""Test the call_from_thread method."""
class BackgroundThread(Thread):
"""A background thread which will modify app in some way."""
def __init__(self, app: App) -> None:
self.app = app
super().__init__()
def run(self) -> None:
def write_stuff(text: str) -> None:
"""Write stuff to a widget."""
self.app.query_one(TextLog).write(text)
self.app.call_from_thread(write_stuff, "Hello")
# Exit the app with a code we can assert
self.app.call_from_thread(self.app.exit, 123)
class ThreadTestApp(App):
"""Trivial app with a single widget."""
def compose(self) -> ComposeResult:
yield TextLog()
def on_ready(self) -> None:
"""Launch a thread which will modify the app."""
try:
self.call_from_thread(print)
except RuntimeError as error:
# Calling this from the same thread as the app is an error
self._runtime_error = error
BackgroundThread(self).start()
app = ThreadTestApp()
result = app.run(headless=True, size=(80, 24))
assert isinstance(app._runtime_error, RuntimeError)
assert result == 123

View File

@@ -24,7 +24,7 @@ def test_non_empty_immutable_sequence() -> None:
def test_no_assign_to_immutable_sequence() -> None:
"""It should not be possible to assign into an immutable sequence."""
tester = wrap([1,2,3,4,5])
tester = wrap([1, 2, 3, 4, 5])
with pytest.raises(TypeError):
tester[0] = 23
with pytest.raises(TypeError):
@@ -33,7 +33,7 @@ def test_no_assign_to_immutable_sequence() -> None:
def test_no_del_from_iummutable_sequence() -> None:
"""It should not be possible delete an item from an immutable sequence."""
tester = wrap([1,2,3,4,5])
tester = wrap([1, 2, 3, 4, 5])
with pytest.raises(TypeError):
del tester[0]
@@ -46,23 +46,23 @@ def test_get_item_from_immutable_sequence() -> None:
def test_get_slice_from_immutable_sequence() -> None:
"""It should be possible to get a slice from an immutable sequence."""
assert list(wrap(range(10))[0:2]) == [0,1]
assert list(wrap(range(10))[0:-1]) == [0,1,2,3,4,5,6,7,8]
assert list(wrap(range(10))[0:2]) == [0, 1]
assert list(wrap(range(10))[0:-1]) == [0, 1, 2, 3, 4, 5, 6, 7, 8]
def test_immutable_sequence_contains() -> None:
"""It should be possible to see if an immutable sequence contains a value."""
tester = wrap([1,2,3,4,5])
tester = wrap([1, 2, 3, 4, 5])
assert 1 in tester
assert 11 not in tester
def test_immutable_sequence_index() -> None:
tester = wrap([1,2,3,4,5])
tester = wrap([1, 2, 3, 4, 5])
assert tester.index(1) == 0
with pytest.raises(ValueError):
_ = tester.index(11)
def test_reverse_immutable_sequence() -> None:
assert list(reversed(wrap([1,2]))) == [2,1]
assert list(reversed(wrap([1, 2]))) == [2, 1]

View File

@@ -1,6 +1,8 @@
import pytest
from rich.segment import Segment
from rich.style import Style
from textual._segment_tools import NoCellPositionForIndex
from textual.strip import Strip
from textual._filter import Monochrome
@@ -62,9 +64,7 @@ def test_eq():
def test_adjust_cell_length():
for repeat in range(3):
assert Strip([]).adjust_cell_length(3) == Strip([Segment(" ")])
assert Strip([Segment("f")]).adjust_cell_length(3) == Strip(
[Segment("f"), Segment(" ")]
@@ -119,9 +119,7 @@ def test_style_links():
def test_crop():
for repeat in range(3):
assert Strip([Segment("foo")]).crop(0, 3) == Strip([Segment("foo")])
assert Strip([Segment("foo")]).crop(0, 2) == Strip([Segment("fo")])
assert Strip([Segment("foo")]).crop(0, 1) == Strip([Segment("f")])
@@ -136,10 +134,42 @@ def test_crop():
def test_divide():
for repeat in range(3):
assert Strip([Segment("foo")]).divide([1, 2]) == [
Strip([Segment("f")]),
Strip([Segment("o")]),
]
@pytest.mark.parametrize(
"index,cell_position",
[
(0, 0),
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 6),
(6, 8),
(7, 10),
(8, 11),
(9, 12),
(10, 13),
(11, 14),
],
)
def test_index_to_cell_position(index, cell_position):
strip = Strip([Segment("ab"), Segment("cd日本語ef"), Segment("gh")])
assert cell_position == strip.index_to_cell_position(index)
def test_index_cell_position_no_segments():
strip = Strip([])
with pytest.raises(NoCellPositionForIndex):
strip.index_to_cell_position(2)
def test_index_cell_position_index_too_large():
strip = Strip([Segment("abcdef"), Segment("ghi")])
with pytest.raises(NoCellPositionForIndex):
strip.index_to_cell_position(100)

View File

@@ -1,29 +1,29 @@
import pytest
from textual.widgets import Tree, TreeNode
def label_of(node: TreeNode[None]):
"""Get the label of a node.
TODO: This is just a helper function to reduce the number of type
errors, which can and will be remove once this code is merged with a
version of main that also has the TreeNode.label PR merged.
"""
return str(node._label)
def label_of(node: TreeNode[None]):
"""Get the label of a node as a string"""
return str(node.label)
def test_tree_node_children() -> None:
"""A node's children property should act like an immutable list."""
CHILDREN=23
CHILDREN = 23
tree = Tree[None]("Root")
for child in range(CHILDREN):
tree.root.add(str(child))
assert len(tree.root.children)==CHILDREN
assert len(tree.root.children) == CHILDREN
for child in range(CHILDREN):
assert label_of(tree.root.children[child]) == str(child)
assert label_of(tree.root.children[0]) == "0"
assert label_of(tree.root.children[-1]) == str(CHILDREN-1)
assert [label_of(node) for node in tree.root.children] == [str(n) for n in range(CHILDREN)]
assert [label_of(node) for node in tree.root.children[:2]] == [str(n) for n in range(2)]
assert label_of(tree.root.children[-1]) == str(CHILDREN - 1)
assert [label_of(node) for node in tree.root.children] == [
str(n) for n in range(CHILDREN)
]
assert [label_of(node) for node in tree.root.children[:2]] == [
str(n) for n in range(2)
]
with pytest.raises(TypeError):
tree.root.children[0] = tree.root.children[1]
with pytest.raises(TypeError):

View File

@@ -1,6 +1,7 @@
from textual.widgets import Tree, TreeNode
from rich.text import Text
def test_tree_node_label() -> None:
"""It should be possible to modify a TreeNode's label."""
node = TreeNode(Tree[None]("Xenomorph Lifecycle"), None, 0, "Facehugger")
@@ -8,6 +9,7 @@ def test_tree_node_label() -> None:
node.label = "Chestbuster"
assert node.label == Text("Chestbuster")
def test_tree_node_label_via_tree() -> None:
"""It should be possible to modify a TreeNode's label when created via a Tree."""
tree = Tree[None]("Xenomorph Lifecycle")

View File

@@ -1,5 +1,6 @@
from textual.widgets import TreeNode, Tree
def test_tree_node_parent() -> None:
"""It should be possible to access a TreeNode's parent."""
tree = Tree[None]("Anakin")