summaryrefslogtreecommitdiff
path: root/lib/taurus/qt/qtgui/panel/test/test_taurusform.py
blob: 99f73482fbaa1bb666f63047c5625b7719817525 (plain)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env python
# ###########################################################################
#
# This file is part of Taurus
#
# http://taurus-scada.org
#
# Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
#
# Taurus is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Taurus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Taurus.  If not, see <http://www.gnu.org/licenses/>.
#
# ###########################################################################

"""Unit tests for Taurus Forms
"""

from taurus.qt.qtgui.panel import TaurusForm, TaurusValue
from taurus.core.util.test.test_plugin import mock_entry_point
import pytest

try:
    # The following are Tango-centric imports.
    from taurus.core.tango.test import nodb_dev  # noqa: F401

    _TANGO_MISSING = False
except Exception:
    _TANGO_MISSING = True


class _DummyTV(TaurusValue):
    pass


def _DummyItemFactory(m):
    """
    A dummy item factory that returns _DummyTV instance for one specific
    attribute: "eval://localhost/@dummy/'test_itemfactory'"
    """
    if m.fullname == "eval://localhost/@dummy/'test_itemfactory'":
        return _DummyTV()


def _BadFactory(m):
    """
    A dummy item factory that fails when called with the attribute
    "eval://localhost/@dummy/'test_badfactory'" and returns _DummyTV otherwise.
    """
    if m.fullname == "eval://localhost/@dummy/'test_badfactory'":
        return _DummyTV()
    raise RuntimeError("_BadFactory is doomed to fail")


class _BadEntryPoint(object):
    """A dummy entry point -like class that fails when loaded (for testing)"""

    name = "_BadEntryPoint"

    def load(self):
        raise RuntimeError("_BadEntryPoint is doomed to fail")


def test_form_itemFactory(qtbot):
    """Checks that the TaurusForm itemFactory API works"""
    lines = ["test_Form_ItemFactory={}:_DummyItemFactory".format(__name__)]
    group = "taurus.form.item_factories"
    mock_entry_point(lines, group=group)

    w = TaurusForm()
    qtbot.addWidget(w)

    w.setModel(
        [
            "eval://localhost/@dummy/'test_itemfactory'",
            "eval://localhost/@dummy/'test_itemfactory2'",
        ]
    )
    qtbot.wait_until(lambda: len(w) == 2, timeout=3200)
    # The first item should get a customized _DummyTV widget
    assert type(w[0]) is _DummyTV
    # The second item shoud get the default form widget
    assert type(w[1]) is w._defaultFormWidget


def test_form_itemFactory_selection(qtbot):
    """Checks that the TaurusForm itemFactory selection API works"""
    lines = ["test_Form_ItemFactorySel={}:_DummyItemFactory".format(__name__)]
    group = "taurus.form.item_factories"
    mapping = mock_entry_point(lines, group=group)
    ep1 = mapping[group]["test_Form_ItemFactorySel"]

    w = TaurusForm()
    qtbot.addWidget(w)

    # the test_Form_ItemFactory should be in the default factories
    default_factories = w.getItemFactories()
    assert ep1 in default_factories

    # no factories should be excluded by default
    inc, exc = w.getItemFactories(return_disabled=True)
    assert exc == []

    # Check that we can deselect all factories
    no_factories = w.setItemFactories(include=[])
    assert no_factories == []

    # Check that we can exclude everything except test_Form_ItemFactory
    select1 = w.setItemFactories(exclude=[r"(?!.*test_Form_ItemFactorySel).*"])
    assert select1 == [ep1]

    # Check that we can include only test_Form_ItemFactory
    select2 = w.setItemFactories(include=["test_Form_ItemFactorySel"])
    assert select2 == [ep1]

    # Check that the selected test_Form_ItemFactory is an entry point
    from pkg_resources import EntryPoint

    assert type(select2[0]) == EntryPoint

    # Check that the selected entry point loads _DummyItemFactory
    assert select2[0].load() is _DummyItemFactory

    # Check that we can include a factory instance
    select3 = w.setItemFactories(include=[_DummyItemFactory])

    # Check that the selected test_Form_ItemFactory is an entry point-alike
    from taurus.core.util.plugin import EntryPointAlike

    assert type(select3[0]) == EntryPointAlike

    # Check that the selected entry point loads _DummyItemFactory
    assert select3[0].load() is _DummyItemFactory

    # Check that the selected entry point has the given name
    assert select3[0].name == repr(_DummyItemFactory)


@pytest.mark.skipif(_TANGO_MISSING, reason="tango not available")
@pytest.mark.forked
def test_form_cwidget_bck_compat(qtbot, nodb_dev):
    """check that the cusomWidgetMap bck-compat works"""

    w = TaurusForm()
    qtbot.addWidget(w)

    # check that custom widget map is empty by default
    assert w.getCustomWidgetMap() == {}

    w.setItemFactories(include=())

    try:
        # check that an explicit call to setCustomWidgetMap works
        dummy = ("taurus.qt.qtgui.panel.test.test_taurusform._DummyTV", (), {})
        w.setCustomWidgetMap({"TangoSchemeTest": dummy})
        w.setModel([nodb_dev, "eval:1"])
        qtbot.wait_until(lambda: len(w) == 2, timeout=3200)
        assert type(w[0]) == _DummyTV
        assert type(w[1]) == TaurusValue
        assert w.getCustomWidgetMap() == {"TangoSchemeTest": dummy}

        # check that the custom widget map can be restored
        w.setCustomWidgetMap({})
        w.setModel([nodb_dev, "eval:1"])
        qtbot.wait_until(lambda: len(w) == 2, timeout=3200)
        assert type(w[0]) == TaurusValue
        assert type(w[1]) == TaurusValue
        assert w.getCustomWidgetMap() == {}
    finally:
        # set model to None as an attempt to avoid problems in atexit()
        w.setModel(None)
        qtbot.wait_until(lambda: len(w) == 0, timeout=3200)


def test_form_itemFactory_loading(qtbot):
    """
    check that the factory loading is robust against unloadable plugins
    and badly-implemented item factories
    """

    w = TaurusForm()
    qtbot.addWidget(w)

    w.setItemFactories(
        include=(_BadEntryPoint, _BadFactory, _DummyItemFactory)
    )
    w.setModel(
        [
            "eval://localhost/@dummy/'test_itemfactory'",
            "eval://localhost/@dummy/'test_badfactory'",
            "eval:1",
        ]
    )
    qtbot.wait_until(lambda: len(w) == 3, timeout=3200)

    # handled by _DummyItemFactory
    assert type(w[0]) == _DummyTV
    # handled in _BadFactory (even if with wrong return value)
    assert type(w[1]) == _DummyTV
    # errored in _BadFactory, ignored by _DummyItemFactory
    assert type(w[2]) == TaurusValue