Passed
Push — master ( 958bc0...1938a8 )
by Jan
05:51 queued 02:21
created

OvalNode.add_child()   A

Complexity

Conditions 2

Size

Total Lines 7
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

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