Passed
Pull Request — master (#173)
by Jan
03:58
created

OvalNode.add_child_to_node()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 6
ccs 5
cts 6
cp 0.8333
rs 10
c 0
b 0
f 0
cc 2
nop 3
crap 2.0185
1 1
from .evaluate import (is_notapp_result, oval_operator_and, oval_operator_one,
2
                       oval_operator_or, oval_operator_xor)
3
4
5 1
class OvalNode():
6
    """The Oval Node object is one node of the OVAL tree.
7
       The graphic representation of the OVAL tree is the OVAL graph.
8
9
    Attributes:
10
        node_id (str): id of node
11
        node_type (str): type node
12
        value (str): value of node for operator and, or, one etc... and for value true,
13
        false, error etc...
14
        negation (bool): value indicating whether the node is negated
15
        comment (str): some comment about node
16
        tag (str): tag specifies if the node represents OVAL test,
17
        OVAL definition or XCCDF rule
18
        test_result_details (dict|None): information about test
19
        children ([OvalNode]): children of node
20
    """
21
22 1
    def __init__(self, **kwargs):
23
        """This metode construct OvalNode and validate values of parameteres.
24
25
        Required args:
26
            node_id (str|int): identifies node
27
            node_type (str): type of node (value or operator)
28
            value (str): value of node
29
30
        Optional args:
31
            negation (bool): value indicating whether the node is negated (empty eq False)
32
            comment (str): text about node (empty eq None)
33
            tag (str): tag specifies if the node represents OVAL test,
34
            OVAL definition or XCCDF rule (empty eq None)
35
            test_result_details (dict|None): information about test (empty eq None)
36
            children ([OvalNode]): array of children of node (empty eq empty array)
37
38
        Raises:
39
            KeyError, TypeError, ValueError
40
        """
41 1
        try:
42 1
            self.node_id = kwargs['node_id']
43 1
            self.node_type = self._validate_type(kwargs['node_type'])
44 1
            self.value = self._validate_value(self.node_type, kwargs['value'])
45
46 1
            self._check_missing_children_for_operator(
47
                kwargs.get('children', None))
48 1
            self.negation = self._validate_negation(
49
                kwargs.get('negation', False))
50 1
        except KeyError as key_error:
51 1
            raise Exception("Missing required argument!") from key_error
52
53 1
        self.comment = kwargs.get('comment', None)
54 1
        self.tag = kwargs.get('tag', None)
55 1
        self.test_result_details = kwargs.get('test_result_details', None)
56
57 1
        input_children = kwargs.get('children', None)
58 1
        self.children = []
59 1
        if input_children:
60 1
            for child in input_children:
61 1
                self.add_child(child)
62
63 1
    @staticmethod
64
    def _validate_negation(input_negation):
65 1
        if not isinstance(input_negation, bool):
66 1
            raise TypeError("Wrong value of negation argument!")
67 1
        return input_negation
68
69 1
    @staticmethod
70
    def _validate_type(input_node_type):
71 1
        node_type = input_node_type.lower()
72 1
        if node_type not in ("value", "operator"):
73 1
            raise TypeError("Wrong value of node_type argument!")
74 1
        return node_type
75
76 1
    @staticmethod
77
    def _validate_value(input_node_type, input_value):
78 1
        value = input_value.lower()
79
80 1
        allowed_values = [
81
            "true",
82
            "false",
83
            "error",
84
            "unknown",
85
            "noteval",
86
            "notappl"]
87 1
        allowed_operators = ["or", "and", "one", "xor"]
88
89 1
        if input_node_type == "value" and value not in allowed_values:
90 1
            raise TypeError(
91
                "Wrong value of argument value for value node!")
92
93 1
        if input_node_type == "operator" and value not in allowed_operators:
94 1
            raise TypeError(
95
                "Wrong value of argument value for operator node!")
96
97 1
        return value
98
99 1
    def _check_missing_children_for_operator(self, children):
100 1
        if children is None and self.node_type == "operator":
101 1
            raise ValueError(
102
                "The operator node must have a child!")
103
104 1
    def __repr__(self):
105 1
        return self.value
106
107 1
    def add_child(self, node):
108 1
        if self.node_type == "operator":
109 1
            assert isinstance(node, OvalNode)
110 1
            self.children.append(node)
111 1
            return
112 1
        raise ValueError(
113
            "The value node cannot contain any child!")
114
115 1
    def _get_result_counts(self):
116 1
        result = {
117
            'true_cnt': 0,
118
            'false_cnt': 0,
119
            'error_cnt': 0,
120
            'unknown_cnt': 0,
121
            'noteval_cnt': 0,
122
            'notappl_cnt': 0
123
        }
124
125 1
        for child in self.children:
126 1
            if child.value == 'true' and not child.negation:
127 1
                result['true_cnt'] += 1
128 1
            elif child.value == 'true' and child.negation:
129 1
                result['false_cnt'] += 1
130 1
            elif child.value == 'false' and not child.negation:
131 1
                result['false_cnt'] += 1
132 1
            elif child.value == 'false' and child.negation:
133 1
                result['true_cnt'] += 1
134
            else:
135 1
                if child.node_type == "operator":
136 1
                    result[child.evaluate_tree() + "_cnt"] += 1
137
                else:
138 1
                    result[child.value + "_cnt"] += 1
139 1
        return result
140
141 1
    def evaluate_tree(self):
142 1
        result = self._get_result_counts()
143 1
        out_result = None
144 1
        if is_notapp_result(result):
145 1
            out_result = "notappl"
146
        else:
147 1
            if self.value == "or":
148 1
                out_result = oval_operator_or(result)
149 1
            elif self.value == "and":
150 1
                out_result = oval_operator_and(result)
151 1
            elif self.value == "one":
152 1
                out_result = oval_operator_one(result)
153 1
            elif self.value == "xor":
154 1
                out_result = oval_operator_xor(result)
155
156 1
        if out_result == 'true' and self.negation:
157 1
            out_result = 'false'
158 1
        elif out_result == 'false' and self.negation:
159 1
            out_result = 'true'
160
161 1
        return out_result
162
163 1
    def find_node_with_id(self, node_id):
164 1
        if self.node_id == node_id:
165 1
            return self
166 1
        for child in self.children:
167 1
            if child.node_id == node_id:
168 1
                return child
169 1
        for child in self.children:
170 1
            if child.children != []:
171 1
                return child.find_node_with_id(node_id)
172
        return None
173
174 1
    def add_child_to_node(self, node_id, new_node):
175 1
        node = self.find_node_with_id(node_id)
176 1
        if node is not None:
177 1
            node.add_child(new_node)
178 1
            return True
179
        return False
180
181 1
    def change_value_of_node(self, node_id, value):
182 1
        node = self.find_node_with_id(node_id)
183 1
        if node is not None:
184 1
            self._validate_value(node.node_type, value)
185 1
            node.value = value
186 1
            return True
187
        return False
188