source: rtems-central/specview.py @ 932679b

Last change on this file since 932679b was f411e8c, checked in by Sebastian Huber <sebastian.huber@…>, on 11/23/21 at 16:42:37

specview.py: Remove unused variable

  • Property mode set to 100755
File size: 13.6 KB
Line 
1#!/usr/bin/env python
2# SPDX-License-Identifier: BSD-2-Clause
3""" Views the specification. """
4
5# Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26# POSSIBILITY OF SUCH DAMAGE.
27
28import argparse
29import itertools
30import sys
31from typing import Any, List, Optional, Set, Tuple
32
33from rtemsspec.items import EmptyItem, Item, ItemCache, ItemMapper, \
34    ItemGetValueContext, Link
35from rtemsspec.sphinxcontent import SphinxContent
36from rtemsspec.util import load_config
37from rtemsspec.transitionmap import Transition, TransitionMap
38
39_CHILD_ROLES = [
40    "requirement-refinement", "interface-ingroup", "interface-ingroup-hidden",
41    "interface-function", "appl-config-group-member", "glossary-member"
42]
43
44_PARENT_ROLES = ["function-implementation", "interface-enumerator"]
45
46
47def _get_value_dummy(_ctx: ItemGetValueContext) -> Any:
48    return ""
49
50
51_MAPPER = ItemMapper(EmptyItem())
52_MAPPER.add_get_value("requirement/functional/action:/text-template",
53                      _get_value_dummy)
54_MAPPER.add_get_value("glossary/term:/plural", _get_value_dummy)
55_MAPPER.add_get_value(
56    "requirement/non-functional/performance-runtime:/limit-kind",
57    _get_value_dummy)
58_MAPPER.add_get_value(
59    "requirement/non-functional/performance-runtime:/limit-condition",
60    _get_value_dummy)
61_MAPPER.add_get_value(
62    "requirement/non-functional/performance-runtime:/environment",
63    _get_value_dummy)
64
65
66def _visit_action_conditions(item: Item, name: str) -> None:
67    for index, condition in enumerate(item[name]):
68        for index_2, state in enumerate(condition["states"]):
69            _MAPPER.substitute(state["text"], item,
70                               f"{name}[{index}]/states[{index_2}]/text")
71
72
73def _visit_action(item: Item) -> None:
74    _visit_action_conditions(item, "pre-conditions")
75    _visit_action_conditions(item, "post-conditions")
76
77
78_VISITORS = {
79    "requirement/functional/action": _visit_action,
80}
81
82
83def _info(item: Item) -> str:
84    if not item.get("_pre_qualified", True):
85        return ", not-pre-qualified"
86    try:
87        if item["_validated"]:
88            return ""
89        return ", not-validated"
90    except KeyError:
91        return ""
92
93
94def _visit_item(item: Item, level: int, role: Optional[str],
95                validated_filter: str) -> bool:
96    validated = item.get("_validated", True)
97    if validated_filter == "yes" and not validated:
98        return False
99    if validated_filter == "no" and validated:
100        return False
101    role_info = "" if role is None else f", role={role}"
102    print(
103        f"{'  ' * level}{item.uid} (type={item.type}{role_info}{_info(item)})")
104    for name in ["text", "brief", "description", "notes", "rationale"]:
105        if name in item:
106            _MAPPER.substitute(item[name], item)
107    try:
108        visitor = _VISITORS[item.type]
109    except KeyError:
110        pass
111    else:
112        visitor(item)
113    return True
114
115
116def _view_interface_placment(item: Item, level: int,
117                             validated_filter: str) -> None:
118    for link in item.links_to_children("interface-placement"):
119        if _visit_item(link.item, level, link.role, validated_filter):
120            _view_interface_placment(link.item, level + 1, validated_filter)
121
122
123def _view(item: Item, level: int, role: Optional[str], validated_filter: str,
124          enabled: List[str]) -> None:
125    if not item.is_enabled(enabled):
126        return
127    if not _visit_item(item, level, role, validated_filter):
128        return
129    for child in item.children("validation"):
130        if child.is_enabled(enabled):
131            _visit_item(child, level + 1, "validation", validated_filter)
132    _view_interface_placment(item, level + 1, validated_filter)
133    for link in item.links_to_children(_CHILD_ROLES):
134        _view(link.item, level + 1, link.role, validated_filter, enabled)
135    for link in item.links_to_parents(_PARENT_ROLES):
136        _view(link.item, level + 1, link.role, validated_filter, enabled)
137
138
139_VALIDATION_LEAF = [
140    "constraint",
141    "glossary/group",
142    "glossary/term",
143    "interface/appl-config-group",
144    "interface/container",
145    "interface/domain",
146    "interface/enum",
147    "interface/enumerator",
148    "interface/header-file",
149    "interface/register-block",
150    "interface/struct",
151    "interface/typedef",
152    "interface/union",
153    "interface/unspecified-define",
154    "interface/unspecified-function",
155    "requirement/functional/action",
156    "requirement/non-functional/performance-runtime",
157    "runtime-measurement-test",
158    "test-case",
159    "test-suite",
160    "validation",
161]
162
163_NOT_PRE_QUALIFIED = set([
164    "/acfg/constraint/option-not-pre-qualified",
165    "/constraint/constant-not-pre-qualified",
166    "/constraint/directive-not-pre-qualified",
167])
168
169
170def _is_pre_qualified(item: Item) -> bool:
171    return not bool(
172        set(parent.uid for parent in item.parents("constraint")).intersection(
173            _NOT_PRE_QUALIFIED))
174
175
176def _validation_count(item: Item, enabled: List[str]) -> int:
177    return len(
178        list(child for child in item.children("validation")
179             if child.is_enabled(enabled)))
180
181
182def _validate(item: Item, enabled: List[str]) -> bool:
183    if not item.is_enabled(enabled):
184        return True
185    count = _validation_count(item, enabled)
186    validated = True
187    for child in item.children(_CHILD_ROLES):
188        validated = _validate(child, enabled) and validated
189        count += 1
190    for parent in item.parents(_PARENT_ROLES):
191        validated = _validate(parent, enabled) and validated
192        count += 1
193    pre_qualified = _is_pre_qualified(item)
194    item["_pre_qualified"] = pre_qualified
195    if count == 0:
196        if not pre_qualified:
197            validated = True
198        else:
199            validated = item.type in _VALIDATION_LEAF
200    item["_validated"] = validated
201    return validated
202
203
204def _no_validation(item: Item, path: List[str],
205                   enabled: List[str]) -> List[str]:
206    path_2 = path + [item.uid]
207    if not item.is_enabled(enabled):
208        return path_2[:-1]
209    leaf = _validation_count(item, enabled) == 0
210    for child in item.children(_CHILD_ROLES):
211        path_2 = _no_validation(child, path_2, enabled)
212        leaf = False
213    for parent in item.parents(_PARENT_ROLES):
214        path_2 = _no_validation(parent, path_2, enabled)
215        leaf = False
216    if leaf and not item.get("_validated", True):
217        for index, component in enumerate(path_2):
218            if component:
219                print(f"{'  ' * index}{component}")
220            path_2[index] = ""
221    return path_2[:-1]
222
223
224def _gather_interface_placement(item: Item, spec: Set) -> None:
225    for child in item.children("interface-placement"):
226        spec.add(child)
227        _gather_interface_placement(child, spec)
228
229
230def _gather(item: Item, spec: Set) -> None:
231    spec.add(item)
232    _gather_interface_placement(item, spec)
233    for child in item.children("validation"):
234        spec.add(child)
235    for child in item.children(_CHILD_ROLES):
236        _gather(child, spec)
237    for parent in item.parents(_PARENT_ROLES):
238        _gather(parent, spec)
239
240
241def _add_link(item_cache: ItemCache, child: Item, link: Link) -> None:
242    parent = item_cache[child.to_abs_uid(link["uid"])]
243    parent.add_link_to_child(Link(child, link))
244
245
246def _process_test_cases(item_cache: ItemCache) -> None:
247    for item in item_cache.all.values():
248        if item.type == "test-case":
249            for actions in item["test-actions"]:
250                for checks in actions["checks"]:
251                    for link in checks["links"]:
252                        _add_link(item_cache, item, link)
253                for link in actions["links"]:
254                    _add_link(item_cache, item, link)
255
256
257def _make_row(transition_map: TransitionMap, map_idx: int,
258              variant: Transition) -> Tuple[str, ...]:
259    return tuple(
260        itertools.chain(
261            [str(map_idx), str(variant.desc_idx)],
262            (transition_map.pre_co_idx_st_idx_to_st_name(co_idx, st_idx)
263             for co_idx, st_idx in enumerate(
264                 transition_map.map_idx_to_pre_co_states(
265                     map_idx, variant.pre_cond_na))),
266            (transition_map.post_co_idx_st_idx_to_st_name(co_idx, st_idx)
267             for co_idx, st_idx in enumerate(variant.post_cond))))
268
269
270def _action_table(enabled: List[str], item: Item) -> None:
271    rows = [
272        tuple(
273            itertools.chain(["Entry", "Descriptor"],
274                            (condition["name"]
275                             for condition in item["pre-conditions"]),
276                            (condition["name"]
277                             for condition in item["post-conditions"])))
278    ]
279    transition_map = TransitionMap(item)
280    for map_idx, variant in transition_map.get_variants(enabled):
281        rows.append(_make_row(transition_map, map_idx, variant))
282    content = SphinxContent()
283    content.add_simple_table(rows)
284    print(str(content))
285
286
287def _to_name(transition_map, co_idx: int, st_idx: int) -> str:
288    return (f"{transition_map.post_co_idx_to_co_name(co_idx)} = "
289            f"{transition_map.post_co_idx_st_idx_to_st_name(co_idx, st_idx)}")
290
291
292def _action_list(enabled: List[str], item: Item) -> None:
293    transition_map = TransitionMap(item)
294    for post_cond, pre_conds in transition_map.get_post_conditions(enabled):
295        print("")
296        if post_cond[0]:
297            print(transition_map.skip_idx_to_name(post_cond[0]))
298        else:
299            names = []  # type: List[str]
300            for co_idx, st_idx in enumerate(post_cond[1:]):
301                st_name = transition_map.post_co_idx_st_idx_to_st_name(
302                    co_idx, st_idx)
303                if st_name != "NA":
304                    co_name = transition_map.post_co_idx_to_co_name(co_idx)
305                    names.append(f"{co_name} = {st_name}")
306            print(", ".join(names))
307        for row in pre_conds:
308            entries = []
309            for co_idx, co_states in enumerate(row):
310                co_name = transition_map.pre_co_idx_to_co_name(co_idx)
311                states = [
312                    transition_map.pre_co_idx_st_idx_to_st_name(
313                        co_idx, st_idx) for st_idx in set(co_states)
314                ]
315                if len(states) == 1:
316                    if states[0] != "NA":
317                        entries.append(f"{co_name} = {states[0]}")
318                else:
319                    entries.append(f"{co_name} = {{ " + ", ".join(states) +
320                                   " }")
321            print("")
322            print("    * " + ", ".join(entries))
323
324
325def main() -> None:
326    """ Views the specification. """
327    parser = argparse.ArgumentParser()
328    parser.add_argument('--filter',
329                        choices=[
330                            "none", "orphan", "no-validation", "action-table",
331                            "action-list"
332                        ],
333                        type=str.lower,
334                        default="none",
335                        help="filter the items")
336    parser.add_argument('--validated',
337                        choices=["all", "yes", "no"],
338                        type=str.lower,
339                        default="all",
340                        help="filter the items by the validated status")
341    parser.add_argument(
342        "--enabled",
343        help=("a comma separated list of enabled options used to evaluate "
344              "enabled-by expressions"))
345    parser.add_argument("UIDs",
346                        metavar="UID",
347                        nargs="*",
348                        help="an UID of a specification item")
349    args = parser.parse_args(sys.argv[1:])
350    enabled = args.enabled.split(",") if args.enabled else []
351    config = load_config("config.yml")
352    item_cache = ItemCache(config["spec"])
353    _process_test_cases(item_cache)
354    root = item_cache["/req/root"]
355
356    if args.filter == "none":
357        _validate(root, enabled)
358        _view(root, 0, None, args.validated, enabled)
359    elif args.filter == "action-table":
360        for uid in args.UIDs:
361            _action_table(enabled, item_cache[uid])
362    elif args.filter == "action-list":
363        for uid in args.UIDs:
364            _action_list(enabled, item_cache[uid])
365    elif args.filter == "orphan":
366        spec = set()  # type: Set[Item]
367        _gather(root, spec)
368        for item in item_cache.all.values():
369            if item["type"] in ["build", "glossary", "spec"]:
370                continue
371            if item not in spec:
372                print(item.uid)
373    elif args.filter == "no-validation":
374        _validate(root, enabled)
375        _no_validation(root, [], enabled)
376
377
378if __name__ == "__main__":
379    main()
Note: See TracBrowser for help on using the repository browser.