Add New Basic Tests

This commit is contained in:
David Sangrey committed 2026-01-25 16:03:13 -05:00
1 parent ccf7fbc164
commit 9b95ca5ca2
19 files changed
+1710 -147

No files matched your search

+91 -40
View File
@@ -1,4 +1,7 @@
# flake8: noqa
# mypy: ignore-errors
"""Test the apply functions used by killswitch to modify data."""
from __future__ import annotations
import copy
@@ -11,35 +14,37 @@ from killswitch import UPDATABLE_DATA
@pytest.mark.parametrize(
('source', 'key', 'action', 'to_set', 'result'),
("source", "key", "action", "to_set", "result"),
[
(['this', 'is', 'a', 'test'], '1', 'delete', None, ['this', 'a', 'test']),
(['this', 'is', 'a', 'test'], '1', '', None, ['this', None, 'a', 'test']),
({'now': 'with', 'a': 'dict'}, 'now', 'delete', None, {'a': 'dict'}),
({'now': 'with', 'a': 'dict'}, 'now', '', None, {'now': None, 'a': 'dict'}),
(['test append'], '1', '', 'yay', ['test append', 'yay']),
(['test neg del'], '-1', 'delete', None, []),
(['test neg del'], '-1337', 'delete', None, ['test neg del']),
(['test neg del'], '-2', 'delete', None, ['test neg del']),
(['test too high del'], '30', 'delete', None, ['test too high del']),
]
(["this", "is", "a", "test"], "1", "delete", None, ["this", "a", "test"]),
(["this", "is", "a", "test"], "1", "", None, ["this", None, "a", "test"]),
({"now": "with", "a": "dict"}, "now", "delete", None, {"a": "dict"}),
({"now": "with", "a": "dict"}, "now", "", None, {"now": None, "a": "dict"}),
(["test append"], "1", "", "yay", ["test append", "yay"]),
(["test neg del"], "-1", "delete", None, []),
(["test neg del"], "-1337", "delete", None, ["test neg del"]),
(["test neg del"], "-2", "delete", None, ["test neg del"]),
(["test too high del"], "30", "delete", None, ["test too high del"]),
],
)
def test_apply(source: UPDATABLE_DATA, key: str, action: str, to_set: Any, result: UPDATABLE_DATA) -> None:
def test_apply(
source: UPDATABLE_DATA, key: str, action: str, to_set: Any, result: UPDATABLE_DATA
) -> None:
"""Test that a single level apply works as expected."""
cpy = copy.deepcopy(source)
killswitch._apply(target=cpy, key=key, to_set=to_set, delete=action == 'delete')
killswitch._apply(target=cpy, key=key, to_set=to_set, delete=action == "delete")
assert cpy == result
def test_apply_errors() -> None:
"""_apply should fail when passed something that isn't a Sequence or MutableMapping."""
with pytest.raises(ValueError, match=r'Dont know how to'):
killswitch._apply(set(), '0') # type: ignore # Its intentional that its broken
killswitch._apply(None, '') # type: ignore # Its intentional that its broken
with pytest.raises(ValueError, match=r"Dont know how to"):
killswitch._apply(set(), "0") # type: ignore # Its intentional that its broken
killswitch._apply(None, "") # type: ignore # Its intentional that its broken
with pytest.raises(ValueError, match=r'Cannot use string'):
killswitch._apply([], 'test')
with pytest.raises(ValueError, match=r"Cannot use string"):
killswitch._apply([], "test")
def test_apply_no_error() -> None:
@@ -49,19 +54,26 @@ def test_apply_no_error() -> None:
The only exception here is for lists. if a list is malformed to what a killswitch expects, it SHOULD explode,
thus causing the killswitch to fail and eat the entire message.
"""
killswitch._apply([], '0', None, True)
killswitch._apply({}, '0', None, True)
killswitch._apply([], "0", None, True)
killswitch._apply({}, "0", None, True)
killswitch._apply({}, "this doesn't exist", None, True)
with pytest.raises(IndexError):
killswitch._apply([], '1', 'bang?')
killswitch._apply([], "1", "bang?")
@pytest.mark.parametrize(
('input', 'expected'),
("input", "expected"),
[
('1', 1), ('1337', 1337), ('no.', None), ('0x10', None), ('010', 10),
(False, 0), (str((1 << 63)-1), (1 << 63)-1), (True, 1), (str(1 << 1337), 1 << 1337)
]
("1", 1),
("1337", 1337),
("no.", None),
("0x10", None),
("010", 10),
(False, 0),
(str((1 << 63) - 1), (1 << 63) - 1),
(True, 1),
(str(1 << 1337), 1 << 1337),
],
)
def test_get_int(input: str, expected: int | None) -> None:
"""Check that _get_int doesn't throw when handed bad data."""
@@ -69,24 +81,63 @@ def test_get_int(input: str, expected: int | None) -> None:
@pytest.mark.parametrize(
('source', 'key', 'action', 'to_set', 'result'),
("source", "key", "action", "to_set", "result"),
[
(['this', 'is', 'a', 'test'], '1', 'delete', None, ['this', 'a', 'test']),
(['this', 'is', 'a', 'test'], '1', '', None, ['this', None, 'a', 'test']),
({'now': 'with', 'a': 'dict'}, 'now', 'delete', None, {'a': 'dict'}),
({'now': 'with', 'a': 'dict'}, 'now', '', None, {'now': None, 'a': 'dict'}),
({'depth': {'is': 'important'}}, 'depth.is', '', 'nonexistent', {'depth': {'is': 'nonexistent'}}),
([{'test': ['stuff']}], '0.test.0', '', 'things', [{'test': ['things']}]),
(({'test': {'with': ['a', 'tuple']}},), '0.test.with.0', 'delete', '', ({'test': {'with': ['tuple']}},)),
({'test': ['with a', {'set', 'of', 'stuff'}]}, 'test.1', 'delete', '', {'test': ['with a']}),
({'keys.can.have.': 'dots!'}, 'keys.can.have.', '', '.s!', {'keys.can.have.': '.s!'}),
({'multilevel.keys': {'with.dots': False}}, 'multilevel.keys.with.dots',
'', True, {'multilevel.keys': {'with.dots': True}}),
({'dotted.key.one.level': False}, 'dotted.key.one.level', '', True, {'dotted.key.one.level': True}),
(["this", "is", "a", "test"], "1", "delete", None, ["this", "a", "test"]),
(["this", "is", "a", "test"], "1", "", None, ["this", None, "a", "test"]),
({"now": "with", "a": "dict"}, "now", "delete", None, {"a": "dict"}),
({"now": "with", "a": "dict"}, "now", "", None, {"now": None, "a": "dict"}),
(
{"depth": {"is": "important"}},
"depth.is",
"",
"nonexistent",
{"depth": {"is": "nonexistent"}},
),
([{"test": ["stuff"]}], "0.test.0", "", "things", [{"test": ["things"]}]),
(
({"test": {"with": ["a", "tuple"]}},),
"0.test.with.0",
"delete",
"",
({"test": {"with": ["tuple"]}},),
),
(
{"test": ["with a", {"set", "of", "stuff"}]},
"test.1",
"delete",
"",
{"test": ["with a"]},
),
(
{"keys.can.have.": "dots!"},
"keys.can.have.",
"",
".s!",
{"keys.can.have.": ".s!"},
),
(
{"multilevel.keys": {"with.dots": False}},
"multilevel.keys.with.dots",
"",
True,
{"multilevel.keys": {"with.dots": True}},
),
(
{"dotted.key.one.level": False},
"dotted.key.one.level",
"",
True,
{"dotted.key.one.level": True},
),
],
)
def test_deep_get(source: UPDATABLE_DATA, key: str, action: str, to_set: Any, result: UPDATABLE_DATA) -> None:
def test_deep_get(
source: UPDATABLE_DATA, key: str, action: str, to_set: Any, result: UPDATABLE_DATA
) -> None:
"""Test _deep_get behaves as expected."""
cpy = copy.deepcopy(source)
killswitch._deep_apply(target=cpy, path=key, to_set=to_set, delete=action == 'delete')
killswitch._deep_apply(
target=cpy, path=key, to_set=to_set, delete=action == "delete"
)
assert cpy == result
+90 -40
View File
@@ -1,4 +1,7 @@
"""Tests of killswitch behaviour."""
# flake8: noqa
# mypy: ignore-errors
"""Tests of killswitch behavior."""
from __future__ import annotations
import copy
@@ -7,42 +10,67 @@ import semantic_version
import killswitch
TEST_SET = killswitch.KillSwitchSet([
killswitch.KillSwitches(
version=semantic_version.SimpleSpec('1.0.0'),
kills={
'no-actions': killswitch.SingleKill('no-actions', 'test'),
'delete-action': killswitch.SingleKill('delete-action', 'remove stuff', delete_fields=['a', 'b.c']),
'delete-action-l': killswitch.SingleKill('delete-action-l', 'remove stuff', delete_fields=['2', '0']),
'set-action': killswitch.SingleKill('set-action', 'set stuff', set_fields={'a': False, 'b.c': True}),
'redact-action': killswitch.SingleKill('redact-action', 'redact stuff', redact_fields=['a', 'b.c'])
}
)
])
TEST_SET = killswitch.KillSwitchSet(
[
killswitch.KillSwitches(
version=semantic_version.SimpleSpec("1.0.0"),
kills={
"no-actions": killswitch.SingleKill("no-actions", "test"),
"delete-action": killswitch.SingleKill(
"delete-action", "remove stuff", delete_fields=["a", "b.c"]
),
"delete-action-l": killswitch.SingleKill(
"delete-action-l", "remove stuff", delete_fields=["2", "0"]
),
"set-action": killswitch.SingleKill(
"set-action", "set stuff", set_fields={"a": False, "b.c": True}
),
"redact-action": killswitch.SingleKill(
"redact-action", "redact stuff", redact_fields=["a", "b.c"]
),
},
)
]
)
@pytest.mark.parametrize(
('input', 'kill', 'should_pass', 'result', 'version'),
("input", "kill", "should_pass", "result", "version"),
[
([], 'doesnt-exist', True, None, '1.0.0'),
([], "doesnt-exist", True, None, "1.0.0"),
# should fail, attempts to use 'a' to index a list
(['a', 'b', 'c'], 'delete-action', False, ['a', 'b', 'c'], '1.0.0'),
(['a', 'b', 'c'], 'delete-action-l', True, ['b'], '1.0.0'),
(set(), 'delete-action-l', False, None, '1.0.0'), # set should be thrown out because it cant be indext
(['a', 'b'], 'delete-action-l', True, ['b'], '1.0.0'), # has a missing value, but that's fine for delete
(['a', 'b'], 'delete-action-l', True, ['a', 'b'], '1.1.0'), # wrong version
(["a", "b", "c"], "delete-action", False, ["a", "b", "c"], "1.0.0"),
(["a", "b", "c"], "delete-action-l", True, ["b"], "1.0.0"),
(
set(),
"delete-action-l",
False,
None,
"1.0.0",
), # set should be thrown out because it cant be indext
(
["a", "b"],
"delete-action-l",
True,
["b"],
"1.0.0",
), # has a missing value, but that's fine for delete
(["a", "b"], "delete-action-l", True, ["a", "b"], "1.1.0"), # wrong version
],
)
def test_killswitch(
input: killswitch.UPDATABLE_DATA, kill: str, should_pass: bool, result: killswitch.UPDATABLE_DATA | None,
version: str
input: killswitch.UPDATABLE_DATA,
kill: str,
should_pass: bool,
result: killswitch.UPDATABLE_DATA | None,
version: str,
) -> None:
"""Simple killswitch tests."""
should_return, res = TEST_SET.check_killswitch(kill, input, version=version)
assert (not should_return) == should_pass, (
f'expected to {"pass" if should_pass else "fail"}, but {"passed" if not should_pass else "failed"}'
)
assert (
not should_return
) == should_pass, f'expected to {"pass" if should_pass else "fail"}, but {"passed" if not should_pass else "failed"}'
if result is None:
return # we didn't expect any result
@@ -51,21 +79,38 @@ def test_killswitch(
@pytest.mark.parametrize(
('kill_dict', 'input', 'result'),
("kill_dict", "input", "result"),
[
({'set_fields': {'test': None}}, {}, {'test': None}),
({'set_fields': {'test': None}, 'delete_fields': ['test']}, {}, {}),
({'set_fields': {'test': None}, 'redact_fields': ['test']}, {}, {'test': 'REDACTED'}),
({'set_fields': {'test': None}, 'redact_fields': ['test'], 'delete_fields': ['test']}, {}, {}),
({"set_fields": {"test": None}}, {}, {"test": None}),
({"set_fields": {"test": None}, "delete_fields": ["test"]}, {}, {}),
(
{"set_fields": {"test": None}, "redact_fields": ["test"]},
{},
{"test": "REDACTED"},
),
(
{
"set_fields": {"test": None},
"redact_fields": ["test"],
"delete_fields": ["test"],
},
{},
{},
),
],
)
def test_operator_precedence(
kill_dict: killswitch.SingleKillSwitchJSON, input: killswitch.UPDATABLE_DATA, result: killswitch.UPDATABLE_DATA
kill_dict: killswitch.SingleKillSwitchJSON,
input: killswitch.UPDATABLE_DATA,
result: killswitch.UPDATABLE_DATA,
) -> None:
"""Ensure that operators are being applied in the correct order."""
kill = killswitch.SingleKill(
"", "", kill_dict.get('redact_fields'), kill_dict.get('delete_fields'), kill_dict.get('set_fields')
"",
"",
kill_dict.get("redact_fields"),
kill_dict.get("delete_fields"),
kill_dict.get("set_fields"),
)
cpy = copy.deepcopy(input)
@@ -76,18 +121,23 @@ def test_operator_precedence(
@pytest.mark.parametrize(
('names', 'input', 'result', 'expected_return'),
("names", "input", "result", "expected_return"),
[
(['no-actions', 'delete-action'], {'a': 1}, {'a': 1}, True),
(["no-actions", "delete-action"], {"a": 1}, {"a": 1}, True),
# this is true because delete-action keyerrors, thus causing failsafe
(['delete-action'], {'a': 1}, {'a': 1}, True),
(['delete-action'], {'a': 1, 'b': {'c': 2}}, {'b': {}}, False),
]
(["delete-action"], {"a": 1}, {"a": 1}, True),
(["delete-action"], {"a": 1, "b": {"c": 2}}, {"b": {}}, False),
],
)
def test_check_multiple(
names: list[str], input: killswitch.UPDATABLE_DATA, result: killswitch.UPDATABLE_DATA, expected_return: bool
names: list[str],
input: killswitch.UPDATABLE_DATA,
result: killswitch.UPDATABLE_DATA,
expected_return: bool,
) -> None:
"""Check that order is correct when checking multiple killswitches."""
should_return, data = TEST_SET.check_multiple_killswitches(input, *names, version='1.0.0')
should_return, data = TEST_SET.check_multiple_killswitches(
input, *names, version="1.0.0"
)
assert should_return == expected_return
assert data == result