Skip to content

Testing

anycfg.testing: the contract suite every built-in format passes, shipped so a third-party format can run it too. Needs pytest. See Testing a format.

anycfg.testing.FormatContract

Behaviour every Format must have.

Attributes to set

format: The Format subclass under test. samples: Values dumps accepts; each must survive loads(dumps(x)) == x. Used only when the format can write. document: A small valid document, as text. malformed: An invalid document holding the marker {secret}, which is replaced by :data:SECRET before parsing.

document = '' class-attribute

format class-attribute

malformed = '' class-attribute

samples = () class-attribute

test_arbitrary_text_parses_or_raises_parse_error()

Source code in src/anycfg/testing.py
106
107
108
109
110
111
112
    def test_arbitrary_text_parses_or_raises_parse_error(self) -> None:
        fmt = self._instance()
        for text in ("", " ", "\n", "{", "[", "}", "=", ":", "#", "\x00", "a" * 3, "
"):
            try:
                fmt.loads(text)
            except ParseError:

test_ignores_a_byte_order_mark()

Source code in src/anycfg/testing.py
60
61
62
63
64
65
66
67
def test_ignores_a_byte_order_mark(self) -> None:
    if self.format.binary:
        return
    import anycfg

    plain = anycfg.loads(self.document, format=self.format)
    marked = anycfg.loads(("" + self.document).encode("utf-8"), format=self.format)
    assert marked == plain

test_is_a_format()

Source code in src/anycfg/testing.py
51
52
53
54
55
def test_is_a_format(self) -> None:
    assert isinstance(self.format, type) and issubclass(self.format, Format)
    assert self.format.name and self.format.name == self.format.name.lower()
    for suffix in self.format.suffixes:
        assert suffix.startswith(".") and suffix == suffix.lower()

test_loads_text()

Source code in src/anycfg/testing.py
57
58
def test_loads_text(self) -> None:
    self._instance().loads(self.document)

test_malformed_raises_parse_error_without_content(caplog)

Source code in src/anycfg/testing.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def test_malformed_raises_parse_error_without_content(self, caplog) -> None:
    import pytest
    import anycfg

    if not self.malformed:
        pytest.skip("no malformed document given")
    text = self.malformed.replace("{secret}", SECRET)
    caplog.set_level(logging.DEBUG)
    with pytest.raises(ParseError) as caught:
        anycfg.loads(text, format=self.format)
    error = caught.value
    seen = [str(error), repr(error), repr(error.args), repr(vars(error))]
    cause = error.__cause__ or error.__context__
    while cause is not None:
        seen.append(repr(cause))
        cause = cause.__cause__ or cause.__context__
    seen.extend(record.getMessage() for record in caplog.records)
    assert not [text for text in seen if SECRET in text]
    # Not even kept as __context__: the parser's error may hold the text.
    assert error.__cause__ is None and error.__context__ is None

test_refuses_an_unknown_option()

Source code in src/anycfg/testing.py
69
70
71
72
73
74
75
76
def test_refuses_an_unknown_option(self) -> None:
    import pytest
    import anycfg

    with pytest.raises(TypeError):
        anycfg.loads(
            self.document, format=self.format, no_such_option_anywhere=True
        )

test_round_trip()

Source code in src/anycfg/testing.py
78
79
80
81
82
83
def test_round_trip(self) -> None:
    if "dump" not in capabilities(self.format):
        return
    fmt = self._instance()
    for sample in self.samples:
        assert fmt.loads(fmt.dumps(sample)) == sample

test_unrepresentable_value_raises_before_writing()

Source code in src/anycfg/testing.py
114
115
116
117
118
119
def test_unrepresentable_value_raises_before_writing(self) -> None:
    import pytest

    if "dump" not in capabilities(self.format):
        return
    with pytest.raises((ConfigTypeError, ConfigValueError)):

anycfg.testing.SECRET = 'hunter2-anycfg-secret' module-attribute