From ce01f48b0084e067abd7718e207a6f2b85a5471e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 28 Dec 2023 09:41:35 +0100 Subject: [PATCH] test_files: Test decoder also with ff-padded input It's customary in the SIM card universe to right-pad data with ff bytes. So far we only test decoders without such padding, which is unrealistic. Let's also tests the decoders with extra 'ff' padding present. For some files this doesn't make sense, so we add a _test_no_pad class attribute that can be spcified to prevent this new "test with ff-padding" from being executed for the test data of the class. Change-Id: I7f5cbb4a6f91040fe9adef9da0a1f30f9f156dae --- pySim/cdma_ruim.py | 1 + pySim/ts_102_221.py | 1 + pySim/ts_31_102.py | 3 +++ pySim/ts_51_011.py | 6 ++++++ tests/test_files.py | 49 ++++++++++++++++++++++++++++++++++++++------- 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/pySim/cdma_ruim.py b/pySim/cdma_ruim.py index b254403f..ad50e607 100644 --- a/pySim/cdma_ruim.py +++ b/pySim/cdma_ruim.py @@ -117,6 +117,7 @@ class EF_AD(TransparentEF): _test_de_encode = [ ( "000000", { 'ms_operation_mode' : 'normal', 'additional_info' : '0000', 'rfu' : '' } ), ] + _test_no_pad = True class OP_MODE(enum.IntEnum): normal = 0x00 diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py index cb02bd38..308fc4a3 100644 --- a/pySim/ts_102_221.py +++ b/pySim/ts_102_221.py @@ -639,6 +639,7 @@ class EF_PL(TransRecEF): ( '656e', "en" ), ( 'ffff', None ), ] + def __init__(self, fid='2f05', sfid=0x05, name='EF.PL', desc='Preferred Languages'): super().__init__(fid, sfid=sfid, name=name, desc=desc, rec_len=2, size=(2, None)) diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py index cce6f356..1976ae0b 100644 --- a/pySim/ts_31_102.py +++ b/pySim/ts_31_102.py @@ -526,6 +526,7 @@ class EF_ECC(LinFixedEF): "marine_guard": False, "mountain_rescue": False, "manual_ecall": False, "automatic_ecall": False } } ), ] + _test_no_pad = True cc_construct = BcdAdapter(Rpad(Bytes(3))) category_construct = FlagsEnum(Byte, police=1, ambulance=2, fire_brigade=3, marine_guard=4, mountain_rescue=5, manual_ecall=6, automatic_ecall=7) @@ -588,6 +589,8 @@ class EF_AD(TransparentEF): "prose_services": False, "extended_drx": False }, "rfu": 0, "mnc_len": 2, "extensions": b'' } ), ] + _test_no_pad = True + class OP_MODE(enum.IntEnum): normal = 0x00 type_approval = 0x80 diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py index 65237698..0a6f774c 100644 --- a/pySim/ts_51_011.py +++ b/pySim/ts_51_011.py @@ -141,6 +141,7 @@ class EF_ADN(LinFixedEF): "numbering_plan_id": "isdn_e164"}, "dialing_nr": "491721217212", "cap_conf_id": 255, "ext1_record_id": 255} ) ] + _test_no_pad = True def __init__(self, fid='6f3a', sfid=None, name='EF.ADN', desc='Abbreviated Dialing Numbers', ext=1, **kwargs): super().__init__(fid, sfid=sfid, name=name, desc=desc, rec_len=(14, 30), **kwargs) @@ -215,6 +216,7 @@ class EF_SMSP(LinFixedEF): "call_number": "" }, "tp_pid": "00", "tp_dcs": "00", "tp_vp_minutes": 1440 } ), ] + _test_no_pad = True class ValidityPeriodAdapter(Adapter): def _decode(self, obj, context, path): if obj <= 143: @@ -565,6 +567,8 @@ class EF_AD(TransparentEF): ( "00ffff", { "ms_operation_mode": "normal", "rfu1": 255, "rfu2": 127, "ofm": True, "extensions": None } ), ] + _test_no_pad = True + class OP_MODE(enum.IntEnum): normal = 0x00 type_approval = 0x80 @@ -871,6 +875,8 @@ class EF_MWIS(LinFixedEF): False}, "num_waiting_voicemail": 0, "num_waiting_fax": 0, "num_waiting_email": 0, "num_waiting_other": 0, "num_waiting_videomail": None} ), ] + _test_no_pad = True + def __init__(self, fid='6fca', sfid=None, name='EF.MWIS', rec_len=(5, 6), desc='Message Waiting Indication Status', **kwargs): super().__init__(fid, sfid=sfid, name=name, desc=desc, rec_len=rec_len, **kwargs) diff --git a/tests/test_files.py b/tests/test_files.py index 2eaaad18..9fdb0224 100755 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -64,12 +64,20 @@ class LinFixed_Test(unittest.TestCase): name = get_qualified_name(c) if hasattr(c, '_test_decode'): for t in c._test_decode: + encoded, rec_num, decoded = self._parse_t(t) with self.subTest(name, test_decode=t): inst = c() - encoded, rec_num, decoded = self._parse_t(t) logging.debug("Testing decode of %s", name) re_dec = inst.decode_record_hex(encoded, rec_num) self.assertEqual(decoded, re_dec) + if hasattr(c, '_test_no_pad') and c._test_no_pad: + continue + with self.subTest(name, test_decode_padded=t): + encoded = encoded + 'ff' + inst = c() + logging.debug("Testing padded decode of %s", name) + re_dec = inst.decode_record_hex(encoded, rec_num) + self.assertEqual(decoded, re_dec) def test_encode_record(self): """Test the encoder for a linear-fixed EF. Requires the given LinFixedEF subclass @@ -104,9 +112,9 @@ class LinFixed_Test(unittest.TestCase): name = get_qualified_name(c) if hasattr(c, '_test_de_encode'): for t in c._test_de_encode: + encoded, rec_num, decoded = self._parse_t(t) with self.subTest(name, test_de_encode=t): inst = c() - encoded, rec_num, decoded = self._parse_t(t) logging.debug("Testing decode of %s", name) re_dec = inst.decode_record_hex(encoded, rec_num) self.assertEqual(decoded, re_dec) @@ -114,6 +122,14 @@ class LinFixed_Test(unittest.TestCase): logging.debug("Testing re-encode of %s", name) re_enc = inst.encode_record_hex(re_dec, rec_num) self.assertEqual(encoded.upper(), re_enc.upper()) + if hasattr(c, '_test_no_pad') and c._test_no_pad: + continue + with self.subTest(name, test_decode_padded=t): + encoded = encoded + 'ff' + inst = c() + logging.debug("Testing padded decode of %s", name) + re_dec = inst.decode_record_hex(encoded, rec_num) + self.assertEqual(decoded, re_dec) class TransRecEF_Test(unittest.TestCase): @@ -136,6 +152,8 @@ class TransRecEF_Test(unittest.TestCase): logging.debug("Testing decode of %s", name) re_dec = inst.decode_record_hex(encoded) self.assertEqual(decoded, re_dec) + # there's no point in testing padded input, as TransRecEF have a fixed record + # size and we cannot ever receive more input data than that size. def test_encode_record(self): """Test the encoder for a transparent record-oriented EF. Requires the given TransRecEF subclass @@ -178,6 +196,8 @@ class TransRecEF_Test(unittest.TestCase): logging.debug("Testing re-encode of %s", name) re_enc = inst.encode_record_hex(re_dec) self.assertEqual(encoded.upper(), re_enc.upper()) + # there's no point in testing padded input, as TransRecEF have a fixed record + # size and we cannot ever receive more input data than that size. class TransparentEF_Test(unittest.TestCase): @@ -204,13 +224,21 @@ class TransparentEF_Test(unittest.TestCase): name = get_qualified_name(c) if hasattr(c, '_test_decode'): for t in c._test_decode: + encoded = t[0] + decoded = t[1] with self.subTest(name, test_decode=t): inst = c() - encoded = t[0] - decoded = t[1] logging.debug("Testing decode of %s", name) re_dec = inst.decode_hex(encoded) self.assertEqual(decoded, re_dec) + if hasattr(c, '_test_no_pad') and c._test_no_pad: + continue + with self.subTest(name, test_decode_padded=t): + encoded = encoded + 'ff' + inst = c() + logging.debug("Testing padded decode of %s", name) + re_dec = inst.decode_hex(encoded) + self.assertEqual(decoded, re_dec) def test_encode_file(self): """Test the encoder for a transparent EF. Requires the given TransparentEF subclass @@ -241,10 +269,10 @@ class TransparentEF_Test(unittest.TestCase): name = get_qualified_name(c) if hasattr(c, '_test_de_encode'): for t in c._test_de_encode: + encoded = t[0] + decoded = t[1] with self.subTest(name, test_de_encode=t): inst = c() - encoded = t[0] - decoded = t[1] logging.debug("Testing decode of %s", name) re_dec = inst.decode_hex(encoded) self.assertEqual(decoded, re_dec) @@ -252,7 +280,14 @@ class TransparentEF_Test(unittest.TestCase): re_dec = inst.decode_hex(encoded) re_enc = inst.encode_hex(re_dec) self.assertEqual(encoded.upper(), re_enc.upper()) - + if hasattr(c, '_test_no_pad') and c._test_no_pad: + continue + with self.subTest(name, test_decode_padded=t): + encoded = encoded + 'ff' + inst = c() + logging.debug("Testing padded decode of %s", name) + re_dec = inst.decode_hex(encoded) + self.assertEqual(decoded, re_dec) if __name__ == '__main__': logger = logging.getLogger()