Passed
Pull Request — main (#42)
by Switcheolytics
55s
created

tests.APITestCase.assertDictStructure()   C

Complexity

Conditions 10

Size

Total Lines 49
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 25
dl 0
loc 49
rs 5.9999
c 0
b 0
f 0
cc 10
nop 4

How to fix   Complexity   

Complexity

Complex classes like tests.APITestCase.assertDictStructure() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import os
2
from unittest import TestCase
3
4
from tradehub.public_client import PublicClient
5
6
mainnet_client = PublicClient(network='mainnet', is_websocket_client=True)
7
MAINNET_VAL_IP = mainnet_client.active_sentry_api_ip
8
MAINNET_WS_URI = mainnet_client.active_ws_uri
9
testnet_client = PublicClient(network='testnet', is_websocket_client=True)
10
TESTNET_VAL_IP = testnet_client.active_sentry_api_ip
11
TESTNET_WS_URI = testnet_client.active_ws_uri
12
13
WALLET_VALIDATOR = "swth1vwges9p847l9csj8ehrlgzajhmt4fcq4sd7gzl"
14
WALLET_DEVEL = "swth1qlue2pat9cxx2s5xqrv0ashs475n9va963h4hz"
15
WALLET_SWTH_ETH1_AMM = "swth1p5hjhag5glkpqaj0y0vn3au7x0vz33k0gxuejk"
16
USERNAME_DEVEL = "devel484"
17
18
WALLET_MNEMONIC = "refuse flag merge fiction choose dream frown gauge need fabric once pizza actual armed reopen couple family fury reopen slush blue try focus minute"
19
WALLET_PRIVATE_KEY = b'\x15\xcf\xdd\xdf\xead\x88\xd2y!\xdb\xb61\xa6\x98\xeeQm\x05\xed\x8d%43!\n\xccS\xcbsf\x90'
20
WALLET_PUBLIC_KEY = b'\x02o\x1f\xfbL\x96\xe8\x1e\xb0\x12V\x80\xc7t\xfc\xb40R\xaeu\xf3{\xf6\xd7m]\xd1\xa9\x91\xa8\xe0Df'
21
WALLET_ADDRESS = 'tswth1upcgussnx4p3jegwj3x2fccwlajwckkzgstrp8'
22
23
TRADING_TESTNET_WALLET_MNEMONIC = "venture consider cool fury front middle junk person suit assist garbage category"
24
25
NEO_ADDRESS = 'APuP9GsSCPJKrexPe49afDV8CQYubZGWd8'
26
NEO_CONTRACT = '3e09e602eeeb401a2fec8e8ea137d59aae54a139'
27
ETH_ADDRESS = '0x32c46323b51c977814e05ef5e258ee4da0e4c3c3'   # Ropsten Testnet Address
28
ETH_CONTRACT = '0x0025b3342582d106454e88ecb091f3e456f81ac3'  # Sushi Ropsten Testnet Contract
29
30
WEB3_API_KEY = os.environ.get('WEB3_API_KEY')
31
WEB3_API_URL = 'https://eth-ropsten.alchemyapi.io/v2/{}'.format(WEB3_API_KEY)
32
33
WEBSOCKET_TIMEOUT_GET_REQUEST = 5
34
WEBSOCKET_TIMEOUT_SUBSCRIPTION = 60
35
36
37
class APITestCase(TestCase):
38
39
    def assertDictStructure(self, expect: dict, actual: dict, path: list = []) -> None:
40
        """
41
        Compare function to check if expected dict with types equals the actual dict. If a dict has a dict as field
42
        the function call it self recursive.
43
44
        :raise AssertionError: if actual type and expected types are not same
45
        :raise AssertionError: if keys in actual and expected are not same
46
47
        :param expect: dict with types
48
        :param actual: dict with values
49
        :param path: current path(list with keys)
50
        :return: None
51
        """
52
        self.assertEqual(expect.keys(), actual.keys(),
53
                         msg=f"Expected field keys are not same: {self.path_to_dict_path(path)}")
54
        for key in actual:
55
            if isinstance(expect[key], dict):
56
                self.assertIsInstance(actual[key], dict,
57
                                      msg=f"Expected field {self.path_to_dict_path(path+[key])} to be type dict, "
58
                                          f"got type {type(actual[key])} instead")
59
                self.assertDictStructure(expect[key], actual[key], path + [key])
60
            elif isinstance(expect[key], list):
61
                self.assertIsInstance(actual[key], list,
62
                                      msg=f"Expected field {self.path_to_dict_path(path+[key])} to be type list, "
63
                                          f"got type {type(actual[key])} instead")
64
65
                if not expect[key]:
66
                    self.assertFalse(actual[key], msg=f"Expected empty list {self.path_to_dict_path(path+[key])},"
67
                                                      f"received non empty list {actual[key]}")
68
                else:
69
                    self.assertTrue(actual[key], msg=f"Expected list {self.path_to_dict_path(path+[key])},"
70
                                                     f"received empty list {actual[key]}")
71
72
                if expect[key] and isinstance(expect[key][0], dict):
73
                    for i, entry in enumerate(actual[key]):
74
                        self.assertDictStructure(expect[key][0], entry, path + [key, i])
75
                else:
76
                    for i, entry in enumerate(actual[key]):
77
                        self.assertIsInstance(entry, expect[key][0],
78
                                              msg=f"Expected field {self.path_to_dict_path(path+[key, i])} "
79
                                                  f"to be type {expect[key][0]}, got type {type(entry)} instead")
80
            else:
81
                if type(expect[key]) == type:
82
                    self.assertIsInstance(actual[key], expect[key],
83
                                          msg=f"Expected field {self.path_to_dict_path(path+[key])} "
84
                                              f"to be type {expect[key]}, got type {type(actual[key])} instead")
85
                else:
86
                    self.assertIn(type(actual[key]), expect[key].__args__,
87
                                  msg=f"Expected field {self.path_to_dict_path(path+[key])} "
88
                                      f"to be type {expect[key]}, got type {type(actual[key])} instead")
89
90
    @staticmethod
91
    def path_to_dict_path(path: list) -> str:
92
        """
93
        This method returns the dict path to a field.
94
95
        path_to_dict_path(["layer1", "layer2, "key"])
96
        -> "['layer1']['layer2']['key']"
97
98
        :param path: list with keys(path)
99
        :return: dict path as str
100
        """
101
        return "".join([f"['{key}']" for key in path])
102