Port to Python 3.
[catacomb-python] / t / t-bytes.py
1 ### -*- mode: python, coding: utf-8 -*-
2 ###
3 ### Test `ByteString'
4 ###
5 ### (c) 2019 Straylight/Edgeware
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of the Python interface to Catacomb.
11 ###
12 ### Catacomb/Python is free software: you can redistribute it and/or
13 ### modify it under the terms of the GNU General Public License as
14 ### published by the Free Software Foundation; either version 2 of the
15 ### License, or (at your option) any later version.
16 ###
17 ### Catacomb/Python is distributed in the hope that it will be useful, but
18 ### WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ### General Public License for more details.
21 ###
22 ### You should have received a copy of the GNU General Public License
23 ### along with Catacomb/Python. If not, write to the Free Software
24 ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25 ### USA.
26
27 ###--------------------------------------------------------------------------
28 ### Imported modules.
29
30 import sys as SYS
31 import catacomb as C
32 import unittest as U
33 import testutils as T
34
35 ###--------------------------------------------------------------------------
36 class TestByteString (U.TestCase):
37
38 def test_create(me):
39
40 ## Create a string and make sure it looks right.
41 x = C.ByteString(T.bin("abcde"))
42 me.assertEqual(x, T.bin("abcde"))
43 me.assertEqual(x, C.bytes("6162636465"))
44 me.assertEqual(len(x), 5)
45
46 def test_index(me):
47
48 x = C.ByteString(T.bin("once upon a time there was a string"))
49
50 ## Check that simple indexing works. Alas the behaviour differs between
51 ## Python major versions.
52 if T.PY3:
53 me.assertEqual(type(x[3]), int)
54 me.assertEqual(x[3], 101)
55 me.assertEqual(x[-5], 116)
56 else:
57 me.assertEqual(type(x[3]), C.ByteString)
58 me.assertEqual(x[3], 'e')
59 me.assertEqual(x[-5], 't')
60
61 ## Check out-of-range detection.
62 x[34]; me.assertRaises(IndexError, lambda: x[35])
63 x[-35]; me.assertRaises(IndexError, lambda: x[-36])
64
65 ## Check slicing. This should always give us bytes.
66 me.assertEqual(type(x[7:17]), C.ByteString)
67 me.assertEqual(x[7:17], T.bin("on a time "))
68
69 ## Complex slicing is also supported.
70 me.assertEqual(x[5:23:3], C.bytes("756e206d7472"))
71
72 def test_compare(me):
73 """
74 Test byte string comparison.
75
76 This is rather important, since we override it and many of the other
77 tests assume that comparison works.
78 """
79
80 def check(big, small):
81 """Check comparisons between BIG and SMALL strings."""
82
83 ## Equality.
84 me.assertTrue(big == big)
85 me.assertFalse(big == small)
86
87 ## Inequality.
88 me.assertFalse(big != big)
89 me.assertTrue(big != small)
90
91 ## Strict less-than.
92 me.assertFalse(big < big)
93 me.assertFalse(big < small)
94 me.assertTrue(small < big)
95
96 ## Non-strict less-than.
97 me.assertTrue(big <= big)
98 me.assertFalse(big <= small)
99 me.assertTrue(small <= big)
100
101 ## Non-strict greater-than.
102 me.assertTrue(big >= big)
103 me.assertTrue(big >= small)
104 me.assertFalse(small >= big)
105
106 ## Strict greater-than.
107 me.assertFalse(big > big)
108 me.assertTrue(big > small)
109 me.assertFalse(small > big)
110
111 ## Strings with equal length.
112 check(C.ByteString(T.bin("a string which is unlike the second")),
113 C.ByteString(T.bin("a string that is not like the first")))
114
115 ## A string and a prefix of it.
116 check(C.ByteString(T.bin("short strings order before longer ones")),
117 C.ByteString(T.bin("short string")))
118
119 ## The `ctstreq' function.
120 x = T.bin("special test string")
121 y = T.bin("my different string")
122 me.assertTrue(C.ctstreq(x, x))
123 me.assertFalse(C.ctstreq(x, y))
124
125 def test_operators(me):
126
127 ## Some example strings.
128 x = C.bytes("03a5fc")
129 y = C.bytes("5fac30")
130 z = C.bytes("00000000")
131
132 ## Operands of a binary operator must have equal lengths.
133 me.assertRaises(ValueError, lambda: x&z)
134 me.assertRaises(ValueError, lambda: x|z)
135 me.assertRaises(ValueError, lambda: x^z)
136
137 ## Bitwise AND.
138 me.assertEqual(type(x&y), C.ByteString)
139 me.assertEqual(x&y, C.bytes("03a430"))
140
141 ## Bitwise OR.
142 me.assertEqual(type(x | y), C.ByteString)
143 me.assertEqual(x | y, C.bytes("5fadfc"))
144
145 # Bitwise XOR.
146 me.assertEqual(type(x ^ y), C.ByteString)
147 me.assertEqual(x ^ y, C.bytes("5c09cc"))
148
149 # Bitwise NOT.
150 me.assertEqual(type(~x), C.ByteString)
151 me.assertEqual(~x, C.bytes("fc5a03"))
152
153 ## Concatenation.
154 me.assertEqual(type(x + y), C.ByteString)
155 me.assertEqual(x + y, C.bytes("03a5fc5fac30"))
156
157 ## Replication (asymmetric but commutative).
158 me.assertEqual(type(3*x), C.ByteString)
159 me.assertEqual(type(x*3), C.ByteString)
160 me.assertEqual(3*x, C.bytes("03a5fc03a5fc03a5fc"))
161 me.assertEqual(x*3, C.bytes("03a5fc03a5fc03a5fc"))
162
163 ## Replication by zero (regression test).
164 me.assertEqual(type(0*x), C.ByteString)
165 me.assertEqual(type(x*0), C.ByteString)
166 me.assertEqual(0*x, C.ByteString(T.bin("")))
167 me.assertEqual(x*0, C.ByteString(T.bin("")))
168
169 def test_zero(me):
170 me.assertEqual(C.ByteString.zero(7), T.bin(7*"\0"))
171 me.assertEqual(C.ByteString.zero(0), T.bin(""))
172
173 ###----- That's all, folks --------------------------------------------------
174
175 if __name__ == "__main__": U.main()