diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-07-15 10:04:25 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-07-15 10:12:50 +0200 |
commit | e49c7597c091559caa5b1e0f2cabe1bb64ae9cb5 (patch) | |
tree | 33978dc3fba68ec39a77855148fc7816d0b56764 /rtemsspec | |
parent | Rename "external" in "modules" (diff) | |
download | rtems-central-e49c7597c091559caa5b1e0f2cabe1bb64ae9cb5.tar.bz2 |
Rename "rtemsqual" in "rtemsspec"
Diffstat (limited to 'rtemsspec')
214 files changed, 15483 insertions, 0 deletions
diff --git a/rtemsspec/__init__.py b/rtemsspec/__init__.py new file mode 100644 index 00000000..13e4cfd0 --- /dev/null +++ b/rtemsspec/__init__.py @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" The RTEMS pre-qualification package. """ + +# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +__all__ = [ + "applconfig", "build", "content", "glossary", "interface", "interfacedoc", + "items", "specdoc", "specverify", "util", "validation" +] + +import rtemsspec.applconfig +import rtemsspec.build +import rtemsspec.content +import rtemsspec.glossary +import rtemsspec.interface +import rtemsspec.interfacedoc +import rtemsspec.items # noqa: F401 +import rtemsspec.specdoc +import rtemsspec.specverify +import rtemsspec.util # noqa: F401 +import rtemsspec.validation # noqa: F401 diff --git a/rtemsspec/applconfig.py b/rtemsspec/applconfig.py new file mode 100644 index 00000000..bd08c8c7 --- /dev/null +++ b/rtemsspec/applconfig.py @@ -0,0 +1,487 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Functions for application configuration documentation generation. """ + +# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import copy +from typing import Any, Dict, List, Optional + +from rtemsspec.content import CContent, get_value_double_colon, \ + get_value_doxygen_function, get_value_hash +from rtemsspec.sphinxcontent import SphinxContent, SphinxMapper +from rtemsspec.items import EmptyItem, Item, ItemCache, ItemGetValueContext, \ + ItemMapper + +ItemMap = Dict[str, Item] + +_FEATURE = "This configuration option is a boolean feature define." + +_OPTION_TYPES = { + "feature": _FEATURE, + "feature-enable": _FEATURE, + "integer": "This configuration option is an integer define.", + "initializer": "This configuration option is an initializer define." +} + +_OPTION_DEFAULT_CONFIG = { + "feature": + lambda item: item["default"], + "feature-enable": + lambda item: + """If this configuration option is undefined, then the described feature is not +enabled.""" +} + + +class _ContentAdaptor: + """ + The content adaptor provides a specialized interface to a content class. + + By default, Sphinx content is generated. + """ + def __init__(self, mapper: ItemMapper, content: Any) -> None: + self.mapper = mapper + self.content = content + + def substitute(self, text: Optional[str]) -> str: + """ Substitutes the optional text using the item mapper. """ + return self.mapper.substitute(text) + + def add_group(self, name: str, description: str) -> None: + """ Adds an option group. """ + self.content.add_header(name, level=2) + self.content.add(description) + + def add_option(self, name: str, index_entries: List[str]) -> None: + """ Adds an option. """ + self.content.add_index_entries([name] + index_entries) + self.content.add_label(name) + self.content.add_header(name, level=3) + self.content.add_definition_item("CONSTANT:", f"``{name}``") + + def add_option_type(self, option_type: str) -> None: + """ Adds an option type. """ + self.content.add_definition_item("OPTION TYPE:", option_type) + + def add_option_default_value(self, value: str) -> None: + """ Adds an option default value. """ + self.content.add_definition_item("DEFAULT VALUE:", value) + + def add_option_default_config(self, config: str) -> None: + """ Adds an option default configuration. """ + self.content.add_definition_item("DEFAULT CONFIGURATION:", config) + + def add_option_value_constraints(self, lines: List[str]) -> None: + """ Adds a option value constraints. """ + self.content.add_definition_item("VALUE CONSTRAINTS:", lines) + + def add_option_description(self, description: str) -> None: + """ Adds a option description. """ + self.content.add_definition_item("DESCRIPTION:", description) + + def add_option_notes(self, notes: Optional[str]) -> None: + """ Adds option notes. """ + if not notes: + notes = "None." + self.content.add_definition_item("NOTES:", notes) + + def add_licence_and_copyrights(self) -> None: + """ Adds the license and copyrights. """ + self.content.add_licence_and_copyrights() + + def register_license_and_copyrights_of_item(self, item: Item) -> None: + """ Registers the license and copyrights of the item. """ + self.content.register_license_and_copyrights_of_item(item) + + def write(self, filename: str): + """ Writes the content to the file specified by the path. """ + self.content.write(filename) + + +class _SphinxContentAdaptor(_ContentAdaptor): + def __init__(self, mapper: ItemMapper) -> None: + super().__init__(mapper, SphinxContent()) + + +class _DoxygenContentAdaptor(_ContentAdaptor): + # pylint: disable=attribute-defined-outside-init + + def __init__(self, mapper: ItemMapper) -> None: + super().__init__(mapper, CContent()) + self._reset() + + def _reset(self) -> None: + self._name = "" + self._option_type = "" + self._default_value = "" + self._default_config = "" + self._value_constraints = [] # type: List[str] + self._description = "" + + def add_group(self, name: str, description: str) -> None: + identifier = f"RTEMSApplConfig{name.replace(' ', '')}" + with self.content.defgroup_block(identifier, name): + self.content.add("@ingroup RTEMSApplConfig") + self.content.doxyfy(description) + self.content.add("@{") + + def add_option(self, name: str, _index_entries: List[str]) -> None: + self.content.open_doxygen_block() + self._name = name + + def add_option_type(self, option_type: str) -> None: + self._option_type = option_type + + def add_option_default_value(self, value: str) -> None: + self._default_value = value + + def add_option_default_config(self, config: str) -> None: + self._default_config = config + + def add_option_value_constraints(self, lines: List[str]) -> None: + self._value_constraints = lines + + def add_option_description(self, description: str) -> None: + self._description = description + + def add_option_notes(self, notes: Optional[str]) -> None: + self.content.add_brief_description(self._option_type) + self.content.doxyfy(self._description) + self.content.add_paragraph("Default Value", self._default_value) + self.content.add_paragraph("Default Configuration", + self._default_config) + self.content.add_paragraph("Value Constraints", + self._value_constraints) + self.content.add_paragraph("Notes", notes) + self.content.close_comment_block() + self.content.append(f"#define {self._name}") + self._reset() + + def add_licence_and_copyrights(self) -> None: + self.content.add("/** @} */") + + +def _generate_feature(content: _ContentAdaptor, item: Item, + option_type: str) -> None: + content.add_option_default_config( + content.substitute(_OPTION_DEFAULT_CONFIG[option_type](item))) + + +def _generate_min_max(lines: List[str], value: str, word: str) -> None: + lines.append("The value of this configuration option shall be " + f"{word} than or equal to {value}.") + + +def _generate_set(lines: List[str], values: List[Any]) -> None: + value_set = "{" + ", ".join([str(x) for x in values]) + "}" + lines.append("The value of this configuration option shall be") + lines.append(f"an element of {value_set}.") + + +def _start_constraint_list(lines: List[str]) -> None: + lines.append("The value of this configuration option shall " + "satisfy all of the following") + lines.append("constraints:") + + +def _generate_item_min(lines: List[str], constraints: Dict[str, Any]) -> None: + if "min" in constraints: + value = constraints["min"] + lines.append("") + lines.append(f"* It shall be greater than or equal to {value}.") + + +def _generate_item_max(lines: List[str], constraints: Dict[str, Any]) -> None: + if "max" in constraints: + value = constraints["max"] + lines.append("") + lines.append(f"* It shall be less than or equal to {value}.") + + +def _generate_item_set(lines: List[str], constraints: Dict[str, Any]) -> None: + if "set" in constraints: + value_set = constraints["set"] + lines.append("") + lines.append(f"* It shall be an element of {value_set}.") + + +def _generate_item_texts(lines: List[str], constraints: Dict[str, + Any]) -> None: + for text in constraints.get("texts", []): + lines.append("") + text = text.replace("The value of this configuration option", "It") + text = text.strip().split("\n") + lines.append(f"* {text[0]}") + lines.extend([f" {x}" if x else "" for x in text[1:]]) + + +def _resolve_constraint_links(content: _ContentAdaptor, item: Item, + constraints: Dict[str, Any]) -> None: + texts = [] # type: List[str] + for parent in item.parents("constraint"): + content.register_license_and_copyrights_of_item(parent) + texts.append(parent["text"]) + if texts: + constraints.setdefault("texts", []).extend(reversed(texts)) + + +def _generate_constraint(content: _ContentAdaptor, item: Item) -> None: + constraints = copy.deepcopy(item["constraints"]) + _resolve_constraint_links(content, item, constraints) + lines = [] # type: List[str] + count = len(constraints) + if count == 1: + if "min" in constraints: + _generate_min_max(lines, constraints["min"], "greater") + elif "max" in constraints: + _generate_min_max(lines, constraints["max"], "less") + elif "set" in constraints: + _generate_set(lines, constraints["set"]) + elif "texts" in constraints: + if len(constraints["texts"]) == 1: + lines.extend(constraints["texts"][0].strip().split("\n")) + else: + _start_constraint_list(lines) + _generate_item_texts(lines, constraints) + elif count == 2 and "min" in constraints and "max" in constraints: + minimum = constraints["min"] + maximum = constraints["max"] + lines.append("The value of this configuration option shall be " + f"greater than or equal to {minimum}") + lines.append(f"and less than or equal to {maximum}.") + else: + _start_constraint_list(lines) + _generate_item_min(lines, constraints) + _generate_item_max(lines, constraints) + _generate_item_set(lines, constraints) + _generate_item_texts(lines, constraints) + content.add_option_value_constraints( + [content.substitute(line) for line in lines]) + + +def _generate_initializer_or_integer(content: _ContentAdaptor, item: Item, + _option_type: str) -> None: + default_value = item["default-value"] + if not isinstance(default_value, str) or " " not in default_value: + default_value = f"The default value is {default_value}." + content.add_option_default_value(content.substitute(default_value)) + _generate_constraint(content, item) + + +_OPTION_GENERATORS = { + "feature": _generate_feature, + "feature-enable": _generate_feature, + "initializer": _generate_initializer_or_integer, + "integer": _generate_initializer_or_integer +} + + +def _generate(group: Item, options: ItemMap, content: _ContentAdaptor) -> None: + content.register_license_and_copyrights_of_item(group) + content.add_group(group["name"], content.substitute(group["description"])) + for item in sorted(options.values(), key=lambda x: x["name"]): + content.mapper.item = item + name = item["name"] + content.register_license_and_copyrights_of_item(item) + content.add_option(name, item["index-entries"]) + option_type = item["appl-config-option-type"] + content.add_option_type(_OPTION_TYPES[option_type]) + _OPTION_GENERATORS[option_type](content, item, option_type) + content.add_option_description(content.substitute(item["description"])) + content.add_option_notes(content.substitute(item["notes"])) + content.add_licence_and_copyrights() + + +def _get_value_none(_ctx: ItemGetValueContext) -> Any: + return None + + +def _sphinx_ref(ref: str) -> str: + return f":ref:`{ref}`" + + +_PTHREAD_NAME_NP = "http://man7.org/linux/man-pages/man3/" \ + "pthread_setname_np.3.html" + +_SPHINX_DOC_REFS = { + "config-scheduler-clustered": + _sphinx_ref("ConfigurationSchedulersClustered"), + "config-scheduler-table": _sphinx_ref("ConfigurationSchedulerTable"), + "config-unlimited-objects": _sphinx_ref("ConfigUnlimitedObjects"), + "mp-proxies": _sphinx_ref("MPCIProxies"), + "mrsp": _sphinx_ref("MrsP"), + "pthread-setname-np": f"`PTHREAD_SETNAME_NP(3) <{_PTHREAD_NAME_NP}>`_", + "scheduler-cbs": _sphinx_ref("SchedulerCBS"), + "scheduler-concepts": _sphinx_ref("SchedulingConcepts"), + "scheduler-edf": _sphinx_ref("SchedulerEDF"), + "scheduler-priority": _sphinx_ref("SchedulerPriority"), + "scheduler-priority-simple": _sphinx_ref("SchedulerPrioritySimple"), + "scheduler-smp-edf": _sphinx_ref("SchedulerSMPEDF"), + "scheduler-smp-priority-affinity": + _sphinx_ref("SchedulerSMPPriorityAffinity"), + "scheduler-smp-priority": _sphinx_ref("SchedulerSMPPriority"), + "scheduler-smp-priority-simple": _sphinx_ref("SchedulerSMPPrioritySimple"), + "terminate": _sphinx_ref("Terminate"), +} + + +def _get_value_sphinx_reference(ctx: ItemGetValueContext) -> Any: + return _SPHINX_DOC_REFS[ctx.key] + + +def _get_value_sphinx_function(ctx: ItemGetValueContext) -> Any: + return f"``{ctx.value[ctx.key]}()``" + + +def _get_value_sphinx_code(ctx: ItemGetValueContext) -> Any: + return f"``{ctx.value[ctx.key]}``" + + +def _add_sphinx_get_values(mapper: ItemMapper) -> None: + for key in _SPHINX_DOC_REFS: + for opt in ["feature-enable", "feature", "initializer", "integer"]: + doc_ref = f"interface/appl-config-option/{opt}:/document-reference" + mapper.add_get_value(doc_ref, _get_value_none) + mapper.add_get_value(f"{doc_ref}/{key}", + _get_value_sphinx_reference) + mapper.add_get_value("interface/function:/name", + _get_value_sphinx_function) + mapper.add_get_value("interface/macro:/name", _get_value_sphinx_function) + mapper.add_get_value("interface/struct:/name", _get_value_sphinx_code) + mapper.add_get_value("interface/typedef:/name", _get_value_sphinx_code) + mapper.add_get_value("interface/union:/name", _get_value_sphinx_code) + + +def _c_user_ref(ref: str, name: str) -> str: + c_user = "https://docs.rtems.org/branches/master/c-user/" + return f"<a href={c_user}{ref}>{name}</a>" + + +_DOXYGEN_DOC_REFS = { + "config-scheduler-clustered": + _c_user_ref("config/scheduler-clustered.html", + "Clustered Scheduler Configuration"), + "config-scheduler-table": + _c_user_ref( + "config/scheduler-clustered.html#configuration-step-3-scheduler-table", + "Configuration Step 3 - Scheduler Table"), + "config-unlimited-objects": + _c_user_ref("config/intro.html#unlimited-objects", "Unlimited Objects"), + "mp-proxies": + _c_user_ref("multiprocessing.html#proxies", "Proxies"), + "mrsp": + _c_user_ref( + "key_concepts.html#multiprocessor-resource-sharing-protocol-mrsp", + "Multiprocessor Resource Sharing Protocol (MrsP)"), + "pthread-setname-np": + f"<a href={_PTHREAD_NAME_NP}>PTHREAD_SETNAME_NP(3)</a>", + "scheduler-cbs": + _c_user_ref( + "scheduling_concepts.html#constant-bandwidth-server-scheduling-cbs", + "Constant Bandwidth Server Scheduling (CBS)"), + "scheduler-concepts": + _c_user_ref("scheduling_concepts.html", "Scheduling Concepts"), + "scheduler-edf": + _c_user_ref("scheduling_concepts.html#earliest-deadline-first-scheduler", + "Earliest Deadline First Scheduler"), + "scheduler-priority": + _c_user_ref("scheduling_concepts.html#deterministic-priority-scheduler", + "Deterministic Priority Scheduler"), + "scheduler-priority-simple": + _c_user_ref("scheduling_concepts.html#simple-priority-scheduler", + "Simple Priority Scheduler"), + "scheduler-smp-edf": + _c_user_ref( + "scheduling_concepts.html#earliest-deadline-first-smp-scheduler", + "Earliest Deadline First SMP Scheduler"), + "scheduler-smp-priority-affinity": + _c_user_ref( + "scheduling_concepts.html" + "#arbitrary-processor-affinity-priority-smp-scheduler", + "Arbitrary Processor Affinity Priority SMP Scheduler"), + "scheduler-smp-priority": + _c_user_ref( + "scheduling_concepts.html#deterministic-priority-smp-scheduler", + "Deterministic Priority SMP Scheduler"), + "scheduler-smp-priority-simple": + _c_user_ref("scheduling_concepts.html#simple-priority-smp-scheduler", + "Simple Priority SMP Scheduler"), + "terminate": + _c_user_ref("fatal_error.html#announcing-a-fatal-error", + "Announcing a Fatal Error"), +} + + +def _get_value_doxygen_reference(ctx: ItemGetValueContext) -> Any: + return _DOXYGEN_DOC_REFS[ctx.key] + + +def _add_doxygen_get_values(mapper: ItemMapper) -> None: + for key in _DOXYGEN_DOC_REFS: + for opt in ["feature-enable", "feature", "initializer", "integer"]: + doc_ref = f"interface/appl-config-option/{opt}:/document-reference" + mapper.add_get_value(doc_ref, _get_value_none) + mapper.add_get_value(f"{doc_ref}/{key}", + _get_value_doxygen_reference) + name = f"interface/appl-config-option/{opt}:/name" + mapper.add_get_value(name, get_value_hash) + mapper.add_get_value("interface/function:/name", + get_value_doxygen_function) + mapper.add_get_value("interface/macro:/name", get_value_doxygen_function) + mapper.add_get_value("interface/struct:/name", get_value_double_colon) + mapper.add_get_value("interface/typedef:/name", get_value_double_colon) + mapper.add_get_value("interface/union:/name", get_value_double_colon) + + +def generate(config: dict, item_cache: ItemCache) -> None: + """ + Generates application configuration documentation sources according to the + configuration. + + :param config: A dictionary with configuration entries. + :param item_cache: The specification item cache containing the application + configuration groups and options. + """ + sphinx_mapper = SphinxMapper(EmptyItem()) + _add_sphinx_get_values(sphinx_mapper) + doxygen_mapper = ItemMapper(EmptyItem()) + _add_doxygen_get_values(doxygen_mapper) + doxygen_content = _DoxygenContentAdaptor(doxygen_mapper) + with doxygen_content.content.defgroup_block( + "RTEMSApplConfig", "Application Configuration Options"): + doxygen_content.content.add("@ingroup RTEMSAPI") + for group_config in config["groups"]: + group = item_cache[group_config["uid"]] + assert group.type == "interface/appl-config-group" + options = {} # type: ItemMap + for child in group.children("appl-config-group-member"): + assert child.type.startswith("interface/appl-config-option") + options[child.uid] = child + sphinx_content = _SphinxContentAdaptor(sphinx_mapper) + _generate(group, options, sphinx_content) + sphinx_content.write(group_config["target"]) + _generate(group, options, doxygen_content) + doxygen_content.content.prepend_copyrights_and_licenses() + doxygen_content.content.prepend_spdx_license_identifier() + doxygen_content.write(config["doxygen-target"]) diff --git a/rtemsspec/build.py b/rtemsspec/build.py new file mode 100644 index 00000000..f1ca2be9 --- /dev/null +++ b/rtemsspec/build.py @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides support for the build specification. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from typing import Dict, List + +from rtemsspec.items import Item, ItemCache + +BSPMap = Dict[str, Dict[str, Item]] +ItemMap = Dict[str, Item] + + +def _extend_by_install_and_source(item: Item, source_files: List[str]) -> None: + for install in item["install"]: + source_files.extend(install["source"]) + source_files.extend(item["source"]) + + +def _extend_by_source(item: Item, source_files: List[str]) -> None: + source_files.extend(item["source"]) + + +def _extend_by_nothing(_item: Item, _source_files: List[str]) -> None: + pass + + +_EXTEND_SOURCE_FILES = { + "ada-test-program": _extend_by_nothing, + "bsp": _extend_by_install_and_source, + "config-file": _extend_by_nothing, + "config-header": _extend_by_nothing, + "test-program": _extend_by_source, + "group": _extend_by_nothing, + "library": _extend_by_install_and_source, + "objects": _extend_by_install_and_source, + "option": _extend_by_nothing, + "script": _extend_by_nothing, + "start-file": _extend_by_source, +} + + +def _gather_source_files(item: Item, enabled: List[str], + source_files: List[str]) -> None: + for parent in item.parents(): + if parent["type"] == "build" and parent["build-type"] in [ + "group", "objects", "start-file", "test-program" + ] and parent.is_enabled(enabled): + _gather_source_files(parent, enabled, source_files) + _EXTEND_SOURCE_FILES[item["build-type"]](item, source_files) + + +def gather_files(config: dict, item_cache: ItemCache) -> List[str]: + """ Generates a list of files form the build specification. """ + bsps = {} # type: BSPMap + for item in item_cache.all.values(): + if item["type"] == "build" and item["build-type"] == "bsp": + arch_bsps = bsps.setdefault(item["arch"].strip(), {}) + arch_bsps[item["bsp"].strip()] = item + source_files = config["sources"] # type: List[str] + arch = config["arch"] + bsp = config["bsp"] + enabled = [arch, arch + "/" + bsp] + config["enabled"] + _gather_source_files(bsps[arch][bsp], enabled, source_files) + for uid in config["uids"]: + _gather_source_files(item_cache[uid], enabled, source_files) + return source_files diff --git a/rtemsspec/content.py b/rtemsspec/content.py new file mode 100644 index 00000000..30a1a81d --- /dev/null +++ b/rtemsspec/content.py @@ -0,0 +1,1017 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides classes for content generation. """ + +# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +# pylint: disable=too-many-lines + +from contextlib import contextmanager +import collections +import itertools +import os +import re +import sys +import textwrap +from typing import Any, Callable, ContextManager, Dict, Iterable, Iterator, \ + List, NamedTuple, Optional, Set, Tuple, Union + +from rtemsspec.items import Item, ItemGetValueContext + +AddContext = Callable[["Content"], ContextManager[None]] +GenericContent = Union[str, List[str], "Content"] +GenericContentIterable = Union[Iterable[str], Iterable[List[str]], + Iterable[GenericContent]] + + +class Copyright: + """ + This class represents a copyright holder with its years of substantial + contributions. + """ + def __init__(self, holder): + self._holder = holder + self._years = set() + + def add_year(self, year: str): + """ + Adds a year to the set of substantial contributions of this copyright + holder. + """ + self._years.add(year) + + def get_statement(self) -> str: + """ Returns a copyright statement. """ + line = "Copyright (C)" + years = sorted(self._years) + year_count = len(years) + if year_count == 1: + line += " " + years[0] + elif year_count > 1: + line += " " + years[0] + ", " + years[-1] + line += " " + self._holder + return line + + def __lt__(self, other: "Copyright") -> bool: + # pylint: disable=protected-access + if self._years and other._years: + self_first_year = sorted(self._years)[0] + other_first_year = sorted(other._years)[0] + if self_first_year == other_first_year: + return self._holder > other._holder + return self_first_year > other_first_year + if self._years or other._years: + return True + return self._holder > other._holder + + +class Copyrights: + """ This class represents a set of copyright holders. """ + def __init__(self): + self.copyrights = {} + + def register(self, statement): + """ Registers a copyright statement. """ + match = re.search( + r"^\s*Copyright\s+\(C\)\s+([0-9]+),\s*([0-9]+)\s+(.+)\s*$", + statement, + flags=re.I, + ) + if match: + holder = match.group(3) + the_copyright = self.copyrights.setdefault(holder, + Copyright(holder)) + the_copyright.add_year(match.group(1)) + the_copyright.add_year(match.group(2)) + return + match = re.search( + r"^\s*Copyright\s+\(C\)\s+([0-9]+)\s+(.+)\s*$", + statement, + flags=re.I, + ) + if match: + holder = match.group(2) + the_copyright = self.copyrights.setdefault(holder, + Copyright(holder)) + the_copyright.add_year(match.group(1)) + return + match = re.search(r"^\s*Copyright\s+\(C\)\s+(.+)\s*$", + statement, + flags=re.I) + if match: + holder = match.group(1) + self.copyrights.setdefault(holder, Copyright(holder)) + return + raise ValueError(statement) + + def get_statements(self): + """ Returns all registered copyright statements as a sorted list. """ + statements = [] + for the_copyright in sorted(self.copyrights.values()): + statements.append(the_copyright.get_statement()) + return statements + + +def make_lines(content: GenericContent) -> List[str]: + """ Makes a list of lines from a generic content. """ + if isinstance(content, str): + return content.strip("\n").split("\n") + if isinstance(content, list): + return content + return content.lines + + +def _indent(lines: List[str], indent: str, + empty_line_indent: str) -> List[str]: + if indent: + return [ + indent + line if line else empty_line_indent + line + for line in lines + ] + return lines + + +@contextmanager +def _add_context(_content: "Content") -> Iterator[None]: + yield + + +_SPECIAL_BLOCK = re.compile(r"^( *\* | *[0-9]+\. | +)") + + +class Content: + """ This class builds content. """ + + # pylint: disable=too-many-instance-attributes + def __init__(self, the_license: str, pop_indent_gap: bool): + self._lines = [] # type: List[str] + self._license = the_license + self._copyrights = Copyrights() + self._gap = False + self._tab = " " + self._indents = [""] + self._indent = "" + self._empty_line_indents = [""] + self._empty_line_indent = "" + self._pop_indent_gap = pop_indent_gap + + def __str__(self): + return "\n".join(itertools.chain(self._lines, [""])) + + @property + def lines(self) -> List[str]: + """ The lines. """ + return self._lines + + @property + def tab(self) -> str: + """ The tabulator. """ + return self._tab + + def append(self, content: GenericContent) -> None: + """ Appends the content. """ + self._lines.extend( + _indent(make_lines(content), self._indent, + self._empty_line_indent)) + + def prepend(self, content: GenericContent) -> None: + """ Prepends the content. """ + self._lines[0:0] = _indent(make_lines(content), self._indent, + self._empty_line_indent) + + def add(self, + content: Optional[GenericContent], + context: AddContext = _add_context) -> None: + """ + Skips leading empty lines, adds a gap if needed, then adds the content. + """ + if not content: + return + lines = make_lines(content) + for index, line in enumerate(lines): + if line: + self._add_gap() + with context(self): + self._lines.extend( + _indent(lines[index:], self._indent, + self._empty_line_indent)) + break + + def wrap_text(self, + text: str, + initial_indent: str = "", + subsequent_indent: Optional[str] = None, + context: AddContext = _add_context) -> None: + """ Adds a gap if needed, then adds the wrapped text. """ + self._add_gap() + with context(self): + if subsequent_indent is None: + if initial_indent: + subsequent_indent = self._tab + else: + subsequent_indent = "" + wrapper = textwrap.TextWrapper() + wrapper.break_long_words = False + wrapper.break_on_hyphens = False + wrapper.initial_indent = initial_indent + wrapper.width = 79 - len(self._indent) + gap = [] # type: List[str] + for block in text.split("\n\n"): + match = _SPECIAL_BLOCK.search(block) + if match: + space = len(match.group(0)) * " " + wrapper.subsequent_indent = f"{subsequent_indent}{space}" + block = block.replace(f"\n{space}", "\n") + else: + wrapper.subsequent_indent = subsequent_indent + self._lines.extend(gap) + self._lines.extend( + _indent(wrapper.wrap(block), self._indent, + self._empty_line_indent)) + gap = [self._empty_line_indent] + + def wrap(self, + content: Optional[GenericContent], + initial_indent: str = "", + subsequent_indent: Optional[str] = None, + context: AddContext = _add_context) -> None: + """ Adds a gap if needed, then adds the wrapped content. """ + if not content: + return + if isinstance(content, str): + text = content + elif isinstance(content, list): + text = "\n".join(content) + else: + text = "\n".join(content.lines) + text = text.strip() + if not text: + return + self.wrap_text(text, initial_indent, subsequent_indent, context) + + def paste(self, content: Optional[GenericContent]) -> None: + """ Pastes the wrapped content directly to the last line. """ + if not content: + return + if isinstance(content, str): + text = content + elif isinstance(content, list): + text = "\n".join(content) + else: + text = "\n".join(content.lines) + indent_len = len(self._indent) + try: + last = self._lines[-1] + text = last[indent_len:] + " " + text + except IndexError: + last = "" + text = text.strip() + if not text: + return + wrapper = textwrap.TextWrapper() + wrapper.break_long_words = False + wrapper.break_on_hyphens = False + wrapper.initial_indent = "" + wrapper.width = 79 - len(self._indent) + for index, block in enumerate(text.split("\n\n")): + if index == 0: + wrapper.subsequent_indent = "" + lines = wrapper.wrap(block) + if 0 < len(last) >= indent_len: + self._lines[-1] = last[0:indent_len] + lines[0] + lines = lines[1:] + self.gap = True + else: + match = _SPECIAL_BLOCK.search(block) + if match: + space = len(match.group(0)) * " " + wrapper.subsequent_indent = space + block = block.replace(f"\n{space}", "\n") + else: + wrapper.subsequent_indent = "" + lines = wrapper.wrap(block) + self._lines.append(self._empty_line_indent) + self._lines.extend( + _indent(lines, self._indent, self._empty_line_indent)) + + def _add_gap(self) -> None: + if self._gap: + self._lines.extend( + _indent([""], self._indent, self._empty_line_indent)) + self._gap = True + + @property + def gap(self) -> bool: + """ + True if the next Content.add() adds a gap before the new content, + otherwise False. + """ + return self._gap + + @gap.setter + def gap(self, value: bool) -> None: + """ Sets the gap indicator for Content.add(). """ + self._gap = value + + def _update_indent(self) -> None: + self._indent = "".join(self._indents) + empty_line_indent = "".join(self._empty_line_indents) + if empty_line_indent.isspace(): + self._empty_line_indent = "" + else: + self._empty_line_indent = empty_line_indent + + def push_indent(self, + indent: Optional[str] = None, + empty_line_indent: Optional[str] = None) -> None: + """ Pushes an indent level. """ + self._indents.append(indent if indent else self._tab) + self._empty_line_indents.append( + empty_line_indent if empty_line_indent else self._tab) + self._update_indent() + self.gap = False + + def pop_indent(self) -> None: + """ Pops an indent level. """ + self._indents.pop() + self._empty_line_indents.pop() + self._update_indent() + self.gap = self._pop_indent_gap + + @contextmanager + def indent(self, + indent: Optional[str] = None, + empty_line_indent: Optional[str] = None) -> Iterator[None]: + """ Opens an indent context. """ + self.push_indent(indent, empty_line_indent) + yield + self.pop_indent() + + def indent_lines(self, level: int) -> None: + """ Indents all lines by the specified indent level. """ + prefix = level * self._tab + self._lines = [prefix + line if line else line for line in self._lines] + + def add_blank_line(self): + """ Adds a blank line. """ + self._lines.append("") + + def register_license(self, the_license: str) -> None: + """ Registers a licence for the content. """ + licenses = re.split(r"\s+OR\s+", the_license) + if self._license not in licenses: + raise ValueError(the_license) + + def register_copyright(self, statement: str) -> None: + """ Registers a copyright statement for the content. """ + self._copyrights.register(statement) + + def register_license_and_copyrights_of_item(self, item: Item) -> None: + """ Registers the license and copyrights of the item. """ + self.register_license(item["SPDX-License-Identifier"]) + for statement in item["copyrights"]: + self.register_copyright(statement) + + def write(self, path: str) -> None: + """ Writes the content to the file specified by the path. """ + directory = os.path.dirname(path) + if directory: + os.makedirs(directory, exist_ok=True) + with open(path, "w+") as out: + out.write(str(self)) + + +_BSD_2_CLAUSE_LICENSE = """Redistribution and use in source and binary \ +forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE.""" + +_PARAM = { + None: "@param ", + "in": "@param[in] ", + "out": "@param[out] ", + "inout": "@param[in,out] ", +} + + +class CInclude(NamedTuple): + """ A C include file. """ + path: str + enabled_by: str = "" + + +def _split_includes( + includes: List[CInclude]) -> Tuple[Set[str], Dict[str, Set[str]]]: + includes_unconditional = set() # type: Set[str] + includes_enabled_by = {} # type: Dict[str, Set[str]] + for inc in set(includes): + if inc.enabled_by and inc.enabled_by != "1": + try: + includes_unconditional.remove(inc.path) + except KeyError: + pass + includes_enabled_by.setdefault(inc.path, set()).add(inc.enabled_by) + elif inc.path not in includes_enabled_by: + includes_unconditional.add(inc.path) + return includes_unconditional, includes_enabled_by + + +_FUNCTION_POINTER = re.compile(r"^[^(]+\(\s\*([^)]+)\)\s*\(") +_DESIGNATOR = re.compile(r"([a-zA-Z0-9_]+)$") + + +def _get_align_pos(param: str) -> Tuple[int, int]: + if param == "...": + return 0, sys.maxsize + match = _DESIGNATOR.search(param) + if not match: + match = _FUNCTION_POINTER.search(param) + assert match + star = param.find("*") + if star >= 0: + return star, match.start(1) + return match.start(1), match.start(1) + + +def _align_params(params: List[str]) -> List[str]: + positions = list(map(_get_align_pos, params)) + max_pos = max(positions)[1] + return [ + param[:pos[0]] + (max_pos - pos[1]) * " " + param[pos[0]:] + for param, pos in zip(params, positions) + ] + + +_NOT_ALPHANUM = re.compile(r"[^a-zA-Z0-9_]") + + +class CContent(Content): + """ This class builds C content. """ + + # pylint: disable=too-many-public-methods + def __init__(self): + super().__init__("BSD-2-Clause", False) + + def doxyfy(self, content: Optional[GenericContent]) -> None: + """ + Adds a gap if needed, then adds the wrapped text with some conversion + to Doxygen markup. + """ + if not content: + return + if isinstance(content, str): + text = content + elif isinstance(content, list): + text = "\n".join(content) + else: + text = "\n".join(content.lines) + text = text.strip() + if not text: + return + blocks = collections.deque(text.split("\n\n")) + while blocks: + block = blocks.popleft() + if block.startswith(".. code-block"): + self.add("@code") + self.gap = False + while blocks: + block = blocks.popleft() + if block.startswith(" "): + self.add(block[4:].replace("\n ", "\n")) + else: + blocks.appendleft(block) + break + self.append("@endcode") + else: + self.wrap_text(block) + + def prepend_spdx_license_identifier(self): + """ + Adds an SPDX License Identifier according to the registered licenses. + """ + self.prepend([f"/* SPDX-License-Identifier: {self._license} */", ""]) + + def add_copyrights_and_licenses(self): + """ + Adds the copyrights and licenses according to the registered copyrights + and licenses. + """ + with self.comment_block(): + self.add(self._copyrights.get_statements()) + self.add(_BSD_2_CLAUSE_LICENSE) + + def prepend_copyrights_and_licenses(self): + """ + Prepends the copyrights and licenses according to the registered + copyrights and licenses. + """ + content = CContent() + with content.comment_block(): + content.add(self._copyrights.get_statements()) + content.add(_BSD_2_CLAUSE_LICENSE) + content.append("") + self.prepend(content) + + def add_have_config(self): + """ Adds a guarded config.h include. """ + self.add(["#ifdef HAVE_CONFIG_H", "#include \"config.h\"", "#endif"]) + + def _add_includes(self, includes: Set[str], local: bool) -> None: + class IncludeKey: # pylint: disable=too-few-public-methods + """ Provides a key to sort includes. """ + def __init__(self, inc: str): + self._inc = inc + + def __lt__(self, other: "IncludeKey") -> bool: + left = self._inc.split("/") + right = other._inc.split("/") + left_len = len(left) + right_len = len(right) + if left_len == right_len: + for left_part, right_part in zip(left[:-1], right[:-1]): + if left_part != right_part: + return left_part < right_part + return left[-1] < right[-1] + return left_len < right_len + + left = "\"" if local else "<" + right = "\"" if local else ">" + self.add([ + f"#include {left}{inc}{right}" + for inc in sorted(includes, key=IncludeKey) + ]) + + def _add_includes_enabled_by(self, includes: Dict[str, Set[str]], + local: bool) -> None: + enabled_by_includes = {} # type: Dict[str, Set[str]] + for inc, enabled_bys in iter(includes.items()): + enabled_by_includes.setdefault(" && ".join(sorted(enabled_bys)), + set()).add(inc) + for enabled_by, incs in sorted(iter(enabled_by_includes.items())): + self.add(f"#if {enabled_by}") + with self.indent(): + self._add_includes(incs, local) + self.add("#endif") + + def add_includes(self, + includes: List[CInclude], + local: bool = False) -> None: + """ Adds a block of includes. """ + includes_unconditional, includes_enabled_by = _split_includes(includes) + self._add_includes(includes_unconditional, local) + self._add_includes_enabled_by(includes_enabled_by, local) + + def _open_comment_block(self, begin) -> None: + self.add(begin) + self.push_indent(" * ", " *") + + def open_comment_block(self) -> None: + """ Opens a comment block. """ + self._open_comment_block("/*") + + def open_doxygen_block(self) -> None: + """ Opens a Doxygen comment block. """ + self._open_comment_block("/**") + + def open_file_block(self) -> None: + """ Opens a Doxygen @file comment block. """ + self._open_comment_block(["/**", " * @file"]) + self.gap = True + + def open_defgroup_block(self, identifier: str, name: str) -> None: + """ Opens a Doxygen @defgroup comment block. """ + self._open_comment_block(["/**", f" * @defgroup {identifier} {name}"]) + self.gap = True + + def open_function_block(self, function: str) -> None: + """ Opens a Doxygen @fn comment block. """ + self._open_comment_block(["/**", f" * @fn {function}"]) + self.gap = True + + def close_comment_block(self) -> None: + """ Closes a comment block. """ + self.pop_indent() + self.append(" */") + self.gap = True + + @contextmanager + def comment_block(self) -> Iterator[None]: + """ Opens a comment block context. """ + self.open_comment_block() + yield + self.close_comment_block() + + @contextmanager + def doxygen_block(self) -> Iterator[None]: + """ Opens a Doxygen comment block context. """ + self.open_doxygen_block() + yield + self.close_comment_block() + + @contextmanager + def file_block(self) -> Iterator[None]: + """ Opens a Doxygen @file comment block context. """ + self.open_file_block() + yield + self.close_comment_block() + + @contextmanager + def defgroup_block(self, identifier: str, name: str) -> Iterator[None]: + """ Opens a Doxygen @defgroup comment block context. """ + self.open_defgroup_block(identifier, name) + yield + self.close_comment_block() + + @contextmanager + def function_block(self, function: str) -> Iterator[None]: + """ Opens a Doxygen @fn comment block context. """ + self.open_function_block(function) + yield + self.close_comment_block() + + def open_add_to_group(self, group: str) -> None: + """ Opens an add to group. """ + with self.doxygen_block(): + self.append([f"@addtogroup {group}", "", "@{"]) + + def close_add_to_group(self) -> None: + """ Closes an add to group. """ + self.add("/** @} */") + + @contextmanager + def add_to_group(self, group: str) -> Iterator[None]: + """ Opens an add to group context. """ + self.open_add_to_group(group) + yield + self.close_add_to_group() + + def open_for_loop(self, begin: str, end: str, step: str) -> None: + """ Opens a for loop. """ + for_loop = [f"for ( {begin}; {end}; {step} ) {{"] + if len(self._indent) + len(for_loop[0]) > 79: + for_loop = [ + "for (", f"{self.tab}{begin};", f"{self.tab}{end};", + f"{self.tab}{step}", ") {" + ] + self.add(for_loop) + self.push_indent() + + def close_for_loop(self) -> None: + """ Closes a for loop. """ + self.pop_indent() + self.append(["}"]) + self.gap = True + + @contextmanager + def for_loop(self, begin: str, end: str, step: str) -> Iterator[None]: + """ Opens a for loop context. """ + self.open_for_loop(begin, end, step) + yield + self.close_for_loop() + + def _function(self, ret: str, name: str, params: List[str], + param_line: str, space: str, semicolon: str) -> None: + # pylint: disable=too-many-arguments + line = f"{ret}{space}{name}(" + if len(self._indent) + len(line) > 79: + line = f"{name}{param_line}{semicolon}" + if len(self._indent) + len(line) > 79: + self.add([ret, f"{name}("]) + else: + self.add([ret, line]) + return + else: + self.add(line) + with self.indent(): + self.add(",\n".join(params)) + self.add(f"){semicolon}") + + def call_function(self, + ret: Optional[str], + name: str, + params: Optional[List[str]] = None) -> None: + """ Adds a function call. """ + if ret: + space = " " + else: + ret = "" + space = "" + if params: + param_line = "( " + ", ".join(params) + " )" + else: + param_line = "()" + line = f"{ret}{space}{name}{param_line};" + if len(self._indent) + len(line) > 79: + if params: + self._function(ret, name, params, param_line, space, ";") + elif ret: + self.add(ret) + with self.indent(): + self.add(f"{name}();") + else: + self.add(f"{name}();") + else: + self.add(line) + + def declare_function(self, + ret: str, + name: str, + params: Optional[List[str]] = None, + define: bool = False, + align: bool = True) -> None: + # pylint: disable=too-many-arguments + """ Adds a function declaration. """ + if not params: + params = ["void"] + param_line = f"( {', '.join(params)} )" + space = "" if not ret or ret.endswith("*") else " " + semicolon = "" if define else ";" + line = f"{ret}{space}{name}{param_line}{semicolon}" + if len(self._indent) + len(line) > 79: + if align: + params = _align_params(params) + self._function(ret, name, params, param_line, space, semicolon) + else: + self.add(line) + + def open_function(self, + ret: str, + name: str, + params: Optional[List[str]] = None, + align: bool = True) -> None: + """ Opens a function definition. """ + self.declare_function(ret, name, params, define=True, align=align) + self.append("{") + self.push_indent() + + def close_function(self) -> None: + """ Closes a function definition. """ + self.pop_indent() + self.add("}") + + @contextmanager + def function(self, + ret: str, + name: str, + params: Optional[List[str]] = None, + align: bool = True) -> Iterator[None]: + """ Opens a function context. """ + self.open_function(ret, name, params, align=align) + yield + self.close_function() + + def open_condition(self, + expression: Optional[str], + chain: bool = False) -> None: + """ Opens a condition. """ + begin = "} else " if chain else "" + ifelse = f"if ( {expression} ) " if expression else "" + self.add(f"{begin}{ifelse}{{") + self.push_indent() + + def close_condition(self) -> None: + """ Closes a condition. """ + self.pop_indent() + self.add("}") + + @contextmanager + def condition(self, expression: Optional[str]) -> Iterator[None]: + """ Opens a condition context. """ + self.open_condition(expression) + yield + self.close_condition() + + @contextmanager + def first_condition(self, expression: Optional[str]) -> Iterator[None]: + """ Opens the first condition context. """ + self.open_condition(expression, False) + yield + self.pop_indent() + + @contextmanager + def next_condition(self, expression: Optional[str]) -> Iterator[None]: + """ Opens the next condition context. """ + self.open_condition(expression, True) + yield + self.pop_indent() + + @contextmanager + def final_condition(self, expression: Optional[str]) -> Iterator[None]: + """ Opens the final condition context. """ + self.open_condition(expression, True) + yield + self.close_condition() + + def add_brief_description(self, description: Optional[str]) -> None: + """ Adds a brief description. """ + self.wrap(description, initial_indent="@brief ") + + def add_param_description( + self, + params: Iterable[Dict[str, str]], + substitute: Callable[[str], str] = lambda x: x) -> None: + """ Adds a list of parameter descriptions. """ + for param in params: + self.wrap(param["name"] + " " + substitute(param["description"]), + initial_indent=_PARAM[param["dir"]]) + + def add_description_block(self, brief: Optional[str], + description: Optional[str]) -> None: + """ Adds a description block. """ + if brief or description: + with self.doxygen_block(): + self.add_brief_description(brief) + self.wrap(description) + self.gap = False + + def add_ingroup(self, ingroups: List[str]) -> None: + """ Adds an ingroup comment block. """ + self.add(["@ingroup " + ingroup for ingroup in sorted(set(ingroups))]) + + def add_group(self, identifier: str, name: str, ingroups: List[str], + brief: Optional[str], description: Optional[str]) -> None: + # pylint: disable=too-many-arguments + """ Adds a group definition. """ + with self.defgroup_block(identifier, name): + self.add_ingroup(ingroups) + self.add_brief_description(brief) + self.wrap(description) + + @contextmanager + def header_guard(self, filename: str) -> Iterator[None]: + """ Opens a header guard context. """ + guard = "_" + _NOT_ALPHANUM.sub("_", filename).upper() + self.add([f"#ifndef {guard}", f"#define {guard}"]) + yield + self.add(f"#endif /* {guard} */") + + @contextmanager + def extern_c(self) -> Iterator[None]: + """ Opens an extern "C" context. """ + self.add(["#ifdef __cplusplus", "extern \"C\" {", "#endif"]) + yield + self.add(["#ifdef __cplusplus", "}", "#endif"]) + + def add_paragraph(self, name: str, + content: Optional[GenericContent]) -> None: + """ Adds a Doxygen paragraph block. """ + if content: + self.add(f"@par {name}") + self.gap = False + last = len(self.lines) + self.doxyfy(content) + if self._empty_line_indent in self.lines[last:]: + self.lines.insert(last, f"{self._indent}@parblock") + self.lines.append(f"{self._indent}@endparblock") + + +def get_value_doxygen_function(ctx: ItemGetValueContext) -> Any: + """ Gets a value as a function for Doxygen markup. """ + return f"{ctx.value[ctx.key]}()" + + +def get_value_double_colon(ctx: ItemGetValueContext) -> Any: + """ Gets a value with a :: prefix. """ + return f"::{ctx.value[ctx.key]}" + + +def get_value_hash(ctx: ItemGetValueContext) -> Any: + """ Gets a value with a # prefix. """ + return f"#{ctx.value[ctx.key]}" + + +class ExpressionMapper: + """ Maps symbols and operations to form a C expression. """ + + # pylint: disable=no-self-use + def map_bool(self, value: bool) -> str: + """ Maps a boolean value to build an expression. """ + return str(int(value)) + + # pylint: disable=no-self-use + def map_symbol(self, symbol: str) -> str: + """ Maps a symbol to build an expression. """ + return f"defined({symbol})" + + def op_and(self) -> str: + """ Returns the and operator. """ + return " && " + + def op_or(self) -> str: + """ Returns the or operator. """ + return " || " + + def op_not(self, symbol: str) -> str: + """ Returns the negation of the symbol. """ + return f"!{symbol}" + + +class PythonExpressionMapper(ExpressionMapper): + """ Maps symbols and operations to form a Python expression. """ + + # pylint: disable=no-self-use + def map_bool(self, value: bool) -> str: + return str(value) + + # pylint: disable=no-self-use + def map_symbol(self, symbol: str) -> str: + return symbol + + def op_and(self) -> str: + return " and " + + def op_or(self) -> str: + return " or " + + def op_not(self, symbol: str) -> str: + return f"not {symbol}" + + +def _to_expression_op(enabled_by: Any, mapper: ExpressionMapper, + operation: str) -> str: + symbols = [ + _to_expression(next_enabled_by, mapper) + for next_enabled_by in enabled_by + ] + if len(symbols) == 1: + return symbols[0] + return f"({operation.join(symbols)})" + + +def _to_expression_op_and(enabled_by: Any, mapper: ExpressionMapper) -> str: + return _to_expression_op(enabled_by, mapper, mapper.op_and()) + + +def _to_expression_op_not(enabled_by: Any, mapper: ExpressionMapper) -> str: + return mapper.op_not(_to_expression(enabled_by, mapper)) + + +def _to_expression_op_or(enabled_by: Any, mapper: ExpressionMapper) -> str: + return _to_expression_op(enabled_by, mapper, mapper.op_or()) + + +_TO_EXPRESSION_OP = { + "and": _to_expression_op_and, + "not": _to_expression_op_not, + "or": _to_expression_op_or +} + + +def _to_expression(enabled_by: Any, mapper: ExpressionMapper) -> str: + if isinstance(enabled_by, bool): + return mapper.map_bool(enabled_by) + if isinstance(enabled_by, list): + return _to_expression_op_or(enabled_by, mapper) + if isinstance(enabled_by, dict): + if len(enabled_by) == 1: + key = next(iter(enabled_by)) + return _TO_EXPRESSION_OP[key](enabled_by[key], mapper) + raise ValueError + return mapper.map_symbol(enabled_by) + + +def enabled_by_to_exp(enabled_by: Any, mapper: ExpressionMapper) -> str: + """ + Returns an expression for an enabled-by attribute value. + """ + exp = _to_expression(enabled_by, mapper) + if exp.startswith("("): + return exp[1:-1] + return exp diff --git a/rtemsspec/glossary.py b/rtemsspec/glossary.py new file mode 100644 index 00000000..1131f45b --- /dev/null +++ b/rtemsspec/glossary.py @@ -0,0 +1,139 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides functions for glossary of terms generation. """ + +# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import glob +import re +from typing import Any, Dict, NamedTuple + +from rtemsspec.sphinxcontent import SphinxContent, SphinxMapper +from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper + +ItemMap = Dict[str, Item] + + +class _Glossary(NamedTuple): + """ A glossary of terms. """ + uid_to_item: ItemMap = {} + term_to_item: ItemMap = {} + + +def _gather_glossary_groups(item: Item, glossary_groups: ItemMap) -> None: + for child in item.children(): + _gather_glossary_groups(child, glossary_groups) + if item["type"] == "glossary" and item["glossary-type"] == "group": + glossary_groups[item.uid] = item + + +def _gather_glossary_terms(item: Item, glossary: _Glossary) -> None: + for child in item.children(): + _gather_glossary_terms(child, glossary) + if item["type"] == "glossary" and item["glossary-type"] == "term": + glossary.uid_to_item[item.uid] = item + term = item["term"] + assert term not in glossary.term_to_item + glossary.term_to_item[term] = item + + +def _generate_glossary_content(terms: ItemMap) -> SphinxContent: + content = SphinxContent() + content.add_header("Glossary", level=1) + content.add(".. glossary::") + with content.indent(): + content.add(":sorted:") + for item in sorted(terms.values(), key=lambda x: x["term"].lower()): + content.register_license_and_copyrights_of_item(item) + text = SphinxMapper(item).substitute(item["text"]) + content.add_definition_item(item["term"], text) + content.add_licence_and_copyrights() + return content + + +def _find_glossary_terms(path: str, document_terms: ItemMap, + glossary: _Glossary) -> None: + for src in glob.glob(path + "/**/*.rst", recursive=True): + if src.endswith("glossary.rst"): + continue + with open(src, "r") as out: + for term in re.findall(":term:`([^`]+)`", out.read()): + item = glossary.term_to_item[term] + document_terms[item.uid] = item + + +class _GlossaryMapper(ItemMapper): + def __init__(self, item: Item, document_terms: ItemMap): + super().__init__(item) + self._document_terms = document_terms + + def get_value(self, ctx: ItemGetValueContext) -> Any: + """ Recursively adds glossary terms to the document terms. """ + if ctx.type_path_key == "glossary/term:/term": + if ctx.item.uid not in self._document_terms: + self._document_terms[ctx.item.uid] = ctx.item + _GlossaryMapper(ctx.item, self._document_terms).substitute( + ctx.item["text"]) + # The value of this substitute is unused. + return "" + + +def _resolve_glossary_terms(document_terms: ItemMap) -> None: + for term in list(document_terms.values()): + _GlossaryMapper(term, document_terms).substitute(term["text"]) + + +def _generate_project_glossary(target: str, glossary: _Glossary) -> None: + content = _generate_glossary_content(glossary.uid_to_item) + content.write(target) + + +def _generate_document_glossary(config: dict, glossary: _Glossary) -> None: + document_terms = {} # type: ItemMap + for path in config["rest-source-paths"]: + _find_glossary_terms(path, document_terms, glossary) + _resolve_glossary_terms(document_terms) + content = _generate_glossary_content(document_terms) + content.write(config["target"]) + + +def generate(config: dict, item_cache: ItemCache) -> None: + """ + Generates glossaries of terms according to the configuration. + + :param config: A dictionary with configuration entries. + :param item_cache: The specification item cache containing the glossary + groups and terms. + """ + groups = {} # type: ItemMap + for item in item_cache.top_level.values(): + _gather_glossary_groups(item, groups) + + project_glossary = _Glossary() + for group in config["project-groups"]: + _gather_glossary_terms(groups[group], project_glossary) + + _generate_project_glossary(config["project-target"], project_glossary) + + for document_config in config["documents"]: + _generate_document_glossary(document_config, project_glossary) diff --git a/rtemsspec/interface.py b/rtemsspec/interface.py new file mode 100644 index 00000000..13cab4b6 --- /dev/null +++ b/rtemsspec/interface.py @@ -0,0 +1,585 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides functions for the generation of interfaces. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from contextlib import contextmanager +import os +from typing import Any, Callable, Dict, Iterator, List, Union + +from rtemsspec.content import CContent, CInclude, enabled_by_to_exp, \ + ExpressionMapper, get_value_double_colon, get_value_doxygen_function, \ + get_value_hash +from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper + +ItemMap = Dict[str, Item] +Lines = Union[str, List[str]] +GetLines = Callable[["Node", Item, Any], Lines] + + +def _get_ingroups(item: Item) -> ItemMap: + ingroups = {} # type: ItemMap + for link in item.links_to_parents(): + if link.role == "interface-ingroup": + ingroups[link.item.uid] = link.item + return ingroups + + +def _get_group_identifiers(groups: ItemMap) -> List[str]: + return [item["identifier"] for item in groups.values()] + + +def _forward_declaration(item: Item) -> str: + target = next(item.parents("interface-target")) + return f"{target['interface-type']} {target['name']}" + + +def _get_value_forward_declaration(ctx: ItemGetValueContext) -> Any: + return _forward_declaration(ctx.item) + + +class _InterfaceMapper(ItemMapper): + def __init__(self, node: "Node"): + super().__init__(node.item) + self._node = node + self._code_or_doc = "doc" + self.add_get_value("interface/forward-declaration:code:/name", + _get_value_forward_declaration) + self.add_get_value("interface/forward-declaration:doc:/name", + _get_value_forward_declaration) + self.add_get_value("interface/function:doc:/name", + get_value_doxygen_function) + self.add_get_value("interface/enumerator:doc:/name", + get_value_double_colon) + self.add_get_value("interface/typedef:doc:/name", + get_value_double_colon) + self.add_get_value("interface/define:doc:/name", get_value_hash) + self.add_get_value("interface/enum:doc:/name", get_value_hash) + self.add_get_value("interface/macro:doc:/name", get_value_hash) + self.add_get_value("interface/variable:doc:/name", get_value_hash) + + @contextmanager + def code(self) -> Iterator[None]: + """ Enables code mapping. """ + code_or_doc = self._code_or_doc + self._code_or_doc = "code" + yield + self._code_or_doc = code_or_doc + + def get_value(self, ctx: ItemGetValueContext) -> Any: + if self._code_or_doc == "code" and ctx.item["type"] == "interface": + node = self._node + header_file = node.header_file + if ctx.item["interface-type"] == "enumerator": + for link in ctx.item.links_to_children(): + if link.role == "interface-enumerator": + header_file.add_includes(link.item) + else: + header_file.add_includes(ctx.item) + header_file.add_potential_edge(node, ctx.item) + return super().get_value( + ItemGetValueContext(ctx.item, f"{self._code_or_doc}:{ctx.path}", + ctx.value, ctx.key, ctx.index)) + + def enabled_by_to_defined(self, enabled_by: str) -> str: + """ + Maps an item-level enabled-by attribute value to the corresponding + defined expression. + """ + return self._node.header_file.enabled_by_defined[enabled_by] + + +class _InterfaceExpressionMapper(ExpressionMapper): + def __init__(self, mapper: _InterfaceMapper): + super().__init__() + self._mapper = mapper + + def map_symbol(self, symbol: str) -> str: + with self._mapper.code(): + return self._mapper.substitute(symbol) + + +class _ItemLevelExpressionMapper(ExpressionMapper): + def __init__(self, mapper: _InterfaceMapper): + super().__init__() + self._mapper = mapper + + def map_symbol(self, symbol: str) -> str: + with self._mapper.code(): + return self._mapper.substitute( + self._mapper.enabled_by_to_defined(symbol)) + + +class _HeaderExpressionMapper(ExpressionMapper): + def __init__(self, item: Item, enabled_by_defined: Dict[str, str]): + super().__init__() + self._mapper = ItemMapper(item) + self._enabled_by_defined = enabled_by_defined + + def map_symbol(self, symbol: str) -> str: + return self._mapper.substitute(self._enabled_by_defined[symbol]) + + +def _add_definition(node: "Node", item: Item, prefix: str, + value: Dict[str, Any], get_lines: GetLines) -> CContent: + content = CContent() + default = value["default"] + variants = value["variants"] + if variants: + ifelse = "#if " + with node.mapper.prefix(os.path.join(prefix, "variants")): + for variant in variants: + enabled_by = enabled_by_to_exp( + variant["enabled-by"], + _InterfaceExpressionMapper(node.mapper)) + content.append(f"{ifelse}{enabled_by}") + with content.indent(): + content.append(get_lines(node, item, + variant["definition"])) + ifelse = "#elif " + if default is not None: + content.append("#else") + with node.mapper.prefix(os.path.join(prefix, "default")): + with content.indent(): + content.append(get_lines(node, item, default)) + content.append("#endif") + else: + with node.mapper.prefix(os.path.join(prefix, "default")): + content.append(get_lines(node, item, default)) + return content + + +class Node: + """ Nodes of a header file. """ + def __init__(self, header_file: "_HeaderFile", item: Item, + ingroups: ItemMap): + self.header_file = header_file + self.item = item + self.ingroups = ingroups + self.in_edges = {} # type: ItemMap + self.out_edges = {} # type: ItemMap + self.content = CContent() + self.mapper = _InterfaceMapper(self) + + def __lt__(self, other: "Node") -> bool: + return self.item.uid < other.item.uid + + @contextmanager + def _enum_struct_or_union(self) -> Iterator[None]: + self.content.add(self._get_description(self.item, self.ingroups)) + name = self.item["name"] + typename = self.item["interface-type"] + kind = self.item["definition-kind"] + if kind == f"{typename}-only": + self.content.append(f"{typename} {name} {{") + elif kind == "typedef-only": + self.content.append(f"typedef {typename} {{") + else: + self.content.append(f"typedef {typename} {name} {{") + self.content.push_indent() + yield + self.content.pop_indent() + if kind == f"{typename}-only": + self.content.append("};") + else: + self.content.append(f"}} {name};") + + def _generate(self) -> None: + _NODE_GENERATORS[self.item["interface-type"]](self) + + def generate(self) -> None: + """ Generates a node to generate the node content. """ + enabled_by = self.item["enabled-by"] + if not isinstance(enabled_by, bool) or not enabled_by: + mapper = _ItemLevelExpressionMapper(self.mapper) + self.content.add(f"#if {enabled_by_to_exp(enabled_by, mapper)}") + with self.content.indent(): + self._generate() + self.content.add("#endif") + else: + self._generate() + + def generate_compound(self) -> None: + """ Generates a compound (struct or union). """ + with self._enum_struct_or_union(): + for index, definition in enumerate(self.item["definition"]): + self.content.add( + _add_definition(self, self.item, f"definition[{index}]", + definition, Node._get_compound_definition)) + + def generate_enum(self) -> None: + """ Generates an enum. """ + with self._enum_struct_or_union(): + enumerators = [] # type: List[CContent] + for link in self.item.links_to_parents(): + if link.role != "interface-enumerator": + continue + enumerator = self._get_description(link.item, {}) + enumerator.append( + _add_definition(self, link.item, "definition", + link.item["definition"], + Node._get_enumerator_definition)) + enumerators.append(enumerator) + for enumerator in enumerators[0:-1]: + enumerator.lines[-1] += "," + enumerator.append("") + self.content.append(enumerator) + try: + self.content.append(enumerators[-1]) + except IndexError: + pass + + def generate_define(self) -> None: + """ Generates a define. """ + self._add_generic_definition(Node._get_define_definition) + + def generate_forward_declaration(self) -> None: + """ Generates a forward declaration. """ + self.content.append([ + "", "/* Forward declaration */", + _forward_declaration(self.item) + ";" + ]) + + def generate_function(self) -> None: + """ Generates a function. """ + self._add_generic_definition(Node._get_function_definition) + + def generate_group(self) -> None: + """ Generates a group. """ + self.header_file.add_ingroup(self.item) + for ingroup in self.ingroups.values(): + self.header_file.add_potential_edge(self, ingroup) + self.content.add_group(self.item["identifier"], self.item["name"], + _get_group_identifiers(self.ingroups), + self.item["brief"], self.item["description"]) + + def generate_macro(self) -> None: + """ Generates a macro. """ + self._add_generic_definition(Node._get_macro_definition) + + def generate_typedef(self) -> None: + """ Generates a typedef. """ + self._add_generic_definition(Node._get_typedef_definition) + + def generate_variable(self) -> None: + """ Generates a variable. """ + self._add_generic_definition(Node._get_variable_definition) + + def substitute_code(self, text: str) -> str: + """ + Performs a variable substitution on code using the item mapper of the + node. + """ + if text: + with self.mapper.code(): + return self.mapper.substitute(text.strip("\n")) + return text + + def substitute_text(self, text: str) -> str: + """ + Performs a variable substitution on a description using the item mapper + of the node. + """ + if text: + return self.mapper.substitute(text.strip("\n")) + return text + + def _get_compound_definition(self, item: Item, definition: Any) -> Lines: + content = CContent() + content.add_description_block( + self.substitute_text(definition["brief"]), + self.substitute_text(definition["description"])) + kind = definition["kind"] + if kind == "member": + member = self.substitute_code(definition["definition"]) + ";" + content.append(member.split("\n")) + else: + content.append(f"{kind} {{") + content.gap = False + with content.indent(): + for index, compound_member in enumerate( + definition["definition"]): + content.add( + _add_definition(self, item, f"definition[{index}]", + compound_member, + Node._get_compound_definition)) + name = definition["name"] + content.append(f"}} {name};") + return content.lines + + def _get_enumerator_definition(self, item: Item, definition: Any) -> Lines: + name = item["name"] + if definition: + return f"{name} = {self.substitute_code(definition)}" + return f"{name}" + + def _get_define_definition(self, item: Item, definition: Any) -> Lines: + name = item["name"] + value = self.substitute_code(definition) + if value: + return f"#define {name} {value}".split("\n") + return f"#define {name}" + + def _get_function_definition(self, item: Item, definition: Any) -> Lines: + content = CContent() + name = item["name"] + ret = self.substitute_code(definition["return"]) + params = [ + self.substitute_code(param) for param in definition["params"] + ] + body = definition["body"] + if body: + with content.function("static inline " + ret, name, params): + content.add(self.substitute_code(body)) + else: + content.declare_function(ret, name, params) + return content.lines + + def _get_macro_definition(self, item: Item, definition: Any) -> Lines: + name = item["name"] + params = [param["name"] for param in item["params"]] + if params: + param_line = " " + ", ".join(params) + " " + else: + param_line = "" + line = f"#define {name}({param_line})" + if len(line) > 79: + param_block = ", \\\n ".join(params) + line = f"#define {name}( \\\n {param_block} \\\n)" + if not definition: + return line + body_lines = self.substitute_code(definition).split("\n") + if len(body_lines) == 1 and len(line + body_lines[0]) <= 79: + body = " " + else: + body = " \\\n " + body += " \\\n ".join(body_lines) + return line + body + + def _get_typedef_definition(self, _item: Item, definition: Any) -> Lines: + return f"typedef {self.substitute_code(definition)};" + + def _get_variable_definition(self, _item: Item, definition: Any) -> Lines: + return f"extern {self.substitute_code(definition)};" + + def _get_description(self, item: Item, ingroups: ItemMap) -> CContent: + content = CContent() + with content.doxygen_block(): + content.add_ingroup(_get_group_identifiers(ingroups)) + content.add_brief_description(self.substitute_text(item["brief"])) + content.wrap(self.substitute_text(item["description"])) + content.wrap(self.substitute_text(item["notes"])) + if "params" in item: + content.add_param_description(item["params"], + self.substitute_text) + if "return" in item: + ret = item["return"] + for retval in ret["return-values"]: + content.wrap(self.substitute_text(retval["description"]), + initial_indent=self.substitute_text( + f"@retval {retval['value']} ")) + content.wrap(self.substitute_text(ret["return"]), + initial_indent="@return ") + return content + + def _add_generic_definition(self, get_lines: GetLines) -> None: + self.content.add(self._get_description(self.item, self.ingroups)) + self.content.append( + _add_definition(self, self.item, "definition", + self.item["definition"], get_lines)) + + +_NODE_GENERATORS = { + "enum": Node.generate_enum, + "define": Node.generate_define, + "forward-declaration": Node.generate_forward_declaration, + "function": Node.generate_function, + "group": Node.generate_group, + "macro": Node.generate_macro, + "struct": Node.generate_compound, + "typedef": Node.generate_typedef, + "union": Node.generate_compound, + "variable": Node.generate_variable, +} + + +class _HeaderFile: + """ A header file. """ + def __init__(self, item: Item, enabled_by_defined: Dict[str, str]): + self._item = item + self._content = CContent() + self._ingroups = {} # type: ItemMap + self._includes = [] # type: List[Item] + self._nodes = {} # type: Dict[str, Node] + self.enabled_by_defined = enabled_by_defined + + def add_includes(self, item: Item) -> None: + """ Adds the includes of the item to the header file includes. """ + for link in item.links_to_parents(): + if link.role == "interface-placement" and link.item[ + "interface-type"] == "header-file": + self._includes.append(link.item) + + def add_ingroup(self, item: Item) -> None: + """ Adds an ingroup to the header file. """ + self._ingroups[item.uid] = item + + def _add_child(self, item: Item) -> None: + ingroups = _get_ingroups(item) + if item["interface-type"] != "group": + self._ingroups.update(ingroups) + self._nodes[item.uid] = Node(self, item, ingroups) + self._content.register_license_and_copyrights_of_item(item) + + def add_potential_edge(self, node: Node, item: Item) -> None: + """ + Adds a potential edge from a node to another node identified by an + item. + """ + if item.uid in self._nodes and item.uid != node.item.uid: + node.out_edges[item.uid] = item + self._nodes[item.uid].in_edges[node.item.uid] = node.item + + def _resolve_ingroups(self, node: Node) -> None: + for ingroup in node.ingroups.values(): + self.add_potential_edge(node, ingroup) + + def generate_nodes(self) -> None: + """ Generates all nodes of this header file. """ + for link in self._item.links_to_children(): + if link.role == "interface-placement": + self._add_child(link.item) + for node in self._nodes.values(): + self._resolve_ingroups(node) + node.generate() + + def _get_nodes_in_dependency_order(self) -> List[Node]: + """ + Gets the nodes of this header file ordered according to node + dependencies and UIDs. + + Performs a topological sort using Kahn's algorithm. + """ + nodes_in_dependency_order = [] # type: List[Node] + + # Get incoming edge degrees for all nodes + in_degree = {} # type: Dict[str, int] + for node in self._nodes.values(): + in_degree[node.item.uid] = len(node.in_edges) + + # Create a queue with all nodes with no incoming edges sorted by UID + queue = [] # type: List[Node] + for node in self._nodes.values(): + if in_degree[node.item.uid] == 0: + queue.append(node) + queue.sort(reverse=True) + + # Topological sort + while queue: + node = queue.pop(0) + nodes_in_dependency_order.insert(0, node) + + # Sort by UID + for uid in sorted(node.out_edges): + in_degree[uid] -= 1 + if in_degree[uid] == 0: + queue.append(self._nodes[uid]) + + return nodes_in_dependency_order + + def finalize(self) -> None: + """ Finalizes the header file. """ + self._content.prepend_spdx_license_identifier() + with self._content.file_block(): + self._content.add_ingroup(_get_group_identifiers(self._ingroups)) + self._content.add_copyrights_and_licenses() + with self._content.header_guard(self._item["path"]): + exp_mapper = _HeaderExpressionMapper(self._item, + self.enabled_by_defined) + includes = [ + CInclude(item["path"], + enabled_by_to_exp(item["enabled-by"], exp_mapper)) + for item in self._includes if item != self._item + ] + includes.extend([ + CInclude(link.item["path"], + enabled_by_to_exp(link["enabled-by"], exp_mapper)) + for link in self._item.links_to_parents() + if link.role == "interface-include" + ]) + self._content.add_includes(includes) + with self._content.extern_c(): + for node in self._get_nodes_in_dependency_order(): + self._content.add(node.content) + + def write(self, domain_path: str) -> None: + """ Writes the header file. """ + self._content.write( + os.path.join(domain_path, self._item["prefix"], + self._item["path"])) + + +def _generate_header_file(item: Item, domains: Dict[str, str], + enabled_by_defined: Dict[str, str]) -> None: + domain = next(item.parents("interface-placement")) + assert domain["interface-type"] == "domain" + domain_path = domains.get(domain.uid, None) + if domain_path is None: + return + header_file = _HeaderFile(item, enabled_by_defined) + header_file.generate_nodes() + header_file.finalize() + header_file.write(domain_path) + + +def _visit_header_files(item: Item, domains: Dict[str, str], + enabled_by_defined: Dict[str, str]) -> None: + for child in item.children(): + _visit_header_files(child, domains, enabled_by_defined) + if item["type"] == "interface" and item["interface-type"] == "header-file": + _generate_header_file(item, domains, enabled_by_defined) + + +def _gather_enabled_by_defined(item_level_interfaces: List[str], + item_cache: ItemCache) -> Dict[str, str]: + enabled_by_defined = {} # type: Dict[str, str] + for uid in item_level_interfaces: + for link in item_cache[uid].links_to_children(): + if link.role == "interface-placement": + define = f"defined(${{{link.item.uid}:/name}})" + enabled_by_defined[link.item["name"]] = define + return enabled_by_defined + + +def generate(config: dict, item_cache: ItemCache) -> None: + """ + Generates header files according to the configuration. + + :param config: A dictionary with configuration entries. + :param item_cache: The specification item cache containing the interfaces. + """ + enabled_by_defined = _gather_enabled_by_defined( + config["item-level-interfaces"], item_cache) + for item in item_cache.top_level.values(): + _visit_header_files(item, config["domains"], enabled_by_defined) diff --git a/rtemsspec/interfacedoc.py b/rtemsspec/interfacedoc.py new file mode 100644 index 00000000..5843bb0f --- /dev/null +++ b/rtemsspec/interfacedoc.py @@ -0,0 +1,200 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" +This module provides functions for the generation of interface documentation. +""" + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +from typing import Any, Callable, Dict, List + +from rtemsspec.content import CContent, enabled_by_to_exp, ExpressionMapper +from rtemsspec.sphinxcontent import get_label, get_reference, SphinxContent, \ + SphinxMapper +from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper + +ItemMap = Dict[str, Item] +AddDefinition = Callable[[CContent, ItemMapper, Item, Dict[str, Any]], None] + +INTERFACE = "Interface" + + +def _forward_declaration(item: Item) -> str: + target = next(item.parents("interface-target")) + return f"{target['interface-type']} {target['name']}" + + +def _get_reference(name: str) -> str: + return get_reference(get_label(f"{INTERFACE}{name}"), f"{name}()") + + +def _get_value_forward_declaration(ctx: ItemGetValueContext) -> Any: + return _forward_declaration(ctx.item) + + +class _CodeMapper(ItemMapper): + def __init__(self, item: Item): + super().__init__(item) + self.add_get_value("interface/forward-declaration:/name", + _get_value_forward_declaration) + + +def _get_value_function(ctx: ItemGetValueContext) -> Any: + return _get_reference(ctx.value[ctx.key]) + + +class _Mapper(SphinxMapper): + def __init__(self, item: Item): + super().__init__(item) + self.add_get_value("interface/function:/name", _get_value_function) + + +def _generate_introduction(target: str, group: Item, + items: List[Item]) -> None: + content = SphinxContent() + content.register_license_and_copyrights_of_item(group) + group_name = group["name"] + with content.section("Introduction", get_label(group_name)): + content.append("") + content.gap = False + content.wrap(group["brief"]) + content.wrap(group["description"]) + content.paste(f"The directives provided by the {group_name} are:") + for item in items: + content.register_license_and_copyrights_of_item(item) + name = item["name"] + brief = item["brief"] + if brief: + brief = f" - {brief}" + else: + brief = "" + ref = _get_reference(name) + content.add_list_item(f"{ref}{brief}") + content.add_licence_and_copyrights() + content.write(target) + + +def _add_function_definition(content: CContent, mapper: ItemMapper, item: Item, + value: Dict[str, Any]) -> None: + name = item["name"] + ret = mapper.substitute(value["return"]) + params = [mapper.substitute(param) for param in value["params"]] + content.declare_function(ret, name, params) + + +def _add_definition(content: CContent, mapper: ItemMapper, item: Item, + prefix: str, value: Dict[str, Any], + add_definition: AddDefinition) -> None: + # pylint: disable=too-many-arguments + assert item["interface-type"] == "function" + default = value["default"] + variants = value["variants"] + if variants: + ifelse = "#if " + with mapper.prefix(os.path.join(prefix, "variants")): + for variant in variants: + enabled_by = enabled_by_to_exp(variant["enabled-by"], + ExpressionMapper()) + content.append(f"{ifelse}{enabled_by}") + with content.indent(): + add_definition(content, mapper, item, + variant["definition"]) + ifelse = "#elif " + if default is not None: + content.append("#else") + with mapper.prefix(os.path.join(prefix, "default")): + with content.indent(): + add_definition(content, mapper, item, default) + content.append("#endif") + else: + with mapper.prefix(os.path.join(prefix, "default")): + add_definition(content, mapper, item, default) + + +def _generate_directives(target: str, group: Item, items: List[Item]) -> None: + content = SphinxContent() + content.register_license_and_copyrights_of_item(group) + group_name = group["name"] + with content.section("Directives", get_label(group_name)): + for item in items: + content.register_license_and_copyrights_of_item(item) + name = item["name"] + code_mapper = _CodeMapper(item) + mapper = _Mapper(item) + with content.section(f"{name}()", "Interface"): + content.wrap(item["brief"]) + with content.definition_item("CALLING SEQUENCE:"): + with content.directive("code-block", "c"): + code = CContent() + _add_definition(code, code_mapper, item, "definition", + item["definition"], + _add_function_definition) + content.add(code) + if item["params"]: + with content.definition_item("DIRECTIVE PARAMETERS:"): + for param in item["params"]: + content.add_definition_item( + mapper.substitute(param["name"]), + mapper.substitute( + f"This parameter {param['description']}"), + wrap=True) + ret = item["return"] + if ret["return"] or ret["return-values"]: + with content.definition_item("DIRECTIVE RETURN VALUES:"): + if ret["return-values"]: + for retval in ret["return-values"]: + content.add_definition_item( + mapper.substitute(str(retval["value"])), + mapper.substitute(retval["description"]), + wrap=True) + content.wrap(mapper.substitute(ret["return"])) + content.add_definition_item("DESCRIPTION:", + mapper.substitute( + item["description"]), + wrap=True) + content.add_definition_item("NOTES:", + mapper.substitute(item["notes"]), + wrap=True) + content.add_licence_and_copyrights() + content.write(target) + + +def generate(config: list, item_cache: ItemCache) -> None: + """ + Generates interface documentation according to the configuration. + + :param config: A dictionary with configuration entries. + :param item_cache: The specification item cache containing the interfaces. + """ + for doc_config in config: + items = [] # type: List[Item] + group = item_cache[doc_config["group"]] + assert group["type"] == "interface" + assert group["interface-type"] == "group" + for child in group.children("interface-ingroup"): + if child["interface-type"] in ["function"]: + items.append(child) + items.sort(key=lambda x: x["name"]) + _generate_introduction(doc_config["introduction-target"], group, items) + _generate_directives(doc_config["directives-target"], group, items) diff --git a/rtemsspec/items.py b/rtemsspec/items.py new file mode 100644 index 00000000..06c13525 --- /dev/null +++ b/rtemsspec/items.py @@ -0,0 +1,511 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides specification items and an item cache. """ + +# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from contextlib import contextmanager +import os +import pickle +import string +import stat +from typing import Any, Callable, Dict, Iterator, List, NamedTuple, Mapping, \ + Optional, Tuple +import yaml + + +class ItemGetValueContext(NamedTuple): + """ Context used to get an item value. """ + item: "Item" + path: str + value: Any + key: str + index: Any # should be int, but this triggers a mypy error + + @property + def type_path_key(self) -> str: + """ Returns the item type followed the path to the key. """ + return f"{self.item.type}:{os.path.join(self.path, self.key)}" + + +ItemMap = Dict[str, "Item"] +ItemGetValue = Callable[[ItemGetValueContext], Any] + + +def _is_enabled_op_and(enabled: List[str], enabled_by: Any) -> bool: + for next_enabled_by in enabled_by: + if not is_enabled(enabled, next_enabled_by): + return False + return True + + +def _is_enabled_op_not(enabled: List[str], enabled_by: Any) -> bool: + return not is_enabled(enabled, enabled_by) + + +def _is_enabled_op_or(enabled: List[str], enabled_by: Any) -> bool: + for next_enabled_by in enabled_by: + if is_enabled(enabled, next_enabled_by): + return True + return False + + +_IS_ENABLED_OP = { + "and": _is_enabled_op_and, + "not": _is_enabled_op_not, + "or": _is_enabled_op_or +} + + +def is_enabled(enabled: List[str], enabled_by: Any) -> bool: + """ Verifies if the given parameter is enabled by specific enables. """ + if isinstance(enabled_by, bool): + return enabled_by + if isinstance(enabled_by, list): + return _is_enabled_op_or(enabled, enabled_by) + if isinstance(enabled_by, dict): + key, value = next(iter(enabled_by.items())) + return _IS_ENABLED_OP[key](enabled, value) + return enabled_by in enabled + + +def _str_representer(dumper, data): + return dumper.represent_scalar("tag:yaml.org,2002:str", + data, + style="|" if "\n" in data else "") + + +yaml.add_representer(str, _str_representer) + + +class Link: + """ A link to an item. """ + def __init__(self, item: "Item", data: Any): + self._item = item + self._data = data + + @classmethod + def create(cls, link: "Link", item: "Item") -> "Link": + """ Creates a link using an existing link with a new target item. """ + return cls(item, link._data) # pylint: disable=protected-access + + def __getitem__(self, name: str) -> Any: + return self._data[name] + + @property + def item(self) -> "Item": + """ The item referenced by this link. """ + return self._item + + @property + def role(self) -> str: + """ The link role. """ + return self._data["role"] + + +def _get_value(ctx: ItemGetValueContext) -> Any: + value = ctx.value[ctx.key] + if ctx.index >= 0: + return value[ctx.index] + return value + + +class Item: + """ Objects of this class represent a specification item. """ + def __init__(self, item_cache: "ItemCache", uid: str, data: Any): + self._item_cache = item_cache + self._uid = uid + self._data = data + self._links_to_parents = [] # type: List[Link] + self._links_to_children = [] # type: List[Link] + + def __contains__(self, key: str) -> bool: + return key in self._data + + def __getitem__(self, key: str) -> Any: + return self._data[key] + + def __setitem__(self, key: str, value: Any) -> None: + self._data[key] = value + + def get(self, key: str, default: Any) -> Any: + """ + Gets the attribute value if the attribute exists, otherwise the + specified default value is returned. + """ + return self._data.get(key, default) + + def get_by_key_path(self, + key_path: str, + prefix: str = "", + get_value: ItemGetValue = _get_value) -> Any: + """ Gets the attribute value corresponding to the key path. """ + if not os.path.isabs(key_path): + key_path = os.path.join(prefix, key_path) + key_path = os.path.normpath(key_path) + path = "/" + value = self._data + for key in key_path.strip("/").split("/"): + parts = key.split("[") + try: + index = int(parts[1].split("]")[0]) + except IndexError: + index = -1 + ctx = ItemGetValueContext(self, path, value, parts[0], index) + try: + value = get_value(ctx) + except KeyError: + value = _get_value(ctx) + path = os.path.join(path, key) + return value + + @property + def uid(self) -> str: + """ Returns the UID of the item. """ + return self._uid + + def to_abs_uid(self, abs_or_rel_uid: str) -> str: + """ + Returns the absolute UID of an absolute UID or an UID relative to this + item. + """ + if abs_or_rel_uid == ".": + return self._uid + if os.path.isabs(abs_or_rel_uid): + return abs_or_rel_uid + return os.path.normpath( + os.path.join(os.path.dirname(self.uid), abs_or_rel_uid)) + + def map(self, abs_or_rel_uid: str) -> "Item": + """ + Maps the absolute UID or the UID relative to this item to the + corresponding item. + """ + return self._item_cache[self.to_abs_uid(abs_or_rel_uid)] + + def links_to_parents(self) -> Iterator[Link]: + """ Yields the links to the parents of this items. """ + yield from self._links_to_parents + + def parents(self, role: Optional[str] = None) -> Iterator["Item"]: + """ Yields the parents of this items. """ + if role is None: + for link in self._links_to_parents: + yield link.item + else: + for link in self._links_to_parents: + if link.role == role: + yield link.item + + def links_to_children(self) -> Iterator[Link]: + """ Yields the links to the children of this items. """ + yield from self._links_to_children + + def children(self, role: Optional[str] = None) -> Iterator["Item"]: + """ Yields the children of this items. """ + if role is None: + for link in self._links_to_children: + yield link.item + else: + for link in self._links_to_children: + if link.role == role: + yield link.item + + def init_parents(self, item_cache: "ItemCache"): + """ Initializes the list of links to parents of this items. """ + for data in self._data["links"]: + link = Link(item_cache[self.to_abs_uid(data["uid"])], data) + self._links_to_parents.append(link) + + def add_link_to_child(self, link: Link): + """ Adds a link to a child item of this items. """ + self._links_to_children.append(link) + + def is_enabled(self, enabled: List[str]): + """ Returns true if the item is enabled by the specified enables. """ + return is_enabled(enabled, self["enabled-by"]) + + @property + def data(self) -> Any: + """ The item data. """ + return self._data + + @property + def file(self) -> str: + """ Returns the file of the item. """ + return self._data["_file"] + + @file.setter + def file(self, value: str): + """ Sets the file of the item. """ + self._data["_file"] = value + + @property + def type(self) -> str: + """ Returns the type of the item. """ + return self._data["_type"] + + def save(self): + """ Saves the item to the corresponding file. """ + with open(self.file, "w") as dst: + data = {} + for key, value in self._data.items(): + if not key.startswith("_"): + data[key] = value + dst.write( + yaml.dump(data, default_flow_style=False, allow_unicode=True)) + + def load(self): + """ Loads the item from the corresponding file. """ + filename = self.file + with open(filename, "r") as src: + self._data = yaml.safe_load(src.read()) + self._data["_file"] = filename + + +class ItemTemplate(string.Template): + """ String template for item mapper identifiers. """ + idpattern = "[a-zA-Z0-9._/-]+(:[][a-zA-Z0-9._/-]+)?(|[a-zA-Z0-9_]+)*" + + +class ItemMapper(Mapping[str, object]): + """ Maps identifiers to items and attribute values. """ + def __init__(self, item: Item): + self._item = item + self._prefix = [""] + self._get_value = {} # type: Dict[str, ItemGetValue] + + @property + def item(self) -> Item: + """ The item of the mapper. """ + return self._item + + @item.setter + def item(self, item: Item) -> None: + """ Sets the item of the mapper. """ + self._item = item + + def add_get_value(self, type_path_key: str, + get_value: ItemGetValue) -> None: + """ + Adds a get value for the specified type and key path. + """ + self._get_value[type_path_key] = get_value + + def push_prefix(self, prefix: str) -> None: + """ Pushes a key path prefix. """ + self._prefix.append(prefix) + + def pop_prefix(self) -> None: + """ Pops a key path prefix. """ + self._prefix.pop() + + @contextmanager + def prefix(self, prefix: str) -> Iterator[None]: + """ Opens a key path prefix context. """ + self.push_prefix(prefix) + yield + self.pop_prefix() + + def map(self, identifier: str) -> Tuple[Item, Any]: + """ + Maps an identifier to the corresponding item and attribute value. + """ + uid_key_path, *pipes = identifier.split("|") + colon = uid_key_path.find(":") + if colon >= 0: + uid, key_path = uid_key_path[:colon], uid_key_path[colon + 1:] + else: + uid, key_path = uid_key_path, "/_uid" + if uid == ".": + item = self._item + prefix = "/".join(self._prefix) + else: + item = self._item.map(uid) + prefix = "" + value = item.get_by_key_path(key_path, prefix, self.get_value) + for func in pipes: + value = getattr(self, func)(value) + return item, value + + def __getitem__(self, identifier): + return self.map(identifier)[1] + + def __iter__(self): + raise StopIteration + + def __len__(self): + raise AttributeError + + def substitute(self, text: Optional[str]) -> str: + """ Performs a variable substitution using the item mapper. """ + if not text: + return "" + return ItemTemplate(text).substitute(self) + + def substitute_with_prefix(self, text: Optional[str], prefix: str) -> str: + """ + Performs a variable substitution using the item mapper with a prefix. + """ + if not text: + return "" + with self.prefix(prefix): + return ItemTemplate(text).substitute(self) + + def get_value(self, ctx: ItemGetValueContext) -> Any: + """ Gets a value by key and optional index. """ + return self._get_value[ctx.type_path_key](ctx) + + +class _SpecType(NamedTuple): + key: str + refinements: Dict[str, Any] + + +def _gather_spec_refinements(item: Item) -> Optional[_SpecType]: + new_type = None # type: Optional[_SpecType] + for link in item.links_to_children(): + if link.role == "spec-refinement": + key = link["spec-key"] + if new_type is None: + new_type = _SpecType(key, {}) + assert new_type.key == key + new_type.refinements[ + link["spec-value"]] = _gather_spec_refinements(link.item) + return new_type + + +class ItemCache: + """ This class provides a cache of specification items. """ + def __init__(self, config: Any): + self._items = {} # type: ItemMap + self._top_level = {} # type: ItemMap + self._load_items(config) + self._set_types(config) + + def __getitem__(self, uid: str) -> Item: + return self._items[uid] + + @property + def all(self) -> ItemMap: + """ Returns the map of all specification items. """ + return self._items + + @property + def top_level(self) -> ItemMap: + """ Returns the map of top-level specification items. """ + return self._top_level + + def _load_items_in_dir(self, base: str, path: str, cache_file: str, + update_cache: bool) -> None: + data_by_uid = {} # type: Dict[str, Any] + if update_cache: + for name in os.listdir(path): + path2 = os.path.join(path, name) + if name.endswith(".yml") and not name.startswith("."): + uid = "/" + os.path.relpath(path2, base).replace( + ".yml", "") + with open(path2, "r") as yaml_src: + data = yaml.safe_load(yaml_src.read()) + data["_file"] = os.path.abspath(path2) + data["_uid"] = uid + data_by_uid[uid] = data + os.makedirs(os.path.dirname(cache_file), exist_ok=True) + with open(cache_file, "wb") as out: + pickle.dump(data_by_uid, out) + else: + with open(cache_file, "rb") as pickle_src: + data_by_uid = pickle.load(pickle_src) + for uid, data in iter(data_by_uid.items()): + item = Item(self, uid, data) + self._items[uid] = item + if not item["links"]: + self._top_level[uid] = item + + def _load_items_recursive(self, base: str, path: str, + cache_dir: str) -> None: + mid = os.path.abspath(path) + mid = mid.replace(os.path.commonprefix([cache_dir, mid]), "") + cache_file = os.path.join(cache_dir, mid, "spec.pickle") + try: + mtime = os.path.getmtime(cache_file) + update_cache = False + except FileNotFoundError: + update_cache = True + for name in os.listdir(path): + path2 = os.path.join(path, name) + if name.endswith(".yml") and not name.startswith("."): + update_cache = update_cache or mtime <= os.path.getmtime(path2) + else: + if stat.S_ISDIR(os.lstat(path2).st_mode): + self._load_items_recursive(base, path2, cache_dir) + self._load_items_in_dir(base, path, cache_file, update_cache) + + def _init_parents(self) -> None: + for item in self._items.values(): + item.init_parents(self) + + def _init_children(self) -> None: + for uid in sorted(self._items): + item = self._items[uid] + for link in item.links_to_parents(): + link.item.add_link_to_child(Link.create(link, item)) + + def _load_items(self, config: Any) -> None: + cache_dir = os.path.abspath(config["cache-directory"]) + for path in config["paths"]: + self._load_items_recursive(path, path, cache_dir) + self._init_parents() + self._init_children() + + def _set_types(self, config: Any) -> None: + spec_root = config["spec-type-root-uid"] + if spec_root: + root_type = _gather_spec_refinements(self[spec_root]) + else: + root_type = None + for item in self._items.values(): + spec_type = root_type + value = item.data + path = [] # type: List[str] + while spec_type is not None: + type_name = value[spec_type.key] + path.append(type_name) + spec_type = spec_type.refinements[type_name] + item["_type"] = "/".join(path) + + +class EmptyItemCache(ItemCache): + """ This class provides a empty cache of specification items. """ + def __init__(self): + super().__init__({ + "cache-directory": ".", + "paths": [], + "spec-type-root-uid": None + }) + + +class EmptyItem(Item): + """ Objects of this class represent empty items. """ + def __init__(self): + super().__init__(EmptyItemCache(), "", {}) diff --git a/rtemsspec/specdoc.py b/rtemsspec/specdoc.py new file mode 100644 index 00000000..40e4a47b --- /dev/null +++ b/rtemsspec/specdoc.py @@ -0,0 +1,572 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides functions to document specification items. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from typing import Any, Dict, Iterator, List, Optional, Set, Tuple + +from rtemsspec.sphinxcontent import get_reference, get_label, \ + SphinxContent, SphinxMapper +from rtemsspec.items import Item, ItemCache, ItemGetValueContext +from rtemsspec.specverify import NAME + +_DocumenterMap = Dict[str, "_Documenter"] + +_PRIMITIVE_TYPES = { + "bool": "{} {} be a boolean.", + "float": "{} {} be a floating-point number.", + "int": "{} {} be an integer number.", + "list-str": "{} {} be a list of strings.", + "none": "The attribute shall have no value.", + "optional-str": "{} {} be an optional string.", + "str": "{} {} be a string.", +} + +_MANDATORY_ATTRIBUTES = { + "all": + "All explicit attributes shall be specified.", + "at-least-one": + "At least one of the explicit attributes shall be specified.", + "at-most-one": + "At most one of the explicit attributes shall be specified.", + "exactly-one": + "Exactly one of the explicit attributes shall be specified.", + "none": + "None of the explicit attributes is mandatory, " + "they are all are optional.", +} + +_SPEC_TYPE_PREFIX = "SpecType" + + +def _a_or_an(value: str) -> str: + if value[0].lower() in ["a", "e", "i", "o", "u"]: + return "an" + return "a" + + +def _get_ref_specification_type(ctx: ItemGetValueContext) -> Any: + return get_reference(_SPEC_TYPE_PREFIX + get_label(ctx.value[ctx.key])) + + +class _AssertContext: + """ This class provides a context to document assert expressions. """ + def __init__(self, content: SphinxContent, ops: Dict[str, Any]): + self.content = content + self.ops = ops + self._comma = "" + + def comma(self): + """ Adds a comma to the content if necessary. """ + if not self.content.lines[-1].endswith(","): + self.content.lines[-1] += self._comma + self._comma = "," + + def paste(self, text: str): + """ Pastes a text to the content. """ + self.content.paste(text) + + +def _negate(negate: bool) -> str: + if negate: + return "not " + return "" + + +def _value(value: Any) -> str: + if isinstance(value, str): + return f"\"``{value}``\"" + if isinstance(value, bool): + if value: + return "true" + return "false" + return str(value) + + +def _list(ctx: _AssertContext, assert_info: List[str]) -> None: + ctx.content.add_list([f"{_value(value)}," for value in assert_info[:-2]]) + try: + ctx.content.add_list_item(f"{_value(assert_info[-2])}, and") + except IndexError: + pass + try: + ctx.content.add_list_item(f"{_value(assert_info[-1])}") + except IndexError: + pass + + +def _document_op_and_or(ctx: _AssertContext, negate: bool, assert_info: Any, + and_or: str) -> None: + if len(assert_info) == 1: + _document_assert(ctx, negate, assert_info[0]) + else: + if negate or ctx.content.lines[-1].endswith("* "): + ctx.paste(f"shall {_negate(negate)}meet") + intro = "" + for element in assert_info: + ctx.comma() + with ctx.content.list_item(intro): + _document_assert(ctx, False, element) + intro = and_or + + +def _document_op_and(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + _document_op_and_or(ctx, negate, assert_info, "and, ") + + +def _document_op_not(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + _document_assert(ctx, not negate, assert_info) + + +def _document_op_or(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + _document_op_and_or(ctx, negate, assert_info, "or, ") + + +def _document_op_eq(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + if negate: + _document_op_ne(ctx, False, assert_info) + else: + ctx.paste(f"shall be equal to {_value(assert_info)}") + + +def _document_op_ne(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + if negate: + _document_op_eq(ctx, False, assert_info) + else: + ctx.paste(f"shall be not equal to {_value(assert_info)}") + + +def _document_op_le(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + if negate: + _document_op_gt(ctx, False, assert_info) + else: + ctx.paste(f"shall be less than or equal to {_value(assert_info)}") + + +def _document_op_lt(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + if negate: + _document_op_ge(ctx, False, assert_info) + else: + ctx.paste(f"shall be less than {_value(assert_info)}") + + +def _document_op_ge(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + if negate: + _document_op_lt(ctx, False, assert_info) + else: + ctx.paste(f"shall be greater than or equal to {_value(assert_info)}") + + +def _document_op_gt(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + if negate: + _document_op_le(ctx, False, assert_info) + else: + ctx.paste(f"shall be greater than {_value(assert_info)}") + + +def _document_op_uid(ctx: _AssertContext, negate: bool, + _assert_info: Any) -> None: + if negate: + ctx.paste("shall be an invalid item UID") + else: + ctx.paste("shall be a valid item UID") + + +def _document_op_re(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + ctx.paste(f"shall {_negate(negate)}match with " + f"the regular expression \"``{assert_info}\"``") + + +def _document_op_in(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + ctx.paste(f"shall {_negate(negate)}be an element of") + _list(ctx, assert_info) + + +def _document_op_contains(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + ctx.paste(f"shall {_negate(negate)}contain an element of") + _list(ctx, assert_info) + + +def _document_assert(ctx: _AssertContext, negate: bool, + assert_info: Any) -> None: + if isinstance(assert_info, bool): + if negate: + assert_info = not assert_info + ctx.paste(f"shall be {_value(assert_info)}") + elif isinstance(assert_info, list): + _document_op_or(ctx, negate, assert_info) + else: + key = next(iter(assert_info)) + ctx.ops[key](ctx, negate, assert_info[key]) + + +_DOCUMENT_OPS = { + "and": _document_op_and, + "contains": _document_op_contains, + "eq": _document_op_eq, + "ge": _document_op_ge, + "gt": _document_op_gt, + "in": _document_op_in, + "le": _document_op_le, + "lt": _document_op_lt, + "ne": _document_op_ne, + "not": _document_op_not, + "or": _document_op_or, + "re": _document_op_re, + "uid": _document_op_uid, +} + + +def _maybe_document_assert(content: SphinxContent, type_info: Any) -> None: + if "assert" in type_info: + content.paste("The value ") + _document_assert(_AssertContext(content, _DOCUMENT_OPS), False, + type_info["assert"]) + content.lines[-1] += "." + + +class _Documenter: + # pylint: disable=too-many-instance-attributes + def __init__(self, item: Item, documenter_map: _DocumenterMap): + self._name = item["spec-type"] + self.section = item["spec-name"] + self._description = item["spec-description"] + self._info_map = item["spec-info"] + self._item = item + self._documenter_map = documenter_map + self.used_by = set() # type: Set[str] + self._mapper = SphinxMapper(item) + self._mapper.add_get_value("spec:/spec-name", + _get_ref_specification_type) + assert self._name not in documenter_map + documenter_map[self._name] = self + + def _substitute(self, text: str) -> str: + if text: + return self._mapper.substitute(text) + return text + + def get_section_reference(self) -> str: + """ Returns the section reference. """ + return get_reference(_SPEC_TYPE_PREFIX + get_label(self.section)) + + def get_a_section_reference(self) -> str: + """ Returns a section reference. """ + return f"{_a_or_an(self.section)} {self.get_section_reference()}" + + def get_list_element_type(self) -> str: + """ Returns the list element type if this is a list only type. """ + if len(self._info_map) == 1 and "list" in self._info_map: + return self._info_map["list"]["spec-type"] + return "" + + def get_list_phrase(self, value: str, shall: str, type_name: str) -> str: + """ Returns a list phrase. """ + if type_name in _PRIMITIVE_TYPES: + type_phrase = _PRIMITIVE_TYPES[type_name].format( + "Each list element", "shall") + else: + documenter = self._documenter_map[type_name] + ref = documenter.get_a_section_reference() + type_phrase = f"Each list element shall be {ref}." + return f"{value} {shall} be a list. {type_phrase}" + + def get_value_type_phrase(self, value: str, shall: str, + type_name: str) -> str: + """ Returns a value type phrase. """ + if type_name in _PRIMITIVE_TYPES: + return _PRIMITIVE_TYPES[type_name].format(value, shall) + documenter = self._documenter_map[type_name] + element_type_name = documenter.get_list_element_type() + if element_type_name: + return self.get_list_phrase(value, shall, element_type_name) + return (f"{value} {shall} be " + f"{documenter.get_a_section_reference()}.") + + def refinements(self) -> Iterator["_Documenter"]: + """ Yields the refinements of this type. """ + refinements = set(self._documenter_map[link.item["spec-type"]] + for link in self._item.links_to_children() + if link.role == "spec-refinement") + yield from sorted(refinements, key=lambda x: x.section) + + def refines(self) -> Iterator[Tuple["_Documenter", str, str]]: + """ Yields the types refined by type. """ + refines = [(self._documenter_map[link.item["spec-type"]], + link["spec-key"], link["spec-value"]) + for link in self._item.links_to_parents() + if link.role == "spec-refinement"] + yield from sorted(refines, key=lambda x: x[0].section) + + def hierarchy(self, content: SphinxContent) -> None: + """ Documents the item type hierarchy. """ + with content.list_item(self.get_section_reference()): + for refinement in self.refinements(): + refinement.hierarchy(content) + + def _document_attributes(self, content: SphinxContent, + attributes: Any) -> None: + for key in sorted(attributes): + info = attributes[key] + content.add(key) + with content.indent(): + content.wrap( + self.get_value_type_phrase("The attribute value", "shall", + info["spec-type"])) + content.paste(self._substitute(info["description"])) + + def document_dict(self, content: SphinxContent, _variant: str, shall: str, + info: Any) -> None: + """ Documents an attribute set. """ + if shall == "may": + content.paste("The value may be a set of attributes.") + content.paste(self._substitute(info["description"])) + has_explicit_attributes = len(info["attributes"]) > 0 + if has_explicit_attributes: + mandatory_attributes = info["mandatory-attributes"] + if isinstance(mandatory_attributes, str): + content.paste(_MANDATORY_ATTRIBUTES[mandatory_attributes]) + else: + assert isinstance(mandatory_attributes, list) + mandatory_attribute_count = len(mandatory_attributes) + if mandatory_attribute_count == 1: + content.paste(f"Only the ``{mandatory_attributes[0]}`` " + "attribute is mandatory.") + elif mandatory_attribute_count > 1: + content.paste("The following explicit " + "attributes are mandatory:") + for attribute in sorted(mandatory_attributes): + content.add_list_item(f"``{attribute}``") + content.add_blank_line() + else: + content.add_blank_line() + content.paste("The explicit attributes for this type are:") + self._document_attributes(content, info["attributes"]) + if "generic-attributes" in info: + if has_explicit_attributes: + content.wrap("In addition to the explicit attributes, " + "generic attributes may be specified.") + else: + content.paste("Generic attributes may be specified.") + content.paste( + self.get_value_type_phrase( + "Each generic attribute key", "shall", + info["generic-attributes"]["key-spec-type"])) + content.paste( + self.get_value_type_phrase( + "Each generic attribute value", "shall", + info["generic-attributes"]["value-spec-type"])) + content.paste( + self._substitute(info["generic-attributes"]["description"])) + + def document_value(self, content: SphinxContent, variant: str, shall: str, + info: Any) -> None: + """ Documents a value. """ + content.paste(self.get_value_type_phrase("The value", shall, variant)) + content.paste(self._substitute(info["description"])) + _maybe_document_assert(content, info) + + def document_list(self, content: SphinxContent, _variant: str, shall: str, + info: Any) -> None: + """ Documents a list value. """ + content.paste( + self.get_list_phrase("The value", shall, info["spec-type"])) + content.paste(self._substitute(info["description"])) + + def document_none(self, content: SphinxContent, _variant: str, shall: str, + _info: Any) -> None: + """ Documents a none value. """ + # pylint: disable=no-self-use + content.paste(f"There {shall} by be no value (null).") + + def _add_description(self, content: SphinxContent) -> None: + refines = [ + f"{documenter.get_section_reference()} though the " + f"``{key}`` attribute if the value is ``{value}``" + for documenter, key, value in self.refines() + ] + if len(refines) == 1: + content.wrap(f"This type refines the {refines[0]}.") + content.paste(self._description) + else: + content.add_list(refines, + "This type refines the following types:", + add_blank_line=True) + content.wrap(self._description) + + def document(self, + content: SphinxContent, + names: Optional[Set[str]] = None) -> None: + """ Document this type. """ + if self.get_list_element_type(): + return + content.register_license_and_copyrights_of_item(self._item) + with content.section(self.section, _SPEC_TYPE_PREFIX): + last = content.lines[-1] + self._add_description(content) + if len(self._info_map) == 1: + if last == content.lines[-1]: + content.add_blank_line() + key, info = next(iter(self._info_map.items())) + _DOCUMENT[key](self, content, key, "shall", info) + else: + content.add("A value of this type shall be of one of " + "the following variants:") + for key in sorted(self._info_map): + with content.list_item(""): + _DOCUMENT[key](self, content, key, "may", + self._info_map[key]) + content.add_list([ + refinement.get_section_reference() + for refinement in self.refinements() + ], "This type is refined by the following types:") + content.add_list(sorted(self.used_by), + "This type is used by the following types:") + example = self._item["spec-example"] + if example: + content.add("Please have a look at the following example:") + with content.directive("code-block", "yaml"): + content.add(example) + if names: + names.remove(self._name) + for refinement in self.refinements(): + refinement.document(content, names) + + def _add_used_by(self, type_name: str) -> None: + if type_name not in _PRIMITIVE_TYPES: + documenter = self._documenter_map[type_name] + element_type_name = documenter.get_list_element_type() + if element_type_name: + type_name = element_type_name + if type_name not in _PRIMITIVE_TYPES: + documenter = self._documenter_map[type_name] + documenter.used_by.add(self.get_section_reference()) + + def resolve_used_by(self) -> None: + """ Resolves type uses in attribute sets. """ + info = self._info_map.get("dict", None) + if info is not None: + for attribute in info["attributes"].values(): + self._add_used_by(attribute["spec-type"]) + if "generic-attributes" in info: + self._add_used_by(info["generic-attributes"]["key-spec-type"]) + self._add_used_by( + info["generic-attributes"]["value-spec-type"]) + + +_DOCUMENT = { + "bool": _Documenter.document_value, + "dict": _Documenter.document_dict, + "float": _Documenter.document_value, + "int": _Documenter.document_value, + "list": _Documenter.document_list, + "none": _Documenter.document_none, + "str": _Documenter.document_value, +} + + +def _gather_item_documenters(item: Item, + documenter_map: _DocumenterMap) -> None: + for link in item.links_to_children(): + if link.role == "spec-member": + _Documenter(link.item, documenter_map) + + +def _create_str_documenter(item_cache: ItemCache, name: str, description: str, + documenter_map: _DocumenterMap) -> None: + type_name = name.lower() + _Documenter( + Item( + item_cache, f"/spec/{type_name}", { + "SPDX-License-Identifier": + "CC-BY-SA-4.0 OR BSD-2-Clause", + "copyrights": [ + "Copyright (C) 2020 embedded brains GmbH " + "(http://www.embedded-brains.de)" + ], + "spec-description": + None, + "spec-example": + None, + "spec-info": { + "str": { + "description": description + } + }, + "spec-name": + name, + "spec-type": + type_name, + }), documenter_map) + + +def document(config: dict, item_cache: ItemCache) -> None: + """ + Documents specification items according to the configuration. + + :param config: A dictionary with configuration entries. + :param item_cache: The specification item cache. + """ + documenter_map = {} # type: _DocumenterMap + root_item = item_cache[config["root-type"]] + _create_str_documenter( + item_cache, "Name", "A string is a valid name if it matches with the " + f"``{NAME.pattern.replace('$', '$$')}`` regular expression.", + documenter_map) + _create_str_documenter( + item_cache, "UID", + "The string shall be a valid absolute or relative item UID.", + documenter_map) + root_documenter = _Documenter(root_item, documenter_map) + _gather_item_documenters(root_item, documenter_map) + content = SphinxContent() + for documenter in documenter_map.values(): + documenter.resolve_used_by() + documenter_names = set(documenter_map) + content.section_label_prefix = "ReqEng" + with content.section("Specification Items"): + with content.section("Specification Item Hierarchy"): + content.add( + "The specification item types have the following hierarchy:") + root_documenter.hierarchy(content) + with content.section("Specification Item Types"): + root_documenter.document(content, documenter_names) + with content.section("Specification Attribute Sets and Value Types"): + documenters = [documenter_map[name] for name in documenter_names] + for documenter in sorted(documenters, key=lambda x: x.section): + documenter.document(content) + content.add_licence_and_copyrights() + content.write(config["doc-target"]) diff --git a/rtemsspec/specverify.py b/rtemsspec/specverify.py new file mode 100644 index 00000000..3e6dd15e --- /dev/null +++ b/rtemsspec/specverify.py @@ -0,0 +1,486 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides functions for specification item verification. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import logging +import re +from typing import Any, Dict, List, NamedTuple, Set + +from rtemsspec.items import Item, ItemCache + +_VerifierMap = Dict[str, "_Verifier"] + + +def _type_name(value: Any): + type_name = type(value).__name__ + if type_name == "NoneType": + return "none" + return type_name + + +class _Path(NamedTuple): + item: Item + path: str + + +class _AssertContext(NamedTuple): + path: _Path + value: Any + type_info: Dict[str, Any] + ops: Dict[str, Any] + + +def _assert_op_and(ctx: _AssertContext, assert_info: Any) -> bool: + for element in assert_info: + if not _assert(ctx, element): + return False + return True + + +def _assert_op_not(ctx: _AssertContext, assert_info: Any) -> bool: + return not _assert(ctx, assert_info) + + +def _assert_op_or(ctx: _AssertContext, assert_info: Any) -> bool: + for element in assert_info: + if _assert(ctx, element): + return True + return False + + +def _assert_op_eq(ctx: _AssertContext, assert_info: Any) -> bool: + return ctx.value == assert_info + + +def _assert_op_ne(ctx: _AssertContext, assert_info: Any) -> bool: + return ctx.value != assert_info + + +def _assert_op_le(ctx: _AssertContext, assert_info: Any) -> bool: + return ctx.value <= assert_info + + +def _assert_op_lt(ctx: _AssertContext, assert_info: Any) -> bool: + return ctx.value < assert_info + + +def _assert_op_ge(ctx: _AssertContext, assert_info: Any) -> bool: + return ctx.value >= assert_info + + +def _assert_op_gt(ctx: _AssertContext, assert_info: Any) -> bool: + return ctx.value > assert_info + + +def _assert_op_uid(ctx: _AssertContext, _assert_info: Any) -> bool: + try: + ctx.path.item.map(ctx.value) + except KeyError: + logging.warning("%s cannot resolve UID: %s", _prefix(ctx.path), + ctx.value) + return False + return True + + +def _assert_op_re(ctx: _AssertContext, assert_info: Any) -> bool: + return re.search(assert_info, ctx.value) is not None + + +def _assert_op_in(ctx: _AssertContext, assert_info: Any) -> bool: + return ctx.value in assert_info + + +_WORD_SEPARATOR = re.compile(r"[ \t\n\r\f\v-]+") + + +def _assert_op_contains(ctx: _AssertContext, assert_info: Any) -> bool: + value = " " + " ".join(_WORD_SEPARATOR.split(ctx.value.lower())) + " " + return any(f" {substring} " in value for substring in assert_info) + + +def _assert(ctx: _AssertContext, assert_info: Any) -> bool: + if isinstance(assert_info, list): + return _assert_op_or(ctx, assert_info) + key = next(iter(assert_info)) + return ctx.ops[key](ctx, assert_info[key]) + + +def _maybe_assert(path: _Path, value: Any, type_info: Any, + ops: Dict[str, Any]) -> bool: + if "assert" in type_info: + return _assert(_AssertContext(path, value, type_info, ops), + type_info["assert"]) + return True + + +_ASSERT_OPS_INT_OR_FLOAT = { + "and": _assert_op_and, + "not": _assert_op_not, + "or": _assert_op_or, + "eq": _assert_op_eq, + "ne": _assert_op_ne, + "le": _assert_op_le, + "lt": _assert_op_lt, + "ge": _assert_op_ge, + "gt": _assert_op_gt, +} + + +def _assert_int_or_float(path: _Path, value: Any, type_info: Any) -> bool: + return _maybe_assert(path, value, type_info, _ASSERT_OPS_INT_OR_FLOAT) + + +_ASSERT_OPS_STR = { + "and": _assert_op_and, + "not": _assert_op_not, + "or": _assert_op_or, + "eq": _assert_op_eq, + "ne": _assert_op_ne, + "le": _assert_op_le, + "lt": _assert_op_lt, + "ge": _assert_op_ge, + "gt": _assert_op_gt, + "uid": _assert_op_uid, + "re": _assert_op_re, + "in": _assert_op_in, + "contains": _assert_op_contains, +} + + +def _assert_str(path: _Path, value: Any, type_info: Any) -> bool: + return _maybe_assert(path, value, type_info, _ASSERT_OPS_STR) + + +def _assert_type(path: _Path, value: Any, type_expected: str) -> bool: + type_actual = _type_name(value) + if type_actual == type_expected: + return True + logging.error("%s expected type '%s', actual type '%s'", _prefix(path), + type_expected, type_actual) + return False + + +NAME = re.compile(r"^([a-z][a-z0-9-]*|SPDX-License-Identifier)$") + + +def _prefix(prefix: _Path) -> str: + if prefix.path.endswith(":"): + return prefix.path + return prefix.path + ":" + + +class _Verifier: + def __init__(self, name: str, verifier_map: _VerifierMap): + self._name = name + self._verifier_map = verifier_map + self.is_subtype = False + verifier_map[name] = self + + def verify_info(self, path: _Path) -> None: + """ Produces a verify logging information. """ + logging.info("%s verify using type '%s'", _prefix(path), self._name) + + def verify(self, path: _Path, value: Any) -> Set[str]: + """ Verifies a value according to the type information. """ + self.verify_info(path) + _assert_type(path, value, self._name) + return set() + + def resolve_type_refinements(self) -> None: + """ Resolves the type refinements for this type. """ + + +class _NameVerifier(_Verifier): + def verify(self, path: _Path, value: Any) -> Set[str]: + """ Verifies a name. """ + self.verify_info(path) + if _assert_type(path, value, "str") and NAME.search(value) is None: + logging.error("%s invalid name: %s", _prefix(path), value) + return set() + + +class _UIDVerifier(_Verifier): + def verify(self, path: _Path, value: Any) -> Set[str]: + """ Verifies an attribute key. """ + self.verify_info(path) + if _assert_type(path, value, "str"): + try: + path.item.map(value) + except KeyError: + logging.error("%s cannot resolve UID: %s", _prefix(path), + value) + return set() + + +class _ItemVerifier(_Verifier): + def __init__(self, name: str, verifier_map: _VerifierMap, + info_map: Dict[str, Any], item: Item): + super().__init__(name, verifier_map) + self._info_map = info_map + self._item = item + self._subtype_key = "" + self._subtype_verifiers = {} # type: _VerifierMap + + def verify_bool(self, path: _Path, value: Any, type_info: Any) -> Set[str]: + """ Verifies a boolean value. """ + # pylint: disable=no-self-use + if type_info and "assert" in type_info: + expected = type_info["assert"] + if expected != value: + logging.error("%s expected %r, actual %r", _prefix(path), + expected, value) + return set() + + def _verify_key(self, path: _Path, value: Any, type_name: str, + key: str) -> None: + if type_name in self._verifier_map: + self._verifier_map[type_name].verify( + _Path(path.item, path.path + f"/{key}"), value[key]) + else: + logging.error("%s unknown specification type: %s", _prefix(path), + type_name) + + def assert_keys_no_constraints(self, path: _Path, specified_keys: Set[str], + keys: List[str]) -> None: + """ Asserts nothing in particular. """ + + def assert_keys_at_least_one(self, path: _Path, specified_keys: Set[str], + keys: List[str]) -> None: + """ Asserts that at least one specified key is present in the keys. """ + present_keys = specified_keys.intersection(keys) + if len(present_keys) == 0: + logging.error( + "%s not at least one key out of %s is present for type '%s'", + _prefix(path), str(sorted(specified_keys)), self._name) + + def assert_keys_at_most_one(self, path: _Path, specified_keys: Set[str], + keys: List[str]) -> None: + """ Asserts that at most one specified key is present in the keys. """ + present_keys = specified_keys.intersection(keys) + if len(present_keys) > 1: + logging.error( + "%s not at most one key out of %s " + "is present for type '%s': %s", _prefix(path), + str(sorted(specified_keys)), self._name, + str(sorted(present_keys))) + + def assert_keys_exactly_one(self, path: _Path, specified_keys: Set[str], + keys: List[str]) -> None: + """ Asserts that exactly one specified key is present in the keys. """ + present_keys = specified_keys.intersection(keys) + if len(present_keys) != 1: + logging.error( + "%s not exactly one key out of %s " + "is present for type '%s': %s", _prefix(path), + str(sorted(specified_keys)), self._name, + str(sorted(present_keys))) + + def assert_keys_subset(self, path: _Path, specified_keys: Set[str], + keys: List[str]) -> None: + """ Asserts that the specified keys are a subset of the keys. """ + if not specified_keys.issubset(keys): + missing_keys = specified_keys.difference( + specified_keys.intersection(keys)) + logging.error("%s missing mandatory keys for type '%s': %s", + _prefix(path), self._name, str(sorted(missing_keys))) + + def _assert_mandatory_keys(self, path: _Path, type_info: Any, + attr_info: Any, keys: List[str]) -> None: + mandatory_attr_info = type_info["mandatory-attributes"] + if isinstance(mandatory_attr_info, str): + _ASSERT_KEYS[mandatory_attr_info](self, path, set(attr_info), keys) + else: + assert isinstance(mandatory_attr_info, list) + self.assert_keys_subset(path, set(mandatory_attr_info), keys) + + def verify_dict(self, path: _Path, value: Any, type_info: Any) -> Set[str]: + """ Verifies a dictionary value. """ + keys = sorted(filter(lambda key: not key.startswith("_"), value)) + attr_info = type_info["attributes"] + self._assert_mandatory_keys(path, type_info, attr_info, keys) + verified_keys = set() # type: Set[str] + for key in keys: + if key in attr_info: + self._verify_key(path, value, attr_info[key]["spec-type"], key) + verified_keys.add(key) + elif "generic-attributes" in type_info: + key_as_value = {key: key} + self._verify_key( + path, key_as_value, + type_info["generic-attributes"]["key-spec-type"], key) + self._verify_key( + path, value, + type_info["generic-attributes"]["value-spec-type"], key) + verified_keys.add(key) + if self._subtype_key: + if self._subtype_key in keys: + subtype_value = value[self._subtype_key] + if subtype_value in self._subtype_verifiers: + verified_keys.update( + self._subtype_verifiers[subtype_value].verify( + path, value)) + else: + logging.error( + "%s unknown subtype for key '%s' for type '%s': %s", + _prefix(path), self._subtype_key, self._name, + subtype_value) + else: + logging.error("%s subtype key '%s' not present for type '%s'", + _prefix(path), self._subtype_key, self._name) + if not self.is_subtype: + unverified_keys = set(keys).difference(verified_keys) + if unverified_keys: + logging.error( + "%s has unverfied keys for type '%s' and its subtypes: %s", + _prefix(path), self._name, str(sorted(unverified_keys))) + return verified_keys + + def verify_int_or_float(self, path: _Path, value: Any, + type_info: Any) -> Set[str]: + """ Verifies an integer or float value. """ + # pylint: disable=no-self-use + if not _assert_int_or_float(path, value, type_info): + logging.error("%s invalid value: %s", _prefix(path), str(value)) + return set() + + def verify_list(self, path: _Path, value: Any, type_info: Any) -> Set[str]: + """ Verifies a list value. """ + verifier = self._verifier_map[type_info["spec-type"]] + for index, element in enumerate(value): + verifier.verify(_Path(path.item, path.path + f"[{index}]"), + element) + return set() + + def verify_none(self, _path: _Path, _value: Any, + _type_info: Any) -> Set[str]: + """ Verifies a none value. """ + # pylint: disable=no-self-use + return set() + + def verify_str(self, path: _Path, value: Any, type_info: Any) -> Set[str]: + """ Verifies a string value. """ + # pylint: disable=no-self-use + if not _assert_str(path, value, type_info): + logging.error("%s invalid value: %s", _prefix(path), value) + return set() + + def verify(self, path: _Path, value: Any) -> Set[str]: + self.verify_info(path) + type_name = _type_name(value) + if type_name in self._info_map: + return _VERIFY[type_name](self, path, value, + self._info_map[type_name]) + logging.error( + "%s expected value of types %s for type '%s', " + "actual type '%s'", _prefix(path), str(sorted(self._info_map)), + self._name, type_name) + return set() + + def _add_subtype_verifier(self, subtype_key: str, subtype_value: str, + subtype_name: str) -> None: + logging.info("add subtype '%s' to '%s'", subtype_name, self._name) + assert not self._subtype_key or self._subtype_key == subtype_key + assert subtype_value not in self._subtype_verifiers + subtype_verifier = self._verifier_map[subtype_name] + subtype_verifier.is_subtype = True + self._subtype_key = subtype_key + self._subtype_verifiers[subtype_value] = subtype_verifier + + def resolve_type_refinements(self) -> None: + for link in self._item.links_to_children(): + if link.role == "spec-refinement": + self._add_subtype_verifier(link["spec-key"], + link["spec-value"], + link.item["spec-type"]) + + +_VERIFY = { + "bool": _ItemVerifier.verify_bool, + "dict": _ItemVerifier.verify_dict, + "float": _ItemVerifier.verify_int_or_float, + "int": _ItemVerifier.verify_int_or_float, + "list": _ItemVerifier.verify_list, + "none": _ItemVerifier.verify_none, + "str": _ItemVerifier.verify_str, +} + +_ASSERT_KEYS = { + "all": _ItemVerifier.assert_keys_subset, + "at-least-one": _ItemVerifier.assert_keys_at_least_one, + "at-most-one": _ItemVerifier.assert_keys_at_most_one, + "exactly-one": _ItemVerifier.assert_keys_exactly_one, + "none": _ItemVerifier.assert_keys_no_constraints, +} + + +def _create_verifier(item: Item, verifier_map: _VerifierMap) -> _Verifier: + spec_type = item["spec-type"] + assert spec_type not in verifier_map + spec_info = item["spec-info"] + assert isinstance(spec_info, dict) + return _ItemVerifier(spec_type, verifier_map, spec_info, item) + + +def _gather_item_verifiers(item: Item, verifier_map: _VerifierMap) -> None: + for link in item.links_to_children(): + if link.role == "spec-member": + _create_verifier(link.item, verifier_map) + + +def verify(config: dict, item_cache: ItemCache) -> None: + """ + Verifies specification items according to the configuration. + + :param config: A dictionary with configuration entries. + :param item_cache: The specification item cache. + """ + verifier_map = {} # type: _VerifierMap + _NameVerifier("name", verifier_map) + _UIDVerifier("uid", verifier_map) + _Verifier("bool", verifier_map) + _Verifier("float", verifier_map) + _Verifier("int", verifier_map) + _Verifier("none", verifier_map) + _Verifier("str", verifier_map) + try: + root_uid = config["root-type"] + except KeyError: + logging.error("configuration has no root type") + return + try: + root_item = item_cache[root_uid] + except KeyError: + logging.error("root type item does not exist in item cache") + return + root_verifier = _create_verifier(root_item, verifier_map) + _gather_item_verifiers(root_item, verifier_map) + for name in sorted(verifier_map): + logging.info("type: %s", name) + verifier_map[name].resolve_type_refinements() + logging.info("start specification item verification") + for key in sorted(item_cache.all): + item = item_cache[key] + root_verifier.verify(_Path(item, f"{item.uid}:"), item.data) + logging.info("finished specification item verification") diff --git a/rtemsspec/sphinxcontent.py b/rtemsspec/sphinxcontent.py new file mode 100644 index 00000000..6247f987 --- /dev/null +++ b/rtemsspec/sphinxcontent.py @@ -0,0 +1,240 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides classes for Sphinx content generation. """ + +# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from contextlib import contextmanager +import re +from typing import Any, Iterable, Iterator, List, Optional, Union + +from rtemsspec.content import Content, make_lines +from rtemsspec.items import Item, ItemGetValueContext, ItemMapper + +GenericContent = Union[str, List[str], "Content"] +GenericContentIterable = Union[Iterable[str], Iterable[List[str]], + Iterable[GenericContent]] + +_HEADER_LEVELS = ["#", "*", "=", "-", "^", "\""] + + +def _to_camel_case(name: str) -> str: + return name[0].upper() + re.sub( + r"\s+(.)", lambda match: match.group(1).upper(), + re.sub(r"[^ \t\n\r\f\va-zA-Z0-9]", " ", name[1:].replace("+", "X"))) + + +def get_reference(label: str, name: Optional[str] = None) -> str: + """ Returns the reference to the specified label. """ + if name: + return f":ref:`{name} <{label}>`" + return f":ref:`{label}`" + + +def get_label(name: str) -> str: + """ Returns the label for the specified name. """ + return _to_camel_case(name.strip()) + + +class SphinxContent(Content): + """ This class builds Sphinx content. """ + def __init__(self, section_level: int = 2): + super().__init__("CC-BY-SA-4.0", True) + self._tab = " " + self._section_level = section_level + self.section_label_prefix = "Section" + + def add_label(self, label: str) -> None: + """ Adds a label. """ + self.add(".. _" + label.strip() + ":") + + def add_header(self, name, level=2) -> None: + """ Adds a header. """ + name = name.strip() + self.add([name, _HEADER_LEVELS[level] * len(name)]) + + def add_header_with_label(self, + name: str, + level: int = 2, + label_prefix: Optional[str] = None) -> str: + """ Adds a header with label. """ + if label_prefix is None: + label_prefix = self.section_label_prefix + label = label_prefix + get_label(name) + self.add_label(label) + self.add_header(name, level) + return label + + def add_index_entries(self, entries) -> None: + """ Adds a list of index entries the content. """ + self.add([".. index:: " + entry for entry in make_lines(entries)]) + + def add_definition_item(self, + name: GenericContent, + definition: GenericContent, + wrap: bool = False) -> None: + """ Adds a definition item the content. """ + @contextmanager + def _definition_item_context(content: Content) -> Iterator[None]: + content.append(name) + content.push_indent() + yield + content.pop_indent() + + if wrap: + self.wrap(definition, context=_definition_item_context) + else: + self.add(definition, context=_definition_item_context) + + @contextmanager + def definition_item(self, name: GenericContent) -> Iterator[None]: + """ Opens a definition item context. """ + self.wrap(name) + self.push_indent() + yield + self.pop_indent() + + def open_directive(self, + name: str, + value: Optional[str] = None, + options: Optional[List[str]] = None) -> None: + """ Opens a directive. """ + value = " " + value if value else "" + self.add(f".. {name.strip()}::{value}") + self.push_indent() + self.add(options) + self.gap = True + + def close_directive(self) -> None: + """ Closes a directive. """ + self.pop_indent() + + @contextmanager + def directive(self, + name: str, + value: Optional[str] = None, + options: Optional[List[str]] = None): + """ Opens a directive context. """ + self.open_directive(name, value, options) + yield + self.close_directive() + + def open_section(self, + name: str, + label_prefix: Optional[str] = None) -> str: + """ Opens a section. """ + label = self.add_header_with_label(name, self._section_level, + label_prefix) + self._section_level += 1 + return label + + def close_section(self) -> None: + """ Closes a section. """ + self._section_level -= 1 + + @contextmanager + def section(self, + name: str, + label_prefix: Optional[str] = None) -> Iterator[str]: + """ Opens a section context. """ + yield self.open_section(name, label_prefix) + self.close_section() + + def add_list_item(self, content: GenericContent) -> None: + """ Adds a list item. """ + self.wrap(content, initial_indent="* ", subsequent_indent=" ") + + def add_list(self, + items: GenericContentIterable, + prologue: Optional[GenericContent] = None, + epilogue: Optional[GenericContent] = None, + add_blank_line: bool = False) -> None: + """ Adds a list with introduction. """ + if items: + self.wrap(prologue) + for item in items: + self.add_list_item(item) + if add_blank_line: + self.add_blank_line() + self.wrap(epilogue) + + def open_list_item(self, content: GenericContent) -> None: + """ Opens a list item. """ + self.add(["* "]) + self.push_indent(" ") + self.gap = True + self.paste(content) + + def close_list_item(self) -> None: + """ Closes a list item. """ + self.pop_indent() + self.gap = True + + @contextmanager + def list_item(self, content: GenericContent) -> Iterator[None]: + """ Opens a list item context. """ + self.open_list_item(content) + yield + self.close_list_item() + + def add_licence_and_copyrights(self) -> None: + """ + Adds a licence and copyright block according to the registered licenses + and copyrights. + """ + statements = self._copyrights.get_statements() + if statements: + self.prepend("") + self.prepend([f".. {stm}" for stm in statements]) + self.prepend([f".. SPDX-License-Identifier: {self._license}", ""]) + + +def _get_ref_term(ctx: ItemGetValueContext) -> Any: + return f":term:`{ctx.value[ctx.key]}`" + + +def _get_ref_term_plural(ctx: ItemGetValueContext) -> Any: + try: + return f":term:`{ctx.value[ctx.key]} <{ctx.value['term']}>`" + except KeyError: + return f":term:`{ctx.value['term']}s <{ctx.value['term']}>`" + + +def _get_appl_config_option(ctx: ItemGetValueContext) -> Any: + return f":ref:`{ctx.value[ctx.key]}`" + + +class SphinxMapper(ItemMapper): + """ Sphinx item mapper. """ + def __init__(self, item: Item): + super().__init__(item) + self.add_get_value("glossary/term:/term", _get_ref_term) + self.add_get_value("glossary/term:/plural", _get_ref_term_plural) + self.add_get_value("interface/appl-config-option/feature-enable:/name", + _get_appl_config_option) + self.add_get_value("interface/appl-config-option/feature:/name", + _get_appl_config_option) + self.add_get_value("interface/appl-config-option/initializer:/name", + _get_appl_config_option) + self.add_get_value("interface/appl-config-option/integer:/name", + _get_appl_config_option) diff --git a/rtemsspec/tests/config/a.yml b/rtemsspec/tests/config/a.yml new file mode 100644 index 00000000..162db4e9 --- /dev/null +++ b/rtemsspec/tests/config/a.yml @@ -0,0 +1,2 @@ +a: b +c: !include b.yml diff --git a/rtemsspec/tests/config/b.yml b/rtemsspec/tests/config/b.yml new file mode 100644 index 00000000..e7e2f941 --- /dev/null +++ b/rtemsspec/tests/config/b.yml @@ -0,0 +1 @@ +!include c/d.yml diff --git a/rtemsspec/tests/config/c/d.yml b/rtemsspec/tests/config/c/d.yml new file mode 100644 index 00000000..dd4175c8 --- /dev/null +++ b/rtemsspec/tests/config/c/d.yml @@ -0,0 +1 @@ +!include e.yml diff --git a/rtemsspec/tests/config/c/e.yml b/rtemsspec/tests/config/c/e.yml new file mode 100644 index 00000000..4bcfe98e --- /dev/null +++ b/rtemsspec/tests/config/c/e.yml @@ -0,0 +1 @@ +d diff --git a/rtemsspec/tests/spec-applconfig/a.yml b/rtemsspec/tests/spec-applconfig/a.yml new file mode 100644 index 00000000..bde070c0 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/a.yml @@ -0,0 +1,27 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +default: default a +description: description a +index-entries: +- index a +name: a +notes: | + notes a + + references: + + * ${b:/name} + + * ${.:/document-reference/terminate} + + * ${func:/name} + + * ${td:/name} +appl-config-option-type: feature +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +type: interface diff --git a/rtemsspec/tests/spec-applconfig/b.yml b/rtemsspec/tests/spec-applconfig/b.yml new file mode 100644 index 00000000..34b5a3c3 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/b.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +description: description b +index-entries: [] +name: b +notes: null +appl-config-option-type: feature-enable +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +type: interface diff --git a/rtemsspec/tests/spec-applconfig/c.yml b/rtemsspec/tests/spec-applconfig/c.yml new file mode 100644 index 00000000..61a645c4 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/c.yml @@ -0,0 +1,23 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: integer +constraints: + max: 99 + min: -1 + texts: + - custom c 1 + - custom c 2 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 13 +description: description c +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +- role: constraint + uid: d +name: c +notes: notes c +type: interface diff --git a/rtemsspec/tests/spec-applconfig/d.yml b/rtemsspec/tests/spec-applconfig/d.yml new file mode 100644 index 00000000..93fbd416 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/d.yml @@ -0,0 +1,7 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: [] +text: constraint d +type: constraint diff --git a/rtemsspec/tests/spec-applconfig/e.yml b/rtemsspec/tests/spec-applconfig/e.yml new file mode 100644 index 00000000..77686aca --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/e.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: integer +constraints: + min: -2 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 7 +description: description e +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +name: e +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/f.yml b/rtemsspec/tests/spec-applconfig/f.yml new file mode 100644 index 00000000..9fdb0b26 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/f.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: integer +constraints: + max: 2 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 1 +description: description f +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +name: f +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/func.yml b/rtemsspec/tests/spec-applconfig/func.yml new file mode 100644 index 00000000..fc08ddc0 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/func.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: + body: null + params: [] + return: void + variants: [] +description: null +name: func +notes: null +params: [] +interface-type: function +links: [] +return: + return: null + return-values: [] +type: interface diff --git a/rtemsspec/tests/spec-applconfig/g.yml b/rtemsspec/tests/spec-applconfig/g.yml new file mode 100644 index 00000000..a0bccd0b --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/g.yml @@ -0,0 +1,9 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +description: description +name: group name +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: appl-config-group +links: [] +type: interface diff --git a/rtemsspec/tests/spec-applconfig/h.yml b/rtemsspec/tests/spec-applconfig/h.yml new file mode 100644 index 00000000..513b49ab --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/h.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: integer +constraints: + texts: + - custom h +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 1 +description: description h +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +name: h +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/i.yml b/rtemsspec/tests/spec-applconfig/i.yml new file mode 100644 index 00000000..6d875ac0 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/i.yml @@ -0,0 +1,20 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: integer +constraints: + set: + - 1 + - 2 + - 3 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 1 +description: description i +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +name: i +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/j.yml b/rtemsspec/tests/spec-applconfig/j.yml new file mode 100644 index 00000000..093c9cc4 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/j.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: integer +constraints: + set: + - 1 + - 2 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: Foo bar. +description: description j +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +- role: constraint + uid: d +name: j +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/k.yml b/rtemsspec/tests/spec-applconfig/k.yml new file mode 100644 index 00000000..6900d41c --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/k.yml @@ -0,0 +1,19 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: integer +constraints: + texts: + - custom k 1 + - custom k 2 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 1 +description: description k +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +name: k +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/l.yml b/rtemsspec/tests/spec-applconfig/l.yml new file mode 100644 index 00000000..1506dddc --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/l.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: initializer +constraints: + max: 2 + min: 0 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 1 +description: description l +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +name: l +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/m.yml b/rtemsspec/tests/spec-applconfig/m.yml new file mode 100644 index 00000000..267f6bc4 --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/m.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +appl-config-option-type: initializer +constraints: + some: garbage +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +default-value: 1 +description: description m +enabled-by: true +index-entries: [] +interface-type: appl-config-option +links: +- role: appl-config-group-member + uid: g +name: m +notes: null +type: interface diff --git a/rtemsspec/tests/spec-applconfig/td.yml b/rtemsspec/tests/spec-applconfig/td.yml new file mode 100644 index 00000000..9ef5c4fa --- /dev/null +++ b/rtemsspec/tests/spec-applconfig/td.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: void ${.:/name} + variants: [] +description: null +name: td +notes: null +interface-type: typedef +links: [] +type: interface diff --git a/rtemsspec/tests/spec-build/bsp.yml b/rtemsspec/tests/spec-build/bsp.yml new file mode 100644 index 00000000..8e42c1b6 --- /dev/null +++ b/rtemsspec/tests/spec-build/bsp.yml @@ -0,0 +1,15 @@ +arch: foo +bsp: bar +build-type: bsp +enabled-by: true +install: +- source: + - abc +links: +- role: null + uid: o +- role: null + uid: d +source: +- def +type: build diff --git a/rtemsspec/tests/spec-build/bsp2.yml b/rtemsspec/tests/spec-build/bsp2.yml new file mode 100644 index 00000000..7488559f --- /dev/null +++ b/rtemsspec/tests/spec-build/bsp2.yml @@ -0,0 +1,11 @@ +arch: foo +bsp: bla +build-type: bsp +enabled-by: true +install: +- source: + - blub +links: [] +source: +- nada +type: build diff --git a/rtemsspec/tests/spec-build/d.yml b/rtemsspec/tests/spec-build/d.yml new file mode 100644 index 00000000..b07f55bd --- /dev/null +++ b/rtemsspec/tests/spec-build/d.yml @@ -0,0 +1,7 @@ +build-type: start-file +enabled-by: +- not: A +links: [] +source: +- pqr +type: build diff --git a/rtemsspec/tests/spec-build/g.yml b/rtemsspec/tests/spec-build/g.yml new file mode 100644 index 00000000..de26b4d5 --- /dev/null +++ b/rtemsspec/tests/spec-build/g.yml @@ -0,0 +1,7 @@ +build-type: group +enabled-by: true +install: +- source: + - ghi +links: [] +type: build diff --git a/rtemsspec/tests/spec-build/o.yml b/rtemsspec/tests/spec-build/o.yml new file mode 100644 index 00000000..3b45d873 --- /dev/null +++ b/rtemsspec/tests/spec-build/o.yml @@ -0,0 +1,11 @@ +build-type: objects +enabled-by: true +install: +- source: + - jkl +links: +- role: null + uid: s +source: +- mno +type: build diff --git a/rtemsspec/tests/spec-build/s.yml b/rtemsspec/tests/spec-build/s.yml new file mode 100644 index 00000000..a0b7eae7 --- /dev/null +++ b/rtemsspec/tests/spec-build/s.yml @@ -0,0 +1,7 @@ +build-type: start-file +enabled-by: +- A +links: [] +source: +- stu +type: build diff --git a/rtemsspec/tests/spec-build/x.yml b/rtemsspec/tests/spec-build/x.yml new file mode 100644 index 00000000..26e98206 --- /dev/null +++ b/rtemsspec/tests/spec-build/x.yml @@ -0,0 +1,3 @@ +enabled-by: true +links: [] +type: nix diff --git a/rtemsspec/tests/spec-doc/a.yml b/rtemsspec/tests/spec-doc/a.yml new file mode 100644 index 00000000..2384ae3c --- /dev/null +++ b/rtemsspec/tests/spec-doc/a.yml @@ -0,0 +1,25 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: spec + uid: root +spec-description: null +spec-example: | + a: null +spec-info: + dict: + attributes: + a: + description: null + spec-type: a + description: null + mandatory-attributes: [] +spec-name: A +spec-type: a +type: spec diff --git a/rtemsspec/tests/spec-doc/b.yml b/rtemsspec/tests/spec-doc/b.yml new file mode 100644 index 00000000..7ee8daa2 --- /dev/null +++ b/rtemsspec/tests/spec-doc/b.yml @@ -0,0 +1,29 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: b + uid: root +- role: spec-refinement + spec-key: d1 + spec-value: b + uid: d +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + generic-attributes: + description: null + key-spec-type: name + value-spec-type: list-only + mandatory-attributes: all +spec-name: B +spec-type: b +type: spec diff --git a/rtemsspec/tests/spec-doc/c.yml b/rtemsspec/tests/spec-doc/c.yml new file mode 100644 index 00000000..314bda78 --- /dev/null +++ b/rtemsspec/tests/spec-doc/c.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + c: + description: null + spec-type: float + description: null + mandatory-attributes: + - c +spec-name: C +spec-type: c +type: spec diff --git a/rtemsspec/tests/spec-doc/d.yml b/rtemsspec/tests/spec-doc/d.yml new file mode 100644 index 00000000..38abd2ea --- /dev/null +++ b/rtemsspec/tests/spec-doc/d.yml @@ -0,0 +1,25 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + d1: + description: null + spec-type: name + d2: + description: null + spec-type: none + description: null + mandatory-attributes: + - d1 + - d2 +spec-name: D +spec-type: d +type: spec diff --git a/rtemsspec/tests/spec-doc/list-only.yml b/rtemsspec/tests/spec-doc/list-only.yml new file mode 100644 index 00000000..5cd964c7 --- /dev/null +++ b/rtemsspec/tests/spec-doc/list-only.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + list: + description: null + spec-type: str +spec-name: List Only +spec-type: list-only +type: spec diff --git a/rtemsspec/tests/spec-doc/root.yml b/rtemsspec/tests/spec-doc/root.yml new file mode 100644 index 00000000..c6fa898a --- /dev/null +++ b/rtemsspec/tests/spec-doc/root.yml @@ -0,0 +1,93 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: [] +spec-description: null +spec-example: null +spec-info: + bool: + assert: true + description: | + A reference to ${.:/spec-name}. + dict: + attributes: + type: + description: null + spec-type: name + description: null + generic-attributes: + description: null + key-spec-type: name + value-spec-type: root + mandatory-attributes: all + float: + assert: + eq: 0.0 + description: null + spec-type: float + int: + assert: + eq: 0 + description: null + spec-type: int + list: + description: null + spec-type: root + none: null + str: + assert: + - and: + - contains: + - a + - b + - c + - eq: d + - ge: e + - gt: f + - in: + - g + - h + - le: i + - lt: j + - ne: k + - re: l + - true + - uid: null + - or: + - and: + - in: [] + - in: + - x + - not: + - not: + contains: + - a + - b + - c + - not: + eq: d + - not: + ge: e + - not: + gt: f + - not: + in: + - g + - h + - not: + le: i + - not: + lt: j + - not: + ne: k + - not: + re: l + - not: true + - not: + uid: null + description: null + spec-type: str +spec-name: Root +spec-type: root +type: spec diff --git a/rtemsspec/tests/spec-glossary/doc.rst b/rtemsspec/tests/spec-glossary/doc.rst new file mode 100644 index 00000000..e07b9a35 --- /dev/null +++ b/rtemsspec/tests/spec-glossary/doc.rst @@ -0,0 +1 @@ +:term:`T` diff --git a/rtemsspec/tests/spec-glossary/g.yml b/rtemsspec/tests/spec-glossary/g.yml new file mode 100644 index 00000000..86797bfc --- /dev/null +++ b/rtemsspec/tests/spec-glossary/g.yml @@ -0,0 +1,7 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +glossary-type: group +links: [] +name: G +type: glossary diff --git a/rtemsspec/tests/spec-glossary/glossary.rst b/rtemsspec/tests/spec-glossary/glossary.rst new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/rtemsspec/tests/spec-glossary/glossary.rst diff --git a/rtemsspec/tests/spec-glossary/glossary/t.yml b/rtemsspec/tests/spec-glossary/glossary/t.yml new file mode 100644 index 00000000..0b82d582 --- /dev/null +++ b/rtemsspec/tests/spec-glossary/glossary/t.yml @@ -0,0 +1,12 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +term: T +glossary-type: term +links: +- role: null + uid: ../g +text: | + Term text $$${/glossary/u:/term} ${/glossary/t:/term} + ${/glossary/u:/glossary-type}. +type: glossary diff --git a/rtemsspec/tests/spec-glossary/glossary/u.yml b/rtemsspec/tests/spec-glossary/glossary/u.yml new file mode 100644 index 00000000..1ce28ff8 --- /dev/null +++ b/rtemsspec/tests/spec-glossary/glossary/u.yml @@ -0,0 +1,11 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +term: U +glossary-type: term +links: +- role: null + uid: ../g +text: | + Term text U. +type: glossary diff --git a/rtemsspec/tests/spec-glossary/glossary/v.yml b/rtemsspec/tests/spec-glossary/glossary/v.yml new file mode 100644 index 00000000..dca475a7 --- /dev/null +++ b/rtemsspec/tests/spec-glossary/glossary/v.yml @@ -0,0 +1,11 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +term: V +glossary-type: term +links: +- role: null + uid: ../g +text: | + Term text V. +type: glossary diff --git a/rtemsspec/tests/spec-interface/asm.yml b/rtemsspec/tests/spec-interface/asm.yml new file mode 100644 index 00000000..2d4fe860 --- /dev/null +++ b/rtemsspec/tests/spec-interface/asm.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + defaults: null + variants: [] +description: null +name: ASM +notes: null +interface-type: define +links: +- role: interface-placement + uid: command-line +- role: other + uid: command-line +type: interface diff --git a/rtemsspec/tests/spec-interface/command-line.yml b/rtemsspec/tests/spec-interface/command-line.yml new file mode 100644 index 00000000..5ecd875f --- /dev/null +++ b/rtemsspec/tests/spec-interface/command-line.yml @@ -0,0 +1,9 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: container +links: +- role: interface-placement + uid: domain-command-line +type: interface diff --git a/rtemsspec/tests/spec-interface/define-a.yml b/rtemsspec/tests/spec-interface/define-a.yml new file mode 100644 index 00000000..6078f749 --- /dev/null +++ b/rtemsspec/tests/spec-interface/define-a.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: '' + variants: [] +description: null +name: A +notes: null +interface-type: define +links: +- role: interface-placement + uid: h2 +- role: interface-ingroup + uid: ga +type: interface diff --git a/rtemsspec/tests/spec-interface/define-b.yml b/rtemsspec/tests/spec-interface/define-b.yml new file mode 100644 index 00000000..3136db5e --- /dev/null +++ b/rtemsspec/tests/spec-interface/define-b.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: '1' + variants: [] +description: null +name: B +notes: null +interface-type: define +links: +- role: interface-placement + uid: h2 +- role: interface-ingroup + uid: ga +type: interface diff --git a/rtemsspec/tests/spec-interface/define-c.yml b/rtemsspec/tests/spec-interface/define-c.yml new file mode 100644 index 00000000..1a515a29 --- /dev/null +++ b/rtemsspec/tests/spec-interface/define-c.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: '2' + variants: [] +description: null +name: C +notes: null +interface-type: define +links: +- role: interface-placement + uid: h2 +- role: interface-ingroup + uid: ga +type: interface diff --git a/rtemsspec/tests/spec-interface/define.yml b/rtemsspec/tests/spec-interface/define.yml new file mode 100644 index 00000000..2f72c770 --- /dev/null +++ b/rtemsspec/tests/spec-interface/define.yml @@ -0,0 +1,29 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: | + \ + ((${float_t:/name}) 123) + variants: + - definition: ((${float_t:/name}) 456) + enabled-by: + - defined(${define-a:/name}) + - (${define-b:/name} > ${define-c:/name}) + - definition: ((${float_t:/name}) 789) + enabled-by: + and: + - defined(C) + - defined(D) +description: null +name: DEFINE +notes: null +interface-type: define +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: ga +type: interface diff --git a/rtemsspec/tests/spec-interface/domain-abc.yml b/rtemsspec/tests/spec-interface/domain-abc.yml new file mode 100644 index 00000000..e878fb8c --- /dev/null +++ b/rtemsspec/tests/spec-interface/domain-abc.yml @@ -0,0 +1,9 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +description: ABC +enabled-by: true +interface-type: domain +links: [] +name: ABC +type: interface diff --git a/rtemsspec/tests/spec-interface/domain-c.yml b/rtemsspec/tests/spec-interface/domain-c.yml new file mode 100644 index 00000000..9eaea624 --- /dev/null +++ b/rtemsspec/tests/spec-interface/domain-c.yml @@ -0,0 +1,9 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +description: C +enabled-by: true +interface-type: domain +links: [] +name: C +type: interface diff --git a/rtemsspec/tests/spec-interface/domain-command-line.yml b/rtemsspec/tests/spec-interface/domain-command-line.yml new file mode 100644 index 00000000..ba2a3a42 --- /dev/null +++ b/rtemsspec/tests/spec-interface/domain-command-line.yml @@ -0,0 +1,9 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +description: Command Line +enabled-by: true +interface-type: domain +links: [] +name: Command Line +type: interface diff --git a/rtemsspec/tests/spec-interface/enum.yml b/rtemsspec/tests/spec-interface/enum.yml new file mode 100644 index 00000000..f3bcbc17 --- /dev/null +++ b/rtemsspec/tests/spec-interface/enum.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enum brief description. +definition-kind: typedef-only +description: Enum description. +name: Enum +notes: null +interface-type: enum +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: gb +- role: interface-enumerator + uid: enumerator-0 +- role: interface-enumerator + uid: enumerator-1 +- role: interface-enumerator + uid: enumerator-2 +type: interface diff --git a/rtemsspec/tests/spec-interface/enum2.yml b/rtemsspec/tests/spec-interface/enum2.yml new file mode 100644 index 00000000..54ac9c21 --- /dev/null +++ b/rtemsspec/tests/spec-interface/enum2.yml @@ -0,0 +1,20 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enum A brief description. +definition-kind: enum-only +description: null +name: EnumA +notes: null +interface-type: enum +links: +- role: interface-placement + uid: h3 +- role: interface-enumerator + uid: enumerator-a +- role: other + uid: enumerator-a +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/enum3.yml b/rtemsspec/tests/spec-interface/enum3.yml new file mode 100644 index 00000000..eaaf1400 --- /dev/null +++ b/rtemsspec/tests/spec-interface/enum3.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enum B brief description. +definition-kind: typedef-and-enum +description: null +name: EnumB +notes: null +interface-type: enum +links: +- role: interface-enumerator + uid: enumerator-b +- role: interface-placement + uid: h +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/enum4.yml b/rtemsspec/tests/spec-interface/enum4.yml new file mode 100644 index 00000000..94297498 --- /dev/null +++ b/rtemsspec/tests/spec-interface/enum4.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enum C brief description. +definition-kind: typedef-and-enum +description: null +name: EnumC +notes: null +interface-type: enum +links: +- role: interface-placement + uid: h2 +type: interface diff --git a/rtemsspec/tests/spec-interface/enumerator-0.yml b/rtemsspec/tests/spec-interface/enumerator-0.yml new file mode 100644 index 00000000..7937340e --- /dev/null +++ b/rtemsspec/tests/spec-interface/enumerator-0.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enumerator 0 brief description. +definition: + default: null + variants: [] +description: null +name: ENUMERATOR_0 +notes: null +interface-type: enumerator +links: [] +type: interface diff --git a/rtemsspec/tests/spec-interface/enumerator-1.yml b/rtemsspec/tests/spec-interface/enumerator-1.yml new file mode 100644 index 00000000..83840471 --- /dev/null +++ b/rtemsspec/tests/spec-interface/enumerator-1.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enumerator 1 brief description. +definition: + default: null + variants: [] +description: null +name: ENUMERATOR_1 +notes: null +interface-type: enumerator +links: [] +type: interface diff --git a/rtemsspec/tests/spec-interface/enumerator-2.yml b/rtemsspec/tests/spec-interface/enumerator-2.yml new file mode 100644 index 00000000..7dd4e7b1 --- /dev/null +++ b/rtemsspec/tests/spec-interface/enumerator-2.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enumerator 2 brief description. +definition: + default: null + variants: [] +description: null +name: ENUMERATOR_2 +notes: null +interface-type: enumerator +links: [] +type: interface diff --git a/rtemsspec/tests/spec-interface/enumerator-a.yml b/rtemsspec/tests/spec-interface/enumerator-a.yml new file mode 100644 index 00000000..c5018b70 --- /dev/null +++ b/rtemsspec/tests/spec-interface/enumerator-a.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enumerator A brief description. +definition: + default: '17' + variants: [] +description: null +name: ENUMERATOR_A +notes: null +interface-type: enumerator +links: [] +type: interface diff --git a/rtemsspec/tests/spec-interface/enumerator-b.yml b/rtemsspec/tests/spec-interface/enumerator-b.yml new file mode 100644 index 00000000..9bcac74f --- /dev/null +++ b/rtemsspec/tests/spec-interface/enumerator-b.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Enumerator B brief description. +definition: + default: ${enumerator-a:/name} + variants: [] +description: null +name: ENUMERATOR_B +notes: null +interface-type: enumerator +links: [] +type: interface diff --git a/rtemsspec/tests/spec-interface/float_t.yml b/rtemsspec/tests/spec-interface/float_t.yml new file mode 100644 index 00000000..b390553d --- /dev/null +++ b/rtemsspec/tests/spec-interface/float_t.yml @@ -0,0 +1,10 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +name: float_t +interface-type: typedef +links: +- role: interface-placement + uid: math +type: interface diff --git a/rtemsspec/tests/spec-interface/forward-decl.yml b/rtemsspec/tests/spec-interface/forward-decl.yml new file mode 100644 index 00000000..31f104ad --- /dev/null +++ b/rtemsspec/tests/spec-interface/forward-decl.yml @@ -0,0 +1,11 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: forward-declaration +links: +- role: interface-placement + uid: h +- role: interface-target + uid: s +type: interface diff --git a/rtemsspec/tests/spec-interface/func.yml b/rtemsspec/tests/spec-interface/func.yml new file mode 100644 index 00000000..af2f1598 --- /dev/null +++ b/rtemsspec/tests/spec-interface/func.yml @@ -0,0 +1,44 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Function brief description. +definition: + default: + body: null + params: + - int ${.:/params[0]/name} + - const int *${.:/params[1]/name} + - int *${.:/params[2]/name} + - int *${.:/params[3]/name} + return: void + variants: [] +description: | + Function description. References to ${func2:/name}, ${td:/name}, + ${enum:/name}, ${define:/name}, ${macro:/name}, ${var:/name}, + ${enumerator-0:/name}, ${s:/name}, ${option:/name}, and ${option:/type}. +name: Function +notes: null +params: +- description: is parameter 0. + dir: null + name: Param0 +- description: is parameter 1. + dir: in + name: Param1 +- description: is parameter 2. + dir: out + name: Param2 +- description: is parameter 3. + dir: inout + name: Param3 +interface-type: function +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: ga +return: + return: null + return-values: [] +type: interface diff --git a/rtemsspec/tests/spec-interface/func2.yml b/rtemsspec/tests/spec-interface/func2.yml new file mode 100644 index 00000000..295faeac --- /dev/null +++ b/rtemsspec/tests/spec-interface/func2.yml @@ -0,0 +1,53 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Very long function brief description. +definition: + default: + body: | + (void) ${.:/params[1]/name}; + (void) ${.:/params[2]/name}; + (void) ${.:/params[3]/name}; + return ${.:/params[0]/name} + 1; + params: + - int ${.:/params[0]/name} + - const ${forward-decl:/name} *${.:/params[1]/name} + - ${forward-decl:/name} *( *${.:/params[2]/name} )( void ) + - ${forward-decl:/name} *${.:/params[3]/name} + return: int + variants: [] +description: | + VeryLongFunction description. +name: VeryLongFunction +notes: | + VeryLongFunction notes. +params: +- description: | + is very long parameter 0 with some super important and extra very long + description which makes a lot of sense. + dir: null + name: VeryLongParam0 +- description: is very long parameter 1. + dir: in + name: VeryLongParam1 +- description: is very long parameter 2. + dir: out + name: VeryLongParam2 +- description: is very long parameter 3. + dir: inout + name: VeryLongParam3 +return: + return: Sometimes some value. See ${func:/name}. + return-values: + - description: is returned, in case A. + value: 1 + - description: is returned, in case B. + value: 2 +interface-type: function +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/func3.yml b/rtemsspec/tests/spec-interface/func3.yml new file mode 100644 index 00000000..28b30eb1 --- /dev/null +++ b/rtemsspec/tests/spec-interface/func3.yml @@ -0,0 +1,27 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: null + variants: + - enabled-by: true + definition: + body: null + params: [] + return: void +description: null +name: VoidFunction +notes: null +params: [] +return: + return: null + return-values: [] +interface-type: function +links: +- role: interface-placement + uid: h4 +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/func4.yml b/rtemsspec/tests/spec-interface/func4.yml new file mode 100644 index 00000000..4e033fe9 --- /dev/null +++ b/rtemsspec/tests/spec-interface/func4.yml @@ -0,0 +1,30 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Function brief description with very long return type. +definition: + default: + body: null + params: [] + return: VeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongType + variants: + - enabled-by: true + definition: + body: null + params: [] + return: NotSoVeryLongType +description: null +name: VeryLongTypeFunction +notes: null +params: [] +return: + return: This function returns an object with a very long type. + return-values: [] +interface-type: function +links: +- role: interface-placement + uid: h4 +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/ga.yml b/rtemsspec/tests/spec-interface/ga.yml new file mode 100644 index 00000000..7d934baa --- /dev/null +++ b/rtemsspec/tests/spec-interface/ga.yml @@ -0,0 +1,13 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Group A brief description. +description: Group A description. +identifier: GroupA +name: Group A +interface-type: group +links: +- role: interface-placement + uid: h +type: interface diff --git a/rtemsspec/tests/spec-interface/gb.yml b/rtemsspec/tests/spec-interface/gb.yml new file mode 100644 index 00000000..9a363756 --- /dev/null +++ b/rtemsspec/tests/spec-interface/gb.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +description: null +identifier: GroupB +name: Group B +interface-type: group +links: +- role: interface-ingroup + uid: ga +- role: other + uid: other +- role: interface-placement + uid: h +type: interface diff --git a/rtemsspec/tests/spec-interface/gc.yml b/rtemsspec/tests/spec-interface/gc.yml new file mode 100644 index 00000000..c1428b82 --- /dev/null +++ b/rtemsspec/tests/spec-interface/gc.yml @@ -0,0 +1,13 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Group C brief description. +description: Group C description. +identifier: GroupC +name: Group C +interface-type: group +links: +- role: interface-placement + uid: h2 +type: interface diff --git a/rtemsspec/tests/spec-interface/h.yml b/rtemsspec/tests/spec-interface/h.yml new file mode 100644 index 00000000..0733837a --- /dev/null +++ b/rtemsspec/tests/spec-interface/h.yml @@ -0,0 +1,28 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: [] +interface-type: header-file +links: +- enabled-by: RTEMS_SMP + role: interface-include + uid: h2 +- enabled-by: [] + role: interface-include + uid: h4 +- enabled-by: RTEMS_SMP + role: interface-include + uid: h4 +- enabled-by: ASM + role: interface-include + uid: h4 +- enabled-by: [] + role: interface-include + uid: h4 +- role: other + uid: h4 +- role: interface-placement + uid: domain-abc +path: h.h +prefix: include +type: interface diff --git a/rtemsspec/tests/spec-interface/h2.yml b/rtemsspec/tests/spec-interface/h2.yml new file mode 100644 index 00000000..194e182e --- /dev/null +++ b/rtemsspec/tests/spec-interface/h2.yml @@ -0,0 +1,12 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: + not: ASM +interface-type: header-file +links: +- role: interface-placement + uid: domain-abc +path: h2.h +prefix: include +type: interface diff --git a/rtemsspec/tests/spec-interface/h3.yml b/rtemsspec/tests/spec-interface/h3.yml new file mode 100644 index 00000000..fc61a1a5 --- /dev/null +++ b/rtemsspec/tests/spec-interface/h3.yml @@ -0,0 +1,11 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: header-file +links: +- role: interface-placement + uid: domain-abc +path: h3.h +prefix: include +type: interface diff --git a/rtemsspec/tests/spec-interface/h4.yml b/rtemsspec/tests/spec-interface/h4.yml new file mode 100644 index 00000000..6233efe5 --- /dev/null +++ b/rtemsspec/tests/spec-interface/h4.yml @@ -0,0 +1,11 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: header-file +links: +- role: interface-placement + uid: domain-abc +path: h4.h +prefix: include +type: interface diff --git a/rtemsspec/tests/spec-interface/macro.yml b/rtemsspec/tests/spec-interface/macro.yml new file mode 100644 index 00000000..a1e0e788 --- /dev/null +++ b/rtemsspec/tests/spec-interface/macro.yml @@ -0,0 +1,46 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Very long macro brief description. +definition: + default: | + do { + (void) ${.:/params[1]/name}; + (void) ${.:/params[2]/name}; + (void) ${.:/params[3]/name}; + } while ( 0 ); + ${.:/params[0]/name} + 1; + variants: [] +description: null +name: VERY_LONG_MACRO +notes: null +params: +- description: | + is very long parameter 0 with some super important and extra very long + description which makes a lot of sense. + dir: null + name: VeryLongParam0 +- description: is very long parameter 1. + dir: in + name: VeryLongParam1 +- description: is very long parameter 2. + dir: out + name: VeryLongParam2 +- description: is very long parameter 3. + dir: inout + name: VeryLongParam3 +return: + return: Sometimes some value. + return-values: + - description: is returned, in case A. + value: 1 + - description: is returned, in case B. + value: 2 +interface-type: macro +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/macro2.yml b/rtemsspec/tests/spec-interface/macro2.yml new file mode 100644 index 00000000..36e05169 --- /dev/null +++ b/rtemsspec/tests/spec-interface/macro2.yml @@ -0,0 +1,29 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Short macro brief description. +definition: + default: | + ( ( ${.:/params[0]/name} ) + 1 ) + variants: + - definition: '' + enabled-by: '0' +description: null +name: MACRO +notes: null +params: +- description: | + is parameter 0. + dir: null + name: Param0 +return: + return: Sometimes some value. + return-values: [] +interface-type: macro +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/macro3.yml b/rtemsspec/tests/spec-interface/macro3.yml new file mode 100644 index 00000000..d99179c5 --- /dev/null +++ b/rtemsspec/tests/spec-interface/macro3.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Macro without parameters. +definition: + default: '0' + variants: [] +description: null +name: MACRO +notes: null +params: [] +return: + return: null + return-values: [] +interface-type: macro +links: +- role: interface-placement + uid: h2 +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/math.yml b/rtemsspec/tests/spec-interface/math.yml new file mode 100644 index 00000000..020449fa --- /dev/null +++ b/rtemsspec/tests/spec-interface/math.yml @@ -0,0 +1,11 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: header-file +links: +- role: interface-placement + uid: domain-c +path: math.h +prefix: null +type: interface diff --git a/rtemsspec/tests/spec-interface/option.yml b/rtemsspec/tests/spec-interface/option.yml new file mode 100644 index 00000000..7580bb8e --- /dev/null +++ b/rtemsspec/tests/spec-interface/option.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 +default: default a +description: description a +index-entries: +- index a +name: a +notes: notes a +appl-config-option-type: feature +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: appl-config-option +links: [] +type: interface diff --git a/rtemsspec/tests/spec-interface/other.yml b/rtemsspec/tests/spec-interface/other.yml new file mode 100644 index 00000000..02b17731 --- /dev/null +++ b/rtemsspec/tests/spec-interface/other.yml @@ -0,0 +1,6 @@ +comment: Some comment. +enabled-by: true +links: +- role: other + uid: h +type: other diff --git a/rtemsspec/tests/spec-interface/other2.yml b/rtemsspec/tests/spec-interface/other2.yml new file mode 100644 index 00000000..2678ce82 --- /dev/null +++ b/rtemsspec/tests/spec-interface/other2.yml @@ -0,0 +1,3 @@ +enabled-by: true +links: [] +type: other diff --git a/rtemsspec/tests/spec-interface/other3.yml b/rtemsspec/tests/spec-interface/other3.yml new file mode 100644 index 00000000..2678ce82 --- /dev/null +++ b/rtemsspec/tests/spec-interface/other3.yml @@ -0,0 +1,3 @@ +enabled-by: true +links: [] +type: other diff --git a/rtemsspec/tests/spec-interface/s.yml b/rtemsspec/tests/spec-interface/s.yml new file mode 100644 index 00000000..bd040ed9 --- /dev/null +++ b/rtemsspec/tests/spec-interface/s.yml @@ -0,0 +1,59 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: +- default: + brief: Brief union description. + definition: + - default: + brief: Brief member description. + definition: ${uint32_t:/name} ${.:name} + description: Member description. + kind: member + name: some_member + variants: [] + - default: + brief: Brief struct description. + definition: + - default: + brief: Brief member 2 description. + definition: ${uint32_t:/name} ${.:name} + description: Member 2 description. + kind: member + name: some_member_2 + variants: [] + - default: + brief: Brief member 3 description. + definition: ${enum:/name} ${.:name} + description: Member 3 description. + kind: member + name: some_member_3 + variants: [] + description: struct description. + kind: struct + name: some_struct + variants: [] + description: Union description. + kind: union + name: some_union + variants: [] +- default: + brief: Brief member 4 description. + definition: ${enum:/name} ${.:name} + description: Member 4 description. + kind: member + name: some_member_4 + variants: [] +definition-kind: struct-only +description: null +name: Struct +notes: null +interface-type: struct +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: gc +type: interface diff --git a/rtemsspec/tests/spec-interface/smp.yml b/rtemsspec/tests/spec-interface/smp.yml new file mode 100644 index 00000000..dcf41bc0 --- /dev/null +++ b/rtemsspec/tests/spec-interface/smp.yml @@ -0,0 +1,10 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +name: RTEMS_SMP +interface-type: define +links: +- role: interface-placement + uid: command-line +type: interface diff --git a/rtemsspec/tests/spec-interface/stdint.yml b/rtemsspec/tests/spec-interface/stdint.yml new file mode 100644 index 00000000..559202c3 --- /dev/null +++ b/rtemsspec/tests/spec-interface/stdint.yml @@ -0,0 +1,11 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +interface-type: header-file +links: +- role: interface-placement + uid: domain-c +path: stdint.h +prefix: null +type: interface diff --git a/rtemsspec/tests/spec-interface/td.yml b/rtemsspec/tests/spec-interface/td.yml new file mode 100644 index 00000000..42f6305e --- /dev/null +++ b/rtemsspec/tests/spec-interface/td.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: Typedef Integer brief description. +definition: + default: | + ${uint32_t:/name} ${.:/name} /* ${other:/comment} */ + variants: [] +description: Typedef Integer description. +name: Integer +notes: null +interface-type: typedef +links: +- role: other + uid: other +- role: interface-ingroup + uid: gb +- role: interface-placement + uid: h +type: interface diff --git a/rtemsspec/tests/spec-interface/td3.yml b/rtemsspec/tests/spec-interface/td3.yml new file mode 100644 index 00000000..533976b2 --- /dev/null +++ b/rtemsspec/tests/spec-interface/td3.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +brief: null +definition: + default: null + variants: + - definition: | + ${uint32_t:/name} ${.:/name} + enabled-by: defined(RTEMS_SMP) +description: null +name: Integer3 +notes: null +interface-type: typedef +links: +- role: interface-placement + uid: h +- role: interface-ingroup + uid: gb +type: interface diff --git a/rtemsspec/tests/spec-interface/uint32_t.yml b/rtemsspec/tests/spec-interface/uint32_t.yml new file mode 100644 index 00000000..a15c93a6 --- /dev/null +++ b/rtemsspec/tests/spec-interface/uint32_t.yml @@ -0,0 +1,12 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +name: uint32_t +interface-type: typedef +links: +- role: other + uid: other3 +- role: interface-placement + uid: stdint +type: interface diff --git a/rtemsspec/tests/spec-interface/var.yml b/rtemsspec/tests/spec-interface/var.yml new file mode 100644 index 00000000..191dbfa3 --- /dev/null +++ b/rtemsspec/tests/spec-interface/var.yml @@ -0,0 +1,20 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: + not: ASM +brief: Variable brief description. +definition: + default: | + ${forward-decl:/name} *${.:/name} + variants: [] +description: Variable description. +name: Variable +notes: null +interface-type: variable +links: +- role: interface-ingroup + uid: gc +- role: interface-placement + uid: h +type: interface diff --git a/rtemsspec/tests/spec-item-cache/.z.yml b/rtemsspec/tests/spec-item-cache/.z.yml new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/rtemsspec/tests/spec-item-cache/.z.yml diff --git a/rtemsspec/tests/spec-item-cache/d/c.yml b/rtemsspec/tests/spec-item-cache/d/c.yml new file mode 100644 index 00000000..f901443f --- /dev/null +++ b/rtemsspec/tests/spec-item-cache/d/c.yml @@ -0,0 +1,13 @@ +a: + b: e + f: + - 1 + - 2 + - 3 + - g: + - 4 + - 5 +links: +- role: null + uid: ../p +v: c diff --git a/rtemsspec/tests/spec-item-cache/empty.txt b/rtemsspec/tests/spec-item-cache/empty.txt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/rtemsspec/tests/spec-item-cache/empty.txt diff --git a/rtemsspec/tests/spec-item-cache/p.yml b/rtemsspec/tests/spec-item-cache/p.yml new file mode 100644 index 00000000..4c3a2964 --- /dev/null +++ b/rtemsspec/tests/spec-item-cache/p.yml @@ -0,0 +1,4 @@ +links: [] +v: p +x: + y: z diff --git a/rtemsspec/tests/spec-sphinx/x.yml b/rtemsspec/tests/spec-sphinx/x.yml new file mode 100644 index 00000000..1dd0b7c2 --- /dev/null +++ b/rtemsspec/tests/spec-sphinx/x.yml @@ -0,0 +1,4 @@ +term: y +glossary-type: term +links: [] +type: glossary diff --git a/rtemsspec/tests/spec-sphinx/y.yml b/rtemsspec/tests/spec-sphinx/y.yml new file mode 100644 index 00000000..79a22535 --- /dev/null +++ b/rtemsspec/tests/spec-sphinx/y.yml @@ -0,0 +1,3 @@ +name: foobar +links: [] +type: other diff --git a/rtemsspec/tests/spec-validation/action2.yml b/rtemsspec/tests/spec-validation/action2.yml new file mode 100644 index 00000000..caafed70 --- /dev/null +++ b/rtemsspec/tests/spec-validation/action2.yml @@ -0,0 +1,146 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +functional-type: action +links: [] +post-conditions: +- name: A + states: + - name: X + test-code: | + /* Post A X */ + text: | + Post A X. + - name: Y + test-code: | + /* Post A Y */ + text: | + Post A Y. + test-epilogue: | + /* Post A epilogue. */ + test-prologue: | + /* Post A prologue. */ +- name: B + states: + - name: X + test-code: | + /* Post B X */ + text: | + Post B X. + - name: Y + test-code: | + /* Post B Y */ + text: | + Post B Y. + test-epilogue: | + /* Post B epilogue. */ + test-prologue: | + /* Post B prologue. */ +pre-conditions: +- name: A + states: + - name: X + test-code: | + /* Pre A X */ + text: | + Pre A X. + - name: Y + test-code: | + /* Pre A Y */ + text: | + Pre A Y. + test-epilogue: | + /* Pre A epilogue. */ + test-prologue: | + /* Pre A prologue. */ +- name: B + states: + - name: X + test-code: | + /* Pre B X */ + text: | + Pre B X. + - name: Y + test-code: | + /* Pre B Y */ + text: | + Pre B Y. + test-epilogue: | + /* Pre B epilogue. */ + test-prologue: | + /* Pre B prologue. */ +requirement-type: functional +test-action: | + /* Action */ +test-brief: | + Test brief. +test-context: +- brief: | + Context member brief. + description: | + Context member description. + member: | + int member +test-description: | + Test description. +test-header: + code: | + /* Header code for ${.:/test-name} with ${.:/test-run}() */ + includes: + - d.h + local-includes: + - e.h + run-params: + - description: | + Parameter A description. + dir: in + name: a + specifier: int *${.:name} + - description: | + Parameter B description. + dir: null + name: b + specifier: int ${.:name} + - description: | + Parameter C description. + dir: out + name: c + specifier: int *${.:name} + target: action2.h +test-includes: +- a.h +test-local-includes: +- b.h +test-name: Action 2 +test-setup: + brief: | + Setup brief. + code: | + /* Setup code */ + description: | + Setup description. +test-stop: null +test-support: | + /* Support code */ +test-target: action2.c +test-teardown: + brief: | + Teardown brief. + code: | + /* Teardown code */ + description: | + Teardown description. +transition-map: +- enabled-by: true + post-conditions: + A: X + B: Y + pre-conditions: + A: all + B: all +rationale: null +references: [] +text: | + Text. +type: requirement diff --git a/rtemsspec/tests/spec-validation/directive.yml b/rtemsspec/tests/spec-validation/directive.yml new file mode 100644 index 00000000..e8842fe3 --- /dev/null +++ b/rtemsspec/tests/spec-validation/directive.yml @@ -0,0 +1,300 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +functional-type: action +links: [] +post-conditions: +- name: Status + states: + - name: Ok + test-code: | + T_rsc(ctx->status, RTEMS_SUCCESSFUL); + text: | + The status shall be RTEMS_SUCCESSFUL. + - name: InvAddr + test-code: | + T_rsc(ctx->status, RTEMS_INVALID_ADDRESS); + text: | + The status shall be RTEMS_INVALID_ADDRESS. + - name: InvName + test-code: | + T_rsc(ctx->status, RTEMS_INVALID_NAME); + text: | + The status shall be RTEMS_INVALID_NAME. + - name: InvNode + test-code: | + T_rsc(ctx->status, RTEMS_INVALID_NODE); + text: | + The status shall be RTEMS_INVALID_NODE. + - name: InvId + test-code: | + T_rsc(ctx->status, RTEMS_INVALID_ID); + text: | + The status shall be RTEMS_INVALID_ID. + test-epilogue: null + test-prologue: null +- name: Id + states: + - name: Nop + test-code: | + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, 0xffffffff); + text: | + The value of the object identifier referenced by the id parameter shall + be the value before the call to rtems_task_ident(). + - name: NullPtr + test-code: | + T_null(ctx->id) + text: | + The id parameter shall be NULL. + - name: Self + test-code: | + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, rtems_task_self()); + text: | + The value of the object identifier referenced by the id parameter shall + be the identifier of the executing thread. + - name: LocalTask + test-code: | + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, ctx->id_local_task); + text: | + The value of the object identifier referenced by the id parameter shall + be the identifier of a local task with a name equal to the name + parameter. If more than one local task with such a name exists, then it + shall be the identifier of the task with the lowest object index. + - name: RemoteTask + test-code: | + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, ctx->id_remote_task); + text: | + The value of the object identifier referenced by the id parameter shall + be the identifier of a remote task on a eligible node defined by the node + parameter with a name equal to the name parameter. If more than one task + with such a name exists on the same node, then it shall be the identifier + of the task with the lowest object index. If more than one task with + such a name exists on different eligible nodes, then it shall be the + identifier of the task with the lowest node index. + test-epilogue: null + test-prologue: null +pre-conditions: +- name: Name + states: + - name: Invalid + test-code: | + ctx->name = 1; + text: | + The name parameter shall not equal to a name of an active Classic API + task object and not equal to RTEMS_SELF. + - name: Self + test-code: | + ctx->name = RTEMS_SELF; + text: | + The name parameter shall be RTEMS_SELF. + - name: Valid + test-code: | + ctx->name = rtems_build_name( 'T', 'A', 'S', 'K' ); + text: | + The name parameter shall equal to a name of an active Classic API task + object. + test-epilogue: | + /* Epilogue */ + test-prologue: | + /* Prologue */ +- name: Node + states: + - name: Local + test-code: | + ctx->node = 1; + text: | + The node parameter shall be the local node number. + - name: Remote + test-code: | + ctx->node = 2; + text: | + The node parameter shall be a remote node number. + - name: Invalid + test-code: | + ctx->node = 256; + text: | + The node parameter shall be an invalid node number. + - name: SearchAll + test-code: | + ctx->node = RTEMS_SEARCH_ALL_NODES; + text: | + The node parameter shall be RTEMS_SEARCH_ALL_NODES. + - name: SearchOther + test-code: | + ctx->node = RTEMS_SEARCH_OTHER_NODES; + text: | + The node parameter shall be RTEMS_SEARCH_OTHER_NODES. + - name: SearchLocal + test-code: | + ctx->node = RTEMS_SEARCH_LOCAL_NODE; + text: | + The node parameter shall be RTEMS_SEARCH_LOCAL_NODE. + test-epilogue: null + test-prologue: null +- name: Id + states: + - name: NullPtr + test-code: | + ctx->id = NULL; + text: | + The id parameter shall be NULL. + - name: Valid + test-code: | + ctx->id_value = 0xffffffff; + ctx->id = &ctx->id_value; + text: | + The id parameter shall point to an object identifier. + test-epilogue: null + test-prologue: null +requirement-type: functional +test-action: | + ctx->status = rtems_task_ident( ctx->name, ctx->node, ctx->id ); +test-brief: Test rtems_task_ident() brief description. +test-context: +- brief: | + Brief context member description. + description: | + Context member description. + member: | + rtems_status_code status +- brief: null + description: null + member: | + rtems_name name +- brief: null + description: null + member: | + uint32_t node +- brief: null + description: null + member: | + rtems_id *id +- brief: null + description: null + member: | + rtems_id id_value +- brief: null + description: null + member: | + rtems_id id_local_task +- brief: null + description: null + member: | + rtems_id id_remote_task +test-description: Test rtems_task_ident() description. +test-includes: +- rtems.h +test-local-includes: +- x.h +test-name: Classic Task Identification +test-setup: + brief: | + Setup brief description. + code: | + rtems_status_code sc; + + sc = rtems_task_create( + rtems_build_name( 'T', 'A', 'S', 'K' ), + 1, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->id_local_task + ); + T_assert_rsc_success( sc ); + description: | + Setup description. +test-stop: null +test-support: | + /* Test rtems_task_ident() support */ +test-header: null +test-target: tc12.c +test-teardown: + brief: null + code: | + rtems_status_code sc; + + if ( ctx->id_local_task != 0 ) { + sc = rtems_task_delete( ctx->id_local_task ); + T_rsc_success( sc ); + } + description: null +transition-map: +- enabled-by: true + post-conditions: + Id: Self + Status: Ok + pre-conditions: + Id: + - Valid + Name: + - Self + Node: all +- enabled-by: true + post-conditions: + Id: LocalTask + Status: Ok + pre-conditions: + Id: + - Valid + Name: + - Valid + Node: + - SearchAll + - SearchLocal + - Local +- enabled-by: true + post-conditions: + Id: Nop + Status: InvName + pre-conditions: + Id: + - Valid + Name: + - Valid + Node: + - Invalid + - SearchOther + - Remote +- enabled-by: true + post-conditions: + Id: Nop + Status: InvName + pre-conditions: + Id: + - Valid + Name: + - Invalid + Node: all +- enabled-by: true + post-conditions: + Id: NullPtr + Status: InvAddr + pre-conditions: + Id: + - NullPtr + Name: all + Node: all +- enabled-by: RTEMS_MULTIPROCESSING + post-conditions: + Id: RemoteTask + Status: Ok + pre-conditions: + Id: + - Valid + Name: + - Valid + Node: + - SearchOther + - Remote +rationale: null +references: [] +text: | + Calling the rtems_task_ident() directive shall yield the specified + post-conditions under the specified pre-conditions. +type: requirement diff --git a/rtemsspec/tests/spec-validation/other.yml b/rtemsspec/tests/spec-validation/other.yml new file mode 100644 index 00000000..112c85a5 --- /dev/null +++ b/rtemsspec/tests/spec-validation/other.yml @@ -0,0 +1,5 @@ +enabled-by: [] +links: +- role: null + uid: other2 +type: other diff --git a/rtemsspec/tests/spec-validation/other2.yml b/rtemsspec/tests/spec-validation/other2.yml new file mode 100644 index 00000000..ce9e0104 --- /dev/null +++ b/rtemsspec/tests/spec-validation/other2.yml @@ -0,0 +1,3 @@ +enabled-by: [] +links: [] +type: other diff --git a/rtemsspec/tests/spec-validation/tc.yml b/rtemsspec/tests/spec-validation/tc.yml new file mode 100644 index 00000000..bb63ea74 --- /dev/null +++ b/rtemsspec/tests/spec-validation/tc.yml @@ -0,0 +1,54 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +includes: +- a.h +links: [] +local-includes: +- x.h +target: tc12.c +actions: +- action: | + /* Test case action 0 code */ + checks: + - check: | + /* Test case action 0 check 0 code */ + description: | + Test case action 0 check 0 description. + links: [] + - check: | + /* Test case action 0 check 1 code; step ${step} */ + description: | + Test case action 0 check 1 description. + links: [] + description: | + Test case action 0 description. + links: [] +- action: | + /* Test case action 1 code */ + checks: + - check: | + /* Test case action 1 check 0 code; step ${step} */ + description: | + Test case action 1 check 0 description. + links: [] + - check: | + /* Test case action 1 check 1 code */ + description: | + Test case action 1 check 1 description. + links: [] + description: | + Test case action 1 description. + links: [] +brief: Test case brief description. +description: Test case description. +epilogue: | + /* Test case epilogue code */ +fixture: null +name: Test Case +prologue: | + /* Test case prologue code */ +support: | + /* Test case support code */ +type: test-case diff --git a/rtemsspec/tests/spec-validation/tc2.yml b/rtemsspec/tests/spec-validation/tc2.yml new file mode 100644 index 00000000..df236b99 --- /dev/null +++ b/rtemsspec/tests/spec-validation/tc2.yml @@ -0,0 +1,41 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +includes: +- b.h +links: [] +local-includes: +- y.h +target: tc12.c +actions: +- action: | + /* Test case 2 action 0 code */ + checks: + - check: | + /* Test case 2 action 0 check 0 code */ + description: | + Test case 2 action 0 check 0 description. + links: [] + - check: | + /* Test case 2 action 0 check 1 code */ + description: | + Test case 2 action 0 check 1 description. + links: [] + description: | + Test case 2 action 0 description. + links: [] +- action: | + /* Test case 2 action 1 code */ + checks: [] + description: | + Test case 2 action 1 description. + links: [] +brief: Test case 2 brief description. +description: Test case 2 description. +epilogue: null +fixture: test_case_2_fixture +name: Test Case 2 +prologue: null +support: null +type: test-case diff --git a/rtemsspec/tests/spec-validation/tc3.yml b/rtemsspec/tests/spec-validation/tc3.yml new file mode 100644 index 00000000..fd946e3e --- /dev/null +++ b/rtemsspec/tests/spec-validation/tc3.yml @@ -0,0 +1,30 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +includes: +- c.h +links: [] +local-includes: +- z.h +target: tc34.c +actions: +- action: | + /* Test case 3 action 0 code */ + checks: + - check: | + /* Test case 3 action 0 check 0 code; step ${step} */ + description: | + Test case 3 action 0 check 0 description. + links: [] + description: | + Test case 3 action 0 description. + links: [] +brief: Test case 3 brief description. +description: Test case 3 description. +epilogue: null +fixture: null +name: Test Case 3 +prologue: null +support: null +type: test-case diff --git a/rtemsspec/tests/spec-validation/tc4.yml b/rtemsspec/tests/spec-validation/tc4.yml new file mode 100644 index 00000000..d415ff79 --- /dev/null +++ b/rtemsspec/tests/spec-validation/tc4.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +includes: [] +links: [] +local-includes: [] +target: tc34.c +actions: [] +brief: Test case 4 brief description. +description: Test case 4 description. +epilogue: | + /* Test case 4 epilogue code */ +fixture: null +name: Test Case 4 +prologue: null +support: null +type: test-case diff --git a/rtemsspec/tests/spec-validation/tp.yml b/rtemsspec/tests/spec-validation/tp.yml new file mode 100644 index 00000000..a8b281d8 --- /dev/null +++ b/rtemsspec/tests/spec-validation/tp.yml @@ -0,0 +1,10 @@ +build-type: test-program +enabled-by: true +links: [] +source: +- tc12.c +- tc34.c +- ts.c +- action2.c +- other.c +type: build diff --git a/rtemsspec/tests/spec-validation/ts.yml b/rtemsspec/tests/spec-validation/ts.yml new file mode 100644 index 00000000..ff80e8e8 --- /dev/null +++ b/rtemsspec/tests/spec-validation/ts.yml @@ -0,0 +1,15 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +includes: +- blue.h +links: [] +local-includes: +- green.h +target: ts.c +code: | + /* Blue green code */ +description: The Blue Green description. +name: Blue Green +type: test-suite diff --git a/rtemsspec/tests/spec-verify/c1.yml b/rtemsspec/tests/spec-verify/c1.yml new file mode 100644 index 00000000..ac9caf74 --- /dev/null +++ b/rtemsspec/tests/spec-verify/c1.yml @@ -0,0 +1,12 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +dict: + a: null +enabled-by: true +links: +- role: x + uid: c2 +list: [] +type: c +uid: 1 diff --git a/rtemsspec/tests/spec-verify/c2.yml b/rtemsspec/tests/spec-verify/c2.yml new file mode 100644 index 00000000..5ea57f13 --- /dev/null +++ b/rtemsspec/tests/spec-verify/c2.yml @@ -0,0 +1,10 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +dict: + b: null +enabled-by: true +links: [] +list: [] +str-contains: uvw +type: c diff --git a/rtemsspec/tests/spec-verify/c3.yml b/rtemsspec/tests/spec-verify/c3.yml new file mode 100644 index 00000000..9a427110 --- /dev/null +++ b/rtemsspec/tests/spec-verify/c3.yml @@ -0,0 +1,13 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +dict: [] +enabled-by: true +links: [] +list: + invalid: null +must-be-true: false +str: /c4 +str-contains: abc ghi +type: c +uid: nix diff --git a/rtemsspec/tests/spec-verify/c4.yml b/rtemsspec/tests/spec-verify/c4.yml new file mode 100644 index 00000000..e0195f37 --- /dev/null +++ b/rtemsspec/tests/spec-verify/c4.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +any-dict: + a: b +bool: true +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +dict: null +enabled-by: true +float: 123.567 +int: 123 +links: [] +list: [] +must-be-true: true +other-int: 0 +str: abc +str-contains: abc uvw +type: c +uid: c3 diff --git a/rtemsspec/tests/spec-verify/d.yml b/rtemsspec/tests/spec-verify/d.yml new file mode 100644 index 00000000..68f65b9c --- /dev/null +++ b/rtemsspec/tests/spec-verify/d.yml @@ -0,0 +1,7 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +d-type: blub +enabled-by: true +links: [] +type: d diff --git a/rtemsspec/tests/spec-verify/d2.yml b/rtemsspec/tests/spec-verify/d2.yml new file mode 100644 index 00000000..488487d1 --- /dev/null +++ b/rtemsspec/tests/spec-verify/d2.yml @@ -0,0 +1,7 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +d-type: bla +enabled-by: true +links: [] +type: d diff --git a/rtemsspec/tests/spec-verify/d3.yml b/rtemsspec/tests/spec-verify/d3.yml new file mode 100644 index 00000000..06b30dad --- /dev/null +++ b/rtemsspec/tests/spec-verify/d3.yml @@ -0,0 +1,6 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +type: d diff --git a/rtemsspec/tests/spec-verify/e.yml b/rtemsspec/tests/spec-verify/e.yml new file mode 100644 index 00000000..b7527dee --- /dev/null +++ b/rtemsspec/tests/spec-verify/e.yml @@ -0,0 +1,6 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +type: e diff --git a/rtemsspec/tests/spec-verify/invalid.yml b/rtemsspec/tests/spec-verify/invalid.yml new file mode 100644 index 00000000..3c193f78 --- /dev/null +++ b/rtemsspec/tests/spec-verify/invalid.yml @@ -0,0 +1,7 @@ +INVALID: [] +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +type: spec-invalid diff --git a/rtemsspec/tests/spec-verify/keys-at-least-one-0.yml b/rtemsspec/tests/spec-verify/keys-at-least-one-0.yml new file mode 100644 index 00000000..8f9e4b5d --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-at-least-one-0.yml @@ -0,0 +1,6 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +type: keys-at-least-one diff --git a/rtemsspec/tests/spec-verify/keys-at-least-one-1.yml b/rtemsspec/tests/spec-verify/keys-at-least-one-1.yml new file mode 100644 index 00000000..31d17a4e --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-at-least-one-1.yml @@ -0,0 +1,7 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +key-a: null +type: keys-at-least-one diff --git a/rtemsspec/tests/spec-verify/keys-at-least-one-2.yml b/rtemsspec/tests/spec-verify/keys-at-least-one-2.yml new file mode 100644 index 00000000..d0eb8a29 --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-at-least-one-2.yml @@ -0,0 +1,8 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +key-a: null +key-b: null +type: keys-at-least-one diff --git a/rtemsspec/tests/spec-verify/keys-at-most-one-0.yml b/rtemsspec/tests/spec-verify/keys-at-most-one-0.yml new file mode 100644 index 00000000..2e3f0202 --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-at-most-one-0.yml @@ -0,0 +1,6 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +type: keys-at-most-one diff --git a/rtemsspec/tests/spec-verify/keys-at-most-one-1.yml b/rtemsspec/tests/spec-verify/keys-at-most-one-1.yml new file mode 100644 index 00000000..e2003342 --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-at-most-one-1.yml @@ -0,0 +1,7 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +key-a: null +type: keys-at-most-one diff --git a/rtemsspec/tests/spec-verify/keys-at-most-one-2.yml b/rtemsspec/tests/spec-verify/keys-at-most-one-2.yml new file mode 100644 index 00000000..88ee2aaa --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-at-most-one-2.yml @@ -0,0 +1,8 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +key-a: null +key-b: null +type: keys-at-most-one diff --git a/rtemsspec/tests/spec-verify/keys-exactly-one-0.yml b/rtemsspec/tests/spec-verify/keys-exactly-one-0.yml new file mode 100644 index 00000000..1a052978 --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-exactly-one-0.yml @@ -0,0 +1,6 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +type: keys-exactly-one diff --git a/rtemsspec/tests/spec-verify/keys-exactly-one-1.yml b/rtemsspec/tests/spec-verify/keys-exactly-one-1.yml new file mode 100644 index 00000000..2f233dd8 --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-exactly-one-1.yml @@ -0,0 +1,7 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +key-a: null +type: keys-exactly-one diff --git a/rtemsspec/tests/spec-verify/keys-exactly-one-2.yml b/rtemsspec/tests/spec-verify/keys-exactly-one-2.yml new file mode 100644 index 00000000..6226ec51 --- /dev/null +++ b/rtemsspec/tests/spec-verify/keys-exactly-one-2.yml @@ -0,0 +1,8 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] +key-a: null +key-b: null +type: keys-exactly-one diff --git a/rtemsspec/tests/spec-verify/notype.yml b/rtemsspec/tests/spec-verify/notype.yml new file mode 100644 index 00000000..8da253c5 --- /dev/null +++ b/rtemsspec/tests/spec-verify/notype.yml @@ -0,0 +1,5 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de +enabled-by: true +links: [] diff --git a/rtemsspec/tests/spec-verify/spec/copyright.yml b/rtemsspec/tests/spec-verify/spec/copyright.yml new file mode 100644 index 00000000..a8f46080 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/copyright.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + str: + assert: + - re: ^\s*Copyright\s+\(C\)\s+[0-9]+,\s*[0-9]+\s+.+\s*$ + - re: ^\s*Copyright\s+\(C\)\s+[0-9]+\s+.+\s*$ + - re: ^\s*Copyright\s+\(C\)\s+.+\s*$ + description: | + A value of this type shall be a copyright statement of a copyright holder + of the specification item. +spec-name: Copyright +spec-type: copyright +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/copyrights.yml b/rtemsspec/tests/spec-verify/spec/copyrights.yml new file mode 100644 index 00000000..522e4f43 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/copyrights.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + list: + description: null + spec-type: copyright +spec-name: Copyrights Type +spec-type: copyrights +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/enabled-by-list.yml b/rtemsspec/tests/spec-verify/spec/enabled-by-list.yml new file mode 100644 index 00000000..f84fff28 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/enabled-by-list.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + list: + description: null + spec-type: enabled-by +spec-name: Enabled-By Expression List +spec-type: enabled-by-list +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/enabled-by.yml b/rtemsspec/tests/spec-verify/spec/enabled-by.yml new file mode 100644 index 00000000..2f3bb287 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/enabled-by.yml @@ -0,0 +1,49 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: | + A value of this type shall be an expression which defines under which + conditions the specification item or parts of it are enabled. The expression + is evaluated with the use of an *enabled set*. This is a set of strings + which indicate enabled features. +spec-example: null +spec-info: + bool: + description: | + This expression evaluates directly to the boolean value. + dict: + attributes: + and: + description: | + The *and* operator evaluates to the *logical and* of the evaluation + results of the expressions in the list. + spec-type: enabled-by-list + not: + description: | + The *not* operator evaluates to the *logical not* of the evaluation + results of the expression. + spec-type: enabled-by + or: + description: | + The *or* operator evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: enabled-by-list + description: | + Each attribute defines an operator. + mandatory-attributes: exactly-one + list: + description: | + This list of expressions evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: enabled-by + str: + description: | + If the value is in the *enabled set*, this expression evaluates to true, + otherwise to false. +spec-name: Enabled-By Expression +spec-type: enabled-by +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/link.yml b/rtemsspec/tests/spec-verify/spec/link.yml new file mode 100644 index 00000000..c9dadb7f --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/link.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + role: + description: | + This mandatory attribute defines the role of the link. + spec-type: name + uid: + description: | + This mandatory attribute defines the link target item UID. + spec-type: uid + description: | + This attribute value shall a link to a specification item. + mandatory-attributes: all +spec-name: Link +spec-type: link +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/links.yml b/rtemsspec/tests/spec-verify/spec/links.yml new file mode 100644 index 00000000..77092dfa --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/links.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: | + This attribute value shall be a list of links to specification items. +spec-example: null +spec-info: + list: + description: null + spec-type: link +spec-name: Item Links Type +spec-type: links +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/list-str.yml b/rtemsspec/tests/spec-verify/spec/list-str.yml new file mode 100644 index 00000000..4d1246fb --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/list-str.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: | + This attribute value shall a list of strings. +spec-example: null +spec-info: + list: + description: null + spec-type: str +spec-name: String List Type +spec-type: list-str +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/optional-str.yml b/rtemsspec/tests/spec-verify/spec/optional-str.yml new file mode 100644 index 00000000..3f409247 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/optional-str.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + none: null + str: + description: null +spec-name: Optional String +spec-type: optional-str +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/root.yml b/rtemsspec/tests/spec-verify/spec/root.yml new file mode 100644 index 00000000..466d01a2 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/root.yml @@ -0,0 +1,39 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: [] +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + SPDX-License-Identifier: + description: | + This mandatory attribute defines the license of this item. + spec-type: spdx-license-identifier + copyrights: + description: | + This mandatory attribute defines the copyright holders and copyright + information of this item. + spec-type: copyrights + enabled-by: + description: | + This mandatory attribute defines the conditions under which this item + is enabled. + spec-type: enabled-by + links: + description: | + This mandatory attribute defines the links of this items to other + items. + spec-type: links + type: + description: | + This mandatory attribute defines the type of this item. + spec-type: name + description: | + This is the root specification item type. + mandatory-attributes: all +spec-name: Root Item Type +spec-type: root +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spdx-license-identifier.yml b/rtemsspec/tests/spec-verify/spec/spdx-license-identifier.yml new file mode 100644 index 00000000..380b61bc --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spdx-license-identifier.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + str: + assert: + - eq: CC-BY-SA-4.0 OR BSD-2-Clause + - eq: BSD-2-Clause + - eq: CC-BY-SA-4.0 + description: | + This attribute value defines the license of this item expressed though an + SPDX License Identifier. +spec-name: SPDX License Identifier +spec-type: spdx-license-identifier +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-assert-float-list.yml b/rtemsspec/tests/spec-verify/spec/spec-assert-float-list.yml new file mode 100644 index 00000000..30addf5c --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-assert-float-list.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + list: + description: null + spec-type: spec-assert-float +spec-name: Specification Floating-Point Assert List +spec-type: spec-assert-float-list +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-assert-float.yml b/rtemsspec/tests/spec-verify/spec/spec-assert-float.yml new file mode 100644 index 00000000..fd6f2564 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-assert-float.yml @@ -0,0 +1,71 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: | + A value of this type shall be an expression which asserts that the + floating-point value of the specified attribute satisfies the required + constraints. +spec-example: null +spec-info: + dict: + attributes: + and: + description: | + The *and* operator evaluates to the *logical and* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-float-list + eq: + description: | + The *eq* operator evaluates to true, if the value to check is equal + to the value of this attribute, otherwise to false. + spec-type: float + ge: + description: | + The *ge* operator evaluates to true, if the value to check is greater + than or equal to the value of this attribute, otherwise to false. + spec-type: float + gt: + description: | + The *gt* operator evaluates to true, if the value to check is greater + than the value of this attribute, otherwise to false. + spec-type: float + le: + description: | + The *le* operator evaluates to true, if the value to check is less + than or equal to the value of this attribute, otherwise to false. + spec-type: float + lt: + description: | + The *lt* operator evaluates to true, if the value to check is less + than the value of this attribute, otherwise to false. + spec-type: float + ne: + description: | + The *ne* operator evaluates to true, if the value to check is not + equal to the value of this attribute, otherwise to false. + spec-type: float + not: + description: | + The *not* operator evaluates to the *logical not* of the evaluation + results of the expression. + spec-type: spec-assert-float + or: + description: | + The *or* operator evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-float-list + description: | + Each attribute defines an operator. + mandatory-attributes: exactly-one + list: + description: | + This list of expressions evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-float +spec-name: Specification Floating-Point Assert +spec-type: spec-assert-float +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-assert-int-list.yml b/rtemsspec/tests/spec-verify/spec/spec-assert-int-list.yml new file mode 100644 index 00000000..98f20673 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-assert-int-list.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + list: + description: null + spec-type: spec-assert-int +spec-name: Specification Integer Assert List +spec-type: spec-assert-int-list +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-assert-int.yml b/rtemsspec/tests/spec-verify/spec/spec-assert-int.yml new file mode 100644 index 00000000..ec903b80 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-assert-int.yml @@ -0,0 +1,70 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: | + A value of this type shall be an expression which asserts that the integer + value of the specified attribute satisfies the required constraints. +spec-example: null +spec-info: + dict: + attributes: + and: + description: | + The *and* operator evaluates to the *logical and* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-int-list + eq: + description: | + The *eq* operator evaluates to true, if the value to check is equal + to the value of this attribute, otherwise to false. + spec-type: int + ge: + description: | + The *ge* operator evaluates to true, if the value to check is greater + than or equal to the value of this attribute, otherwise to false. + spec-type: int + gt: + description: | + The *gt* operator evaluates to true, if the value to check is greater + than the value of this attribute, otherwise to false. + spec-type: int + le: + description: | + The *le* operator evaluates to true, if the value to check is less + than or equal to the value of this attribute, otherwise to false. + spec-type: int + lt: + description: | + The *lt* operator evaluates to true, if the value to check is less + than the value of this attribute, otherwise to false. + spec-type: int + ne: + description: | + The *ne* operator evaluates to true, if the value to check is not + equal to the value of this attribute, otherwise to false. + spec-type: int + not: + description: | + The *not* operator evaluates to the *logical not* of the evaluation + results of the expression. + spec-type: spec-assert-int + or: + description: | + The *or* operator evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-int-list + description: | + Each attribute defines an operator. + mandatory-attributes: exactly-one + list: + description: | + This list of expressions evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-int +spec-name: Specification Integer Assert +spec-type: spec-assert-int +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-assert-str-list.yml b/rtemsspec/tests/spec-verify/spec/spec-assert-str-list.yml new file mode 100644 index 00000000..290c0bd9 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-assert-str-list.yml @@ -0,0 +1,16 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + list: + description: null + spec-type: spec-assert-str +spec-name: Specification String Assert List +spec-type: spec-assert-str-list +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-assert-str.yml b/rtemsspec/tests/spec-verify/spec/spec-assert-str.yml new file mode 100644 index 00000000..915da6ed --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-assert-str.yml @@ -0,0 +1,94 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: | + A value of this type shall be an expression which asserts that the string of + the specified attribute satisfies the required constraints. +spec-example: null +spec-info: + dict: + attributes: + and: + description: | + The *and* operator evaluates to the *logical and* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-str-list + contains: + description: | + The *contains* operator evaluates to true, if the string to check + converted to lower case with all white space characters converted to + a single space character contains a string of the list of strings of + this attribute, otherwise to false. + spec-type: list-str + eq: + description: | + The *eq* operator evaluates to true, if the string to check is equal + to the value of this attribute, otherwise to false. + spec-type: str + ge: + description: | + The *ge* operator evaluates to true, if the string to check is + greater than or equal to the value of this attribute, otherwise to + false. + spec-type: str + gt: + description: | + The *gt* operator evaluates to true, if the string to check is + greater than the value of this attribute, otherwise to false. + spec-type: str + in: + description: | + The *in* operator evaluates to true, if the string to check is + contained in the list of strings of this attribute, otherwise to + false. + spec-type: list-str + le: + description: | + The *le* operator evaluates to true, if the string to check is less + than or equal to the value of this attribute, otherwise to false. + spec-type: str + lt: + description: | + The *lt* operator evaluates to true, if the string to check is less + than the value of this attribute, otherwise to false. + spec-type: str + ne: + description: | + The *ne* operator evaluates to true, if the string to check is not + equal to the value of this attribute, otherwise to false. + spec-type: str + not: + description: | + The *not* operator evaluates to the *logical not* of the evaluation + results of the expression. + spec-type: spec-assert-str + or: + description: | + The *or* operator evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-str-list + re: + description: | + The *re* operator evaluates to true, if the string to check matches + with the regular expression of this attribute, otherwise to false. + spec-type: str + uid: + description: | + The *uid* operator evaluates to true, if the string is a valid UID, + otherwise to false. + spec-type: none + description: | + Each attribute defines an operator. + mandatory-attributes: exactly-one + list: + description: | + This list of expressions evaluates to the *logical or* of the evaluation + results of the expressions in the list. + spec-type: spec-assert-str +spec-name: Specification String Assert +spec-type: spec-assert-str +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-attribute-value.yml b/rtemsspec/tests/spec-verify/spec/spec-attribute-value.yml new file mode 100644 index 00000000..d44e2256 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-attribute-value.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + description: + description: | + It shall be the description of the attribute value. + spec-type: optional-str + spec-type: + description: | + It shall be the specification type of the attribute value. + spec-type: name + description: | + This set of attributes specifies an attribute value. + mandatory-attributes: all +spec-name: Specification Attribute Value +spec-type: spec-attribute-value +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-attributes.yml b/rtemsspec/tests/spec-verify/spec/spec-attributes.yml new file mode 100644 index 00000000..eb489783 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-attributes.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + generic-attributes: + description: | + Each generic attribute specifies an explicit attribute of the attribute + set. The key of the each generic attribute defines the attribute key + of the explicit attribute. + key-spec-type: name + value-spec-type: spec-attribute-value + mandatory-attributes: none +spec-name: Specification Explicit Attributes +spec-type: spec-attributes +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-bool.yml b/rtemsspec/tests/spec-verify/spec/spec-bool.yml new file mode 100644 index 00000000..e23f3b1f --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-bool.yml @@ -0,0 +1,33 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + assert: + description: | + This optional attribute defines the value constraint of the specified + boolean value. If the value of the assert attribute is true, then + the value of the specified boolean value shall be true. If the value + of the assert attribute is false, then the value of the specified + boolean value shall be false. In case the assert attribute is not + present, then the value of the specified boolean value may be true or + false. + spec-type: bool + description: + description: | + It shall be the description of the specified boolean value. + spec-type: optional-str + description: | + This attribute set specifies a boolean value. + mandatory-attributes: + - description +spec-name: Specification Boolean Value +spec-type: spec-bool +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-dict.yml b/rtemsspec/tests/spec-verify/spec/spec-dict.yml new file mode 100644 index 00000000..1fae4d15 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-dict.yml @@ -0,0 +1,37 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + attributes: + description: | + It shall specify the explicit attributes of the attribute set. + spec-type: spec-attributes + description: + description: | + It shall be the description of the attribute set. + spec-type: optional-str + generic-attributes: + description: | + It shall specify the generic attributes of the attribute set. + spec-type: spec-generic-attributes + mandatory-attributes: + description: | + It shall specify the mandatory attributes of the attribute set. + spec-type: spec-mandatory-attributes + description: | + This set of attributes specifies a set of attributes. + mandatory-attributes: + - attributes + - description + - mandatory-attributes +spec-name: Specification Attribute Set +spec-type: spec-dict +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-float.yml b/rtemsspec/tests/spec-verify/spec/spec-float.yml new file mode 100644 index 00000000..1f831eb8 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-float.yml @@ -0,0 +1,30 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + assert: + description: | + This optional attribute defines the value constraints of the + specified floating-point value. In case the assert attribute is not + present, then the value of the specified floating-point value may be + every valid floating-point number. + spec-type: spec-assert-float + description: + description: | + It shall be the description of the specified floating-point value. + spec-type: optional-str + description: | + This set of attributes specifies a floating-point value. + mandatory-attributes: + - description +spec-name: Specification Floating-Point Value +spec-type: spec-float +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-generic-attributes.yml b/rtemsspec/tests/spec-verify/spec/spec-generic-attributes.yml new file mode 100644 index 00000000..8f9b4180 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-generic-attributes.yml @@ -0,0 +1,33 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + description: + description: | + It shall be the description of the generic attributes. + spec-type: optional-str + key-spec-type: + description: | + It shall be the specification type of the generic attribute keys. + spec-type: name + value-spec-type: + description: | + It shall be the specification type of the generic attribute values. + spec-type: name + description: | + This set of attributes specifies generic attributes. Generic attributes + are attributes which are not explicitly specified by + ${spec-attributes:/spec-name}. They are restricted to uniform attribute + key and value types. + mandatory-attributes: all +spec-name: Specification Generic Attributes +spec-type: spec-generic-attributes +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-info.yml b/rtemsspec/tests/spec-verify/spec/spec-info.yml new file mode 100644 index 00000000..5bdbeee0 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-info.yml @@ -0,0 +1,46 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + bool: + description: | + It shall specify a boolean value. + spec-type: spec-bool + dict: + description: | + It shall specify a set of attributes. + spec-type: spec-dict + float: + description: | + It shall specify a floating-point value. + spec-type: spec-float + int: + description: | + It shall specify an integer value. + spec-type: spec-int + list: + description: | + It shall specify a list of attributes or values. + spec-type: spec-list + none: + description: | + It specifies that no value is required. + spec-type: none + str: + description: | + It shall specify a string. + spec-type: spec-str + description: | + This set of attributes specifies attribute values. + mandatory-attributes: at-least-one +spec-name: Specification Information +spec-type: spec-info +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-int.yml b/rtemsspec/tests/spec-verify/spec/spec-int.yml new file mode 100644 index 00000000..080a3a9d --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-int.yml @@ -0,0 +1,30 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + assert: + description: | + This optional attribute defines the value constraints of the + specified integer value. In case the assert attribute is not + present, then the value of the specified integer value may be every + valid integer number. + spec-type: spec-assert-int + description: + description: | + It shall be the description of the specified integer value. + spec-type: optional-str + description: | + This set of attributes specifies an integer value. + mandatory-attributes: + - description +spec-name: Specification Integer Value +spec-type: spec-int +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-list.yml b/rtemsspec/tests/spec-verify/spec/spec-list.yml new file mode 100644 index 00000000..b8f87807 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-list.yml @@ -0,0 +1,26 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + description: + description: | + It shall be the description of the list. + spec-type: optional-str + spec-type: + description: | + It shall be the specification type of elements of the list. + spec-type: name + description: | + This set of attributes specifies a list of attributes or values. + mandatory-attributes: all +spec-name: Specification List +spec-type: spec-list +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-mandatory-attributes.yml b/rtemsspec/tests/spec-verify/spec/spec-mandatory-attributes.yml new file mode 100644 index 00000000..700de958 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-mandatory-attributes.yml @@ -0,0 +1,30 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: | + It defines which explicit attributes are mandatory. +spec-example: null +spec-info: + list: + description: | + The list defines the mandatory attributes through their key names. + spec-type: name + str: + assert: + in: + - all + - at-least-one + - at-most-one + - exactly-one + - none + description: | + It defines how many explicit attributes are mandatory. If `none` is + used, then none of the explicit attributes is mandatory, they are all + optional. +spec-name: Specification Mandatory Attributes +spec-type: spec-mandatory-attributes +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-member.yml b/rtemsspec/tests/spec-verify/spec/spec-member.yml new file mode 100644 index 00000000..790500ef --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-member.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: role + spec-value: spec-member + uid: link +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: | + It defines the specification membership role of links. + mandatory-attributes: all +spec-name: Specification Member Link Role +spec-type: spec-member +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-refinement.yml b/rtemsspec/tests/spec-verify/spec/spec-refinement.yml new file mode 100644 index 00000000..8fd16da1 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-refinement.yml @@ -0,0 +1,32 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: role + spec-value: spec-refinement + uid: link +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + spec-key: + description: | + It shall be the specification type refinement attribute key of the + specification refinement. + spec-type: name + spec-value: + description: | + It shall be the specification type refinement attribute value of the + specification refinement. + spec-type: name + description: | + It defines the specification refinement role of links. + mandatory-attributes: all +spec-name: Specification Refinement Link Role +spec-type: spec-refinement +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec-str.yml b/rtemsspec/tests/spec-verify/spec/spec-str.yml new file mode 100644 index 00000000..f83dae5e --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec-str.yml @@ -0,0 +1,29 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + assert: + description: | + This optional attribute defines the constraints of the specified + string. In case the assert attribute is not present, then the + specified string may be every valid string. + spec-type: spec-assert-str + description: + description: | + It shall be the description of the specified string attribute. + spec-type: optional-str + description: | + This set of attributes specifies a string. + mandatory-attributes: + - description +spec-name: Specification String Value +spec-type: spec-str +type: spec diff --git a/rtemsspec/tests/spec-verify/spec/spec.yml b/rtemsspec/tests/spec-verify/spec/spec.yml new file mode 100644 index 00000000..e67e920e --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec/spec.yml @@ -0,0 +1,72 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: spec + uid: root +spec-description: null +spec-example: | + SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause + copyrights: + - Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + enabled-by: true + links: + - role: spec-member + uid: root + - role: spec-refinement + spec-key: type + spec-value: example + uid: root + spec-description: null + spec-example: null + spec-info: + dict: + attributes: + an-example-attribute: + description: | + It shall be an example. + spec-type: optional-str + example-number: + description: | + It shall be the example number. + spec-type: int + description: | + This set of attributes specifies an example. + mandatory-attributes: all + spec-name: Example Item Type + spec-type: spec + type: spec +spec-info: + dict: + attributes: + spec-description: + description: | + It shall be the description of the specification type. + spec-type: optional-str + spec-example: + description: | + If the value is present, then it shall be an example of the + specification type. + spec-type: optional-str + spec-info: + description: null + spec-type: spec-info + spec-name: + description: | + It shall be the human readable name of the specification type. + spec-type: optional-str + spec-type: + description: | + It shall the specification type. + spec-type: name + description: | + This set of attributes specifies specification types. + mandatory-attributes: all +spec-name: Specification Item Type +spec-type: spec +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/any-dict.yml b/rtemsspec/tests/spec-verify/spec2/any-dict.yml new file mode 100644 index 00000000..1f1176d9 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/any-dict.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: {} + generic-attributes: + key-spec-type: name + value-spec-type: str + mandatory-attributes: none +spec-type: any-dict +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/c.yml b/rtemsspec/tests/spec-verify/spec2/c.yml new file mode 100644 index 00000000..4154288c --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/c.yml @@ -0,0 +1,40 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +- role: spec-refinement + spec-key: type + spec-value: c + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: + any-dict: + spec-type: any-dict + bool: + spec-type: some-bool + dict: + spec-type: some-dict + float: + spec-type: some-float + int: + spec-type: some-int + list: + spec-type: some-list + must-be-true: + spec-type: must-be-true + other-int: + spec-type: other-int + str: + spec-type: some-str + str-contains: + spec-type: str-contains + uid: + spec-type: uid + mandatory-attributes: all +spec-type: c +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/d-a.yml b/rtemsspec/tests/spec-verify/spec2/d-a.yml new file mode 100644 index 00000000..e011310d --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/d-a.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +- role: spec-refinement + spec-key: d-type + spec-value: blub + uid: d +- role: other + uid: d +spec-example: null +spec-info: + dict: + attributes: + d-type: + spec-type: x + mandatory-attributes: none +spec-type: d-a +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/d.yml b/rtemsspec/tests/spec-verify/spec2/d.yml new file mode 100644 index 00000000..27089960 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/d.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +- role: spec-refinement + spec-key: type + spec-value: d + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: + d-type: + spec-type: name + mandatory-attributes: + - d-type +spec-type: d +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/invalid.yml b/rtemsspec/tests/spec-verify/spec2/invalid.yml new file mode 100644 index 00000000..a38e724f --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/invalid.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +- role: spec-refinement + spec-key: type + spec-value: spec-invalid + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: + INVALID: + spec-type: invalid + mandatory-attributes: none + none: true + str: + foo: bar + unexpected: null +spec-type: spec-invalid +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/keys-at-least-one.yml b/rtemsspec/tests/spec-verify/spec2/keys-at-least-one.yml new file mode 100644 index 00000000..2336efe1 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/keys-at-least-one.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +- role: spec-refinement + spec-key: type + spec-value: keys-at-least-one + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: + key-a: + spec-type: none + key-b: + spec-type: none + mandatory-attributes: at-least-one +spec-type: keys-at-least-one +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/keys-at-most-one.yml b/rtemsspec/tests/spec-verify/spec2/keys-at-most-one.yml new file mode 100644 index 00000000..b8fb29c5 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/keys-at-most-one.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +- role: spec-refinement + spec-key: type + spec-value: keys-at-most-one + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: + key-a: + spec-type: none + key-b: + spec-type: none + mandatory-attributes: at-most-one +spec-type: keys-at-most-one +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/keys-exactly-one.yml b/rtemsspec/tests/spec-verify/spec2/keys-exactly-one.yml new file mode 100644 index 00000000..c546d574 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/keys-exactly-one.yml @@ -0,0 +1,22 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +- role: spec-refinement + spec-key: type + spec-value: keys-exactly-one + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: + key-a: + spec-type: none + key-b: + spec-type: none + mandatory-attributes: exactly-one +spec-type: keys-exactly-one +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/must-be-true.yml b/rtemsspec/tests/spec-verify/spec2/must-be-true.yml new file mode 100644 index 00000000..eaf0ea14 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/must-be-true.yml @@ -0,0 +1,13 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + bool: + assert: true +spec-type: must-be-true +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/other-int.yml b/rtemsspec/tests/spec-verify/spec2/other-int.yml new file mode 100644 index 00000000..f0209c08 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/other-int.yml @@ -0,0 +1,12 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + int: {} +spec-type: other-int +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/some-bool.yml b/rtemsspec/tests/spec-verify/spec2/some-bool.yml new file mode 100644 index 00000000..3204d479 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/some-bool.yml @@ -0,0 +1,12 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + bool: {} +spec-type: some-bool +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/some-dict.yml b/rtemsspec/tests/spec-verify/spec2/some-dict.yml new file mode 100644 index 00000000..c0bd51b8 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/some-dict.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + dict: + attributes: + a: + spec-type: none + mandatory-attributes: none + none: null +spec-type: some-dict +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/some-float.yml b/rtemsspec/tests/spec-verify/spec2/some-float.yml new file mode 100644 index 00000000..114f6feb --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/some-float.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + float: + assert: + - le: 0.0 +spec-type: some-float +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/some-int.yml b/rtemsspec/tests/spec-verify/spec2/some-int.yml new file mode 100644 index 00000000..8f59d8a1 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/some-int.yml @@ -0,0 +1,42 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + int: + assert: + - and: + - not: + eq: 8 + - eq: 8 + - and: + - eq: 8 + - ne: 8 + - and: + - ge: 8 + - le: 8 + - and: + - gt: 8 + - lt: 8 + - and: + - le: 8 + - ge: 8 + - and: + - lt: 8 + - gt: 8 + - and: + - or: + - eq: 8 + - ne: 8 + - eq: 1 + - ne: 2 + - le: 3 + - lt: 4 + - ge: 5 + - gt: 6 +spec-type: some-int +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/some-list.yml b/rtemsspec/tests/spec-verify/spec2/some-list.yml new file mode 100644 index 00000000..b3b45086 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/some-list.yml @@ -0,0 +1,13 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + list: + spec-type: none +spec-type: some-list +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/some-str.yml b/rtemsspec/tests/spec-verify/spec2/some-str.yml new file mode 100644 index 00000000..c75aaf10 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/some-str.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + str: + assert: + - uid: null + - eq: abc + - ne: abc + - re: abc +spec-type: some-str +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/sta.yml b/rtemsspec/tests/spec-verify/spec2/sta.yml new file mode 100644 index 00000000..1c70a1ce --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/sta.yml @@ -0,0 +1,9 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: [] +spec-example: null +spec-info: {} +spec-type: a +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/str-contains.yml b/rtemsspec/tests/spec-verify/spec2/str-contains.yml new file mode 100644 index 00000000..fbd7b856 --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/str-contains.yml @@ -0,0 +1,20 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + str: + assert: + and: + - contains: + - abc + - def + - not: + contains: + - ghi +spec-type: str-contains +type: spec diff --git a/rtemsspec/tests/spec-verify/spec2/x.yml b/rtemsspec/tests/spec-verify/spec2/x.yml new file mode 100644 index 00000000..e96d281a --- /dev/null +++ b/rtemsspec/tests/spec-verify/spec2/x.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: /spec/root +spec-example: null +spec-info: + str: + assert: + eq: x +spec-type: x +type: spec diff --git a/rtemsspec/tests/spec/build-more.yml b/rtemsspec/tests/spec/build-more.yml new file mode 100644 index 00000000..fb35b357 --- /dev/null +++ b/rtemsspec/tests/spec/build-more.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: build-type + spec-value: test-program + uid: build +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Build More +spec-type: build-more +type: spec diff --git a/rtemsspec/tests/spec/build.yml b/rtemsspec/tests/spec/build.yml new file mode 100644 index 00000000..8329c6d4 --- /dev/null +++ b/rtemsspec/tests/spec/build.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: build + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + build-type: + description: null + spec-type: name + description: null + mandatory-attributes: all +spec-name: Build +spec-type: build +type: spec diff --git a/rtemsspec/tests/spec/constraint.yml b/rtemsspec/tests/spec/constraint.yml new file mode 100644 index 00000000..5e6af544 --- /dev/null +++ b/rtemsspec/tests/spec/constraint.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: constraint + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + requirement-type: + description: null + spec-type: name + description: null + mandatory-attributes: all +spec-name: Constraint +spec-type: constraint +type: spec diff --git a/rtemsspec/tests/spec/functional-more.yml b/rtemsspec/tests/spec/functional-more.yml new file mode 100644 index 00000000..dee60872 --- /dev/null +++ b/rtemsspec/tests/spec/functional-more.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: functional-type + spec-value: action + uid: functional +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Functional More +spec-type: functional-more +type: spec diff --git a/rtemsspec/tests/spec/functional.yml b/rtemsspec/tests/spec/functional.yml new file mode 100644 index 00000000..9ae9cfec --- /dev/null +++ b/rtemsspec/tests/spec/functional.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: requirement-type + spec-value: functional + uid: requirement +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + functional-type: + description: null + spec-type: name + description: null + mandatory-attributes: all +spec-name: Functional +spec-type: functional +type: spec diff --git a/rtemsspec/tests/spec/glossary-more.yml b/rtemsspec/tests/spec/glossary-more.yml new file mode 100644 index 00000000..bbcad8c3 --- /dev/null +++ b/rtemsspec/tests/spec/glossary-more.yml @@ -0,0 +1,25 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: glossary-type + spec-value: group + uid: glossary +- role: spec-refinement + spec-key: glossary-type + spec-value: term + uid: glossary +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Glossary More +spec-type: glossary-more +type: spec diff --git a/rtemsspec/tests/spec/glossary.yml b/rtemsspec/tests/spec/glossary.yml new file mode 100644 index 00000000..6a34d364 --- /dev/null +++ b/rtemsspec/tests/spec/glossary.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: glossary + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + glossary-type: + description: null + spec-type: name + description: null + mandatory-attributes: all +spec-name: Glossary +spec-type: glossary +type: spec diff --git a/rtemsspec/tests/spec/interface-appl-config-more.yml b/rtemsspec/tests/spec/interface-appl-config-more.yml new file mode 100644 index 00000000..8a8ecc56 --- /dev/null +++ b/rtemsspec/tests/spec/interface-appl-config-more.yml @@ -0,0 +1,33 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: appl-config-option-type + spec-value: feature + uid: interface-appl-config-option +- role: spec-refinement + spec-key: appl-config-option-type + spec-value: feature-enable + uid: interface-appl-config-option +- role: spec-refinement + spec-key: appl-config-option-type + spec-value: integer + uid: interface-appl-config-option +- role: spec-refinement + spec-key: appl-config-option-type + spec-value: initializer + uid: interface-appl-config-option +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Interface Application Configuration More +spec-type: interface-appl-config-more +type: spec diff --git a/rtemsspec/tests/spec/interface-appl-config-option.yml b/rtemsspec/tests/spec/interface-appl-config-option.yml new file mode 100644 index 00000000..bb6997b7 --- /dev/null +++ b/rtemsspec/tests/spec/interface-appl-config-option.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: interface-type + spec-value: appl-config-option + uid: interface +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Interface Application Configuration Option +spec-type: interface-appl-config-option +type: spec diff --git a/rtemsspec/tests/spec/interface-more.yml b/rtemsspec/tests/spec/interface-more.yml new file mode 100644 index 00000000..deaf1e60 --- /dev/null +++ b/rtemsspec/tests/spec/interface-more.yml @@ -0,0 +1,81 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: interface-type + spec-value: appl-config-group + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: struct + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: union + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: container + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: define + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: domain + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: enum + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: enumerator + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: forward-declaration + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: function + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: group + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: header-file + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: macro + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: typedef + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: unspecified + uid: interface +- role: spec-refinement + spec-key: interface-type + spec-value: variable + uid: interface +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Interface More +spec-type: interface-more +type: spec diff --git a/rtemsspec/tests/spec/interface.yml b/rtemsspec/tests/spec/interface.yml new file mode 100644 index 00000000..99ba9ac5 --- /dev/null +++ b/rtemsspec/tests/spec/interface.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: interface + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + build-type: + description: null + spec-type: name + description: null + mandatory-attributes: all +spec-name: Interface +spec-type: interface +type: spec diff --git a/rtemsspec/tests/spec/other.yml b/rtemsspec/tests/spec/other.yml new file mode 100644 index 00000000..ae7b8770 --- /dev/null +++ b/rtemsspec/tests/spec/other.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: other + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Other +spec-type: other +type: spec diff --git a/rtemsspec/tests/spec/requirement.yml b/rtemsspec/tests/spec/requirement.yml new file mode 100644 index 00000000..72efb21c --- /dev/null +++ b/rtemsspec/tests/spec/requirement.yml @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: requirement + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + requirement-type: + description: null + spec-type: name + description: null + mandatory-attributes: all +spec-name: Requirement +spec-type: requirement +type: spec diff --git a/rtemsspec/tests/spec/root.yml b/rtemsspec/tests/spec/root.yml new file mode 100644 index 00000000..4c3ea506 --- /dev/null +++ b/rtemsspec/tests/spec/root.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: [] +spec-description: null +spec-example: null +spec-info: + dict: + attributes: + type: + description: null + spec-type: name + description: null + mandatory-attributes: all +spec-name: Root +spec-type: root +type: spec diff --git a/rtemsspec/tests/spec/spec.yml b/rtemsspec/tests/spec/spec.yml new file mode 100644 index 00000000..b4e42b2e --- /dev/null +++ b/rtemsspec/tests/spec/spec.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: spec + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Spec +spec-type: spec +type: spec diff --git a/rtemsspec/tests/spec/test-case.yml b/rtemsspec/tests/spec/test-case.yml new file mode 100644 index 00000000..9eeeb674 --- /dev/null +++ b/rtemsspec/tests/spec/test-case.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: test-case + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Test Case +spec-type: test-case +type: spec diff --git a/rtemsspec/tests/spec/test-suite.yml b/rtemsspec/tests/spec/test-suite.yml new file mode 100644 index 00000000..8818c410 --- /dev/null +++ b/rtemsspec/tests/spec/test-suite.yml @@ -0,0 +1,21 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +links: +- role: spec-member + uid: root +- role: spec-refinement + spec-key: type + spec-value: test-suite + uid: root +spec-description: null +spec-example: null +spec-info: + dict: + attributes: {} + description: null + mandatory-attributes: all +spec-name: Test Suite +spec-type: test-suite +type: spec diff --git a/rtemsspec/tests/test_applconfig.py b/rtemsspec/tests/test_applconfig.py new file mode 100644 index 00000000..e98db813 --- /dev/null +++ b/rtemsspec/tests/test_applconfig.py @@ -0,0 +1,589 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.applconfig module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os + +from rtemsspec.applconfig import generate +from rtemsspec.items import ItemCache +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_applconfig(tmpdir): + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-applconfig", with_spec_types=True) + item_cache = ItemCache(item_cache_config) + + applconfig_config = {} + g_rst = os.path.join(tmpdir, "g.rst") + applconfig_config["groups"] = [{"uid": "/g", "target": g_rst}] + doxygen_h = os.path.join(tmpdir, "doxygen.h") + applconfig_config["doxygen-target"] = doxygen_h + generate(applconfig_config, item_cache) + + with open(g_rst, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +group name +========== + +description + +.. index:: a +.. index:: index a + +.. _a: + +a +- + +CONSTANT: + ``a`` + +OPTION TYPE: + This configuration option is a boolean feature define. + +DEFAULT CONFIGURATION: + default a + +DESCRIPTION: + description a + +NOTES: + notes a + + references: + + * :ref:`b` + + * :ref:`Terminate` + + * ``func()`` + + * ``td`` + +.. index:: b + +.. _b: + +b +- + +CONSTANT: + ``b`` + +OPTION TYPE: + This configuration option is a boolean feature define. + +DEFAULT CONFIGURATION: + If this configuration option is undefined, then the described feature is \ +not + enabled. + +DESCRIPTION: + description b + +NOTES: + None. + +.. index:: c + +.. _c: + +c +- + +CONSTANT: + ``c`` + +OPTION TYPE: + This configuration option is an integer define. + +DEFAULT VALUE: + The default value is 13. + +VALUE CONSTRAINTS: + The value of this configuration option shall satisfy all of the following + constraints: + + * It shall be greater than or equal to -1. + + * It shall be less than or equal to 99. + + * custom c 1 + + * custom c 2 + + * constraint d + +DESCRIPTION: + description c + +NOTES: + notes c + +.. index:: e + +.. _e: + +e +- + +CONSTANT: + ``e`` + +OPTION TYPE: + This configuration option is an integer define. + +DEFAULT VALUE: + The default value is 7. + +VALUE CONSTRAINTS: + The value of this configuration option shall be greater than or equal to \ +-2. + +DESCRIPTION: + description e + +NOTES: + None. + +.. index:: f + +.. _f: + +f +- + +CONSTANT: + ``f`` + +OPTION TYPE: + This configuration option is an integer define. + +DEFAULT VALUE: + The default value is 1. + +VALUE CONSTRAINTS: + The value of this configuration option shall be less than or equal to 2. + +DESCRIPTION: + description f + +NOTES: + None. + +.. index:: h + +.. _h: + +h +- + +CONSTANT: + ``h`` + +OPTION TYPE: + This configuration option is an integer define. + +DEFAULT VALUE: + The default value is 1. + +VALUE CONSTRAINTS: + custom h + +DESCRIPTION: + description h + +NOTES: + None. + +.. index:: i + +.. _i: + +i +- + +CONSTANT: + ``i`` + +OPTION TYPE: + This configuration option is an integer define. + +DEFAULT VALUE: + The default value is 1. + +VALUE CONSTRAINTS: + The value of this configuration option shall be + an element of {1, 2, 3}. + +DESCRIPTION: + description i + +NOTES: + None. + +.. index:: j + +.. _j: + +j +- + +CONSTANT: + ``j`` + +OPTION TYPE: + This configuration option is an integer define. + +DEFAULT VALUE: + Foo bar. + +VALUE CONSTRAINTS: + The value of this configuration option shall satisfy all of the following + constraints: + + * It shall be an element of [1, 2]. + + * constraint d + +DESCRIPTION: + description j + +NOTES: + None. + +.. index:: k + +.. _k: + +k +- + +CONSTANT: + ``k`` + +OPTION TYPE: + This configuration option is an integer define. + +DEFAULT VALUE: + The default value is 1. + +VALUE CONSTRAINTS: + The value of this configuration option shall satisfy all of the following + constraints: + + * custom k 1 + + * custom k 2 + +DESCRIPTION: + description k + +NOTES: + None. + +.. index:: l + +.. _l: + +l +- + +CONSTANT: + ``l`` + +OPTION TYPE: + This configuration option is an initializer define. + +DEFAULT VALUE: + The default value is 1. + +VALUE CONSTRAINTS: + The value of this configuration option shall be greater than or equal to 0 + and less than or equal to 2. + +DESCRIPTION: + description l + +NOTES: + None. + +.. index:: m + +.. _m: + +m +- + +CONSTANT: + ``m`` + +OPTION TYPE: + This configuration option is an initializer define. + +DEFAULT VALUE: + The default value is 1. + +DESCRIPTION: + description m + +NOTES: + None. +""" + assert content == src.read() + with open(doxygen_h, "r") as src: + content = """/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup RTEMSApplConfig Application Configuration Options + * + * @ingroup RTEMSAPI + */ + +/** + * @defgroup RTEMSApplConfiggroupname group name + * + * @ingroup RTEMSApplConfig + * + * description + * + * @{ + */ + +/** + * @brief This configuration option is a boolean feature define. + * + * description a + * + * @par Default Configuration + * default a + * + * @par Notes + * @parblock + * notes a + * + * references: + * + * * #b + * + * * <a + * href=https://docs.rtems.org/branches/master/c-user/fatal_error.html#announcing-a-fatal-error>Announcing + * a Fatal Error</a> + * + * * func() + * + * * ::td + * @endparblock + */ +#define a + +/** + * @brief This configuration option is a boolean feature define. + * + * description b + * + * @par Default Configuration + * If this configuration option is undefined, then the described feature is not + * enabled. + */ +#define b + +/** + * @brief This configuration option is an integer define. + * + * description c + * + * @par Default Value + * The default value is 13. + * + * @par Value Constraints + * @parblock + * The value of this configuration option shall satisfy all of the following + * constraints: + * + * * It shall be greater than or equal to -1. + * + * * It shall be less than or equal to 99. + * + * * custom c 1 + * + * * custom c 2 + * + * * constraint d + * @endparblock + * + * @par Notes + * notes c + */ +#define c + +/** + * @brief This configuration option is an integer define. + * + * description e + * + * @par Default Value + * The default value is 7. + * + * @par Value Constraints + * The value of this configuration option shall be greater than or equal to -2. + */ +#define e + +/** + * @brief This configuration option is an integer define. + * + * description f + * + * @par Default Value + * The default value is 1. + * + * @par Value Constraints + * The value of this configuration option shall be less than or equal to 2. + */ +#define f + +/** + * @brief This configuration option is an integer define. + * + * description h + * + * @par Default Value + * The default value is 1. + * + * @par Value Constraints + * custom h + */ +#define h + +/** + * @brief This configuration option is an integer define. + * + * description i + * + * @par Default Value + * The default value is 1. + * + * @par Value Constraints + * The value of this configuration option shall be an element of {1, 2, 3}. + */ +#define i + +/** + * @brief This configuration option is an integer define. + * + * description j + * + * @par Default Value + * Foo bar. + * + * @par Value Constraints + * @parblock + * The value of this configuration option shall satisfy all of the following + * constraints: + * + * * It shall be an element of [1, 2]. + * + * * constraint d + * @endparblock + */ +#define j + +/** + * @brief This configuration option is an integer define. + * + * description k + * + * @par Default Value + * The default value is 1. + * + * @par Value Constraints + * @parblock + * The value of this configuration option shall satisfy all of the following + * constraints: + * + * * custom k 1 + * + * * custom k 2 + * @endparblock + */ +#define k + +/** + * @brief This configuration option is an initializer define. + * + * description l + * + * @par Default Value + * The default value is 1. + * + * @par Value Constraints + * The value of this configuration option shall be greater than or equal to 0 + * and less than or equal to 2. + */ +#define l + +/** + * @brief This configuration option is an initializer define. + * + * description m + * + * @par Default Value + * The default value is 1. + */ +#define m + +/** @} */ +""" + assert content == src.read() diff --git a/rtemsspec/tests/test_build.py b/rtemsspec/tests/test_build.py new file mode 100644 index 00000000..28e971fb --- /dev/null +++ b/rtemsspec/tests/test_build.py @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.build module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from rtemsspec.build import gather_files +from rtemsspec.items import ItemCache +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_build(tmpdir): + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-build") + item_cache = ItemCache(item_cache_config) + + build_config = {} + build_config["arch"] = "foo" + build_config["bsp"] = "bar" + build_config["enabled"] = ["A"] + build_config["sources"] = ["a", "b"] + build_config["uids"] = ["/g"] + files = gather_files(build_config, item_cache) + assert files == ["a", "b", "stu", "jkl", "mno", "abc", "def"] diff --git a/rtemsspec/tests/test_content.py b/rtemsspec/tests/test_content.py new file mode 100644 index 00000000..27118e1a --- /dev/null +++ b/rtemsspec/tests/test_content.py @@ -0,0 +1,276 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.content module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import pytest + +from rtemsspec.content import Content, enabled_by_to_exp, \ + ExpressionMapper, PythonExpressionMapper + + +def test_tab(): + content = Content("BSD-2-Clause", True) + assert content.tab == " " + + +def test_append(): + content = Content("BSD-2-Clause", True) + content.append("") + assert str(content) == """ +""" + content.append(["a", "b"]) + assert str(content) == """ +a +b +""" + with content.indent(): + content.append(["c", "d"]) + assert str(content) == """ +a +b + c + d +""" + + +def test_prepend(): + content = Content("BSD-2-Clause", True) + content.prepend("") + assert str(content) == """ +""" + content.prepend(["a", "b"]) + assert str(content) == """a +b + +""" + with content.indent(): + content.prepend(["c", "d"]) + assert str(content) == """ c + d +a +b + +""" + + +def test_add(): + content = Content("BSD-2-Clause", True) + content.add("") + assert str(content) == "" + content.add("a") + assert str(content) == """a +""" + content.add(["b", "c"]) + assert str(content) == """a + +b +c +""" + + +def test_wrap(): + content = Content("BSD-2-Clause", True) + content.wrap("") + assert str(content) == "" + content.wrap("a") + assert str(content) == """a +""" + content.wrap(["b", "c"]) + assert str(content) == """a + +b c +""" + content.wrap(content) + assert str(content) == """a + +b c + +a + +b c +""" + content = Content("BSD-2-Clause", True) + content.wrap("\n") + assert str(content) == "" + content = Content("BSD-2-Clause", True) + content.wrap(["a", "", " b"]) + assert str(content) == """a + + b +""" + content = Content("BSD-2-Clause", True) + content.wrap([ + "a", "", "* b", + "cccccccccccc ddddddddddddddddd eeeeeeeeeeeeeeeeeeee ffffffffffffffff", + "ggggggggggggggggg hhhhhhhhhhhhhhhhhhhhhhhhh iiiiiiiiiiiiiiii", + "jjjjjjjjjjjjjjjjjjj" + ]) + assert str(content) == """a + +* b cccccccccccc ddddddddddddddddd eeeeeeeeeeeeeeeeeeee ffffffffffffffff + ggggggggggggggggg hhhhhhhhhhhhhhhhhhhhhhhhh iiiiiiiiiiiiiiii + jjjjjjjjjjjjjjjjjjj +""" + + +def test_paste(): + content = Content("BSD-2-Clause", True) + content.paste("") + assert str(content) == "" + content.paste("a") + assert str(content) == """a +""" + content.paste(["b", "c"]) + assert str(content) == """a b c +""" + content.paste(content) + assert str(content) == """a b c a b c +""" + content = Content("BSD-2-Clause", True) + content.paste("\n") + assert str(content) == "" + content.append("") + content.paste("a") + assert str(content) == """ +a +""" + content = Content("BSD-2-Clause", True) + content.paste(["a", "b", "", "c"]) + assert str(content) == """a b + +c +""" + content = Content("BSD-2-Clause", True) + content.paste(["a", "b", "", " c"]) + assert str(content) == """a b + + c +""" + + +def test_add_blank_line(): + content = Content("BSD-2-Clause", True) + content.add_blank_line() + assert str(content) == """ +""" + + +def test_indent(): + content = Content("BSD-2-Clause", True) + content.add_blank_line() + content.append("x") + content.indent_lines(3) + assert str(content) == """ + x +""" + + +def test_write(tmpdir): + content = Content("BSD-2-Clause", True) + content.append("x") + path = os.path.join(tmpdir, "x", "y") + content.write(path) + with open(path, "r") as src: + assert src.read() == """x +""" + tmpdir.chdir() + path = "z" + content.write(path) + with open(path, "r") as src: + assert src.read() == """x +""" + + +def to_c_exp(enabled_by): + return enabled_by_to_exp(enabled_by, ExpressionMapper()) + + +def test_enabled_by_to_exp(): + assert to_c_exp(True) == "1" + assert to_c_exp(False) == "0" + assert to_c_exp([]) == "" + assert to_c_exp(["A"]) == "defined(A)" + assert to_c_exp(["B"]) == "defined(B)" + assert to_c_exp(["A", "B"]) == "defined(A) || defined(B)" + assert to_c_exp({"not": "A"}) == "!defined(A)" + assert to_c_exp({"and": ["A", "B"]}) == "defined(A) && defined(B)" + assert to_c_exp({"and": ["A", "B", { + "not": "C" + }]}) == "defined(A) && defined(B) && !defined(C)" + assert to_c_exp( + { + "not": { + "and": + ["A", + { + "not": ["B", "C", + { + "and": ["D", + { + "not": "E" + }] + }] + }] + } + } + ) == "!(defined(A) && !(defined(B) || defined(C) || (defined(D) && !defined(E))))" + with pytest.raises(KeyError): + to_c_exp({"foo": "bar"}) + with pytest.raises(ValueError): + to_c_exp({"foo": "bar", "bla": "blub"}) + + +def to_python_exp(enabled_by): + return enabled_by_to_exp(enabled_by, PythonExpressionMapper()) + + +def test_enabled_by_to_python_exp(): + assert to_python_exp(True) == "True" + assert to_python_exp(False) == "False" + assert to_python_exp([]) == "" + assert to_python_exp(["A"]) == "A" + assert to_python_exp(["B"]) == "B" + assert to_python_exp(["A", "B"]) == "A or B" + assert to_python_exp({"not": "A"}) == "not A" + assert to_python_exp({"and": ["A", "B"]}) == "A and B" + assert to_python_exp({"and": ["A", "B", { + "not": "C" + }]}) == "A and B and not C" + assert to_python_exp({ + "not": { + "and": ["A", { + "not": ["B", "C", { + "and": ["D", { + "not": "E" + }] + }] + }] + } + }) == "not (A and not (B or C or (D and not E)))" + with pytest.raises(KeyError): + to_python_exp({"foo": "bar"}) + with pytest.raises(ValueError): + to_python_exp({"foo": "bar", "bla": "blub"}) diff --git a/rtemsspec/tests/test_content_c.py b/rtemsspec/tests/test_content_c.py new file mode 100644 index 00000000..81f15727 --- /dev/null +++ b/rtemsspec/tests/test_content_c.py @@ -0,0 +1,474 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.content module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import pytest + +from rtemsspec.content import CContent, CInclude + + +def test_doxyfy(): + content = CContent() + content.doxyfy(None) + assert str(content) == "" + content.doxyfy(" ") + assert str(content) == "" + content.doxyfy([" "]) + assert str(content) == "" + content.doxyfy(CContent()) + assert str(content) == "" + content.doxyfy(""".. code-block:: c + + abc + + def + +ghi + +.. code-block:: c +""") + assert str(content) == """@code +abc + +def +@endcode + +ghi + +@code +@endcode +""" + + +def test_add_have_config(): + content = CContent() + content.add_have_config() + assert str(content) == """#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +""" + content.add_have_config() + assert str(content) == """#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +""" + + +def test_add_includes(): + assert not CInclude("a") == "a" + content = CContent() + content.add_includes([]) + assert str(content) == "" + content = CContent() + content.add_includes([CInclude("a"), CInclude("a")]) + assert str(content) == """#include <a> +""" + content.add_includes([CInclude("b")]) + assert str(content) == """#include <a> + +#include <b> +""" + content = CContent() + content.add_includes([CInclude("c"), CInclude("b")], local=True) + assert str(content) == """#include "b" +#include "c" +""" + content = CContent() + content.add_includes([CInclude("d/f"), CInclude("d/e")]) + assert str(content) == """#include <d/e> +#include <d/f> +""" + content = CContent() + content.add_includes([CInclude("h"), CInclude("g/h")]) + assert str(content) == """#include <h> +#include <g/h> +""" + content = CContent() + content.add_includes([CInclude("i/l/k"), CInclude("i/j/k")]) + assert str(content) == """#include <i/j/k> +#include <i/l/k> +""" + content = CContent() + content.add_includes([CInclude("a", "X"), CInclude("a")]) + assert str(content) == """#if X + #include <a> +#endif +""" + content = CContent() + content.add_includes([CInclude("a"), CInclude("a", "X")]) + assert str(content) == """#if X + #include <a> +#endif +""" + content = CContent() + content.add_includes([CInclude("a", "X"), CInclude("b", "X")]) + assert str(content) == """#if X + #include <a> + #include <b> +#endif +""" + content = CContent() + content.add_includes( + [CInclude("a", "Y"), + CInclude("a", "X"), + CInclude("b", "X")]) + assert str(content) == """#if X + #include <b> +#endif + +#if X && Y + #include <a> +#endif +""" + + +def test_comment_block(): + content = CContent() + with content.comment_block(): + assert not content.gap + content.add("") + assert not content.gap + assert str(content) == """/* +""" + content.add("a") + assert content.gap + assert str(content) == """/* + * a +""" + content.add("b") + assert content.gap + assert str(content) == """/* + * a + * + * b +""" + content.gap = False + content.add("c") + assert content.gap + assert str(content) == """/* + * a + * + * b + * c +""" + + +def test_for_loop(): + content = CContent() + with content.for_loop("i = 0", "i < 3", "++i"): + content.add("j[i] = i;") + assert str(content) == """for ( i = 0; i < 3; ++i ) { + j[i] = i; +} +""" + content = CContent() + with content.for_loop("iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii = 0", + "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii < 3", + "++iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"): + content.add("j[i] = i;") + assert str(content) == """for ( + iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii = 0; + iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii < 3; + ++iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii +) { + j[i] = i; +} +""" + + +def test_add_brief_description(): + content = CContent() + content.add_brief_description("") + assert str(content) == "" + content.gap = True + content.add_brief_description( + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT " + "HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED " + "WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES " + "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE " + "DISCLAIMED.") + assert str(content) == """ +@brief THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. +""" + + +def test_add_param_description(): + content = CContent() + content.add_param_description([]) + assert str(content) == "" + params = [{"description": "A", "dir": None, "name": "a"}] + content.add_param_description(params) + assert str(content) == """@param a A +""" + content = CContent() + params = [ + { + "description": "A", + "dir": None, + "name": "a" + }, + { + "description": "B", + "dir": "in", + "name": "b" + }, + { + "description": "C", + "dir": "out", + "name": "c" + }, + { + "description": "D", + "dir": "inout", + "name": "d" + }, + ] + content.add_param_description(params, lambda x: x + x) + assert str(content) == """@param a AA + +@param[in] b BB + +@param[out] c CC + +@param[in,out] d DD +""" + + +def test_add_description_block(): + content = CContent() + content.add_description_block("", None) + assert str(content) == "" + content.add_description_block("a", "b") + assert str(content) == """/** + * @brief a + * + * b + */ +""" + content = CContent() + content.add_description_block("a", None) + assert str(content) == """/** + * @brief a + */ +""" + content = CContent() + content.add_description_block(None, "b") + assert str(content) == """/** + * b + */ +""" + + +def test_add_to_group(): + content = CContent() + with content.add_to_group("a"): + content.add("b") + assert str(content) == """/** + * @addtogroup a + * + * @{ + */ + +b + +/** @} */ +""" + + +def test_function(): + content = CContent() + content.call_function("a =", "b", []) + assert str(content) == """a = b(); +""" + content = CContent() + content.call_function(None, "a", [ + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ]) + assert str(content) == """a( + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +); +""" + content = CContent() + content.call_function( + None, + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + []) + assert str( + content + ) == """aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(); +""" + content = CContent() + content.call_function("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", []) + assert str(content) == """aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(); +""" + content = CContent() + content.declare_function("a", "b", []) + assert str(content) == """a b( void ); +""" + content = CContent() + content.declare_function("a *", "b", []) + assert str(content) == """a *b( void ); +""" + content = CContent() + content.declare_function("a", "b", ["..."]) + assert str(content) == """a b( ... ); +""" + content = CContent() + content.declare_function("a *", "b", [ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x", + "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy y", + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz z", "..." + ]) + assert str(content) == """a *b( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x, + yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy y, + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz z, + ... +); +""" + content = CContent() + content.declare_function( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", [ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x", + "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy *y", + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz *( *z )( void )" + ]) + assert str(content) == """aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x, + yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy *y, + zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz *( *z )( void ) +); +""" + content = CContent() + content.declare_function("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", []) + assert str(content) == """aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( void ); +""" + content = CContent() + with content.function("a", "b", []): + content.add("c") + assert str(content) == """a b( void ) +{ + c +} +""" + + +def test_condition(): + content = CContent() + with content.condition("a"): + content.add("b") + assert str(content) == """if ( a ) { + b +} +""" + content = CContent() + with content.first_condition("a"): + content.add("b") + with content.next_condition("c"): + content.add("d") + with content.final_condition(None): + content.add("e") + assert str(content) == """if ( a ) { + b +} else if ( c ) { + d +} else { + e +} +""" + + +def test_add_paragraph(): + content = CContent() + content.add_paragraph("a", "") + assert str(content) == "" + content.add_paragraph("a", "b") + assert str(content) == """@par a +b +""" + content = CContent() + with content.doxygen_block(): + content.add_paragraph("a", ["b", "", "c"]) + assert str(content) == """/** + * @par a + * @parblock + * b + * + * c + * @endparblock + */ +""" + + +def test_prepend_copyrights_and_licenses(): + content = CContent() + content.add("x") + assert str(content) == """x +""" + content.register_copyright("Copyright (C) 1234 Foo Bar") + content.prepend_copyrights_and_licenses() + content.prepend_spdx_license_identifier() + assert str(content) == """/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 1234 Foo Bar + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +x +""" diff --git a/rtemsspec/tests/test_content_copyrights.py b/rtemsspec/tests/test_content_copyrights.py new file mode 100644 index 00000000..b92c06bc --- /dev/null +++ b/rtemsspec/tests/test_content_copyrights.py @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.content module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import pytest + +from rtemsspec.content import Copyright +from rtemsspec.content import Copyrights + + +def test_copyright_get_statement(): + c = Copyright("John Doe") + assert "Copyright (C) John Doe" == c.get_statement() + c.add_year("3") + assert "Copyright (C) 3 John Doe" == c.get_statement() + c.add_year("3") + assert "Copyright (C) 3 John Doe" == c.get_statement() + c.add_year("5") + assert "Copyright (C) 3, 5 John Doe" == c.get_statement() + c.add_year("4") + assert "Copyright (C) 3, 5 John Doe" == c.get_statement() + c.add_year("2") + assert "Copyright (C) 2, 5 John Doe" == c.get_statement() + + +def test_copyright_lt(): + a = Copyright("A") + b = Copyright("B") + c = Copyright("C") + assert b < a + assert c < a + assert c < b + b.add_year("1") + assert b < c + a.add_year("2") + assert a < b + + +def test_copyrights_register(): + c = Copyrights() + with pytest.raises(ValueError): + c.register("abc") + c.register("Copyright (C) A") + c.register("Copyright (C) 2 A") + c.register("Copyright (C) 2, 3 A") + c.register("Copyright (C) D") + c.register("Copyright (C) 1 D") + c.register("Copyright (C) 1, 4 D") + c.register("Copyright (C) C") + c.register("Copyright (C) 1 B") + s = c.get_statements() + assert 4 == len(s) + assert "Copyright (C) C" == s[0] + assert "Copyright (C) 2, 3 A" == s[1] + assert "Copyright (C) 1, 4 D" == s[2] + assert "Copyright (C) 1 B" == s[3] diff --git a/rtemsspec/tests/test_content_sphinx.py b/rtemsspec/tests/test_content_sphinx.py new file mode 100644 index 00000000..6581b173 --- /dev/null +++ b/rtemsspec/tests/test_content_sphinx.py @@ -0,0 +1,274 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.sphinxcontent module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import pytest + +from rtemsspec.sphinxcontent import get_reference, get_label, \ + SphinxContent, SphinxMapper +from rtemsspec.items import Item, ItemCache, ItemMapper +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_add_label(): + content = SphinxContent() + content.add_label("x") + assert str(content) == """.. _x: +""" + + +def test_directive(): + content = SphinxContent() + with content.directive("x"): + content.add("y") + assert str(content) == """.. x:: + + y +""" + with content.directive("z", "xy", [":a:", ":b:"]): + content.add("c") + assert str(content) == """.. x:: + + y + +.. z:: xy + :a: + :b: + + c +""" + + +def test_add_header(): + content = SphinxContent() + content.add_header("x") + assert str(content) == """x += +""" + content.add_header("yz", 1) + assert str(content) == """x += + +yz +** +""" + + +def test_add_header_with_label(): + content = SphinxContent() + label = content.add_header_with_label("x", 1) + assert label == "SectionX" + assert str(content) == """.. _SectionX: + +x +* +""" + label = content.add_header_with_label("yz w", 2) + assert label == "SectionYzW" + assert str(content) == """.. _SectionX: + +x +* + +.. _SectionYzW: + +yz w +==== +""" + + +def test_get_reference(): + assert get_reference("a") == ":ref:`a`" + assert get_reference("a", "b") == ":ref:`b <a>`" + + +def test_get_label(): + assert get_label("ab cd") == "AbCd" + + +def test_section(): + content = SphinxContent() + with content.section("ab cd") as label: + content.add(label) + with content.section("ef gh") as label2: + content.add(label2) + assert str(content) == """.. _SectionAbCd: + +ab cd +===== + +SectionAbCd + +.. _SectionEfGh: + +ef gh +----- + +SectionEfGh +""" + + +def test_list_item(): + content = SphinxContent() + with content.list_item("ab cd"): + content.paste("ef gh") + with content.list_item("ij kl"): + content.add("mn op") + content.paste("qr st") + with content.list_item("uv"): + pass + content.add_list_item("wx") + assert str(content) == """* ab cd ef gh + + * ij kl + + mn op qr st + +* uv + +* wx +""" + + +def test_add_list(): + content = SphinxContent() + content.add_list([], "a") + assert str(content) == "" + content.add_list(["b", "c"], "a", "d") + assert str(content) == """a + +* b + +* c + +d +""" + content = SphinxContent() + content.add_list(["b", "c"], add_blank_line=True) + assert str(content) == """* b + +* c + +""" + + +def test_append(): + content = SphinxContent() + content.append("x") + assert str(content) == """x +""" + with content.indent(): + content.append("y") + assert str(content) == """x + y +""" + content.append("") + assert str(content) == """x + y + +""" + + +def test_add_index_entries(): + content = SphinxContent() + content.add_index_entries(["x", "y"]) + assert str(content) == """.. index:: x +.. index:: y +""" + content.add_index_entries("z") + assert str(content) == """.. index:: x +.. index:: y + +.. index:: z +""" + + +def test_add_definition_item(): + content = SphinxContent() + content.add_definition_item("x", ["y", "z"]) + assert str(content) == """x + y + z +""" + content = SphinxContent() + content.add_definition_item("a", "\n b\n") + assert str(content) == """a + b +""" + content = SphinxContent() + content.add_definition_item("a", "\n b\nc", wrap=True) + assert str(content) == """a + b c +""" + + +def test_definition_item(): + content = SphinxContent() + with content.definition_item("x"): + content.add(["y", "z"]) + assert str(content) == """x + y + z +""" + + +def test_license(): + content = SphinxContent() + with pytest.raises(ValueError): + content.register_license("x") + content.register_license("CC-BY-SA-4.0") + assert str(content) == "" + content.add_licence_and_copyrights() + assert str(content) == """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +""" + + +def test_license_and_copyrights(): + content = SphinxContent() + with pytest.raises(ValueError): + content.register_license("x") + content.register_copyright("Copyright (C) A") + assert str(content) == "" + content.add_licence_and_copyrights() + assert str(content) == """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) A + +""" + + +def test_substitute(tmpdir): + config = create_item_cache_config_and_copy_spec(tmpdir, + "spec-sphinx", + with_spec_types=True) + item_cache = ItemCache(config) + mapper = SphinxMapper(item_cache["/x"]) + with pytest.raises(KeyError): + mapper.substitute("${x:/y}") + assert mapper.substitute("${x:/term}") == ":term:`y`" + assert mapper.substitute("${x:/plural}") == ":term:`ys <y>`" + mapper.add_get_value("other:/name", lambda ctx: ctx.value[ctx.key]) + assert mapper.substitute("${y:/name}") == "foobar" diff --git a/rtemsspec/tests/test_glossary.py b/rtemsspec/tests/test_glossary.py new file mode 100644 index 00000000..2682b5da --- /dev/null +++ b/rtemsspec/tests/test_glossary.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.glossary module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os + +from rtemsspec.glossary import generate +from rtemsspec.items import ItemCache +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_glossary(tmpdir): + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-glossary", with_spec_types=True) + item_cache = ItemCache(item_cache_config) + + glossary_config = {} + glossary_config["project-groups"] = ["/g"] + project_glossary = os.path.join(tmpdir, "project", "glossary.rst") + glossary_config["project-target"] = project_glossary + doc = {} + doc["rest-source-paths"] = [str(tmpdir)] + document_glossary = os.path.join(tmpdir, "document", "glossary.rst") + doc["target"] = document_glossary + glossary_config["documents"] = [doc] + generate(glossary_config, item_cache) + + with open(project_glossary, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +Glossary +******** + +.. glossary:: + :sorted: + + T + Term text $:term:`U` :term:`T` + term. + + U + Term text U. + + V + Term text V. +""" + assert content == src.read() + + with open(document_glossary, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +Glossary +******** + +.. glossary:: + :sorted: + + T + Term text $:term:`U` :term:`T` + term. + + U + Term text U. +""" + assert content == src.read() diff --git a/rtemsspec/tests/test_interface.py b/rtemsspec/tests/test_interface.py new file mode 100644 index 00000000..c6aa625b --- /dev/null +++ b/rtemsspec/tests/test_interface.py @@ -0,0 +1,354 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.interface module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import pytest + +from rtemsspec.interface import generate +from rtemsspec.items import EmptyItemCache, ItemCache +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_interface(tmpdir): + interface_config = {} + interface_config["item-level-interfaces"] = [] + base_directory = os.path.join(tmpdir, "base") + interface_domains = {"/domain-abc": base_directory} + interface_config["domains"] = interface_domains + + generate(interface_config, EmptyItemCache()) + + interface_config["item-level-interfaces"] = ["/command-line"] + + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-interface", with_spec_types=True) + generate(interface_config, ItemCache(item_cache_config)) + + with open(os.path.join(base_directory, "include", "h.h"), "r") as src: + content = """/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup GroupA + * @ingroup GroupB + * @ingroup GroupC + */ + +/* + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _H_H +#define _H_H + +#include <h3.h> +#include <math.h> +#include <stdint.h> + +#if !defined(ASM) && defined(RTEMS_SMP) + #include <h2.h> +#endif + +#if defined(ASM) && defined(RTEMS_SMP) + #include <h4.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup GroupA Group A + * + * @brief Group A brief description. + * + * Group A description. + */ + +/** + * @defgroup GroupB Group B + * + * @ingroup GroupA + */ + +/* Forward declaration */ +struct Struct; + +/** + * @ingroup GroupB + * + * @brief Enum brief description. + * + * Enum description. + */ +typedef enum { + /** + * @brief Enumerator 0 brief description. + */ + ENUMERATOR_0, + + /** + * @brief Enumerator 1 brief description. + */ + ENUMERATOR_1, + + /** + * @brief Enumerator 2 brief description. + */ + ENUMERATOR_2 +} Enum; + +/** + * @ingroup GroupA + */ +#if defined(A) || (B > C) + #define DEFINE ((float_t) 456) +#elif defined(C) && defined(D) + #define DEFINE ((float_t) 789) +#else + #define DEFINE \\ + ((float_t) 123) +#endif + +/** + * @ingroup GroupB + * + * @brief Enum B brief description. + */ +typedef enum EnumB { + /** + * @brief Enumerator B brief description. + */ + ENUMERATOR_B = ENUMERATOR_A +} EnumB; + +/** + * @ingroup GroupA + * + * @brief Function brief description. + * + * Function description. References to VeryLongFunction(), ::Integer, #Enum, + * #DEFINE, #VERY_LONG_MACRO, #Variable, ::ENUMERATOR_0, Struct, a, and + * interface. + * + * @param Param0 is parameter 0. + * + * @param[in] Param1 is parameter 1. + * + * @param[out] Param2 is parameter 2. + * + * @param[in,out] Param3 is parameter 3. + */ +void Function( int Param0, const int *Param1, int *Param2, int *Param3 ); + +/** + * @ingroup GroupB + * + * @brief Very long function brief description. + * + * VeryLongFunction description. + * + * VeryLongFunction notes. + * + * @param VeryLongParam0 is very long parameter 0 with some super important and + * extra very long description which makes a lot of sense. + * + * @param[in] VeryLongParam1 is very long parameter 1. + * + * @param[out] VeryLongParam2 is very long parameter 2. + * + * @param[in,out] VeryLongParam3 is very long parameter 3. + * + * @retval 1 is returned, in case A. + * + * @retval 2 is returned, in case B. + * + * @return Sometimes some value. See Function(). + */ +static inline int VeryLongFunction( + int VeryLongParam0, + const struct Struct *VeryLongParam1, + struct Struct *( *VeryLongParam2 )( void ), + struct Struct *VeryLongParam3 +) +{ + (void) VeryLongParam1; + (void) VeryLongParam2; + (void) VeryLongParam3; + return VeryLongParam0 + 1; +} + +/** + * @ingroup GroupB + * + * @brief Very long macro brief description. + * + * @param VeryLongParam0 is very long parameter 0 with some super important and + * extra very long description which makes a lot of sense. + * + * @param[in] VeryLongParam1 is very long parameter 1. + * + * @param[out] VeryLongParam2 is very long parameter 2. + * + * @param[in,out] VeryLongParam3 is very long parameter 3. + * + * @retval 1 is returned, in case A. + * + * @retval 2 is returned, in case B. + * + * @return Sometimes some value. + */ +#define VERY_LONG_MACRO( \\ + VeryLongParam0, \\ + VeryLongParam1, \\ + VeryLongParam2, \\ + VeryLongParam3 \\ +) \\ + do { \\ + (void) VeryLongParam1; \\ + (void) VeryLongParam2; \\ + (void) VeryLongParam3; \\ + } while ( 0 ); \\ + VeryLongParam0 + 1; + +/** + * @ingroup GroupB + * + * @brief Short macro brief description. + * + * @param Param0 is parameter 0. + * + * @return Sometimes some value. + */ +#if 0 + #define MACRO( Param0 ) +#else + #define MACRO( Param0 ) ( ( Param0 ) + 1 ) +#endif + +/** + * @ingroup GroupC + */ +struct Struct { + /** + * @brief Brief union description. + * + * Union description. + */ + union { + /** + * @brief Brief member description. + * + * Member description. + */ + uint32_t some_member; + + /** + * @brief Brief struct description. + * + * struct description. + */ + struct { + /** + * @brief Brief member 2 description. + * + * Member 2 description. + */ + uint32_t some_member_2; + + /** + * @brief Brief member 3 description. + * + * Member 3 description. + */ + Enum some_member_3; + } some_struct; + } some_union; + + /** + * @brief Brief member 4 description. + * + * Member 4 description. + */ + Enum some_member_4; +}; + +/** + * @ingroup GroupB + * + * @brief Typedef Integer brief description. + * + * Typedef Integer description. + */ +typedef uint32_t Integer /* Some comment. */; + +/** + * @ingroup GroupB + */ +#if defined(RTEMS_SMP) + typedef uint32_t Integer3; +#endif + +#if !defined(ASM) + /** + * @ingroup GroupC + * + * @brief Variable brief description. + * + * Variable description. + */ + extern struct Struct *Variable; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _H_H */ +""" + assert content == src.read() diff --git a/rtemsspec/tests/test_interfacedoc.py b/rtemsspec/tests/test_interfacedoc.py new file mode 100644 index 00000000..b9948fc8 --- /dev/null +++ b/rtemsspec/tests/test_interfacedoc.py @@ -0,0 +1,224 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.interfacedoc module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import pytest + +from rtemsspec.interfacedoc import generate +from rtemsspec.items import EmptyItemCache, ItemCache +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_interfacedoc(tmpdir): + doc_config = {} + doc_config["group"] = "/gb" + introduction_rst = os.path.join(tmpdir, "introduction.rst") + doc_config["introduction-target"] = introduction_rst + directives_rst = os.path.join(tmpdir, "directives.rst") + doc_config["directives-target"] = directives_rst + + doc_config_2 = {} + doc_config_2["group"] = "/ga" + introduction_2_rst = os.path.join(tmpdir, "introduction-2.rst") + doc_config_2["introduction-target"] = introduction_2_rst + directives_2_rst = os.path.join(tmpdir, "directives-2.rst") + doc_config_2["directives-target"] = directives_2_rst + + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-interface", with_spec_types=True) + generate([doc_config, doc_config_2], ItemCache(item_cache_config)) + + with open(introduction_rst, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +.. _GroupBIntroduction: + +Introduction +============ + +The directives provided by the Group B are: + +* :ref:`VeryLongFunction() <InterfaceVeryLongFunction>` - Very long function + brief description. + +* :ref:`VeryLongTypeFunction() <InterfaceVeryLongTypeFunction>` - Function + brief description with very long return type. + +* :ref:`VoidFunction() <InterfaceVoidFunction>` +""" + assert content == src.read() + + with open(directives_rst, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +.. _GroupBDirectives: + +Directives +========== + +.. _InterfaceVeryLongFunction: + +VeryLongFunction() +------------------ + +Very long function brief description. + +CALLING SEQUENCE: + .. code-block:: c + + int VeryLongFunction( + int VeryLongParam0, + const struct Struct *VeryLongParam1, + struct Struct *( *VeryLongParam2 )( void ), + struct Struct *VeryLongParam3 + ); + +DIRECTIVE PARAMETERS: + VeryLongParam0 + This parameter is very long parameter 0 with some super important and + extra very long description which makes a lot of sense. + + VeryLongParam1 + This parameter is very long parameter 1. + + VeryLongParam2 + This parameter is very long parameter 2. + + VeryLongParam3 + This parameter is very long parameter 3. + +DIRECTIVE RETURN VALUES: + 1 + is returned, in case A. + + 2 + is returned, in case B. + + Sometimes some value. See :ref:`Function() <InterfaceFunction>`. + +DESCRIPTION: + VeryLongFunction description. + +NOTES: + VeryLongFunction notes. + +.. _InterfaceVeryLongTypeFunction: + +VeryLongTypeFunction() +---------------------- + +Function brief description with very long return type. + +CALLING SEQUENCE: + .. code-block:: c + + #if 1 + NotSoVeryLongType VeryLongTypeFunction( void ); + #else + VeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongType + VeryLongTypeFunction( void ); + #endif + +DIRECTIVE RETURN VALUES: + This function returns an object with a very long type. + +.. _InterfaceVoidFunction: + +VoidFunction() +-------------- + +CALLING SEQUENCE: + .. code-block:: c + + #if 1 + void VoidFunction( void ); + #endif +""" + assert content == src.read() + + with open(introduction_2_rst, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +.. _GroupAIntroduction: + +Introduction +============ + +Group A brief description. + +Group A description. The directives provided by the Group A are: + +* :ref:`Function() <InterfaceFunction>` - Function brief description. +""" + assert content == src.read() + + with open(directives_2_rst, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +.. _GroupADirectives: + +Directives +========== + +.. _InterfaceFunction: + +Function() +---------- + +Function brief description. + +CALLING SEQUENCE: + .. code-block:: c + + void Function( int Param0, const int *Param1, int *Param2, int *Param3 ); + +DIRECTIVE PARAMETERS: + Param0 + This parameter is parameter 0. + + Param1 + This parameter is parameter 1. + + Param2 + This parameter is parameter 2. + + Param3 + This parameter is parameter 3. + +DESCRIPTION: + Function description. References to :ref:`VeryLongFunction() + <InterfaceVeryLongFunction>`, Integer, Enum, DEFINE, VERY_LONG_MACRO, + Variable, ENUMERATOR_0, Struct, :ref:`a`, and interface. +""" + assert content == src.read() diff --git a/rtemsspec/tests/test_items_item.py b/rtemsspec/tests/test_items_item.py new file mode 100644 index 00000000..511349ab --- /dev/null +++ b/rtemsspec/tests/test_items_item.py @@ -0,0 +1,196 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.items module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import pytest + +from rtemsspec.items import EmptyItemCache, Item, ItemCache, Link + + +def test_to_abs_uid(): + item = Item(EmptyItemCache(), "/x/y", {}) + assert item.to_abs_uid(".") == "/x/y" + assert item.to_abs_uid("z") == "/x/z" + assert item.to_abs_uid("/z") == "/z" + assert item.to_abs_uid("../z") == "/z" + assert item.to_abs_uid("../../z") == "/z" + + +def test_uid(): + item = Item(EmptyItemCache(), "x", {}) + assert item.uid == "x" + + +def test_contains(): + data = {} + data["x"] = "y" + item = Item(EmptyItemCache(), "z", data) + assert "x" in item + assert "a" not in item + + +def test_data(): + data = {} + data["x"] = "y" + item = Item(EmptyItemCache(), "z", data) + assert item.data == {"x": "y"} + + +def test_get_key_path(): + data = {} + data["a"] = {"b": "c", "d": [1, 2, 3]} + data["x"] = "y" + item = Item(EmptyItemCache(), "z", data) + assert item.get_by_key_path("x") == "y" + assert item.get_by_key_path("a/d[2]") == 3 + assert item.get_by_key_path("a/b/../d[0]") == 1 + assert item.get_by_key_path("/a/b/../d[0]") == 1 + assert item.get_by_key_path("../d[0]", "a/b") == 1 + with pytest.raises(KeyError): + assert item.get_by_key_path("y") + with pytest.raises(ValueError): + assert item.get_by_key_path("[") + with pytest.raises(ValueError): + assert item.get_by_key_path("x[y]") + + +def test_getitem(): + data = {} + data["x"] = "y" + item = Item(EmptyItemCache(), "z", data) + assert item["x"] == "y" + + +def test_setitem(): + data = {} + item = Item(EmptyItemCache(), "z", data) + with pytest.raises(KeyError): + item["a"] + item["a"] = "b" + assert item["a"] == "b" + + +def test_get(): + data = {} + data["x"] = "y" + item = Item(EmptyItemCache(), "z", data) + assert item.get("x", "z") == "y" + assert item.get("z", "a") == "a" + + +def test_children(): + child = Item(EmptyItemCache(), "c", {}) + parent = Item(EmptyItemCache(), "p", {}) + parent.add_link_to_child(Link(child, {"a": "b", "role": "c"})) + children = [item for item in parent.children()] + assert len(children) == 1 + assert children[0] == child + children = [item for item in parent.children("c")] + assert len(children) == 1 + assert children[0] == child + children = [item for item in parent.children("d")] + assert len(children) == 0 + links = [link for link in parent.links_to_children()] + assert len(links) == 1 + assert links[0].item == child + assert links[0]["a"] == "b" + assert links[0].role == "c" + + +def test_parents(): + item_cache = EmptyItemCache() + child = Item(item_cache, "c", + {"links": [{ + "a": "b", + "role": "c", + "uid": "p" + }]}) + parent = Item(item_cache, "p", {"links": []}) + item_cache._items["p"] = parent + child.init_parents(item_cache) + for link in child.links_to_parents(): + link.item.add_link_to_child(Link.create(link, child)) + parents = [item for item in child.parents()] + assert len(parents) == 1 + assert parents[0] == parent + parents = [item for item in child.parents("c")] + assert len(parents) == 1 + assert parents[0] == parent + parents = [item for item in child.parents("d")] + assert len(parents) == 0 + links = [link for link in child.links_to_parents()] + assert len(links) == 1 + assert links[0].item == parent + assert links[0]["a"] == "b" + assert links[0].role == "c" + + +def _is_enabled(enabled, enabled_by): + item = Item(EmptyItemCache(), "i", {"enabled-by": enabled_by}) + return item.is_enabled(enabled) + + +def test_is_enabled(): + assert _is_enabled([], True) + assert not _is_enabled([], False) + assert not _is_enabled([], []) + assert not _is_enabled([], ["A"]) + assert _is_enabled(["A"], "A") + assert not _is_enabled(["B"], "A") + assert _is_enabled(["A"], ["A"]) + assert not _is_enabled(["B"], ["A"]) + assert _is_enabled(["A"], ["A", "B"]) + assert _is_enabled(["B"], ["A", "B"]) + assert not _is_enabled(["C"], ["A", "B"]) + assert not _is_enabled(["A"], {"not": "A"}) + assert _is_enabled(["B"], {"not": "A"}) + assert not _is_enabled(["A"], {"and": ["A", "B"]}) + assert _is_enabled(["A", "B"], {"and": ["A", "B"]}) + assert _is_enabled(["A", "B", "C"], {"and": ["A", "B"]}) + assert _is_enabled(["A", "B"], {"and": ["A", "B", {"not": "C"}]}) + assert not _is_enabled(["A", "B", "C"], {"and": ["A", "B", {"not": "C"}]}) + with pytest.raises(KeyError): + _is_enabled(["A"], {"x": "A"}) + assert _is_enabled([], {"not": {"and": ["A", {"not": "A"}]}}) + + +def test_save_and_load(tmpdir): + item_file = os.path.join(tmpdir, "i.yml") + item = Item(EmptyItemCache(), "i", {"k": "v"}) + item.file = item_file + assert item.file == item_file + item.save() + with open(item_file, "r") as src: + assert src.read() == "k: v\n" + assert item.file == item_file + + item2 = Item(EmptyItemCache(), "i2", {}) + item2.file = item_file + with pytest.raises(KeyError): + item2["k"] + item2.load() + assert item2["k"] == "v" + assert item.file == item_file diff --git a/rtemsspec/tests/test_items_itemcache.py b/rtemsspec/tests/test_items_itemcache.py new file mode 100644 index 00000000..678ae2b2 --- /dev/null +++ b/rtemsspec/tests/test_items_itemcache.py @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.items module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import pytest + +from rtemsspec.items import EmptyItem, ItemCache, ItemMapper, ItemTemplate +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_config_error(): + with pytest.raises(KeyError): + ItemCache({}) + + +def test_load(tmpdir): + config = create_item_cache_config_and_copy_spec(tmpdir, "spec-item-cache") + item_cache = ItemCache(config) + cache_dir = config["cache-directory"] + assert os.path.exists(os.path.join(cache_dir, "spec", "spec.pickle")) + assert os.path.exists(os.path.join(cache_dir, "spec", "d", "spec.pickle")) + assert item_cache["/d/c"]["v"] == "c" + assert item_cache["/p"]["v"] == "p" + t = item_cache.top_level + assert len(t) == 1 + p = t["/p"] + assert p["v"] == "p" + assert p.map("/p") == p + assert p.map("p") == p + a = item_cache.all + assert len(a) == 2 + assert a["/p"]["v"] == "p" + assert a["/d/c"]["v"] == "c" + item_cache_2 = ItemCache(config) + assert item_cache_2["/d/c"]["v"] == "c" + with open(os.path.join(tmpdir, "spec", "d", "c.yml"), "w+") as out: + out.write("links:\n- role: null\n uid: ../p\nv: x\n") + item_cache_3 = ItemCache(config) + assert item_cache_3["/d/c"]["v"] == "x" + + +class Mapper(ItemMapper): + def __init__(self, item): + super().__init__(item) + + def u(self, value): + return "u" + value + + def v(self, value): + return "v" + value + + def dup(self, value): + return value + value + + def get_value(self, ctx): + if ctx.key == "x-to-b": + return ctx.value["b"] + raise KeyError + + +def test_item_mapper(tmpdir): + config = create_item_cache_config_and_copy_spec(tmpdir, "spec-item-cache") + item_cache = ItemCache(config) + item = item_cache["/p"] + base_mapper = ItemMapper(item) + assert base_mapper["d/c:v"] == "c" + mapper = Mapper(item) + assert mapper.substitute(None) == "" + assert mapper.substitute_with_prefix(None, "v") == "" + with mapper.prefix("v"): + assert mapper[".:."] == "p" + assert mapper[".:../x/y"] == "z" + item_2, value_2 = mapper.map(".:.") + assert item == item_2 + assert value_2 == "p" + assert mapper.substitute("$$${.:.}") == "$p" + assert mapper.substitute_with_prefix("$$${.:.}", "v") == "$p" + with mapper.prefix("x"): + with mapper.prefix("y"): + assert mapper[".:."] == "z" + assert mapper["."] == "/p" + assert mapper["d/c"] == "/d/c" + assert mapper["d/c:v"] == "c" + assert mapper["d/c:a/b"] == "e" + assert mapper["d/c:a/b|u"] == "ue" + assert mapper["d/c:a/x-to-b|u|v"] == "vue" + assert mapper["d/c:a/f[1]"] == 2 + assert mapper["d/c:a/../a/f[3]/g[0]|dup"] == 8 + item_3, value_3 = mapper.map("/p:/v") + assert item == item_3 + assert value_3 == "p" + with pytest.raises(StopIteration): + for something in mapper: + pass + with pytest.raises(AttributeError): + len(mapper) + + +def test_empty_item_mapper(): + item = EmptyItem() + mapper = ItemMapper(item) + assert mapper.item == item + item_2 = EmptyItem() + mapper.item = item_2 + assert mapper.item == item_2 diff --git a/rtemsspec/tests/test_specdoc.py b/rtemsspec/tests/test_specdoc.py new file mode 100644 index 00000000..0ac432e9 --- /dev/null +++ b/rtemsspec/tests/test_specdoc.py @@ -0,0 +1,291 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.specdoc module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os + +from rtemsspec.items import ItemCache +from rtemsspec.specdoc import document +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_document(tmpdir): + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-doc") + item_cache_config["spec-type-root-uid"] = "/root" + item_cache = ItemCache(item_cache_config) + assert item_cache["/root"].type == "spec" + doc_target = os.path.join(tmpdir, "items.rst") + config = { + "root-type": "/root", + "doc-target": doc_target, + } + document(config, item_cache) + with open(doc_target, "r") as src: + content = """.. SPDX-License-Identifier: CC-BY-SA-4.0 + +.. Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + +.. _ReqEngSpecificationItems: + +Specification Items +=================== + +.. _ReqEngSpecificationItemHierarchy: + +Specification Item Hierarchy +---------------------------- + +The specification item types have the following hierarchy: + +* :ref:`SpecTypeRoot` + + * :ref:`SpecTypeA` + + * :ref:`SpecTypeB` + +.. _ReqEngSpecificationItemTypes: + +Specification Item Types +------------------------ + +.. _SpecTypeRoot: + +Root +^^^^ + +A value of this type shall be of one of the following variants: + +* The value may be a boolean. A reference to :ref:`SpecTypeRoot`. The value + shall be true. + +* The value may be a set of attributes. All explicit attributes shall be + specified. The explicit attributes for this type are: + + type + The attribute value shall be a :ref:`SpecTypeName`. + + In addition to the explicit attributes, generic attributes may be specified. + Each generic attribute key shall be a :ref:`SpecTypeName`. Each generic + attribute value shall be a :ref:`SpecTypeRoot`. + +* The value may be a floating-point number. The value shall be equal to 0.0. + +* The value may be an integer number. The value shall be equal to 0. + +* The value may be a list. Each list element shall be a :ref:`SpecTypeRoot`. + +* There may by be no value (null). + +* The value may be a string. The value + + * shall meet, + + * shall contain an element of + + * "``a``", + + * "``b``", and + + * "``c``", + + * and, shall be equal to "``d``", + + * and, shall be greater than or equal to "``e``", + + * and, shall be greater than "``f``", + + * and, shall be an element of + + * "``g``", and + + * "``h``", + + * and, shall be less than or equal to "``i``", + + * and, shall be less than "``j``", + + * and, shall be not equal to "``k``", + + * and, shall match with the regular expression "``l"``, + + * and, shall be true, + + * and, shall be a valid item UID, + + * or, + + * shall be an element of, + + * or, shall be an element of + + * "``x``", + + * or, shall not meet, + + * shall not contain an element of + + * "``a``", + + * "``b``", and + + * "``c``", + + * or, shall be not equal to "``d``", + + * or, shall be less than "``e``", + + * or, shall be less than or equal to "``f``", + + * or, shall not be an element of + + * "``g``", and + + * "``h``", + + * or, shall be greater than "``i``", + + * or, shall be greater than or equal to "``j``", + + * or, shall be equal to "``k``", + + * or, shall not match with the regular expression "``l"``, + + * or, shall be false, + + * or, shall be an invalid item UID. + +This type is refined by the following types: + +* :ref:`SpecTypeA` + +* :ref:`SpecTypeB` + +This type is used by the following types: + +* :ref:`SpecTypeRoot` + +.. _SpecTypeA: + +A +^ + +This type refines the :ref:`SpecTypeRoot` though the ``type`` attribute if the +value is ``spec``. + +The explicit attributes for this type are: + +a + The attribute value shall be an :ref:`SpecTypeA`. + +This type is used by the following types: + +* :ref:`SpecTypeA` + +Please have a look at the following example: + +.. code-block:: yaml + + a: null + +.. _SpecTypeB: + +B +^ + +This type refines the following types: + +* :ref:`SpecTypeD` though the ``d1`` attribute if the value is ``b`` + +* :ref:`SpecTypeRoot` though the ``type`` attribute if the value is ``b`` + +Generic attributes may be specified. Each generic attribute key shall be a +:ref:`SpecTypeName`. Each generic attribute value shall be a list. Each list +element shall be a string. + +.. _ReqEngSpecificationAttributeSetsAndValueTypes: + +Specification Attribute Sets and Value Types +-------------------------------------------- + +.. _SpecTypeC: + +C +^ + +Only the ``c`` attribute is mandatory. The explicit attributes for this type +are: + +c + The attribute value shall be a floating-point number. + +.. _SpecTypeD: + +D +^ + +The following explicit attributes are mandatory: + +* ``d1`` + +* ``d2`` + +The explicit attributes for this type are: + +d1 + The attribute value shall be a :ref:`SpecTypeName`. + +d2 + The attribute shall have no value. + +This type is refined by the following types: + +* :ref:`SpecTypeB` + +.. _SpecTypeName: + +Name +^^^^ + +The value shall be a string. A string is a valid name if it matches with the +``^([a-z][a-z0-9-]*|SPDX-License-Identifier)$`` regular expression. + +This type is used by the following types: + +* :ref:`SpecTypeB` + +* :ref:`SpecTypeD` + +* :ref:`SpecTypeRoot` + +.. _SpecTypeUID: + +UID +^^^ + +The value shall be a string. The string shall be a valid absolute or relative +item UID. +""" + assert content == src.read() diff --git a/rtemsspec/tests/test_specverify.py b/rtemsspec/tests/test_specverify.py new file mode 100644 index 00000000..076a6fab --- /dev/null +++ b/rtemsspec/tests/test_specverify.py @@ -0,0 +1,1909 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.specverify module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import logging + +from rtemsspec.items import ItemCache +from rtemsspec.specverify import verify +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_no_root_type(caplog, tmpdir): + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-verify") + item_cache = ItemCache(item_cache_config) + config = {} + caplog.set_level(logging.INFO) + verify(config, item_cache) + log = "\n".join( + [f"{rec.levelname} {rec.message}" for rec in caplog.records]) + assert log == """ERROR configuration has no root type""" + + +def test_no_root_item(caplog, tmpdir): + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-verify") + item_cache = ItemCache(item_cache_config) + config = {"root-type": "/nix"} + caplog.set_level(logging.INFO) + verify(config, item_cache) + log = "\n".join( + [f"{rec.levelname} {rec.message}" for rec in caplog.records]) + assert log == """ERROR root type item does not exist in item cache""" + + +def test_verify(caplog, tmpdir): + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-verify") + item_cache = ItemCache(item_cache_config) + config = {"root-type": "/spec/root"} + caplog.set_level(logging.INFO) + verify(config, item_cache) + log = "\n".join( + [f"{rec.levelname} {rec.message}" for rec in caplog.records]) + assert log == """INFO type: any-dict +INFO type: bool +INFO type: c +INFO type: copyright +INFO type: copyrights +INFO type: d +INFO add subtype 'd-a' to 'd' +INFO type: d-a +INFO type: enabled-by +INFO type: enabled-by-list +INFO type: float +INFO type: int +INFO type: keys-at-least-one +INFO type: keys-at-most-one +INFO type: keys-exactly-one +INFO type: link +INFO add subtype 'spec-member' to 'link' +INFO add subtype 'spec-refinement' to 'link' +INFO type: links +INFO type: list-str +INFO type: must-be-true +INFO type: name +INFO type: none +INFO type: optional-str +INFO type: other-int +INFO type: root +INFO add subtype 'spec' to 'root' +INFO add subtype 'c' to 'root' +INFO add subtype 'd' to 'root' +INFO add subtype 'spec-invalid' to 'root' +INFO add subtype 'keys-at-least-one' to 'root' +INFO add subtype 'keys-at-most-one' to 'root' +INFO add subtype 'keys-exactly-one' to 'root' +INFO type: some-bool +INFO type: some-dict +INFO type: some-float +INFO type: some-int +INFO type: some-list +INFO type: some-str +INFO type: spdx-license-identifier +INFO type: spec +INFO type: spec-assert-float +INFO type: spec-assert-float-list +INFO type: spec-assert-int +INFO type: spec-assert-int-list +INFO type: spec-assert-str +INFO type: spec-assert-str-list +INFO type: spec-attribute-value +INFO type: spec-attributes +INFO type: spec-bool +INFO type: spec-dict +INFO type: spec-float +INFO type: spec-generic-attributes +INFO type: spec-info +INFO type: spec-int +INFO type: spec-invalid +INFO type: spec-list +INFO type: spec-mandatory-attributes +INFO type: spec-member +INFO type: spec-refinement +INFO type: spec-str +INFO type: str +INFO type: str-contains +INFO type: uid +INFO type: x +INFO start specification item verification +INFO /c1: verify using type 'root' +INFO /c1:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /c1:/copyrights: verify using type 'copyrights' +INFO /c1:/copyrights[0]: verify using type 'copyright' +INFO /c1:/enabled-by: verify using type 'enabled-by' +INFO /c1:/links: verify using type 'links' +INFO /c1:/links[0]: verify using type 'link' +INFO /c1:/links[0]/role: verify using type 'name' +INFO /c1:/links[0]/uid: verify using type 'uid' +ERROR /c1:/links[0]: unknown subtype for key 'role' for type 'link': x +INFO /c1:/type: verify using type 'name' +INFO /c1: verify using type 'c' +ERROR /c1: missing mandatory keys for type 'c': ['any-dict', 'bool', 'float', 'int', 'must-be-true', 'other-int', 'str', 'str-contains'] +INFO /c1:/dict: verify using type 'some-dict' +INFO /c1:/dict/a: verify using type 'none' +INFO /c1:/list: verify using type 'some-list' +INFO /c1:/uid: verify using type 'uid' +ERROR /c1:/uid: expected type 'str', actual type 'int' +INFO /c2: verify using type 'root' +INFO /c2:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /c2:/copyrights: verify using type 'copyrights' +INFO /c2:/copyrights[0]: verify using type 'copyright' +INFO /c2:/enabled-by: verify using type 'enabled-by' +INFO /c2:/links: verify using type 'links' +INFO /c2:/type: verify using type 'name' +INFO /c2: verify using type 'c' +ERROR /c2: missing mandatory keys for type 'c': ['any-dict', 'bool', 'float', 'int', 'must-be-true', 'other-int', 'str', 'uid'] +INFO /c2:/dict: verify using type 'some-dict' +ERROR /c2:/dict: has unverfied keys for type 'some-dict' and its subtypes: ['b'] +INFO /c2:/list: verify using type 'some-list' +INFO /c2:/str-contains: verify using type 'str-contains' +ERROR /c2:/str-contains: invalid value: uvw +INFO /c3: verify using type 'root' +INFO /c3:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /c3:/copyrights: verify using type 'copyrights' +INFO /c3:/copyrights[0]: verify using type 'copyright' +INFO /c3:/enabled-by: verify using type 'enabled-by' +INFO /c3:/links: verify using type 'links' +INFO /c3:/type: verify using type 'name' +INFO /c3: verify using type 'c' +ERROR /c3: missing mandatory keys for type 'c': ['any-dict', 'bool', 'float', 'int', 'other-int'] +INFO /c3:/dict: verify using type 'some-dict' +ERROR /c3:/dict: expected value of types ['dict', 'none'] for type 'some-dict', actual type 'list' +INFO /c3:/list: verify using type 'some-list' +ERROR /c3:/list: expected value of types ['list'] for type 'some-list', actual type 'dict' +INFO /c3:/must-be-true: verify using type 'must-be-true' +ERROR /c3:/must-be-true: expected True, actual False +INFO /c3:/str: verify using type 'some-str' +INFO /c3:/str-contains: verify using type 'str-contains' +ERROR /c3:/str-contains: invalid value: abc ghi +INFO /c3:/uid: verify using type 'uid' +ERROR /c3:/uid: cannot resolve UID: nix +INFO /c4: verify using type 'root' +INFO /c4:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /c4:/copyrights: verify using type 'copyrights' +INFO /c4:/copyrights[0]: verify using type 'copyright' +INFO /c4:/enabled-by: verify using type 'enabled-by' +INFO /c4:/links: verify using type 'links' +INFO /c4:/type: verify using type 'name' +INFO /c4: verify using type 'c' +INFO /c4:/any-dict: verify using type 'any-dict' +INFO /c4:/any-dict/a: verify using type 'name' +INFO /c4:/any-dict/a: verify using type 'str' +INFO /c4:/bool: verify using type 'some-bool' +INFO /c4:/dict: verify using type 'some-dict' +INFO /c4:/float: verify using type 'some-float' +ERROR /c4:/float: invalid value: 123.567 +INFO /c4:/int: verify using type 'some-int' +INFO /c4:/list: verify using type 'some-list' +INFO /c4:/must-be-true: verify using type 'must-be-true' +INFO /c4:/other-int: verify using type 'other-int' +INFO /c4:/str: verify using type 'some-str' +WARNING /c4:/str: cannot resolve UID: abc +INFO /c4:/str-contains: verify using type 'str-contains' +INFO /c4:/uid: verify using type 'uid' +INFO /d: verify using type 'root' +INFO /d:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /d:/copyrights: verify using type 'copyrights' +INFO /d:/copyrights[0]: verify using type 'copyright' +INFO /d:/enabled-by: verify using type 'enabled-by' +INFO /d:/links: verify using type 'links' +INFO /d:/type: verify using type 'name' +INFO /d: verify using type 'd' +INFO /d:/d-type: verify using type 'name' +INFO /d: verify using type 'd-a' +INFO /d:/d-type: verify using type 'x' +ERROR /d:/d-type: invalid value: blub +INFO /d2: verify using type 'root' +INFO /d2:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /d2:/copyrights: verify using type 'copyrights' +INFO /d2:/copyrights[0]: verify using type 'copyright' +INFO /d2:/enabled-by: verify using type 'enabled-by' +INFO /d2:/links: verify using type 'links' +INFO /d2:/type: verify using type 'name' +INFO /d2: verify using type 'd' +INFO /d2:/d-type: verify using type 'name' +ERROR /d2: unknown subtype for key 'd-type' for type 'd': bla +INFO /d3: verify using type 'root' +INFO /d3:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /d3:/copyrights: verify using type 'copyrights' +INFO /d3:/copyrights[0]: verify using type 'copyright' +INFO /d3:/enabled-by: verify using type 'enabled-by' +INFO /d3:/links: verify using type 'links' +INFO /d3:/type: verify using type 'name' +INFO /d3: verify using type 'd' +ERROR /d3: missing mandatory keys for type 'd': ['d-type'] +ERROR /d3: subtype key 'd-type' not present for type 'd' +INFO /e: verify using type 'root' +INFO /e:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /e:/copyrights: verify using type 'copyrights' +INFO /e:/copyrights[0]: verify using type 'copyright' +INFO /e:/enabled-by: verify using type 'enabled-by' +INFO /e:/links: verify using type 'links' +INFO /e:/type: verify using type 'name' +ERROR /e: unknown subtype for key 'type' for type 'root': e +INFO /invalid: verify using type 'root' +INFO /invalid:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /invalid:/copyrights: verify using type 'copyrights' +INFO /invalid:/copyrights[0]: verify using type 'copyright' +INFO /invalid:/enabled-by: verify using type 'enabled-by' +INFO /invalid:/links: verify using type 'links' +INFO /invalid:/type: verify using type 'name' +INFO /invalid: verify using type 'spec-invalid' +ERROR /invalid: unknown specification type: invalid +INFO /keys-at-least-one-0: verify using type 'root' +INFO /keys-at-least-one-0:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-at-least-one-0:/copyrights: verify using type 'copyrights' +INFO /keys-at-least-one-0:/copyrights[0]: verify using type 'copyright' +INFO /keys-at-least-one-0:/enabled-by: verify using type 'enabled-by' +INFO /keys-at-least-one-0:/links: verify using type 'links' +INFO /keys-at-least-one-0:/type: verify using type 'name' +INFO /keys-at-least-one-0: verify using type 'keys-at-least-one' +ERROR /keys-at-least-one-0: not at least one key out of ['key-a', 'key-b'] is present for type 'keys-at-least-one' +INFO /keys-at-least-one-1: verify using type 'root' +INFO /keys-at-least-one-1:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-at-least-one-1:/copyrights: verify using type 'copyrights' +INFO /keys-at-least-one-1:/copyrights[0]: verify using type 'copyright' +INFO /keys-at-least-one-1:/enabled-by: verify using type 'enabled-by' +INFO /keys-at-least-one-1:/links: verify using type 'links' +INFO /keys-at-least-one-1:/type: verify using type 'name' +INFO /keys-at-least-one-1: verify using type 'keys-at-least-one' +INFO /keys-at-least-one-1:/key-a: verify using type 'none' +INFO /keys-at-least-one-2: verify using type 'root' +INFO /keys-at-least-one-2:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-at-least-one-2:/copyrights: verify using type 'copyrights' +INFO /keys-at-least-one-2:/copyrights[0]: verify using type 'copyright' +INFO /keys-at-least-one-2:/enabled-by: verify using type 'enabled-by' +INFO /keys-at-least-one-2:/links: verify using type 'links' +INFO /keys-at-least-one-2:/type: verify using type 'name' +INFO /keys-at-least-one-2: verify using type 'keys-at-least-one' +INFO /keys-at-least-one-2:/key-a: verify using type 'none' +INFO /keys-at-least-one-2:/key-b: verify using type 'none' +INFO /keys-at-most-one-0: verify using type 'root' +INFO /keys-at-most-one-0:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-at-most-one-0:/copyrights: verify using type 'copyrights' +INFO /keys-at-most-one-0:/copyrights[0]: verify using type 'copyright' +INFO /keys-at-most-one-0:/enabled-by: verify using type 'enabled-by' +INFO /keys-at-most-one-0:/links: verify using type 'links' +INFO /keys-at-most-one-0:/type: verify using type 'name' +INFO /keys-at-most-one-0: verify using type 'keys-at-most-one' +INFO /keys-at-most-one-1: verify using type 'root' +INFO /keys-at-most-one-1:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-at-most-one-1:/copyrights: verify using type 'copyrights' +INFO /keys-at-most-one-1:/copyrights[0]: verify using type 'copyright' +INFO /keys-at-most-one-1:/enabled-by: verify using type 'enabled-by' +INFO /keys-at-most-one-1:/links: verify using type 'links' +INFO /keys-at-most-one-1:/type: verify using type 'name' +INFO /keys-at-most-one-1: verify using type 'keys-at-most-one' +INFO /keys-at-most-one-1:/key-a: verify using type 'none' +INFO /keys-at-most-one-2: verify using type 'root' +INFO /keys-at-most-one-2:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-at-most-one-2:/copyrights: verify using type 'copyrights' +INFO /keys-at-most-one-2:/copyrights[0]: verify using type 'copyright' +INFO /keys-at-most-one-2:/enabled-by: verify using type 'enabled-by' +INFO /keys-at-most-one-2:/links: verify using type 'links' +INFO /keys-at-most-one-2:/type: verify using type 'name' +INFO /keys-at-most-one-2: verify using type 'keys-at-most-one' +ERROR /keys-at-most-one-2: not at most one key out of ['key-a', 'key-b'] is present for type 'keys-at-most-one': ['key-a', 'key-b'] +INFO /keys-at-most-one-2:/key-a: verify using type 'none' +INFO /keys-at-most-one-2:/key-b: verify using type 'none' +INFO /keys-exactly-one-0: verify using type 'root' +INFO /keys-exactly-one-0:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-exactly-one-0:/copyrights: verify using type 'copyrights' +INFO /keys-exactly-one-0:/copyrights[0]: verify using type 'copyright' +INFO /keys-exactly-one-0:/enabled-by: verify using type 'enabled-by' +INFO /keys-exactly-one-0:/links: verify using type 'links' +INFO /keys-exactly-one-0:/type: verify using type 'name' +INFO /keys-exactly-one-0: verify using type 'keys-exactly-one' +ERROR /keys-exactly-one-0: not exactly one key out of ['key-a', 'key-b'] is present for type 'keys-exactly-one': [] +INFO /keys-exactly-one-1: verify using type 'root' +INFO /keys-exactly-one-1:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-exactly-one-1:/copyrights: verify using type 'copyrights' +INFO /keys-exactly-one-1:/copyrights[0]: verify using type 'copyright' +INFO /keys-exactly-one-1:/enabled-by: verify using type 'enabled-by' +INFO /keys-exactly-one-1:/links: verify using type 'links' +INFO /keys-exactly-one-1:/type: verify using type 'name' +INFO /keys-exactly-one-1: verify using type 'keys-exactly-one' +INFO /keys-exactly-one-1:/key-a: verify using type 'none' +INFO /keys-exactly-one-2: verify using type 'root' +INFO /keys-exactly-one-2:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /keys-exactly-one-2:/copyrights: verify using type 'copyrights' +INFO /keys-exactly-one-2:/copyrights[0]: verify using type 'copyright' +INFO /keys-exactly-one-2:/enabled-by: verify using type 'enabled-by' +INFO /keys-exactly-one-2:/links: verify using type 'links' +INFO /keys-exactly-one-2:/type: verify using type 'name' +INFO /keys-exactly-one-2: verify using type 'keys-exactly-one' +ERROR /keys-exactly-one-2: not exactly one key out of ['key-a', 'key-b'] is present for type 'keys-exactly-one': ['key-a', 'key-b'] +INFO /keys-exactly-one-2:/key-a: verify using type 'none' +INFO /keys-exactly-one-2:/key-b: verify using type 'none' +INFO /notype: verify using type 'root' +ERROR /notype: missing mandatory keys for type 'root': ['type'] +INFO /notype:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /notype:/copyrights: verify using type 'copyrights' +INFO /notype:/copyrights[0]: verify using type 'copyright' +INFO /notype:/enabled-by: verify using type 'enabled-by' +INFO /notype:/links: verify using type 'links' +ERROR /notype: subtype key 'type' not present for type 'root' +INFO /spec/copyright: verify using type 'root' +INFO /spec/copyright:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/copyright:/copyrights: verify using type 'copyrights' +INFO /spec/copyright:/copyrights[0]: verify using type 'copyright' +INFO /spec/copyright:/enabled-by: verify using type 'enabled-by' +INFO /spec/copyright:/links: verify using type 'links' +INFO /spec/copyright:/links[0]: verify using type 'link' +INFO /spec/copyright:/links[0]/role: verify using type 'name' +INFO /spec/copyright:/links[0]/uid: verify using type 'uid' +INFO /spec/copyright:/links[0]: verify using type 'spec-member' +INFO /spec/copyright:/type: verify using type 'name' +INFO /spec/copyright: verify using type 'spec' +INFO /spec/copyright:/spec-description: verify using type 'optional-str' +INFO /spec/copyright:/spec-example: verify using type 'optional-str' +INFO /spec/copyright:/spec-info: verify using type 'spec-info' +INFO /spec/copyright:/spec-info/str: verify using type 'spec-str' +INFO /spec/copyright:/spec-info/str/assert: verify using type 'spec-assert-str' +INFO /spec/copyright:/spec-info/str/assert[0]: verify using type 'spec-assert-str' +INFO /spec/copyright:/spec-info/str/assert[0]/re: verify using type 'str' +INFO /spec/copyright:/spec-info/str/assert[1]: verify using type 'spec-assert-str' +INFO /spec/copyright:/spec-info/str/assert[1]/re: verify using type 'str' +INFO /spec/copyright:/spec-info/str/assert[2]: verify using type 'spec-assert-str' +INFO /spec/copyright:/spec-info/str/assert[2]/re: verify using type 'str' +INFO /spec/copyright:/spec-info/str/description: verify using type 'optional-str' +INFO /spec/copyright:/spec-name: verify using type 'optional-str' +INFO /spec/copyright:/spec-type: verify using type 'name' +INFO /spec/copyrights: verify using type 'root' +INFO /spec/copyrights:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/copyrights:/copyrights: verify using type 'copyrights' +INFO /spec/copyrights:/copyrights[0]: verify using type 'copyright' +INFO /spec/copyrights:/enabled-by: verify using type 'enabled-by' +INFO /spec/copyrights:/links: verify using type 'links' +INFO /spec/copyrights:/links[0]: verify using type 'link' +INFO /spec/copyrights:/links[0]/role: verify using type 'name' +INFO /spec/copyrights:/links[0]/uid: verify using type 'uid' +INFO /spec/copyrights:/links[0]: verify using type 'spec-member' +INFO /spec/copyrights:/type: verify using type 'name' +INFO /spec/copyrights: verify using type 'spec' +INFO /spec/copyrights:/spec-description: verify using type 'optional-str' +INFO /spec/copyrights:/spec-example: verify using type 'optional-str' +INFO /spec/copyrights:/spec-info: verify using type 'spec-info' +INFO /spec/copyrights:/spec-info/list: verify using type 'spec-list' +INFO /spec/copyrights:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/copyrights:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/copyrights:/spec-name: verify using type 'optional-str' +INFO /spec/copyrights:/spec-type: verify using type 'name' +INFO /spec/enabled-by: verify using type 'root' +INFO /spec/enabled-by:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/enabled-by:/copyrights: verify using type 'copyrights' +INFO /spec/enabled-by:/copyrights[0]: verify using type 'copyright' +INFO /spec/enabled-by:/enabled-by: verify using type 'enabled-by' +INFO /spec/enabled-by:/links: verify using type 'links' +INFO /spec/enabled-by:/links[0]: verify using type 'link' +INFO /spec/enabled-by:/links[0]/role: verify using type 'name' +INFO /spec/enabled-by:/links[0]/uid: verify using type 'uid' +INFO /spec/enabled-by:/links[0]: verify using type 'spec-member' +INFO /spec/enabled-by:/type: verify using type 'name' +INFO /spec/enabled-by: verify using type 'spec' +INFO /spec/enabled-by:/spec-description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-example: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-info: verify using type 'spec-info' +INFO /spec/enabled-by:/spec-info/bool: verify using type 'spec-bool' +INFO /spec/enabled-by:/spec-info/bool/description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/enabled-by:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/enabled-by:/spec-info/dict/attributes/and: verify using type 'name' +INFO /spec/enabled-by:/spec-info/dict/attributes/and: verify using type 'spec-attribute-value' +INFO /spec/enabled-by:/spec-info/dict/attributes/and/description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-info/dict/attributes/and/spec-type: verify using type 'name' +INFO /spec/enabled-by:/spec-info/dict/attributes/not: verify using type 'name' +INFO /spec/enabled-by:/spec-info/dict/attributes/not: verify using type 'spec-attribute-value' +INFO /spec/enabled-by:/spec-info/dict/attributes/not/description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-info/dict/attributes/not/spec-type: verify using type 'name' +INFO /spec/enabled-by:/spec-info/dict/attributes/or: verify using type 'name' +INFO /spec/enabled-by:/spec-info/dict/attributes/or: verify using type 'spec-attribute-value' +INFO /spec/enabled-by:/spec-info/dict/attributes/or/description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-info/dict/attributes/or/spec-type: verify using type 'name' +INFO /spec/enabled-by:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/enabled-by:/spec-info/list: verify using type 'spec-list' +INFO /spec/enabled-by:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/enabled-by:/spec-info/str: verify using type 'spec-str' +INFO /spec/enabled-by:/spec-info/str/description: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-name: verify using type 'optional-str' +INFO /spec/enabled-by:/spec-type: verify using type 'name' +INFO /spec/enabled-by-list: verify using type 'root' +INFO /spec/enabled-by-list:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/enabled-by-list:/copyrights: verify using type 'copyrights' +INFO /spec/enabled-by-list:/copyrights[0]: verify using type 'copyright' +INFO /spec/enabled-by-list:/enabled-by: verify using type 'enabled-by' +INFO /spec/enabled-by-list:/links: verify using type 'links' +INFO /spec/enabled-by-list:/links[0]: verify using type 'link' +INFO /spec/enabled-by-list:/links[0]/role: verify using type 'name' +INFO /spec/enabled-by-list:/links[0]/uid: verify using type 'uid' +INFO /spec/enabled-by-list:/links[0]: verify using type 'spec-member' +INFO /spec/enabled-by-list:/type: verify using type 'name' +INFO /spec/enabled-by-list: verify using type 'spec' +INFO /spec/enabled-by-list:/spec-description: verify using type 'optional-str' +INFO /spec/enabled-by-list:/spec-example: verify using type 'optional-str' +INFO /spec/enabled-by-list:/spec-info: verify using type 'spec-info' +INFO /spec/enabled-by-list:/spec-info/list: verify using type 'spec-list' +INFO /spec/enabled-by-list:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/enabled-by-list:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/enabled-by-list:/spec-name: verify using type 'optional-str' +INFO /spec/enabled-by-list:/spec-type: verify using type 'name' +INFO /spec/link: verify using type 'root' +INFO /spec/link:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/link:/copyrights: verify using type 'copyrights' +INFO /spec/link:/copyrights[0]: verify using type 'copyright' +INFO /spec/link:/enabled-by: verify using type 'enabled-by' +INFO /spec/link:/links: verify using type 'links' +INFO /spec/link:/links[0]: verify using type 'link' +INFO /spec/link:/links[0]/role: verify using type 'name' +INFO /spec/link:/links[0]/uid: verify using type 'uid' +INFO /spec/link:/links[0]: verify using type 'spec-member' +INFO /spec/link:/type: verify using type 'name' +INFO /spec/link: verify using type 'spec' +INFO /spec/link:/spec-description: verify using type 'optional-str' +INFO /spec/link:/spec-example: verify using type 'optional-str' +INFO /spec/link:/spec-info: verify using type 'spec-info' +INFO /spec/link:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/link:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/link:/spec-info/dict/attributes/role: verify using type 'name' +INFO /spec/link:/spec-info/dict/attributes/role: verify using type 'spec-attribute-value' +INFO /spec/link:/spec-info/dict/attributes/role/description: verify using type 'optional-str' +INFO /spec/link:/spec-info/dict/attributes/role/spec-type: verify using type 'name' +INFO /spec/link:/spec-info/dict/attributes/uid: verify using type 'name' +INFO /spec/link:/spec-info/dict/attributes/uid: verify using type 'spec-attribute-value' +INFO /spec/link:/spec-info/dict/attributes/uid/description: verify using type 'optional-str' +INFO /spec/link:/spec-info/dict/attributes/uid/spec-type: verify using type 'name' +INFO /spec/link:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/link:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/link:/spec-name: verify using type 'optional-str' +INFO /spec/link:/spec-type: verify using type 'name' +INFO /spec/links: verify using type 'root' +INFO /spec/links:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/links:/copyrights: verify using type 'copyrights' +INFO /spec/links:/copyrights[0]: verify using type 'copyright' +INFO /spec/links:/enabled-by: verify using type 'enabled-by' +INFO /spec/links:/links: verify using type 'links' +INFO /spec/links:/links[0]: verify using type 'link' +INFO /spec/links:/links[0]/role: verify using type 'name' +INFO /spec/links:/links[0]/uid: verify using type 'uid' +INFO /spec/links:/links[0]: verify using type 'spec-member' +INFO /spec/links:/type: verify using type 'name' +INFO /spec/links: verify using type 'spec' +INFO /spec/links:/spec-description: verify using type 'optional-str' +INFO /spec/links:/spec-example: verify using type 'optional-str' +INFO /spec/links:/spec-info: verify using type 'spec-info' +INFO /spec/links:/spec-info/list: verify using type 'spec-list' +INFO /spec/links:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/links:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/links:/spec-name: verify using type 'optional-str' +INFO /spec/links:/spec-type: verify using type 'name' +INFO /spec/list-str: verify using type 'root' +INFO /spec/list-str:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/list-str:/copyrights: verify using type 'copyrights' +INFO /spec/list-str:/copyrights[0]: verify using type 'copyright' +INFO /spec/list-str:/enabled-by: verify using type 'enabled-by' +INFO /spec/list-str:/links: verify using type 'links' +INFO /spec/list-str:/links[0]: verify using type 'link' +INFO /spec/list-str:/links[0]/role: verify using type 'name' +INFO /spec/list-str:/links[0]/uid: verify using type 'uid' +INFO /spec/list-str:/links[0]: verify using type 'spec-member' +INFO /spec/list-str:/type: verify using type 'name' +INFO /spec/list-str: verify using type 'spec' +INFO /spec/list-str:/spec-description: verify using type 'optional-str' +INFO /spec/list-str:/spec-example: verify using type 'optional-str' +INFO /spec/list-str:/spec-info: verify using type 'spec-info' +INFO /spec/list-str:/spec-info/list: verify using type 'spec-list' +INFO /spec/list-str:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/list-str:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/list-str:/spec-name: verify using type 'optional-str' +INFO /spec/list-str:/spec-type: verify using type 'name' +INFO /spec/optional-str: verify using type 'root' +INFO /spec/optional-str:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/optional-str:/copyrights: verify using type 'copyrights' +INFO /spec/optional-str:/copyrights[0]: verify using type 'copyright' +INFO /spec/optional-str:/enabled-by: verify using type 'enabled-by' +INFO /spec/optional-str:/links: verify using type 'links' +INFO /spec/optional-str:/links[0]: verify using type 'link' +INFO /spec/optional-str:/links[0]/role: verify using type 'name' +INFO /spec/optional-str:/links[0]/uid: verify using type 'uid' +INFO /spec/optional-str:/links[0]: verify using type 'spec-member' +INFO /spec/optional-str:/type: verify using type 'name' +INFO /spec/optional-str: verify using type 'spec' +INFO /spec/optional-str:/spec-description: verify using type 'optional-str' +INFO /spec/optional-str:/spec-example: verify using type 'optional-str' +INFO /spec/optional-str:/spec-info: verify using type 'spec-info' +INFO /spec/optional-str:/spec-info/none: verify using type 'none' +INFO /spec/optional-str:/spec-info/str: verify using type 'spec-str' +INFO /spec/optional-str:/spec-info/str/description: verify using type 'optional-str' +INFO /spec/optional-str:/spec-name: verify using type 'optional-str' +INFO /spec/optional-str:/spec-type: verify using type 'name' +INFO /spec/root: verify using type 'root' +INFO /spec/root:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/root:/copyrights: verify using type 'copyrights' +INFO /spec/root:/copyrights[0]: verify using type 'copyright' +INFO /spec/root:/enabled-by: verify using type 'enabled-by' +INFO /spec/root:/links: verify using type 'links' +INFO /spec/root:/type: verify using type 'name' +INFO /spec/root: verify using type 'spec' +INFO /spec/root:/spec-description: verify using type 'optional-str' +INFO /spec/root:/spec-example: verify using type 'optional-str' +INFO /spec/root:/spec-info: verify using type 'spec-info' +INFO /spec/root:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/root:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/root:/spec-info/dict/attributes/SPDX-License-Identifier: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/SPDX-License-Identifier: verify using type 'spec-attribute-value' +INFO /spec/root:/spec-info/dict/attributes/SPDX-License-Identifier/description: verify using type 'optional-str' +INFO /spec/root:/spec-info/dict/attributes/SPDX-License-Identifier/spec-type: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/copyrights: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/copyrights: verify using type 'spec-attribute-value' +INFO /spec/root:/spec-info/dict/attributes/copyrights/description: verify using type 'optional-str' +INFO /spec/root:/spec-info/dict/attributes/copyrights/spec-type: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/enabled-by: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/enabled-by: verify using type 'spec-attribute-value' +INFO /spec/root:/spec-info/dict/attributes/enabled-by/description: verify using type 'optional-str' +INFO /spec/root:/spec-info/dict/attributes/enabled-by/spec-type: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/links: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/links: verify using type 'spec-attribute-value' +INFO /spec/root:/spec-info/dict/attributes/links/description: verify using type 'optional-str' +INFO /spec/root:/spec-info/dict/attributes/links/spec-type: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/type: verify using type 'name' +INFO /spec/root:/spec-info/dict/attributes/type: verify using type 'spec-attribute-value' +INFO /spec/root:/spec-info/dict/attributes/type/description: verify using type 'optional-str' +INFO /spec/root:/spec-info/dict/attributes/type/spec-type: verify using type 'name' +INFO /spec/root:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/root:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/root:/spec-name: verify using type 'optional-str' +INFO /spec/root:/spec-type: verify using type 'name' +INFO /spec/spdx-license-identifier: verify using type 'root' +INFO /spec/spdx-license-identifier:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spdx-license-identifier:/copyrights: verify using type 'copyrights' +INFO /spec/spdx-license-identifier:/copyrights[0]: verify using type 'copyright' +INFO /spec/spdx-license-identifier:/enabled-by: verify using type 'enabled-by' +INFO /spec/spdx-license-identifier:/links: verify using type 'links' +INFO /spec/spdx-license-identifier:/links[0]: verify using type 'link' +INFO /spec/spdx-license-identifier:/links[0]/role: verify using type 'name' +INFO /spec/spdx-license-identifier:/links[0]/uid: verify using type 'uid' +INFO /spec/spdx-license-identifier:/links[0]: verify using type 'spec-member' +INFO /spec/spdx-license-identifier:/type: verify using type 'name' +INFO /spec/spdx-license-identifier: verify using type 'spec' +INFO /spec/spdx-license-identifier:/spec-description: verify using type 'optional-str' +INFO /spec/spdx-license-identifier:/spec-example: verify using type 'optional-str' +INFO /spec/spdx-license-identifier:/spec-info: verify using type 'spec-info' +INFO /spec/spdx-license-identifier:/spec-info/str: verify using type 'spec-str' +INFO /spec/spdx-license-identifier:/spec-info/str/assert: verify using type 'spec-assert-str' +INFO /spec/spdx-license-identifier:/spec-info/str/assert[0]: verify using type 'spec-assert-str' +INFO /spec/spdx-license-identifier:/spec-info/str/assert[0]/eq: verify using type 'str' +INFO /spec/spdx-license-identifier:/spec-info/str/assert[1]: verify using type 'spec-assert-str' +INFO /spec/spdx-license-identifier:/spec-info/str/assert[1]/eq: verify using type 'str' +INFO /spec/spdx-license-identifier:/spec-info/str/assert[2]: verify using type 'spec-assert-str' +INFO /spec/spdx-license-identifier:/spec-info/str/assert[2]/eq: verify using type 'str' +INFO /spec/spdx-license-identifier:/spec-info/str/description: verify using type 'optional-str' +INFO /spec/spdx-license-identifier:/spec-name: verify using type 'optional-str' +INFO /spec/spdx-license-identifier:/spec-type: verify using type 'name' +INFO /spec/spec: verify using type 'root' +INFO /spec/spec:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec:/copyrights: verify using type 'copyrights' +INFO /spec/spec:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec:/links: verify using type 'links' +INFO /spec/spec:/links[0]: verify using type 'link' +INFO /spec/spec:/links[0]/role: verify using type 'name' +INFO /spec/spec:/links[0]/uid: verify using type 'uid' +INFO /spec/spec:/links[0]: verify using type 'spec-member' +INFO /spec/spec:/links[1]: verify using type 'link' +INFO /spec/spec:/links[1]/role: verify using type 'name' +INFO /spec/spec:/links[1]/uid: verify using type 'uid' +INFO /spec/spec:/links[1]: verify using type 'spec-refinement' +INFO /spec/spec:/links[1]/spec-key: verify using type 'name' +INFO /spec/spec:/links[1]/spec-value: verify using type 'name' +INFO /spec/spec:/type: verify using type 'name' +INFO /spec/spec: verify using type 'spec' +INFO /spec/spec:/spec-description: verify using type 'optional-str' +INFO /spec/spec:/spec-example: verify using type 'optional-str' +INFO /spec/spec:/spec-info: verify using type 'spec-info' +INFO /spec/spec:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec:/spec-info/dict/attributes/spec-description: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-description: verify using type 'spec-attribute-value' +INFO /spec/spec:/spec-info/dict/attributes/spec-description/description: verify using type 'optional-str' +INFO /spec/spec:/spec-info/dict/attributes/spec-description/spec-type: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-example: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-example: verify using type 'spec-attribute-value' +INFO /spec/spec:/spec-info/dict/attributes/spec-example/description: verify using type 'optional-str' +INFO /spec/spec:/spec-info/dict/attributes/spec-example/spec-type: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-info: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-info: verify using type 'spec-attribute-value' +INFO /spec/spec:/spec-info/dict/attributes/spec-info/description: verify using type 'optional-str' +INFO /spec/spec:/spec-info/dict/attributes/spec-info/spec-type: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-name: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-name: verify using type 'spec-attribute-value' +INFO /spec/spec:/spec-info/dict/attributes/spec-name/description: verify using type 'optional-str' +INFO /spec/spec:/spec-info/dict/attributes/spec-name/spec-type: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-type: verify using type 'name' +INFO /spec/spec:/spec-info/dict/attributes/spec-type: verify using type 'spec-attribute-value' +INFO /spec/spec:/spec-info/dict/attributes/spec-type/description: verify using type 'optional-str' +INFO /spec/spec:/spec-info/dict/attributes/spec-type/spec-type: verify using type 'name' +INFO /spec/spec:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec:/spec-name: verify using type 'optional-str' +INFO /spec/spec:/spec-type: verify using type 'name' +INFO /spec/spec-assert-float: verify using type 'root' +INFO /spec/spec-assert-float:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-assert-float:/copyrights: verify using type 'copyrights' +INFO /spec/spec-assert-float:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-assert-float:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-assert-float:/links: verify using type 'links' +INFO /spec/spec-assert-float:/links[0]: verify using type 'link' +INFO /spec/spec-assert-float:/links[0]/role: verify using type 'name' +INFO /spec/spec-assert-float:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-assert-float:/links[0]: verify using type 'spec-member' +INFO /spec/spec-assert-float:/type: verify using type 'name' +INFO /spec/spec-assert-float: verify using type 'spec' +INFO /spec/spec-assert-float:/spec-description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-example: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info: verify using type 'spec-info' +INFO /spec/spec-assert-float:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-assert-float:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/and: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/and: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/and/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/and/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/eq: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/eq: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/eq/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/eq/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ge: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ge: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ge/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ge/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/gt: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/gt: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/gt/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/gt/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/le: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/le: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/le/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/le/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/lt: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/lt: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/lt/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/lt/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ne: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ne: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ne/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/ne/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/not: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/not: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/not/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/not/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/or: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/or: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/or/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/attributes/or/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-assert-float:/spec-info/list: verify using type 'spec-list' +INFO /spec/spec-assert-float:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/spec-assert-float:/spec-name: verify using type 'optional-str' +INFO /spec/spec-assert-float:/spec-type: verify using type 'name' +INFO /spec/spec-assert-float-list: verify using type 'root' +INFO /spec/spec-assert-float-list:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-assert-float-list:/copyrights: verify using type 'copyrights' +INFO /spec/spec-assert-float-list:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-assert-float-list:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-assert-float-list:/links: verify using type 'links' +INFO /spec/spec-assert-float-list:/links[0]: verify using type 'link' +INFO /spec/spec-assert-float-list:/links[0]/role: verify using type 'name' +INFO /spec/spec-assert-float-list:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-assert-float-list:/links[0]: verify using type 'spec-member' +INFO /spec/spec-assert-float-list:/type: verify using type 'name' +INFO /spec/spec-assert-float-list: verify using type 'spec' +INFO /spec/spec-assert-float-list:/spec-description: verify using type 'optional-str' +INFO /spec/spec-assert-float-list:/spec-example: verify using type 'optional-str' +INFO /spec/spec-assert-float-list:/spec-info: verify using type 'spec-info' +INFO /spec/spec-assert-float-list:/spec-info/list: verify using type 'spec-list' +INFO /spec/spec-assert-float-list:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/spec-assert-float-list:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/spec-assert-float-list:/spec-name: verify using type 'optional-str' +INFO /spec/spec-assert-float-list:/spec-type: verify using type 'name' +INFO /spec/spec-assert-int: verify using type 'root' +INFO /spec/spec-assert-int:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-assert-int:/copyrights: verify using type 'copyrights' +INFO /spec/spec-assert-int:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-assert-int:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-assert-int:/links: verify using type 'links' +INFO /spec/spec-assert-int:/links[0]: verify using type 'link' +INFO /spec/spec-assert-int:/links[0]/role: verify using type 'name' +INFO /spec/spec-assert-int:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-assert-int:/links[0]: verify using type 'spec-member' +INFO /spec/spec-assert-int:/type: verify using type 'name' +INFO /spec/spec-assert-int: verify using type 'spec' +INFO /spec/spec-assert-int:/spec-description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-example: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info: verify using type 'spec-info' +INFO /spec/spec-assert-int:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-assert-int:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/and: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/and: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/and/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/and/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/eq: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/eq: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/eq/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/eq/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ge: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ge: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ge/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ge/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/gt: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/gt: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/gt/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/gt/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/le: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/le: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/le/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/le/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/lt: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/lt: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/lt/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/lt/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ne: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ne: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ne/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/ne/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/not: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/not: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/not/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/not/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/or: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/or: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/or/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/attributes/or/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-assert-int:/spec-info/list: verify using type 'spec-list' +INFO /spec/spec-assert-int:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/spec-assert-int:/spec-name: verify using type 'optional-str' +INFO /spec/spec-assert-int:/spec-type: verify using type 'name' +INFO /spec/spec-assert-int-list: verify using type 'root' +INFO /spec/spec-assert-int-list:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-assert-int-list:/copyrights: verify using type 'copyrights' +INFO /spec/spec-assert-int-list:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-assert-int-list:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-assert-int-list:/links: verify using type 'links' +INFO /spec/spec-assert-int-list:/links[0]: verify using type 'link' +INFO /spec/spec-assert-int-list:/links[0]/role: verify using type 'name' +INFO /spec/spec-assert-int-list:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-assert-int-list:/links[0]: verify using type 'spec-member' +INFO /spec/spec-assert-int-list:/type: verify using type 'name' +INFO /spec/spec-assert-int-list: verify using type 'spec' +INFO /spec/spec-assert-int-list:/spec-description: verify using type 'optional-str' +INFO /spec/spec-assert-int-list:/spec-example: verify using type 'optional-str' +INFO /spec/spec-assert-int-list:/spec-info: verify using type 'spec-info' +INFO /spec/spec-assert-int-list:/spec-info/list: verify using type 'spec-list' +INFO /spec/spec-assert-int-list:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/spec-assert-int-list:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/spec-assert-int-list:/spec-name: verify using type 'optional-str' +INFO /spec/spec-assert-int-list:/spec-type: verify using type 'name' +INFO /spec/spec-assert-str: verify using type 'root' +INFO /spec/spec-assert-str:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-assert-str:/copyrights: verify using type 'copyrights' +INFO /spec/spec-assert-str:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-assert-str:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-assert-str:/links: verify using type 'links' +INFO /spec/spec-assert-str:/links[0]: verify using type 'link' +INFO /spec/spec-assert-str:/links[0]/role: verify using type 'name' +INFO /spec/spec-assert-str:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-assert-str:/links[0]: verify using type 'spec-member' +INFO /spec/spec-assert-str:/type: verify using type 'name' +INFO /spec/spec-assert-str: verify using type 'spec' +INFO /spec/spec-assert-str:/spec-description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-example: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info: verify using type 'spec-info' +INFO /spec/spec-assert-str:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-assert-str:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/and: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/and: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/and/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/and/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/contains: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/contains: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/contains/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/contains/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/eq: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/eq: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/eq/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/eq/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ge: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ge: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ge/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ge/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/gt: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/gt: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/gt/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/gt/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/in: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/in: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/in/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/in/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/le: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/le: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/le/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/le/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/lt: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/lt: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/lt/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/lt/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ne: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ne: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ne/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/ne/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/not: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/not: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/not/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/not/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/or: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/or: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/or/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/or/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/re: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/re: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/re/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/re/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/uid: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/uid: verify using type 'spec-attribute-value' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/uid/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/attributes/uid/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-assert-str:/spec-info/list: verify using type 'spec-list' +INFO /spec/spec-assert-str:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/spec-assert-str:/spec-name: verify using type 'optional-str' +INFO /spec/spec-assert-str:/spec-type: verify using type 'name' +INFO /spec/spec-assert-str-list: verify using type 'root' +INFO /spec/spec-assert-str-list:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-assert-str-list:/copyrights: verify using type 'copyrights' +INFO /spec/spec-assert-str-list:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-assert-str-list:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-assert-str-list:/links: verify using type 'links' +INFO /spec/spec-assert-str-list:/links[0]: verify using type 'link' +INFO /spec/spec-assert-str-list:/links[0]/role: verify using type 'name' +INFO /spec/spec-assert-str-list:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-assert-str-list:/links[0]: verify using type 'spec-member' +INFO /spec/spec-assert-str-list:/type: verify using type 'name' +INFO /spec/spec-assert-str-list: verify using type 'spec' +INFO /spec/spec-assert-str-list:/spec-description: verify using type 'optional-str' +INFO /spec/spec-assert-str-list:/spec-example: verify using type 'optional-str' +INFO /spec/spec-assert-str-list:/spec-info: verify using type 'spec-info' +INFO /spec/spec-assert-str-list:/spec-info/list: verify using type 'spec-list' +INFO /spec/spec-assert-str-list:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/spec-assert-str-list:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/spec-assert-str-list:/spec-name: verify using type 'optional-str' +INFO /spec/spec-assert-str-list:/spec-type: verify using type 'name' +INFO /spec/spec-attribute-value: verify using type 'root' +INFO /spec/spec-attribute-value:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-attribute-value:/copyrights: verify using type 'copyrights' +INFO /spec/spec-attribute-value:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-attribute-value:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-attribute-value:/links: verify using type 'links' +INFO /spec/spec-attribute-value:/links[0]: verify using type 'link' +INFO /spec/spec-attribute-value:/links[0]/role: verify using type 'name' +INFO /spec/spec-attribute-value:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-attribute-value:/links[0]: verify using type 'spec-member' +INFO /spec/spec-attribute-value:/type: verify using type 'name' +INFO /spec/spec-attribute-value: verify using type 'spec' +INFO /spec/spec-attribute-value:/spec-description: verify using type 'optional-str' +INFO /spec/spec-attribute-value:/spec-example: verify using type 'optional-str' +INFO /spec/spec-attribute-value:/spec-info: verify using type 'spec-info' +INFO /spec/spec-attribute-value:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/spec-type: verify using type 'name' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/spec-type: verify using type 'spec-attribute-value' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/spec-type/description: verify using type 'optional-str' +INFO /spec/spec-attribute-value:/spec-info/dict/attributes/spec-type/spec-type: verify using type 'name' +INFO /spec/spec-attribute-value:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-attribute-value:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-attribute-value:/spec-name: verify using type 'optional-str' +INFO /spec/spec-attribute-value:/spec-type: verify using type 'name' +INFO /spec/spec-attributes: verify using type 'root' +INFO /spec/spec-attributes:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-attributes:/copyrights: verify using type 'copyrights' +INFO /spec/spec-attributes:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-attributes:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-attributes:/links: verify using type 'links' +INFO /spec/spec-attributes:/links[0]: verify using type 'link' +INFO /spec/spec-attributes:/links[0]/role: verify using type 'name' +INFO /spec/spec-attributes:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-attributes:/links[0]: verify using type 'spec-member' +INFO /spec/spec-attributes:/type: verify using type 'name' +INFO /spec/spec-attributes: verify using type 'spec' +INFO /spec/spec-attributes:/spec-description: verify using type 'optional-str' +INFO /spec/spec-attributes:/spec-example: verify using type 'optional-str' +INFO /spec/spec-attributes:/spec-info: verify using type 'spec-info' +INFO /spec/spec-attributes:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-attributes:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-attributes:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-attributes:/spec-info/dict/generic-attributes: verify using type 'spec-generic-attributes' +INFO /spec/spec-attributes:/spec-info/dict/generic-attributes/description: verify using type 'optional-str' +INFO /spec/spec-attributes:/spec-info/dict/generic-attributes/key-spec-type: verify using type 'name' +INFO /spec/spec-attributes:/spec-info/dict/generic-attributes/value-spec-type: verify using type 'name' +INFO /spec/spec-attributes:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-attributes:/spec-name: verify using type 'optional-str' +INFO /spec/spec-attributes:/spec-type: verify using type 'name' +INFO /spec/spec-bool: verify using type 'root' +INFO /spec/spec-bool:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-bool:/copyrights: verify using type 'copyrights' +INFO /spec/spec-bool:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-bool:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-bool:/links: verify using type 'links' +INFO /spec/spec-bool:/links[0]: verify using type 'link' +INFO /spec/spec-bool:/links[0]/role: verify using type 'name' +INFO /spec/spec-bool:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-bool:/links[0]: verify using type 'spec-member' +INFO /spec/spec-bool:/type: verify using type 'name' +INFO /spec/spec-bool: verify using type 'spec' +INFO /spec/spec-bool:/spec-description: verify using type 'optional-str' +INFO /spec/spec-bool:/spec-example: verify using type 'optional-str' +INFO /spec/spec-bool:/spec-info: verify using type 'spec-info' +INFO /spec/spec-bool:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-bool:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-bool:/spec-info/dict/attributes/assert: verify using type 'name' +INFO /spec/spec-bool:/spec-info/dict/attributes/assert: verify using type 'spec-attribute-value' +INFO /spec/spec-bool:/spec-info/dict/attributes/assert/description: verify using type 'optional-str' +INFO /spec/spec-bool:/spec-info/dict/attributes/assert/spec-type: verify using type 'name' +INFO /spec/spec-bool:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-bool:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-bool:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-bool:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-bool:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-bool:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-bool:/spec-info/dict/mandatory-attributes[0]: verify using type 'name' +INFO /spec/spec-bool:/spec-name: verify using type 'optional-str' +INFO /spec/spec-bool:/spec-type: verify using type 'name' +INFO /spec/spec-dict: verify using type 'root' +INFO /spec/spec-dict:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-dict:/copyrights: verify using type 'copyrights' +INFO /spec/spec-dict:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-dict:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-dict:/links: verify using type 'links' +INFO /spec/spec-dict:/links[0]: verify using type 'link' +INFO /spec/spec-dict:/links[0]/role: verify using type 'name' +INFO /spec/spec-dict:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-dict:/links[0]: verify using type 'spec-member' +INFO /spec/spec-dict:/type: verify using type 'name' +INFO /spec/spec-dict: verify using type 'spec' +INFO /spec/spec-dict:/spec-description: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-example: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-info: verify using type 'spec-info' +INFO /spec/spec-dict:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-dict:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-dict:/spec-info/dict/attributes/attributes: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/attributes/attributes: verify using type 'spec-attribute-value' +INFO /spec/spec-dict:/spec-info/dict/attributes/attributes/description: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-info/dict/attributes/attributes/spec-type: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-dict:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/attributes/generic-attributes: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/attributes/generic-attributes: verify using type 'spec-attribute-value' +INFO /spec/spec-dict:/spec-info/dict/attributes/generic-attributes/description: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-info/dict/attributes/generic-attributes/spec-type: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/attributes/mandatory-attributes: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/attributes/mandatory-attributes: verify using type 'spec-attribute-value' +INFO /spec/spec-dict:/spec-info/dict/attributes/mandatory-attributes/description: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-info/dict/attributes/mandatory-attributes/spec-type: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-dict:/spec-info/dict/mandatory-attributes[0]: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/mandatory-attributes[1]: verify using type 'name' +INFO /spec/spec-dict:/spec-info/dict/mandatory-attributes[2]: verify using type 'name' +INFO /spec/spec-dict:/spec-name: verify using type 'optional-str' +INFO /spec/spec-dict:/spec-type: verify using type 'name' +INFO /spec/spec-float: verify using type 'root' +INFO /spec/spec-float:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-float:/copyrights: verify using type 'copyrights' +INFO /spec/spec-float:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-float:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-float:/links: verify using type 'links' +INFO /spec/spec-float:/links[0]: verify using type 'link' +INFO /spec/spec-float:/links[0]/role: verify using type 'name' +INFO /spec/spec-float:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-float:/links[0]: verify using type 'spec-member' +INFO /spec/spec-float:/type: verify using type 'name' +INFO /spec/spec-float: verify using type 'spec' +INFO /spec/spec-float:/spec-description: verify using type 'optional-str' +INFO /spec/spec-float:/spec-example: verify using type 'optional-str' +INFO /spec/spec-float:/spec-info: verify using type 'spec-info' +INFO /spec/spec-float:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-float:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-float:/spec-info/dict/attributes/assert: verify using type 'name' +INFO /spec/spec-float:/spec-info/dict/attributes/assert: verify using type 'spec-attribute-value' +INFO /spec/spec-float:/spec-info/dict/attributes/assert/description: verify using type 'optional-str' +INFO /spec/spec-float:/spec-info/dict/attributes/assert/spec-type: verify using type 'name' +INFO /spec/spec-float:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-float:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-float:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-float:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-float:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-float:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-float:/spec-info/dict/mandatory-attributes[0]: verify using type 'name' +INFO /spec/spec-float:/spec-name: verify using type 'optional-str' +INFO /spec/spec-float:/spec-type: verify using type 'name' +INFO /spec/spec-generic-attributes: verify using type 'root' +INFO /spec/spec-generic-attributes:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-generic-attributes:/copyrights: verify using type 'copyrights' +INFO /spec/spec-generic-attributes:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-generic-attributes:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-generic-attributes:/links: verify using type 'links' +INFO /spec/spec-generic-attributes:/links[0]: verify using type 'link' +INFO /spec/spec-generic-attributes:/links[0]/role: verify using type 'name' +INFO /spec/spec-generic-attributes:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-generic-attributes:/links[0]: verify using type 'spec-member' +INFO /spec/spec-generic-attributes:/type: verify using type 'name' +INFO /spec/spec-generic-attributes: verify using type 'spec' +INFO /spec/spec-generic-attributes:/spec-description: verify using type 'optional-str' +INFO /spec/spec-generic-attributes:/spec-example: verify using type 'optional-str' +INFO /spec/spec-generic-attributes:/spec-info: verify using type 'spec-info' +INFO /spec/spec-generic-attributes:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/key-spec-type: verify using type 'name' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/key-spec-type: verify using type 'spec-attribute-value' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/key-spec-type/description: verify using type 'optional-str' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/key-spec-type/spec-type: verify using type 'name' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/value-spec-type: verify using type 'name' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/value-spec-type: verify using type 'spec-attribute-value' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/value-spec-type/description: verify using type 'optional-str' +INFO /spec/spec-generic-attributes:/spec-info/dict/attributes/value-spec-type/spec-type: verify using type 'name' +INFO /spec/spec-generic-attributes:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-generic-attributes:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-generic-attributes:/spec-name: verify using type 'optional-str' +INFO /spec/spec-generic-attributes:/spec-type: verify using type 'name' +INFO /spec/spec-info: verify using type 'root' +INFO /spec/spec-info:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-info:/copyrights: verify using type 'copyrights' +INFO /spec/spec-info:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-info:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-info:/links: verify using type 'links' +INFO /spec/spec-info:/links[0]: verify using type 'link' +INFO /spec/spec-info:/links[0]/role: verify using type 'name' +INFO /spec/spec-info:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-info:/links[0]: verify using type 'spec-member' +INFO /spec/spec-info:/type: verify using type 'name' +INFO /spec/spec-info: verify using type 'spec' +INFO /spec/spec-info:/spec-description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-example: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info: verify using type 'spec-info' +INFO /spec/spec-info:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-info:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-info:/spec-info/dict/attributes/bool: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/bool: verify using type 'spec-attribute-value' +INFO /spec/spec-info:/spec-info/dict/attributes/bool/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/attributes/bool/spec-type: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/dict: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/dict: verify using type 'spec-attribute-value' +INFO /spec/spec-info:/spec-info/dict/attributes/dict/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/attributes/dict/spec-type: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/float: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/float: verify using type 'spec-attribute-value' +INFO /spec/spec-info:/spec-info/dict/attributes/float/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/attributes/float/spec-type: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/int: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/int: verify using type 'spec-attribute-value' +INFO /spec/spec-info:/spec-info/dict/attributes/int/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/attributes/int/spec-type: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/list: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/list: verify using type 'spec-attribute-value' +INFO /spec/spec-info:/spec-info/dict/attributes/list/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/attributes/list/spec-type: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/none: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/none: verify using type 'spec-attribute-value' +INFO /spec/spec-info:/spec-info/dict/attributes/none/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/attributes/none/spec-type: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/str: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/attributes/str: verify using type 'spec-attribute-value' +INFO /spec/spec-info:/spec-info/dict/attributes/str/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/attributes/str/spec-type: verify using type 'name' +INFO /spec/spec-info:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-info:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-info:/spec-name: verify using type 'optional-str' +INFO /spec/spec-info:/spec-type: verify using type 'name' +INFO /spec/spec-int: verify using type 'root' +INFO /spec/spec-int:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-int:/copyrights: verify using type 'copyrights' +INFO /spec/spec-int:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-int:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-int:/links: verify using type 'links' +INFO /spec/spec-int:/links[0]: verify using type 'link' +INFO /spec/spec-int:/links[0]/role: verify using type 'name' +INFO /spec/spec-int:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-int:/links[0]: verify using type 'spec-member' +INFO /spec/spec-int:/type: verify using type 'name' +INFO /spec/spec-int: verify using type 'spec' +INFO /spec/spec-int:/spec-description: verify using type 'optional-str' +INFO /spec/spec-int:/spec-example: verify using type 'optional-str' +INFO /spec/spec-int:/spec-info: verify using type 'spec-info' +INFO /spec/spec-int:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-int:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-int:/spec-info/dict/attributes/assert: verify using type 'name' +INFO /spec/spec-int:/spec-info/dict/attributes/assert: verify using type 'spec-attribute-value' +INFO /spec/spec-int:/spec-info/dict/attributes/assert/description: verify using type 'optional-str' +INFO /spec/spec-int:/spec-info/dict/attributes/assert/spec-type: verify using type 'name' +INFO /spec/spec-int:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-int:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-int:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-int:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-int:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-int:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-int:/spec-info/dict/mandatory-attributes[0]: verify using type 'name' +INFO /spec/spec-int:/spec-name: verify using type 'optional-str' +INFO /spec/spec-int:/spec-type: verify using type 'name' +INFO /spec/spec-list: verify using type 'root' +INFO /spec/spec-list:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-list:/copyrights: verify using type 'copyrights' +INFO /spec/spec-list:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-list:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-list:/links: verify using type 'links' +INFO /spec/spec-list:/links[0]: verify using type 'link' +INFO /spec/spec-list:/links[0]/role: verify using type 'name' +INFO /spec/spec-list:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-list:/links[0]: verify using type 'spec-member' +INFO /spec/spec-list:/type: verify using type 'name' +INFO /spec/spec-list: verify using type 'spec' +INFO /spec/spec-list:/spec-description: verify using type 'optional-str' +INFO /spec/spec-list:/spec-example: verify using type 'optional-str' +INFO /spec/spec-list:/spec-info: verify using type 'spec-info' +INFO /spec/spec-list:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-list:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-list:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-list:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-list:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-list:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-list:/spec-info/dict/attributes/spec-type: verify using type 'name' +INFO /spec/spec-list:/spec-info/dict/attributes/spec-type: verify using type 'spec-attribute-value' +INFO /spec/spec-list:/spec-info/dict/attributes/spec-type/description: verify using type 'optional-str' +INFO /spec/spec-list:/spec-info/dict/attributes/spec-type/spec-type: verify using type 'name' +INFO /spec/spec-list:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-list:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-list:/spec-name: verify using type 'optional-str' +INFO /spec/spec-list:/spec-type: verify using type 'name' +INFO /spec/spec-mandatory-attributes: verify using type 'root' +INFO /spec/spec-mandatory-attributes:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-mandatory-attributes:/copyrights: verify using type 'copyrights' +INFO /spec/spec-mandatory-attributes:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-mandatory-attributes:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-mandatory-attributes:/links: verify using type 'links' +INFO /spec/spec-mandatory-attributes:/links[0]: verify using type 'link' +INFO /spec/spec-mandatory-attributes:/links[0]/role: verify using type 'name' +INFO /spec/spec-mandatory-attributes:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-mandatory-attributes:/links[0]: verify using type 'spec-member' +INFO /spec/spec-mandatory-attributes:/type: verify using type 'name' +INFO /spec/spec-mandatory-attributes: verify using type 'spec' +INFO /spec/spec-mandatory-attributes:/spec-description: verify using type 'optional-str' +INFO /spec/spec-mandatory-attributes:/spec-example: verify using type 'optional-str' +INFO /spec/spec-mandatory-attributes:/spec-info: verify using type 'spec-info' +INFO /spec/spec-mandatory-attributes:/spec-info/list: verify using type 'spec-list' +INFO /spec/spec-mandatory-attributes:/spec-info/list/description: verify using type 'optional-str' +INFO /spec/spec-mandatory-attributes:/spec-info/list/spec-type: verify using type 'name' +INFO /spec/spec-mandatory-attributes:/spec-info/str: verify using type 'spec-str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/assert: verify using type 'spec-assert-str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/assert/in: verify using type 'list-str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/assert/in[0]: verify using type 'str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/assert/in[1]: verify using type 'str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/assert/in[2]: verify using type 'str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/assert/in[3]: verify using type 'str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/assert/in[4]: verify using type 'str' +INFO /spec/spec-mandatory-attributes:/spec-info/str/description: verify using type 'optional-str' +INFO /spec/spec-mandatory-attributes:/spec-name: verify using type 'optional-str' +INFO /spec/spec-mandatory-attributes:/spec-type: verify using type 'name' +INFO /spec/spec-member: verify using type 'root' +INFO /spec/spec-member:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-member:/copyrights: verify using type 'copyrights' +INFO /spec/spec-member:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-member:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-member:/links: verify using type 'links' +INFO /spec/spec-member:/links[0]: verify using type 'link' +INFO /spec/spec-member:/links[0]/role: verify using type 'name' +INFO /spec/spec-member:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-member:/links[0]: verify using type 'spec-member' +INFO /spec/spec-member:/links[1]: verify using type 'link' +INFO /spec/spec-member:/links[1]/role: verify using type 'name' +INFO /spec/spec-member:/links[1]/uid: verify using type 'uid' +INFO /spec/spec-member:/links[1]: verify using type 'spec-refinement' +INFO /spec/spec-member:/links[1]/spec-key: verify using type 'name' +INFO /spec/spec-member:/links[1]/spec-value: verify using type 'name' +INFO /spec/spec-member:/type: verify using type 'name' +INFO /spec/spec-member: verify using type 'spec' +INFO /spec/spec-member:/spec-description: verify using type 'optional-str' +INFO /spec/spec-member:/spec-example: verify using type 'optional-str' +INFO /spec/spec-member:/spec-info: verify using type 'spec-info' +INFO /spec/spec-member:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-member:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-member:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-member:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-member:/spec-name: verify using type 'optional-str' +INFO /spec/spec-member:/spec-type: verify using type 'name' +INFO /spec/spec-refinement: verify using type 'root' +INFO /spec/spec-refinement:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-refinement:/copyrights: verify using type 'copyrights' +INFO /spec/spec-refinement:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-refinement:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-refinement:/links: verify using type 'links' +INFO /spec/spec-refinement:/links[0]: verify using type 'link' +INFO /spec/spec-refinement:/links[0]/role: verify using type 'name' +INFO /spec/spec-refinement:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-refinement:/links[0]: verify using type 'spec-member' +INFO /spec/spec-refinement:/links[1]: verify using type 'link' +INFO /spec/spec-refinement:/links[1]/role: verify using type 'name' +INFO /spec/spec-refinement:/links[1]/uid: verify using type 'uid' +INFO /spec/spec-refinement:/links[1]: verify using type 'spec-refinement' +INFO /spec/spec-refinement:/links[1]/spec-key: verify using type 'name' +INFO /spec/spec-refinement:/links[1]/spec-value: verify using type 'name' +INFO /spec/spec-refinement:/type: verify using type 'name' +INFO /spec/spec-refinement: verify using type 'spec' +INFO /spec/spec-refinement:/spec-description: verify using type 'optional-str' +INFO /spec/spec-refinement:/spec-example: verify using type 'optional-str' +INFO /spec/spec-refinement:/spec-info: verify using type 'spec-info' +INFO /spec/spec-refinement:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-refinement:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-key: verify using type 'name' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-key: verify using type 'spec-attribute-value' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-key/description: verify using type 'optional-str' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-key/spec-type: verify using type 'name' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-value: verify using type 'name' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-value: verify using type 'spec-attribute-value' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-value/description: verify using type 'optional-str' +INFO /spec/spec-refinement:/spec-info/dict/attributes/spec-value/spec-type: verify using type 'name' +INFO /spec/spec-refinement:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-refinement:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-refinement:/spec-name: verify using type 'optional-str' +INFO /spec/spec-refinement:/spec-type: verify using type 'name' +INFO /spec/spec-str: verify using type 'root' +INFO /spec/spec-str:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec/spec-str:/copyrights: verify using type 'copyrights' +INFO /spec/spec-str:/copyrights[0]: verify using type 'copyright' +INFO /spec/spec-str:/enabled-by: verify using type 'enabled-by' +INFO /spec/spec-str:/links: verify using type 'links' +INFO /spec/spec-str:/links[0]: verify using type 'link' +INFO /spec/spec-str:/links[0]/role: verify using type 'name' +INFO /spec/spec-str:/links[0]/uid: verify using type 'uid' +INFO /spec/spec-str:/links[0]: verify using type 'spec-member' +INFO /spec/spec-str:/type: verify using type 'name' +INFO /spec/spec-str: verify using type 'spec' +INFO /spec/spec-str:/spec-description: verify using type 'optional-str' +INFO /spec/spec-str:/spec-example: verify using type 'optional-str' +INFO /spec/spec-str:/spec-info: verify using type 'spec-info' +INFO /spec/spec-str:/spec-info/dict: verify using type 'spec-dict' +INFO /spec/spec-str:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec/spec-str:/spec-info/dict/attributes/assert: verify using type 'name' +INFO /spec/spec-str:/spec-info/dict/attributes/assert: verify using type 'spec-attribute-value' +INFO /spec/spec-str:/spec-info/dict/attributes/assert/description: verify using type 'optional-str' +INFO /spec/spec-str:/spec-info/dict/attributes/assert/spec-type: verify using type 'name' +INFO /spec/spec-str:/spec-info/dict/attributes/description: verify using type 'name' +INFO /spec/spec-str:/spec-info/dict/attributes/description: verify using type 'spec-attribute-value' +INFO /spec/spec-str:/spec-info/dict/attributes/description/description: verify using type 'optional-str' +INFO /spec/spec-str:/spec-info/dict/attributes/description/spec-type: verify using type 'name' +INFO /spec/spec-str:/spec-info/dict/description: verify using type 'optional-str' +INFO /spec/spec-str:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec/spec-str:/spec-info/dict/mandatory-attributes[0]: verify using type 'name' +INFO /spec/spec-str:/spec-name: verify using type 'optional-str' +INFO /spec/spec-str:/spec-type: verify using type 'name' +INFO /spec2/any-dict: verify using type 'root' +INFO /spec2/any-dict:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/any-dict:/copyrights: verify using type 'copyrights' +INFO /spec2/any-dict:/copyrights[0]: verify using type 'copyright' +INFO /spec2/any-dict:/enabled-by: verify using type 'enabled-by' +INFO /spec2/any-dict:/links: verify using type 'links' +INFO /spec2/any-dict:/links[0]: verify using type 'link' +INFO /spec2/any-dict:/links[0]/role: verify using type 'name' +INFO /spec2/any-dict:/links[0]/uid: verify using type 'uid' +INFO /spec2/any-dict:/links[0]: verify using type 'spec-member' +INFO /spec2/any-dict:/type: verify using type 'name' +INFO /spec2/any-dict: verify using type 'spec' +ERROR /spec2/any-dict: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/any-dict:/spec-example: verify using type 'optional-str' +INFO /spec2/any-dict:/spec-info: verify using type 'spec-info' +INFO /spec2/any-dict:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/any-dict:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/any-dict:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/any-dict:/spec-info/dict/generic-attributes: verify using type 'spec-generic-attributes' +ERROR /spec2/any-dict:/spec-info/dict/generic-attributes: missing mandatory keys for type 'spec-generic-attributes': ['description'] +INFO /spec2/any-dict:/spec-info/dict/generic-attributes/key-spec-type: verify using type 'name' +INFO /spec2/any-dict:/spec-info/dict/generic-attributes/value-spec-type: verify using type 'name' +INFO /spec2/any-dict:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/any-dict:/spec-type: verify using type 'name' +INFO /spec2/c: verify using type 'root' +INFO /spec2/c:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/c:/copyrights: verify using type 'copyrights' +INFO /spec2/c:/copyrights[0]: verify using type 'copyright' +INFO /spec2/c:/enabled-by: verify using type 'enabled-by' +INFO /spec2/c:/links: verify using type 'links' +INFO /spec2/c:/links[0]: verify using type 'link' +INFO /spec2/c:/links[0]/role: verify using type 'name' +INFO /spec2/c:/links[0]/uid: verify using type 'uid' +INFO /spec2/c:/links[0]: verify using type 'spec-member' +INFO /spec2/c:/links[1]: verify using type 'link' +INFO /spec2/c:/links[1]/role: verify using type 'name' +INFO /spec2/c:/links[1]/uid: verify using type 'uid' +INFO /spec2/c:/links[1]: verify using type 'spec-refinement' +INFO /spec2/c:/links[1]/spec-key: verify using type 'name' +INFO /spec2/c:/links[1]/spec-value: verify using type 'name' +INFO /spec2/c:/type: verify using type 'name' +INFO /spec2/c: verify using type 'spec' +ERROR /spec2/c: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/c:/spec-example: verify using type 'optional-str' +INFO /spec2/c:/spec-info: verify using type 'spec-info' +INFO /spec2/c:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/c:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/c:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/c:/spec-info/dict/attributes/any-dict: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/any-dict: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/any-dict: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/any-dict/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/bool: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/bool: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/bool: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/bool/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/dict: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/dict: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/dict: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/dict/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/float: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/float: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/float: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/float/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/int: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/int: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/int: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/int/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/list: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/list: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/list: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/list/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/must-be-true: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/must-be-true: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/must-be-true: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/must-be-true/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/other-int: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/other-int: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/other-int: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/other-int/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/str: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/str: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/str: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/str/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/str-contains: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/str-contains: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/str-contains: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/str-contains/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/uid: verify using type 'name' +INFO /spec2/c:/spec-info/dict/attributes/uid: verify using type 'spec-attribute-value' +ERROR /spec2/c:/spec-info/dict/attributes/uid: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/c:/spec-info/dict/attributes/uid/spec-type: verify using type 'name' +INFO /spec2/c:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/c:/spec-type: verify using type 'name' +INFO /spec2/d: verify using type 'root' +INFO /spec2/d:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/d:/copyrights: verify using type 'copyrights' +INFO /spec2/d:/copyrights[0]: verify using type 'copyright' +INFO /spec2/d:/enabled-by: verify using type 'enabled-by' +INFO /spec2/d:/links: verify using type 'links' +INFO /spec2/d:/links[0]: verify using type 'link' +INFO /spec2/d:/links[0]/role: verify using type 'name' +INFO /spec2/d:/links[0]/uid: verify using type 'uid' +INFO /spec2/d:/links[0]: verify using type 'spec-member' +INFO /spec2/d:/links[1]: verify using type 'link' +INFO /spec2/d:/links[1]/role: verify using type 'name' +INFO /spec2/d:/links[1]/uid: verify using type 'uid' +INFO /spec2/d:/links[1]: verify using type 'spec-refinement' +INFO /spec2/d:/links[1]/spec-key: verify using type 'name' +INFO /spec2/d:/links[1]/spec-value: verify using type 'name' +INFO /spec2/d:/type: verify using type 'name' +INFO /spec2/d: verify using type 'spec' +ERROR /spec2/d: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/d:/spec-example: verify using type 'optional-str' +INFO /spec2/d:/spec-info: verify using type 'spec-info' +INFO /spec2/d:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/d:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/d:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/d:/spec-info/dict/attributes/d-type: verify using type 'name' +INFO /spec2/d:/spec-info/dict/attributes/d-type: verify using type 'spec-attribute-value' +ERROR /spec2/d:/spec-info/dict/attributes/d-type: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/d:/spec-info/dict/attributes/d-type/spec-type: verify using type 'name' +INFO /spec2/d:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/d:/spec-info/dict/mandatory-attributes[0]: verify using type 'name' +INFO /spec2/d:/spec-type: verify using type 'name' +INFO /spec2/d-a: verify using type 'root' +INFO /spec2/d-a:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/d-a:/copyrights: verify using type 'copyrights' +INFO /spec2/d-a:/copyrights[0]: verify using type 'copyright' +INFO /spec2/d-a:/enabled-by: verify using type 'enabled-by' +INFO /spec2/d-a:/links: verify using type 'links' +INFO /spec2/d-a:/links[0]: verify using type 'link' +INFO /spec2/d-a:/links[0]/role: verify using type 'name' +INFO /spec2/d-a:/links[0]/uid: verify using type 'uid' +INFO /spec2/d-a:/links[0]: verify using type 'spec-member' +INFO /spec2/d-a:/links[1]: verify using type 'link' +INFO /spec2/d-a:/links[1]/role: verify using type 'name' +INFO /spec2/d-a:/links[1]/uid: verify using type 'uid' +INFO /spec2/d-a:/links[1]: verify using type 'spec-refinement' +INFO /spec2/d-a:/links[1]/spec-key: verify using type 'name' +INFO /spec2/d-a:/links[1]/spec-value: verify using type 'name' +INFO /spec2/d-a:/links[2]: verify using type 'link' +INFO /spec2/d-a:/links[2]/role: verify using type 'name' +INFO /spec2/d-a:/links[2]/uid: verify using type 'uid' +ERROR /spec2/d-a:/links[2]: unknown subtype for key 'role' for type 'link': other +INFO /spec2/d-a:/type: verify using type 'name' +INFO /spec2/d-a: verify using type 'spec' +ERROR /spec2/d-a: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/d-a:/spec-example: verify using type 'optional-str' +INFO /spec2/d-a:/spec-info: verify using type 'spec-info' +INFO /spec2/d-a:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/d-a:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/d-a:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/d-a:/spec-info/dict/attributes/d-type: verify using type 'name' +INFO /spec2/d-a:/spec-info/dict/attributes/d-type: verify using type 'spec-attribute-value' +ERROR /spec2/d-a:/spec-info/dict/attributes/d-type: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/d-a:/spec-info/dict/attributes/d-type/spec-type: verify using type 'name' +INFO /spec2/d-a:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/d-a:/spec-type: verify using type 'name' +INFO /spec2/invalid: verify using type 'root' +INFO /spec2/invalid:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/invalid:/copyrights: verify using type 'copyrights' +INFO /spec2/invalid:/copyrights[0]: verify using type 'copyright' +INFO /spec2/invalid:/enabled-by: verify using type 'enabled-by' +INFO /spec2/invalid:/links: verify using type 'links' +INFO /spec2/invalid:/links[0]: verify using type 'link' +INFO /spec2/invalid:/links[0]/role: verify using type 'name' +INFO /spec2/invalid:/links[0]/uid: verify using type 'uid' +INFO /spec2/invalid:/links[0]: verify using type 'spec-member' +INFO /spec2/invalid:/links[1]: verify using type 'link' +INFO /spec2/invalid:/links[1]/role: verify using type 'name' +INFO /spec2/invalid:/links[1]/uid: verify using type 'uid' +INFO /spec2/invalid:/links[1]: verify using type 'spec-refinement' +INFO /spec2/invalid:/links[1]/spec-key: verify using type 'name' +INFO /spec2/invalid:/links[1]/spec-value: verify using type 'name' +INFO /spec2/invalid:/type: verify using type 'name' +INFO /spec2/invalid: verify using type 'spec' +ERROR /spec2/invalid: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/invalid:/spec-example: verify using type 'optional-str' +INFO /spec2/invalid:/spec-info: verify using type 'spec-info' +INFO /spec2/invalid:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/invalid:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/invalid:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/invalid:/spec-info/dict/attributes/INVALID: verify using type 'name' +ERROR /spec2/invalid:/spec-info/dict/attributes/INVALID: invalid name: INVALID +INFO /spec2/invalid:/spec-info/dict/attributes/INVALID: verify using type 'spec-attribute-value' +ERROR /spec2/invalid:/spec-info/dict/attributes/INVALID: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/invalid:/spec-info/dict/attributes/INVALID/spec-type: verify using type 'name' +INFO /spec2/invalid:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/invalid:/spec-info/none: verify using type 'none' +ERROR /spec2/invalid:/spec-info/none: expected type 'none', actual type 'bool' +INFO /spec2/invalid:/spec-info/str: verify using type 'spec-str' +ERROR /spec2/invalid:/spec-info/str: missing mandatory keys for type 'spec-str': ['description'] +ERROR /spec2/invalid:/spec-info/str: has unverfied keys for type 'spec-str' and its subtypes: ['foo'] +ERROR /spec2/invalid:/spec-info: has unverfied keys for type 'spec-info' and its subtypes: ['unexpected'] +INFO /spec2/invalid:/spec-type: verify using type 'name' +INFO /spec2/keys-at-least-one: verify using type 'root' +INFO /spec2/keys-at-least-one:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/keys-at-least-one:/copyrights: verify using type 'copyrights' +INFO /spec2/keys-at-least-one:/copyrights[0]: verify using type 'copyright' +INFO /spec2/keys-at-least-one:/enabled-by: verify using type 'enabled-by' +INFO /spec2/keys-at-least-one:/links: verify using type 'links' +INFO /spec2/keys-at-least-one:/links[0]: verify using type 'link' +INFO /spec2/keys-at-least-one:/links[0]/role: verify using type 'name' +INFO /spec2/keys-at-least-one:/links[0]/uid: verify using type 'uid' +INFO /spec2/keys-at-least-one:/links[0]: verify using type 'spec-member' +INFO /spec2/keys-at-least-one:/links[1]: verify using type 'link' +INFO /spec2/keys-at-least-one:/links[1]/role: verify using type 'name' +INFO /spec2/keys-at-least-one:/links[1]/uid: verify using type 'uid' +INFO /spec2/keys-at-least-one:/links[1]: verify using type 'spec-refinement' +INFO /spec2/keys-at-least-one:/links[1]/spec-key: verify using type 'name' +INFO /spec2/keys-at-least-one:/links[1]/spec-value: verify using type 'name' +INFO /spec2/keys-at-least-one:/type: verify using type 'name' +INFO /spec2/keys-at-least-one: verify using type 'spec' +ERROR /spec2/keys-at-least-one: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/keys-at-least-one:/spec-example: verify using type 'optional-str' +INFO /spec2/keys-at-least-one:/spec-info: verify using type 'spec-info' +INFO /spec2/keys-at-least-one:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/keys-at-least-one:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/keys-at-least-one:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/keys-at-least-one:/spec-info/dict/attributes/key-a: verify using type 'name' +INFO /spec2/keys-at-least-one:/spec-info/dict/attributes/key-a: verify using type 'spec-attribute-value' +ERROR /spec2/keys-at-least-one:/spec-info/dict/attributes/key-a: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/keys-at-least-one:/spec-info/dict/attributes/key-a/spec-type: verify using type 'name' +INFO /spec2/keys-at-least-one:/spec-info/dict/attributes/key-b: verify using type 'name' +INFO /spec2/keys-at-least-one:/spec-info/dict/attributes/key-b: verify using type 'spec-attribute-value' +ERROR /spec2/keys-at-least-one:/spec-info/dict/attributes/key-b: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/keys-at-least-one:/spec-info/dict/attributes/key-b/spec-type: verify using type 'name' +INFO /spec2/keys-at-least-one:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/keys-at-least-one:/spec-type: verify using type 'name' +INFO /spec2/keys-at-most-one: verify using type 'root' +INFO /spec2/keys-at-most-one:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/keys-at-most-one:/copyrights: verify using type 'copyrights' +INFO /spec2/keys-at-most-one:/copyrights[0]: verify using type 'copyright' +INFO /spec2/keys-at-most-one:/enabled-by: verify using type 'enabled-by' +INFO /spec2/keys-at-most-one:/links: verify using type 'links' +INFO /spec2/keys-at-most-one:/links[0]: verify using type 'link' +INFO /spec2/keys-at-most-one:/links[0]/role: verify using type 'name' +INFO /spec2/keys-at-most-one:/links[0]/uid: verify using type 'uid' +INFO /spec2/keys-at-most-one:/links[0]: verify using type 'spec-member' +INFO /spec2/keys-at-most-one:/links[1]: verify using type 'link' +INFO /spec2/keys-at-most-one:/links[1]/role: verify using type 'name' +INFO /spec2/keys-at-most-one:/links[1]/uid: verify using type 'uid' +INFO /spec2/keys-at-most-one:/links[1]: verify using type 'spec-refinement' +INFO /spec2/keys-at-most-one:/links[1]/spec-key: verify using type 'name' +INFO /spec2/keys-at-most-one:/links[1]/spec-value: verify using type 'name' +INFO /spec2/keys-at-most-one:/type: verify using type 'name' +INFO /spec2/keys-at-most-one: verify using type 'spec' +ERROR /spec2/keys-at-most-one: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/keys-at-most-one:/spec-example: verify using type 'optional-str' +INFO /spec2/keys-at-most-one:/spec-info: verify using type 'spec-info' +INFO /spec2/keys-at-most-one:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/keys-at-most-one:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/keys-at-most-one:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/keys-at-most-one:/spec-info/dict/attributes/key-a: verify using type 'name' +INFO /spec2/keys-at-most-one:/spec-info/dict/attributes/key-a: verify using type 'spec-attribute-value' +ERROR /spec2/keys-at-most-one:/spec-info/dict/attributes/key-a: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/keys-at-most-one:/spec-info/dict/attributes/key-a/spec-type: verify using type 'name' +INFO /spec2/keys-at-most-one:/spec-info/dict/attributes/key-b: verify using type 'name' +INFO /spec2/keys-at-most-one:/spec-info/dict/attributes/key-b: verify using type 'spec-attribute-value' +ERROR /spec2/keys-at-most-one:/spec-info/dict/attributes/key-b: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/keys-at-most-one:/spec-info/dict/attributes/key-b/spec-type: verify using type 'name' +INFO /spec2/keys-at-most-one:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/keys-at-most-one:/spec-type: verify using type 'name' +INFO /spec2/keys-exactly-one: verify using type 'root' +INFO /spec2/keys-exactly-one:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/keys-exactly-one:/copyrights: verify using type 'copyrights' +INFO /spec2/keys-exactly-one:/copyrights[0]: verify using type 'copyright' +INFO /spec2/keys-exactly-one:/enabled-by: verify using type 'enabled-by' +INFO /spec2/keys-exactly-one:/links: verify using type 'links' +INFO /spec2/keys-exactly-one:/links[0]: verify using type 'link' +INFO /spec2/keys-exactly-one:/links[0]/role: verify using type 'name' +INFO /spec2/keys-exactly-one:/links[0]/uid: verify using type 'uid' +INFO /spec2/keys-exactly-one:/links[0]: verify using type 'spec-member' +INFO /spec2/keys-exactly-one:/links[1]: verify using type 'link' +INFO /spec2/keys-exactly-one:/links[1]/role: verify using type 'name' +INFO /spec2/keys-exactly-one:/links[1]/uid: verify using type 'uid' +INFO /spec2/keys-exactly-one:/links[1]: verify using type 'spec-refinement' +INFO /spec2/keys-exactly-one:/links[1]/spec-key: verify using type 'name' +INFO /spec2/keys-exactly-one:/links[1]/spec-value: verify using type 'name' +INFO /spec2/keys-exactly-one:/type: verify using type 'name' +INFO /spec2/keys-exactly-one: verify using type 'spec' +ERROR /spec2/keys-exactly-one: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/keys-exactly-one:/spec-example: verify using type 'optional-str' +INFO /spec2/keys-exactly-one:/spec-info: verify using type 'spec-info' +INFO /spec2/keys-exactly-one:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/keys-exactly-one:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/keys-exactly-one:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/keys-exactly-one:/spec-info/dict/attributes/key-a: verify using type 'name' +INFO /spec2/keys-exactly-one:/spec-info/dict/attributes/key-a: verify using type 'spec-attribute-value' +ERROR /spec2/keys-exactly-one:/spec-info/dict/attributes/key-a: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/keys-exactly-one:/spec-info/dict/attributes/key-a/spec-type: verify using type 'name' +INFO /spec2/keys-exactly-one:/spec-info/dict/attributes/key-b: verify using type 'name' +INFO /spec2/keys-exactly-one:/spec-info/dict/attributes/key-b: verify using type 'spec-attribute-value' +ERROR /spec2/keys-exactly-one:/spec-info/dict/attributes/key-b: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/keys-exactly-one:/spec-info/dict/attributes/key-b/spec-type: verify using type 'name' +INFO /spec2/keys-exactly-one:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/keys-exactly-one:/spec-type: verify using type 'name' +INFO /spec2/must-be-true: verify using type 'root' +INFO /spec2/must-be-true:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/must-be-true:/copyrights: verify using type 'copyrights' +INFO /spec2/must-be-true:/copyrights[0]: verify using type 'copyright' +INFO /spec2/must-be-true:/enabled-by: verify using type 'enabled-by' +INFO /spec2/must-be-true:/links: verify using type 'links' +INFO /spec2/must-be-true:/links[0]: verify using type 'link' +INFO /spec2/must-be-true:/links[0]/role: verify using type 'name' +INFO /spec2/must-be-true:/links[0]/uid: verify using type 'uid' +INFO /spec2/must-be-true:/links[0]: verify using type 'spec-member' +INFO /spec2/must-be-true:/type: verify using type 'name' +INFO /spec2/must-be-true: verify using type 'spec' +ERROR /spec2/must-be-true: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/must-be-true:/spec-example: verify using type 'optional-str' +INFO /spec2/must-be-true:/spec-info: verify using type 'spec-info' +INFO /spec2/must-be-true:/spec-info/bool: verify using type 'spec-bool' +ERROR /spec2/must-be-true:/spec-info/bool: missing mandatory keys for type 'spec-bool': ['description'] +INFO /spec2/must-be-true:/spec-info/bool/assert: verify using type 'bool' +INFO /spec2/must-be-true:/spec-type: verify using type 'name' +INFO /spec2/other-int: verify using type 'root' +INFO /spec2/other-int:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/other-int:/copyrights: verify using type 'copyrights' +INFO /spec2/other-int:/copyrights[0]: verify using type 'copyright' +INFO /spec2/other-int:/enabled-by: verify using type 'enabled-by' +INFO /spec2/other-int:/links: verify using type 'links' +INFO /spec2/other-int:/links[0]: verify using type 'link' +INFO /spec2/other-int:/links[0]/role: verify using type 'name' +INFO /spec2/other-int:/links[0]/uid: verify using type 'uid' +INFO /spec2/other-int:/links[0]: verify using type 'spec-member' +INFO /spec2/other-int:/type: verify using type 'name' +INFO /spec2/other-int: verify using type 'spec' +ERROR /spec2/other-int: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/other-int:/spec-example: verify using type 'optional-str' +INFO /spec2/other-int:/spec-info: verify using type 'spec-info' +INFO /spec2/other-int:/spec-info/int: verify using type 'spec-int' +ERROR /spec2/other-int:/spec-info/int: missing mandatory keys for type 'spec-int': ['description'] +INFO /spec2/other-int:/spec-type: verify using type 'name' +INFO /spec2/some-bool: verify using type 'root' +INFO /spec2/some-bool:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/some-bool:/copyrights: verify using type 'copyrights' +INFO /spec2/some-bool:/copyrights[0]: verify using type 'copyright' +INFO /spec2/some-bool:/enabled-by: verify using type 'enabled-by' +INFO /spec2/some-bool:/links: verify using type 'links' +INFO /spec2/some-bool:/links[0]: verify using type 'link' +INFO /spec2/some-bool:/links[0]/role: verify using type 'name' +INFO /spec2/some-bool:/links[0]/uid: verify using type 'uid' +INFO /spec2/some-bool:/links[0]: verify using type 'spec-member' +INFO /spec2/some-bool:/type: verify using type 'name' +INFO /spec2/some-bool: verify using type 'spec' +ERROR /spec2/some-bool: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/some-bool:/spec-example: verify using type 'optional-str' +INFO /spec2/some-bool:/spec-info: verify using type 'spec-info' +INFO /spec2/some-bool:/spec-info/bool: verify using type 'spec-bool' +ERROR /spec2/some-bool:/spec-info/bool: missing mandatory keys for type 'spec-bool': ['description'] +INFO /spec2/some-bool:/spec-type: verify using type 'name' +INFO /spec2/some-dict: verify using type 'root' +INFO /spec2/some-dict:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/some-dict:/copyrights: verify using type 'copyrights' +INFO /spec2/some-dict:/copyrights[0]: verify using type 'copyright' +INFO /spec2/some-dict:/enabled-by: verify using type 'enabled-by' +INFO /spec2/some-dict:/links: verify using type 'links' +INFO /spec2/some-dict:/links[0]: verify using type 'link' +INFO /spec2/some-dict:/links[0]/role: verify using type 'name' +INFO /spec2/some-dict:/links[0]/uid: verify using type 'uid' +INFO /spec2/some-dict:/links[0]: verify using type 'spec-member' +INFO /spec2/some-dict:/type: verify using type 'name' +INFO /spec2/some-dict: verify using type 'spec' +ERROR /spec2/some-dict: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/some-dict:/spec-example: verify using type 'optional-str' +INFO /spec2/some-dict:/spec-info: verify using type 'spec-info' +INFO /spec2/some-dict:/spec-info/dict: verify using type 'spec-dict' +ERROR /spec2/some-dict:/spec-info/dict: missing mandatory keys for type 'spec-dict': ['description'] +INFO /spec2/some-dict:/spec-info/dict/attributes: verify using type 'spec-attributes' +INFO /spec2/some-dict:/spec-info/dict/attributes/a: verify using type 'name' +INFO /spec2/some-dict:/spec-info/dict/attributes/a: verify using type 'spec-attribute-value' +ERROR /spec2/some-dict:/spec-info/dict/attributes/a: missing mandatory keys for type 'spec-attribute-value': ['description'] +INFO /spec2/some-dict:/spec-info/dict/attributes/a/spec-type: verify using type 'name' +INFO /spec2/some-dict:/spec-info/dict/mandatory-attributes: verify using type 'spec-mandatory-attributes' +INFO /spec2/some-dict:/spec-info/none: verify using type 'none' +INFO /spec2/some-dict:/spec-type: verify using type 'name' +INFO /spec2/some-float: verify using type 'root' +INFO /spec2/some-float:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/some-float:/copyrights: verify using type 'copyrights' +INFO /spec2/some-float:/copyrights[0]: verify using type 'copyright' +INFO /spec2/some-float:/enabled-by: verify using type 'enabled-by' +INFO /spec2/some-float:/links: verify using type 'links' +INFO /spec2/some-float:/links[0]: verify using type 'link' +INFO /spec2/some-float:/links[0]/role: verify using type 'name' +INFO /spec2/some-float:/links[0]/uid: verify using type 'uid' +INFO /spec2/some-float:/links[0]: verify using type 'spec-member' +INFO /spec2/some-float:/type: verify using type 'name' +INFO /spec2/some-float: verify using type 'spec' +ERROR /spec2/some-float: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/some-float:/spec-example: verify using type 'optional-str' +INFO /spec2/some-float:/spec-info: verify using type 'spec-info' +INFO /spec2/some-float:/spec-info/float: verify using type 'spec-float' +ERROR /spec2/some-float:/spec-info/float: missing mandatory keys for type 'spec-float': ['description'] +INFO /spec2/some-float:/spec-info/float/assert: verify using type 'spec-assert-float' +INFO /spec2/some-float:/spec-info/float/assert[0]: verify using type 'spec-assert-float' +INFO /spec2/some-float:/spec-info/float/assert[0]/le: verify using type 'float' +INFO /spec2/some-float:/spec-type: verify using type 'name' +INFO /spec2/some-int: verify using type 'root' +INFO /spec2/some-int:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/some-int:/copyrights: verify using type 'copyrights' +INFO /spec2/some-int:/copyrights[0]: verify using type 'copyright' +INFO /spec2/some-int:/enabled-by: verify using type 'enabled-by' +INFO /spec2/some-int:/links: verify using type 'links' +INFO /spec2/some-int:/links[0]: verify using type 'link' +INFO /spec2/some-int:/links[0]/role: verify using type 'name' +INFO /spec2/some-int:/links[0]/uid: verify using type 'uid' +INFO /spec2/some-int:/links[0]: verify using type 'spec-member' +INFO /spec2/some-int:/type: verify using type 'name' +INFO /spec2/some-int: verify using type 'spec' +ERROR /spec2/some-int: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/some-int:/spec-example: verify using type 'optional-str' +INFO /spec2/some-int:/spec-info: verify using type 'spec-info' +INFO /spec2/some-int:/spec-info/int: verify using type 'spec-int' +ERROR /spec2/some-int:/spec-info/int: missing mandatory keys for type 'spec-int': ['description'] +INFO /spec2/some-int:/spec-info/int/assert: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[0]/and: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[0]/and[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[0]/and[0]/not: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[0]/and[0]/not/eq: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[0]/and[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[0]/and[1]/eq: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[1]/and: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[1]/and[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[1]/and[0]/eq: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[1]/and[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[1]/and[1]/ne: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[2]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[2]/and: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[2]/and[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[2]/and[0]/ge: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[2]/and[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[2]/and[1]/le: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[3]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[3]/and: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[3]/and[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[3]/and[0]/gt: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[3]/and[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[3]/and[1]/lt: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[4]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[4]/and: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[4]/and[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[4]/and[0]/le: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[4]/and[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[4]/and[1]/ge: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[5]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[5]/and: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[5]/and[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[5]/and[0]/lt: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[5]/and[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[5]/and[1]/gt: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[6]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[6]/and: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[6]/and[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[6]/and[0]/or: verify using type 'spec-assert-int-list' +INFO /spec2/some-int:/spec-info/int/assert[6]/and[0]/or[0]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[6]/and[0]/or[0]/eq: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[6]/and[0]/or[1]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[6]/and[0]/or[1]/ne: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[7]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[7]/eq: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[8]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[8]/ne: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[9]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[9]/le: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[10]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[10]/lt: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[11]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[11]/ge: verify using type 'int' +INFO /spec2/some-int:/spec-info/int/assert[12]: verify using type 'spec-assert-int' +INFO /spec2/some-int:/spec-info/int/assert[12]/gt: verify using type 'int' +INFO /spec2/some-int:/spec-type: verify using type 'name' +INFO /spec2/some-list: verify using type 'root' +INFO /spec2/some-list:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/some-list:/copyrights: verify using type 'copyrights' +INFO /spec2/some-list:/copyrights[0]: verify using type 'copyright' +INFO /spec2/some-list:/enabled-by: verify using type 'enabled-by' +INFO /spec2/some-list:/links: verify using type 'links' +INFO /spec2/some-list:/links[0]: verify using type 'link' +INFO /spec2/some-list:/links[0]/role: verify using type 'name' +INFO /spec2/some-list:/links[0]/uid: verify using type 'uid' +INFO /spec2/some-list:/links[0]: verify using type 'spec-member' +INFO /spec2/some-list:/type: verify using type 'name' +INFO /spec2/some-list: verify using type 'spec' +ERROR /spec2/some-list: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/some-list:/spec-example: verify using type 'optional-str' +INFO /spec2/some-list:/spec-info: verify using type 'spec-info' +INFO /spec2/some-list:/spec-info/list: verify using type 'spec-list' +ERROR /spec2/some-list:/spec-info/list: missing mandatory keys for type 'spec-list': ['description'] +INFO /spec2/some-list:/spec-info/list/spec-type: verify using type 'name' +INFO /spec2/some-list:/spec-type: verify using type 'name' +INFO /spec2/some-str: verify using type 'root' +INFO /spec2/some-str:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/some-str:/copyrights: verify using type 'copyrights' +INFO /spec2/some-str:/copyrights[0]: verify using type 'copyright' +INFO /spec2/some-str:/enabled-by: verify using type 'enabled-by' +INFO /spec2/some-str:/links: verify using type 'links' +INFO /spec2/some-str:/links[0]: verify using type 'link' +INFO /spec2/some-str:/links[0]/role: verify using type 'name' +INFO /spec2/some-str:/links[0]/uid: verify using type 'uid' +INFO /spec2/some-str:/links[0]: verify using type 'spec-member' +INFO /spec2/some-str:/type: verify using type 'name' +INFO /spec2/some-str: verify using type 'spec' +ERROR /spec2/some-str: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/some-str:/spec-example: verify using type 'optional-str' +INFO /spec2/some-str:/spec-info: verify using type 'spec-info' +INFO /spec2/some-str:/spec-info/str: verify using type 'spec-str' +ERROR /spec2/some-str:/spec-info/str: missing mandatory keys for type 'spec-str': ['description'] +INFO /spec2/some-str:/spec-info/str/assert: verify using type 'spec-assert-str' +INFO /spec2/some-str:/spec-info/str/assert[0]: verify using type 'spec-assert-str' +INFO /spec2/some-str:/spec-info/str/assert[0]/uid: verify using type 'none' +INFO /spec2/some-str:/spec-info/str/assert[1]: verify using type 'spec-assert-str' +INFO /spec2/some-str:/spec-info/str/assert[1]/eq: verify using type 'str' +INFO /spec2/some-str:/spec-info/str/assert[2]: verify using type 'spec-assert-str' +INFO /spec2/some-str:/spec-info/str/assert[2]/ne: verify using type 'str' +INFO /spec2/some-str:/spec-info/str/assert[3]: verify using type 'spec-assert-str' +INFO /spec2/some-str:/spec-info/str/assert[3]/re: verify using type 'str' +INFO /spec2/some-str:/spec-type: verify using type 'name' +INFO /spec2/sta: verify using type 'root' +INFO /spec2/sta:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/sta:/copyrights: verify using type 'copyrights' +INFO /spec2/sta:/copyrights[0]: verify using type 'copyright' +INFO /spec2/sta:/enabled-by: verify using type 'enabled-by' +INFO /spec2/sta:/links: verify using type 'links' +INFO /spec2/sta:/type: verify using type 'name' +INFO /spec2/sta: verify using type 'spec' +ERROR /spec2/sta: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/sta:/spec-example: verify using type 'optional-str' +INFO /spec2/sta:/spec-info: verify using type 'spec-info' +ERROR /spec2/sta:/spec-info: not at least one key out of ['bool', 'dict', 'float', 'int', 'list', 'none', 'str'] is present for type 'spec-info' +INFO /spec2/sta:/spec-type: verify using type 'name' +INFO /spec2/str-contains: verify using type 'root' +INFO /spec2/str-contains:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/str-contains:/copyrights: verify using type 'copyrights' +INFO /spec2/str-contains:/copyrights[0]: verify using type 'copyright' +INFO /spec2/str-contains:/enabled-by: verify using type 'enabled-by' +INFO /spec2/str-contains:/links: verify using type 'links' +INFO /spec2/str-contains:/links[0]: verify using type 'link' +INFO /spec2/str-contains:/links[0]/role: verify using type 'name' +INFO /spec2/str-contains:/links[0]/uid: verify using type 'uid' +INFO /spec2/str-contains:/links[0]: verify using type 'spec-member' +INFO /spec2/str-contains:/type: verify using type 'name' +INFO /spec2/str-contains: verify using type 'spec' +ERROR /spec2/str-contains: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/str-contains:/spec-example: verify using type 'optional-str' +INFO /spec2/str-contains:/spec-info: verify using type 'spec-info' +INFO /spec2/str-contains:/spec-info/str: verify using type 'spec-str' +ERROR /spec2/str-contains:/spec-info/str: missing mandatory keys for type 'spec-str': ['description'] +INFO /spec2/str-contains:/spec-info/str/assert: verify using type 'spec-assert-str' +INFO /spec2/str-contains:/spec-info/str/assert/and: verify using type 'spec-assert-str-list' +INFO /spec2/str-contains:/spec-info/str/assert/and[0]: verify using type 'spec-assert-str' +INFO /spec2/str-contains:/spec-info/str/assert/and[0]/contains: verify using type 'list-str' +INFO /spec2/str-contains:/spec-info/str/assert/and[0]/contains[0]: verify using type 'str' +INFO /spec2/str-contains:/spec-info/str/assert/and[0]/contains[1]: verify using type 'str' +INFO /spec2/str-contains:/spec-info/str/assert/and[1]: verify using type 'spec-assert-str' +INFO /spec2/str-contains:/spec-info/str/assert/and[1]/not: verify using type 'spec-assert-str' +INFO /spec2/str-contains:/spec-info/str/assert/and[1]/not/contains: verify using type 'list-str' +INFO /spec2/str-contains:/spec-info/str/assert/and[1]/not/contains[0]: verify using type 'str' +INFO /spec2/str-contains:/spec-type: verify using type 'name' +INFO /spec2/x: verify using type 'root' +INFO /spec2/x:/SPDX-License-Identifier: verify using type 'spdx-license-identifier' +INFO /spec2/x:/copyrights: verify using type 'copyrights' +INFO /spec2/x:/copyrights[0]: verify using type 'copyright' +INFO /spec2/x:/enabled-by: verify using type 'enabled-by' +INFO /spec2/x:/links: verify using type 'links' +INFO /spec2/x:/links[0]: verify using type 'link' +INFO /spec2/x:/links[0]/role: verify using type 'name' +INFO /spec2/x:/links[0]/uid: verify using type 'uid' +INFO /spec2/x:/links[0]: verify using type 'spec-member' +INFO /spec2/x:/type: verify using type 'name' +INFO /spec2/x: verify using type 'spec' +ERROR /spec2/x: missing mandatory keys for type 'spec': ['spec-description', 'spec-name'] +INFO /spec2/x:/spec-example: verify using type 'optional-str' +INFO /spec2/x:/spec-info: verify using type 'spec-info' +INFO /spec2/x:/spec-info/str: verify using type 'spec-str' +ERROR /spec2/x:/spec-info/str: missing mandatory keys for type 'spec-str': ['description'] +INFO /spec2/x:/spec-info/str/assert: verify using type 'spec-assert-str' +INFO /spec2/x:/spec-info/str/assert/eq: verify using type 'str' +INFO /spec2/x:/spec-type: verify using type 'name' +INFO finished specification item verification""" diff --git a/rtemsspec/tests/test_util.py b/rtemsspec/tests/test_util.py new file mode 100644 index 00000000..c85e6833 --- /dev/null +++ b/rtemsspec/tests/test_util.py @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.util module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os + +from rtemsspec.util import copy_files, load_config + + +def test_copy_files(tmpdir): + src_dir = os.path.dirname(__file__) + copy_files(src_dir, tmpdir, []) + filename = "config/c/d.yml" + assert not os.path.exists(os.path.join(tmpdir, filename)) + copy_files(src_dir, tmpdir, [filename]) + assert os.path.exists(os.path.join(tmpdir, filename)) + + +def test_load_config(): + filename = os.path.join(os.path.dirname(__file__), "config", "a.yml") + config = load_config(filename) + assert config["a"] == "b" + assert config["c"] == "d" diff --git a/rtemsspec/tests/test_validation.py b/rtemsspec/tests/test_validation.py new file mode 100644 index 00000000..d2a79f8c --- /dev/null +++ b/rtemsspec/tests/test_validation.py @@ -0,0 +1,1271 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests for the rtemsspec.validation module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import pytest + +from rtemsspec.validation import generate +from rtemsspec.items import EmptyItemCache, ItemCache +from rtemsspec.tests.util import create_item_cache_config_and_copy_spec + + +def test_validation(tmpdir): + validation_config = {} + base_directory = os.path.join(tmpdir, "base") + validation_config["base-directory"] = base_directory + + generate(validation_config, EmptyItemCache()) + + item_cache_config = create_item_cache_config_and_copy_spec( + tmpdir, "spec-validation", with_spec_types=True) + generate(validation_config, ItemCache(item_cache_config)) + + with open(os.path.join(base_directory, "ts.c"), "r") as src: + content = """/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestSuiteBlueGreen + */ + +/* + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <blue.h> + +#include "green.h" + +#include <t.h> + +/** + * @defgroup RTEMSTestSuiteBlueGreen Blue Green + * + * @ingroup RTEMSTestSuites + * + * @brief Test Suite + * + * The Blue Green description. + * + * @{ + */ + +/* Blue green code */ + +/** @} */ +""" + assert content == src.read() + + with open(os.path.join(base_directory, "tc12.c"), "r") as src: + content = """/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseClassicTaskIdentification + * @ingroup RTEMSTestCaseTestCase + * @ingroup RTEMSTestCaseTestCase2 + */ + +/* + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <a.h> +#include <b.h> +#include <rtems.h> + +#include "x.h" +#include "y.h" + +#include <t.h> + +/** + * @defgroup RTEMSTestCaseClassicTaskIdentification Classic Task Identification + * + * @ingroup RTEMSTestSuiteBlueGreen + * + * @brief Test Case + * + * @{ + */ + +typedef enum { + ClassicTaskIdentification_Pre_Name_Invalid, + ClassicTaskIdentification_Pre_Name_Self, + ClassicTaskIdentification_Pre_Name_Valid +} ClassicTaskIdentification_Pre_Name; + +typedef enum { + ClassicTaskIdentification_Pre_Node_Local, + ClassicTaskIdentification_Pre_Node_Remote, + ClassicTaskIdentification_Pre_Node_Invalid, + ClassicTaskIdentification_Pre_Node_SearchAll, + ClassicTaskIdentification_Pre_Node_SearchOther, + ClassicTaskIdentification_Pre_Node_SearchLocal +} ClassicTaskIdentification_Pre_Node; + +typedef enum { + ClassicTaskIdentification_Pre_Id_NullPtr, + ClassicTaskIdentification_Pre_Id_Valid +} ClassicTaskIdentification_Pre_Id; + +typedef enum { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Status_InvNode, + ClassicTaskIdentification_Post_Status_InvId +} ClassicTaskIdentification_Post_Status; + +typedef enum { + ClassicTaskIdentification_Post_Id_Nop, + ClassicTaskIdentification_Post_Id_NullPtr, + ClassicTaskIdentification_Post_Id_Self, + ClassicTaskIdentification_Post_Id_LocalTask, + ClassicTaskIdentification_Post_Id_RemoteTask +} ClassicTaskIdentification_Post_Id; + +/** + * @brief Test context for Classic Task Identification test case. + */ +typedef struct { + /** + * @brief Brief context member description. + * + * Context member description. + */ + rtems_status_code status; + + rtems_name name; + + uint32_t node; + + rtems_id *id; + + rtems_id id_value; + + rtems_id id_local_task; + + rtems_id id_remote_task; + + /** + * @brief This member defines the pre-condition states for the next action. + */ + size_t pcs[ 3 ]; + + /** + * @brief This member indicates if the test action loop is currently + * executed. + */ + bool in_action_loop; +} ClassicTaskIdentification_Context; + +static ClassicTaskIdentification_Context + ClassicTaskIdentification_Instance; + +static const char * const ClassicTaskIdentification_PreDesc_Name[] = { + "Invalid", + "Self", + "Valid" +}; + +static const char * const ClassicTaskIdentification_PreDesc_Node[] = { + "Local", + "Remote", + "Invalid", + "SearchAll", + "SearchOther", + "SearchLocal" +}; + +static const char * const ClassicTaskIdentification_PreDesc_Id[] = { + "NullPtr", + "Valid" +}; + +static const char * const * const ClassicTaskIdentification_PreDesc[] = { + ClassicTaskIdentification_PreDesc_Name, + ClassicTaskIdentification_PreDesc_Node, + ClassicTaskIdentification_PreDesc_Id, + NULL +}; + +/* Test rtems_task_ident() support */ + +static void ClassicTaskIdentification_Pre_Name_Prepare( + ClassicTaskIdentification_Context *ctx, + ClassicTaskIdentification_Pre_Name state +) +{ + /* Prologue */ + + switch ( state ) { + case ClassicTaskIdentification_Pre_Name_Invalid: { + ctx->name = 1; + break; + } + + case ClassicTaskIdentification_Pre_Name_Self: { + ctx->name = RTEMS_SELF; + break; + } + + case ClassicTaskIdentification_Pre_Name_Valid: { + ctx->name = rtems_build_name( 'T', 'A', 'S', 'K' ); + break; + } + } + + /* Epilogue */ +} + +static void ClassicTaskIdentification_Pre_Node_Prepare( + ClassicTaskIdentification_Context *ctx, + ClassicTaskIdentification_Pre_Node state +) +{ + switch ( state ) { + case ClassicTaskIdentification_Pre_Node_Local: { + ctx->node = 1; + break; + } + + case ClassicTaskIdentification_Pre_Node_Remote: { + ctx->node = 2; + break; + } + + case ClassicTaskIdentification_Pre_Node_Invalid: { + ctx->node = 256; + break; + } + + case ClassicTaskIdentification_Pre_Node_SearchAll: { + ctx->node = RTEMS_SEARCH_ALL_NODES; + break; + } + + case ClassicTaskIdentification_Pre_Node_SearchOther: { + ctx->node = RTEMS_SEARCH_OTHER_NODES; + break; + } + + case ClassicTaskIdentification_Pre_Node_SearchLocal: { + ctx->node = RTEMS_SEARCH_LOCAL_NODE; + break; + } + } +} + +static void ClassicTaskIdentification_Pre_Id_Prepare( + ClassicTaskIdentification_Context *ctx, + ClassicTaskIdentification_Pre_Id state +) +{ + switch ( state ) { + case ClassicTaskIdentification_Pre_Id_NullPtr: { + ctx->id = NULL; + break; + } + + case ClassicTaskIdentification_Pre_Id_Valid: { + ctx->id_value = 0xffffffff; + ctx->id = &ctx->id_value; + break; + } + } +} + +static void ClassicTaskIdentification_Post_Status_Check( + ClassicTaskIdentification_Context *ctx, + ClassicTaskIdentification_Post_Status state +) +{ + switch ( state ) { + case ClassicTaskIdentification_Post_Status_Ok: { + T_rsc(ctx->status, RTEMS_SUCCESSFUL); + break; + } + + case ClassicTaskIdentification_Post_Status_InvAddr: { + T_rsc(ctx->status, RTEMS_INVALID_ADDRESS); + break; + } + + case ClassicTaskIdentification_Post_Status_InvName: { + T_rsc(ctx->status, RTEMS_INVALID_NAME); + break; + } + + case ClassicTaskIdentification_Post_Status_InvNode: { + T_rsc(ctx->status, RTEMS_INVALID_NODE); + break; + } + + case ClassicTaskIdentification_Post_Status_InvId: { + T_rsc(ctx->status, RTEMS_INVALID_ID); + break; + } + } +} + +static void ClassicTaskIdentification_Post_Id_Check( + ClassicTaskIdentification_Context *ctx, + ClassicTaskIdentification_Post_Id state +) +{ + switch ( state ) { + case ClassicTaskIdentification_Post_Id_Nop: { + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, 0xffffffff); + break; + } + + case ClassicTaskIdentification_Post_Id_NullPtr: { + T_null(ctx->id) + break; + } + + case ClassicTaskIdentification_Post_Id_Self: { + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, rtems_task_self()); + break; + } + + case ClassicTaskIdentification_Post_Id_LocalTask: { + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, ctx->id_local_task); + break; + } + + case ClassicTaskIdentification_Post_Id_RemoteTask: { + T_eq_ptr(ctx->id, &ctx->id_value); + T_eq_u32(ctx->id_value, ctx->id_remote_task); + break; + } + } +} + +/** + * @brief Setup brief description. + * + * Setup description. + */ +static void ClassicTaskIdentification_Setup( + ClassicTaskIdentification_Context *ctx +) +{ + rtems_status_code sc; + + sc = rtems_task_create( + rtems_build_name( 'T', 'A', 'S', 'K' ), + 1, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &ctx->id_local_task + ); + T_assert_rsc_success( sc ); +} + +static void ClassicTaskIdentification_Setup_Wrap( void *arg ) +{ + ClassicTaskIdentification_Context *ctx; + + ctx = arg; + ctx->in_action_loop = false; + ClassicTaskIdentification_Setup( ctx ); +} + +static void ClassicTaskIdentification_Teardown( + ClassicTaskIdentification_Context *ctx +) +{ + rtems_status_code sc; + + if ( ctx->id_local_task != 0 ) { + sc = rtems_task_delete( ctx->id_local_task ); + T_rsc_success( sc ); + } +} + +static void ClassicTaskIdentification_Teardown_Wrap( void *arg ) +{ + ClassicTaskIdentification_Context *ctx; + + ctx = arg; + ctx->in_action_loop = false; + ClassicTaskIdentification_Teardown( ctx ); +} + +static void ClassicTaskIdentification_Scope( void *arg, char *buf, size_t n ) +{ + ClassicTaskIdentification_Context *ctx; + + ctx = arg; + + if ( ctx->in_action_loop ) { + T_get_scope( ClassicTaskIdentification_PreDesc, buf, n, ctx->pcs ); + } +} + +static T_fixture ClassicTaskIdentification_Fixture = { + .setup = ClassicTaskIdentification_Setup_Wrap, + .stop = NULL, + .teardown = ClassicTaskIdentification_Teardown_Wrap, + .scope = ClassicTaskIdentification_Scope, + .initial_context = &ClassicTaskIdentification_Instance +}; + +static const uint8_t ClassicTaskIdentification_TransitionMap[][ 2 ] = { + { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_Self + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_Self + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_Self + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_Self + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_Self + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_Self + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_LocalTask + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { +#if defined(RTEMS_MULTIPROCESSING) + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_RemoteTask +#else + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop +#endif + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_LocalTask + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { +#if defined(RTEMS_MULTIPROCESSING) + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_RemoteTask +#else + ClassicTaskIdentification_Post_Status_InvName, + ClassicTaskIdentification_Post_Id_Nop +#endif + }, { + ClassicTaskIdentification_Post_Status_InvAddr, + ClassicTaskIdentification_Post_Id_NullPtr + }, { + ClassicTaskIdentification_Post_Status_Ok, + ClassicTaskIdentification_Post_Id_LocalTask + } +}; + +/** + * @fn void T_case_body_ClassicTaskIdentification( void ) + * + * @brief Test rtems_task_ident() brief description. + * + * Test rtems_task_ident() description. + */ +T_TEST_CASE_FIXTURE( + ClassicTaskIdentification, + &ClassicTaskIdentification_Fixture +) +{ + ClassicTaskIdentification_Context *ctx; + size_t index; + + ctx = T_fixture_context(); + ctx->in_action_loop = true; + index = 0; + + for ( + ctx->pcs[ 0 ] = ClassicTaskIdentification_Pre_Name_Invalid; + ctx->pcs[ 0 ] != ClassicTaskIdentification_Pre_Name_Valid + 1; + ++ctx->pcs[ 0 ] + ) { + for ( + ctx->pcs[ 1 ] = ClassicTaskIdentification_Pre_Node_Local; + ctx->pcs[ 1 ] != ClassicTaskIdentification_Pre_Node_SearchLocal + 1; + ++ctx->pcs[ 1 ] + ) { + for ( + ctx->pcs[ 2 ] = ClassicTaskIdentification_Pre_Id_NullPtr; + ctx->pcs[ 2 ] != ClassicTaskIdentification_Pre_Id_Valid + 1; + ++ctx->pcs[ 2 ] + ) { + ClassicTaskIdentification_Pre_Name_Prepare( ctx, ctx->pcs[ 0 ] ); + ClassicTaskIdentification_Pre_Node_Prepare( ctx, ctx->pcs[ 1 ] ); + ClassicTaskIdentification_Pre_Id_Prepare( ctx, ctx->pcs[ 2 ] ); + ctx->status = rtems_task_ident( ctx->name, ctx->node, ctx->id ); + ClassicTaskIdentification_Post_Status_Check( + ctx, + ClassicTaskIdentification_TransitionMap[ index ][ 0 ] + ); + ClassicTaskIdentification_Post_Id_Check( + ctx, + ClassicTaskIdentification_TransitionMap[ index ][ 1 ] + ); + ++index; + } + } + } +} + +/** @} */ + +/** + * @defgroup RTEMSTestCaseTestCase Test Case + * + * @ingroup RTEMSTestSuiteBlueGreen + * + * @brief Test Case + * + * @{ + */ + +/* Test case support code */ + +/** + * @fn void T_case_body_TestCase( void ) + * + * @brief Test case brief description. + * + * Test case description. + * + * This test case performs the following actions: + * + * - Test case action 0 description. + * + * - Test case action 0 check 0 description. + * + * - Test case action 0 check 1 description. + * + * - Test case action 1 description. + * + * - Test case action 1 check 0 description. + * + * - Test case action 1 check 1 description. + */ +T_TEST_CASE( TestCase ) +{ + /* Test case prologue code */ + + T_plan(2); + + /* Test case action 0 code */ + /* Test case action 0 check 0 code */ + /* Test case action 0 check 1 code; step 0 */ + + /* Test case action 1 code */ + /* Test case action 1 check 0 code; step 1 */ + /* Test case action 1 check 1 code */ + + /* Test case epilogue code */ +} + +/** @} */ + +/** + * @defgroup RTEMSTestCaseTestCase2 Test Case 2 + * + * @ingroup RTEMSTestSuiteBlueGreen + * + * @brief Test Case + * + * @{ + */ + +/** + * @fn void T_case_body_TestCase2( void ) + * + * @brief Test case 2 brief description. + * + * Test case 2 description. + * + * This test case performs the following actions: + * + * - Test case 2 action 0 description. + * + * - Test case 2 action 0 check 0 description. + * + * - Test case 2 action 0 check 1 description. + * + * - Test case 2 action 1 description. + */ +T_TEST_CASE_FIXTURE( TestCase2, &test_case_2_fixture ) +{ + /* Test case 2 action 0 code */ + /* Test case 2 action 0 check 0 code */ + /* Test case 2 action 0 check 1 code */ + + /* Test case 2 action 1 code */ +} + +/** @} */ +""" + assert content == src.read() + + with open(os.path.join(base_directory, "tc34.c"), "r") as src: + content = """/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseTestCase3 + * @ingroup RTEMSTestCaseTestCase4 + */ + +/* + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <c.h> + +#include "z.h" + +#include <t.h> + +/** + * @defgroup RTEMSTestCaseTestCase3 Test Case 3 + * + * @ingroup RTEMSTestSuiteBlueGreen + * + * @brief Test Case + * + * @{ + */ + +/** + * @fn void T_case_body_TestCase3( void ) + * + * @brief Test case 3 brief description. + * + * Test case 3 description. + * + * This test case performs the following actions: + * + * - Test case 3 action 0 description. + * + * - Test case 3 action 0 check 0 description. + */ +T_TEST_CASE( TestCase3 ) +{ + T_plan(1); + + /* Test case 3 action 0 code */ + /* Test case 3 action 0 check 0 code; step 0 */ +} + +/** @} */ + +/** + * @defgroup RTEMSTestCaseTestCase4 Test Case 4 + * + * @ingroup RTEMSTestSuiteBlueGreen + * + * @brief Test Case + * + * @{ + */ + +/** + * @fn void T_case_body_TestCase4( void ) + * + * @brief Test case 4 brief description. + * + * Test case 4 description. + */ +T_TEST_CASE( TestCase4 ) +{ + /* Test case 4 epilogue code */ +} + +/** @} */ +""" + assert content == src.read() + with open(os.path.join(base_directory, "action2.h"), "r") as src: + content = """/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseAction2 + */ + +/* + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ACTION2_H +#define _ACTION2_H + +#include <d.h> + +#include "e.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup RTEMSTestCaseAction2 + * + * @{ + */ + +typedef enum { + Action2_Pre_A_X, + Action2_Pre_A_Y +} Action2_Pre_A; + +typedef enum { + Action2_Pre_B_X, + Action2_Pre_B_Y +} Action2_Pre_B; + +typedef enum { + Action2_Post_A_X, + Action2_Post_A_Y +} Action2_Post_A; + +typedef enum { + Action2_Post_B_X, + Action2_Post_B_Y +} Action2_Post_B; + +/* Header code for Action 2 with Action2_Run() */ + +/** + * @brief Test brief. + * + * Test description. + * + * @param[in] a Parameter A description. + * + * @param b Parameter B description. + * + * @param[out] c Parameter C description. + */ +void Action2_Run( int *a, int b, int *c ); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ACTION2_H */ +""" + assert content == src.read() + with open(os.path.join(base_directory, "action2.c"), "r") as src: + content = """/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseAction2 + */ + +/* + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <a.h> + +#include "b.h" + +#include <t.h> + +/** + * @defgroup RTEMSTestCaseAction2 Action 2 + * + * @ingroup RTEMSTestSuiteBlueGreen + * + * @brief Test Case + * + * @{ + */ + +/** + * @brief Test context for Action 2 test case. + */ +typedef struct { + /** + * @brief Context member brief. + * + * Context member description. + */ + int member; + + /** + * @brief This member contains a copy of the corresponding Action2_Run() + * parameter. + */ + int *a; + + /** + * @brief This member contains a copy of the corresponding Action2_Run() + * parameter. + */ + int b; + + /** + * @brief This member contains a copy of the corresponding Action2_Run() + * parameter. + */ + int *c; + + /** + * @brief This member defines the pre-condition states for the next action. + */ + size_t pcs[ 2 ]; + + /** + * @brief This member indicates if the test action loop is currently + * executed. + */ + bool in_action_loop; +} Action2_Context; + +static Action2_Context + Action2_Instance; + +static const char * const Action2_PreDesc_A[] = { + "X", + "Y" +}; + +static const char * const Action2_PreDesc_B[] = { + "X", + "Y" +}; + +static const char * const * const Action2_PreDesc[] = { + Action2_PreDesc_A, + Action2_PreDesc_B, + NULL +}; + +/* Support code */ + +static void Action2_Pre_A_Prepare( Action2_Context *ctx, Action2_Pre_A state ) +{ + /* Pre A prologue. */ + + switch ( state ) { + case Action2_Pre_A_X: { + /* Pre A X */ + break; + } + + case Action2_Pre_A_Y: { + /* Pre A Y */ + break; + } + } + + /* Pre A epilogue. */ +} + +static void Action2_Pre_B_Prepare( Action2_Context *ctx, Action2_Pre_B state ) +{ + /* Pre B prologue. */ + + switch ( state ) { + case Action2_Pre_B_X: { + /* Pre B X */ + break; + } + + case Action2_Pre_B_Y: { + /* Pre B Y */ + break; + } + } + + /* Pre B epilogue. */ +} + +static void Action2_Post_A_Check( Action2_Context *ctx, Action2_Post_A state ) +{ + /* Post A prologue. */ + + switch ( state ) { + case Action2_Post_A_X: { + /* Post A X */ + break; + } + + case Action2_Post_A_Y: { + /* Post A Y */ + break; + } + } + + /* Post A epilogue. */ +} + +static void Action2_Post_B_Check( Action2_Context *ctx, Action2_Post_B state ) +{ + /* Post B prologue. */ + + switch ( state ) { + case Action2_Post_B_X: { + /* Post B X */ + break; + } + + case Action2_Post_B_Y: { + /* Post B Y */ + break; + } + } + + /* Post B epilogue. */ +} + +/** + * @brief Setup brief. + * + * Setup description. + */ +static void Action2_Setup( Action2_Context *ctx ) +{ + /* Setup code */ +} + +static void Action2_Setup_Wrap( void *arg ) +{ + Action2_Context *ctx; + + ctx = arg; + ctx->in_action_loop = false; + Action2_Setup( ctx ); +} + +/** + * @brief Teardown brief. + * + * Teardown description. + */ +static void Action2_Teardown( Action2_Context *ctx ) +{ + /* Teardown code */ +} + +static void Action2_Teardown_Wrap( void *arg ) +{ + Action2_Context *ctx; + + ctx = arg; + ctx->in_action_loop = false; + Action2_Teardown( ctx ); +} + +static void Action2_Scope( void *arg, char *buf, size_t n ) +{ + Action2_Context *ctx; + + ctx = arg; + + if ( ctx->in_action_loop ) { + T_get_scope( Action2_PreDesc, buf, n, ctx->pcs ); + } +} + +static T_fixture Action2_Fixture = { + .setup = Action2_Setup_Wrap, + .stop = NULL, + .teardown = Action2_Teardown_Wrap, + .scope = Action2_Scope, + .initial_context = &Action2_Instance +}; + +static const uint8_t Action2_TransitionMap[][ 2 ] = { + { + Action2_Post_A_X, + Action2_Post_B_Y + }, { + Action2_Post_A_X, + Action2_Post_B_Y + }, { + Action2_Post_A_X, + Action2_Post_B_Y + }, { + Action2_Post_A_X, + Action2_Post_B_Y + } +}; + +static T_fixture_node Action2_Node; + +void Action2_Run( int *a, int b, int *c ) +{ + Action2_Context *ctx; + size_t index; + + ctx = T_push_fixture( &Action2_Node, &Action2_Fixture ); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->in_action_loop = true; + index = 0; + + for ( + ctx->pcs[ 0 ] = Action2_Pre_A_X; + ctx->pcs[ 0 ] != Action2_Pre_A_Y + 1; + ++ctx->pcs[ 0 ] + ) { + for ( + ctx->pcs[ 1 ] = Action2_Pre_B_X; + ctx->pcs[ 1 ] != Action2_Pre_B_Y + 1; + ++ctx->pcs[ 1 ] + ) { + Action2_Pre_A_Prepare( ctx, ctx->pcs[ 0 ] ); + Action2_Pre_B_Prepare( ctx, ctx->pcs[ 1 ] ); + /* Action */ + Action2_Post_A_Check( + ctx, + Action2_TransitionMap[ index ][ 0 ] + ); + Action2_Post_B_Check( + ctx, + Action2_TransitionMap[ index ][ 1 ] + ); + ++index; + } + } + + T_pop_fixture(); +} + +/** @} */ +""" + assert content == src.read() diff --git a/rtemsspec/tests/util.py b/rtemsspec/tests/util.py new file mode 100644 index 00000000..d07df74c --- /dev/null +++ b/rtemsspec/tests/util.py @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" Unit tests utility module. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import shutil +from typing import Dict + + +def create_item_cache_config_and_copy_spec( + tmp_dir: str, + spec_dir: str, + with_spec_types: bool = False) -> Dict[str, str]: + """ + Creates an item cache configuration and copies a specification + directory to the temporary tests directory. + """ + config = {} + cache_dir = os.path.join(tmp_dir, "cache") + config["cache-directory"] = os.path.normpath(cache_dir) + spec_src = os.path.join(os.path.dirname(__file__), spec_dir) + spec_dst = os.path.join(tmp_dir, "spec") + shutil.copytree(spec_src, spec_dst) + config["paths"] = [os.path.normpath(spec_dst)] + if with_spec_types: + spec = os.path.join(os.path.dirname(__file__), "spec") + shutil.copytree(spec, os.path.join(spec_dst, "spec")) + config["spec-type-root-uid"] = "/spec/root" + else: + config["spec-type-root-uid"] = None + return config diff --git a/rtemsspec/util.py b/rtemsspec/util.py new file mode 100644 index 00000000..d2403cd3 --- /dev/null +++ b/rtemsspec/util.py @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides utility functions. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import shutil +from typing import Any, List +import yaml + + +def copy_files(src_dir: str, dst_dir: str, files: List[str]) -> None: + """ + Copies a list of files in the source directory to the destination + directory preserving the directory of the files relative to the source + directory. + """ + for a_file in files: + src = os.path.join(src_dir, a_file) + dst = os.path.join(dst_dir, a_file) + os.makedirs(os.path.dirname(dst), exist_ok=True) + shutil.copy2(src, dst) + + +def load_config(config_filename: str) -> Any: + """ Loads the configuration file with recursive includes. """ + class IncludeLoader(yaml.SafeLoader): # pylint: disable=too-many-ancestors + """ YAML loader customization to process custom include tags. """ + _filenames = [config_filename] + + def include(self, node): + """ Processes the custom include tag. """ + container = IncludeLoader._filenames[0] + dirname = os.path.dirname(container) + filename = os.path.join(dirname, self.construct_scalar(node)) + IncludeLoader._filenames.insert(0, filename) + with open(filename, "r") as included_file: + data = yaml.load(included_file, IncludeLoader) + IncludeLoader._filenames.pop() + return data + + IncludeLoader.add_constructor("!include", IncludeLoader.include) + with open(config_filename, "r") as config_file: + return yaml.load(config_file.read(), Loader=IncludeLoader) diff --git a/rtemsspec/validation.py b/rtemsspec/validation.py new file mode 100644 index 00000000..d2d5a500 --- /dev/null +++ b/rtemsspec/validation.py @@ -0,0 +1,714 @@ +# SPDX-License-Identifier: BSD-2-Clause +""" This module provides functions for the generation of validation tests. """ + +# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import itertools +import os +from typing import Any, Dict, List, NamedTuple, Optional, Tuple + +from rtemsspec.content import CContent, CInclude, enabled_by_to_exp, \ + ExpressionMapper +from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper + +ItemMap = Dict[str, Item] + + +class _CodeMapper(ItemMapper): + def get_value(self, ctx: ItemGetValueContext) -> Any: + if ctx.type_path_key == "requirement/functional/action:/test-run": + return f"{ctx.item['test-name'].replace(' ', '')}_Run" + raise KeyError + + +class _TextMapper(ItemMapper): + def __init__(self, item: Item): + super().__init__(item) + self._step = 0 + + @property + def steps(self): + """ The count of test steps. """ + return self._step + + def reset_step(self): + """ Resets the test step counter. """ + self._step = 0 + + def map(self, identifier: str) -> Tuple[Item, Any]: + if identifier == "step": + step = self._step + self._step = step + 1 + return self._item, str(step) + return super().map(identifier) + + +def _add_ingroup(content: CContent, items: List["_TestItem"]) -> None: + content.add_ingroup([item.group_identifier for item in items]) + + +class _TestItem: + """ A test item with a defaul implementation for test cases. """ + def __init__(self, item: Item): + self._item = item + self._ident = self.name.replace(" ", "") + self._code_mapper = _CodeMapper(self._item) + self._text_mapper = _TextMapper(self._item) + + def __getitem__(self, key: str): + return self._item[key] + + @property + def item(self) -> Item: + """ Returns the item. """ + return self._item + + @property + def uid(self) -> str: + """ Returns the item UID. """ + return self._item.uid + + @property + def ident(self) -> str: + """ Returns the test identifier. """ + return self._ident + + @property + def name(self) -> str: + """ Returns the name. """ + return self._item["name"] + + @property + def includes(self) -> List[str]: + """ Returns the list of includes. """ + return self._item["includes"] + + @property + def local_includes(self) -> List[str]: + """ Returns the list of local includes. """ + return self._item["local-includes"] + + @property + def group_identifier(self) -> str: + """ Returns the group identifier. """ + return f"RTEMSTestCase{self.ident}" + + def substitute_code(self, text: Optional[str]) -> str: + """ Performs a variable substitution for code. """ + return self._code_mapper.substitute(text) + + def substitute_text(self, + text: Optional[str], + prefix: Optional[str] = None) -> str: + """ + Performs a variable substitution for text with an optinal prefix. + """ + if prefix: + return self._text_mapper.substitute_with_prefix(text, prefix) + return self._text_mapper.substitute(text) + + def add_test_case_description( + self, content: CContent, + test_case_to_suites: Dict[str, List["_TestItem"]]) -> None: + """ Adds the test case description. """ + with content.defgroup_block(self.group_identifier, self.name): + _add_ingroup(content, test_case_to_suites[self.uid]) + content.add(["@brief Test Case", "", "@{"]) + + def _add_test_case_action_description(self, content: CContent) -> None: + actions = self["actions"] + if actions: + content.add("This test case performs the following actions:") + for action in actions: + content.wrap(self.substitute_text(action["description"]), + initial_indent="- ") + for check in action["checks"]: + content.wrap(self.substitute_text(check["description"]), + initial_indent=" - ", + subsequent_indent=" ") + + def _generate_test_case_actions(self) -> CContent: + content = CContent() + for action in self["actions"]: + content.add(self.substitute_code(action["action"])) + for check in action["checks"]: + content.append(self.substitute_text(check["check"])) + return content + + def generate(self, content: CContent, _base_directory: str, + test_case_to_suites: Dict[str, List["_TestItem"]]) -> None: + """ Generates the content. """ + self.add_test_case_description(content, test_case_to_suites) + content.add(self.substitute_code(self["support"])) + with content.function_block(f"void T_case_body_{self.ident}( void )"): + content.add_brief_description(self.substitute_text(self["brief"])) + content.wrap(self.substitute_text(self["description"])) + self._add_test_case_action_description(content) + content.gap = False + params = [f"{self.ident}"] + fixture = self["fixture"] + if fixture: + params.append(f"&{fixture}") + name = "T_TEST_CASE_FIXTURE" + else: + name = "T_TEST_CASE" + with content.function("", name, params): + content.add(self.substitute_code(self["prologue"])) + self._text_mapper.reset_step() + action_content = self._generate_test_case_actions() + if self._text_mapper.steps > 0: + content.add(f"T_plan({self._text_mapper.steps});") + content.add(action_content) + content.add(self.substitute_code(self["epilogue"])) + content.add("/** @} */") + + +class _TestSuiteItem(_TestItem): + """ A test suite item. """ + @property + def group_identifier(self) -> str: + return f"RTEMSTestSuite{self.ident}" + + def generate(self, content: CContent, _base_directory: str, + _test_case_to_suites: Dict[str, List[_TestItem]]) -> None: + with content.defgroup_block(self.group_identifier, self.name): + content.add(["@ingroup RTEMSTestSuites", "", "@brief Test Suite"]) + content.wrap(self.substitute_text(self["description"])) + content.add("@{") + content.add(self.substitute_code(self["code"])) + content.add("/** @} */") + + +class _PostCondition(NamedTuple): + """ A set of post conditions with an enabled by expression. """ + enabled_by: str + conditions: Tuple[int, ...] + + +_DirectiveIndexToEnum = Tuple[Tuple[str, ...], ...] +_TransitionMap = List[List[_PostCondition]] + + +def _directive_state_to_index( + conditions: List[Any]) -> Tuple[Dict[str, int], ...]: + return tuple( + dict((state["name"], index) + for index, state in enumerate(condition["states"])) + for condition in conditions) + + +def _directive_index_to_enum(prefix: str, + conditions: List[Any]) -> _DirectiveIndexToEnum: + return tuple( + tuple([f"{prefix}_{condition['name']}"] + [ + f"{prefix}_{condition['name']}_{state['name']}" + for state in condition["states"] + ]) for index, condition in enumerate(conditions)) + + +def _directive_add_enum(content: CContent, + index_to_enum: _DirectiveIndexToEnum) -> None: + for enum in index_to_enum: + content.add("typedef enum {") + with content.indent(): + content.add(",\n".join(enum[1:])) + content.add(f"}} {enum[0]};") + + +class _TestDirectiveItem(_TestItem): + """ A test directive item. """ + + # pylint: disable=too-many-instance-attributes + def __init__(self, item: Item): + super().__init__(item) + self._pre_condition_count = len(item["pre-conditions"]) + self._post_condition_count = len(item["post-conditions"]) + self._pre_index_to_enum = _directive_index_to_enum( + f"{self.ident}_Pre", item["pre-conditions"]) + self._post_index_to_enum = _directive_index_to_enum( + f"{self.ident}_Post", item["post-conditions"]) + self._pre_state_to_index = _directive_state_to_index( + item["pre-conditions"]) + self._post_state_to_index = _directive_state_to_index( + item["post-conditions"]) + self._pre_index_to_condition = dict( + (index, condition) + for index, condition in enumerate(item["pre-conditions"])) + self._post_index_to_name = dict( + (index, condition["name"]) + for index, condition in enumerate(item["post-conditions"])) + + @property + def name(self) -> str: + return self._item["test-name"] + + @property + def context(self) -> str: + """ Returns the test case context type. """ + return f"{self._ident}_Context" + + @property + def includes(self) -> List[str]: + return self._item["test-includes"] + + @property + def local_includes(self) -> List[str]: + return self._item["test-local-includes"] + + def _add_pre_condition_descriptions(self, content: CContent) -> None: + for condition in self["pre-conditions"]: + content.add("static const char * const " + f"{self.ident}_PreDesc_{condition['name']}[] = {{") + with content.indent(): + content.add(",\n".join(f"\"{state['name']}\"" + for state in condition["states"])) + content.add("};") + content.add("static const char * const * const " + f"{self.ident}_PreDesc[] = {{") + with content.indent(): + content.add(",\n".join([ + f"{self.ident}_PreDesc_{condition['name']}" + for condition in self["pre-conditions"] + ] + ["NULL"])) + content.add("};") + + def _add_context(self, content: CContent, header: Dict[str, Any]) -> None: + with content.doxygen_block(): + content.add_brief_description( + f"Test context for {self.name} test case.") + content.append("typedef struct {") + with content.indent(): + for info in self["test-context"]: + content.add_description_block(info["brief"], + info["description"]) + content.add(f"{info['member'].strip()};") + for param in self._get_run_params(header): + content.add_description_block( + "This member contains a copy of the corresponding " + f"{self.ident}_Run() parameter.", None) + content.add(f"{param};") + content.add_description_block( + "This member defines the pre-condition states " + "for the next action.", None) + content.add(f"size_t pcs[ {self._pre_condition_count} ];") + content.add_description_block( + "This member indicates if the test action loop " + "is currently executed.", None) + content.add("bool in_action_loop;") + content.add([ + f"}} {self.context};", "", f"static {self.context}", + f" {self.ident}_Instance;" + ]) + + def _add_scope_body(self, content: CContent) -> None: + with content.condition("ctx->in_action_loop"): + content.call_function( + None, "T_get_scope", + [f"{self.ident}_PreDesc", "buf", "n", "ctx->pcs"]) + + def _add_fixture_scope(self, content: CContent) -> None: + params = ["void *arg", "char *buf", "size_t n"] + with content.function("static void", f"{self.ident}_Scope", params): + content.add([f"{self.context} *ctx;", "", "ctx = arg;"]) + self._add_scope_body(content) + + def _add_fixture_method(self, content: CContent, + info: Optional[Dict[str, Optional[str]]], + name: str) -> str: + if not info: + return "NULL" + method = f"{self.ident}_{name}" + wrap = f"{method}_Wrap" + content.add_description_block(info["brief"], info["description"]) + with content.function("static void", method, [f"{self.context} *ctx"]): + content.add(self.substitute_code(info["code"])) + with content.function("static void", wrap, ["void *arg"]): + content.add([ + f"{self.context} *ctx;", "", "ctx = arg;", + "ctx->in_action_loop = false;", f"{method}( ctx );" + ]) + return wrap + + def _add_transitions(self, condition_index: int, map_index: int, + transition: Dict[str, + Any], transition_map: _TransitionMap, + post: Tuple[int, ...]) -> None: + # pylint: disable=too-many-arguments + if condition_index < self._pre_condition_count: + condition = self._pre_index_to_condition[condition_index] + state_count = len(condition["states"]) + map_index *= state_count + states = transition["pre-conditions"][condition["name"]] + if isinstance(states, str): + assert states == "all" + for index in range(state_count): + self._add_transitions(condition_index + 1, + map_index + index, transition, + transition_map, post) + else: + for state in states: + self._add_transitions( + condition_index + 1, map_index + + self._pre_state_to_index[condition_index][state], + transition, transition_map, post) + else: + enabled_by = enabled_by_to_exp(transition["enabled-by"], + ExpressionMapper()) + assert enabled_by != "1" or not transition_map[map_index] + transition_map[map_index].append(_PostCondition(enabled_by, post)) + + def _get_transition_map(self) -> _TransitionMap: + transition_count = 1 + for condition in self["pre-conditions"]: + state_count = len(condition["states"]) + assert state_count > 0 + transition_count *= state_count + transition_map = [list() for _ in range(transition_count) + ] # type: _TransitionMap + for transition in self["transition-map"]: + post = tuple(self._post_state_to_index[index][ + transition["post-conditions"][self._post_index_to_name[index]]] + for index in range(self._post_condition_count)) + self._add_transitions(0, 0, transition, transition_map, post) + return transition_map + + def _post_condition_enumerators(self, conditions: Any) -> str: + return ",\n".join( + f" {self._post_index_to_enum[index][condition + 1]}" + for index, condition in enumerate(conditions)) + + def _add_transition_map(self, content: CContent) -> None: + transition_map = self._get_transition_map() + content.add([ + "static const uint8_t " + f"{self.ident}_TransitionMap[][ {self._post_condition_count} ]" + " = {", " {" + ]) + elements = [] + for transistions in transition_map: + assert transistions[0].enabled_by == "1" + if len(transistions) == 1: + elements.append( + self._post_condition_enumerators( + transistions[0].conditions)) + else: + ifelse = "#if " + enumerators = [] # type: List[str] + for variant in transistions[1:]: + enumerators.append(ifelse + variant.enabled_by) + enumerators.append( + self._post_condition_enumerators(variant.conditions)) + ifelse = "#elif " + enumerators.append("#else") + enumerators.append( + self._post_condition_enumerators( + transistions[0].conditions)) + enumerators.append("#endif") + elements.append("\n".join(enumerators)) + content.append(["\n }, {\n".join(elements), " }", "};"]) + + def _add_action(self, content: CContent) -> None: + for index, enum in enumerate(self._pre_index_to_enum): + content.append(f"{enum[0]}_Prepare( ctx, ctx->pcs[ {index} ] );") + content.append(self.substitute_code(self["test-action"])) + transition_map = f"{self.ident}_TransitionMap" + for index, enum in enumerate(self._post_index_to_enum): + content.append([ + f"{enum[0]}_Check(", " ctx,", + f" {transition_map}[ index ][ {index} ]", ");" + ]) + content.append("++index;") + + def _add_for_loops(self, content: CContent, index: int) -> None: + if index < self._pre_condition_count: + var = f"ctx->pcs[ {index} ]" + begin = self._pre_index_to_enum[index][1] + end = self._pre_index_to_enum[index][-1] + with content.for_loop(f"{var} = {begin}", f"{var} != {end} + 1", + f"++{var}"): + self._add_for_loops(content, index + 1) + else: + self._add_action(content) + + def _add_test_case(self, content: CContent, header: Dict[str, + Any]) -> None: + fixture = f"{self.ident}_Fixture" + prologue = CContent() + epilogue = CContent() + if header: + content.add(f"static T_fixture_node {self.ident}_Node;") + ret = "void" + name = f"{self.ident}_Run" + params = self._get_run_params(header) + prologue.add([f"{self.context} *ctx;", "size_t index;"]) + prologue.call_function("ctx =", "T_push_fixture", + [f"&{self.ident}_Node", f"&{fixture}"]) + prologue.add([ + f"ctx->{param['name']} = {param['name']};" + for param in header["run-params"] + ] + ["ctx->in_action_loop = true;", "index = 0;"]) + epilogue.add("T_pop_fixture();") + align = True + else: + with content.function_block( + f"void T_case_body_{self.ident}( void )"): + content.add_brief_description(self["test-brief"]) + content.wrap(self["test-description"]) + content.gap = False + ret = "" + name = "T_TEST_CASE_FIXTURE" + params = [f"{self.ident}", f"&{fixture}"] + prologue.add([ + f"{self.context} *ctx;", "size_t index;", "", + "ctx = T_fixture_context();", "ctx->in_action_loop = true;", + "index = 0;" + ]) + align = False + with content.function(ret, name, params, align=align): + content.add(prologue) + self._add_for_loops(content, 0) + content.add(epilogue) + + def _add_handler(self, content: CContent, conditions: List[Any], + index_to_enum: _DirectiveIndexToEnum, + action: str) -> None: + for condition_index, condition in enumerate(conditions): + enum = index_to_enum[condition_index] + handler = f"{enum[0]}_{action}" + params = [f"{self.context} *ctx", f"{enum[0]} state"] + with content.function("static void", handler, params): + content.add(self.substitute_code(condition["test-prologue"])) + content.add("switch ( state ) {") + with content.indent(): + for state_index, state in enumerate(condition["states"]): + content.add(f"case {enum[state_index + 1]}: {{") + with content.indent(): + content.add( + self.substitute_code(state["test-code"])) + content.append("break;") + content.add("}") + content.add("}") + content.add(self.substitute_code(condition["test-epilogue"])) + + def _get_run_params(self, header: Optional[Dict[str, Any]]) -> List[str]: + if not header: + return [] + return [ + self.substitute_text(param["specifier"], + f"test-header/run-params[{index}]") + for index, param in enumerate(header["run-params"]) + ] + + def _generate_header_body(self, content: CContent, + header: Dict[str, Any]) -> None: + _directive_add_enum(content, self._pre_index_to_enum) + _directive_add_enum(content, self._post_index_to_enum) + content.add(self.substitute_code(header["code"])) + with content.doxygen_block(): + content.add_brief_description(self["test-brief"]) + content.wrap(self["test-description"]) + content.add_param_description(header["run-params"]) + content.gap = False + content.declare_function("void", f"{self.ident}_Run", + self._get_run_params(header)) + + def _generate_header(self, base_directory: str, header: Dict[str, + Any]) -> None: + content = CContent() + content.register_license_and_copyrights_of_item(self._item) + content.prepend_spdx_license_identifier() + with content.file_block(): + content.add_ingroup([self.group_identifier]) + content.add_copyrights_and_licenses() + with content.header_guard(os.path.basename(header["target"])): + content.add_includes(list(map(CInclude, header["includes"]))) + content.add_includes(list(map(CInclude, header["local-includes"])), + local=True) + with content.extern_c(): + with content.add_to_group(self.group_identifier): + self._generate_header_body(content, header) + content.write(os.path.join(base_directory, header["target"])) + + def generate(self, content: CContent, base_directory: str, + test_case_to_suites: Dict[str, List[_TestItem]]) -> None: + self.add_test_case_description(content, test_case_to_suites) + header = self["test-header"] + if header: + self._generate_header(base_directory, header) + else: + _directive_add_enum(content, self._pre_index_to_enum) + _directive_add_enum(content, self._post_index_to_enum) + self._add_context(content, header) + self._add_pre_condition_descriptions(content) + content.add(self.substitute_code(self["test-support"])) + self._add_handler(content, self["pre-conditions"], + self._pre_index_to_enum, "Prepare") + self._add_handler(content, self["post-conditions"], + self._post_index_to_enum, "Check") + setup = self._add_fixture_method(content, self["test-setup"], "Setup") + stop = self._add_fixture_method(content, self["test-stop"], "Stop") + teardown = self._add_fixture_method(content, self["test-teardown"], + "Teardown") + self._add_fixture_scope(content) + content.add([ + f"static T_fixture {self.ident}_Fixture = {{", + f" .setup = {setup},", f" .stop = {stop},", + f" .teardown = {teardown},", f" .scope = {self.ident}_Scope,", + f" .initial_context = &{self.ident}_Instance", "};" + ]) + self._add_transition_map(content) + self._add_test_case(content, header) + content.add("/** @} */") + + +class _SourceFile: + """ A test source file. """ + def __init__(self, filename: str): + """ Initializes a test source file. """ + self._file = filename + self._test_suites = [] # type: List[_TestItem] + self._test_cases = [] # type: List[_TestItem] + + @property + def test_suites(self) -> List[_TestItem]: + """ The test suites of the source file. """ + return self._test_suites + + @property + def test_cases(self) -> List[_TestItem]: + """ The test cases of the source file. """ + return self._test_cases + + def add_test_suite(self, test_suite: Item) -> None: + """ Adds a test suite to the source file. """ + self._test_suites.append(_TestSuiteItem(test_suite)) + + def add_test_case(self, test_case: Item) -> None: + """ Adds a test case to the source file. """ + self._test_cases.append(_TestItem(test_case)) + + def add_test_directive(self, test_directive: Item) -> None: + """ Adds a test directive to the source file. """ + self._test_cases.append(_TestDirectiveItem(test_directive)) + + def generate(self, base_directory: str, + test_case_to_suites: Dict[str, List[_TestItem]]) -> None: + """ + Generates the source file and the corresponding build specification. + """ + content = CContent() + includes = [] # type: List[CInclude] + local_includes = [] # type: List[CInclude] + for item in itertools.chain(self._test_suites, self._test_cases): + includes.extend(map(CInclude, item.includes)) + local_includes.extend(map(CInclude, item.local_includes)) + content.register_license_and_copyrights_of_item(item.item) + content.prepend_spdx_license_identifier() + with content.file_block(): + _add_ingroup(content, self._test_suites) + _add_ingroup(content, self._test_cases) + content.add_copyrights_and_licenses() + content.add_have_config() + content.add_includes(includes) + content.add_includes(local_includes, local=True) + content.add_includes([CInclude("t.h")]) + for item in sorted(self._test_cases, key=lambda x: x.name): + item.generate(content, base_directory, test_case_to_suites) + for item in sorted(self._test_suites, key=lambda x: x.name): + item.generate(content, base_directory, test_case_to_suites) + content.write(os.path.join(base_directory, self._file)) + + +class _TestProgram: + """ A test program. """ + def __init__(self, item: Item): + """ Initializes a test program. """ + self._item = item + self._source_files = [] # type: List[_SourceFile] + + @property + def source_files(self) -> List[_SourceFile]: + """ The source files of the test program. """ + return self._source_files + + def add_source_files(self, source_files: Dict[str, _SourceFile]) -> None: + """ + Adds the source files of the test program which are present in the + source file map. + """ + for filename in self._item["source"]: + source_file = source_files.get(filename, None) + if source_file is not None: + self._source_files.append(source_file) + + +def _get_source_file(filename: str, + source_files: Dict[str, _SourceFile]) -> _SourceFile: + return source_files.setdefault(filename, _SourceFile(filename)) + + +def _gather_items(item: Item, source_files: Dict[str, _SourceFile], + test_programs: List[_TestProgram]) -> None: + if item["type"] == "test-suite": + src = _get_source_file(item["target"], source_files) + src.add_test_suite(item) + elif item["type"] == "test-case": + src = _get_source_file(item["target"], source_files) + src.add_test_case(item) + elif item["type"] == "requirement" and item[ + "requirement-type"] == "functional" and item[ + "functional-type"] == "action": + src = _get_source_file(item["test-target"], source_files) + src.add_test_directive(item) + elif item["type"] == "build" and item["build-type"] == "test-program": + test_programs.append(_TestProgram(item)) + + +def generate(config: dict, item_cache: ItemCache) -> None: + """ + Generates source files and build specification items for validation test + suites and test cases according to the configuration. + + :param config: A dictionary with configuration entries. + :param item_cache: The specification item cache containing the validation + test suites and test cases. + """ + source_files = {} # type: Dict[str, _SourceFile] + test_programs = [] # type: List[_TestProgram] + for item in item_cache.all.values(): + _gather_items(item, source_files, test_programs) + + test_case_to_suites = {} # type: Dict[str, List[_TestItem]] + for test_program in test_programs: + test_program.add_source_files(source_files) + test_suites = [] # type: List[_TestItem] + for source_file in test_program.source_files: + test_suites.extend(source_file.test_suites) + for source_file in test_program.source_files: + for test_case in source_file.test_cases: + test_case_to_suites.setdefault(test_case.uid, + []).extend(test_suites) + + for src in source_files.values(): + src.generate(config["base-directory"], test_case_to_suites) |