|
| 1 | +import copy |
| 2 | +import re |
| 3 | +from typing import Any |
| 4 | + |
1 | 5 | import pytest |
2 | 6 | from pytest_mock import MockerFixture |
3 | | -from tango._tango import AttrWriteType, CmdArgType |
4 | | - |
5 | | -from fastcs.backends.tango.dsr import _collect_dev_attributes, _collect_dev_commands |
6 | | - |
7 | | - |
8 | | -def test_collect_attributes(mapping): |
9 | | - attributes = _collect_dev_attributes(mapping) |
10 | | - |
11 | | - # Check that attributes are created and of expected type |
12 | | - assert list(attributes.keys()) == [ |
13 | | - "BigEnum", |
14 | | - "ReadBool", |
15 | | - "ReadInt", |
16 | | - "ReadWriteFloat", |
17 | | - "ReadWriteInt", |
18 | | - "StringEnum", |
19 | | - "WriteBool", |
20 | | - ] |
21 | | - assert attributes["ReadInt"].attr_write == AttrWriteType.READ |
22 | | - assert attributes["ReadInt"].attr_type == CmdArgType.DevLong64 |
23 | | - assert attributes["StringEnum"].attr_write == AttrWriteType.READ_WRITE |
24 | | - assert attributes["StringEnum"].attr_type == CmdArgType.DevString |
25 | | - assert attributes["ReadWriteFloat"].attr_write == AttrWriteType.READ_WRITE |
26 | | - assert attributes["ReadWriteFloat"].attr_type == CmdArgType.DevDouble |
27 | | - assert attributes["WriteBool"].attr_write == AttrWriteType.WRITE |
28 | | - assert attributes["WriteBool"].attr_type == CmdArgType.DevBoolean |
29 | | - |
30 | | - |
31 | | -@pytest.mark.asyncio |
32 | | -async def test_collect_commands(mapping, mocker: MockerFixture): |
33 | | - commands = _collect_dev_commands(mapping) |
34 | | - |
35 | | - # Check that command is created and it can be called |
36 | | - assert list(commands.keys()) == ["Go"] |
37 | | - await commands["Go"](mocker.MagicMock()) |
| 7 | +from tango import DevState |
| 8 | +from tango.test_context import DeviceTestContext |
| 9 | +from tests.conftest import AssertableController |
| 10 | + |
| 11 | +from fastcs.attributes import AttrR |
| 12 | +from fastcs.backends.tango.backend import TangoBackend |
| 13 | +from fastcs.datatypes import Bool, Float, Int |
| 14 | + |
| 15 | + |
| 16 | +def pascal_2_snake(input: list[str]) -> list[str]: |
| 17 | + snake_list = copy.deepcopy(input) |
| 18 | + snake_list[-1] = re.sub(r"(?<!^)(?=[A-Z])", "_", snake_list[-1]).lower() |
| 19 | + return snake_list |
| 20 | + |
| 21 | + |
| 22 | +class TestTangoDevice: |
| 23 | + @pytest.fixture(scope="class", autouse=True) |
| 24 | + def setup_class(self, class_mocker: MockerFixture): |
| 25 | + self.controller = AssertableController(class_mocker) |
| 26 | + |
| 27 | + @pytest.fixture(scope="class") |
| 28 | + def tango_context(self): |
| 29 | + device = TangoBackend(self.controller)._dsr._device |
| 30 | + with DeviceTestContext(device) as proxy: |
| 31 | + yield proxy |
| 32 | + |
| 33 | + @pytest.fixture(scope="class") |
| 34 | + def client_read(self, tango_context): |
| 35 | + def _read_attribute(path: list[str], expected: Any): |
| 36 | + attribute = "_".join(path) |
| 37 | + with self.controller.assertPerformed(pascal_2_snake(path), "READ"): |
| 38 | + result = tango_context.read_attribute(attribute).value |
| 39 | + assert result == expected |
| 40 | + |
| 41 | + return _read_attribute |
| 42 | + |
| 43 | + @pytest.fixture(scope="class") |
| 44 | + def client_write(self, tango_context): |
| 45 | + def _write_attribute(path: list[str], expected: Any): |
| 46 | + attribute = "_".join(path) |
| 47 | + with self.controller.assertPerformed(pascal_2_snake(path), "WRITE"): |
| 48 | + tango_context.write_attribute(attribute, expected) |
| 49 | + |
| 50 | + return _write_attribute |
| 51 | + |
| 52 | + @pytest.fixture(scope="class") |
| 53 | + def client_exec(self, tango_context): |
| 54 | + def _exec_command(path: list[str]): |
| 55 | + command = "_".join(path) |
| 56 | + with self.controller.assertPerformed(pascal_2_snake(path), "EXECUTE"): |
| 57 | + tango_context.command_inout(command) |
| 58 | + |
| 59 | + return _exec_command |
| 60 | + |
| 61 | + def test_list_attributes(self, tango_context): |
| 62 | + assert list(tango_context.get_attribute_list()) == [ |
| 63 | + "BigEnum", |
| 64 | + "ReadBool", |
| 65 | + "ReadInt", |
| 66 | + "ReadWriteFloat", |
| 67 | + "ReadWriteInt", |
| 68 | + "StringEnum", |
| 69 | + "WriteBool", |
| 70 | + "SubController01_ReadInt", |
| 71 | + "SubController02_ReadInt", |
| 72 | + "State", |
| 73 | + "Status", |
| 74 | + ] |
| 75 | + |
| 76 | + def test_list_commands(self, tango_context): |
| 77 | + assert list(tango_context.get_command_list()) == [ |
| 78 | + "Go", |
| 79 | + "Init", |
| 80 | + "State", |
| 81 | + "Status", |
| 82 | + ] |
| 83 | + |
| 84 | + def test_state(self, tango_context): |
| 85 | + assert tango_context.command_inout("State") == DevState.ON |
| 86 | + |
| 87 | + def test_status(self, tango_context): |
| 88 | + expected = "The device is in ON state." |
| 89 | + assert tango_context.command_inout("Status") == expected |
| 90 | + |
| 91 | + def test_read_int(self, client_read): |
| 92 | + client_read(["ReadInt"], AttrR(Int())._value) |
| 93 | + |
| 94 | + def test_read_write_int(self, client_read, client_write): |
| 95 | + client_read(["ReadWriteInt"], AttrR(Int())._value) |
| 96 | + client_write(["ReadWriteInt"], AttrR(Int())._value) |
| 97 | + |
| 98 | + def test_read_write_float(self, client_read, client_write): |
| 99 | + client_read(["ReadWriteFloat"], AttrR(Float())._value) |
| 100 | + client_write(["ReadWriteFloat"], AttrR(Float())._value) |
| 101 | + |
| 102 | + def test_read_bool(self, client_read): |
| 103 | + client_read(["ReadBool"], AttrR(Bool())._value) |
| 104 | + |
| 105 | + def test_write_bool(self, client_write): |
| 106 | + client_write(["WriteBool"], AttrR(Bool())._value) |
| 107 | + |
| 108 | + # # We need to discuss enums |
| 109 | + # def test_string_enum(self, client_read, client_write): |
| 110 | + # client_read(["StringEnum"], "green") |
| 111 | + # client_write(["StringEnum"], "green") |
| 112 | + |
| 113 | + def test_big_enum(self, client_read): |
| 114 | + client_read(["BigEnum"], AttrR(Int(), allowed_values=list(range(1, 18)))._value) |
| 115 | + |
| 116 | + # The method works but does not seem linked to the device instance? |
| 117 | + # def test_go(self, client_exec): |
| 118 | + # client_exec(["Go"]) |
| 119 | + |
| 120 | + def test_read_child1(self, client_read): |
| 121 | + client_read(["SubController01", "ReadInt"], AttrR(Int())._value) |
| 122 | + |
| 123 | + def test_read_child2(self, client_read): |
| 124 | + client_read(["SubController02", "ReadInt"], AttrR(Int())._value) |
0 commit comments