Skip to content

Commit d2e5561

Browse files
authored
Add tests to Autofill (and tidy current ones) (#183)
2 parents fb3ebb4 + 06a41db commit d2e5561

File tree

5 files changed

+267
-14
lines changed

5 files changed

+267
-14
lines changed

tests/conftest.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
from unittest.mock import MagicMock, patch
33

44
import pytest
5+
from lxml.etree import Element, SubElement, tostring
6+
from lxml.objectify import fromstring
57

8+
from techui_builder.autofill import Autofiller
69
from techui_builder.builder import Builder, JsonMap
710
from techui_builder.generate import Generator
811
from techui_builder.validator import Validator
@@ -62,9 +65,94 @@ def generator():
6265
return g
6366

6467

68+
@pytest.fixture
69+
def autofiller():
70+
index_bob = Path(__file__).parent.joinpath(Path("t01-services/synoptic/index.bob"))
71+
72+
a = Autofiller(index_bob)
73+
74+
return a
75+
76+
6577
@pytest.fixture
6678
def validator():
6779
test_bobs = [Path("tests/test_files/motor-edited.bob")]
6880
v = Validator(test_bobs)
6981

7082
return v
83+
84+
85+
@pytest.fixture
86+
def example_embedded_widget():
87+
# You cannot set a text tag of an ObjectifiedElement,
88+
# so we need to make an etree.Element and convert it ...
89+
90+
widget_element = Element("widget")
91+
widget_element.set("type", "embedded")
92+
widget_element.set("version", "2.0.0")
93+
name_element = SubElement(widget_element, "name")
94+
name_element.text = "motor"
95+
width_element = SubElement(widget_element, "width")
96+
width_element.text = "205"
97+
height_element = SubElement(widget_element, "height")
98+
height_element.text = "120"
99+
file_element = SubElement(widget_element, "file")
100+
file_element.text = (
101+
"example/t01-services/synoptic/techui-support/bob/pmac/motor_embed.bob"
102+
)
103+
104+
# ... which requires this horror
105+
widget_element = fromstring(tostring(widget_element))
106+
107+
return widget_element
108+
109+
110+
@pytest.fixture
111+
def example_related_widget():
112+
# You cannot set a text tag of an ObjectifiedElement,
113+
# so we need to make an etree.Element and convert it ...
114+
115+
widget_element = Element("widget")
116+
widget_element.set("type", "action_button")
117+
widget_element.set("version", "2.0.0")
118+
name_element = SubElement(widget_element, "name")
119+
name_element.text = "motor"
120+
width_element = SubElement(widget_element, "width")
121+
width_element.text = "205"
122+
height_element = SubElement(widget_element, "height")
123+
height_element.text = "120"
124+
125+
actions_element = SubElement(widget_element, "actions")
126+
action_element = SubElement(actions_element, "action")
127+
action_element.set("type", "open_display")
128+
file_element = SubElement(action_element, "file")
129+
file_element.text = (
130+
"example/t01-services/synoptic/techui-support/bob/pmac/motor.bob"
131+
)
132+
desc_element = SubElement(action_element, "description")
133+
desc_element.text = "placeholder description"
134+
135+
# ... which requires this horror
136+
widget_element = fromstring(tostring(widget_element))
137+
138+
return widget_element
139+
140+
141+
@pytest.fixture
142+
def example_symbol_widget():
143+
# You cannot set a text tag of an ObjectifiedElement,
144+
# so we need to make an etree.Element and convert it ...
145+
widget_element = Element("widget")
146+
widget_element.set("type", "symbol")
147+
widget_element.set("version", "2.0.0")
148+
name_element = SubElement(widget_element, "name")
149+
name_element.text = "motor"
150+
width_element = SubElement(widget_element, "width")
151+
width_element.text = "205"
152+
height_element = SubElement(widget_element, "height")
153+
height_element.text = "120"
154+
155+
# ... which requires this horror
156+
widget_element = fromstring(tostring(widget_element))
157+
158+
return widget_element

tests/test_autofiller.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import logging
2+
from pathlib import Path
3+
from unittest.mock import Mock, patch
4+
5+
import pytest
6+
from lxml.etree import ElementTree
7+
from lxml.objectify import Element
8+
9+
from techui_builder.models import Component
10+
11+
12+
def test_autofiller_read_bob(autofiller):
13+
# Imported in to autofill from utils, so that needs to be patched
14+
with patch("techui_builder.autofill.read_bob") as mock_read_bob:
15+
mock_read_bob.return_value = (Mock(spec=ElementTree), Mock())
16+
17+
autofiller.read_bob()
18+
19+
mock_read_bob.assert_called()
20+
21+
22+
def test_autofiller_autofill_bob(autofiller):
23+
autofiller.replace_content = Mock()
24+
# This mess of a Mock represents a basic Builder object with a components dict
25+
mock_builder = Mock(conf=Mock(components={"test_widget": Mock(spec=Component)}))
26+
27+
mock_widget = Element("widget")
28+
29+
autofiller.widgets = {"test_widget": mock_widget}
30+
31+
autofiller.autofill_bob(mock_builder)
32+
33+
autofiller.replace_content.assert_called()
34+
assert mock_widget.find("run_actions_on_mouse_click") == "true"
35+
36+
37+
def test_autofiller_write_bob(autofiller):
38+
with (
39+
patch("techui_builder.builder.etree.ElementTree") as mock_tree,
40+
patch("techui_builder.builder.objectify.deannotate") as mock_deannotate,
41+
):
42+
autofiller.tree = mock_tree
43+
44+
autofiller.write_bob(Path("tests/test_files/test_autofilled_bob.bob"))
45+
46+
mock_deannotate.assert_called_once()
47+
mock_tree.write.assert_called_once_with(
48+
Path("tests/test_files/test_autofilled_bob.bob"),
49+
pretty_print=True,
50+
encoding="utf-8",
51+
xml_declaration=True,
52+
)
53+
54+
55+
@pytest.mark.parametrize(
56+
"prefix, description, filename, expected_desc, expected_file",
57+
[
58+
("TEST_1", None, None, "test_component", "test_component.bob"),
59+
("TEST_2", "test_desc", "test_file.bob", "test_desc", "test_file.bob"),
60+
],
61+
)
62+
def test_autofiller_replace_content(
63+
autofiller,
64+
example_related_widget,
65+
prefix,
66+
description,
67+
filename,
68+
expected_desc,
69+
expected_file,
70+
):
71+
with patch("techui_builder.autofill._get_action_group") as mock_get:
72+
mock_get.return_value = example_related_widget.actions.action
73+
74+
mock_component = Mock(
75+
spec=Component,
76+
prefix=prefix,
77+
desc=description,
78+
file=filename,
79+
)
80+
81+
autofiller.replace_content(
82+
example_related_widget,
83+
"test_component",
84+
mock_component,
85+
)
86+
87+
assert example_related_widget.pv_name == f"{prefix}:DEVSTA"
88+
assert example_related_widget.actions.action.description.text == expected_desc
89+
assert example_related_widget.actions.action.file.text == expected_file
90+
91+
92+
def test_autofiller_replace_content_no_action_group(autofiller, caplog):
93+
# Just to only run the code we want to test
94+
autofiller.macros = ["desc"]
95+
96+
with patch("techui_builder.autofill._get_action_group") as mock_get:
97+
# Simulate no action group found
98+
mock_get.return_value = None
99+
100+
mock_component = Mock(
101+
spec=Component,
102+
desc="description",
103+
)
104+
105+
with caplog.at_level(logging.DEBUG):
106+
autofiller.replace_content(None, "", mock_component)
107+
108+
for log_output in caplog.records:
109+
assert "Skipping replace_content for" in log_output.message
110+
111+
112+
def test_autofiller_replace_content_unsupported_macro(autofiller):
113+
autofiller.macros = ["bad_macro"]
114+
115+
mock_component = Mock(
116+
spec=Component,
117+
bad_macro="bad_macro",
118+
)
119+
120+
with pytest.raises(ValueError) as e:
121+
autofiller.replace_content(None, "", mock_component)
122+
123+
assert e == "The provided macro type is not supported."

tests/test_builder.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77
from lxml import objectify
8+
from phoebusgen.widget import ActionButton, Group
89

910
from techui_builder.builder import (
1011
JsonMap,
@@ -108,6 +109,30 @@ def test_gb_extract_entities(builder, index, type, desc, P, M, R): # noqa: N803
108109
assert entity.R == R
109110

110111

112+
def test_builder_generate_screen(builder_with_setup):
113+
# with (
114+
# patch("techui_builder.builder.Generator.build_screen") as mock_build_screen,
115+
# patch("techui_builder.builder.Generator.write_screen") as mock_write_screen,
116+
# ):
117+
builder_with_setup.generator.build_screen = Mock()
118+
builder_with_setup.generator.write_screen = Mock()
119+
120+
builder_with_setup._generate_screen("TEST")
121+
122+
builder_with_setup.generator.build_screen.assert_called_once()
123+
builder_with_setup.generator.write_screen.assert_called_once()
124+
125+
126+
def test_builder_validate_screen(builder_with_setup):
127+
builder_with_setup.validator.validate_bob = Mock()
128+
builder_with_setup.generator.widgets = [Mock(spec=ActionButton)]
129+
builder_with_setup.generator.group = Mock(spec=Group, name="TEST")
130+
131+
builder_with_setup._validate_screen("TEST")
132+
133+
builder_with_setup.validator.validate_bob.assert_called_once()
134+
135+
111136
def test_create_screens(builder_with_setup):
112137
# We don't want to access Generator in this test
113138
builder_with_setup._generate_screen = Mock()

tests/test_utils.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from pathlib import Path
2+
from unittest.mock import Mock, patch
3+
4+
from lxml.etree import _ElementTree
5+
from lxml.objectify import Element, ObjectifiedElement
6+
7+
from techui_builder.utils import get_widgets, read_bob
8+
9+
10+
def test_read_bob():
11+
with patch("techui_builder.utils.get_widgets") as mock_get_widgets:
12+
mock_get_widgets.return_value = {"test_widget": Mock(spec=ObjectifiedElement)}
13+
14+
tree, widgets = read_bob(Path("tests/test_files/index.bob"))
15+
16+
assert isinstance(tree, _ElementTree)
17+
assert isinstance(widgets["test_widget"], ObjectifiedElement)
18+
mock_get_widgets.assert_called_once()
19+
20+
21+
def test_get_widgets(example_symbol_widget):
22+
test_root = Element("root")
23+
test_root.append(example_symbol_widget)
24+
25+
widgets = get_widgets(test_root)
26+
27+
assert "motor" in widgets.keys()

tests/test_validator.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pathlib import Path
22
from unittest.mock import Mock, patch
33

4-
from lxml.etree import Element, SubElement, _ElementTree, tostring
4+
from lxml.etree import Element, _ElementTree, tostring
55
from lxml.objectify import fromstring
66
from phoebusgen.widget import EmbeddedDisplay
77

@@ -31,21 +31,11 @@ def test_validator_read_bob(validator):
3131

3232

3333
# TODO: Clean up this test... (make fixture for mock xml?)
34-
def test_validator_validate_bob(validator):
34+
def test_validator_validate_bob(validator, example_embedded_widget):
3535
# You cannot set a text tag of an ObjectifiedElement,
3636
# so we need to make an etree.Element and convert it ...
3737
mock_root_element = Element("root")
38-
mock_widget_element = SubElement(mock_root_element, "widget")
39-
mock_name_element = SubElement(mock_widget_element, "name")
40-
mock_name_element.text = "motor"
41-
mock_width_element = SubElement(mock_widget_element, "width")
42-
mock_width_element.text = "205"
43-
mock_height_element = SubElement(mock_widget_element, "height")
44-
mock_height_element.text = "120"
45-
mock_file_element = SubElement(mock_widget_element, "file")
46-
mock_file_element.text = (
47-
"example/t01-services/synoptic/techui_supportbob/pmac/motor_embed.bob"
48-
)
38+
mock_root_element.append(example_embedded_widget)
4939
# ... which requires this horror
5040
mock_element = fromstring(tostring(mock_root_element))
5141
# mock_element = ObjectifiedElement(mock_widget_element)
@@ -59,7 +49,7 @@ def test_validator_validate_bob(validator):
5949
validator.validate = {"motor-edited": Path("tests/test_files/motor-edited.bob")}
6050
test_pwidget = EmbeddedDisplay(
6151
"motor",
62-
"example/t01-services/synoptic/techui_supportbob/pmac/motor_embed.bob",
52+
"example/t01-services/synoptic/techui-support/bob/pmac/motor_embed.bob",
6353
0,
6454
0,
6555
205,

0 commit comments

Comments
 (0)