forked from keylime/keylime
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_binary.py
More file actions
412 lines (283 loc) · 13.7 KB
/
Copy pathtest_binary.py
File metadata and controls
412 lines (283 loc) · 13.7 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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
"""
Unit tests for keylime.models.base.types.binary module
"""
import base64
import unittest
from sqlalchemy.types import LargeBinary, String
from keylime.models.base.types.binary import Binary
class TestBinaryInitialization(unittest.TestCase):
"""Test cases for Binary initialization"""
def test_init_default_persist_as(self):
"""Test Binary initialization with default persist_as (LargeBinary)"""
binary = Binary()
self.assertIsInstance(binary._type_engine, LargeBinary) # pylint: disable=protected-access
def test_init_with_largebinary_class(self):
"""Test Binary initialization with LargeBinary class"""
binary = Binary(persist_as=LargeBinary)
self.assertIsInstance(binary._type_engine, LargeBinary) # pylint: disable=protected-access
def test_init_with_largebinary_instance(self):
"""Test Binary initialization with LargeBinary instance"""
binary = Binary(persist_as=LargeBinary())
self.assertIsInstance(binary._type_engine, LargeBinary) # pylint: disable=protected-access
def test_init_with_string_class(self):
"""Test Binary initialization with String class"""
binary = Binary(persist_as=String)
self.assertIsInstance(binary._type_engine, String) # pylint: disable=protected-access
def test_init_with_string_instance(self):
"""Test Binary initialization with String instance"""
binary = Binary(persist_as=String())
self.assertIsInstance(binary._type_engine, String) # pylint: disable=protected-access
def test_init_with_invalid_type_raises_error(self):
"""Test that Binary initialization with invalid persist_as raises TypeError"""
with self.assertRaises(TypeError) as context:
Binary(persist_as=int) # type: ignore[arg-type]
self.assertIn("must have a persist_as value of type 'LargeBinary' or 'String'", str(context.exception))
class TestBinaryCast(unittest.TestCase):
"""Test cases for Binary.cast() method"""
def test_cast_none_returns_none(self):
"""Test that casting None returns None"""
binary = Binary()
result = binary.cast(None)
self.assertIsNone(result)
def test_cast_empty_string_returns_none(self):
"""Test that casting empty string returns None"""
binary = Binary()
result = binary.cast("")
self.assertIsNone(result)
def test_cast_bytes_returns_unchanged(self):
"""Test that casting bytes returns them unchanged"""
binary = Binary()
data = b"\x03\xff\xaa\x55"
result = binary.cast(data)
self.assertEqual(result, data)
self.assertIsInstance(result, bytes)
def test_cast_base64_string(self):
"""Test casting valid base64 string"""
binary = Binary()
data = b"\x03\xff\xaa\x55"
base64_str = base64.b64encode(data).decode("utf-8")
result = binary.cast(base64_str)
self.assertEqual(result, data)
def test_cast_string_ambiguous_as_base64(self):
"""Test that ambiguous strings (valid as both base64 and hex) are treated as base64"""
binary = Binary()
# "03ffaa55" is valid base64, so it's decoded as base64 not hex
ambiguous_str = "03ffaa55"
result = binary.cast(ambiguous_str)
# Should be base64 decoded, not hex decoded
expected = base64.b64decode(ambiguous_str)
self.assertEqual(result, expected)
def test_cast_hex_string_with_prefix(self):
"""Test casting valid hex string with 0x prefix"""
binary = Binary()
hex_str = "0x03ffaa55"
result = binary.cast(hex_str)
self.assertEqual(result, b"\x03\xff\xaa\x55")
def test_cast_hex_only_with_0x_prefix(self):
"""Test that hex without 0x may be interpreted as base64 if valid"""
binary = Binary()
# Without 0x prefix, strings that are valid base64 are decoded as base64
hex_str = "DEADBEEF"
result = binary.cast(hex_str)
# This is valid base64, so it gets base64 decoded
expected = base64.b64decode(hex_str)
self.assertEqual(result, expected)
def test_cast_hex_string_with_prefix_uppercase(self):
"""Test casting hex string with 0x prefix and uppercase"""
binary = Binary()
hex_str = "0x03FFAA55"
result = binary.cast(hex_str)
self.assertEqual(result, b"\x03\xff\xaa\x55")
def test_cast_invalid_string_raises_value_error(self):
"""Test that casting invalid base64/hex string raises ValueError"""
binary = Binary()
invalid_str = "not valid base64 or hex!"
with self.assertRaises(ValueError) as context:
binary.cast(invalid_str)
self.assertIn("not valid base64 or hex", str(context.exception))
def test_cast_invalid_hex_string_raises_value_error(self):
"""Test that casting invalid hex string raises ValueError"""
binary = Binary()
invalid_hex = "0xGGHH" # Invalid hex characters
with self.assertRaises(ValueError) as context:
binary.cast(invalid_hex)
self.assertIn("not valid base64 or hex", str(context.exception))
def test_cast_odd_length_hex_raises_value_error(self):
"""Test that casting odd-length hex string raises ValueError"""
binary = Binary()
odd_hex = "03f" # Odd number of hex digits
with self.assertRaises(ValueError) as context:
binary.cast(odd_hex)
self.assertIn("not valid base64 or hex", str(context.exception))
def test_cast_invalid_type_raises_type_error(self):
"""Test that casting invalid type raises TypeError"""
binary = Binary()
invalid_value = 12345 # Integer is not valid
with self.assertRaises(TypeError) as context:
binary.cast(invalid_value) # type: ignore[arg-type]
self.assertIn("should be either 'bytes' or 'str'", str(context.exception))
def test_cast_list_raises_type_error(self):
"""Test that casting list raises TypeError"""
binary = Binary()
invalid_value = [1, 2, 3]
with self.assertRaises(TypeError) as context:
binary.cast(invalid_value) # type: ignore[arg-type]
self.assertIn("should be either 'bytes' or 'str'", str(context.exception))
class TestBinaryDump(unittest.TestCase):
"""Test cases for Binary._dump() method"""
def test_dump_none_returns_none(self):
"""Test that dumping None returns None"""
binary = Binary()
result = binary._dump(None) # pylint: disable=protected-access
self.assertIsNone(result)
def test_dump_empty_string_returns_none(self):
"""Test that dumping empty string returns None"""
binary = Binary()
result = binary._dump("") # pylint: disable=protected-access
self.assertIsNone(result)
def test_dump_bytes_with_largebinary_backend(self):
"""Test dumping bytes with LargeBinary backend returns bytes"""
binary = Binary(persist_as=LargeBinary)
data = b"\x03\xff\xaa\x55"
result = binary._dump(data) # pylint: disable=protected-access
self.assertEqual(result, data)
self.assertIsInstance(result, bytes)
def test_dump_bytes_with_string_backend(self):
"""Test dumping bytes with String backend returns base64"""
binary = Binary(persist_as=String)
data = b"\x03\xff\xaa\x55"
result = binary._dump(data) # pylint: disable=protected-access
expected = base64.b64encode(data).decode("utf-8")
self.assertEqual(result, expected)
self.assertIsInstance(result, str)
def test_dump_base64_string_with_largebinary_backend(self):
"""Test dumping base64 string with LargeBinary backend returns bytes"""
binary = Binary(persist_as=LargeBinary)
data = b"\x03\xff\xaa\x55"
base64_str = base64.b64encode(data).decode("utf-8")
result = binary._dump(base64_str) # pylint: disable=protected-access
self.assertEqual(result, data)
self.assertIsInstance(result, bytes)
def test_dump_base64_string_with_string_backend(self):
"""Test dumping base64 string with String backend returns base64"""
binary = Binary(persist_as=String)
data = b"\x03\xff\xaa\x55"
base64_str = base64.b64encode(data).decode("utf-8")
result = binary._dump(base64_str) # pylint: disable=protected-access
self.assertEqual(result, base64_str)
self.assertIsInstance(result, str)
def test_dump_hex_string_with_prefix_largebinary_backend(self):
"""Test dumping hex string with 0x prefix and LargeBinary backend returns bytes"""
binary = Binary(persist_as=LargeBinary)
hex_str = "0x03ffaa55" # Use 0x prefix to ensure hex interpretation
result = binary._dump(hex_str) # pylint: disable=protected-access
self.assertEqual(result, b"\x03\xff\xaa\x55")
self.assertIsInstance(result, bytes)
def test_dump_hex_string_with_prefix_string_backend(self):
"""Test dumping hex string with 0x prefix and String backend returns base64"""
binary = Binary(persist_as=String)
hex_str = "0x03ffaa55" # Use 0x prefix to ensure hex interpretation
expected_bytes = b"\x03\xff\xaa\x55"
expected_base64 = base64.b64encode(expected_bytes).decode("utf-8")
result = binary._dump(hex_str) # pylint: disable=protected-access
self.assertEqual(result, expected_base64)
self.assertIsInstance(result, str)
class TestBinaryRender(unittest.TestCase):
"""Test cases for Binary.render() method"""
def test_render_bytes_returns_base64(self):
"""Test that rendering bytes returns base64 string"""
binary = Binary()
data = b"\x03\xff\xaa\x55"
result = binary.render(data)
expected = base64.b64encode(data).decode("utf-8")
self.assertEqual(result, expected)
self.assertIsInstance(result, str)
def test_render_base64_string_returns_base64(self):
"""Test that rendering base64 string returns base64"""
binary = Binary()
data = b"\x03\xff\xaa\x55"
base64_str = base64.b64encode(data).decode("utf-8")
result = binary.render(base64_str)
self.assertEqual(result, base64_str)
def test_render_hex_string_with_prefix_returns_base64(self):
"""Test that rendering hex string with 0x prefix returns base64"""
binary = Binary()
hex_str = "0x03ffaa55" # Use 0x prefix to ensure hex interpretation
expected_bytes = b"\x03\xff\xaa\x55"
expected_base64 = base64.b64encode(expected_bytes).decode("utf-8")
result = binary.render(hex_str)
self.assertEqual(result, expected_base64)
def test_render_with_largebinary_backend_still_returns_base64(self):
"""Test that render always returns base64 regardless of backend"""
binary = Binary(persist_as=LargeBinary)
data = b"\x03\xff\xaa\x55"
result = binary.render(data)
expected = base64.b64encode(data).decode("utf-8")
self.assertEqual(result, expected)
def test_render_with_string_backend_returns_base64(self):
"""Test that render returns base64 with String backend"""
binary = Binary(persist_as=String)
data = b"\x03\xff\xaa\x55"
result = binary.render(data)
expected = base64.b64encode(data).decode("utf-8")
self.assertEqual(result, expected)
class TestBinaryProperties(unittest.TestCase):
"""Test cases for Binary properties"""
def test_native_type_returns_bytes(self):
"""Test that native_type property returns bytes class"""
binary = Binary()
self.assertEqual(binary.native_type, bytes)
def test_generate_error_msg(self):
"""Test that generate_error_msg returns correct message"""
binary = Binary()
msg = binary.generate_error_msg(b"any_value")
self.assertEqual(msg, "must be valid binary")
class TestBinaryEdgeCases(unittest.TestCase):
"""Test cases for Binary edge cases"""
def test_roundtrip_bytes_to_base64_to_bytes(self):
"""Test roundtrip: bytes -> render -> cast -> bytes"""
binary = Binary()
original = b"\x03\xff\xaa\x55\x12\x34\x56\x78"
# Render to base64
base64_str = binary.render(original)
# Cast back to bytes
result = binary.cast(base64_str)
self.assertEqual(result, original)
def test_roundtrip_hex_to_bytes_to_base64(self):
"""Test roundtrip: hex -> cast -> render"""
binary = Binary()
hex_str = "0x03ffaa55"
# Cast hex to bytes
data = binary.cast(hex_str)
# Render to base64
base64_str = binary.render(data)
# Cast base64 back to bytes
result = binary.cast(base64_str)
self.assertEqual(result, b"\x03\xff\xaa\x55")
def test_empty_bytes_handling(self):
"""Test handling of empty bytes"""
binary = Binary()
empty_bytes = b""
result = binary.cast(empty_bytes)
# Empty bytes is falsy, so cast returns None
self.assertIsNone(result)
def test_single_byte_value(self):
"""Test handling single byte value"""
binary = Binary()
single_byte = b"\xff"
result = binary.cast(single_byte)
self.assertEqual(result, single_byte)
def test_large_binary_data(self):
"""Test handling large binary data"""
binary = Binary()
large_data = b"\xff" * 1000
result = binary.cast(large_data)
self.assertEqual(result, large_data)
def test_zero_bytes(self):
"""Test handling binary data with zero bytes"""
binary = Binary()
zero_data = b"\x00\x00\x00\x00"
result = binary.cast(zero_data)
self.assertEqual(result, zero_data)
if __name__ == "__main__":
unittest.main()