tests: test commands

This commit is contained in:
cătălin 2023-04-03 18:40:11 +02:00
commit 570c29d9f1
Signed by: catalin
GPG key ID: 686088EF78EE4083
16 changed files with 235 additions and 52 deletions

1
.gitignore vendored
View file

@ -215,3 +215,4 @@ report.xml
.pdm-python .pdm-python
reportlog.json reportlog.json
.ruff_cache/ .ruff_cache/
.pdm.toml

View file

@ -12,5 +12,13 @@ tests:
dist: dist:
pdm build pdm build
publish-pypi:
pdm publish -u $(PYPI_REGISTRY_USERNAME) -P $(PYPI_REGISTRY_PASSWORD)
publish-roboces:
pdm publish --build -u $(ROBOCES_REGISTRY_USERNAME) -p $(ROBOCES_REGISTRY_PASSWORD) -r roboces
publish: publish:
pdm publish -u $(ROBOCES_REGISTRY_USERNAME) -P $(ROBOCES_REGISTRY_PASSWORD) -r https://git.roboces.dev/api/packages/catalin/pypi make publish-pypi
make publish-roboces

View file

@ -2,12 +2,10 @@
[(r)age](https://github.com/woodruffw/pyrage) encrypted note-taking CLI app [(r)age](https://github.com/woodruffw/pyrage) encrypted note-taking CLI app
## install and init ## install
You can use plain `pip` but I'd recommend `pipx`
```shell ```shell
pipx install halig pip install halig
``` ```
## cli mode ## cli mode
@ -16,8 +14,4 @@ pipx install halig
$ halig edit some_notebook # edit today's note $ halig edit some_notebook # edit today's note
$ halig edit some_notebook/foo # edit /path/to/some_notebook/foo.age $ halig edit some_notebook/foo # edit /path/to/some_notebook/foo.age
$ halig notebooks # list current notebooks $ halig notebooks # list current notebooks
``` ```
## tui mode
wip

View file

View file

@ -1,23 +1,14 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
import pendulum
from pendulum.datetime import DateTime
from pendulum.tz import local_timezone
from halig.settings import Settings from halig.settings import Settings
class ICommand(ABC): class ICommand(ABC):
@abstractmethod @abstractmethod
def run(self): def run(self):
... ... # pragma: no cover
class BaseCommand(ICommand): class BaseCommand(ICommand):
@property
def today(self) -> DateTime:
tz = local_timezone()
return pendulum.now(tz)
def __init__(self, settings: Settings, *args, **kwargs): def __init__(self, settings: Settings, *args, **kwargs):
self.settings = settings self.settings = settings

View file

@ -3,6 +3,7 @@ import subprocess
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from halig import utils
from halig.commands.base import BaseCommand from halig.commands.base import BaseCommand
from halig.encryption import Encryptor from halig.encryption import Encryptor
from halig.settings import Settings from halig.settings import Settings
@ -30,7 +31,7 @@ class EditCommand(BaseCommand):
self.encryptor = Encryptor(self.settings) self.encryptor = Encryptor(self.settings)
if self.note_path.is_dir(): if self.note_path.is_dir():
self.note_path /= f"{self.today.date()}.age" self.note_path /= f"{utils.now().date()}.age"
if not self.note_path.name.endswith(".age"): if not self.note_path.name.endswith(".age"):
err = f"File {self.note_path.name} is not a valid AGE file" err = f"File {self.note_path.name} is not a valid AGE file"
@ -43,7 +44,7 @@ class EditCommand(BaseCommand):
def edit_contents(self, original_contents: bytes) -> bytes: def edit_contents(self, original_contents: bytes) -> bytes:
"""Let the user edit the contents by opening an in-memory tempfile """Let the user edit the contents by opening an in-memory tempfile
using $EDITOR and encrypting the new contents using $EDITOR and encrypt the new contents
Args: Args:
original_contents (bytes): original data that will be dumped into the original_contents (bytes): original data that will be dumped into the

View file

@ -28,4 +28,4 @@ class NotebooksCommand(BaseCommand):
return tree return tree
def run(self): def run(self):
print(self.build_tree(self.settings.notebooks_root_path)) print(self.build_tree(self.settings.notebooks_root_path)) # pragma: no cover

View file

@ -3,6 +3,7 @@ from pathlib import Path
from rich.console import Console from rich.console import Console
from rich.markdown import Markdown from rich.markdown import Markdown
from halig import utils
from halig.commands.base import BaseCommand from halig.commands.base import BaseCommand
from halig.encryption import Encryptor from halig.encryption import Encryptor
from halig.settings import Settings from halig.settings import Settings
@ -16,7 +17,7 @@ class ShowCommand(BaseCommand):
self.encryptor = Encryptor(self.settings) self.encryptor = Encryptor(self.settings)
self.console = Console() self.console = Console()
if self.note_path.is_dir(): if self.note_path.is_dir():
self.note_path /= f"{self.today.date()}.age" self.note_path /= f"{utils.now().date()}.age"
if not self.note_path.exists(): if not self.note_path.exists():
err = f"File {self.note_path.name} does not exist" err = f"File {self.note_path.name} does not exist"
@ -26,9 +27,11 @@ class ShowCommand(BaseCommand):
err = f"File {self.note_path.name} is not a valid AGE file" err = f"File {self.note_path.name} is not a valid AGE file"
raise ValueError(err) raise ValueError(err)
def run(self): def decrypt(self) -> str:
with self.note_path.open("rb") as f: with self.note_path.open("rb") as f:
data = f.read() data = f.read()
contents = self.encryptor.decrypt(data) return self.encryptor.decrypt(data).decode()
md_contents = Markdown(contents.decode())
def run(self): # pragma: no cover
md_contents = Markdown(self.decrypt())
self.console.print(md_contents) self.console.print(md_contents)

7
halig/utils.py Normal file
View file

@ -0,0 +1,7 @@
import pendulum
from pendulum.tz import local_timezone
def now():
tz = local_timezone()
return pendulum.now(tz)

49
pdm.lock generated
View file

@ -85,6 +85,12 @@ version = "0.1.2"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "Markdown URL utilities" summary = "Markdown URL utilities"
[[package]]
name = "mock"
version = "5.0.1"
requires_python = ">=3.6"
summary = "Rolling backport of unittest.mock for all Pythons"
[[package]] [[package]]
name = "mypy" name = "mypy"
version = "1.1.1" version = "1.1.1"
@ -166,7 +172,7 @@ dependencies = [
[[package]] [[package]]
name = "pyfakefs" name = "pyfakefs"
version = "5.1.0" version = "5.2.0"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "pyfakefs implements a fake file system that mocks the Python file system modules." summary = "pyfakefs implements a fake file system that mocks the Python file system modules."
@ -182,15 +188,6 @@ version = "1.0.3"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "Python bindings for rage (age in Rust)" summary = "Python bindings for rage (age in Rust)"
[[package]]
name = "pyrage-stubs"
version = "1.0.1"
requires_python = ">= 3.7"
summary = "A PEP 561 stub package for pyrage's types"
dependencies = [
"pyrage<2.0,>=1.0.0",
]
[[package]] [[package]]
name = "pyright" name = "pyright"
version = "1.1.301" version = "1.1.301"
@ -247,6 +244,15 @@ dependencies = [
"typer>=0.3.2", "typer>=0.3.2",
] ]
[[package]]
name = "pytest-mock"
version = "3.10.0"
requires_python = ">=3.7"
summary = "Thin-wrapper around the mock package for easier use with pytest"
dependencies = [
"pytest>=5.0",
]
[[package]] [[package]]
name = "pytest-pretty" name = "pytest-pretty"
version = "1.1.1" version = "1.1.1"
@ -342,9 +348,8 @@ requires_python = ">=3.7"
summary = "Backported and Experimental Type Hints for Python 3.7+" summary = "Backported and Experimental Type Hints for Python 3.7+"
[metadata] [metadata]
lock_version = "4.2" lock_version = "4.1"
groups = ["default", "linters", "linting", "testing"] content_hash = "sha256:3f09b4f252ecdcbfd074ccc8da97ac8700aef25a5ae1a37c7eae9b53b0d17008"
content_hash = "sha256:bd20ae8c3a5d73b6301022d3e5fd8844e31baf827ff41860ca8afd55d5b3ffe9"
[metadata.files] [metadata.files]
"attrs 22.2.0" = [ "attrs 22.2.0" = [
@ -459,6 +464,10 @@ content_hash = "sha256:bd20ae8c3a5d73b6301022d3e5fd8844e31baf827ff41860ca8afd55d
{url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, {url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
] ]
"mock 5.0.1" = [
{url = "https://files.pythonhosted.org/packages/a9/c8/7f5fc5ee6a666d7e4ee7a3222bcb37ebebaea3697d7bf54517728f56bb28/mock-5.0.1.tar.gz", hash = "sha256:e3ea505c03babf7977fd21674a69ad328053d414f05e6433c30d8fa14a534a6b"},
{url = "https://files.pythonhosted.org/packages/e6/88/8a05e7ad0bb823246b2add3d2e97f990c41c71a40762c8db77a4bd78eedf/mock-5.0.1-py3-none-any.whl", hash = "sha256:c41cfb1e99ba5d341fbcc5308836e7d7c9786d302f995b2c271ce2144dece9eb"},
]
"mypy 1.1.1" = [ "mypy 1.1.1" = [
{url = "https://files.pythonhosted.org/packages/2a/28/8485aad67750b3374443d28bad3eed947737cf425a640ea4be4ac70a7827/mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"}, {url = "https://files.pythonhosted.org/packages/2a/28/8485aad67750b3374443d28bad3eed947737cf425a640ea4be4ac70a7827/mypy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce61663faf7a8e5ec6f456857bfbcec2901fbdb3ad958b778403f63b9e606a1b"},
{url = "https://files.pythonhosted.org/packages/30/da/808ceaf2bcf23a9e90156c7b11b41add8dd5a009ee48159ec820d04d97bd/mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"}, {url = "https://files.pythonhosted.org/packages/30/da/808ceaf2bcf23a9e90156c7b11b41add8dd5a009ee48159ec820d04d97bd/mypy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9401e33814cec6aec8c03a9548e9385e0e228fc1b8b0a37b9ea21038e64cdd8a"},
@ -579,9 +588,9 @@ content_hash = "sha256:bd20ae8c3a5d73b6301022d3e5fd8844e31baf827ff41860ca8afd55d
{url = "https://files.pythonhosted.org/packages/fa/c2/3df79cd00e65678fce12e59e8c95378a992a93d7b9f9510d4f1f65df1936/pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"}, {url = "https://files.pythonhosted.org/packages/fa/c2/3df79cd00e65678fce12e59e8c95378a992a93d7b9f9510d4f1f65df1936/pydantic-1.10.7-cp311-cp311-win_amd64.whl", hash = "sha256:b4a849d10f211389502059c33332e91327bc154acc1845f375a99eca3afa802d"},
{url = "https://files.pythonhosted.org/packages/fd/66/3da2e7c0306251435bd61ae9da52db8a00672fdf2b2db1e3efe1692f41dd/pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"}, {url = "https://files.pythonhosted.org/packages/fd/66/3da2e7c0306251435bd61ae9da52db8a00672fdf2b2db1e3efe1692f41dd/pydantic-1.10.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:950ce33857841f9a337ce07ddf46bc84e1c4946d2a3bba18f8280297157a3fd1"},
] ]
"pyfakefs 5.1.0" = [ "pyfakefs 5.2.0" = [
{url = "https://files.pythonhosted.org/packages/38/4b/0e12c26797eeb1ea4574f3b94937817ee781a13d3fb800c2dc4c115a56f3/pyfakefs-5.1.0.tar.gz", hash = "sha256:316c6026640d14a6b4fbde71fd9674576d1b5710deda8fabde8aad51d785dbc3"}, {url = "https://files.pythonhosted.org/packages/41/63/c06696cd4e6305f83fdb6ea275771ae04a9fd97afbec41b2bdaa3c7c7945/pyfakefs-5.2.0-py3-none-any.whl", hash = "sha256:cf465f90c9657018e381668b6fae38e034417d937ef596968ff8b2550ad158d7"},
{url = "https://files.pythonhosted.org/packages/a4/db/1b738a4d422eee1bb9688c2ea01d9b4bcc02e4e98ad71e13f5db3ff3cd5a/pyfakefs-5.1.0-py3-none-any.whl", hash = "sha256:e6f34a8224b41f1b1ab25aa8d430121dac42e3c6e981e01eae76b3343fba47d0"}, {url = "https://files.pythonhosted.org/packages/9e/99/92012cd1dd8c41171efee7086610ddc7997b6ed11e1be80105b8d9ca5e9a/pyfakefs-5.2.0.tar.gz", hash = "sha256:db570ae847f0abd44b5b67ab379f0b111e6bdcd35486eeece0ea2439c9e30766"},
] ]
"pygments 2.14.0" = [ "pygments 2.14.0" = [
{url = "https://files.pythonhosted.org/packages/0b/42/d9d95cc461f098f204cd20c85642ae40fbff81f74c300341b8d0e0df14e0/Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, {url = "https://files.pythonhosted.org/packages/0b/42/d9d95cc461f098f204cd20c85642ae40fbff81f74c300341b8d0e0df14e0/Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"},
@ -592,10 +601,6 @@ content_hash = "sha256:bd20ae8c3a5d73b6301022d3e5fd8844e31baf827ff41860ca8afd55d
{url = "https://files.pythonhosted.org/packages/d9/a4/785af8296a882132b63de046c54d9a45c8d1d634e22c5d40463accd8eefd/pyrage-1.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c554d7669539c0a7a870464faf55f0121c117339b1b0f57d6ca5eb85079c107"}, {url = "https://files.pythonhosted.org/packages/d9/a4/785af8296a882132b63de046c54d9a45c8d1d634e22c5d40463accd8eefd/pyrage-1.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c554d7669539c0a7a870464faf55f0121c117339b1b0f57d6ca5eb85079c107"},
{url = "https://files.pythonhosted.org/packages/fb/9c/54a5c8aad8442ba26845c325c8b4eaa90cc3b470d0e57465d82ca54ad843/pyrage-1.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:32b63a06f138a1c231285c61f61a1800b7b894851b06cb763b7b35b18ccd2b11"}, {url = "https://files.pythonhosted.org/packages/fb/9c/54a5c8aad8442ba26845c325c8b4eaa90cc3b470d0e57465d82ca54ad843/pyrage-1.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:32b63a06f138a1c231285c61f61a1800b7b894851b06cb763b7b35b18ccd2b11"},
] ]
"pyrage-stubs 1.0.1" = [
{url = "https://files.pythonhosted.org/packages/00/5c/5e0430c00a0094d7e86b3487839de6b4213cf34f46faf27cc98acac54084/pyrage_stubs-1.0.1-py3-none-any.whl", hash = "sha256:729d9c8ac43f9aac9e22fe6ae3cf285a4f0740bece7b793a57eb229fb6db93a7"},
{url = "https://files.pythonhosted.org/packages/6f/c3/352df4e5927d4f34fefdd0e9e0332061c3b98937e39b871c91f8e66098ea/pyrage-stubs-1.0.1.tar.gz", hash = "sha256:e33bc444bfda7b5a783d3821aa99ba9269d2a9f2c39ccd8aba46a7b8525fbd22"},
]
"pyright 1.1.301" = [ "pyright 1.1.301" = [
{url = "https://files.pythonhosted.org/packages/1f/f9/35360780b41236428be6a2a8f8f53007d5460e757d8bfe007b7303f63682/pyright-1.1.301.tar.gz", hash = "sha256:6ac4afc0004dca3a977a4a04a8ba25b5b5aa55f8289550697bfc20e11be0d5f2"}, {url = "https://files.pythonhosted.org/packages/1f/f9/35360780b41236428be6a2a8f8f53007d5460e757d8bfe007b7303f63682/pyright-1.1.301.tar.gz", hash = "sha256:6ac4afc0004dca3a977a4a04a8ba25b5b5aa55f8289550697bfc20e11be0d5f2"},
{url = "https://files.pythonhosted.org/packages/4c/af/7a7bd8513361934d269aca00bdea5f879d92e5b89f79e4923d1f1b06d498/pyright-1.1.301-py3-none-any.whl", hash = "sha256:ecc3752ba8c866a8041c90becf6be79bd52f4c51f98472e4776cae6d55e12826"}, {url = "https://files.pythonhosted.org/packages/4c/af/7a7bd8513361934d269aca00bdea5f879d92e5b89f79e4923d1f1b06d498/pyright-1.1.301-py3-none-any.whl", hash = "sha256:ecc3752ba8c866a8041c90becf6be79bd52f4c51f98472e4776cae6d55e12826"},
@ -615,6 +620,10 @@ content_hash = "sha256:bd20ae8c3a5d73b6301022d3e5fd8844e31baf827ff41860ca8afd55d
{url = "https://files.pythonhosted.org/packages/07/e1/5f71f28d1f77ade128b54c20cee04e34508f7480f599d418baf26547c64e/pytest_duration_insights-0.1.1-py2.py3-none-any.whl", hash = "sha256:27f771077f58b558a62fee0af396c1a2efc4aa1217aad9e0cf11d120b2067e86"}, {url = "https://files.pythonhosted.org/packages/07/e1/5f71f28d1f77ade128b54c20cee04e34508f7480f599d418baf26547c64e/pytest_duration_insights-0.1.1-py2.py3-none-any.whl", hash = "sha256:27f771077f58b558a62fee0af396c1a2efc4aa1217aad9e0cf11d120b2067e86"},
{url = "https://files.pythonhosted.org/packages/cf/09/b2129ad0ff70f0283d86e76497ddac9b53f0aa876fec8462dc3408d3721d/pytest-duration-insights-0.1.1.tar.gz", hash = "sha256:9dcc6aca40bfbdab2b0b34f0e55c3b5bd4ac41f3a419a2b7b8a22fb7ebe62933"}, {url = "https://files.pythonhosted.org/packages/cf/09/b2129ad0ff70f0283d86e76497ddac9b53f0aa876fec8462dc3408d3721d/pytest-duration-insights-0.1.1.tar.gz", hash = "sha256:9dcc6aca40bfbdab2b0b34f0e55c3b5bd4ac41f3a419a2b7b8a22fb7ebe62933"},
] ]
"pytest-mock 3.10.0" = [
{url = "https://files.pythonhosted.org/packages/91/84/c951790e199cd54ddbf1021965b62a5415b81193ebdb4f4af2659fd06a73/pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"},
{url = "https://files.pythonhosted.org/packages/f6/2b/137a7db414aeaf3d753d415a2bc3b90aba8c5f61dff7a7a736d84b2ec60d/pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"},
]
"pytest-pretty 1.1.1" = [ "pytest-pretty 1.1.1" = [
{url = "https://files.pythonhosted.org/packages/ba/8f/7cafa3856d81175264fcc8929d0c5c60e59b787b1b2891095b77a7aaebb7/pytest_pretty-1.1.1.tar.gz", hash = "sha256:dfabbeee334ff5e77f3f731623cd44f147b3db7001df8d9ef8ea1f54986b41e2"}, {url = "https://files.pythonhosted.org/packages/ba/8f/7cafa3856d81175264fcc8929d0c5c60e59b787b1b2891095b77a7aaebb7/pytest_pretty-1.1.1.tar.gz", hash = "sha256:dfabbeee334ff5e77f3f731623cd44f147b3db7001df8d9ef8ea1f54986b41e2"},
{url = "https://files.pythonhosted.org/packages/c5/98/859ccc1482b23c008e434da91880bb1197e29d9fe3644c3124b58e9b6bd9/pytest_pretty-1.1.1-py3-none-any.whl", hash = "sha256:22d19d319f2ce07d62ea64f487616d99433cae8530cd20813487bad8a7d5f088"}, {url = "https://files.pythonhosted.org/packages/c5/98/859ccc1482b23c008e434da91880bb1197e29d9fe3644c3124b58e9b6bd9/pytest_pretty-1.1.1-py3-none-any.whl", hash = "sha256:22d19d319f2ce07d62ea64f487616d99433cae8530cd20813487bad8a7d5f088"},

View file

@ -1,5 +1,6 @@
[tool.pdm.build] [tool.pdm.build]
includes = [] includes = []
[build-system] [build-system]
requires = ["pdm-backend"] requires = ["pdm-backend"]
build-backend = "pdm.backend" build-backend = "pdm.backend"
@ -19,9 +20,10 @@ dependencies = [
"pendulum>=2.1.2", "pendulum>=2.1.2",
] ]
name = "halig" name = "halig"
version = "0.1.1" version = "0.1.2"
description = "age-encrypted, file-based, note-taking CLI app" description = "age-encrypted, file-based, note-taking CLI app"
readme = "README.md" readme = "README.md"
[project.scripts] [project.scripts]
halig = "halig.main:app" halig = "halig.main:app"
@ -34,6 +36,8 @@ testing = [
"pytest-reportlog>=0.2.1", "pytest-reportlog>=0.2.1",
"pytest-duration-insights>=0.1.1", "pytest-duration-insights>=0.1.1",
"pytest-pretty>=1.1.1", "pytest-pretty>=1.1.1",
"pytest-mock>=3.10.0",
"mock>=5.0.1",
] ]
linting = [ linting = [
"black>=23.3.0", "black>=23.3.0",
@ -41,11 +45,9 @@ linting = [
"pyright>=1.1.301", "pyright>=1.1.301",
"mypy>=1.1.1", "mypy>=1.1.1",
"types-PyYAML>=6.0.12.9", "types-PyYAML>=6.0.12.9",
"pyrage-stubs>=1.0.1",
]
linters = [
"pyrage-stubs>=1.0.1",
] ]
[tool.pytest]
mock_use_standalone_module = true
[tool.pyright] [tool.pyright]
reportMissingImports = false reportMissingImports = false
@ -63,5 +65,6 @@ warn_unused_configs = true
module = [ module = [
"pyrage", "pyrage",
"pyrage.ssh", "pyrage.ssh",
"pyrage.x25519",
] ]
ignore_missing_imports = true ignore_missing_imports = true

View file

@ -0,0 +1,63 @@
from pathlib import Path
import pendulum
import pytest as pytest
from halig import utils
from halig.commands.notebooks import NotebooksCommand
from halig.settings import Settings
@pytest.fixture()
def notes(notebooks_path: Path):
personal = (notebooks_path / "Personal")
work = (notebooks_path / "Work")
personal.mkdir()
work.mkdir()
personal_todos = (personal / "todos.age")
personal_todos.touch()
work_todos = (work / "todos.age")
work_todos.touch()
dailies = work / "Dailies"
dailies.mkdir()
dt = pendulum.now()
for day_offset in range(10):
dt = dt.subtract(days=day_offset)
(dailies / f"{dt.date()}.age").touch()
@pytest.fixture
def notebooks_command(settings: Settings):
return NotebooksCommand(max_depth=float("inf"), settings=settings)
@pytest.fixture()
def current_note(notes, settings, encryptor) -> Path:
note_path = settings.notebooks_root_path / f"{utils.now().date()}.age"
note_path.touch()
data = encryptor.encrypt("foo".encode())
with note_path.open("wb") as f:
f.write(data)
return note_path
@pytest.fixture
def current_daily(notes, settings, encryptor) -> Path:
note_path = settings.notebooks_root_path / "Work" / "Dailies" / f"{utils.now().date()}.age"
data = encryptor.encrypt("foo".encode())
with note_path.open("wb") as f:
f.write(data)
return note_path
@pytest.fixture
def mock_edit(mocker):
def edit(callargs: list):
with open(callargs[1], "wb") as f:
f.write("edited".encode())
mocker.patch('halig.commands.edit.subprocess.call', side_effect=edit)

View file

@ -0,0 +1,30 @@
import pytest
from halig.commands.edit import EditCommand
from halig.settings import Settings
def test_edit_raises_invalid_age_file(notes, settings: Settings):
note_path = settings.notebooks_root_path / "foo.txt"
note_path.touch()
with pytest.raises(ValueError, match="is not a valid AGE file"):
EditCommand(note_path, settings=settings, )
def test_edit_current_note(mock_edit, current_note, settings: Settings, encryptor):
edit_command = EditCommand(note_path=settings.notebooks_root_path, settings=settings)
assert edit_command.note_path == current_note
edit_command.run()
with current_note.open("rb") as f:
contents = encryptor.decrypt(f.read()).decode()
assert contents == "edited"
def test_edit_current_daily(mock_edit, current_daily, settings, encryptor):
current_daily.unlink()
edit_command = EditCommand(note_path=current_daily, settings=settings)
assert edit_command.note_path == current_daily
edit_command.run()
with current_daily.open("rb") as f:
contents = encryptor.decrypt(f.read()).decode()
assert contents == "edited"

View file

@ -0,0 +1,42 @@
from halig.commands.notebooks import NotebooksCommand
def test_build_tree_max_depth_0(notes, notebooks_command: NotebooksCommand):
notebooks_command.max_depth = 0
tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
assert not tree.children
def test_build_tree_max_depth_1(notes, notebooks_command: NotebooksCommand):
notebooks_command.max_depth = 1
tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
personal = tree.children[0]
work = tree.children[1]
assert personal.label == "Personal"
assert work.label == "Work"
assert not personal.children
assert not work.children
def test_build_tree_max_depth_2(notes, notebooks_command: NotebooksCommand):
notebooks_command.max_depth = 2
tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
personal = tree.children[0]
work = tree.children[1]
assert personal.label == "Personal"
assert work.label == "Work"
assert len(work.children) == 2
assert len(personal.children) == 1
def test_build_tree_max_depth_inf(notes, notebooks_command: NotebooksCommand):
tree = notebooks_command.build_tree(notebooks_command.settings.notebooks_root_path)
personal = tree.children[0]
work = tree.children[1]
assert personal.label == "Personal"
assert work.label == "Work"
assert len(work.children) == 2
assert len(personal.children) == 1
assert work.children[0].label == "Dailies"
assert len(work.children[0].children) == 10

View file

@ -0,0 +1,30 @@
from pathlib import Path
import pytest
from halig.commands.show import ShowCommand
from halig.settings import Settings
def test_show_raises_note_path_does_not_exist(notes, settings: Settings):
with pytest.raises(ValueError, match="does not exist"):
ShowCommand(Path('foo'), settings=settings, )
def test_show_raises_note_path_is_not_age_valid(notes, settings: Settings):
note_path = settings.notebooks_root_path / "foo.txt"
note_path.touch()
with pytest.raises(ValueError, match="is not a valid AGE file"):
ShowCommand(note_path, settings=settings, )
def test_show_current_note(current_note, settings):
show_command = ShowCommand(note_path=settings.notebooks_root_path, settings=settings)
assert show_command.note_path == current_note
assert show_command.decrypt() == "foo"
def test_show_current_daily(current_daily, settings: Settings):
show_command = ShowCommand(note_path=current_daily, settings=settings)
assert show_command.note_path == current_daily
assert show_command.decrypt() == "foo"

View file

@ -41,6 +41,7 @@ def ssh_recipient(halig_ssh_public_key: str) -> Recipient:
@pytest.fixture() @pytest.fixture()
def halig_path(fs, halig_ssh_public_key, halig_ssh_private_key) -> Path: def halig_path(fs, halig_ssh_public_key, halig_ssh_private_key) -> Path:
fs.add_real_paths(["/etc/localtime"])
ssh_path = Path("~/.ssh").expanduser() ssh_path = Path("~/.ssh").expanduser()
ssh_path.mkdir(parents=True) ssh_path.mkdir(parents=True)