class TestBrewCLI(object): @pytest.mark.randomize(formulas=nonempty_list_of(str), force=bool, min_length=1) def test_install(self, cask, debug, verbose, formulas, force): cmd = self.__cask("install", cask) _test_command(cmd, formulas, debug=debug, verbose=verbose, force=force) @pytest.mark.randomize(formulas=nonempty_list_of(str), min_length=1) def test_rm(self, cask, debug, verbose, formulas): cmd = self.__cask("rm", cask) _test_command(cmd, formulas, debug=debug, verbose=verbose) @pytest.mark.randomize(formula=str, use_formula=bool) def test_list(self, cask, debug, verbose, formula, use_formula): cmd = self.__cask("ls", cask) args = [formula if use_formula else None] _test_command(cmd, args, debug=debug, verbose=verbose) def test_missing(self, cask, debug, verbose): cmd = self.__cask("missing", cask) _test_command((cmd, "list_missing"), debug=debug, verbose=verbose) @staticmethod def __cask(cmd, cask): return "cask {0}".format(cmd) if cask else cmd
class TestBrew(object): @classmethod def setup_class(cls): cls.patcher = patch("cider._sh.spawn", spec=True, return_value=0) sh.spawn = cls.patcher.start() @classmethod def teardown_class(cls): cls.patcher.stop() @pytest.mark.randomize(formulas=nonempty_list_of(str), force=bool) def test_install(self, cask, debug, verbose, formulas, force): brew = Brew(cask, debug, verbose) args = self.__cmd(cask) args += ["install"] + formulas + (["--force"] if force else []) args += self.__flags(debug, verbose) brew.install(*formulas, force=force) sh.spawn.assert_called_with(args, debug=debug, check_output=False, env=brew.env) @pytest.mark.randomize(formulas=nonempty_list_of(str)) def test_rm(self, cask, debug, verbose, formulas): brew = Brew(cask, debug, verbose) args = self.__cmd(cask) + ["zap" if cask else "rm"] + formulas args += self.__flags(debug, verbose) brew.rm(*formulas) sh.spawn.assert_called_with(args, debug=debug, check_output=False, env=brew.env) @pytest.mark.randomize(formula=str) def test_safe_install(self, cask, debug, verbose, formula): brew = Brew(cask, debug, verbose) old_side_effect = sh.spawn.side_effect args = self.__cmd(cask) + ["install", formula] args += self.__flags(debug, verbose) sh.spawn.side_effect = CalledProcessError(42, " ".join(args)) brew.safe_install(formula) sh.spawn.assert_called_with(args, debug=debug, check_output=False, env=brew.env) sh.spawn.side_effect = old_side_effect @pytest.mark.randomize(tap=str, use_tap=bool) def test_tap(self, cask, debug, verbose, tap, use_tap): with pytest.raises(AssertionError) if cask else empty(): brew = Brew(cask, debug, verbose) tap = tap if use_tap else None args = self.__cmd() + ["tap"] + ([tap] if tap is not None else []) args += self.__flags(debug, verbose) brew.tap(tap) sh.spawn.assert_called_with(args, debug=debug, check_output=not use_tap, env=brew.env) @pytest.mark.randomize(tap=str) def test_untap(self, cask, debug, verbose, tap): with pytest.raises(AssertionError) if cask else empty(): brew = Brew(cask, debug, verbose) args = self.__cmd() + ["untap", tap] args += self.__flags(debug, verbose) brew.untap(tap) sh.spawn.assert_called_with(args, debug=debug, check_output=False, env=brew.env) @pytest.mark.randomize() def test_ls(self, cask, debug, verbose): brew = Brew(cask, debug, verbose) old_return, sh.spawn.return_value = sh.spawn.return_value, "" args = self.__cmd(cask) + ["ls", "-1"] brew.ls() sh.spawn.assert_called_with(args, debug=debug, check_output=True, env=brew.env) sh.spawn.return_value = old_return @pytest.mark.randomize(formula=str) def test_uses(self, cask, debug, verbose, formula): brew = Brew(cask, debug, verbose) old_return, sh.spawn.return_value = sh.spawn.return_value, "" args = self.__cmd(cask) args += ["uses", "--installed", "--recursive", formula] args += self.__flags(debug, verbose) brew.uses(formula) sh.spawn.assert_called_with(args, debug=debug, check_output=True, env=brew.env) sh.spawn.return_value = old_return @staticmethod def __cmd(cask=None): return ["brew"] + (["cask"] if cask else []) @staticmethod def __flags(debug, verbose): return ((["--debug"] if debug else []) + (["--verbose"] if verbose else []))
args = ["defaults", "write"] + (["-f"] if force else []) args += [domain, key, defaults.key_type(value), str(value)] defaults.write(domain, key, value, force) sh.spawn.assert_called_with(args, debug=debug, env=defaults.env) @pytest.mark.randomize(domain=str, key=str) def test_delete(self, debug, domain, key): defaults = Defaults(debug) args = ["defaults", "delete", domain, key] defaults.delete(domain, key) sh.spawn.assert_called_with(args, debug=debug, env=defaults.env) @pytest.mark.randomize(args=nonempty_list_of(str), check_call=bool, check_output=bool, debug=bool) def test_spawn(args, check_call, check_output, debug): if check_output: expected_call = "check_output" elif check_call: expected_call = "check_call" else: expected_call = "call" with patch("subprocess.{0}".format(expected_call)) as call: call.return_value = random.randint(0, 100) actual_return_value = sh.spawn(args, check_call=check_call,
import pytest from kulka.response import parser from kulka.response.asyncpacket import ID_CODE def create_async_packet(id_code, data): dlen = len(data) + 1 dlen_msb = dlen >> 8 & 0xFF dlen_lsb = dlen & 0xFF given = bytearray([0xFF, 0xFE, id_code, dlen_msb, dlen_lsb] + data) given.append(sum(given[2:]) & 0xFF ^ 0xFF) return given @pytest.mark.parametrize('id_code', ID_CODE.keys()) @pytest.mark.randomize(data=pytest.nonempty_list_of(int), min_num=0, max_num=255) def test_truncated_async_packet(id_code, data): given = create_async_packet(id_code, data) for i in range(len(given) - 1): with pytest.raises(ValueError): parser(given[:i]) @pytest.mark.parametrize('id_code', ID_CODE.keys()) @pytest.mark.randomize(data=pytest.nonempty_list_of(int), min_num=0, max_num=255) def test_valid_async_packet(id_code, data): response_, _ = parser(create_async_packet(id_code, data))
def _create(self, items): subset = set(items) for item in items: self._item_to_subset[item] = subset self._subsets.append(subset) @staticmethod def _arbitrary(s): """Returns an arbitrary item from set s. Consistently returns the same item as long as s remains the same. """ return next(iter(s)) @pytest.mark.randomize(equivalence=nonempty_list_of(int), unrelateds=nonempty_list_of(list_of(int)), min_num=-10, max_num=100) def test_canonify(equivalence, unrelateds, n_calls=1000): e = Equivalence() e.disconnect(equivalence) canon = e.canonify(equivalence[0]) equivalence = set(equivalence) assert canon in equivalence for unrelated in unrelateds: unrelated = list(set(unrelated).difference(equivalence)) e.disconnect(unrelated) for item in equivalence: assert e.canonify(item) == canon
args = ["defaults", "write"] + (["-f"] if force else []) args += [domain, key, defaults.key_type(value), str(value)] defaults.write(domain, key, value, force) sh.spawn.assert_called_with(args, debug=debug, env=defaults.env) @pytest.mark.randomize(domain=str, key=str) def test_delete(self, debug, domain, key): defaults = Defaults(debug) args = ["defaults", "delete", domain, key] defaults.delete(domain, key) sh.spawn.assert_called_with(args, debug=debug, env=defaults.env) @pytest.mark.randomize(args=nonempty_list_of(str), check_call=bool, check_output=bool, debug=bool) def test_spawn(args, check_call, check_output, debug): if check_output: expected_call = "check_output" elif check_call: expected_call = "check_call" else: expected_call = "call" with patch("subprocess.{0}".format(expected_call)) as call: call.return_value = random.randint(0, 100) actual_return_value = sh.spawn( args, check_call=check_call, check_output=check_output, debug=debug )
import pytest from kulka.response import parser from kulka.response.responsepacket import MRSP def create_response(mrsp, seq, data): given = bytearray([0xFF, 0xFF, mrsp, seq, len(data) + 1] + data) given.append(sum(given[2:]) & 0xFF ^ 0xFF) return given @pytest.mark.parametrize('mrsp', MRSP.keys()) @pytest.mark.randomize(seq=int, data=pytest.nonempty_list_of(int), min_num=0, max_num=255) def test_truncated_response(mrsp, seq, data): given = create_response(mrsp, seq, data) for i in range(len(given) - 1): with pytest.raises(ValueError): parser(given[:i]) @pytest.mark.parametrize('mrsp', MRSP.keys()) @pytest.mark.randomize(seq=int, data=pytest.nonempty_list_of(int), min_num=0, max_num=255) def test_valid_response(mrsp, seq, data): response_, _ = parser(create_response(mrsp, seq, data))
class TestCiderCLI(object): @pytest.mark.randomize(tap=str) def test_tap(self, debug, verbose, tap): _test_command("tap", [tap], debug=debug, verbose=verbose) def test_tap_missing(self, debug, verbose): _test_command(("tap missing", "list_missing_taps"), debug=debug, verbose=verbose) @pytest.mark.randomize(name=str, key=str, value=str, globaldomain=bool, force=bool) def test_set_default(self, debug, verbose, name, key, value, globaldomain, force): cmd, callback = "set-default", "set_default" result, MockCider = _invoke_command(cmd, [name, key, value], debug=debug, verbose=verbose, force=force, globalDomain=globaldomain) assert not result.exception assert result.exit_code == 0 MockCider.assert_called_with(False, debug, verbose) if globaldomain: name, key, value = self.__global_domain_params(name, key) getattr(MockCider(), callback).assert_called_with(name, key, value, force=force) @pytest.mark.randomize(name=str, key=str, globaldomain=bool) def test_remove_default(self, debug, verbose, name, key, globaldomain): cmd, callback = "remove-default", "remove_default" result, MockCider = _invoke_command(cmd, [name, key], debug=debug, verbose=verbose, globalDomain=globaldomain) assert not result.exception assert result.exit_code == 0 MockCider.assert_called_with(False, debug, verbose) if globaldomain: name, key, _ = self.__global_domain_params(name, key) getattr(MockCider(), callback).assert_called_with(name, key) def test_apply_defaults(self, debug, verbose): _test_command(("apply-defaults", "apply_defaults"), debug=debug, verbose=verbose) @pytest.mark.randomize(app=str, icon=str) def test_set_icon(self, debug, verbose, app, icon): _test_command(("set-icon", "set_icon"), [app, icon], debug=debug, verbose=verbose) @pytest.mark.randomize(app=str) def test_remove_icon(self, debug, verbose, app): _test_command(("remove-icon", "remove_icon"), [app], debug=debug, verbose=verbose) def test_apply_icons(self, debug, verbose): _test_command(("apply-icons", "apply_icons"), debug=debug, verbose=verbose) def test_run_scripts(self, debug, verbose): _test_command(("run-scripts", "run_scripts"), debug=debug, verbose=verbose, expected_flags={ "before": True, "after": True }) def test_restore(self, debug, verbose): _test_command("restore", debug=debug, verbose=verbose, expected_flags={"ignore_errors": False}) @pytest.mark.randomize(force=bool) def test_relink(self, debug, verbose, force): _test_command("relink", debug=debug, verbose=verbose, force=force) @pytest.mark.randomize(name=str, sources=nonempty_list_of(str), min_length=1) def test_addlink(self, debug, verbose, name, sources): _test_command("addlink", [name] + sources, debug=debug, verbose=verbose) @pytest.mark.randomize(name=str, min_length=1) def test_unlink(self, debug, verbose, name): _test_command("unlink", [name], debug=debug, verbose=verbose) @staticmethod def __global_domain_params(name, key): return "NSGlobalDomain", name, key
class TestBrewCore(object): @pytest.mark.randomize(formulas=nonempty_list_of(str), force=bool, min_length=1) def test_install(self, tmpdir, cask, debug, verbose, formulas, force): cider = Cider(cask, debug, verbose, cider_dir=str(tmpdir)) cider.brew = MagicMock() cider.install(*formulas, force=force) cider.brew.install.assert_called_once_with(*formulas, force=force) key = "casks" if cask else "formulas" for formula in formulas: assert formula in cider.read_bootstrap().get(key, []) @pytest.mark.randomize(formulas=nonempty_list_of(str), min_length=1) def test_rm(self, tmpdir, cask, debug, verbose, formulas): cider = Cider(cask, debug, verbose, cider_dir=str(tmpdir)) cider.brew = MagicMock() cider.rm(*formulas) cider.brew.rm.assert_called_once_with(*formulas) key = "casks" if cask else "formulas" for formula in formulas: assert formula not in cider.read_bootstrap().get(key, []) @pytest.mark.randomize(data=dict_of(str, str)) def test_read_bootstrap(self, tmpdir, cask, debug, verbose, data): with patch("cider.core.read_config") as mock: cider = Cider(cask, debug, verbose, cider_dir=str(tmpdir)) mock.return_value = data assert cider.read_bootstrap() == data mock.assert_called_with(cider.bootstrap_file, {}) @pytest.mark.randomize(random_prefix=str, bootstrap={ "formulas": list_of(str), "casks": list_of(str) }, min_length=1) def test_installed(self, tmpdir, cask, debug, verbose, random_prefix, bootstrap): cider = Cider(cask, debug, verbose, cider_dir=str(tmpdir)) cider.read_bootstrap = MagicMock(return_value=bootstrap) key = "casks" if cask else "formulas" installed = bootstrap.get(key, []) random_choice = random.choice(installed) if installed else None for prefix in [None, random_choice, random_prefix]: assert cider.installed(prefix) == [ x for x in installed if not prefix or x.startswith(prefix) ] @pytest.mark.randomize(installed=list_of(str), brewed=list_of(str), min_length=1) def test_missing(self, tmpdir, cask, debug, verbose, installed, brewed): orphans = [] def generate_uses(): uses = {} for formula in brewed: subset = [x for x in installed if x != formula] if subset and random.choice([True, False]): uses[formula] = random.sample( subset, random.randint(1, len(subset))) else: orphans.append(formula) return lambda x: uses.get(x, []) cider = Cider(cask, debug, verbose, cider_dir=str(tmpdir)) cider.brew = MagicMock() cider.brew.ls = MagicMock(return_value=brewed) cider.brew.uses = MagicMock(side_effect=generate_uses()) cider.installed = MagicMock(return_value=installed) assert cider.missing() == sorted(orphans)
class TestCiderCore(object): @pytest.mark.parametrize("bool_values", ["yes", "no", "y", "n", "true", "false"]) @pytest.mark.randomize(domain=str, key=str, values=[str, int, float], force=bool) def test_set_default(self, tmpdir, debug, verbose, domain, key, values, bool_values, force): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) cider.defaults = MagicMock() for value in values + map(random_case, bool_values): json_value = cider.json_value(value) cider.set_default(domain, key, value, force=force) cider.defaults.write.assert_called_with(domain, key, json_value, force) assert cider.read_defaults()[domain][key] == json_value # Verify str(value) => defaults.write(value) cider.set_default(domain, key, str(value), force=force) cider.defaults.write.assert_called_with( domain, key, cider.json_value(str(value)), force) @pytest.mark.randomize(domain=str, key=str) def test_remove_default(self, tmpdir, debug, verbose, domain, key): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) cider.defaults = MagicMock() cider.remove_default(domain, key) cider.defaults.delete.assert_called_with(domain, key) assert key not in cider.read_defaults().get(domain, []) @pytest.mark.randomize(tap=str) def test_tap(self, tmpdir, debug, verbose, tap): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) cider.brew = MagicMock() cider.tap(tap) cider.brew.tap.assert_called_with(tap) assert tap in cider.read_bootstrap().get("taps", []) @pytest.mark.randomize(tap=str) def test_untap(self, tmpdir, debug, verbose, tap): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) cider.brew = MagicMock() cider.untap(tap) cider.brew.untap.assert_called_with(tap) assert tap not in cider.read_bootstrap().get("taps", []) @pytest.mark.randomize(data=dict_of(str, str)) def test_read_defaults(self, tmpdir, debug, verbose, data): with patch("cider.core.read_config") as mock: cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) mock.return_value = data assert cider.read_defaults() == data mock.assert_called_with(cider.defaults_file, {}) @pytest.mark.randomize(force=bool) def test_relink(self, tmpdir, debug, verbose, force): """ Tests that: 1. Target directories are created. 2. For each source in glob(key), mklink(src, expandtarget(src, target)) is called. 3. Previously-cached targets are removed. 4. Cache is updated with new targets. """ def generate_symlinks(): srcdir = tmpdir.join(random_str(min_length=1)) def symkey(directory, key): return str(directory.join(key).relto(srcdir)) def symvalue(directory, value): return str(directory.join(value)) + ("/" if value.endswith("/") else "") outerdir = srcdir.join(random_str(min_length=1)) innerdir = outerdir.join(random_str(min_length=1)) targetdir = tmpdir.join(random_str(min_length=1)) ext = random_str(min_length=1, max_length=8) os.makedirs(str(innerdir)) for _ in range(random.randint(0, 10)): touch(str(innerdir.join("{0}.{1}".format(random_str(), ext)))) path = str(outerdir.join(random_str(min_length=1))) touch(path) return { symkey(outerdir, "*/*." + ext): symvalue(targetdir, "a/b/c/"), symkey(outerdir, "*/*." + ext): symvalue(targetdir, "a/b/c"), symkey(outerdir, path): symvalue(targetdir, "a/b/d"), } cider = Cider(False, debug, verbose, cider_dir=str(tmpdir), support_dir=str(tmpdir.join(".cache"))) cider.mklink = MagicMock(return_value=True) for srcglob, target in generate_symlinks().items(): invalid = not isdirname(target) and ("*" in srcglob or "?" in srcglob) old_targets = cider._cached_targets() # pylint:disable=W0212 cider.read_bootstrap = MagicMock( return_value={"symlinks": { srcglob: target }}) with pytest.raises(SymlinkError) if invalid else empty(): new_targets = set(cider.relink(force)) for src in iglob(srcglob): cider.mklink.assert_called_with( src, cider.expandtarget(src, target)) assert os.path.isdir(os.path.dirname(target)) for dead_target in set(old_targets) - new_targets: assert not os.path.exists(dead_target) new_cache = cider._cached_targets() # pylint:disable=W0212 assert new_targets == set(new_cache) & new_targets def test_mklink(self, tmpdir, debug, verbose): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir), support_dir=str(tmpdir.join(".cache"))) source = str(tmpdir.join(random_str(min_length=1))) target = str(tmpdir.join(random_str(min_length=1))) # SymlinkError should be raised if source does not exist. with pytest.raises(SymlinkError): assert not cider.mklink(source, target) # Should succeed for valid source/target. touch(source) for _ in range(2): assert cider.mklink(source, target) assert os.path.islink(target) # Should fail for existing target. os.remove(target) touch(target) assert not cider.mklink(source, target) assert not os.path.islink(target) # Should allow removing existing target with --force. with patch("cider._osx.move_to_trash", side_effect=os.remove): assert cider.mklink(source, target, force=True) @pytest.mark.randomize(name=str, min_length=1) def test_addlink(self, tmpdir, debug, verbose, name): """ Tests that: 1. Symlink directory is created & file is moved there. 2. Symlink is created. 3. Symlink is added to bootstrap. 4. Cache is updated with new target. Expected errors: - StowError is raised if target does not exist. - StowError is raised if target already exists. """ cider = Cider(False, debug, verbose, cider_dir=str(tmpdir), support_dir=str(tmpdir.join(".cache"))) cider.add_symlink = MagicMock() source = os.path.abspath(str(tmpdir.join(random_str(min_length=1)))) basename = os.path.basename(source) stow_dir = os.path.abspath(os.path.join(cider.symlink_dir, name)) stow = os.path.join(stow_dir, basename) # StowError should be raised if source does not exist. with pytest.raises(StowError): cider.addlink(name, source) touch(source) cider.addlink(name, source) assert os.path.isdir(stow_dir) assert os.path.isfile(stow) assert os.path.islink(source) assert os.path.samefile(os.path.realpath(stow), os.path.realpath(source)) cider.add_symlink.assert_called_with(name, source) new_cache = cider._cached_targets() # pylint:disable=W0212 assert source in new_cache # StowError should be raised if source already exists. os.remove(source) touch(source) with pytest.raises(StowError): cider.addlink(source, name) @pytest.mark.randomize(name=str, links=nonempty_list_of(str), min_length=1) def test_unlink(self, tmpdir, debug, verbose, name, links): """ Tests that: 1. Each symlink is moved back to its original location. 2. Symlinks are removed from bootstrap. 3. Cache is updated with targets removed. 4. Symlink directory is removed if empty. Expected errors: - StowError is raised if no symlink was found. - SymlinkError is raised if target already exists. """ cider = Cider(False, debug, verbose, cider_dir=str(tmpdir.join("cider")), support_dir=str(tmpdir.join("cider", ".cache"))) cider.remove_symlink = MagicMock() stow_dir = os.path.abspath(os.path.join(cider.symlink_dir, name)) os.makedirs(stow_dir) for link in links: source = os.path.join(stow_dir, link) target = str(tmpdir.join(link)) touch(source) os.symlink(source, target) cider.add_symlink(name, target) cider.unlink(name) new_cache = cider._cached_targets() # pylint:disable=W0212 for link in links: source = os.path.join(stow_dir, link) target = str(tmpdir.join(link)) assert os.path.exists(target) assert not os.path.islink(target) assert not os.path.exists(source) assert target not in new_cache cider.remove_symlink.assert_called_with(name) assert not os.path.exists(stow_dir) @pytest.mark.randomize(defaults=dict_of(str, dict_of(str, str))) def test_apply_defaults(self, tmpdir, debug, verbose, defaults): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) cider.defaults = MagicMock() cider.read_defaults = MagicMock(return_value=defaults) cider.apply_defaults() for domain, options in defaults.items(): for key, value in options.items(): cider.defaults.write.assert_any_call(domain, key, value) @pytest.mark.randomize(before=bool, after=bool, bootstrap={ "before-scripts": list_of(str), "after-scripts": list_of(str) }, min_length=1) def test_run_scripts(self, tmpdir, debug, verbose, before, after, bootstrap): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) cider.read_bootstrap = MagicMock(return_value=bootstrap) scripts = [] scripts += bootstrap.get("before-scripts", []) if before else [] scripts += bootstrap.get("after-scripts", []) if after else [] # TODO: Assert ordering with patch("cider.core.spawn", autospec=True, return_value=0) as spawn: cider.run_scripts(before, after) for script in scripts: spawn.assert_any_call([script], shell=True, debug=debug, cwd=cider.cider_dir, env=cider.env) @pytest.mark.randomize(installed=list_of(str), brewed=list_of(str), min_length=1) def test_missing_taps(self, tmpdir, debug, verbose, installed, brewed): cider = Cider(False, debug, verbose, cider_dir=str(tmpdir)) cider.brew = MagicMock() cider.brew.tap = MagicMock(return_value="\n".join(brewed)) missing = set(brewed) - set(installed) assert cider.missing_taps() == sorted(missing)
import pytest from pytest import list_of, nonempty_list_of, dict_of, Generator @pytest.mark.randomize(l=list_of(int)) def test_list_of(l): assert isinstance(l, list) assert all(isinstance(i, int) for i in l), l @pytest.mark.randomize(l=nonempty_list_of(int), ncalls=50) def test_nonempty_list_of(l): assert isinstance(l, list), l assert len(l) >= 1 @pytest.mark.randomize(l=list_of(str, min_items=10, max_items=12), fixed_length=5) def test_list_of_options(l): assert isinstance(l, list) assert 10 <= len(l) <= 12 assert all(isinstance(s, str) and len(s) == 5 for s in l), l @pytest.mark.randomize(l=list_of(str, items=15)) def test_list_of_num_items(l): assert len(l) == 15 @pytest.mark.randomize(l=list_of(str, items=15, min_items=1000)) def test_list_of_items_precedes_over_min_items(l):
import pytest from kulka.response import parser from kulka.response.responsepacket import MRSP def create_response(mrsp, seq, data): given = bytearray([0xFF, 0xFF, mrsp, seq, len(data) + 1] + data) given.append(sum(given[2:]) & 0xFF ^ 0xFF) return given @pytest.mark.parametrize('mrsp', MRSP.keys()) @pytest.mark.randomize(seq=int, data=pytest.nonempty_list_of(int), min_num=0, max_num=255) def test_truncated_response(mrsp, seq, data): given = create_response(mrsp, seq, data) for i in range(len(given) - 1): with pytest.raises(ValueError): parser(given[:i]) @pytest.mark.parametrize('mrsp', MRSP.keys()) @pytest.mark.randomize(seq=int, data=pytest.nonempty_list_of(int), min_num=0, max_num=255) def test_valid_response(mrsp, seq, data): response_, _ = parser(create_response(mrsp, seq, data)) assert response_.mrsp == MRSP[mrsp] assert response_.seq == seq assert response_.data == bytearray(data)