Skip to content

Commit c85e3d3

Browse files
committed
backend/sdoc_source_code: general source code reader: support scope=file
1 parent 1d5f1de commit c85e3d3

File tree

9 files changed

+93
-4
lines changed

9 files changed

+93
-4
lines changed

docs/sphinx/source/strictdoc_01_user_guide.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1803,7 +1803,7 @@ The marker must be added to the top comment of a file. Currently supported only
18031803
"""
18041804
This class implements ...
18051805
1806-
@relation(REQ-1, scope=file)
1806+
@relation(REQ-1, scope=class)
18071807
"""
18081808
18091809
**3\) Linking a function to a requirement (Python and C only)**

docs/strictdoc_01_user_guide.sdoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2145,7 +2145,7 @@ The marker must be added to the top comment of a file. Currently supported only
21452145
"""
21462146
This class implements ...
21472147

2148-
@relation(REQ-1, scope=file)
2148+
@relation(REQ-1, scope=class)
21492149
"""
21502150

21512151
**3\) Linking a function to a requirement (Python and C only)**

strictdoc/backend/sdoc_source_code/grammar.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// The EmptyLine is needed in addition to the SingleLineString because
88
// otherwise textX's get_location() ignores the whitespaces.
99
// TODO: Maybe there is a trick to disable that and only use SingleLineString.
10-
EmptyLine | RangeMarker | LineMarker | SingleLineString
10+
EmptyLine | RangeMarker | LineMarker | FunctionRangeMarker | SingleLineString
1111
;
1212
1313
EmptyLine[noskipws]:
@@ -31,6 +31,11 @@
3131
)
3232
;
3333
34+
FunctionRangeMarker[noskipws]:
35+
/^.*?@relation/
36+
"(" (reqs_objs += Req[', ']) ', scope=file)' '\n'?
37+
;
38+
3439
LineMarker[noskipws]:
3540
// It is a hard-won result: it is important that the "@sdoc" is within the
3641
// regex. Putting it next to the regex as "@sdoc" does not work.

strictdoc/backend/sdoc_source_code/reader.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
from strictdoc.backend.sdoc.error_handling import StrictDocSemanticError
1010
from strictdoc.backend.sdoc_source_code.grammar import SOURCE_FILE_GRAMMAR
11+
from strictdoc.backend.sdoc_source_code.models.function_range_marker import (
12+
FunctionRangeMarker,
13+
)
1114
from strictdoc.backend.sdoc_source_code.models.range_marker import (
1215
LineMarker,
1316
RangeMarker,
@@ -206,10 +209,37 @@ def line_marker_processor(line_marker: LineMarker, parse_context: ParseContext):
206209
markers.append(line_marker)
207210

208211

212+
def function_range_marker_processor(
213+
function_range_marker: FunctionRangeMarker, parse_context: ParseContext
214+
):
215+
location = get_location(function_range_marker)
216+
line = location["line"]
217+
column = location["col"]
218+
219+
if (
220+
len(parse_context.marker_stack) > 0
221+
and parse_context.marker_stack[-1].ng_is_nodoc
222+
):
223+
# This marker is within a "nosdoc" block, so we ignore it.
224+
return
225+
226+
parse_context.markers.append(function_range_marker)
227+
function_range_marker.ng_source_line_begin = 1
228+
function_range_marker.ng_range_line_begin = 1
229+
function_range_marker.ng_range_line_end = parse_context.lines_total
230+
function_range_marker.ng_marker_line = line
231+
function_range_marker.ng_marker_column = column
232+
233+
for req in function_range_marker.reqs:
234+
markers = parse_context.map_reqs_to_markers.setdefault(req, [])
235+
markers.append(function_range_marker)
236+
237+
209238
class SourceFileTraceabilityReader:
210239
SOURCE_FILE_MODELS = [
211-
Req,
240+
FunctionRangeMarker,
212241
LineMarker,
242+
Req,
213243
SourceFileTraceabilityInfo,
214244
RangeMarker,
215245
]
@@ -241,8 +271,12 @@ def read(self, input_string, file_path=None) -> SourceFileTraceabilityInfo:
241271
parse_line_marker_processor = partial(
242272
line_marker_processor, parse_context=parse_context
243273
)
274+
parse_function_range_marker_processor = partial(
275+
function_range_marker_processor, parse_context=parse_context
276+
)
244277

245278
obj_processors = {
279+
"FunctionRangeMarker": parse_function_range_marker_processor,
246280
"LineMarker": parse_line_marker_processor,
247281
"RangeMarker": parse_range_marker_processor,
248282
"Req": parse_req_processor,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""
2+
@relation(REQ-001, scope=file)
3+
"""
4+
5+
def hello_world():
6+
# @sdoc[REQ-001]
7+
print("ignored hello world") # noqa: T201
8+
print("ignored hello world") # noqa: T201
9+
# @sdoc[/REQ-001]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[DOCUMENT]
2+
TITLE: Hello world doc
3+
4+
[REQUIREMENT]
5+
UID: REQ-001
6+
TITLE: Requirement Title
7+
STATEMENT: Requirement Statement
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[project]
2+
3+
features = [
4+
"REQUIREMENT_TO_SOURCE_TRACEABILITY",
5+
]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
RUN: %strictdoc export %S --output-dir Output | filecheck %s --dump-input=fail
2+
CHECK: Published: Hello world doc
3+
4+
RUN: %check_exists --file "%S/Output/html/_source_files/file.py.html"
5+
6+
RUN: %cat %S/Output/html/_source_files/file.py.html | filecheck %s --dump-input=fail --check-prefix CHECK-SOURCE-FILE
7+
CHECK-SOURCE-FILE: [ 1-9 ]
8+
CHECK-SOURCE-FILE: [ 6-9 ]

tests/unit/strictdoc/backend/sdoc_source_code/test_dsl_source_file_syntax.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,27 @@ def test_050_line_marker():
362362
assert markers[2].ng_range_line_end == 5
363363

364364

365+
def test_060_file_level_marker():
366+
source_input = """\
367+
\"\"\"
368+
@relation(REQ-001, scope=file)
369+
\"\"\"
370+
371+
def hello_world():
372+
pass
373+
""".lstrip()
374+
375+
reader = SourceFileTraceabilityReader()
376+
377+
document = reader.read(source_input)
378+
assert len(document.markers) == 1
379+
markers = document.markers
380+
assert markers[0].reqs == ["REQ-001"]
381+
assert markers[0].ng_source_line_begin == 1
382+
assert markers[0].ng_range_line_begin == 1
383+
assert markers[0].ng_range_line_end == 6
384+
385+
365386
def test_validation_01_one_range_marker_begin_req_not_equal_to_end_req():
366387
source_input = """
367388
# @sdoc[REQ-001]

0 commit comments

Comments
 (0)