|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import logging |
| 4 | +from contextlib import nullcontext |
| 5 | +from dataclasses import dataclass, field |
| 6 | +from typing import Any, Optional, Type |
| 7 | + |
| 8 | +import pytest |
| 9 | + |
| 10 | +import instamatic._collections as ic |
| 11 | +from tests.utils import InstanceAutoTracker |
| 12 | + |
| 13 | + |
| 14 | +def test_no_overwrite_dict() -> None: |
| 15 | + """Should work as normal dict unless key exists, in which case raises.""" |
| 16 | + nod = ic.NoOverwriteDict({1: 2}) |
| 17 | + nod.update({3: 4}) |
| 18 | + nod[5] = 6 |
| 19 | + del nod[1] |
| 20 | + nod[1] = 6 |
| 21 | + assert nod == {1: 6, 3: 4, 5: 6} |
| 22 | + with pytest.raises(KeyError): |
| 23 | + nod[1] = 2 |
| 24 | + with pytest.raises(KeyError): |
| 25 | + nod.update({3: 4}) |
| 26 | + |
| 27 | + |
| 28 | +def test_null_logger(caplog) -> None: |
| 29 | + """NullLogger should void and not propagate messages to root logger.""" |
| 30 | + |
| 31 | + messages = [] |
| 32 | + handler = logging.StreamHandler() |
| 33 | + handler.emit = lambda record: messages.append(record.getMessage()) |
| 34 | + null_logger = ic.NullLogger() |
| 35 | + root_logger = logging.getLogger() |
| 36 | + root_logger.addHandler(handler) |
| 37 | + |
| 38 | + with caplog.at_level(logging.DEBUG): |
| 39 | + null_logger.debug('debug message that should be ignored') |
| 40 | + null_logger.info('info message that should be ignored') |
| 41 | + null_logger.warning('warning message that should be ignored') |
| 42 | + null_logger.error('error message that should be ignored') |
| 43 | + null_logger.critical('critical message that should be ignored') |
| 44 | + |
| 45 | + # Nothing should have been captured by pytest's caplog |
| 46 | + root_logger.removeHandler(handler) |
| 47 | + assert caplog.records == [] |
| 48 | + assert caplog.text == '' |
| 49 | + assert messages == [] |
| 50 | + |
| 51 | + |
| 52 | +@dataclass |
| 53 | +class PartialFormatterTestCase(InstanceAutoTracker): |
| 54 | + template: str = '{s} & {f:06.2f}' |
| 55 | + args: list[Any] = field(default_factory=list) |
| 56 | + kwargs: dict[str, Any] = field(default_factory=dict) |
| 57 | + returns: str = '' |
| 58 | + raises: Optional[Type[Exception]] = None |
| 59 | + |
| 60 | + |
| 61 | +PartialFormatterTestCase(returns='{s} & {f:06.2f}') |
| 62 | +PartialFormatterTestCase(kwargs={'s': 'Text'}, returns='Text & {f:06.2f}') |
| 63 | +PartialFormatterTestCase(kwargs={'f': 3.1415}, returns='{s} & 003.14') |
| 64 | +PartialFormatterTestCase(kwargs={'x': 'test'}, returns='{s} & {f:06.2f}') |
| 65 | +PartialFormatterTestCase(kwargs={'f': 'Text'}, raises=ValueError) |
| 66 | +PartialFormatterTestCase(template='{0}{1}', args=[5], returns='5{1}') |
| 67 | +PartialFormatterTestCase(template='{0}{1}', args=[5, 6], returns='56') |
| 68 | +PartialFormatterTestCase(template='{0}{1}', args=[5, 6, 7], returns='56') |
| 69 | + |
| 70 | + |
| 71 | +@pytest.mark.parametrize('test_case', PartialFormatterTestCase.INSTANCES) |
| 72 | +def test_partial_formatter(test_case) -> None: |
| 73 | + """Should replace only some {words}, but still fail if format is wrong.""" |
| 74 | + c = test_case |
| 75 | + with pytest.raises(r) if (r := c.raises) else nullcontext(): |
| 76 | + assert ic.partial_formatter.format(c.template, *c.args, **c.kwargs) == c.returns |
0 commit comments