Path:
tests/unit/strictdoc/backend/sdoc/test_dsl_passthrough.py
Lines:
1308
Non-empty lines:
949
Non-empty lines covered with requirements:
949 / 949 (100.0%)
Functions:
46
Functions covered by requirements:
46 / 46 (100.0%)
- "2.2. Identical SDoc content by import/export roundtrip" (REQUIREMENT)
- "2.2. Identical SDoc content by import/export roundtrip" (REQUIREMENT)
1
"""2
@relation(SDOC-SRS-136, scope=file)3
"""4
5
import pytest
6
7
from strictdoc.backend.sdoc.models.document import SDocDocument
8
from strictdoc.backend.sdoc.models.grammar_element import ReferenceType
9
from strictdoc.backend.sdoc.models.inline_link import InlineLink
10
from strictdoc.backend.sdoc.models.node import (
11
SDocNode,
12
)13
from strictdoc.backend.sdoc.models.reference import (
14
FileReference,
15
)16
from strictdoc.backend.sdoc.reader import SDReader
17
from strictdoc.backend.sdoc.writer import SDWriter
18
from strictdoc.helpers.exception import StrictDocException
19
20
21
def test_001_minimal_doc(default_project_config):
22
input_sdoc = """\
23
[DOCUMENT]24
TITLE: Test Doc25
26
[REQUIREMENT]27
STATEMENT: ...28
29
[REQUIREMENT]30
STATEMENT: ...31
32
[REQUIREMENT]33
STATEMENT: ...34
"""35
36
reader = SDReader()
37
38
document = reader.read(input_sdoc)
39
assert isinstance(document, SDocDocument)
40
41
writer = SDWriter(default_project_config)
42
output = writer.write(document)
43
44
assert input_sdoc == output
45
46
47
def test_002_minimal_req(default_project_config):
48
input_sdoc = """
49
[DOCUMENT]50
TITLE: Test Doc51
52
[REQUIREMENT]53
TITLE: Hello54
""".lstrip()
55
56
reader = SDReader()
57
58
document = reader.read(input_sdoc)
59
assert isinstance(document, SDocDocument)
60
61
writer = SDWriter(default_project_config)
62
output = writer.write(document)
63
64
assert input_sdoc == output
65
66
67
def test_005_requirement_UID_supports_special_characters(
68
default_project_config,
69
):70
input_sdoc = """
71
[DOCUMENT]72
TITLE: Test Doc73
74
[REQUIREMENT]75
UID: FOO-176
TITLE: Hello77
78
[REQUIREMENT]79
UID: FOO.180
TITLE: Hello81
82
[REQUIREMENT]83
UID: FOO/184
TITLE: Hello85
86
[REQUIREMENT]87
UID: FOO_188
TITLE: Hello89
90
[REQUIREMENT]91
UID: FOO 192
TITLE: Hello93
94
[REQUIREMENT]95
UID: FOO::196
TITLE: Hello97
""".lstrip()
98
99
reader = SDReader()
100
101
document = reader.read(input_sdoc)
102
assert isinstance(document, SDocDocument)
103
104
writer = SDWriter(default_project_config)
105
output = writer.write(document)
106
107
assert input_sdoc == output
108
109
110
def test_003_comments_01_several_comments(default_project_config):
111
input_sdoc = """
112
[DOCUMENT]113
TITLE: Test Doc114
115
[REQUIREMENT]116
TITLE: Hello117
COMMENT: Comment #1118
COMMENT: Comment #2119
COMMENT: Comment #3120
""".lstrip()
121
122
reader = SDReader()
123
124
document = reader.read(input_sdoc)
125
assert isinstance(document, SDocDocument)
126
127
writer = SDWriter(default_project_config)
128
output = writer.write(document)
129
130
assert input_sdoc == output
131
132
133
def test_004_several_tags(default_project_config):
134
input_sdoc = """
135
[DOCUMENT]136
TITLE: Test Doc137
138
[REQUIREMENT]139
TAGS: A, B, C, D140
TITLE: Hello141
""".lstrip()
142
143
reader = SDReader()
144
145
document = reader.read(input_sdoc)
146
assert isinstance(document, SDocDocument)
147
148
writer = SDWriter(default_project_config)
149
output = writer.write(document)
150
151
assert input_sdoc == output
152
153
154
def test_010_multiple_sections(default_project_config):
155
input_sdoc = """\
156
[DOCUMENT]157
TITLE: Test Doc158
159
[[SECTION]]160
TITLE: Test Section161
162
[REQUIREMENT]163
STATEMENT: >>>164
This is a statement 1165
This is a statement 2166
This is a statement 3167
<<<168
169
[[/SECTION]]170
171
[[SECTION]]172
TITLE: Test Section173
174
[REQUIREMENT]175
STATEMENT: >>>176
This is a statement 1177
This is a statement 2178
This is a statement 3179
<<<180
181
[[/SECTION]]182
"""183
184
reader = SDReader()
185
186
document = reader.read(input_sdoc)
187
assert isinstance(document, SDocDocument)
188
189
writer = SDWriter(default_project_config)
190
output = writer.write(document)
191
assert input_sdoc == output
192
193
194
def test_020_requirement_mid(default_project_config):
195
input_sdoc = """
196
[DOCUMENT]197
TITLE: Test Doc198
199
[GRAMMAR]200
ELEMENTS:201
- TAG: TEXT202
FIELDS:203
- TITLE: UID204
TYPE: String205
REQUIRED: False206
- TITLE: STATEMENT207
TYPE: String208
REQUIRED: True209
- TAG: REQUIREMENT210
FIELDS:211
- TITLE: MID212
TYPE: String213
REQUIRED: False214
- TITLE: STATEMENT215
TYPE: String216
REQUIRED: False217
218
[REQUIREMENT]219
MID: abcdef123456220
STATEMENT: >>>221
This is a statement 1222
This is a statement 2223
This is a statement 3224
<<<225
""".lstrip()
226
227
reader = SDReader()
228
229
document = reader.read(input_sdoc)
230
assert isinstance(document, SDocDocument)
231
232
writer = SDWriter(default_project_config)
233
output = writer.write(document)
234
assert input_sdoc == output
235
236
237
def test_021_section_and_document_mid(default_project_config):
238
input_sdoc = """
239
[DOCUMENT]240
MID: xyz09876241
TITLE: Test Doc242
OPTIONS:243
ENABLE_MID: True244
245
[[SECTION]]246
MID: abcdef123456247
TITLE: Test Section248
249
[[/SECTION]]250
""".lstrip()
251
252
reader = SDReader()
253
254
document = reader.read(input_sdoc)
255
assert isinstance(document, SDocDocument)
256
257
writer = SDWriter(default_project_config)
258
output = writer.write(document)
259
260
assert input_sdoc == output
261
262
263
def test_022_requirement_uid_and_link(default_project_config):
264
input_sdoc = """
265
[DOCUMENT]266
TITLE: Test Doc267
268
[REQUIREMENT]269
UID: With spaces and (_-.) and non latin 特点270
STATEMENT: >>>271
This is a statement.272
273
[TEXT]274
STATEMENT: >>>275
[LINK: With spaces and (_-.) and non latin 特点]276
<<<277
""".lstrip()
278
279
reader = SDReader()
280
281
document = reader.read(input_sdoc)
282
assert isinstance(document, SDocDocument)
283
284
writer = SDWriter(default_project_config)
285
output = writer.write(document)
286
287
assert input_sdoc == output
288
289
290
def test_030_multiline_statement(default_project_config):
291
input_sdoc = """
292
[DOCUMENT]293
TITLE: Test Doc294
295
[[SECTION]]296
TITLE: Test Section297
298
[REQUIREMENT]299
STATEMENT: >>>300
This is a statement 1301
This is a statement 2302
This is a statement 3303
<<<304
305
[[/SECTION]]306
""".lstrip()
307
308
reader = SDReader()
309
310
document = reader.read(input_sdoc)
311
assert isinstance(document, SDocDocument)
312
313
assert isinstance(
314
document.section_contents[0].section_contents[0], SDocNode
315
)316
requirement_1 = document.section_contents[0].section_contents[0]
317
assert (
318
requirement_1.reserved_statement
319
== "This is a statement 1\nThis is a statement 2\nThis is a statement 3\n"
320
)321
322
writer = SDWriter(default_project_config)
323
output = writer.write(document)
324
325
assert input_sdoc == output
326
327
328
def test_036_rationale_single_line(default_project_config):
329
input_sdoc = """
330
[DOCUMENT]331
TITLE: Test Doc332
333
[[SECTION]]334
TITLE: Test Section335
336
[REQUIREMENT]337
STATEMENT: Some statement338
RATIONALE: This is a Rationale339
340
[[/SECTION]]341
""".lstrip()
342
343
reader = SDReader()
344
345
document = reader.read(input_sdoc)
346
assert isinstance(document, SDocDocument)
347
348
writer = SDWriter(default_project_config)
349
output = writer.write(document)
350
351
assert input_sdoc == output
352
353
assert isinstance(
354
document.section_contents[0].section_contents[0], SDocNode
355
)356
requirement_1 = document.section_contents[0].section_contents[0]
357
assert requirement_1.rationale == "This is a Rationale"
358
359
360
def test_037_rationale_multi_line(default_project_config):
361
input_sdoc = """
362
[DOCUMENT]363
TITLE: Test Doc364
365
[[SECTION]]366
TITLE: Test Section367
368
[REQUIREMENT]369
STATEMENT: Some statement370
RATIONALE: >>>371
This is a Rationale line 1372
This is a Rationale line 2373
This is a Rationale line 3374
<<<375
376
[[/SECTION]]377
""".lstrip()
378
379
reader = SDReader()
380
381
document = reader.read(input_sdoc)
382
assert isinstance(document, SDocDocument)
383
384
writer = SDWriter(default_project_config)
385
output = writer.write(document)
386
387
assert input_sdoc == output
388
389
assert isinstance(
390
document.section_contents[0].section_contents[0], SDocNode
391
)392
requirement_1 = document.section_contents[0].section_contents[0]
393
assert requirement_1.rationale == (
394
"This is a Rationale line 1\n"
395
"This is a Rationale line 2\n"
396
"This is a Rationale line 3\n"
397
)398
399
400
# This test is needed to make sure that the grammar details related401
# to the difference of parting single vs multiline strings are covered.402
def test_050_requirement_single_line_statement_one_symbol(
403
default_project_config,
404
):405
input_sdoc = """
406
[DOCUMENT]407
TITLE: Test Doc408
409
[REQUIREMENT]410
STATEMENT: 1411
""".lstrip()
412
413
reader = SDReader()
414
415
document = reader.read(input_sdoc)
416
assert isinstance(document, SDocDocument)
417
418
document: SDocDocument = reader.read(input_sdoc)
419
requirement = document.section_contents[0]
420
assert requirement.reserved_statement == "1"
421
422
writer = SDWriter(default_project_config)
423
output = writer.write(document)
424
425
assert input_sdoc == output
426
427
428
def test_060_file_ref(default_project_config):
429
input_sdoc = """
430
[DOCUMENT]431
TITLE: Test Doc432
433
[REQUIREMENT]434
STATEMENT: ...435
RELATIONS:436
- TYPE: File437
VALUE: /tmp/sample.cpp438
""".lstrip()
439
440
reader = SDReader()
441
442
document = reader.read(input_sdoc)
443
assert isinstance(document, SDocDocument)
444
445
requirement: SDocNode = document.section_contents[0]
446
relations = requirement.relations
447
assert len(relations) == 1
448
449
reference: FileReference = relations[0]
450
assert isinstance(reference, FileReference)
451
assert reference.ref_type == ReferenceType.FILE
452
assert reference.g_file_entry.g_file_path == "/tmp/sample.cpp"
453
454
writer = SDWriter(default_project_config)
455
output = writer.write(document)
456
457
assert input_sdoc == output
458
459
460
def test_070_document_config_version(default_project_config):
461
input_sdoc = """
462
[DOCUMENT]463
TITLE: Test Doc464
VERSION: 0.0.1465
466
[REQUIREMENT]467
STATEMENT: ...468
""".lstrip()
469
470
reader = SDReader()
471
472
document = reader.read(input_sdoc)
473
assert isinstance(document, SDocDocument)
474
475
document: SDocDocument = reader.read(input_sdoc)
476
assert document.config.version == "0.0.1"
477
478
writer = SDWriter(default_project_config)
479
output = writer.write(document)
480
481
assert input_sdoc == output
482
483
484
def test_071_document_config_number(default_project_config):
485
input_sdoc = """
486
[DOCUMENT]487
TITLE: Test Doc488
UID: SDOC-01489
490
[REQUIREMENT]491
STATEMENT: ...492
""".lstrip()
493
494
reader = SDReader()
495
496
document = reader.read(input_sdoc)
497
assert isinstance(document, SDocDocument)
498
499
document: SDocDocument = reader.read(input_sdoc)
500
assert document.config.uid == "SDOC-01"
501
502
writer = SDWriter(default_project_config)
503
output = writer.write(document)
504
505
assert input_sdoc == output
506
507
508
def test_072_document_config_classification(default_project_config):
509
input_sdoc = """
510
[DOCUMENT]511
TITLE: Test Doc512
UID: SDOC-01513
VERSION: 0.0.1514
CLASSIFICATION: Restricted515
516
[REQUIREMENT]517
STATEMENT: ...518
""".lstrip()
519
520
reader = SDReader()
521
522
document = reader.read(input_sdoc)
523
assert isinstance(document, SDocDocument)
524
525
document: SDocDocument = reader.read(input_sdoc)
526
assert document.config.classification == "Restricted"
527
528
writer = SDWriter(default_project_config)
529
output = writer.write(document)
530
531
assert input_sdoc == output
532
533
534
def test_073_document_config_requirement_prefix(default_project_config):
535
input_sdoc = """
536
[DOCUMENT]537
TITLE: Test Doc538
UID: SDOC-01539
VERSION: 0.0.1540
PREFIX: DOC-541
542
[REQUIREMENT]543
STATEMENT: ...544
""".lstrip()
545
546
reader = SDReader()
547
548
document = reader.read(input_sdoc)
549
assert isinstance(document, SDocDocument)
550
551
document: SDocDocument = reader.read(input_sdoc)
552
assert document.config.requirement_prefix == "DOC-"
553
554
writer = SDWriter(default_project_config)
555
output = writer.write(document)
556
557
assert input_sdoc == output
558
559
560
def test_074_document_config_metadata(default_project_config):
561
input_sdoc = """
562
[DOCUMENT]563
TITLE: Test Doc564
UID: SDOC-01565
VERSION: 0.0.1566
METADATA:567
AUTHOR: James T. Kirk568
CHECKED-BY: Chuck Norris569
APPROVED-BY: Wile E. Coyote570
OWNER: [LINK: FOO]571
572
[REQUIREMENT]573
UID: FOO574
""".lstrip()
575
576
reader = SDReader()
577
578
document = reader.read(input_sdoc)
579
assert isinstance(document, SDocDocument)
580
581
custom_metadata = document.config.custom_metadata
582
assert custom_metadata is not None
583
owner_entry = custom_metadata.entries[-1]
584
assert owner_entry.key == "OWNER"
585
assert len(owner_entry.parts) == 1
586
assert isinstance(owner_entry.parts[0], InlineLink)
587
assert owner_entry.parts[0].link == "FOO"
588
589
writer = SDWriter(default_project_config)
590
output = writer.write(document)
591
592
assert input_sdoc == output
593
594
595
def test_090_document_config_all_fields(default_project_config):
596
input_sdoc = """
597
[DOCUMENT]598
TITLE: Test Doc599
UID: SDOC-01600
VERSION: 0.0.1601
CLASSIFICATION: Restricted602
ROOT: True603
OPTIONS:604
MARKUP: Text605
AUTO_LEVELS: Off606
LAYOUT: Website607
VIEW_STYLE: Table608
NODE_IN_TOC: True609
610
[[SECTION]]611
LEVEL: 123612
TITLE: "Section"613
614
[REQUIREMENT]615
LEVEL: 456616
STATEMENT: ABC617
618
[[/SECTION]]619
""".lstrip()
620
621
reader = SDReader()
622
623
document = reader.read(input_sdoc)
624
assert isinstance(document, SDocDocument)
625
626
document: SDocDocument = reader.read(input_sdoc)
627
assert document.title == "Test Doc"
628
assert document.config.version == "0.0.1"
629
assert document.config.uid == "SDOC-01"
630
assert document.config.classification == "Restricted"
631
assert document.config.root is True
632
assert document.config.markup == "Text"
633
assert document.config.auto_levels is False
634
assert document.config.requirement_style == "Table"
635
assert document.config.requirement_in_toc == "True"
636
637
section = document.section_contents[0]
638
assert isinstance(section, SDocNode)
639
assert section.custom_level == "123"
640
641
requirement = section.section_contents[0]
642
assert isinstance(requirement, SDocNode)
643
assert requirement.custom_level == "456"
644
645
writer = SDWriter(default_project_config)
646
output = writer.write(document)
647
648
assert input_sdoc == output
649
650
651
def test_100_basic_test(default_project_config):
652
input_sdoc = """
653
[DOCUMENT]654
TITLE: Test Doc655
656
[[SECTION]]657
TITLE: Test Section658
659
[REQUIREMENT]660
TAGS: Tag 1, Tag 2, Tag 3661
STATEMENT: System shall do X662
COMMENT: This requirement is very important663
RELATIONS:664
- TYPE: File665
VALUE: /usr/local/bin/hexe666
- TYPE: File667
VALUE: /usr/local/bin/hexe668
- TYPE: File669
VALUE: /usr/local/bin/hexe670
671
[REQUIREMENT]672
UID: REQ-001673
STATUS: Draft674
TITLE: Optional title B675
STATEMENT: System shall do Y676
COMMENT: This requirement is very important677
678
[[/SECTION]]679
""".lstrip()
680
681
reader = SDReader()
682
683
document = reader.read(input_sdoc)
684
assert isinstance(document, SDocDocument)
685
686
assert isinstance(
687
document.section_contents[0].section_contents[0], SDocNode
688
)689
requirement_1 = document.section_contents[0].section_contents[0]
690
assert requirement_1.reserved_tags[0] == "Tag 1"
691
assert requirement_1.reserved_tags[1] == "Tag 2"
692
assert requirement_1.reserved_tags[2] == "Tag 3"
693
694
writer = SDWriter(default_project_config)
695
output = writer.write(document)
696
697
assert input_sdoc == output
698
699
700
def test_081_document_config_markup_not_specified(default_project_config):
701
input_sdoc = """
702
[DOCUMENT]703
TITLE: Test Doc704
VERSION: 0.0.1705
706
[REQUIREMENT]707
TITLE: ...708
""".lstrip()
709
710
reader = SDReader()
711
712
document = reader.read(input_sdoc)
713
assert isinstance(document, SDocDocument)
714
715
document: SDocDocument = reader.read(input_sdoc)
716
assert document.config.version == "0.0.1"
717
assert document.config.markup is None
718
719
writer = SDWriter(default_project_config)
720
output = writer.write(document)
721
722
assert input_sdoc == output
723
724
725
def test_081_document_config_markup_specified(default_project_config):
726
input_sdoc = """
727
[DOCUMENT]728
TITLE: Test Doc729
VERSION: 0.0.1730
OPTIONS:731
MARKUP: Text732
733
[REQUIREMENT]734
STATEMENT: ...735
""".lstrip()
736
737
reader = SDReader()
738
739
document = reader.read(input_sdoc)
740
assert isinstance(document, SDocDocument)
741
742
document: SDocDocument = reader.read(input_sdoc)
743
assert document.config.version == "0.0.1"
744
745
writer = SDWriter(default_project_config)
746
output = writer.write(document)
747
748
assert input_sdoc == output
749
750
751
def test_082_document_config_auto_levels_specified_to_false(
752
default_project_config,
753
):754
input_sdoc = """
755
[DOCUMENT]756
TITLE: Test Doc757
VERSION: 0.0.1758
OPTIONS:759
AUTO_LEVELS: Off760
""".lstrip()
761
762
reader = SDReader()
763
764
document = reader.read(input_sdoc)
765
assert isinstance(document, SDocDocument)
766
767
document: SDocDocument = reader.read(input_sdoc)
768
assert document.config.auto_levels is False
769
770
writer = SDWriter(default_project_config)
771
output = writer.write(document)
772
773
assert input_sdoc == output
774
775
776
def test_083_requirement_level(default_project_config):
777
input_sdoc = """
778
[DOCUMENT]779
TITLE: Test Doc780
VERSION: 0.0.1781
OPTIONS:782
AUTO_LEVELS: Off783
784
[[SECTION]]785
LEVEL: 123786
TITLE: "Section"787
788
[REQUIREMENT]789
LEVEL: 456790
STATEMENT: ABC791
792
[[/SECTION]]793
""".lstrip()
794
795
reader = SDReader()
796
797
document = reader.read(input_sdoc)
798
assert isinstance(document, SDocDocument)
799
800
document: SDocDocument = reader.read(input_sdoc)
801
assert document.config.auto_levels is False
802
section: SDocNode = document.section_contents[0]
803
assert section.custom_level == "123"
804
805
requirement = section.section_contents[0]
806
assert isinstance(requirement, SDocNode)
807
assert requirement.custom_level == "456"
808
809
writer = SDWriter(default_project_config)
810
output = writer.write(document)
811
812
assert input_sdoc == output
813
814
815
def test_085_options_requirement_style(default_project_config):
816
input_sdoc = """
817
[DOCUMENT]818
TITLE: Test Doc819
VERSION: 0.0.1820
OPTIONS:821
VIEW_STYLE: Table822
""".lstrip()
823
824
reader = SDReader()
825
826
document = reader.read(input_sdoc)
827
assert isinstance(document, SDocDocument)
828
829
document: SDocDocument = reader.read(input_sdoc)
830
assert document.config.requirement_style == "Table"
831
832
writer = SDWriter(default_project_config)
833
output = writer.write(document)
834
835
assert input_sdoc == output
836
837
838
def test_087_options_requirement_in_toc(default_project_config):
839
input_sdoc = """
840
[DOCUMENT]841
TITLE: Test Doc842
VERSION: 0.0.1843
OPTIONS:844
NODE_IN_TOC: True845
""".lstrip()
846
847
reader = SDReader()
848
849
document = reader.read(input_sdoc)
850
assert isinstance(document, SDocDocument)
851
852
document: SDocDocument = reader.read(input_sdoc)
853
assert document.config.requirement_in_toc == "True"
854
855
writer = SDWriter(default_project_config)
856
output = writer.write(document)
857
858
assert input_sdoc == output
859
860
861
def test_089_document_config_use_mid(default_project_config):
862
input_sdoc = """
863
[DOCUMENT]864
MID: foobar865
TITLE: Test Doc866
OPTIONS:867
ENABLE_MID: True868
""".lstrip()
869
870
reader = SDReader()
871
872
document = reader.read(input_sdoc)
873
assert isinstance(document, SDocDocument)
874
875
document: SDocDocument = reader.read(input_sdoc)
876
assert document.config.enable_mid is True
877
878
writer = SDWriter(default_project_config)
879
output = writer.write(document)
880
881
assert input_sdoc == output
882
883
884
def test_090_byte_order_mark_symbol_does_not_cause_parsing_errors():
885
input_sdoc = (
886
"\ufeff"
887
"""\
888
[DOCUMENT]889
TITLE: Test Doc890
"""891
)892
893
reader = SDReader()
894
895
document = reader.read(input_sdoc)
896
assert isinstance(document, SDocDocument)
897
898
899
def test__validation__30__composite_node_start_end_tags_do_not_match():
900
input_sdoc = """\
901
[DOCUMENT]902
TITLE: Test Doc903
904
[[REQUIREMENT]]905
UID: TITLE906
907
[[/FOOBAR]]908
""".lstrip()
909
910
reader = SDReader()
911
912
with pytest.raises(Exception) as exc_info:
913
_ = reader.read(input_sdoc)
914
915
assert exc_info.type is StrictDocException
916
assert exc_info.value.args[0] == (
917
"[[NODE]] syntax error: "918
"Opening and closing tags must match: "919
"opening: REQUIREMENT, closing: FOOBAR."920
)921
922
923
def test_edge_case_01_minimal_requirement(default_project_config):
924
input_sdoc = """
925
[DOCUMENT]926
TITLE: Test Doc927
928
[REQUIREMENT]929
STATEMENT: ...930
""".lstrip()
931
932
reader = SDReader()
933
934
document: SDocDocument = reader.read(input_sdoc)
935
assert isinstance(document, SDocDocument)
936
937
requirement: SDocNode = document.section_contents[0]
938
assert requirement.reserved_uid is None
939
assert requirement.reserved_title is None
940
assert requirement.reserved_statement == "..."
941
942
writer = SDWriter(default_project_config)
943
output = writer.write(document)
944
945
assert input_sdoc == output
946
947
948
def test_edge_case_02_uid_present_but_empty_with_no_space_character():
949
# Note: There is no whitespace character after "UID:".950
input_sdoc = """
951
[DOCUMENT]952
TITLE: Test Doc953
954
[REQUIREMENT]955
UID:956
""".lstrip()
957
958
reader = SDReader()
959
960
with pytest.raises(Exception) as exc_info:
961
_ = reader.read(input_sdoc)
962
963
assert exc_info.type is StrictDocException
964
assert "Expected ': '" in exc_info.value.args[0]
965
966
967
def test_edge_case_03_uid_present_but_empty_with_space_character():
968
# Note: There is a whitespace character after "UID:".969
input_sdoc = """
970
[DOCUMENT]971
TITLE: Test Doc972
973
[REQUIREMENT]974
UID: 975
""".lstrip() # noqa: W291
976
977
reader = SDReader()
978
979
with pytest.raises(Exception) as exc_info:
980
_ = reader.read(input_sdoc)
981
982
assert exc_info.type is StrictDocException
983
assert "Expected '([\\w]+[\\w()\\-\\/.: ]*)'" in exc_info.value.args[0]
984
985
986
def test_edge_case_04_uid_present_but_empty_with_two_space_characters():
987
# Note: There are two whitespace characters after "UID:".988
input_sdoc = """
989
[DOCUMENT]990
TITLE: Test Doc991
992
[REQUIREMENT]993
UID: 994
""".lstrip() # noqa: W291
995
996
reader = SDReader()
997
998
with pytest.raises(Exception) as exc_info:
999
_ = reader.read(input_sdoc)
1000
1001
assert exc_info.type is StrictDocException
1002
assert "Expected '([\\w]+[\\w()\\-\\/.: ]*)'" in exc_info.value.args[0]
1003
1004
1005
def test_edge_case_10_empty_multiline_field():
1006
input_sdoc = """
1007
[DOCUMENT]1008
TITLE: Test Doc1009
1010
[REQUIREMENT]1011
COMMENT: >>>1012
<<<1013
""".lstrip()
1014
1015
reader = SDReader()
1016
1017
with pytest.raises(Exception) as exc_info:
1018
_ = reader.read(input_sdoc)
1019
1020
assert exc_info.type is StrictDocException
1021
assert (
1022
"Expected '^\\[ANCHOR: ' or '[LINK: ' or "
1023
"'(?ms)(?!^<<<)(?!\\[LINK: "
1024
"([\\w]+[\\w()\\-\\/.: ]*))(?!^\\[ANCHOR: "
1025
"([\\w]+[\\w()\\-\\/.: ]*)).'" in exc_info.value.args[0]
1026
)1027
1028
1029
def test_edge_case_11_empty_multiline_field_with_one_newline():
1030
input_sdoc = """
1031
[DOCUMENT]1032
TITLE: Test Doc1033
1034
[REQUIREMENT]1035
COMMENT: >>>1036
1037
<<<1038
""".lstrip()
1039
1040
reader = SDReader()
1041
1042
with pytest.raises(Exception) as exc_info:
1043
_ = reader.read(input_sdoc)
1044
1045
assert exc_info.type is StrictDocException
1046
assert "Node statement cannot be empty." in exc_info.value.args[0]
1047
1048
1049
def test_edge_case_19_empty_section_title():
1050
input_sdoc = """
1051
[DOCUMENT]1052
TITLE: Test Doc1053
1054
[[SECTION]]1055
TITLE:1056
1057
[[/SECTION]]1058
""".lstrip()
1059
1060
reader = SDReader()
1061
1062
with pytest.raises(StrictDocException) as exc_info:
1063
_ = reader.read(input_sdoc)
1064
1065
assert exc_info.type is StrictDocException
1066
assert "TITLE:*" in exc_info.value.args[0]
1067
assert "Expected ' '" in exc_info.value.args[0]
1068
1069
1070
def test_edge_case_20_empty_section_title():
1071
input_sdoc = """
1072
[DOCUMENT]1073
TITLE: Test Doc1074
1075
[[SECTION]]1076
TITLE: 1077
1078
[[/SECTION]]1079
""".lstrip() # noqa: W291
1080
1081
reader = SDReader()
1082
1083
with pytest.raises(Exception) as exc_info:
1084
_ = reader.read(input_sdoc)
1085
1086
assert exc_info.type is StrictDocException
1087
assert "TITLE: *" in exc_info.value.args[0]
1088
1089
1090
def test_edge_case_21_section_title_with_empty_space():
1091
# Empty space after TITLE:1092
input_sdoc = """
1093
[DOCUMENT]1094
TITLE: Test Doc1095
1096
[[SECTION]]1097
TITLE: 1098
1099
[[/SECTION]]1100
""".lstrip() # noqa: W291
1101
1102
reader = SDReader()
1103
1104
with pytest.raises(Exception) as exc_info:
1105
_ = reader.read(input_sdoc)
1106
1107
assert exc_info.type is StrictDocException
1108
assert "TITLE: *" in exc_info.value.args[0]
1109
1110
1111
def test_edge_case_22_section_title_with_two_empty_spaces():
1112
# Two empty spaces after TITLE:1113
input_sdoc = """
1114
[DOCUMENT]1115
TITLE: Test Doc1116
1117
[[SECTION]]1118
TITLE: 1119
1120
[[/SECTION]]1121
""".lstrip() # noqa: W291
1122
1123
reader = SDReader()
1124
1125
with pytest.raises(Exception) as exc_info:
1126
_ = reader.read(input_sdoc)
1127
1128
assert exc_info.type is StrictDocException
1129
assert "TITLE: *" in exc_info.value.args[0]
1130
1131
1132
def test_edge_case_23_leading_spaces_do_not_imply_empy_field(
1133
default_project_config,
1134
):1135
input_sdoc = """
1136
[DOCUMENT]1137
TITLE: Test Doc1138
1139
[GRAMMAR]1140
ELEMENTS:1141
- TAG: TEXT1142
FIELDS:1143
- TITLE: STATEMENT1144
TYPE: String1145
REQUIRED: True1146
- TAG: REQUIREMENT1147
FIELDS:1148
- TITLE: STATEMENT1149
TYPE: String1150
REQUIRED: False1151
- TITLE: MY_FIELD1152
TYPE: String1153
REQUIRED: True1154
RELATIONS:1155
- TYPE: Parent1156
1157
[REQUIREMENT]1158
MY_FIELD: >>>1159
Some text here...1160
Some text here...1161
Some text here...1162
<<<1163
""".lstrip()
1164
1165
expected_sdoc = """
1166
[DOCUMENT]1167
TITLE: Test Doc1168
1169
[GRAMMAR]1170
ELEMENTS:1171
- TAG: TEXT1172
FIELDS:1173
- TITLE: STATEMENT1174
TYPE: String1175
REQUIRED: True1176
- TAG: REQUIREMENT1177
FIELDS:1178
- TITLE: STATEMENT1179
TYPE: String1180
REQUIRED: False1181
- TITLE: MY_FIELD1182
TYPE: String1183
REQUIRED: True1184
RELATIONS:1185
- TYPE: Parent1186
1187
[REQUIREMENT]1188
MY_FIELD: >>>1189
Some text here...1190
Some text here...1191
Some text here...1192
<<<1193
""".lstrip()
1194
1195
reader = SDReader()
1196
1197
document = reader.read(input_sdoc)
1198
assert isinstance(document, SDocDocument)
1199
1200
writer = SDWriter(default_project_config)
1201
output = writer.write(document)
1202
assert expected_sdoc == output
1203
1204
1205
def test_edge_case_30_single_vs_multiline_disallow_multiline_reserved_single():
1206
input_sdoc = """\
1207
[DOCUMENT]1208
TITLE: Test Doc1209
1210
[REQUIREMENT]1211
STATUS: >>>1212
Multiline status is not allowed.1213
<<<1214
""".lstrip() # noqa: W291
1215
1216
reader = SDReader()
1217
1218
with pytest.raises(Exception) as exc_info:
1219
_ = reader.read(input_sdoc)
1220
1221
assert exc_info.type is StrictDocException
1222
assert exc_info.value.args[0] == (
1223
"The node field STATUS is a reserved field and can only be written as "1224
"a single-line, not multiline, field."1225
)1226
1227
1228
def test_crlf_single_line_field():
1229
input_sdoc = (
1230
"[DOCUMENT]\r\n"
1231
"TITLE: Test Doc\r\n"
1232
"\r\n"
1233
"[REQUIREMENT]\r\n"
1234
"STATEMENT: Test statement.\r\n"
1235
)1236
1237
reader = SDReader()
1238
1239
document = reader.read(input_sdoc)
1240
assert isinstance(document, SDocDocument)
1241
assert document.title == "Test Doc"
1242
node = document.section_contents[0]
1243
assert isinstance(node, SDocNode)
1244
assert node.reserved_statement == "Test statement."
1245
1246
1247
def test_crlf_multiline_field():
1248
input_sdoc = (
1249
"[DOCUMENT]\r\n"
1250
"TITLE: Test Doc\r\n"
1251
"\r\n"
1252
"[REQUIREMENT]\r\n"
1253
"STATEMENT: >>>\r\n"
1254
"Multiline content.\r\n"
1255
"<<<\r\n"
1256
)1257
1258
reader = SDReader()
1259
1260
document = reader.read(input_sdoc)
1261
assert isinstance(document, SDocDocument)
1262
node = document.section_contents[0]
1263
assert isinstance(node, SDocNode)
1264
assert node.reserved_statement == "Multiline content.\r\n"
1265
1266
1267
def test_anchor_title_with_quoted_comma_roundtrip(default_project_config):
1268
input_sdoc = """
1269
[DOCUMENT]1270
TITLE: Test Doc1271
1272
[TEXT]1273
STATEMENT: >>>1274
[ANCHOR: A1, "Title with, a comma"]1275
<<<1276
""".lstrip()
1277
1278
reader = SDReader()
1279
1280
document = reader.read(input_sdoc)
1281
assert isinstance(document, SDocDocument)
1282
1283
writer = SDWriter(default_project_config)
1284
output = writer.write(document)
1285
1286
assert input_sdoc == output
1287
1288
1289
def test_anchor_title_with_quoted_bracket_roundtrip(default_project_config):
1290
input_sdoc = """
1291
[DOCUMENT]1292
TITLE: Test Doc1293
1294
[TEXT]1295
STATEMENT: >>>1296
[ANCHOR: A1, "Title [with] brackets"]1297
<<<1298
""".lstrip()
1299
1300
reader = SDReader()
1301
1302
document = reader.read(input_sdoc)
1303
assert isinstance(document, SDocDocument)
1304
1305
writer = SDWriter(default_project_config)
1306
output = writer.write(document)
1307
1308
assert input_sdoc == output