@@ -634,6 +634,87 @@ def test_smartlink(self) -> None:
634634 )
635635 self .assertEqual (302 , response .status_code )
636636
637+ def _smartlink_redirect_location (self , client , path : str ) -> tuple [int , str ]:
638+ response = client .get (path , headers = {"Content-Type" : "application/json" })
639+ location = ""
640+ for head in response .headers :
641+ if head [0 ] == "Location" :
642+ location = head [1 ]
643+ return response .status_code , location
644+
645+ def test_smartlink_critical_edge_cases (self ) -> None :
646+ """Critical smartlink paths from #945 — multi-CRE, unlinked node, ntype, version."""
647+ collection = db .Node_collection ().with_graph ()
648+ with self .app .test_client () as client :
649+ # Multiple CREs → standard-section node page (preserved by #938).
650+ cwe_multi = defs .Standard (name = "CWEmulti" , sectionID = "789" )
651+ ce = defs .CRE (id = "444-444" , description = "CE" , name = "CE" , tags = [])
652+ cf = defs .CRE (id = "555-555" , description = "CF" , name = "CF" , tags = [])
653+ dcwe_multi = collection .add_node (cwe_multi )
654+ dce = collection .add_cre (ce )
655+ dcf = collection .add_cre (cf )
656+ collection .add_link (dce , dcwe_multi , ltype = defs .LinkTypes .LinkedTo )
657+ collection .add_link (dcf , dcwe_multi , ltype = defs .LinkTypes .LinkedTo )
658+
659+ status , location = self ._smartlink_redirect_location (
660+ client , "/smartlink/standard/CWEmulti/789"
661+ )
662+ self .assertEqual (status , 302 )
663+ self .assertEqual (location , "/node/standard/CWEmulti/sectionid/789" )
664+
665+ # Local standard with no CRE links → MITRE external redirect, not node page.
666+ orphan = defs .Standard (name = "CWE" , sectionID = "8888" )
667+ collection .add_node (orphan )
668+ status , location = self ._smartlink_redirect_location (
669+ client , "/smartlink/standard/CWE/8888"
670+ )
671+ self .assertEqual (status , 302 )
672+ self .assertEqual (
673+ location , "https://cwe.mitre.org/data/definitions/8888.html"
674+ )
675+
676+ # Case-insensitive ntype still resolves the standard node.
677+ cwe_std = defs .Standard (name = "CWE" , sectionID = "456" )
678+ cre_a = defs .CRE (id = "222-222" , description = "CD" , name = "CD" , tags = [])
679+ cre_b = defs .CRE (id = "223-223" , description = "CE" , name = "CE" , tags = [])
680+ dcwe = collection .add_node (cwe_std )
681+ dcre_a = collection .add_cre (cre_a )
682+ dcre_b = collection .add_cre (cre_b )
683+ collection .add_link (dcre_a , dcwe , ltype = defs .LinkTypes .LinkedTo )
684+ collection .add_link (dcre_b , dcwe , ltype = defs .LinkTypes .LinkedTo )
685+
686+ status , location = self ._smartlink_redirect_location (
687+ client , "/smartlink/STANDARD/CWE/456"
688+ )
689+ self .assertEqual (status , 302 )
690+ self .assertEqual (location , "/node/STANDARD/CWE/sectionid/456" )
691+
692+ # version query param selects the matching standard row (multi-CRE → node page).
693+ std_v1 = defs .Standard (name = "VERSTD" , sectionID = "100" , version = "1.0" )
694+ std_v2 = defs .Standard (name = "VERSTD" , sectionID = "200" , version = "2.0" )
695+ cre_v1a = defs .CRE (id = "100-100" , description = "v1a" , name = "V1A" , tags = [])
696+ cre_v1b = defs .CRE (id = "100-101" , description = "v1b" , name = "V1B" , tags = [])
697+ cre_v2a = defs .CRE (id = "200-200" , description = "v2a" , name = "V2A" , tags = [])
698+ cre_v2b = defs .CRE (id = "200-201" , description = "v2b" , name = "V2B" , tags = [])
699+ dstd_v1 = collection .add_node (std_v1 )
700+ dstd_v2 = collection .add_node (std_v2 )
701+ for cre in (cre_v1a , cre_v1b , cre_v2a , cre_v2b ):
702+ dcre = collection .add_cre (cre )
703+ target = dstd_v1 if cre .id .startswith ("100" ) else dstd_v2
704+ collection .add_link (dcre , target , ltype = defs .LinkTypes .LinkedTo )
705+
706+ status , location = self ._smartlink_redirect_location (
707+ client , "/smartlink/standard/VERSTD/100?version=1.0"
708+ )
709+ self .assertEqual (status , 302 )
710+ self .assertEqual (location , "/node/standard/VERSTD/sectionid/100" )
711+
712+ status , location = self ._smartlink_redirect_location (
713+ client , "/smartlink/standard/VERSTD/200?version=2.0"
714+ )
715+ self .assertEqual (status , 302 )
716+ self .assertEqual (location , "/node/standard/VERSTD/sectionid/200" )
717+
637718 @patch .object (redis , "from_url" )
638719 @patch .object (db , "Node_collection" )
639720 def test_gap_analysis_from_cache_full_response (
0 commit comments