blob: 9fdb0224aec2510fb9696806defb23ba9eb7c74e [file] [log] [blame]
Harald Welte865eea62023-01-27 19:26:12 +01001#!/usr/bin/env python3
2
3# (C) 2023 by Harald Welte <laforge@osmocom.org>
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18import unittest
19import logging
20
21from pySim.utils import *
22from pySim.filesystem import *
23
24import pySim.iso7816_4
25import pySim.ts_102_221
26import pySim.ts_102_222
27import pySim.ts_31_102
28import pySim.ts_31_103
29import pySim.ts_51_011
30import pySim.sysmocom_sja2
31import pySim.gsm_r
Harald Weltef9e2df12023-07-11 21:03:54 +020032import pySim.cdma_ruim
Harald Welte865eea62023-01-27 19:26:12 +010033
34def get_qualified_name(c):
35 """return the qualified (by module) name of a class."""
36 return "%s.%s" % (c.__module__, c.__name__)
37
38class LinFixed_Test(unittest.TestCase):
39 classes = all_subclasses(LinFixedEF)
Harald Weltee45168e2023-12-21 20:20:44 +010040 maxDiff = None
Harald Welte865eea62023-01-27 19:26:12 +010041
Harald Weltebcd26152023-12-28 09:34:05 +010042 @staticmethod
43 def _parse_t(t):
44 """Parse a test description which can either be a 2-tuple of (enc, dec) or
45 a 3-tuple of (enc, rec_nr, dec)."""
46 if len(t) == 2:
47 encoded = t[0]
48 rec_num = 1
49 decoded = t[1]
50 else:
51 encoded = t[0]
52 rec_num = t[1]
53 decoded = t[2]
54 return encoded, rec_num, decoded
55
Harald Welte865eea62023-01-27 19:26:12 +010056 def test_decode_record(self):
57 """Test the decoder for a linear-fixed EF. Requires the given LinFixedEF subclass
58 to have an '_test_decode' attribute, containing a list of tuples. Each tuple can
59 either be a
60 * 2-tuple (hexstring, decoded_dict) or a
61 * 3-tuple (hexstring, record_nr, decoded_dict)
62 """
63 for c in self.classes:
64 name = get_qualified_name(c)
65 if hasattr(c, '_test_decode'):
66 for t in c._test_decode:
Harald Weltece01f482023-12-28 09:41:35 +010067 encoded, rec_num, decoded = self._parse_t(t)
Harald Welte865eea62023-01-27 19:26:12 +010068 with self.subTest(name, test_decode=t):
69 inst = c()
Harald Welte865eea62023-01-27 19:26:12 +010070 logging.debug("Testing decode of %s", name)
71 re_dec = inst.decode_record_hex(encoded, rec_num)
72 self.assertEqual(decoded, re_dec)
Harald Weltece01f482023-12-28 09:41:35 +010073 if hasattr(c, '_test_no_pad') and c._test_no_pad:
74 continue
75 with self.subTest(name, test_decode_padded=t):
76 encoded = encoded + 'ff'
77 inst = c()
78 logging.debug("Testing padded decode of %s", name)
79 re_dec = inst.decode_record_hex(encoded, rec_num)
80 self.assertEqual(decoded, re_dec)
Harald Welte865eea62023-01-27 19:26:12 +010081
82 def test_encode_record(self):
83 """Test the encoder for a linear-fixed EF. Requires the given LinFixedEF subclass
84 to have an '_test_encode' attribute, containing a list of tuples. Each tuple can
85 either be a
86 * 2-tuple (hexstring, decoded_dict) or a
87 * 3-tuple (hexstring, record_nr, decoded_dict)
88 """
89 for c in self.classes:
90 name = get_qualified_name(c)
91 if hasattr(c, '_test_encode'):
92 for t in c._test_encode:
93 with self.subTest(name, test_encode=t):
94 inst = c()
Harald Weltebcd26152023-12-28 09:34:05 +010095 encoded, rec_num, decoded = self._parse_t(t)
Harald Welte865eea62023-01-27 19:26:12 +010096 logging.debug("Testing encode of %s", name)
97 re_enc = inst.encode_record_hex(decoded, rec_num)
Harald Welte2822dca2023-12-21 22:14:08 +010098 self.assertEqual(encoded.upper(), re_enc.upper())
Harald Welte865eea62023-01-27 19:26:12 +010099
100 def test_de_encode_record(self):
101 """Test the decoder and encoder for a linear-fixed EF. Performs first a decoder
102 test, and then re-encodes the decoded data, comparing the re-encoded data with the
103 initial input data.
104
105 Requires the given LinFixedEF subclass to have a '_test_de_encode' attribute,
106 containing a list of tuples. Each tuple can
107 either be a
108 * 2-tuple (hexstring, decoded_dict) or a
109 * 3-tuple (hexstring, record_nr, decoded_dict)
110 """
111 for c in self.classes:
112 name = get_qualified_name(c)
113 if hasattr(c, '_test_de_encode'):
114 for t in c._test_de_encode:
Harald Weltece01f482023-12-28 09:41:35 +0100115 encoded, rec_num, decoded = self._parse_t(t)
Harald Welte865eea62023-01-27 19:26:12 +0100116 with self.subTest(name, test_de_encode=t):
117 inst = c()
Harald Welte865eea62023-01-27 19:26:12 +0100118 logging.debug("Testing decode of %s", name)
119 re_dec = inst.decode_record_hex(encoded, rec_num)
120 self.assertEqual(decoded, re_dec)
121 # re-encode the decoded data
122 logging.debug("Testing re-encode of %s", name)
123 re_enc = inst.encode_record_hex(re_dec, rec_num)
Harald Welte2822dca2023-12-21 22:14:08 +0100124 self.assertEqual(encoded.upper(), re_enc.upper())
Harald Weltece01f482023-12-28 09:41:35 +0100125 if hasattr(c, '_test_no_pad') and c._test_no_pad:
126 continue
127 with self.subTest(name, test_decode_padded=t):
128 encoded = encoded + 'ff'
129 inst = c()
130 logging.debug("Testing padded decode of %s", name)
131 re_dec = inst.decode_record_hex(encoded, rec_num)
132 self.assertEqual(decoded, re_dec)
Harald Welte865eea62023-01-27 19:26:12 +0100133
134
135class TransRecEF_Test(unittest.TestCase):
136 classes = all_subclasses(TransRecEF)
Harald Weltee45168e2023-12-21 20:20:44 +0100137 maxDiff = None
Harald Welte865eea62023-01-27 19:26:12 +0100138
139 def test_decode_record(self):
140 """Test the decoder for a transparent record-oriented EF. Requires the given TransRecEF subclass
141 to have an '_test_decode' attribute, containing a list of tuples. Each tuple has to be a
142 2-tuple (hexstring, decoded_dict).
143 """
144 for c in self.classes:
145 name = get_qualified_name(c)
146 if hasattr(c, '_test_decode'):
147 for t in c._test_decode:
148 with self.subTest(name, test_decode=t):
149 inst = c()
150 encoded = t[0]
151 decoded = t[1]
152 logging.debug("Testing decode of %s", name)
153 re_dec = inst.decode_record_hex(encoded)
154 self.assertEqual(decoded, re_dec)
Harald Weltece01f482023-12-28 09:41:35 +0100155 # there's no point in testing padded input, as TransRecEF have a fixed record
156 # size and we cannot ever receive more input data than that size.
Harald Welte865eea62023-01-27 19:26:12 +0100157
158 def test_encode_record(self):
159 """Test the encoder for a transparent record-oriented EF. Requires the given TransRecEF subclass
160 to have an '_test_encode' attribute, containing a list of tuples. Each tuple has to be a
161 2-tuple (hexstring, decoded_dict).
162 """
163 for c in self.classes:
164 name = get_qualified_name(c)
165 if hasattr(c, '_test_decode'):
166 for t in c._test_decode:
167 with self.subTest(name, test_decode=t):
168 inst = c()
169 encoded = t[0]
170 decoded = t[1]
171 logging.debug("Testing decode of %s", name)
172 re_dec = inst.decode_record_hex(encoded)
173 self.assertEqual(decoded, re_dec)
174
175
176 def test_de_encode_record(self):
177 """Test the decoder and encoder for a transparent record-oriented EF. Performs first a decoder
178 test, and then re-encodes the decoded data, comparing the re-encoded data with the
179 initial input data.
180
181 Requires the given TransRecEF subclass to have a '_test_de_encode' attribute,
182 containing a list of tuples. Each tuple has to be a 2-tuple (hexstring, decoded_dict).
183 """
184 for c in self.classes:
185 name = get_qualified_name(c)
186 if hasattr(c, '_test_de_encode'):
187 for t in c._test_de_encode:
188 with self.subTest(name, test_de_encode=t):
189 inst = c()
190 encoded = t[0]
191 decoded = t[1]
192 logging.debug("Testing decode of %s", name)
193 re_dec = inst.decode_record_hex(encoded)
194 self.assertEqual(decoded, re_dec)
195 # re-encode the decoded data
196 logging.debug("Testing re-encode of %s", name)
197 re_enc = inst.encode_record_hex(re_dec)
Harald Welte2822dca2023-12-21 22:14:08 +0100198 self.assertEqual(encoded.upper(), re_enc.upper())
Harald Weltece01f482023-12-28 09:41:35 +0100199 # there's no point in testing padded input, as TransRecEF have a fixed record
200 # size and we cannot ever receive more input data than that size.
Harald Welte865eea62023-01-27 19:26:12 +0100201
202
203class TransparentEF_Test(unittest.TestCase):
Harald Weltee45168e2023-12-21 20:20:44 +0100204 maxDiff = None
205
Harald Welte865eea62023-01-27 19:26:12 +0100206 @classmethod
207 def get_classes(cls):
208 """get list of TransparentEF sub-classes which are not a TransRecEF subclass."""
209 classes = all_subclasses(TransparentEF)
210 trans_rec_classes = all_subclasses(TransRecEF)
211 return filter(lambda c: c not in trans_rec_classes, classes)
212
213 @classmethod
214 def setUpClass(cls):
215 """set-up method called once for this class by unittest framework"""
216 cls.classes = cls.get_classes()
217
218 def test_decode_file(self):
219 """Test the decoder for a transparent EF. Requires the given TransparentEF subclass
220 to have a '_test_decode' attribute, containing a list of tuples. Each tuple
221 is a 2-tuple (hexstring, decoded_dict).
222 """
223 for c in self.classes:
224 name = get_qualified_name(c)
225 if hasattr(c, '_test_decode'):
226 for t in c._test_decode:
Harald Weltece01f482023-12-28 09:41:35 +0100227 encoded = t[0]
228 decoded = t[1]
Harald Welte865eea62023-01-27 19:26:12 +0100229 with self.subTest(name, test_decode=t):
230 inst = c()
Harald Welte865eea62023-01-27 19:26:12 +0100231 logging.debug("Testing decode of %s", name)
232 re_dec = inst.decode_hex(encoded)
233 self.assertEqual(decoded, re_dec)
Harald Weltece01f482023-12-28 09:41:35 +0100234 if hasattr(c, '_test_no_pad') and c._test_no_pad:
235 continue
236 with self.subTest(name, test_decode_padded=t):
237 encoded = encoded + 'ff'
238 inst = c()
239 logging.debug("Testing padded decode of %s", name)
240 re_dec = inst.decode_hex(encoded)
241 self.assertEqual(decoded, re_dec)
Harald Welte865eea62023-01-27 19:26:12 +0100242
243 def test_encode_file(self):
244 """Test the encoder for a transparent EF. Requires the given TransparentEF subclass
245 to have a '_test_encode' attribute, containing a list of tuples. Each tuple
246 is a 2-tuple (hexstring, decoded_dict).
247 """
248 for c in self.classes:
249 name = get_qualified_name(c)
250 if hasattr(c, '_test_encode'):
251 for t in c._test_encode:
252 with self.subTest(name, test_encode=t):
253 inst = c()
254 encoded = t[0]
255 decoded = t[1]
256 logging.debug("Testing encode of %s", name)
257 re_dec = inst.decode_hex(encoded)
258 self.assertEqual(decoded, re_dec)
259
260 def test_de_encode_file(self):
261 """Test the decoder and encoder for a transparent EF. Performs first a decoder
262 test, and then re-encodes the decoded data, comparing the re-encoded data with the
263 initial input data.
264
265 Requires the given TransparentEF subclass to have a '_test_de_encode' attribute,
266 containing a list of tuples. Each tuple is a 2-tuple (hexstring, decoded_dict).
267 """
268 for c in self.classes:
269 name = get_qualified_name(c)
270 if hasattr(c, '_test_de_encode'):
271 for t in c._test_de_encode:
Harald Weltece01f482023-12-28 09:41:35 +0100272 encoded = t[0]
273 decoded = t[1]
Harald Welte865eea62023-01-27 19:26:12 +0100274 with self.subTest(name, test_de_encode=t):
275 inst = c()
Harald Welte865eea62023-01-27 19:26:12 +0100276 logging.debug("Testing decode of %s", name)
277 re_dec = inst.decode_hex(encoded)
278 self.assertEqual(decoded, re_dec)
279 logging.debug("Testing re-encode of %s", name)
280 re_dec = inst.decode_hex(encoded)
281 re_enc = inst.encode_hex(re_dec)
Harald Welte2822dca2023-12-21 22:14:08 +0100282 self.assertEqual(encoded.upper(), re_enc.upper())
Harald Weltece01f482023-12-28 09:41:35 +0100283 if hasattr(c, '_test_no_pad') and c._test_no_pad:
284 continue
285 with self.subTest(name, test_decode_padded=t):
286 encoded = encoded + 'ff'
287 inst = c()
288 logging.debug("Testing padded decode of %s", name)
289 re_dec = inst.decode_hex(encoded)
290 self.assertEqual(decoded, re_dec)
Harald Welte865eea62023-01-27 19:26:12 +0100291
292if __name__ == '__main__':
293 logger = logging.getLogger()
294 logger.setLevel(logging.DEBUG)
295 unittest.main()