Skip to content

Commit 7df2f97

Browse files
test: Add unit tests for filepath reserved section validation
- Test that filepath rejects paths starting with _hash/ - Test that filepath rejects paths starting with _schema/ - Test that filepath allows all other user-managed paths - Test filepath codec properties and registration
1 parent cc77b37 commit 7df2f97

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

tests/unit/test_codecs.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,106 @@ def test_blob_handles_serialization(self):
427427
# BlobCodec.decode() should unpack back to original
428428
decoded = blob_codec.decode(encoded)
429429
assert decoded == data
430+
431+
432+
class TestFilepathCodec:
433+
"""Tests for the built-in FilepathCodec."""
434+
435+
def test_filepath_is_registered(self):
436+
"""Test that filepath is automatically registered."""
437+
assert is_codec_registered("filepath")
438+
439+
def test_filepath_properties(self):
440+
"""Test FilepathCodec properties."""
441+
filepath_codec = get_codec("filepath")
442+
assert filepath_codec.name == "filepath"
443+
# Filepath requires @store, so only test is_store=True
444+
assert filepath_codec.get_dtype(is_store=True) == "json"
445+
446+
def test_filepath_rejects_hash_section(self):
447+
"""Test that filepath rejects paths starting with _hash/."""
448+
from unittest.mock import MagicMock, patch
449+
450+
filepath_codec = get_codec("filepath")
451+
452+
# Mock the backend to avoid actual file operations
453+
with patch("datajoint.hash_registry.get_store_backend") as mock_get_backend:
454+
mock_backend = MagicMock()
455+
mock_backend.exists.return_value = True
456+
mock_get_backend.return_value = mock_backend
457+
458+
# Test various forms of _hash/ paths
459+
invalid_paths = [
460+
"_hash/abc123",
461+
"_hash/schema/file.dat",
462+
"/_hash/nested/path.bin",
463+
]
464+
465+
for path in invalid_paths:
466+
with pytest.raises(
467+
ValueError,
468+
match=r"<filepath@> cannot use reserved sections '_hash/' or '_schema/'",
469+
):
470+
filepath_codec.encode(path, store_name="test_store")
471+
472+
def test_filepath_rejects_schema_section(self):
473+
"""Test that filepath rejects paths starting with _schema/."""
474+
from unittest.mock import MagicMock, patch
475+
476+
filepath_codec = get_codec("filepath")
477+
478+
# Mock the backend to avoid actual file operations
479+
with patch("datajoint.hash_registry.get_store_backend") as mock_get_backend:
480+
mock_backend = MagicMock()
481+
mock_backend.exists.return_value = True
482+
mock_get_backend.return_value = mock_backend
483+
484+
# Test various forms of _schema/ paths
485+
invalid_paths = [
486+
"_schema/mytable",
487+
"_schema/myschema/mytable/key.dat",
488+
"/_schema/nested/data.zarr",
489+
]
490+
491+
for path in invalid_paths:
492+
with pytest.raises(
493+
ValueError,
494+
match=r"<filepath@> cannot use reserved sections '_hash/' or '_schema/'",
495+
):
496+
filepath_codec.encode(path, store_name="test_store")
497+
498+
def test_filepath_allows_user_paths(self):
499+
"""Test that filepath allows any paths outside reserved sections."""
500+
from unittest.mock import MagicMock, patch
501+
502+
filepath_codec = get_codec("filepath")
503+
504+
# Mock the backend to avoid actual file operations
505+
with patch("datajoint.hash_registry.get_store_backend") as mock_get_backend:
506+
mock_backend = MagicMock()
507+
mock_backend.exists.return_value = True
508+
mock_backend.size.return_value = 1024
509+
mock_get_backend.return_value = mock_backend
510+
511+
# Test valid user-managed paths
512+
valid_paths = [
513+
"subject01/session001/data.bin",
514+
"raw/experiment_2024/recording.nwb",
515+
"processed/analysis_v2/results.csv",
516+
"my_hash_file.dat", # "hash" in name is fine
517+
"my_schema_backup.sql", # "schema" in name is fine
518+
]
519+
520+
for path in valid_paths:
521+
result = filepath_codec.encode(path, store_name="test_store")
522+
assert isinstance(result, dict)
523+
assert result["path"] == path
524+
assert result["store"] == "test_store"
525+
assert result["size"] == 1024
526+
assert result["is_dir"] is False
527+
assert "timestamp" in result
528+
529+
def test_filepath_in_list_codecs(self):
530+
"""Test that filepath appears in list_codecs."""
531+
codecs = list_codecs()
532+
assert "filepath" in codecs

0 commit comments

Comments
 (0)