edq.testing.unittest
1import datetime 2import typing 3import unittest 4 5import edq.util.dirent 6import edq.util.json 7import edq.util.reflection 8import edq.util.time 9 10FORMAT_STR: str = "\n--- Expected ---\n%s\n--- Actual ---\n%s\n---\n" 11 12class BaseTest(unittest.TestCase): 13 """ 14 A base class for unit tests. 15 """ 16 17 maxDiff = None 18 """ Don't limit the size of diffs. """ 19 20 testing_timezone: typing.Union[datetime.timezone, None] = edq.util.time.UTC 21 22 @classmethod 23 def setUpClass(cls) -> None: 24 super().setUpClass() 25 26 edq.util.time.set_testing_local_timezone(cls.testing_timezone) 27 28 @classmethod 29 def tearDownClass(cls) -> None: 30 super().tearDownClass() 31 32 edq.util.time.set_testing_local_timezone(None) 33 34 def assertJSONEqual(self, a: typing.Any, b: typing.Any, message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 35 """ 36 Like unittest.TestCase.assertEqual(), 37 but uses a default assertion message containing the full JSON representation of the arguments. 38 """ 39 40 a_json = edq.util.json.dumps(a, indent = 4) 41 b_json = edq.util.json.dumps(b, indent = 4) 42 43 if (message is None): 44 message = FORMAT_STR % (a_json, b_json) 45 46 super().assertEqual(a, b, msg = message) 47 48 def assertJSONDictEqual(self, a: typing.Any, b: typing.Any, message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 49 """ 50 Like unittest.TestCase.assertDictEqual(), 51 but will try to convert each comparison argument to a dict if it is not already, 52 and uses a default assertion message containing the full JSON representation of the arguments. 53 """ 54 55 if (not isinstance(a, dict)): 56 if (isinstance(a, edq.util.json.DictConverter)): 57 a = a.to_dict() 58 else: 59 a = vars(a) 60 61 if (not isinstance(b, dict)): 62 if (isinstance(b, edq.util.json.DictConverter)): 63 b = b.to_dict() 64 else: 65 b = vars(b) 66 67 a_json = edq.util.json.dumps(a, indent = 4) 68 b_json = edq.util.json.dumps(b, indent = 4) 69 70 if (message is None): 71 message = FORMAT_STR % (a_json, b_json) 72 73 super().assertDictEqual(a, b, msg = message) 74 75 def assertJSONListEqual(self, a: typing.List[typing.Any], b: typing.List[typing.Any], message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 76 """ 77 Call assertDictEqual(), but supply a default message containing the full JSON representation of the arguments. 78 """ 79 80 a_json = edq.util.json.dumps(a, indent = 4) 81 b_json = edq.util.json.dumps(b, indent = 4) 82 83 if (message is None): 84 message = FORMAT_STR % (a_json, b_json) 85 86 super().assertListEqual(a, b, msg = message) 87 88 def assertFileHashEqual(self, a: str, b: str) -> None: # pylint: disable=invalid-name 89 """ 90 Assert that the hash of two files matches. 91 Will fail if either path does not exist. 92 """ 93 94 if (not edq.util.dirent.exists(a)): 95 self.fail(f"File does not exist: '{a}'.") 96 97 if (not edq.util.dirent.exists(b)): 98 self.fail(f"File does not exist: '{b}'.") 99 100 a_hash = edq.util.dirent.hash_file(a) 101 b_hash = edq.util.dirent.hash_file(b) 102 103 self.assertEqual(a_hash, b_hash, msg = f"Hash mismatch: '{a}' ({a_hash}) vs '{b}' ({b_hash}).") 104 105 def format_error_string(self, ex: typing.Union[BaseException, None]) -> str: 106 """ 107 Format an error string from an exception so it can be checked for testing. 108 The type of the error will be included, 109 and any nested errors will be joined together. 110 """ 111 112 parts = [] 113 114 while (ex is not None): 115 type_name = edq.util.reflection.get_qualified_name(ex) 116 message = str(ex) 117 118 parts.append(f"{type_name}: {message}") 119 120 ex = ex.__cause__ 121 122 return "; ".join(parts)
13class BaseTest(unittest.TestCase): 14 """ 15 A base class for unit tests. 16 """ 17 18 maxDiff = None 19 """ Don't limit the size of diffs. """ 20 21 testing_timezone: typing.Union[datetime.timezone, None] = edq.util.time.UTC 22 23 @classmethod 24 def setUpClass(cls) -> None: 25 super().setUpClass() 26 27 edq.util.time.set_testing_local_timezone(cls.testing_timezone) 28 29 @classmethod 30 def tearDownClass(cls) -> None: 31 super().tearDownClass() 32 33 edq.util.time.set_testing_local_timezone(None) 34 35 def assertJSONEqual(self, a: typing.Any, b: typing.Any, message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 36 """ 37 Like unittest.TestCase.assertEqual(), 38 but uses a default assertion message containing the full JSON representation of the arguments. 39 """ 40 41 a_json = edq.util.json.dumps(a, indent = 4) 42 b_json = edq.util.json.dumps(b, indent = 4) 43 44 if (message is None): 45 message = FORMAT_STR % (a_json, b_json) 46 47 super().assertEqual(a, b, msg = message) 48 49 def assertJSONDictEqual(self, a: typing.Any, b: typing.Any, message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 50 """ 51 Like unittest.TestCase.assertDictEqual(), 52 but will try to convert each comparison argument to a dict if it is not already, 53 and uses a default assertion message containing the full JSON representation of the arguments. 54 """ 55 56 if (not isinstance(a, dict)): 57 if (isinstance(a, edq.util.json.DictConverter)): 58 a = a.to_dict() 59 else: 60 a = vars(a) 61 62 if (not isinstance(b, dict)): 63 if (isinstance(b, edq.util.json.DictConverter)): 64 b = b.to_dict() 65 else: 66 b = vars(b) 67 68 a_json = edq.util.json.dumps(a, indent = 4) 69 b_json = edq.util.json.dumps(b, indent = 4) 70 71 if (message is None): 72 message = FORMAT_STR % (a_json, b_json) 73 74 super().assertDictEqual(a, b, msg = message) 75 76 def assertJSONListEqual(self, a: typing.List[typing.Any], b: typing.List[typing.Any], message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 77 """ 78 Call assertDictEqual(), but supply a default message containing the full JSON representation of the arguments. 79 """ 80 81 a_json = edq.util.json.dumps(a, indent = 4) 82 b_json = edq.util.json.dumps(b, indent = 4) 83 84 if (message is None): 85 message = FORMAT_STR % (a_json, b_json) 86 87 super().assertListEqual(a, b, msg = message) 88 89 def assertFileHashEqual(self, a: str, b: str) -> None: # pylint: disable=invalid-name 90 """ 91 Assert that the hash of two files matches. 92 Will fail if either path does not exist. 93 """ 94 95 if (not edq.util.dirent.exists(a)): 96 self.fail(f"File does not exist: '{a}'.") 97 98 if (not edq.util.dirent.exists(b)): 99 self.fail(f"File does not exist: '{b}'.") 100 101 a_hash = edq.util.dirent.hash_file(a) 102 b_hash = edq.util.dirent.hash_file(b) 103 104 self.assertEqual(a_hash, b_hash, msg = f"Hash mismatch: '{a}' ({a_hash}) vs '{b}' ({b_hash}).") 105 106 def format_error_string(self, ex: typing.Union[BaseException, None]) -> str: 107 """ 108 Format an error string from an exception so it can be checked for testing. 109 The type of the error will be included, 110 and any nested errors will be joined together. 111 """ 112 113 parts = [] 114 115 while (ex is not None): 116 type_name = edq.util.reflection.get_qualified_name(ex) 117 message = str(ex) 118 119 parts.append(f"{type_name}: {message}") 120 121 ex = ex.__cause__ 122 123 return "; ".join(parts)
A base class for unit tests.
23 @classmethod 24 def setUpClass(cls) -> None: 25 super().setUpClass() 26 27 edq.util.time.set_testing_local_timezone(cls.testing_timezone)
Hook method for setting up class fixture before running tests in the class.
29 @classmethod 30 def tearDownClass(cls) -> None: 31 super().tearDownClass() 32 33 edq.util.time.set_testing_local_timezone(None)
Hook method for deconstructing the class fixture after running all tests in the class.
35 def assertJSONEqual(self, a: typing.Any, b: typing.Any, message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 36 """ 37 Like unittest.TestCase.assertEqual(), 38 but uses a default assertion message containing the full JSON representation of the arguments. 39 """ 40 41 a_json = edq.util.json.dumps(a, indent = 4) 42 b_json = edq.util.json.dumps(b, indent = 4) 43 44 if (message is None): 45 message = FORMAT_STR % (a_json, b_json) 46 47 super().assertEqual(a, b, msg = message)
Like unittest.TestCase.assertEqual(), but uses a default assertion message containing the full JSON representation of the arguments.
49 def assertJSONDictEqual(self, a: typing.Any, b: typing.Any, message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 50 """ 51 Like unittest.TestCase.assertDictEqual(), 52 but will try to convert each comparison argument to a dict if it is not already, 53 and uses a default assertion message containing the full JSON representation of the arguments. 54 """ 55 56 if (not isinstance(a, dict)): 57 if (isinstance(a, edq.util.json.DictConverter)): 58 a = a.to_dict() 59 else: 60 a = vars(a) 61 62 if (not isinstance(b, dict)): 63 if (isinstance(b, edq.util.json.DictConverter)): 64 b = b.to_dict() 65 else: 66 b = vars(b) 67 68 a_json = edq.util.json.dumps(a, indent = 4) 69 b_json = edq.util.json.dumps(b, indent = 4) 70 71 if (message is None): 72 message = FORMAT_STR % (a_json, b_json) 73 74 super().assertDictEqual(a, b, msg = message)
Like unittest.TestCase.assertDictEqual(), but will try to convert each comparison argument to a dict if it is not already, and uses a default assertion message containing the full JSON representation of the arguments.
76 def assertJSONListEqual(self, a: typing.List[typing.Any], b: typing.List[typing.Any], message: typing.Union[str, None] = None) -> None: # pylint: disable=invalid-name 77 """ 78 Call assertDictEqual(), but supply a default message containing the full JSON representation of the arguments. 79 """ 80 81 a_json = edq.util.json.dumps(a, indent = 4) 82 b_json = edq.util.json.dumps(b, indent = 4) 83 84 if (message is None): 85 message = FORMAT_STR % (a_json, b_json) 86 87 super().assertListEqual(a, b, msg = message)
Call assertDictEqual(), but supply a default message containing the full JSON representation of the arguments.
89 def assertFileHashEqual(self, a: str, b: str) -> None: # pylint: disable=invalid-name 90 """ 91 Assert that the hash of two files matches. 92 Will fail if either path does not exist. 93 """ 94 95 if (not edq.util.dirent.exists(a)): 96 self.fail(f"File does not exist: '{a}'.") 97 98 if (not edq.util.dirent.exists(b)): 99 self.fail(f"File does not exist: '{b}'.") 100 101 a_hash = edq.util.dirent.hash_file(a) 102 b_hash = edq.util.dirent.hash_file(b) 103 104 self.assertEqual(a_hash, b_hash, msg = f"Hash mismatch: '{a}' ({a_hash}) vs '{b}' ({b_hash}).")
Assert that the hash of two files matches. Will fail if either path does not exist.
106 def format_error_string(self, ex: typing.Union[BaseException, None]) -> str: 107 """ 108 Format an error string from an exception so it can be checked for testing. 109 The type of the error will be included, 110 and any nested errors will be joined together. 111 """ 112 113 parts = [] 114 115 while (ex is not None): 116 type_name = edq.util.reflection.get_qualified_name(ex) 117 message = str(ex) 118 119 parts.append(f"{type_name}: {message}") 120 121 ex = ex.__cause__ 122 123 return "; ".join(parts)
Format an error string from an exception so it can be checked for testing. The type of the error will be included, and any nested errors will be joined together.