Skip to content

Commit 6d87279

Browse files
authored
fix: BCPs can normatively cite all other standards levels (ietf-tools#6530)
* fix: BCPs can normatively cite all other standards levels Fixes ietf-tools#6524 * Revise the logic and add tests * Fix bug in truth table
1 parent 601ab53 commit 6d87279

2 files changed

Lines changed: 146 additions & 13 deletions

File tree

ietf/doc/models.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -676,39 +676,59 @@ def __str__(self):
676676
return u"%s %s %s" % (self.source.name, self.relationship.name.lower(), self.target.name)
677677

678678
def is_downref(self):
679-
680-
if self.source.type.slug!='draft' or self.relationship.slug not in ['refnorm','refold','refunk']:
679+
if self.source.type.slug != "draft" or self.relationship.slug not in [
680+
"refnorm",
681+
"refold",
682+
"refunk",
683+
]:
681684
return None
682685

683686
state = self.source.get_state()
684-
if state and state.slug == 'rfc':
687+
if state and state.slug == "rfc":
685688
source_lvl = self.source.std_level.slug if self.source.std_level else None
686689
elif self.source.intended_std_level:
687690
source_lvl = self.source.intended_std_level.slug
688691
else:
689692
source_lvl = None
690693

691-
if source_lvl not in ['bcp','ps','ds','std']:
694+
if source_lvl not in ["bcp", "ps", "ds", "std", "unkn"]:
692695
return None
693696

694-
if self.target.document.get_state().slug == 'rfc':
697+
if self.target.document.get_state().slug == "rfc":
695698
if not self.target.document.std_level:
696-
target_lvl = 'unkn'
699+
target_lvl = "unkn"
697700
else:
698701
target_lvl = self.target.document.std_level.slug
699702
else:
700703
if not self.target.document.intended_std_level:
701-
target_lvl = 'unkn'
704+
target_lvl = "unkn"
702705
else:
703706
target_lvl = self.target.document.intended_std_level.slug
704707

705-
rank = { 'ps':1, 'ds':2, 'std':3, 'bcp':3 }
708+
if self.relationship.slug not in ["refnorm", "refunk"]:
709+
return None
710+
711+
if source_lvl in ["inf", "exp"]:
712+
return None
706713

707-
if ( target_lvl not in rank ) or ( rank[target_lvl] < rank[source_lvl] ):
708-
if self.relationship.slug == 'refnorm' and target_lvl!='unkn':
709-
return "Downref"
710-
else:
711-
return "Possible Downref"
714+
pos_downref = (
715+
"Downref" if self.relationship.slug != "refunk" else "Possible Downref"
716+
)
717+
718+
if source_lvl in ["bcp", "ps", "ds", "std"] and target_lvl in ["inf", "exp"]:
719+
return pos_downref
720+
721+
if source_lvl == "ds" and target_lvl == "ps":
722+
return pos_downref
723+
724+
if source_lvl == "std" and target_lvl in ["ps", "ds"]:
725+
return pos_downref
726+
727+
if source_lvl not in ["inf", "exp"] and target_lvl == "unkn":
728+
return "Possible Downref"
729+
730+
if source_lvl == "unkn" and target_lvl in ["ps", "ds"]:
731+
return "Possible Downref"
712732

713733
return None
714734

ietf/doc/tests_models.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Copyright The IETF Trust 2016-2023, All Rights Reserved
2+
# -*- coding: utf-8 -*-
3+
4+
import itertools
5+
6+
from ietf.doc.factories import WgRfcFactory
7+
from ietf.doc.models import RelatedDocument
8+
from ietf.utils.test_utils import TestCase
9+
10+
11+
class RelatedDocumentTests(TestCase):
12+
def test_is_downref(self):
13+
rfcs = [
14+
WgRfcFactory(std_level_id=lvl)
15+
for lvl in ["inf", "exp", "bcp", "ps", "ds", "std", "unkn"]
16+
]
17+
18+
result_matrix = {
19+
# source
20+
"inf": {
21+
"inf": None, # target
22+
"exp": None, # target
23+
"bcp": None, # target
24+
"ps": None, # target
25+
"ds": None, # target
26+
"std": None, # target
27+
"unkn": None, # target
28+
},
29+
# source
30+
"exp": {
31+
"inf": None, # target
32+
"exp": None, # target
33+
"bcp": None, # target
34+
"ps": None, # target
35+
"ds": None, # target
36+
"std": None, # target
37+
"unkn": None, # target
38+
},
39+
# source
40+
"bcp": {
41+
"inf": "Downref", # target
42+
"exp": "Downref", # target
43+
"bcp": None, # target
44+
"ps": None, # target
45+
"ds": None, # target
46+
"std": None, # target
47+
"unkn": "Possible Downref", # target
48+
},
49+
# source
50+
"ps": {
51+
"inf": "Downref", # target
52+
"exp": "Downref", # target
53+
"bcp": None, # target
54+
"ps": None, # target
55+
"ds": None, # target
56+
"std": None, # target
57+
"unkn": "Possible Downref", # target
58+
},
59+
# source
60+
"ds": {
61+
"inf": "Downref", # target
62+
"exp": "Downref", # target
63+
"bcp": None, # target
64+
"ps": "Downref", # target
65+
"ds": None, # target
66+
"std": None, # target
67+
"unkn": "Possible Downref", # target
68+
},
69+
# source
70+
"std": {
71+
"inf": "Downref", # target
72+
"exp": "Downref", # target
73+
"bcp": None, # target
74+
"ps": "Downref", # target
75+
"ds": "Downref", # target
76+
"std": None, # target
77+
"unkn": "Possible Downref", # target
78+
},
79+
# source
80+
"unkn": {
81+
"inf": None, # target
82+
"exp": None, # target
83+
"bcp": None, # target
84+
"ps": "Possible Downref", # target
85+
"ds": "Possible Downref", # target
86+
"std": None, # target
87+
"unkn": "Possible Downref", # target
88+
},
89+
}
90+
91+
for rel in ["refnorm", "refinfo", "refunk", "refold"]:
92+
for source, target in itertools.product(rfcs, rfcs):
93+
ref = RelatedDocument.objects.create(
94+
source=source,
95+
target=target.docalias.first(),
96+
relationship_id=rel,
97+
)
98+
99+
result = ref.is_downref()
100+
101+
desired_result = (
102+
result_matrix[source.std_level_id][target.std_level_id]
103+
if ref.relationship.slug in ["refnorm", "refunk"]
104+
else None
105+
)
106+
if (
107+
ref.relationship.slug == "refunk"
108+
and desired_result is not None
109+
and not desired_result.startswith("Possible")
110+
):
111+
desired_result = f"Possible {desired_result}"
112+
113+
self.assertEqual(desired_result, result)

0 commit comments

Comments
 (0)