@@ -556,20 +556,74 @@ def test_entity_path_from_identifier():
556556 quoted_entity_id = "pics/2017-06-11%2012.56.14.jpg"
557557 path = ROCrateEntity .get_path_from_identifier (quoted_entity_id , rocrate_path = rocrate_path )
558558 logger .debug (f"Quoted Entity Path: { path } " )
559- assert str (path ) == f"{ rocrate_path } /pics/2017-06-11%2012.56.14.jpg" , \
559+ assert str (path ) == f"{ rocrate_path } /pics/2017-06-11%2012.56.14.jpg" , (
560560 "Path should be pics/2017-06-11%2012.56.14.jpg"
561+ )
561562
562563 # Test quoted entity id which does not exist within the ro-crate
563564 quoted_entity_id = "pics/2018-06-11%2012.56.14.jpg"
564- path = ROCrateEntity .get_path_from_identifier (
565- quoted_entity_id , rocrate_path = rocrate_path , decode = True )
565+ path = ROCrateEntity .get_path_from_identifier (quoted_entity_id , rocrate_path = rocrate_path , decode = True )
566566 logger .debug (f"Quoted Entity Path: { path } " )
567- assert str (path ) == f"{ rocrate_path } /pics/2018-06-11 12.56.14.jpg" , \
568- "Path should be pics/2018-06-11 12.56.14.jpg"
567+ assert str (path ) == f"{ rocrate_path } /pics/2018-06-11 12.56.14.jpg" , "Path should be pics/2018-06-11 12.56.14.jpg"
569568
570569 # Test unquoted entity id which exists within the ro-crate
571570 unquoted_entity_id = "pics/2017-06-11 12.56.14.jpg"
572571 path = ROCrateEntity .get_path_from_identifier (unquoted_entity_id , rocrate_path = rocrate_path )
573572 logger .debug (f"Unquoted Entity Path: { path } " )
574- assert str (path ) == f"{ rocrate_path } /pics/2017-06-11 12.56.14.jpg" , \
575- "Path should be pics/2017-06-11 12.56.14.jpg"
573+ assert str (path ) == f"{ rocrate_path } /pics/2017-06-11 12.56.14.jpg" , "Path should be pics/2017-06-11 12.56.14.jpg"
574+
575+
576+ def _metadata_dict_with_id (entity_id : str ) -> dict :
577+ """Build a minimal RO-Crate metadata dict referencing a single data entity."""
578+ return {
579+ "@context" : "https://w3id.org/ro/crate/1.1/context" ,
580+ "@graph" : [
581+ {
582+ "@id" : "ro-crate-metadata.json" ,
583+ "@type" : "CreativeWork" ,
584+ "conformsTo" : {"@id" : "https://w3id.org/ro/crate/1.1" },
585+ "about" : {"@id" : "./" },
586+ },
587+ {
588+ "@id" : "./" ,
589+ "@type" : "Dataset" ,
590+ "name" : "Test crate" ,
591+ "hasPart" : [{"@id" : entity_id }],
592+ },
593+ {"@id" : entity_id , "@type" : "File" , "name" : "remote-file" },
594+ ],
595+ }
596+
597+
598+ @pytest .mark .parametrize (
599+ "entity_id" ,
600+ [
601+ # authority-based absolute URIs (with a `//` authority component)
602+ "scp://transfer.example.org//data/A.0.0" ,
603+ "sftp://user@host/path/to/file" ,
604+ "s3://bucket/key" ,
605+ "https://example.org/data.txt" ,
606+ "arcp://name,foo/bar" ,
607+ # scheme-only absolute URIs (no authority; RO-Crate 1.1 § 4.2.2 + RFC 3986)
608+ "urn:doi:10.5281/zenodo.1234" ,
609+ "doi:10.5281/zenodo.1234" ,
610+ ],
611+ )
612+ def test_absolute_uri_data_entity_is_classified_as_remote (entity_id ):
613+ """
614+ Data entities whose @id is an absolute URI (any non-file scheme, with or
615+ without authority) MUST be recognized as remote (web-based) data entities
616+ so that the must/4 payload check is skipped for them.
617+
618+ Regression test for issue #176.
619+ """
620+ crate = ROCrate .from_metadata_dict (_metadata_dict_with_id (entity_id ))
621+ entity = crate .metadata .get_entity (entity_id )
622+ assert entity is not None , "Entity should be present in the metadata"
623+ assert entity .is_remote (), f"Entity with absolute URI '{ entity_id } ' should be classified as remote"
624+ assert entity in crate .metadata .get_web_data_entities (), (
625+ f"Entity '{ entity_id } ' should be listed as a web data entity"
626+ )
627+ assert entity not in crate .metadata .get_data_entities (exclude_web_data_entities = True ), (
628+ f"Entity '{ entity_id } ' should be excluded from local-only data entities"
629+ )
0 commit comments