Skip to content

Commit 5f14ca3

Browse files
Add tests for 53f107d, related to issues #46 & #66
1 parent 52a4aaa commit 5f14ca3

File tree

3 files changed

+106
-42
lines changed

3 files changed

+106
-42
lines changed

tests/conftest.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
sys.platform.startswith("win"), reason="Cothread doesn't work on windows"
1616
)
1717

18+
# Default length used to initialise Waveform and longString records.
19+
# Length picked to match string record length, so we can re-use test strings.
20+
WAVEFORM_LENGTH = 40
21+
1822
class SubprocessIOC:
1923
def __init__(self, ioc_py):
2024
self.pv_prefix = "".join(
@@ -76,9 +80,9 @@ def _clear_records():
7680
# https://github.com/dls-controls/pythonSoftIOC/issues/56
7781
RecordLookup._RecordDirectory.clear()
7882

79-
@pytest.fixture
83+
@pytest.fixture(autouse=True)
8084
def clear_records():
81-
"""Fixture to delete all records before and after a test."""
85+
"""Deletes all records before and after every test"""
8286
_clear_records()
8387
yield
8488
_clear_records()

tests/test_record_values.py

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from enum import Enum
77
from math import isnan, inf, nan
88

9-
from conftest import requires_cothread
9+
from conftest import requires_cothread, WAVEFORM_LENGTH
1010

1111
from softioc import asyncio_dispatcher, builder, softioc
1212
from softioc.pythonSoftIoc import RecordWrapper
@@ -18,6 +18,9 @@
1818
DEVICE_NAME = "RECORD-VALUE-TESTS"
1919
TIMEOUT = 5 # Seconds
2020

21+
# The maximum length string for StringIn/Out records
22+
MAX_LEN_STR = "a 39 char string exactly maximum length"
23+
2124
VERY_LONG_STRING = "This is a fairly long string, the kind that someone " \
2225
"might think to put into a record that can theoretically hold a huge " \
2326
"string and so lets test it and prove that shall we?"
@@ -101,6 +104,8 @@ def record_values_names(fixture_value):
101104
("mbbOut_int", builder.mbbOut, 1, 1, int),
102105
("strIn_abc", builder.stringIn, "abc", "abc", str),
103106
("strOut_abc", builder.stringOut, "abc", "abc", str),
107+
("strIn_39chars", builder.stringIn, MAX_LEN_STR, MAX_LEN_STR, str),
108+
("strOut_39chars", builder.stringOut, MAX_LEN_STR, MAX_LEN_STR, str),
104109
("strIn_empty", builder.stringIn, "", "", str),
105110
("strOut_empty", builder.stringOut, "", "", str),
106111
("strin_utf8", builder.stringIn, "%a€b", "%a€b", str), # Valid UTF-8
@@ -310,7 +315,7 @@ def run_ioc(record_configurations: list, conn, set_enum, get_enum):
310315
if set_enum == SetValueEnum.INITIAL_VALUE:
311316
kwarg.update({"initial_value": initial_value})
312317
elif creation_func in [builder.WaveformIn, builder.WaveformOut]:
313-
kwarg = {"length": 50} # Required when no value on creation
318+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
314319
# Related to this issue:
315320
# https://github.com/dls-controls/pythonSoftIOC/issues/37
316321

@@ -493,7 +498,7 @@ class TestGetValue:
493498
"""Tests that use .get() to check whether values applied with .set(),
494499
initial_value, or caput return the expected value"""
495500

496-
def test_value_pre_init_set(self, clear_records, record_values):
501+
def test_value_pre_init_set(self, record_values):
497502
"""Test that records provide the expected values on get calls when using
498503
.set() and .get() before IOC initialisation occurs"""
499504

@@ -507,7 +512,7 @@ def test_value_pre_init_set(self, clear_records, record_values):
507512

508513
kwarg = {}
509514
if creation_func in [builder.WaveformIn, builder.WaveformOut]:
510-
kwarg = {"length": 50} # Required when no value on creation
515+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
511516

512517
out_rec = creation_func(record_name, **kwarg)
513518
out_rec.set(initial_value)
@@ -678,15 +683,15 @@ class TestDefaultValue:
678683
],
679684
)
680685
def test_value_default_pre_init(
681-
self, creation_func, expected_value, expected_type, clear_records
686+
self, creation_func, expected_value, expected_type
682687
):
683688
"""Test that the correct default values are returned from .get() (before
684689
record initialisation) when no initial_value or .set() is done"""
685690
# Out records do not have default values until records are initialized
686691

687692
kwarg = {}
688693
if creation_func in [builder.WaveformIn, builder.WaveformOut]:
689-
kwarg = {"length": 50} # Required when no value on creation
694+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
690695

691696
out_rec = creation_func("out-record", **kwarg)
692697
record_value_asserts(
@@ -728,7 +733,7 @@ def record_func_reject_none(self, record_func):
728733
return record_func
729734

730735
def test_value_none_rejected_initial_value(
731-
self, clear_records, record_func_reject_none
736+
self, record_func_reject_none
732737
):
733738
"""Test setting \"None\" as the initial_value raises an exception"""
734739

@@ -737,7 +742,7 @@ def test_value_none_rejected_initial_value(
737742
builder.WaveformIn,
738743
builder.WaveformOut,
739744
]:
740-
kwarg = {"length": 50} # Required when no value on creation
745+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
741746

742747
with pytest.raises(self.expected_exceptions):
743748
record_func_reject_none("SOME-NAME", initial_value=None, **kwarg)
@@ -749,7 +754,7 @@ def test_value_none_rejected_set_before_init(
749754

750755
kwarg = {}
751756
if record_func_reject_none in [builder.WaveformIn, builder.WaveformOut]:
752-
kwarg = {"length": 50} # Required when no value on creation
757+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
753758

754759
with pytest.raises(self.expected_exceptions):
755760
record = record_func_reject_none("SOME-NAME", **kwarg)
@@ -759,7 +764,7 @@ def none_value_test_func(self, record_func, queue):
759764
"""Start the IOC and catch the expected exception"""
760765
kwarg = {}
761766
if record_func in [builder.WaveformIn, builder.WaveformOut]:
762-
kwarg = {"length": 50} # Required when no value on creation
767+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
763768

764769
record = record_func("SOME-NAME", **kwarg)
765770

@@ -793,3 +798,84 @@ def test_value_none_rejected_set_after_init(self, record_func_reject_none):
793798
finally:
794799
process.terminate()
795800
process.join(timeout=3)
801+
802+
803+
class TestInvalidValues:
804+
"""Tests for values that records should reject"""
805+
806+
def test_string_rejects_overlong_strings(self):
807+
"""Test that stringIn & stringOut records reject strings >=39 chars"""
808+
809+
OVERLONG_STR = MAX_LEN_STR + "A"
810+
811+
with pytest.raises(ValueError):
812+
builder.stringIn("STRIN1", initial_value=OVERLONG_STR)
813+
814+
with pytest.raises(ValueError):
815+
builder.stringOut("STROUT1", initial_value=OVERLONG_STR)
816+
817+
with pytest.raises(ValueError):
818+
si = builder.stringIn("STRIN2")
819+
si.set(OVERLONG_STR)
820+
821+
with pytest.raises(ValueError):
822+
so = builder.stringOut("STROUT2", initial_value=OVERLONG_STR)
823+
so.set(OVERLONG_STR)
824+
825+
def test_long_string_rejects_overlong_strings(self):
826+
"""Test that longStringIn & longStringOut records reject
827+
strings >=39 chars"""
828+
OVERLONG_STR = MAX_LEN_STR + "A"
829+
830+
with pytest.raises(AssertionError):
831+
builder.longStringIn(
832+
"LSTRIN1",
833+
initial_value=OVERLONG_STR,
834+
length=WAVEFORM_LENGTH)
835+
836+
with pytest.raises(AssertionError):
837+
builder.longStringOut(
838+
"LSTROUT1",
839+
initial_value=OVERLONG_STR,
840+
length=WAVEFORM_LENGTH)
841+
842+
with pytest.raises(AssertionError):
843+
lsi = builder.longStringIn("LSTRIN2", length=WAVEFORM_LENGTH)
844+
lsi.set(OVERLONG_STR)
845+
846+
with pytest.raises(AssertionError):
847+
lso = builder.longStringIn("LSTROUT2", length=WAVEFORM_LENGTH)
848+
lso.set(OVERLONG_STR)
849+
850+
# And a different way to initialise the records to trigger same behaviour:
851+
with pytest.raises(AssertionError):
852+
lsi = builder.longStringIn("LSTRIN3", initial_value="ABC")
853+
lsi.set(OVERLONG_STR)
854+
855+
with pytest.raises(AssertionError):
856+
lso = builder.longStringOut("LSTROUT3", initial_value="ABC")
857+
lso.set(OVERLONG_STR)
858+
859+
860+
def test_waveform_rejects_zero_length(self):
861+
"""Test that WaveformIn/Out and longStringIn/Out records throw an
862+
exception when being initialized with a zero length array"""
863+
with pytest.raises(AssertionError):
864+
builder.WaveformIn("W_IN", [])
865+
with pytest.raises(AssertionError):
866+
builder.WaveformOut("W_OUT", [])
867+
with pytest.raises(AssertionError):
868+
builder.longStringIn("L_IN", length=0)
869+
with pytest.raises(AssertionError):
870+
builder.longStringOut("L_OUT", length=0)
871+
872+
def test_waveform_rejects_overlonglong_values(self):
873+
"""Test that Waveform records throw an exception when an overlong
874+
value is written"""
875+
w_in = builder.WaveformIn("W_IN", [1, 2, 3])
876+
w_out = builder.WaveformOut("W_OUT", [1, 2, 3])
877+
878+
with pytest.raises(AssertionError):
879+
w_in.set([1, 2, 3, 4])
880+
with pytest.raises(AssertionError):
881+
w_out.set([1, 2, 3, 4])

tests/test_records.py

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import pytest
55
import asyncio
66

7-
from conftest import requires_cothread, _clear_records
7+
from conftest import requires_cothread, _clear_records, WAVEFORM_LENGTH
88

99
from softioc import asyncio_dispatcher, builder, softioc
1010

@@ -14,7 +14,7 @@
1414
DEVICE_NAME = "RECORD-TESTS"
1515
TIMEOUT = 5 # Seconds
1616

17-
def test_records(tmp_path, clear_records):
17+
def test_records(tmp_path):
1818
# Ensure we definitely unload all records that may be hanging over from
1919
# previous tests, then create exactly one instance of expected records.
2020
from sim_records import create_records
@@ -85,32 +85,6 @@ def test_DISP_can_be_overridden():
8585
# Note: DISP attribute won't exist if field not specified
8686
assert record.DISP.Value() == 0
8787

88-
def test_waveform_disallows_zero_length(clear_records):
89-
"""Test that WaveformIn/Out records throw an exception when being
90-
initialized with a zero length array"""
91-
with pytest.raises(AssertionError):
92-
builder.WaveformIn("W_IN", [])
93-
with pytest.raises(AssertionError):
94-
builder.WaveformOut("W_OUT", [])
95-
96-
def test_waveform_disallows_too_long_values(clear_records):
97-
"""Test that Waveform and longString records throw an exception when
98-
an overlong value is written"""
99-
w_in = builder.WaveformIn("W_IN", [1, 2, 3])
100-
w_out = builder.WaveformOut("W_OUT", [1, 2, 3])
101-
102-
ls_in = builder.longStringIn("LS_IN", initial_value="ABC")
103-
ls_out = builder.longStringOut("LS_OUT", initial_value="ABC")
104-
105-
with pytest.raises(AssertionError):
106-
w_in.set([1, 2, 3, 4])
107-
with pytest.raises(AssertionError):
108-
w_out.set([1, 2, 3, 4])
109-
with pytest.raises(AssertionError):
110-
ls_in.set("ABCD")
111-
with pytest.raises(AssertionError):
112-
ls_out.set("ABCD")
113-
11488
def validate_fixture_names(params):
11589
"""Provide nice names for the out_records fixture in TestValidate class"""
11690
return params[0].__name__
@@ -149,7 +123,7 @@ def validate_ioc_test_func(self, record_func, queue, validate_pass: bool):
149123

150124
kwarg = {}
151125
if record_func in [builder.WaveformIn, builder.WaveformOut]:
152-
kwarg = {"length": 50} # Required when no value on creation
126+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
153127

154128
kwarg.update(
155129
{
@@ -275,7 +249,7 @@ def on_update_func(new_val):
275249

276250
kwarg = {}
277251
if record_func is builder.WaveformOut:
278-
kwarg = {"length": 50} # Required when no value on creation
252+
kwarg = {"length": WAVEFORM_LENGTH} # Must specify when no value
279253

280254
record_func(
281255
"ON-UPDATE-RECORD",

0 commit comments

Comments
 (0)