Source code for pyEDAA.Reports.CodeCoverage.UCIS.Assertions

# ==================================================================================================================== #
#              _____ ____    _        _      ____                       _                                              #
#  _ __  _   _| ____|  _ \  / \      / \    |  _ \ ___ _ __   ___  _ __| |_ ___                                        #
# | '_ \| | | |  _| | | | |/ _ \    / _ \   | |_) / _ \ '_ \ / _ \| '__| __/ __|                                       #
# | |_) | |_| | |___| |_| / ___ \  / ___ \ _|  _ <  __/ |_) | (_) | |  | |_\__ \                                       #
# | .__/ \__, |_____|____/_/   \_\/_/   \_(_)_| \_\___| .__/ \___/|_|   \__|___/                                       #
# |_|    |___/                                        |_|                                                              #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2026-2026 Electronic Design Automation Abstraction (EDA²)                                                  #
#                                                                                                                      #
# Licensed under the Apache License, Version 2.0 (the "License");                                                      #
# you may not use this file except in compliance with the License.                                                     #
# You may obtain a copy of the License at                                                                              #
#                                                                                                                      #
#   http://www.apache.org/licenses/LICENSE-2.0                                                                         #
#                                                                                                                      #
# Unless required by applicable law or agreed to in writing, software                                                  #
# distributed under the License is distributed on an "AS IS" BASIS,                                                    #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                             #
# See the License for the specific language governing permissions and                                                  #
# limitations under the License.                                                                                       #
#                                                                                                                      #
# SPDX-License-Identifier: Apache-2.0                                                                                  #
# ==================================================================================================================== #
#
"""
The assertion coverage of the UCIS XML interchange format: an instance's ``<assertionCoverage>`` and its assertions.

An assertion - e.g. an ``assert``, ``assume`` or ``cover`` directive - has a bin per outcome.
"""
from __future__                                   import annotations

from typing                                       import TYPE_CHECKING, Iterable, Mapping, Optional as Nullable, Self

from lxml.etree                                   import _Element
from pyTooling.Common                             import getFullyQualifiedName, StringEnum
from pyTooling.Decorators                         import export, readonly

from pyEDAA.Reports.CodeCoverage.UCIS.Bins        import Bin
from pyEDAA.Reports.CodeCoverage.UCIS.Elements    import Base, MetricCoverage, ObjectAttributesMixin, UserAttribute

if TYPE_CHECKING:
	from pyEDAA.Reports.CodeCoverage.UCIS.Instances import InstanceCoverage


[docs] @export class AssertionBinKind(StringEnum): """ Kind of an assertion's bin: the outcome it counts, named as the bin's element. """ Cover = "coverBin" #: The cover directive's sequence matched. Pass = "passBin" #: The assertion passed. Fail = "failBin" #: The assertion failed. Vacuous = "vacuousBin" #: The assertion passed vacuously. Disabled = "disabledBin" #: The assertion was disabled. Attempt = "attemptBin" #: The assertion was attempted. Active = "activeBin" #: The assertion's threads were active. PeakActive = "peakActiveBin" #: The peak number of the assertion's active threads.
[docs] @export class AssertionCoverage(MetricCoverage): """ An ``<assertionCoverage>`` of an instance: its assertions. """ _assertions: list[Assertion] #: The assertions.
[docs] def __init__( self, metricMode: Nullable[str] = None, weight: int = 1, userAttributes: Nullable[Iterable[UserAttribute]] = None, *, parent: Nullable[InstanceCoverage] = None ) -> None: """ Initialize the assertion coverage, and append it to the assertion coverages of its instance. Its assertions are added by creating them with this coverage as their parent. :param metricMode: Optional, the mode in which the coverage was measured. Default: ``None``. :param weight: Optional, weight of the mode in computing the coverage. Default: ``1``. :param userAttributes: Optional, the user-defined attributes. Default: ``None``. :param parent: Optional, the instance the coverage belongs to. Default: ``None``. :raises TypeError: If parameter ``metricMode`` isn't of type :class:`str`. :raises ValueError: If parameter ``weight`` is ``None``. :raises TypeError: If parameter ``weight`` isn't of type :class:`int`. :raises ValueError: If parameter ``weight`` is negative. :raises TypeError: If parameter ``userAttributes`` isn't iterable. :raises TypeError: If parameter ``userAttributes`` contains an element not of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Elements.UserAttribute`. :raises TypeError: If parameter ``parent`` isn't of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Instances.InstanceCoverage`. """ super().__init__(metricMode, weight, userAttributes, parent=parent) self._assertions = [] if parent is not None: parent._assertionCoverages.append(self)
[docs] @classmethod def Parse(cls, element: _Element, *, parent: Nullable[InstanceCoverage] = None) -> Self: """ Parse an assertion coverage and its assertions from its ``<assertionCoverage>`` element. :param element: The ``<assertionCoverage>`` element. :param parent: Optional, the instance the coverage belongs to. Default: ``None``. :returns: The assertion coverage. :raises CodeCoverageError: If a user-defined attribute's value isn't of the type the attribute states. """ assertionCoverage = cls( element.attrib.get("metricMode"), int(element.attrib.get("weight", "1")), cls._ParseUserAttributes(element), parent=parent ) for assertionElement in element.iterfind("{*}assertion"): Assertion.Parse(assertionElement, parent=assertionCoverage) return assertionCoverage
@readonly def Assertions(self) -> list[Assertion]: """ Read-only property to access the assertions (:attr:`_assertions`). :returns: The assertions, in the order the report lists them. """ return self._assertions
[docs] @export class Assertion(Base, ObjectAttributesMixin): """ An ``<assertion>`` of an assertion coverage: its name, its kind and a bin per outcome the report counts. """ _parent: Nullable[AssertionCoverage] #: The assertion coverage the assertion belongs to. _name: str #: Name of the assertion. _assertionKind: str #: Kind of the assertion, e.g. ``assert`` or ``cover``. _bins: dict[AssertionBinKind, Bin] #: The bins, by the outcome they count.
[docs] def __init__( self, name: str, assertionKind: str, bins: Nullable[Mapping[AssertionBinKind, Bin]] = None, alias: Nullable[str] = None, excluded: bool = False, excludedReason: Nullable[str] = None, weight: int = 1, userAttributes: Nullable[Iterable[UserAttribute]] = None, *, parent: Nullable[AssertionCoverage] = None ) -> None: """ Initialize the assertion, become its bins' parent, and append it to the assertions of its assertion coverage. :param name: Name of the assertion, e.g. ``a1``. :param assertionKind: Kind of the assertion, e.g. ``assert`` or ``cover``. :param bins: Optional, the bins, by the outcome they count. Default: ``None``. :param alias: Optional, an alias of the assertion's name. Default: ``None``. :param excluded: Optional, whether the assertion is excluded from the coverage. Default: ``False``. :param excludedReason: Optional, why the assertion is excluded. Default: ``None``. :param weight: Optional, weight of the assertion in computing the coverage. Default: ``1``. :param userAttributes: Optional, the user-defined attributes. Default: ``None``. :param parent: Optional, the assertion coverage the assertion belongs to. Default: ``None``. :raises ValueError: If parameter ``name`` is ``None``. :raises TypeError: If parameter ``name`` isn't of type :class:`str`. :raises ValueError: If parameter ``assertionKind`` is ``None``. :raises TypeError: If parameter ``assertionKind`` isn't of type :class:`str`. :raises TypeError: If parameter ``bins`` isn't a mapping. :raises TypeError: If parameter ``bins`` contains a key not of type :class:`AssertionBinKind`. :raises TypeError: If parameter ``bins`` contains a value not of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Bins.Bin`. :raises TypeError: If parameter ``alias`` isn't of type :class:`str`. :raises ValueError: If parameter ``excluded`` is ``None``. :raises TypeError: If parameter ``excluded`` isn't of type :class:`bool`. :raises TypeError: If parameter ``excludedReason`` isn't of type :class:`str`. :raises ValueError: If parameter ``weight`` is ``None``. :raises TypeError: If parameter ``weight`` isn't of type :class:`int`. :raises ValueError: If parameter ``weight`` is negative. :raises TypeError: If parameter ``userAttributes`` isn't iterable. :raises TypeError: If parameter ``userAttributes`` contains an element not of type :class:`~pyEDAA.Reports.CodeCoverage.UCIS.Elements.UserAttribute`. :raises TypeError: If parameter ``parent`` isn't of type :class:`AssertionCoverage`. """ super().__init__(userAttributes) ObjectAttributesMixin.__init__(self, alias, excluded, excludedReason, weight) for parameterName, value in ( ("name", name), ("assertionKind", assertionKind) ): if value is None: raise ValueError(f"Parameter '{parameterName}' is None.") elif not isinstance(value, str): ex = TypeError(f"Parameter '{parameterName}' is not of type 'str'.") ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") raise ex if parent is not None and not isinstance(parent, AssertionCoverage): ex = TypeError("Parameter 'parent' is not of type 'AssertionCoverage'.") ex.add_note(f"Got type '{getFullyQualifiedName(parent)}'.") raise ex self._parent = parent self._name = name self._assertionKind = assertionKind self._bins = {} if bins is not None: if not isinstance(bins, Mapping): ex = TypeError("Parameter 'bins' is not a mapping.") ex.add_note(f"Got type '{getFullyQualifiedName(bins)}'.") raise ex for binKind, coverBin in bins.items(): if not isinstance(binKind, AssertionBinKind): ex = TypeError("Parameter 'bins' contains a key not of type 'AssertionBinKind'.") ex.add_note(f"Got type '{getFullyQualifiedName(binKind)}'.") raise ex elif not isinstance(coverBin, Bin): ex = TypeError("Parameter 'bins' contains a value not of type 'Bin'.") ex.add_note(f"Got type '{getFullyQualifiedName(coverBin)}' for key '{binKind}'.") raise ex coverBin._parent = self self._bins[binKind] = coverBin if parent is not None: parent._assertions.append(self)
[docs] @classmethod def Parse(cls, element: _Element, *, parent: Nullable[AssertionCoverage] = None) -> Self: """ Parse an assertion and its bins from its ``<assertion>`` element. :param element: The ``<assertion>`` element. :param parent: Optional, the assertion coverage the assertion belongs to. Default: ``None``. :returns: The assertion. :raises CodeCoverageError: If a user-defined attribute's value isn't of the type the attribute states. """ bins = { binKind: Bin.Parse(binElement) for binKind in AssertionBinKind if (binElement := element.find(f"{{*}}{binKind}")) is not None } return cls( element.attrib["name"], element.attrib["assertionKind"], bins, element.attrib.get("alias"), cls._ParseBoolean(element.attrib.get("excluded", "false")), element.attrib.get("excludedReason"), int(element.attrib.get("weight", "1")), cls._ParseUserAttributes(element), parent=parent )
@readonly def Parent(self) -> Nullable[AssertionCoverage]: """ Read-only property to access the assertion coverage the assertion belongs to (:attr:`_parent`). :returns: The assertion coverage; ``None``, if the assertion belongs to none. """ return self._parent @readonly def Name(self) -> str: """ Read-only property to access the name of the assertion (:attr:`_name`). :returns: The name, as declared. """ return self._name @readonly def AssertionKind(self) -> str: """ Read-only property to access the kind of the assertion (:attr:`_assertionKind`). :returns: The kind, as stated, e.g. ``assert`` or ``cover``. """ return self._assertionKind @readonly def Bins(self) -> dict[AssertionBinKind, Bin]: """ Read-only property to access the bins (:attr:`_bins`). :returns: The bins, by the outcome they count, in the order of :class:`AssertionBinKind`. """ return self._bins