Path:
tests/unit/strictdoc/core/transforms/test_update_requirement.py
Lines:
520
Non-empty lines:
459
Non-empty lines covered with requirements:
459 / 459 (100.0%)
Functions:
7
Functions covered by requirements:
7 / 7 (100.0%)
1
"""2
@relation(SDOC-SRS-55, scope=file)3
"""4
5
from strictdoc.backend.sdoc.constants import SDocMarkup
6
from strictdoc.backend.sdoc.document_reference import DocumentReference
7
from strictdoc.backend.sdoc.models.grammar_element import (
8
GrammarElementRelationChild,
9
GrammarElementRelationParent,
10
)11
from strictdoc.core.document_tree import DocumentTree
12
from strictdoc.core.project_config import ProjectConfig
13
from strictdoc.core.traceability_index import TraceabilityIndex
14
from strictdoc.core.traceability_index_builder import TraceabilityIndexBuilder
15
from strictdoc.core.transforms.update_requirement import (
16
CreateOrUpdateNodeCommand,
17
UpdateNodeInfo,
18
)19
from strictdoc.export.html.form_objects.requirement_form_object import (
20
RequirementFormObject,
21
RequirementReferenceFormField,
22
)23
from strictdoc.helpers.mid import MID
24
from tests.unit.helpers.document_builder import DocumentBuilder
25
26
MARKDOWN_TABLE = (
27
"| | Action | Verify |\n"
28
"|---|--------|--------|\n"
29
"| 1 | Do the thing | |\n"
30
"| 2 | Do another thing | |\n"
31
)32
33
34
def test_01_single_document_add_first_parent_relation_with_no_role():
35
document_builder = DocumentBuilder()
36
requirement1 = document_builder.add_requirement("REQ-001")
37
requirement2 = document_builder.add_requirement("REQ-002")
38
assert len(requirement2.relations) == 0
39
40
document_1 = document_builder.build()
41
42
file_tree = []
43
document_list = [document_1]
44
map_docs_by_paths = {}
45
document_tree = DocumentTree(
46
file_tree=file_tree,
47
document_list=document_list,
48
map_docs_by_paths=map_docs_by_paths,
49
map_docs_by_rel_paths={},
50
map_grammars_by_filenames={},
51
)52
traceability_index: TraceabilityIndex = (
53
TraceabilityIndexBuilder.create_from_document_tree(
54
document_tree, project_config=document_builder.project_config
55
)56
)57
traceability_index.document_tree = document_tree
58
assert traceability_index.get_parent_requirements(requirement1) == []
59
60
requirement2_parents = list(
61
traceability_index.get_parent_relations_with_roles(requirement2)
62
)63
assert requirement2_parents == []
64
65
form_object: RequirementFormObject = (
66
RequirementFormObject.create_from_requirement(
67
requirement=requirement2,
68
revision=0,
69
context_document_mid=document_1.reserved_mid,
70
)71
)72
form_object.reference_fields.append(
73
RequirementReferenceFormField(
74
field_mid=MID.create(),
75
field_type=RequirementReferenceFormField.FieldType.PARENT,
76
field_value="REQ-001",
77
field_role=None,
78
)79
)80
update_command = CreateOrUpdateNodeCommand(
81
form_object=form_object,
82
node_info=UpdateNodeInfo(requirement2),
83
traceability_index=traceability_index,
84
project_config=ProjectConfig.default_config(),
85
)86
update_command.perform()
87
88
assert len(requirement2.relations) == 1
89
requirement2_parents = list(
90
traceability_index.get_parent_relations_with_roles(requirement2)
91
)92
assert requirement2_parents == [
93
(requirement1, None),
94
]95
96
97
def test_02_single_document_add_second_parent_relation_with_role():
98
document_builder = DocumentBuilder()
99
requirement1 = document_builder.add_requirement("REQ-001")
100
requirement2 = document_builder.add_requirement("REQ-002")
101
document_builder.add_requirement_relation(
102
relation_type="Parent",
103
source_requirement_id="REQ-002",
104
target_requirement_id="REQ-001",
105
role="Refines",
106
)107
assert len(requirement2.relations) == 1
108
109
document_1 = document_builder.build()
110
requirement_grammar_element = document_1.grammar.elements_by_type[
111
"REQUIREMENT"112
]113
requirement_grammar_element.relations.append(
114
GrammarElementRelationParent(
115
requirement_grammar_element, "Parent", "Refines"
116
)117
)118
file_tree = []
119
document_list = [document_1]
120
map_docs_by_paths = {}
121
document_tree = DocumentTree(
122
file_tree=file_tree,
123
document_list=document_list,
124
map_docs_by_paths=map_docs_by_paths,
125
map_docs_by_rel_paths={},
126
map_grammars_by_filenames={},
127
)128
traceability_index: TraceabilityIndex = (
129
TraceabilityIndexBuilder.create_from_document_tree(
130
document_tree, project_config=document_builder.project_config
131
)132
)133
traceability_index.document_tree = document_tree
134
assert traceability_index.get_parent_requirements(requirement1) == []
135
136
requirement2_parents = list(
137
traceability_index.get_parent_relations_with_roles(requirement2)
138
)139
assert requirement2_parents == [(requirement1, "Refines")]
140
141
form_object: RequirementFormObject = (
142
RequirementFormObject.create_from_requirement(
143
requirement=requirement2,
144
revision=0,
145
context_document_mid=document_1.reserved_mid,
146
)147
)148
update_command = CreateOrUpdateNodeCommand(
149
form_object=form_object,
150
node_info=UpdateNodeInfo(requirement2),
151
traceability_index=traceability_index,
152
project_config=ProjectConfig.default_config(),
153
)154
update_command.perform()
155
assert len(requirement2.relations) == 1
156
157
form_object.reference_fields.append(
158
RequirementReferenceFormField(
159
field_mid=MID.create(),
160
field_type=RequirementReferenceFormField.FieldType.PARENT,
161
field_value="REQ-001",
162
field_role="Implements",
163
)164
)165
update_command.perform()
166
167
assert len(requirement2.relations) == 2
168
requirement2_parents = list(
169
traceability_index.get_parent_relations_with_roles(requirement2)
170
)171
assert requirement2_parents == [
172
(requirement1, "Refines"),
173
(requirement1, "Implements"),
174
]175
176
177
def test_20_single_document_add_second_child_relation_with_role():
178
document_builder = DocumentBuilder()
179
requirement1 = document_builder.add_requirement("REQ-001")
180
requirement2 = document_builder.add_requirement("REQ-002")
181
document_builder.add_requirement_relation(
182
relation_type="Child",
183
source_requirement_id="REQ-002",
184
target_requirement_id="REQ-001",
185
role="IsRefinedBy",
186
)187
188
assert len(requirement2.relations) == 1
189
190
document_1 = document_builder.build()
191
requirement_grammar_element = document_1.grammar.elements_by_type[
192
"REQUIREMENT"193
]194
requirement_grammar_element.relations.append(
195
GrammarElementRelationChild(
196
requirement_grammar_element, "Child", "IsRefinedBy"
197
)198
)199
file_tree = []
200
document_list = [document_1]
201
map_docs_by_paths = {}
202
document_tree = DocumentTree(
203
file_tree=file_tree,
204
document_list=document_list,
205
map_docs_by_paths=map_docs_by_paths,
206
map_docs_by_rel_paths={},
207
map_grammars_by_filenames={},
208
)209
traceability_index: TraceabilityIndex = (
210
TraceabilityIndexBuilder.create_from_document_tree(
211
document_tree, project_config=document_builder.project_config
212
)213
)214
traceability_index.document_tree = document_tree
215
requirement1_parents = list(
216
traceability_index.get_parent_relations_with_roles(requirement1)
217
)218
assert requirement1_parents == [(requirement2, "IsRefinedBy")]
219
220
requirement2_children = list(
221
traceability_index.get_child_relations_with_roles(requirement2)
222
)223
assert requirement2_children == [(requirement1, "IsRefinedBy")]
224
225
form_object: RequirementFormObject = (
226
RequirementFormObject.create_from_requirement(
227
requirement=requirement2,
228
revision=0,
229
context_document_mid=document_1.reserved_mid,
230
)231
)232
form_object.reference_fields.append(
233
RequirementReferenceFormField(
234
field_mid=MID.create(),
235
field_type=RequirementReferenceFormField.FieldType.CHILD,
236
field_value="REQ-001",
237
field_role="IsImplementedBy",
238
)239
)240
update_command = CreateOrUpdateNodeCommand(
241
form_object=form_object,
242
node_info=UpdateNodeInfo(requirement2),
243
traceability_index=traceability_index,
244
project_config=ProjectConfig.default_config(),
245
)246
update_command.perform()
247
248
requirement1_parents = list(
249
traceability_index.get_parent_relations_with_roles(requirement1)
250
)251
assert requirement1_parents == [
252
(requirement2, "IsRefinedBy"),
253
(requirement2, "IsImplementedBy"),
254
]255
256
requirement2_children = list(
257
traceability_index.get_child_relations_with_roles(requirement2)
258
)259
assert requirement2_children == [
260
(requirement1, "IsRefinedBy"),
261
(requirement1, "IsImplementedBy"),
262
]263
264
265
def test_25_single_document_remove_child_relation():
266
document_builder = DocumentBuilder()
267
requirement1 = document_builder.add_requirement("REQ-001")
268
requirement2 = document_builder.add_requirement("REQ-002")
269
document_builder.add_requirement_relation(
270
relation_type="Child",
271
source_requirement_id="REQ-002",
272
target_requirement_id="REQ-001",
273
role="IsRefinedBy",
274
)275
276
assert len(requirement2.relations) == 1
277
278
document_1 = document_builder.build()
279
requirement_grammar_element = document_1.grammar.elements_by_type[
280
"REQUIREMENT"281
]282
requirement_grammar_element.relations.append(
283
GrammarElementRelationChild(
284
requirement_grammar_element, "Child", "IsRefinedBy"
285
)286
)287
288
file_tree = []
289
document_list = [document_1]
290
map_docs_by_paths = {}
291
document_tree = DocumentTree(
292
file_tree=file_tree,
293
document_list=document_list,
294
map_docs_by_paths=map_docs_by_paths,
295
map_docs_by_rel_paths={},
296
map_grammars_by_filenames={},
297
)298
traceability_index: TraceabilityIndex = (
299
TraceabilityIndexBuilder.create_from_document_tree(
300
document_tree, project_config=document_builder.project_config
301
)302
)303
traceability_index.document_tree = document_tree
304
requirement1_parents = list(
305
traceability_index.get_parent_relations_with_roles(requirement1)
306
)307
assert requirement1_parents == [(requirement2, "IsRefinedBy")]
308
309
requirement2_children = list(
310
traceability_index.get_child_relations_with_roles(requirement2)
311
)312
assert requirement2_children == [(requirement1, "IsRefinedBy")]
313
314
form_object: RequirementFormObject = (
315
RequirementFormObject.create_from_requirement(
316
requirement=requirement2,
317
revision=0,
318
context_document_mid=document_1.reserved_mid,
319
)320
)321
322
# Form object has no relations.323
form_object.reference_fields.clear()
324
325
update_command = CreateOrUpdateNodeCommand(
326
form_object=form_object,
327
node_info=UpdateNodeInfo(requirement2),
328
traceability_index=traceability_index,
329
project_config=ProjectConfig.default_config(),
330
)331
update_command.perform()
332
333
requirement1_parents = list(
334
traceability_index.get_parent_relations_with_roles(requirement1)
335
)336
assert requirement1_parents == []
337
338
requirement2_children = list(
339
traceability_index.get_child_relations_with_roles(requirement2)
340
)341
assert requirement2_children == []
342
343
344
def test_26_two_documents_remove_child_relation():
345
# Document 1346
document_builder = DocumentBuilder("DOC-1")
347
requirement1 = document_builder.add_requirement("REQ-001")
348
document_1 = document_builder.build()
349
350
# Document 2351
document_builder = DocumentBuilder("DOC-2")
352
requirement2 = document_builder.add_requirement("REQ-002")
353
document_builder.add_requirement_relation(
354
relation_type="Child",
355
source_requirement_id="REQ-002",
356
target_requirement_id="REQ-001",
357
role="IsRefinedBy",
358
)359
assert len(requirement2.relations) == 1
360
document_2 = document_builder.build()
361
362
document_2_requirement_grammar_element = (
363
document_2.grammar.elements_by_type["REQUIREMENT"]
364
)365
document_2_requirement_grammar_element.relations.append(
366
GrammarElementRelationChild(
367
document_2_requirement_grammar_element, "Child", "IsRefinedBy"
368
)369
)370
assert requirement1.get_document() != requirement2.get_document()
371
372
file_tree = []
373
document_list = [document_1, document_2]
374
map_docs_by_paths = {}
375
document_tree = DocumentTree(
376
file_tree=file_tree,
377
document_list=document_list,
378
map_docs_by_paths=map_docs_by_paths,
379
map_docs_by_rel_paths={},
380
map_grammars_by_filenames={},
381
)382
traceability_index: TraceabilityIndex = (
383
TraceabilityIndexBuilder.create_from_document_tree(
384
document_tree,
385
project_config=ProjectConfig.default_config(),
386
)387
)388
traceability_index.document_tree = document_tree
389
390
requirement2_children = list(
391
traceability_index.get_child_relations_with_roles(requirement2)
392
)393
assert requirement2_children == [(requirement1, "IsRefinedBy")]
394
395
form_object: RequirementFormObject = (
396
RequirementFormObject.create_from_requirement(
397
requirement=requirement2,
398
revision=0,
399
context_document_mid=document_2.reserved_mid,
400
)401
)402
403
# Form object has no relations.404
form_object.reference_fields.clear()
405
406
update_command = CreateOrUpdateNodeCommand(
407
form_object=form_object,
408
node_info=UpdateNodeInfo(requirement2),
409
traceability_index=traceability_index,
410
project_config=ProjectConfig.default_config(),
411
)412
update_command.perform()
413
414
requirement1_parents = list(
415
traceability_index.get_parent_relations_with_roles(requirement1)
416
)417
assert requirement1_parents == []
418
419
requirement2_children = list(
420
traceability_index.get_child_relations_with_roles(requirement2)
421
)422
assert requirement2_children == []
423
424
425
def test_30_markdown_document_updates_field_with_markdown_table():
426
document_builder = DocumentBuilder()
427
requirement = document_builder.add_requirement("REQ-001")
428
429
document_1 = document_builder.build()
430
document_1.config.markup = SDocMarkup.MARKDOWN
431
432
document_tree = DocumentTree(
433
file_tree=[],
434
document_list=[document_1],
435
map_docs_by_paths={},
436
map_docs_by_rel_paths={},
437
map_grammars_by_filenames={},
438
)439
traceability_index: TraceabilityIndex = (
440
TraceabilityIndexBuilder.create_from_document_tree(
441
document_tree, project_config=document_builder.project_config
442
)443
)444
traceability_index.document_tree = document_tree
445
446
form_object: RequirementFormObject = (
447
RequirementFormObject.create_from_requirement(
448
requirement=requirement,
449
revision=0,
450
context_document_mid=document_1.reserved_mid,
451
)452
)453
for field in form_object.fields["STATEMENT"]:
454
field.field_value = MARKDOWN_TABLE
455
456
update_command = CreateOrUpdateNodeCommand(
457
form_object=form_object,
458
node_info=UpdateNodeInfo(requirement),
459
traceability_index=traceability_index,
460
project_config=ProjectConfig.default_config(),
461
)462
result = update_command.perform()
463
464
assert result is not None
465
assert not form_object.any_errors()
466
assert requirement.reserved_statement == MARKDOWN_TABLE
467
468
469
def test_31_included_markdown_document_uses_own_markup_when_updated_from_parent():
470
parent_document_builder = DocumentBuilder(uid="PARENT")
471
parent_document = parent_document_builder.build()
472
parent_document.config.markup = SDocMarkup.RST
473
474
included_document_builder = DocumentBuilder(uid="INCLUDED")
475
requirement = included_document_builder.add_requirement("REQ-001")
476
included_document = included_document_builder.build()
477
included_document.config.markup = SDocMarkup.MARKDOWN
478
479
included_document.ng_including_document_reference = DocumentReference()
480
included_document.ng_including_document_reference.set_document(
481
parent_document482
)483
parent_document.included_documents.append(included_document)
484
485
document_tree = DocumentTree(
486
file_tree=[],
487
document_list=[parent_document, included_document],
488
map_docs_by_paths={},
489
map_docs_by_rel_paths={},
490
map_grammars_by_filenames={},
491
)492
traceability_index: TraceabilityIndex = (
493
TraceabilityIndexBuilder.create_from_document_tree(
494
document_tree,
495
project_config=included_document_builder.project_config,
496
)497
)498
traceability_index.document_tree = document_tree
499
500
form_object: RequirementFormObject = (
501
RequirementFormObject.create_from_requirement(
502
requirement=requirement,
503
revision=0,
504
context_document_mid=parent_document.reserved_mid,
505
)506
)507
for field in form_object.fields["STATEMENT"]:
508
field.field_value = MARKDOWN_TABLE
509
510
update_command = CreateOrUpdateNodeCommand(
511
form_object=form_object,
512
node_info=UpdateNodeInfo(requirement),
513
traceability_index=traceability_index,
514
project_config=ProjectConfig.default_config(),
515
)516
result = update_command.perform()
517
518
assert result is not None
519
assert not form_object.any_errors()
520
assert requirement.reserved_statement == MARKDOWN_TABLE