forked from gijzelaerr/python-snap7
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_datatypes.py
More file actions
252 lines (201 loc) · 8.41 KB
/
test_datatypes.py
File metadata and controls
252 lines (201 loc) · 8.41 KB
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
"""
Tests for S7 data types and conversion utilities.
"""
import pytest
import struct
from snap7.datatypes import S7Area, S7WordLen, S7DataTypes
class TestS7DataTypes:
"""Test S7 data type utilities."""
def test_get_size_bytes(self) -> None:
"""Test size calculation for different word lengths."""
assert S7DataTypes.get_size_bytes(S7WordLen.BIT, 1) == 1
assert S7DataTypes.get_size_bytes(S7WordLen.BYTE, 1) == 1
assert S7DataTypes.get_size_bytes(S7WordLen.WORD, 1) == 2
assert S7DataTypes.get_size_bytes(S7WordLen.DWORD, 1) == 4
assert S7DataTypes.get_size_bytes(S7WordLen.REAL, 1) == 4
# Test with multiple items
assert S7DataTypes.get_size_bytes(S7WordLen.WORD, 5) == 10
assert S7DataTypes.get_size_bytes(S7WordLen.BYTE, 10) == 10
def test_encode_address_db(self) -> None:
"""Test address encoding for DB area."""
address = S7DataTypes.encode_address(area=S7Area.DB, db_number=1, start=10, word_len=S7WordLen.BYTE, count=5)
assert len(address) == 12
assert address[0] == 0x12 # Specification type
assert address[1] == 0x0A # Length
assert address[2] == 0x10 # Syntax ID
assert address[3] == S7WordLen.BYTE # Word length
# Verify count and DB number
count_bytes = address[4:6]
db_bytes = address[6:8]
assert struct.unpack(">H", count_bytes)[0] == 5
assert struct.unpack(">H", db_bytes)[0] == 1
# Verify area code
assert address[8] == S7Area.DB
def test_encode_address_memory(self) -> None:
"""Test address encoding for memory areas."""
address = S7DataTypes.encode_address(
area=S7Area.MK,
db_number=0, # Should be ignored for non-DB areas
start=20,
word_len=S7WordLen.WORD,
count=1,
)
assert len(address) == 12
assert address[8] == S7Area.MK
# DB number should be 0 for non-DB areas
db_bytes = address[6:8]
assert struct.unpack(">H", db_bytes)[0] == 0
def test_encode_address_bit_access(self) -> None:
"""Test address encoding for bit access."""
# Test bit access: bit 5 of byte 10 = bit 85
address = S7DataTypes.encode_address(
area=S7Area.MK,
db_number=0,
start=85, # Bit 5 of byte 10
word_len=S7WordLen.BIT,
count=1,
)
# For bit access, address should be converted to byte.bit format
address_bytes = address[9:12]
bit_address = struct.unpack(">I", b"\x00" + address_bytes)[0]
# Should be (10 << 3) | 5 = 85
assert bit_address == 85
def test_decode_s7_data_bytes(self) -> None:
"""Test decoding byte data."""
data = b"\x01\x02\x03\x04"
values = S7DataTypes.decode_s7_data(data, S7WordLen.BYTE, 4)
assert len(values) == 4
assert values == [1, 2, 3, 4]
def test_decode_s7_data_words(self) -> None:
"""Test decoding word data."""
# Big-endian 16-bit words: 0x0102, 0x0304
data = b"\x01\x02\x03\x04"
values = S7DataTypes.decode_s7_data(data, S7WordLen.WORD, 2)
assert len(values) == 2
assert values == [0x0102, 0x0304]
def test_decode_s7_data_signed_int(self) -> None:
"""Test decoding signed integers."""
# Big-endian signed 16-bit: -1, 1000
data = b"\xff\xff\x03\xe8"
values = S7DataTypes.decode_s7_data(data, S7WordLen.INT, 2)
assert len(values) == 2
assert values == [-1, 1000]
def test_decode_s7_data_dwords(self) -> None:
"""Test decoding double words."""
# Big-endian 32-bit: 0x01020304
data = b"\x01\x02\x03\x04"
values = S7DataTypes.decode_s7_data(data, S7WordLen.DWORD, 1)
assert len(values) == 1
assert values == [0x01020304]
def test_decode_s7_data_real(self) -> None:
"""Test decoding IEEE float."""
# Big-endian IEEE 754 float for 3.14159
data = struct.pack(">f", 3.14159)
values = S7DataTypes.decode_s7_data(data, S7WordLen.REAL, 1)
assert len(values) == 1
assert abs(values[0] - 3.14159) < 0.00001
def test_decode_s7_data_bits(self) -> None:
"""Test decoding bit data."""
data = b"\x01\x00\x01"
values = S7DataTypes.decode_s7_data(data, S7WordLen.BIT, 3)
assert len(values) == 3
assert values == [True, False, True]
def test_encode_s7_data_bytes(self) -> None:
"""Test encoding byte data."""
values = [1, 2, 3, 255]
data = S7DataTypes.encode_s7_data(values, S7WordLen.BYTE)
assert data == b"\x01\x02\x03\xff"
def test_encode_s7_data_words(self) -> None:
"""Test encoding word data."""
values = [0x0102, 0x0304]
data = S7DataTypes.encode_s7_data(values, S7WordLen.WORD)
# Should be big-endian
assert data == b"\x01\x02\x03\x04"
def test_encode_s7_data_real(self) -> None:
"""Test encoding IEEE float."""
values = [3.14159]
data = S7DataTypes.encode_s7_data(values, S7WordLen.REAL)
# Should be big-endian IEEE 754
expected = struct.pack(">f", 3.14159)
assert data == expected
def test_encode_s7_data_bits(self) -> None:
"""Test encoding bit data."""
values = [True, False, True, False]
data = S7DataTypes.encode_s7_data(values, S7WordLen.BIT)
assert data == b"\x01\x00\x01\x00"
def test_parse_address_db(self) -> None:
"""Test parsing DB addresses."""
# Test DB byte address
area, db_num, offset = S7DataTypes.parse_address("DB1.DBB10")
assert area == S7Area.DB
assert db_num == 1
assert offset == 10
# Test DB word address
area, db_num, offset = S7DataTypes.parse_address("DB5.DBW20")
assert area == S7Area.DB
assert db_num == 5
assert offset == 20
# Test DB bit address
area, db_num, offset = S7DataTypes.parse_address("DB1.DBX10.5")
assert area == S7Area.DB
assert db_num == 1
assert offset == 10 * 8 + 5 # Bit offset
def test_parse_address_memory(self) -> None:
"""Test parsing memory addresses."""
# Test memory byte
area, db_num, offset = S7DataTypes.parse_address("M10")
assert area == S7Area.MK
assert db_num == 0
assert offset == 10
# Test memory word
area, db_num, offset = S7DataTypes.parse_address("MW20")
assert area == S7Area.MK
assert db_num == 0
assert offset == 20
# Test memory bit
area, db_num, offset = S7DataTypes.parse_address("M10.5")
assert area == S7Area.MK
assert db_num == 0
assert offset == 10 * 8 + 5
def test_parse_address_inputs(self) -> None:
"""Test parsing input addresses."""
# Test input byte
area, db_num, offset = S7DataTypes.parse_address("I5")
assert area == S7Area.PE
assert db_num == 0
assert offset == 5
# Test input word
area, db_num, offset = S7DataTypes.parse_address("IW10")
assert area == S7Area.PE
assert db_num == 0
assert offset == 10
# Test input bit
area, db_num, offset = S7DataTypes.parse_address("I0.7")
assert area == S7Area.PE
assert db_num == 0
assert offset == 7
def test_parse_address_outputs(self) -> None:
"""Test parsing output addresses."""
# Test output byte
area, db_num, offset = S7DataTypes.parse_address("Q3")
assert area == S7Area.PA
assert db_num == 0
assert offset == 3
# Test output word
area, db_num, offset = S7DataTypes.parse_address("QW12")
assert area == S7Area.PA
assert db_num == 0
assert offset == 12
def test_parse_address_invalid(self) -> None:
"""Test parsing invalid addresses."""
with pytest.raises(ValueError):
S7DataTypes.parse_address("INVALID")
with pytest.raises(ValueError):
S7DataTypes.parse_address("X1.0") # Unsupported area
def test_parse_address_case_insensitive(self) -> None:
"""Test that address parsing is case insensitive."""
area1, db1, offset1 = S7DataTypes.parse_address("db1.dbw10")
area2, db2, offset2 = S7DataTypes.parse_address("DB1.DBW10")
assert area1 == area2
assert db1 == db2
assert offset1 == offset2