filesystem: add unit tests for encoder/decoder methods

Lets add test vectors for the per-record/per-file encode/decode of
our various classes for the Elementary Files.

We keep the test vectors as class variables of the respective EF-classes
to ensure implementation and test vectors are next to each other.

The test classes then iterate over all EF subclasses and execute the
decode/encode functions using the test vectors from the class variables.

Change-Id: I02d884547f4982e0b8ed7ef21b8cda75237942e2
Related: OS#4963
This commit is contained in:
Harald Welte 2023-01-27 19:26:12 +01:00
parent d2edd414a8
commit 865eea68c3
7 changed files with 523 additions and 13 deletions

View File

@ -58,7 +58,11 @@ class FuncNTypeAdapter(Adapter):
class EF_FN(LinFixedEF):
"""Section 7.2"""
_test_decode = [
( "40315801000010ff01",
{ "functional_number_and_type": { "functional_number": "04138510000001f",
"presentation_of_only_this_fn": True, "permanent_fn": True }, "list_number": 1 } ),
]
def __init__(self):
super().__init__(fid='6ff1', sfid=None, name='EF.FN',
desc='Functional numbers', rec_len=(9, 9))
@ -147,7 +151,12 @@ NextTableType = Enum(Byte, decision=0xf0, predefined=0xf1,
class EF_CallconfC(TransparentEF):
"""Section 7.3"""
_test_de_encode = [
( "026121ffffffffffff1e000a040a010253600795792426f0",
{ "pl_conf": 3, "conf_nr": "1612ffffffffffff", "max_rand": 30, "n_ack_max": 10,
"pl_ack": 1, "n_nested_max": 10, "train_emergency_gid": 1, "shunting_emergency_gid": 2,
"imei": "350670599742620f" } ),
]
def __init__(self):
super().__init__(fid='6ff2', sfid=None, name='EF.CallconfC', size=(24, 24),
desc='Call Configuration of emergency calls Configuration')
@ -180,7 +189,9 @@ class EF_CallconfI(LinFixedEF):
class EF_Shunting(TransparentEF):
"""Section 7.6"""
_test_de_encode = [
( "03f8ffffff000000", { "common_gid": 3, "shunting_gid": "f8ffffff000000" } ),
]
def __init__(self):
super().__init__(fid='6ff4', sfid=None,
name='EF.Shunting', desc='Shunting', size=(8, 8))
@ -190,7 +201,18 @@ class EF_Shunting(TransparentEF):
class EF_GsmrPLMN(LinFixedEF):
"""Section 7.7"""
_test_de_encode = [
( "22f860f86f8d6f8e01", { "plmn": "228f06", "class_of_network": {
"supported": { "vbs": True, "vgcs": True, "emlpp": True,
"fn": True, "eirene": True }, "preference": 0 },
"ic_incoming_ref_tbl": "6f8d", "outgoing_ref_tbl": "6f8e",
"ic_table_ref": "01" } ),
( "22f810416f8d6f8e02", { "plmn": "228f01", "class_of_network": {
"supported": { "vbs": False, "vgcs": False, "emlpp": False,
"fn": True, "eirene": False }, "preference": 1 },
"ic_incoming_ref_tbl": "6f8d", "outgoing_ref_tbl": "6f8e",
"ic_table_ref": "02" } ),
]
def __init__(self):
super().__init__(fid='6ff5', sfid=None, name='EF.GsmrPLMN',
desc='GSM-R network selection', rec_len=(9, 9))
@ -204,7 +226,12 @@ class EF_GsmrPLMN(LinFixedEF):
class EF_IC(LinFixedEF):
"""Section 7.8"""
_test_de_encode = [
( "f06f8e40f10001", { "next_table_type": "decision", "id_of_next_table": "6f8e",
"ic_decision_value": "041f", "network_string_table_index": 1 } ),
( "ffffffffffffff", { "next_table_type": "empty", "id_of_next_table": "ffff",
"ic_decision_value": "ffff", "network_string_table_index": 65535 } ),
]
def __init__(self):
super().__init__(fid='6f8d', sfid=None, name='EF.IC',
desc='International Code', rec_len=(7, 7))
@ -216,7 +243,12 @@ class EF_IC(LinFixedEF):
class EF_NW(LinFixedEF):
"""Section 7.9"""
_test_de_encode = [
( "47534d2d52204348", "GSM-R CH" ),
( "537769737347534d", "SwissGSM" ),
( "47534d2d52204442", "GSM-R DB" ),
( "47534d2d52524649", "GSM-RRFI" ),
]
def __init__(self):
super().__init__(fid='6f80', sfid=None, name='EF.NW',
desc='Network Name', rec_len=(8, 8))
@ -225,8 +257,15 @@ class EF_NW(LinFixedEF):
class EF_Switching(LinFixedEF):
"""Section 8.4"""
def __init__(self, fid, name, desc):
_test_de_encode = [
( "f26f87f0ff00", { "next_table_type": "num_dial_digits", "id_of_next_table": "6f87",
"decision_value": "0fff", "string_table_index": 0 } ),
( "f06f8ff1ff01", { "next_table_type": "decision", "id_of_next_table": "6f8f",
"decision_value": "1fff", "string_table_index": 1 } ),
( "f16f89f5ff05", { "next_table_type": "predefined", "id_of_next_table": "6f89",
"decision_value": "5fff", "string_table_index": 5 } ),
]
def __init__(self, fid='1234', name='Switching', desc=None):
super().__init__(fid=fid, sfid=None,
name=name, desc=desc, rec_len=(6, 6))
self._construct = Struct('next_table_type'/NextTableType,
@ -237,13 +276,17 @@ class EF_Switching(LinFixedEF):
class EF_Predefined(LinFixedEF):
"""Section 8.5"""
_test_de_encode = [
( "f26f85", 1, { "next_table_type": "num_dial_digits", "id_of_next_table": "6f85" } ),
( "f0ffc8", 2, { "predefined_value1": "0fff", "string_table_index1": 200 } ),
]
# header and other records have different structure. WTF !?!
construct_first = Struct('next_table_type'/NextTableType,
'id_of_next_table'/HexAdapter(Bytes(2)))
construct_others = Struct('predefined_value1'/BcdAdapter(Bytes(2)),
'string_table_index1'/Int8ub)
def __init__(self, fid, name, desc):
def __init__(self, fid='1234', name='Predefined', desc=None):
super().__init__(fid=fid, sfid=None,
name=name, desc=desc, rec_len=(3, 3))
@ -263,8 +306,11 @@ class EF_Predefined(LinFixedEF):
class EF_DialledVals(TransparentEF):
"""Section 8.6"""
def __init__(self, fid, name, desc):
_test_de_encode = [
( "ffffff22", { "next_table_type": "empty", "id_of_next_table": "ffff", "dialed_digits": "22" } ),
( "f16f8885", { "next_table_type": "predefined", "id_of_next_table": "6f88", "dialed_digits": "58" }),
]
def __init__(self, fid='1234', name='DialledVals', desc=None):
super().__init__(fid=fid, sfid=None, name=name, desc=desc, size=(4, 4))
self._construct = Struct('next_table_type'/NextTableType,
'id_of_next_table'/HexAdapter(Bytes(2)),

View File

@ -574,6 +574,14 @@ SC_DO = DataObjectChoice('security_condition', 'Security Condition',
# TS 102 221 Section 13.1
class EF_DIR(LinFixedEF):
# FIXME: re-encode failure when changing to _test_de_encode
_test_decode = [
( '61294f10a0000000871002ffffffff890709000050055553696d31730ea00c80011781025f608203454150',
{ "application_template": [ { "application_id": h2b("a0000000871002ffffffff8907090000") },
{ "application_label": "USim1" },
{ "discretionary_template": h2b("a00c80011781025f608203454150") } ] }
),
]
class ApplicationLabel(BER_TLV_IE, tag=0x50):
# TODO: UCS-2 coding option as per Annex A of TS 102 221
_construct = GreedyString('ascii')
@ -593,6 +601,9 @@ class EF_DIR(LinFixedEF):
# TS 102 221 Section 13.2
class EF_ICCID(TransparentEF):
_test_de_encode = [
( '988812010000400310f0', { "iccid": "8988211000000430010" } ),
]
def __init__(self, fid='2fe2', sfid=0x02, name='EF.ICCID', desc='ICC Identification'):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=(10, 10))
@ -604,6 +615,11 @@ class EF_ICCID(TransparentEF):
# TS 102 221 Section 13.3
class EF_PL(TransRecEF):
_test_de_encode = [
( '6465', "de" ),
( '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))
@ -623,6 +639,28 @@ class EF_PL(TransRecEF):
# TS 102 221 Section 13.4
class EF_ARR(LinFixedEF):
_test_de_encode = [
( '800101a40683010a950108800106900080016097008401d4a40683010a950108',
[ [ { "access_mode": [ "read_search_compare" ] },
{ "control_reference_template": "ADM1" } ],
[ { "access_mode": [ "write_append", "update_erase" ] },
{ "always": None } ],
[ { "access_mode": [ "delete_file", "terminate_ef" ] },
{ "never": None } ],
[ { "command_header": { "INS": 212 } },
{ "control_reference_template": "ADM1" } ]
] ),
( '80010190008001029700800118a40683010a9501088401d4a40683010a950108',
[ [ { "access_mode": [ "read_search_compare" ] },
{ "always": None } ],
[ { "access_mode": [ "update_erase" ] },
{ "never": None } ],
[ { "access_mode": [ "activate_file_or_record", "deactivate_file_or_record" ] },
{ "control_reference_template": "ADM1" } ],
[ { "command_header": { "INS": 212 } },
{ "control_reference_template": "ADM1" } ]
] ),
]
def __init__(self, fid='2f06', sfid=0x06, name='EF.ARR', desc='Access Rule Reference'):
super().__init__(fid, sfid=sfid, name=name, desc=desc)
# add those commands to the general commands of a TransparentEF
@ -705,6 +743,10 @@ class EF_ARR(LinFixedEF):
# TS 102 221 Section 13.6
class EF_UMPC(TransparentEF):
_test_de_encode = [
( '3cff02', { "max_current_mA": 60, "t_op_s": 255,
"addl_info": { "req_inc_idle_current": False, "support_uicc_suspend": True } } ),
]
def __init__(self, fid='2f08', sfid=0x08, name='EF.UMPC', desc='UICC Maximum Power Consumption'):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=(5, 5))
addl_info = FlagsEnum(Byte, req_inc_idle_current=1,

View File

@ -539,6 +539,7 @@ class EF_Keys(TransparentEF):
# TS 31.102 Section 4.2.6
class EF_HPPLMN(TransparentEF):
_test_de_encode = [ ( '05', 5 ) ]
def __init__(self, fid='6f31', sfid=0x12, name='EF.HPPLMN', size=(1, 1),
desc='Higher Priority PLMN search period'):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
@ -595,7 +596,17 @@ class EF_UST(EF_UServiceTable):
# TS 31.103 Section 4.2.7 - *not* the same as DF.GSM/EF.ECC!
class EF_ECC(LinFixedEF):
cc_construct = Rpad(BcdAdapter(Rpad(Bytes(3))), pattern='f')
_test_de_encode = [
( '19f1ff01', { "call_code": "911f",
"service_category": { "police": True, "ambulance": False, "fire_brigade": False,
"marine_guard": False, "mountain_rescue": False,
"manual_ecall": False, "automatic_ecall": False } } ),
( '19f3ff02', { "call_code": "913f",
"service_category": { "police": False, "ambulance": True, "fire_brigade": False,
"marine_guard": False, "mountain_rescue": False,
"manual_ecall": False, "automatic_ecall": False } } ),
]
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)
alpha_construct = GsmStringAdapter(Rpad(GreedyBytes))
@ -633,12 +644,28 @@ class EF_ECC(LinFixedEF):
# TS 31.102 Section 4.2.17
class EF_LOCI(TransparentEF):
_test_de_encode = [
( '47d1264a62f21037211e00',
{ "tmsi": "47d1264a", "lai": { "mcc_mnc": "262f01", "lac": "3721" },
"rfu": 30, "lu_status": 0 } ),
]
def __init__(self, fid='6f7e', sfid=0x0b, name='EF.LOCI', desc='Location information', size=(11, 11)):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
Lai = Struct('mcc_mnc'/BcdAdapter(Bytes(3)), 'lac'/HexAdapter(Bytes(2)))
self._construct = Struct('tmsi'/HexAdapter(Bytes(4)), 'lai'/Lai, 'rfu'/Int8ub, 'lu_status'/Int8ub)
# TS 31.102 Section 4.2.18
class EF_AD(TransparentEF):
_test_de_encode = [
( '00000002', { "ms_operation_mode": "normal",
"additional_info": { "ciphering_indicator": False, "csg_display_control": False,
"prose_services": False, "extended_drx": False },
"rfu": 0, "mnc_len": 2, "extensions": b'' } ),
( '01000102', { "ms_operation_mode": "normal_and_specific_facilities",
"additional_info": { "ciphering_indicator": True, "csg_display_control": False,
"prose_services": False, "extended_drx": False },
"rfu": 0, "mnc_len": 2, "extensions": b'' } ),
]
class OP_MODE(enum.IntEnum):
normal = 0x00
type_approval = 0x80
@ -739,6 +766,9 @@ class EF_ACL(TransparentEF):
# TS 31.102 Section 4.2.51
class EF_START_HFN(TransparentEF):
_test_de_encode = [
( 'f00000f00000', { "start_cs": 15728640, "start_ps": 15728640 } ),
]
def __init__(self, fid='6f5b', sfid=0x0f, name='EF.START-HFN', size=(6, 6),
desc='Initialisation values for Hyperframe number', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -746,6 +776,9 @@ class EF_START_HFN(TransparentEF):
# TS 31.102 Section 4.2.52
class EF_THRESHOLD(TransparentEF):
_test_de_encode = [
( 'f01000', { "max_start": 15732736 } ),
]
def __init__(self, fid='6f5c', sfid=0x10, name='EF.THRESHOLD', size=(3, 3),
desc='Maximum value of START', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -820,6 +853,9 @@ class EF_GBANL(LinFixedEF):
# TS 31.102 Section 4.2.85
class EF_EHPLMNPI(TransparentEF):
_test_de_encode = [
( '02', { "presentation_ind": "display_all" } ),
]
def __init__(self, fid='6fdb', sfid=None, name='EF.EHPLMNPI', size=(1, 1),
desc='Equivalent HPLMN Presentation Indication', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -905,6 +941,10 @@ class EF_EPSNSC(LinFixedEF):
# TS 31.102 Section 4.2.96
class EF_PWS(TransparentEF):
_test_de_encode = [
( '00', { "pws_configuration": { "ignore_pws_in_hplmn_and_equivalent": False,
"ignore_pws_in_vplmn": False } } ),
]
def __init__(self, fid='6fec', sfid=None, name='EF.PWS', desc='Public Warning System', size=(1, 1), **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
pws_config = FlagsEnum(
@ -973,6 +1013,10 @@ class EF_5GS3GPPLOCI(TransparentEF):
# TS 31.102 Section 4.4.11.7
class EF_UAC_AIC(TransparentEF):
_test_de_encode = [
( '03', { "uac_access_id_config": { "multimedia_priority_service": True,
"mission_critical_service": True } } ),
]
def __init__(self, fid='4f06', sfid=0x06, name='EF.UAC_AIC', size=(4, 4),
desc='UAC Access Identities Configuration', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)

View File

@ -124,6 +124,7 @@ class EF_UServiceTable(TransparentEF):
# TS 31.102 Section 4.4.2.1
class EF_PBR(LinFixedEF):
# TODO: a80ac0034f3a02c5034f0904aa0acb034f3d07c2034f4a06
def __init__(self, fid='4F30', name='EF.PBR', desc='Phone Book Reference', **kwargs):
super().__init__(fid, name=name, desc=desc, **kwargs)
#self._tlv = FIXME

View File

@ -80,6 +80,11 @@ EF_ISIM_ADF_map = {
# TS 31.103 Section 4.2.2
class EF_IMPI(TransparentEF):
# FIXME: re-encode fails with "string encoding failed, expected unicode string"
_test_decode = [
( '803137333830303630303030303031303140696d732e6d6e633030302e6d63633733382e336770706e6574776f726b2e6f7267',
{ "nai": "738006000000101@ims.mnc000.mcc738.3gppnetwork.org" } ),
]
class nai(BER_TLV_IE, tag=0x80):
_construct = GreedyString("utf8")
@ -89,6 +94,11 @@ class EF_IMPI(TransparentEF):
# TS 31.103 Section 4.2.3
class EF_DOMAIN(TransparentEF):
# FIXME: re-encode fails with "string encoding failed, expected unicode string"
_test_decode = [
( '8021696d732e6d6e633030302e6d63633733382e336770706e6574776f726b2e6f7267',
{ "domain": "ims.mnc000.mcc738.3gppnetwork.org" } ),
]
class domain(BER_TLV_IE, tag=0x80):
_construct = GreedyString("utf8")
@ -98,6 +108,11 @@ class EF_DOMAIN(TransparentEF):
# TS 31.103 Section 4.2.4
class EF_IMPU(LinFixedEF):
# FIXME: re-encode fails with "string encoding failed, expected unicode string"
_test_decode = [
( '80357369703a37333830303630303030303031303140696d732e6d6e633030302e6d63633733382e336770706e6574776f726b2e6f7267',
{ "impu": "sip:738006000000101@ims.mnc000.mcc738.3gppnetwork.org" } ),
]
class impu(BER_TLV_IE, tag=0x80):
_construct = GreedyString("utf8")
@ -139,6 +154,10 @@ class EF_IST(EF_UServiceTable):
# TS 31.103 Section 4.2.8
class EF_PCSCF(LinFixedEF):
_test_de_encode = [
( '802c0070637363662e696d732e6d6e633030302e6d63633733382e7075622e336770706e6574776f726b2e6f7267',
{ "addr": "pcscf.ims.mnc000.mcc738.pub.3gppnetwork.org", "addr_type": "00" } ),
]
def __init__(self, fid='6f09', sfid=None, name='EF.P-CSCF', desc='P-CSCF Address', **kwargs):
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, **kwargs)
@ -163,6 +182,8 @@ class EF_GBANL(LinFixedEF):
# TS 31.103 Section 4.2.11
class EF_NAFKCA(LinFixedEF):
# TODO: 80296273662e696d732e6d6e633030302e6d63633733382e7075622e336770706e6574776f726b2e6f7267ffffffffffffff
# TODO: 8030656e65746e61667830312e696d732e6d6e633030302e6d63633733382e7075622e336770706e6574776f726b2e6f7267
def __init__(self, fid='6fdd', sfid=None, name='EF.NAFKCA', desc='NAF Key Centre Address', **kwargs):
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, **kwargs)

View File

@ -358,6 +358,14 @@ class ExtendedBcdAdapter(Adapter):
# TS 51.011 Section 10.5.1
class EF_ADN(LinFixedEF):
_test_decode = [
( '42204841203120536963ffffffff06810628560810ffffffffffffff',
{ "alpha_id": "B HA 1 Sic", "len_of_bcd": 6, "ton_npi": { "ext": True, "type_of_number":
"unknown", "numbering_plan_id":
"isdn_e164" }, "dialing_nr":
"6082658001", "cap_conf_id": 255, "ext1_record_id": 255 }),
]
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)
ext_name = 'ext%u_record_id' % ext
@ -419,6 +427,19 @@ class EF_MSISDN(LinFixedEF):
# TS 51.011 Section 10.5.6
class EF_SMSP(LinFixedEF):
# FIXME: re-encode fails / missing alpha_id at start of output
_test_decode = [
( '454e6574776f726b73fffffffffffffff1ffffffffffffffffffffffffffffffffffffffffffffffff0000a7',
{ "alpha_id": "ENetworks", "parameter_indicators": { "tp_dest_addr": False, "tp_sc_addr": True,
"tp_pid": True, "tp_dcs": True, "tp_vp": True },
"tp_dest_addr": { "length": 255, "ton_npi": { "ext": True, "type_of_number": "reserved_for_extension",
"numbering_plan_id": "reserved_for_extension" },
"call_number": "" },
"tp_sc_addr": { "length": 255, "ton_npi": { "ext": True, "type_of_number": "reserved_for_extension",
"numbering_plan_id": "reserved_for_extension" },
"call_number": "" },
"tp_pid": "00", "tp_dcs": "00", "tp_vp_minutes": 1440 } ),
]
class ValidityPeriodAdapter(Adapter):
def _decode(self, obj, context, path):
if obj <= 143:
@ -530,6 +551,9 @@ class DF_TELECOM(CardDF):
# TS 51.011 Section 10.3.1
class EF_LP(TransRecEF):
_test_de_encode = [
( "24", "24"),
]
def __init__(self, fid='6f05', sfid=None, name='EF.LP', size=(1, None), rec_len=1,
desc='Language Preference'):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len)
@ -542,6 +566,10 @@ class EF_LP(TransRecEF):
# TS 51.011 Section 10.3.2
class EF_IMSI(TransparentEF):
_test_de_encode = [
( "082982608200002080", { "imsi": "228062800000208" } ),
( "082926101160845740", { "imsi": "262011106487504" } ),
]
def __init__(self, fid='6f07', sfid=None, name='EF.IMSI', desc='IMSI', size=(9, 9)):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
# add those commands to the general commands of a TransparentEF
@ -580,6 +608,10 @@ class EF_IMSI(TransparentEF):
# TS 51.011 Section 10.3.4
class EF_PLMNsel(TransRecEF):
_test_de_encode = [
( "22F860", { "mcc": "228", "mnc": "06" } ),
( "330420", { "mcc": "334", "mnc": "020" } ),
]
def __init__(self, fid='6f30', sfid=None, name='EF.PLMNsel', desc='PLMN selector',
size=(24, None), rec_len=3, **kwargs):
super().__init__(fid, name=name, sfid=sfid, desc=desc, size=size, rec_len=rec_len, **kwargs)
@ -598,6 +630,9 @@ class EF_PLMNsel(TransRecEF):
# TS 51.011 Section 10.3.6
class EF_ACMmax(TransparentEF):
_test_de_encode = [
( "000000", { "acm_max": 0 } ),
]
def __init__(self, fid='6f37', sfid=None, name='EF.ACMmax', size=(3, 3),
desc='ACM maximum value', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -655,6 +690,11 @@ class EF_ServiceTable(TransparentEF):
# TS 51.011 Section 10.3.11
class EF_SPN(TransparentEF):
_test_de_encode = [
( "0147534d2d52204348ffffffffffffffff",
{ "rfu": 0, "hide_in_oplmn": False, "show_in_hplmn": True, "spn": "GSM-R CH" } ),
]
def __init__(self, fid='6f46', sfid=None, name='EF.SPN',
desc='Service Provider Name', size=(17, 17), **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -669,6 +709,7 @@ class EF_SPN(TransparentEF):
# TS 51.011 Section 10.3.13
class EF_CBMI(TransRecEF):
# TODO: Test vectors
def __init__(self, fid='6f45', sfid=None, name='EF.CBMI', size=(2, None), rec_len=2,
desc='Cell Broadcast message identifier selection', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
@ -676,6 +717,9 @@ class EF_CBMI(TransRecEF):
# TS 51.011 Section 10.3.15
class EF_ACC(TransparentEF):
_test_de_encode = [
( "0100", "0100" ),
]
def __init__(self, fid='6f78', sfid=None, name='EF.ACC',
desc='Access Control Class', size=(2, 2), **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -683,6 +727,10 @@ class EF_ACC(TransparentEF):
# TS 51.011 Section 10.3.16
class EF_LOCI(TransparentEF):
_test_de_encode = [
( "7802570222f81009780000",
{ "tmsi": "78025702", "lai": "22f8100978", "tmsi_time": 0, "lu_status": "updated" } ),
]
def __init__(self, fid='6f7e', sfid=None, name='EF.LOCI', desc='Location Information', size=(11, 11)):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
self._construct = Struct('tmsi'/HexAdapter(Bytes(4)), 'lai'/HexAdapter(Bytes(5)), 'tmsi_time'/Int8ub,
@ -691,6 +739,10 @@ class EF_LOCI(TransparentEF):
# TS 51.011 Section 10.3.18
class EF_AD(TransparentEF):
_test_de_encode = [
( "00ffff",
{ "ms_operation_mode": "normal", "rfu1": 255, "rfu2": 127, "ofm": True, "extensions": None } ),
]
class OP_MODE(enum.IntEnum):
normal = 0x00
type_approval = 0x80
@ -722,6 +774,9 @@ class EF_AD(TransparentEF):
# TS 51.011 Section 10.3.20 / 10.3.22
class EF_VGCS(TransRecEF):
_test_de_encode = [
( "92f9ffff", "299fffff" ),
]
def __init__(self, fid='6fb1', sfid=None, name='EF.VGCS', size=(4, 200), rec_len=4,
desc='Voice Group Call Service', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
@ -729,6 +784,12 @@ class EF_VGCS(TransRecEF):
# TS 51.011 Section 10.3.21 / 10.3.23
class EF_VGCSS(TransparentEF):
_test_decode = [
( "010000004540fc",
{ "flags": [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 ] }
),
]
def __init__(self, fid='6fb2', sfid=None, name='EF.VGCSS', size=(7, 7),
desc='Voice Group Call Service Status', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -737,6 +798,13 @@ class EF_VGCSS(TransparentEF):
# TS 51.011 Section 10.3.24
class EF_eMLPP(TransparentEF):
_test_de_encode = [
( "7c04", { "levels": { "A": False, "B": False, "zero": True, "one": True,
"two": True, "three": True, "four": True },
"fast_call_setup_cond": { "A": False, "B": False, "zero": True, "one": False,
"two": False, "three": False, "four": False }
}),
]
def __init__(self, fid='6fb5', sfid=None, name='EF.eMLPP', size=(2, 2),
desc='enhanced Multi Level Pre-emption and Priority', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -747,6 +815,10 @@ class EF_eMLPP(TransparentEF):
# TS 51.011 Section 10.3.25
class EF_AAeM(TransparentEF):
_test_de_encode = [
( "3c", { "auto_answer_prio_levels": { "A": False, "B": False, "zero": True, "one": True,
"two": True, "three": True, "four": False } } ),
]
def __init__(self, fid='6fb6', sfid=None, name='EF.AAeM', size=(1, 1),
desc='Automatic Answer for eMLPP Service', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
@ -816,12 +888,19 @@ class EF_NIA(LinFixedEF):
# TS 51.011 Section 10.3.32
class EF_Kc(TransparentEF):
_test_de_encode = [
( "837d783609a3858f05", { "kc": "837d783609a3858f", "cksn": 5 } ),
]
def __init__(self, fid='6f20', sfid=None, name='EF.Kc', desc='Ciphering key Kc', size=(9, 9), **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
self._construct = Struct('kc'/HexAdapter(Bytes(8)), 'cksn'/Int8ub)
# TS 51.011 Section 10.3.33
class EF_LOCIGPRS(TransparentEF):
_test_de_encode = [
( "ffffffffffffff22f8990000ff01",
{ "ptmsi": "ffffffff", "ptmsi_sig": "ffffff", "rai": "22f8990000ff", "rau_status": "not_updated" } ),
]
def __init__(self, fid='6f53', sfid=None, name='EF.LOCIGPRS', desc='GPRS Location Information', size=(14, 14)):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
self._construct = Struct('ptmsi'/HexAdapter(Bytes(4)), 'ptmsi_sig'/HexAdapter(Bytes(3)),
@ -831,7 +910,11 @@ class EF_LOCIGPRS(TransparentEF):
# TS 51.011 Section 10.3.35..37
class EF_xPLMNwAcT(TransRecEF):
def __init__(self, fid, sfid=None, name=None, desc=None, size=(40, None), rec_len=5, **kwargs):
_test_de_encode = [
( '62F2104000', { "mcc": "262", "mnc": "01", "act": [ "E-UTRAN" ] } ),
( '62F2108000', { "mcc": "262", "mnc": "01", "act": [ "UTRAN" ] } ),
]
def __init__(self, fid='1234', sfid=None, name=None, desc=None, size=(40, None), rec_len=5, **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
def _decode_record_hex(self, in_hex, **kwargs):
@ -895,6 +978,8 @@ class EF_InvScan(TransparentEF):
# TS 51.011 Section 4.2.58
class EF_PNN(LinFixedEF):
# TODO: 430a82d432bbbc7eb75de432450a82d432bbbc7eb75de432ffffffff
# TODO: 430a82c596b34cbfbfe5eb39ffffffffffffffffffffffffffffffffffff
class FullNameForNetwork(BER_TLV_IE, tag=0x43):
# TS 24.008 10.5.3.5a
# TODO: proper decode
@ -914,6 +999,10 @@ class EF_PNN(LinFixedEF):
# TS 51.011 Section 10.3.42
class EF_OPL(LinFixedEF):
_test_de_encode = [
( '62f2100000fffe01',
{ "lai": { "mcc_mnc": "262f01", "lac_min": "0000", "lac_max": "fffe" }, "pnn_record_id": 1 } ),
]
def __init__(self, fid='6fc6', sfid=None, name='EF.OPL', rec_len=(8, 8), desc='Operator PLMN List', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, rec_len=rec_len, **kwargs)
self._construct = Struct('lai'/Struct('mcc_mnc'/BcdAdapter(Bytes(3)),
@ -921,6 +1010,10 @@ class EF_OPL(LinFixedEF):
# TS 51.011 Section 10.3.44 + TS 31.102 4.2.62
class EF_MBI(LinFixedEF):
_test_de_encode = [
( '0100000000',
{ "mbi_voicemail": 1, "mbi_fax": 0, "mbi_email": 0, "mbi_other": 0, "mbi_videocall": 0 } ),
]
def __init__(self, fid='6fc9', sfid=None, name='EF.MBI', rec_len=(4, 5), desc='Mailbox Identifier', **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, rec_len=rec_len, **kwargs)
self._construct = Struct('mbi_voicemail'/Int8ub, 'mbi_fax'/Int8ub, 'mbi_email'/Int8ub,
@ -938,6 +1031,7 @@ class EF_MWIS(LinFixedEF):
# TS 51.011 Section 10.3.66
class EF_SPDI(TransparentEF):
# TODO: a305800337f800ffffffffffffffffffffffffffffffffffffffffffffff
class ServiceProviderPLMN(BER_TLV_IE, tag=0x80):
# flexible numbers of 3-byte PLMN records
_construct = GreedyRange(BcdAdapter(Bytes(3)))

262
tests/test_files.py Executable file
View File

@ -0,0 +1,262 @@
#!/usr/bin/env python3
# (C) 2023 by Harald Welte <laforge@osmocom.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
import logging
from pySim.utils import *
from pySim.filesystem import *
import pySim.iso7816_4
import pySim.ts_102_221
import pySim.ts_102_222
import pySim.ts_31_102
import pySim.ts_31_103
import pySim.ts_51_011
import pySim.sysmocom_sja2
import pySim.gsm_r
def get_qualified_name(c):
"""return the qualified (by module) name of a class."""
return "%s.%s" % (c.__module__, c.__name__)
class LinFixed_Test(unittest.TestCase):
classes = all_subclasses(LinFixedEF)
def test_decode_record(self):
"""Test the decoder for a linear-fixed EF. Requires the given LinFixedEF subclass
to have an '_test_decode' attribute, containing a list of tuples. Each tuple can
either be a
* 2-tuple (hexstring, decoded_dict) or a
* 3-tuple (hexstring, record_nr, decoded_dict)
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_decode'):
for t in c._test_decode:
with self.subTest(name, test_decode=t):
inst = c()
if len(t) == 2:
encoded = t[0]
rec_num = 1
decoded = t[1]
else:
encoded = t[0]
rec_num = t[1]
decoded = t[2]
logging.debug("Testing 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
to have an '_test_encode' attribute, containing a list of tuples. Each tuple can
either be a
* 2-tuple (hexstring, decoded_dict) or a
* 3-tuple (hexstring, record_nr, decoded_dict)
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_encode'):
for t in c._test_encode:
with self.subTest(name, test_encode=t):
inst = c()
if len(t) == 2:
encoded = t[0]
rec_num = 1
decoded = t[1]
else:
encoded = t[0]
rec_num = t[1]
decoded = t[2]
logging.debug("Testing encode of %s", name)
re_enc = inst.encode_record_hex(decoded, rec_num)
self.assertEqual(encoded, re_enc)
def test_de_encode_record(self):
"""Test the decoder and encoder for a linear-fixed EF. Performs first a decoder
test, and then re-encodes the decoded data, comparing the re-encoded data with the
initial input data.
Requires the given LinFixedEF subclass to have a '_test_de_encode' attribute,
containing a list of tuples. Each tuple can
either be a
* 2-tuple (hexstring, decoded_dict) or a
* 3-tuple (hexstring, record_nr, decoded_dict)
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_de_encode'):
for t in c._test_de_encode:
with self.subTest(name, test_de_encode=t):
inst = c()
if len(t) == 2:
encoded = t[0]
rec_num = 1
decoded = t[1]
else:
encoded = t[0]
rec_num = t[1]
decoded = t[2]
logging.debug("Testing decode of %s", name)
re_dec = inst.decode_record_hex(encoded, rec_num)
self.assertEqual(decoded, re_dec)
# re-encode the decoded data
logging.debug("Testing re-encode of %s", name)
re_enc = inst.encode_record_hex(re_dec, rec_num)
self.assertEqual(encoded, re_enc)
class TransRecEF_Test(unittest.TestCase):
classes = all_subclasses(TransRecEF)
def test_decode_record(self):
"""Test the decoder for a transparent record-oriented EF. Requires the given TransRecEF subclass
to have an '_test_decode' attribute, containing a list of tuples. Each tuple has to be a
2-tuple (hexstring, decoded_dict).
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_decode'):
for t in c._test_decode:
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_record_hex(encoded)
self.assertEqual(decoded, re_dec)
def test_encode_record(self):
"""Test the encoder for a transparent record-oriented EF. Requires the given TransRecEF subclass
to have an '_test_encode' attribute, containing a list of tuples. Each tuple has to be a
2-tuple (hexstring, decoded_dict).
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_decode'):
for t in c._test_decode:
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_record_hex(encoded)
self.assertEqual(decoded, re_dec)
def test_de_encode_record(self):
"""Test the decoder and encoder for a transparent record-oriented EF. Performs first a decoder
test, and then re-encodes the decoded data, comparing the re-encoded data with the
initial input data.
Requires the given TransRecEF subclass to have a '_test_de_encode' attribute,
containing a list of tuples. Each tuple has to be a 2-tuple (hexstring, decoded_dict).
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_de_encode'):
for t in c._test_de_encode:
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_record_hex(encoded)
self.assertEqual(decoded, re_dec)
# re-encode the decoded data
logging.debug("Testing re-encode of %s", name)
re_enc = inst.encode_record_hex(re_dec)
self.assertEqual(encoded, re_enc)
class TransparentEF_Test(unittest.TestCase):
@classmethod
def get_classes(cls):
"""get list of TransparentEF sub-classes which are not a TransRecEF subclass."""
classes = all_subclasses(TransparentEF)
trans_rec_classes = all_subclasses(TransRecEF)
return filter(lambda c: c not in trans_rec_classes, classes)
@classmethod
def setUpClass(cls):
"""set-up method called once for this class by unittest framework"""
cls.classes = cls.get_classes()
def test_decode_file(self):
"""Test the decoder for a transparent EF. Requires the given TransparentEF subclass
to have a '_test_decode' attribute, containing a list of tuples. Each tuple
is a 2-tuple (hexstring, decoded_dict).
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_decode'):
for t in c._test_decode:
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)
def test_encode_file(self):
"""Test the encoder for a transparent EF. Requires the given TransparentEF subclass
to have a '_test_encode' attribute, containing a list of tuples. Each tuple
is a 2-tuple (hexstring, decoded_dict).
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_encode'):
for t in c._test_encode:
with self.subTest(name, test_encode=t):
inst = c()
encoded = t[0]
decoded = t[1]
logging.debug("Testing encode of %s", name)
re_dec = inst.decode_hex(encoded)
self.assertEqual(decoded, re_dec)
def test_de_encode_file(self):
"""Test the decoder and encoder for a transparent EF. Performs first a decoder
test, and then re-encodes the decoded data, comparing the re-encoded data with the
initial input data.
Requires the given TransparentEF subclass to have a '_test_de_encode' attribute,
containing a list of tuples. Each tuple is a 2-tuple (hexstring, decoded_dict).
"""
for c in self.classes:
name = get_qualified_name(c)
if hasattr(c, '_test_de_encode'):
for t in c._test_de_encode:
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)
logging.debug("Testing re-encode of %s", name)
re_dec = inst.decode_hex(encoded)
re_enc = inst.encode_hex(re_dec)
self.assertEqual(encoded, re_enc)
if __name__ == '__main__':
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
unittest.main()