Skip to content

Commit b4a2816

Browse files
authored
Merge pull request #18 from nathanjmcdougall/feature/unit-tests-storage
Add unit tests for storage
2 parents f41916b + 5842824 commit b4a2816

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

labtech/storage.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ def __init__(self, storage_dir: Union[str, Path], *, with_gitignore: bool = True
5252
gitignore_file.write('*\n')
5353

5454
def _key_path(self, key: str) -> Path:
55+
if not key:
56+
raise StorageError("Key cannot be empty")
57+
58+
disallowed_key_chars = ['.', '/', '\\', os.path.sep, os.path.altsep]
59+
for char in disallowed_key_chars:
60+
if char is not None and char in key: # altsep can be None
61+
raise StorageError(f"Key '{key}' must not contain the forbidden character '{char}'")
62+
5563
key_path = (self._storage_path / key).resolve()
5664
if key_path.parent != self._storage_path:
5765
raise StorageError((f"Key '{key}' should only reference a directory directly "

tests/labtech/test_storage.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import os
2+
from pathlib import Path
3+
4+
import pytest
5+
6+
from labtech.exceptions import StorageError
7+
from labtech.storage import LocalStorage
8+
9+
10+
@pytest.fixture()
11+
def local_storage(tmp_path: Path) -> LocalStorage:
12+
return LocalStorage(tmp_path)
13+
14+
class TestLocalStorage:
15+
class TestDunderInit:
16+
def test_str(self, tmp_path: Path):
17+
tmp_path_str = tmp_path.as_posix()
18+
19+
storage = LocalStorage(tmp_path_str)
20+
assert isinstance(storage._storage_path, Path)
21+
assert storage._storage_path.exists()
22+
assert storage._storage_path == tmp_path
23+
24+
def test_path(self, tmp_path: Path):
25+
storage = LocalStorage(tmp_path)
26+
assert isinstance(storage._storage_path, Path)
27+
assert storage._storage_path.exists()
28+
assert storage._storage_path == tmp_path
29+
30+
class TestFindKeys:
31+
def test_empty(self, local_storage: LocalStorage):
32+
assert local_storage.find_keys() == []
33+
34+
def test_single_key(self, local_storage: LocalStorage):
35+
key = 'key'
36+
(local_storage._storage_path / key).mkdir(exist_ok=True)
37+
assert local_storage.find_keys() == [key]
38+
39+
def test_multiple_keys_sorted(self, local_storage: LocalStorage):
40+
keys = ['b', 'a', 'c']
41+
for key in keys:
42+
(local_storage._storage_path / key).mkdir(exist_ok=True)
43+
assert local_storage.find_keys() == sorted(keys)
44+
45+
class TestExists:
46+
def test_missing_key(self, local_storage: LocalStorage):
47+
assert not local_storage.exists('fake')
48+
49+
def test_existing_key(self, local_storage: LocalStorage):
50+
key = 'key'
51+
(local_storage._storage_path / key).touch()
52+
assert local_storage.exists(key)
53+
54+
def test_empty_key_raises(self, local_storage: LocalStorage):
55+
with pytest.raises(StorageError):
56+
local_storage.exists("")
57+
58+
def test_nested_key_raises(self, local_storage: LocalStorage):
59+
with pytest.raises(StorageError):
60+
local_storage.exists("nested/key")
61+
62+
def test_key_with_slash_raises(self, local_storage: LocalStorage):
63+
with pytest.raises(StorageError):
64+
local_storage.exists("key/")
65+
66+
with pytest.raises(StorageError):
67+
local_storage.exists("key" + os.path.sep)
68+
69+
with pytest.raises(StorageError):
70+
local_storage.exists("/key")
71+
72+
with pytest.raises(StorageError):
73+
local_storage.exists(os.path.sep + "key")
74+
75+
def test_backslash(self, local_storage: LocalStorage):
76+
with pytest.raises(StorageError):
77+
local_storage.exists("key\\with\\backslashes")
78+
79+
def test_dot(self, local_storage: LocalStorage):
80+
with pytest.raises(StorageError):
81+
local_storage.exists("key.with.dots")
82+
83+
def test_forwardslash(self, local_storage: LocalStorage):
84+
with pytest.raises(StorageError):
85+
local_storage.exists("key/with/forwardslashes")
86+
87+
def test_relative_path_trickery(self, local_storage: LocalStorage):
88+
key = "other_key"
89+
(local_storage._storage_path / key).touch()
90+
with pytest.raises(StorageError):
91+
local_storage.exists("key/../other_key")

0 commit comments

Comments
 (0)