1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
import pytest
from unittest.mock import MagicMock
from ..core import HasCallbackProperties, delay_callback
from ..selection import SelectionCallbackProperty, ChoiceSeparator
class Example(HasCallbackProperties):
a = SelectionCallbackProperty()
b = SelectionCallbackProperty(default_index=1)
c = SelectionCallbackProperty(default_index=-1)
class TestSelectionCallbackProperty():
def setup_method(self, method):
self.state = Example()
self.a = Example.a
self.b = Example.b
self.c = Example.c
def test_set_choices(self):
# make sure that default_index is respected
self.a.set_choices(self.state, [1, 2])
self.b.set_choices(self.state, [1, 2])
self.c.set_choices(self.state, [1, 2, 3])
assert self.state.a == 1
assert self.state.b == 2
assert self.state.c == 3
self.a.set_choices(self.state, None)
assert self.state.a is None
def test_set_value(self):
# Since there are no choices set yet, the properties cannot be set to
# any values yet.
with pytest.raises(ValueError) as exc:
self.state.a = 1
assert exc.value.args[0] == "value 1 is not in valid choices: []"
self.a.set_choices(self.state, [1, 2])
# The following should work since it is a valid choice
self.state.a = 2
# Again if we try and set to an invalid value, things break
with pytest.raises(ValueError) as exc:
self.state.a = 3
assert exc.value.args[0] == "value 3 is not in valid choices: [1, 2]"
def test_value_constant(self):
# Make sure that the value is preserved if possible
self.a.set_choices(self.state, [1, 2])
self.state.a = 2
self.a.set_choices(self.state, [2, 5, 3])
assert self.state.a == 2
self.a.set_choices(self.state, [1, 4, 5])
assert self.state.a == 1
self.a.set_choices(self.state, [4, 2, 1])
assert self.state.a == 1
def test_get_choices(self):
self.a.set_choices(self.state, [1, 2])
self.a.get_choices == [1, 2]
self.a.set_choices(self.state, [2, 5, 3])
self.a.get_choices == [2, 5, 3]
def test_display_func(self):
separator = ChoiceSeparator('header')
self.a.set_choices(self.state, [separator, 1, 2])
self.a.get_choice_labels(self.state) == ['header', '1', '2']
assert self.a.get_display_func(self.state) is None
assert self.b.get_display_func(self.state) is None
def val(x):
return 'val{0}'.format(x)
self.a.set_display_func(self.state, val)
self.a.get_choice_labels(self.state) == ['header', 'val1', 'val2']
assert self.a.get_display_func(self.state) is val
assert self.b.get_display_func(self.state) is None
def test_callbacks(self):
# Make sure that callbacks are called when either choices or selection
# are changed
func = MagicMock()
self.state.add_callback('a', func)
self.a.set_choices(self.state, [1, 2, 3])
func.assert_called_with(1)
self.state.a = 2
func.assert_called_with(2)
self.a.set_choices(self.state, [4, 5, 6])
func.assert_called_with(4)
def test_choice_separator(self):
separator = ChoiceSeparator('header')
self.a.set_choices(self.state, [separator, 1, 2])
assert self.state.a == 1
separator = ChoiceSeparator('header')
self.a.set_choices(self.state, [separator])
assert self.state.a is None
def test_delay(self):
func = MagicMock()
self.state.add_callback('a', func)
# Here we set the choices and as a result the selection changes from
# None to a value, so the callback is called after the delay block
with delay_callback(self.state, 'a'):
self.a.set_choices(self.state, [4, 5, 6])
assert func.call_count == 0
func.assert_called_once_with(4)
func.reset_mock()
# Check that the callback gets called even if only the choices
# but not the selection are changed in a delay block
with delay_callback(self.state, 'a'):
self.a.set_choices(self.state, [1, 2, 4])
assert func.call_count == 0
func.assert_called_once_with(4)
func.reset_mock()
|