Skip to content

Commit 45b2f49

Browse files
committed
test(uri): ✅ add tests for file:// URIs with non-local authority
1 parent 379d297 commit 45b2f49

2 files changed

Lines changed: 63 additions & 0 deletions

File tree

tests/unit/test_rocrate.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@ def _metadata_dict_with_id(entity_id: str) -> dict:
604604
"s3://bucket/key",
605605
"https://example.org/data.txt",
606606
"arcp://name,foo/bar",
607+
# `file://` URIs with a (non-local) authority denote files living on
608+
# another host (RFC 8089), so they are remote too.
609+
"file://gs02r3b58-ib0/scratch/tmp/5190874/tmp_rf_samples_slt86rc0",
607610
# scheme-only absolute URIs (no authority; RO-Crate 1.1 § 4.2.2 + RFC 3986)
608611
"urn:doi:10.5281/zenodo.1234",
609612
"doi:10.5281/zenodo.1234",
@@ -627,3 +630,30 @@ def test_absolute_uri_data_entity_is_classified_as_remote(entity_id):
627630
assert entity not in crate.metadata.get_data_entities(exclude_web_data_entities=True), (
628631
f"Entity '{entity_id}' should be excluded from local-only data entities"
629632
)
633+
634+
635+
@pytest.mark.parametrize(
636+
"entity_id",
637+
[
638+
# `file://` URIs without an authority (RFC 8089) or with the special
639+
# `localhost` authority refer to the local machine, so they describe
640+
# local payload members that the must/4 check must still verify.
641+
"file:///absolute/path/to/file.txt",
642+
"file://localhost/absolute/path/to/file.txt",
643+
],
644+
)
645+
def test_local_file_uri_data_entity_is_not_remote(entity_id):
646+
"""
647+
`file://` Data Entity identifiers that point to the local machine (empty or
648+
`localhost` authority) MUST NOT be treated as remote/web-based: only
649+
`file://<host>/...` URIs with a real host are remote (issue #176 follow-up).
650+
"""
651+
crate = ROCrate.from_metadata_dict(_metadata_dict_with_id(entity_id))
652+
entity = crate.metadata.get_entity(entity_id)
653+
assert entity is not None, "Entity should be present in the metadata"
654+
assert not entity.is_remote(), (
655+
f"Entity with local file URI '{entity_id}' should NOT be classified as remote"
656+
)
657+
assert entity not in crate.metadata.get_web_data_entities(), (
658+
f"Entity '{entity_id}' should not be listed as a web data entity"
659+
)

tests/unit/test_uri.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,39 @@ def test_scheme_only_absolute_uri_is_remote(uri_str, expected_scheme):
7373
assert not uri.is_natively_checkable()
7474

7575

76+
def test_file_uri_with_remote_host_is_remote():
77+
# A `file://` URI carrying a (non-local) authority points to a file on
78+
# another host (RFC 8089) and must be treated as remote, not as a local
79+
# payload member (regression for issue #176 with `file://` schemes).
80+
uri = URI("file://gs02r3b58-ib0/scratch/tmp/5190874/tmp_rf_samples_slt86rc0")
81+
assert uri.scheme == "file"
82+
assert uri.is_remote_resource()
83+
assert not uri.is_local_resource()
84+
assert not uri.is_natively_checkable()
85+
86+
87+
@pytest.mark.parametrize("uri_str", [
88+
"file:///absolute/path/file.txt",
89+
"file://localhost/absolute/path/file.txt",
90+
])
91+
def test_file_uri_to_local_host_is_local(uri_str):
92+
# An empty or `localhost` authority denotes the local machine.
93+
uri = URI(uri_str)
94+
assert uri.scheme == "file"
95+
assert uri.is_local_resource()
96+
assert not uri.is_remote_resource()
97+
98+
99+
@pytest.mark.parametrize("path", ["README.md", "data/file.txt", "./", "/abs/dir"])
100+
def test_local_path_never_gains_a_spurious_host(path):
101+
# Plain filesystem paths are normalized to authority-less `file:` URIs, so
102+
# the first path segment is never mistaken for a remote host.
103+
uri = URI(path)
104+
assert uri.is_local_resource()
105+
assert not uri.is_remote_resource()
106+
assert uri.get_netloc() == ""
107+
108+
76109
def test_url_with_query_params():
77110
uri = URI("http://example.com?param1=value1&param2=value2")
78111
assert uri.get_query_param("param1") == "value1"

0 commit comments

Comments
 (0)