Change in pysim[master]: filesystem: add unit tests for encoder/decoder methods

dexter gerrit-no-reply at lists.osmocom.org
Fri Apr 30 17:02:52 UTC 2021


dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/24012 )


Change subject: filesystem: add unit tests for encoder/decoder methods
......................................................................

filesystem: add unit tests for encoder/decoder methods

Some files have a custom _encode... and _decode... metod. Those methods
can be detected automatically and tested with a test vector that is
directly defined in the respective file class.

Change-Id: I02d884547f4982e0b8ed7ef21b8cda75237942e2
Related: OS#4963
---
M pySim/filesystem.py
M pySim/ts_102_221.py
M pySim/ts_31_102.py
M pySim/ts_31_103.py
M pySim/ts_51_011.py
A tests/test_files.py
6 files changed, 126 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/12/24012/1

diff --git a/pySim/filesystem.py b/pySim/filesystem.py
index dec521e..f0c985c 100644
--- a/pySim/filesystem.py
+++ b/pySim/filesystem.py
@@ -34,7 +34,7 @@
 
 from typing import cast, Optional, Iterable, List, Any, Dict, Tuple
 
-from pySim.utils import sw_match, h2b, b2h, is_hex
+from pySim.utils import sw_match, h2b, b2h, is_hex, JsonEncoder
 from pySim.construct import filter_dict
 from pySim.exceptions import *
 from pySim.jsonpath import js_path_find, js_path_modify
@@ -378,6 +378,58 @@
         sels.update({x.name:x for x in self.parent.children.values() if x != self})
         return sels
 
+    def test_encode_decode(self, verbose=False):
+        """Unit-test to verify the encoder and decoder function of a certain
+	file. To run this, simply define a _encode_decode_testvector[] testvector
+	list inside the specific file implementation. The list shall contain at
+	least one dictionary with at least one set of abstract data.
+	"""
+
+	# Find out which encoder/decoder functions are present
+        has_dec_rec = hasattr(self.__class__, '_decode_record_hex') and callable(getattr(self.__class__, '_decode_record_hex'))
+        has_enc_rec = hasattr(self.__class__, '_encode_record_hex') and callable(getattr(self.__class__, '_encode_record_hex'))
+        has_dec = hasattr(self.__class__, '_decode_hex') and callable(getattr(self.__class__, '_decode_hex'))
+        has_enc = hasattr(self.__class__, '_encode_hex') and callable(getattr(self.__class__, '_encode_hex'))
+        has_testvec = hasattr(self.__class__, '_encode_decode_testvector')
+
+	# Check if a decoder, encoder and a testvector is present
+        if has_dec_rec and has_enc_rec:
+            print("Testing %s (record oriented)" % (self.name))
+            encode = self._encode_record_hex
+            decode = self._decode_record_hex
+            if not has_testvec:
+                print(" Cannot test: Please define _encode_decode_testvector[] in %s" % (self.name))
+                return
+        elif has_dec and has_enc:
+            print("Testing %s (transparent)" % (self.name))
+            encode = self._encode_hex
+            decode = self._decode_hex
+            if not has_testvec:
+                print(" Cannot test: Please define _encode_decode_testvector[] in %s" % (self.name))
+                return
+        else:
+            return
+
+        # Encode+Decode the test data and make sure the end result matches the
+	# input
+        for testvec_json in self.__class__._encode_decode_testvector:
+            print(" testvec_json: " + str(testvec_json))
+            testvec = json.loads(testvec_json)
+            if verbose:
+                print(" testvec:      " + str(testvec))
+            encoded = encode(testvec)
+            if verbose:
+                print(" encoded:      " + str(encoded))
+            decoded = decode(encoded)
+            if verbose:
+                print(" decoded:      " + str(decoded))
+            decoded_json = json.dumps(decoded, cls=JsonEncoder)
+            if verbose:
+                print(" decoded_json: " + str(decoded_json))
+            if testvec_json != decoded_json:
+                raise ValueError("The encoded end result (decoded_json) does not match the original input (testvec_json)")
+            else:
+                print(" Ok.")
 
 class TransparentEF(CardEF):
     """Transparent EF (Entry File) in the smart card filesystem.
diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py
index 88a36a1..ab4ecf6 100644
--- a/pySim/ts_102_221.py
+++ b/pySim/ts_102_221.py
@@ -189,6 +189,7 @@
 
 # TS 102 221 Section 13.2
 class EF_ICCID(TransparentEF):
+    _encode_decode_testvector = ['{"iccid": "8988211000000433188"}']
     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})
 
diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py
index de729be..e7f5fbb 100644
--- a/pySim/ts_31_102.py
+++ b/pySim/ts_31_102.py
@@ -291,6 +291,7 @@
 
 # TS 31.102 4.4.11.8
 class EF_SUCI_Calc_Info(TransparentEF):
+    _encode_decode_testvector = ['{"prot_scheme_id_list": [{"priority": 0, "identifier": 2, "key_index": 1}, {"priority": 1, "identifier": 1, "key_index": 2}, {"priority": 2, "identifier": 0, "key_index": 0}], "hnet_pubkey_list": [{"hnet_pubkey_identifier": 27, "hnet_pubkey": "0272da71976234ce833a6907425867b82e074d44ef907dfb4b3e21c1c2256ebcd1"}, {"hnet_pubkey_identifier": 30, "hnet_pubkey": "5a8d38864820197c3394b92613b20b91633cbd897119273bf8e4a6f4eec0a650"}]}']
     def __init__(self, fid="4f07", sfid=0x07, name='EF.SUCI_Calc_Info', size={2, None},
         desc='SUCI Calc Info'):
         super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
diff --git a/pySim/ts_31_103.py b/pySim/ts_31_103.py
index 1009ba3..bac7a7d 100644
--- a/pySim/ts_31_103.py
+++ b/pySim/ts_31_103.py
@@ -117,6 +117,8 @@
 
 # TS 31.103 Section 4.2.8
 class EF_PCSCF(LinFixedEF):
+    _encode_decode_testvector = ['{"addr": "192.168.100.110", "addr_type": "01"}',
+				 '{"addr": "hello,world", "addr_type": "00"}']
     def __init__(self, fid='6f09', sfid=None, name='EF.P-CSCF', desc='P-CSCF Address'):
         super().__init__(fid=fid, sfid=sfid, name=name, desc=desc)
     def _decode_record_hex(self, raw_hex):
diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py
index 8e4428c..06f4c0e 100644
--- a/pySim/ts_51_011.py
+++ b/pySim/ts_51_011.py
@@ -376,6 +376,8 @@
 
 # TS 51.011 Section 10.5.5
 class EF_MSISDN(LinFixedEF):
+    _encode_decode_testvector = ['{"msisdn": [1, 1, "+4916012345678"]}',
+				 '{"msisdn": [1, 3, "123456"]}']
     def __init__(self, fid='6f40', sfid=None, name='EF.MSISDN', desc='MSISDN'):
         super().__init__(fid, sfid=sfid, name=name, desc=desc, rec_len={15, 34})
     def _decode_record_hex(self, raw_hex_data):
@@ -465,6 +467,8 @@
 
 # TS 51.011 Section 10.3.2
 class EF_IMSI(TransparentEF):
+    _encode_decode_testvector = ['{"imsi": "001010000000102"}',
+				 '{"imsi": "123456789012345"}']
     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)
     def _decode_hex(self, raw_hex):
@@ -474,6 +478,9 @@
 
 # TS 51.011 Section 10.3.4
 class EF_PLMNsel(TransRecEF):
+    _encode_decode_testvector = ['{"mcc": "123", "mnc": "45"}',
+				 '{"mcc": "001", "mnc": "01"}',
+				 '{"mcc": "456", "mnc": "123"}']
     def __init__(self, fid='6f30', sfid=None, name='EF.PLMNsel', desc='PLMN selector',
                  size={24,None}, rec_len=3):
         super().__init__(fid, name=name, sfid=sfid, desc=desc, size=size, rec_len=rec_len)
@@ -517,6 +524,9 @@
 
 # TS 51.011 Section 10.3.11
 class EF_SPN(TransparentEF):
+    _encode_decode_testvector = ['{"spn": ["testme", false, false]}',
+				 '{"spn": ["", true, false]}',
+				 '{"spn": ["hello world", false, true]}']
     def __init__(self, fid='6f46', sfid=None, name='EF.SPN', desc='Service Provider Name', size={17,17}):
         super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
     def _decode_hex(self, raw_hex):
@@ -638,6 +648,10 @@
                                  'corporate'/BcdAdapter(Bytes(4)))
 # TS 51.011 Section 10.3.30
 class EF_CNL(TransRecEF):
+    _encode_decode_testvector = ['{"mcc": "", "mnc": "", "network_subset": 255, "service_provider_id": 255, "corporate_id": 255}',
+				 '{"mcc": "001", "mnc": "01", "network_subset": 23, "service_provider_id": 42, "corporate_id": 5}',
+				 '{"mcc": "123", "mnc": "567", "network_subset": 255, "service_provider_id": 255, "corporate_id": 255}',
+				 '{"mcc": "262", "mnc": "12", "network_subset": 111, "service_provider_id": 0, "corporate_id": 0}']
     def __init__(self, fid='6f32', sfid=None, name='EF.CNL', size={6,None}, rec_len=6,
                  desc='Co-operative Network List'):
         super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len)
@@ -676,6 +690,10 @@
 
 # TS 51.011 Section 10.3.35..37
 class EF_xPLMNwAcT(TransRecEF):
+    _encode_decode_testvector = ['{"mcc": "001", "mnc": "01", "act": ["UTRAN", "E-UTRAN", "GSM", "GSM COMPACT", "cdma2000 HRPD", "cdma2000 1xRTT"]}',
+				 '{"mcc": "001", "mnc": "01", "act": ["UTRAN", "E-UTRAN WB-S1", "GSM", "GSM COMPACT", "cdma2000 HRPD", "cdma2000 1xRTT"]}',
+				 '{"mcc": "001", "mnc": "01", "act": ["UTRAN", "E-UTRAN NB-S1", "GSM", "GSM COMPACT", "cdma2000 HRPD", "cdma2000 1xRTT"]}',
+				 '{"mcc": "001", "mnc": "01", "act": ["UTRAN", "E-UTRAN WB-S1", "E-UTRAN NB-S1", "GSM", "GSM COMPACT", "cdma2000 HRPD", "cdma2000 1xRTT"]}']
     def __init__(self, fid, sfid=None, name=None, desc=None, size={40,None}, rec_len=5):
         super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len)
     def _decode_record_hex(self, in_hex):
diff --git a/tests/test_files.py b/tests/test_files.py
new file mode 100755
index 0000000..a855afa
--- /dev/null
+++ b/tests/test_files.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+
+import unittest
+from pySim import utils
+from pySim.ts_31_102 import EF_SUCI_Calc_Info
+
+from typing import List
+
+import json
+import gc
+
+from pySim.ts_51_011 import EF, DF, EF_SST_map
+from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map
+from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map
+
+from pySim.filesystem import CardEF, CardMF, CardDF, CardADF
+from pySim.ts_51_011 import CardProfileSIM, DF_TELECOM, DF_GSM
+from pySim.ts_102_221 import CardProfileUICC
+from pySim.ts_31_102 import CardApplicationUSIM
+from pySim.ts_31_103 import CardApplicationISIM
+
+# Check if a file (specified by its name) exists in a given list with files
+def file_in_list(file_list, name):
+	for f in file_list:
+		if f.name == name:
+			return True
+	return False
+
+class DecTestCase(unittest.TestCase):
+
+	def testFileContentDecoderEncoder(self):
+		# Create files in memory
+		profile = CardProfileUICC()
+		profile.add_application(CardApplicationUSIM)
+		profile.add_application(CardApplicationISIM)
+		df_telecom = DF_TELECOM()
+		df_gsm = DF_GSM()
+
+		# Collect one sample of each EF from memory
+		test_candidates = []
+		for obj in gc.get_objects():
+			if isinstance(obj, CardEF):
+				if not file_in_list(test_candidates, obj.name):
+					test_candidates.append(obj)
+
+		# Execute integrated encoder/decoder unit tests
+		for obj in test_candidates:
+			obj.test_encode_decode()
+
+if __name__ == "__main__":
+	unittest.main()

-- 
To view, visit https://gerrit.osmocom.org/c/pysim/+/24012
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I02d884547f4982e0b8ed7ef21b8cda75237942e2
Gerrit-Change-Number: 24012
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210430/fe364622/attachment-0001.htm>


More information about the gerrit-log mailing list