Path:
strictdoc/backend/sdoc_source_code/models/source_file_info.py
Lines:
101
Non-empty lines:
83
Non-empty lines covered with requirements:
83 / 83 (100.0%)
Functions:
8
Functions covered by requirements:
8 / 8 (100.0%)
1
from typing import Any, Dict, List, Optional, Union
2
3
from typing_extensions import TypeAlias
4
5
from strictdoc.backend.sdoc_source_code.models.language import LanguageItem
6
from strictdoc.backend.sdoc_source_code.models.language_item_marker import (
7
LanguageItemMarker,
8
)9
from strictdoc.backend.sdoc_source_code.models.line_marker import LineMarker
10
from strictdoc.backend.sdoc_source_code.models.range_marker import (
11
ForwardRangeMarker,
12
RangeMarker,
13
)14
from strictdoc.backend.sdoc_source_code.models.source_node import SourceNode
15
from strictdoc.core.file_system.source_tree import SourceFile
16
from strictdoc.helpers.auto_described import auto_described
17
from strictdoc.helpers.file_stats import SourceFileStats
18
19
RelationMarkerType: TypeAlias = Union[
20
LanguageItemMarker, LineMarker, RangeMarker, ForwardRangeMarker
21
]22
23
24
@auto_described25
class SourceFileTraceabilityInfo:
26
"""
27
Class that keeps all traceability info related to a single source file.28
29
At the init time, only the backward RangeMarkers are available from30
a source file. At runtime, the ForwardRangeMarkers are mixed in31
from the Requirement/FileReference links. This is why the .markers32
is a union.33
34
Note that g_parts is only used by the textX grammar to allow the35
definition of the child grammar elements. All other instance variables36
of this class are not using or based on g_parts. Instead, they are37
populated during the textX processing step, e.g., via38
general_language_marker_processors.py.39
"""40
41
def __init__(self, g_parts: List[Any]): # noqa: ARG002
42
self.source_file: Optional[SourceFile] = None
43
self.source_nodes: List[SourceNode] = []
44
self.functions: List[LanguageItem] = []
45
46
#47
# { # noqa: ERA00148
# "REQ-001": [RangeMarker(...), ...], # noqa: ERA00149
# "REQ-002": [RangeMarker(...), ...], # noqa: ERA00150
# } # noqa: ERA00151
self.ng_map_reqs_to_markers: Dict[str, List[RelationMarkerType]] = {}
52
53
self.ng_map_names_to_markers: Dict[str, List[RelationMarkerType]] = {}
54
self.ng_map_names_to_definition_functions: Dict[str, LanguageItem] = {}
55
56
#57
# Merged ranges contain ranges that are fully covered by one or more58
# forward or backward relations. If a range is part of a larger range,59
# it gets merged into the larger range. The merged ranges are tracked so60
# that for each source code function it can be answered whether the61
# function is covered by any requirement or not.62
#63
self.merged_ranges: List[List[int]] = []
64
self.file_stats: SourceFileStats = SourceFileStats()
65
self.ng_lines_covered = 0
66
self.lines_info: Dict[int, bool] = {}
67
self._coverage: float = 0
68
self.covered_functions: int = 0
69
70
self.markers: List[RelationMarkerType] = []
71
72
def is_document(self) -> bool:
73
return False
74
75
# FIXME: is_requirement() will go away.76
def is_requirement(self) -> bool:
77
return False
78
79
# FIXME: is_section() will go away.80
def is_section(self) -> bool:
81
return False
82
83
# FIXME: is_section() will go away.84
def is_source_file(self) -> bool:
85
return True
86
87
def get_coverage(self) -> float:
88
return self._coverage
89
90
def set_coverage_stats(
91
self,
92
merged_ranges: List[List[int]],
93
lines_covered: int,
94
) -> None:
95
self.merged_ranges = merged_ranges
96
self.ng_lines_covered = lines_covered
97
self._coverage = (
98
round(lines_covered / self.file_stats.lines_non_empty * 100, 1)
99
if self.file_stats.lines_non_empty != 0
100
else 0
101
)