Skip to content

Commit 2a91cb8

Browse files
authored
Update unittests (#67)
1 parent 77af14d commit 2a91cb8

File tree

10 files changed

+77
-15
lines changed

10 files changed

+77
-15
lines changed

.github/workflows/tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ jobs:
5454
run: |
5555
poetry run ty --version
5656
poetry run ty check .
57-
poetry run ty check tests/ || true
5857
5958
- name: Run unittests
6059
run: |

DEVELOP.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ poetry run pytest -sv tests
1414
make tests
1515
```
1616

17+
Lint the code and run type checking
18+
19+
```bash
20+
make lint
21+
make ty
22+
```
23+
1724
Install git hooks for the automatic linting and code formatting with [pre-commit](https://pre-commit.com/)
1825

1926
```bash

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/hapless)
66

77

8-
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
9-
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
8+
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
9+
[![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty)
1010
[![EditorConfig](https://img.shields.io/badge/-EditorConfig-grey?logo=editorconfig)](https://editorconfig.org/)
1111
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
1212

hapless/cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
22
from shlex import join as shlex_join
3-
from typing import Optional
3+
from typing import Optional, Tuple
44

55
import click
66

@@ -99,7 +99,7 @@ def errors(hap_alias: str, follow: bool):
9999
default=False,
100100
help="Include failed haps for the removal.",
101101
)
102-
def clean(clean_all):
102+
def clean(clean_all: bool):
103103
hapless.clean(clean_all=clean_all)
104104

105105

@@ -124,7 +124,7 @@ def cleanall():
124124
default=False,
125125
help="Verify command launched does not fail immediately.",
126126
)
127-
def run(cmd, name, check):
127+
def run(cmd: Tuple[str, ...], name: str, check: bool):
128128
hap = hapless.get_hap(name)
129129
if hap is not None:
130130
console.error(f"Hap with such name already exists: {hap}")

hapless/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from hapless.formatters import Formatter
1515
from hapless.hap import Hap, Status
1616
from hapless.ui import ConsoleUI
17-
from hapless.utils import kill_proc_tree, logger, wait_created
17+
from hapless.utils import get_exec_path, kill_proc_tree, logger, wait_created
1818

1919

2020
class Hapless:
@@ -223,7 +223,7 @@ def run_hap(
223223
self._check_fast_failure(hap)
224224

225225
def _run_via_spawn(self, hap: Hap) -> None:
226-
exec_path = Path(sys.argv[0])
226+
exec_path = get_exec_path()
227227
proc = subprocess.Popen(
228228
[f"{exec_path}", "__internal_wrap_hap", f"{hap.hid}"],
229229
start_new_session=True,

hapless/utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import logging
22
import os
3+
import shutil
34
import signal
45
import sys
56
import time
7+
from collections import deque
68
from contextlib import nullcontext
79
from functools import wraps
810
from pathlib import Path
@@ -122,6 +124,24 @@ def isatty() -> bool:
122124
return sys.stdin.isatty() and sys.stdout.isatty()
123125

124126

127+
def get_exec_path() -> Path:
128+
if str(sys.argv[0]).endswith("hap"):
129+
exec_path = sys.argv[0]
130+
else:
131+
logger.warning("Unusual invocation, checking `hap` in PATH")
132+
exec_path = shutil.which("hap")
133+
134+
if exec_path is None:
135+
raise RuntimeError("Cannot find `hap` executable, please reinstall hapless")
136+
137+
return Path(exec_path)
138+
139+
140+
def tail_lines(filepath: Path, n: int = 20):
141+
with open(filepath) as f:
142+
return deque(f, n)
143+
144+
125145
def configure_logger() -> logging.Logger:
126146
logger = structlog.get_logger()
127147
level = logging.DEBUG if config.DEBUG else logging.CRITICAL

pyproject.toml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,10 @@ structlog = "^25.4.0"
4242
# Optional dependencies installed as extras
4343
pytest = { version = "^7.4.4", optional = true }
4444
pytest-cov = { version = "^3.0.0", optional = true }
45-
ruff = { version = "^0.9.0", optional = true }
46-
nox = { version = "^2024.10.9", optional = true }
4745
pytest-env = { version = "^1.1.2", optional = true }
46+
ruff = { version = "^0.9.0", optional = true }
4847
ty = { version = "^0.0.1a21", optional = true }
49-
48+
nox = { version = "^2024.10.9", optional = true }
5049

5150
[tool.poetry.extras]
5251
dev = [
@@ -82,9 +81,7 @@ extend-select = [
8281
]
8382

8483
[tool.ty.src]
85-
exclude = [
86-
"tests/",
87-
]
84+
exclude = []
8885

8986
[tool.pytest.ini_options]
9087
env = [

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def runner() -> Generator[CliRunner, None, None]:
2626
with cli_runner.isolated_filesystem() as path:
2727
hapless_test = Hapless(hapless_dir=Path(path))
2828
with patch("hapless.cli.hapless", hapless_test) as hapless_mock:
29-
cli_runner.hapless = hapless_mock
29+
cli_runner.hapless = hapless_mock # ty: ignore[unresolved-attribute]
3030
yield cli_runner
3131

3232

tests/test_cli_utils.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from unittest.mock import Mock, PropertyMock, patch
2+
3+
import pytest
4+
5+
from hapless.cli_utils import get_or_exit
6+
7+
8+
@patch("hapless.cli_utils.hapless")
9+
def test_get_or_exit_non_existing(hapless_mock, capsys):
10+
with patch.object(hapless_mock, "get_hap", return_value=None) as get_hap_mock:
11+
with pytest.raises(SystemExit) as e:
12+
get_or_exit("hap-me")
13+
14+
assert e.value.code == 1
15+
get_hap_mock.assert_called_once_with("hap-me")
16+
17+
captured = capsys.readouterr()
18+
assert "No such hap: hap-me" in captured.out
19+
20+
21+
@patch("hapless.cli_utils.hapless")
22+
def test_get_or_exit_not_accessible(hapless_mock, capsys):
23+
hap_mock = Mock(owner="someone-else")
24+
prop_mock = PropertyMock(return_value=False)
25+
type(hap_mock).accessible = prop_mock
26+
with patch.object(hapless_mock, "get_hap", return_value=hap_mock) as get_hap_mock:
27+
with pytest.raises(SystemExit) as e:
28+
get_or_exit("hap-not-mine")
29+
30+
assert e.value.code == 1
31+
get_hap_mock.assert_called_once_with("hap-not-mine")
32+
prop_mock.assert_called_once_with()
33+
34+
captured = capsys.readouterr()
35+
assert (
36+
"Cannot manage hap launched by another user. Owner: someone-else"
37+
in captured.out
38+
)

tests/test_hap_workdir.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def blocking_run(*args, **kwargs):
4343
)
4444

4545
restarted_hap = hapless.get_hap("hap-same-name")
46+
assert restarted_hap is not None
4647
assert restarted_hap.rc == 0
4748
assert restarted_hap.stdout_path.exists()
4849
assert "Correct file is being run" in restarted_hap.stdout_path.read_text()

0 commit comments

Comments
 (0)