Coverage for tests/test_running.py: 100.00%
58 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-17 17:18 +0200
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-17 17:18 +0200
1"""Tests about running duties."""
3from __future__ import annotations
5from typing import NoReturn
6from unittest.mock import NonCallableMock
8import pytest
10from duty.collection import Collection, Duty
11from duty.decorator import duty as decorate
12from duty.exceptions import DutyFailure
14INTERRUPT_CODE = 130
17def test_run_duty() -> None:
18 """Run a duty."""
19 duty = Duty("name", "description", lambda ctx: 1)
20 assert duty.run() is None # type: ignore[func-returns-value]
21 assert duty(duty.context) is None # type: ignore[func-returns-value]
24def test_run_pre_post_duties_lambdas() -> None:
25 """Run pre- and post- duties as lambdas."""
26 pre_calls = []
27 post_calls = []
29 duty = Duty(
30 "name",
31 "description",
32 lambda ctx: None,
33 pre=[lambda ctx: pre_calls.append(True)],
34 post=[lambda ctx: post_calls.append(True)],
35 )
37 duty.run()
39 assert pre_calls[0] is True
40 assert post_calls[0] is True
43def test_run_pre_post_duties_instances() -> None:
44 """Run pre- and post- duties as duties."""
45 pre_calls = []
46 post_calls = []
48 pre_duty = Duty("pre", "", lambda ctx: pre_calls.append(True))
49 post_duty = Duty("post", "", lambda ctx: post_calls.append(True))
51 duty = Duty(
52 name="name",
53 description="description",
54 function=lambda ctx: None,
55 pre=[pre_duty],
56 post=[post_duty],
57 )
59 duty.run()
61 assert pre_calls[0] is True
62 assert post_calls[0] is True
65def test_run_pre_post_duties_refs() -> None:
66 """Run pre- and post- duties as duties references."""
67 pre_calls = []
68 post_calls = []
70 collection = Collection()
71 collection.add(decorate(lambda ctx: pre_calls.append(True), name="pre")) # type: ignore[call-overload]
72 collection.add(decorate(lambda ctx: post_calls.append(True), name="post")) # type: ignore[call-overload]
74 duty = Duty("name", "description", lambda ctx: None, collection=collection, pre=["pre"], post=["post"])
75 duty.run()
77 assert pre_calls[0] is True
78 assert post_calls[0] is True
81def test_dont_run_other_pre_post_duties() -> None:
82 """Don't run other types of pre- and post- duties."""
83 pre_duty = NonCallableMock()
84 post_duty = NonCallableMock()
86 duty = Duty("name", "description", lambda ctx: 0, pre=[pre_duty], post=[post_duty])
87 duty.run()
89 assert not pre_duty.called
90 assert not post_duty.called
93def test_code_when_keyboard_interrupt() -> None:
94 """Return a code 130 on keyboard interruption."""
96 def interrupt() -> NoReturn:
97 raise KeyboardInterrupt
99 with pytest.raises(DutyFailure) as excinfo:
100 Duty("name", "description", lambda ctx: ctx.run(interrupt)).run()
101 assert excinfo.value.code == INTERRUPT_CODE
104def test_dont_raise_duty_failure() -> None:
105 """Don't raise a duty failure on success."""
106 duty = Duty("n", "d", lambda ctx: ctx.run(lambda: 0))
107 assert not duty.run() # type: ignore[func-returns-value]
110def test_cant_find_duty_without_collection() -> None:
111 """Check that we can't find a duty with its name without a collection."""
112 duty = decorate(lambda ctx: None, name="duty1", post=["duty2"]) # type: ignore[call-overload]
113 with pytest.raises(RuntimeError):
114 duty.run()