Test Failed
Pull Request — master (#203)
by Jan
03:38
created

oval_graph.arf_xml_parser._test_info   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Test Coverage

Coverage 98.2%

Importance

Changes 0
Metric Value
eloc 143
dl 0
loc 175
ccs 109
cts 111
cp 0.982
rs 8.64
c 0
b 0
f 0
wmc 47

23 Methods

Rating   Name   Duplication   Size   Complexity  
A _TestInfo._get_key_for_element() 0 3 2
A _TestInfo._xml_element_to_dict() 0 13 2
A _TestInfo._get_collected_objects_info() 0 15 4
A _TestInfo._get_system_data() 0 4 1
A _TestInfo._get_ref_var() 0 13 5
A _TestInfo._get_item_ref() 0 3 2
A _TestInfo._get_oval_system_characteristics() 0 4 1
A _TestInfo._get_item() 0 7 4
A _TestInfo._find_item_ref() 0 3 1
A _TestInfo._get_unique_key() 0 3 1
A _TestInfo._get_object_items() 0 9 4
A _TestInfo.get_info_about_test() 0 5 3
A _TestInfo.__init__() 0 9 1
A _TestInfo._get_tests() 0 2 1
A _TestInfo._get_object_info() 0 4 1
A _TestInfo._get_tests_info() 0 15 4
A _TestInfo._get_unique_id_in_dict() 0 4 2
A _TestInfo._get_oval_definitions() 0 4 1
A _TestInfo._get_collected_objects() 0 4 1
A _TestInfo._get_objects() 0 4 1
A _TestInfo._collected_object_is_not_none_and_contain_var_ref() 0 3 1
A _TestInfo._get_dict_of_data() 0 3 1
A _TestInfo._fix_message() 0 5 3

How to fix   Complexity   

Complexity

Complex classes like oval_graph.arf_xml_parser._test_info 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 1
import uuid
2
3 1
ns = {
4
    'XMLSchema': 'http://oval.mitre.org/XMLSchema/oval-results-5',
5
    'xccdf': 'http://checklists.nist.gov/xccdf/1.2',
6
    'arf': 'http://scap.nist.gov/schema/asset-reporting-format/1.1',
7
    'oval-definitions': 'http://oval.mitre.org/XMLSchema/oval-definitions-5',
8
    'scap': 'http://scap.nist.gov/schema/scap/source/1.2',
9
    'oval-characteristics': 'http://oval.mitre.org/XMLSchema/oval-system-characteristics-5',
10
}
11
12
13 1
class _TestInfo:
14 1
    def __init__(self, report_data):
15 1
        self.report_data = report_data
16 1
        self.oval_definitions = self._get_oval_definitions()
17 1
        self.tests = self._get_tests()
18 1
        self.objects = self._get_objects()
19 1
        self.oval_system_characteristics = self._get_oval_system_characteristics()
20 1
        self.collected_objects = self._get_collected_objects()
21 1
        self.system_data = self._get_system_data()
22 1
        self.tests_info = self._get_tests_info()
23
24 1
    def _get_oval_system_characteristics(self):
25 1
        return self.report_data.find(
26
            ('.//XMLSchema:oval_results/XMLSchema:results/XMLSchema:system'
27
             '/oval-characteristics:oval_system_characteristics'), ns)
28
29 1
    @staticmethod
30
    def _get_dict_of_data(data):
31 1
        return {item.attrib.get('id'): item for item in data}
32
33 1
    def _get_collected_objects(self):
34 1
        data = self.oval_system_characteristics.find(
35
            './/oval-characteristics:collected_objects', ns)
36 1
        return self._get_dict_of_data(data)
37
38 1
    def _get_system_data(self):
39 1
        data = self.oval_system_characteristics.find(
40
            './/oval-characteristics:system_data', ns)
41 1
        return self._get_dict_of_data(data)
42
43 1
    def _get_oval_definitions(self):
44 1
        data = self.report_data.find(
45
            ('.//XMLSchema:oval_results/oval-definitions:oval_definitions'), ns)
46 1
        return data
47
48 1
    def _get_tests(self):
49 1
        return self.oval_definitions.find('.//oval-definitions:tests', ns)
50
51 1
    def _get_objects(self):
52 1
        data = self.oval_definitions.find(
53
            ('.//oval-definitions:objects'), ns)
54 1
        return self._get_dict_of_data(data)
55
56 1
    @staticmethod
57
    def _get_key_for_element(element):
58 1
        return element.tag.split('}')[1] if '}' in element.tag else element.tag
59
60 1
    def _find_item_ref(self, object_):
61 1
        list_of_item_ref = [self._get_item_ref(item) for item in object_]
62 1
        return list(filter(None, list_of_item_ref))
63
64 1
    @staticmethod
65
    def _get_item_ref(item):
66 1
        return item.get('item_ref') if item.get('item_ref') else None
67
68 1
    @staticmethod
69
    def _get_unique_key(key):
70 1
        return key + '@' + str(uuid.uuid4())
71
72 1
    def _get_unique_id_in_dict(self, object_, dict_):
73 1
        if self._get_key_for_element(object_) in dict_:
74 1
            return self._get_unique_key(self._get_key_for_element(object_))
75 1
        return self._get_key_for_element(object_)
76
77 1
    def _get_collected_objects_info(self, collected_object, object_):
78 1
        out = {}
79 1
        if len(collected_object) == 0:
80 1
            out[self._get_unique_id_in_dict(object_, out)
81
                ] = self._get_object_items(object_, collected_object)
82
        else:
83 1
            item_refs = self._find_item_ref(collected_object)
84 1
            if item_refs:
85 1
                for item_id in item_refs:
86 1
                    out[self._get_unique_id_in_dict(
87
                        object_, out)] = self._get_item(item_id)
88
            else:
89 1
                out[self._get_unique_id_in_dict(
90
                    object_, out)] = self._get_object_items(object_, collected_object)
91 1
        return out
92
93 1
    def _xml_element_to_dict(self, object_, collected_object):
94 1
        result = {}
95 1
        if collected_object is not None:
96 1
            result[
97
                collected_object.attrib.get('id')
98
            ] = collected_object.attrib.get('flag')
99 1
            result.update(
100
                self._get_collected_objects_info(collected_object, object_))
101
        else:
102 1
            result[object_.attrib.get('id')] = "does not exist"
103 1
            result[self._get_unique_id_in_dict(
104
                object_, result)] = self._get_object_items(object_, collected_object)
105 1
        return result
106
107 1
    def _get_object_items(self, object_, collected_object):
108 1
        out = {}
109 1
        for element in object_.iterchildren():
110 1
            if element.text and element.text.strip():
111 1
                out[self._get_unique_id_in_dict(element, out)] = element.text
112
            else:
113 1
                out[self._get_unique_id_in_dict(element, out)] = self._get_ref_var(
114
                    element, collected_object)
115 1
        return out
116
117 1
    def _get_ref_var(self, element, collected_object):
118 1
        variable_value = ''
119 1
        if self._collected_object_is_not_none_and_contain_var_ref(
120
                element, collected_object):
121 1
            var_id = element.attrib.get('var_ref')
122 1
            for item in collected_object:
123 1
                if var_id == item.attrib.get('variable_id'):
124 1
                    variable_value += item.text
125 1
                elif self._get_key_for_element(item) == 'message':
126 1
                    variable_value += self._fix_message(item, var_id) + '<br>'
127
        else:
128 1
            variable_value = 'no value'
129 1
        return variable_value
130
131 1
    @staticmethod
132
    def _fix_message(item, var_id):
133 1
        if len(item.text) == 99 and var_id[:99 - item.text.find('(')] in var_id:
134 1
            return item.text[:item.text.find('(') + 1] + var_id + ')'
135
        return item.text
136
137 1
    @staticmethod
138
    def _collected_object_is_not_none_and_contain_var_ref(element, collected_object):
139 1
        return collected_object is not None and 'var_ref' in element.attrib
140
141 1
    def _get_item(self, item_ref):
142 1
        item = self.system_data.get(item_ref)
143 1
        out = {}
144 1
        for element in item.iterchildren():
145 1
            if element.text and element.text.strip():
146 1
                out[self._get_unique_id_in_dict(element, out)] = element.text
147 1
        return out
148
149 1
    def _get_object_info(self, id_object):
150 1
        object_ = self.objects.get(id_object)
151 1
        object_collected = self.collected_objects.get(id_object)
152 1
        return self._xml_element_to_dict(object_, object_collected)
153
154 1
    def _get_tests_info(self):
155 1
        out = []
156 1
        for test in self.tests:
157 1
            objects = []
158 1
            for item in test:
159 1
                object_id = item.attrib.get('object_ref')
160 1
                if object_id:
161 1
                    objects.append(self._get_object_info(object_id))
162 1
            out.append(
163
                dict(
164
                    id=test.attrib.get('id'),
165
                    comment=test.attrib.get('comment'),
166
                    objects=objects,
167
                ))
168 1
        return out
169
170 1
    def get_info_about_test(self, id_of_test):
171 1
        for test in self.tests_info:
172 1
            if test['id'] == id_of_test:
173 1
                return test
174
        return None
175