Skip to content

Commit

Permalink
fix implementation details and edge cases; test
Browse files Browse the repository at this point in the history
  • Loading branch information
vreuter committed Jul 8, 2019
1 parent 081f2e7 commit 45531b5
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 8 deletions.
14 changes: 7 additions & 7 deletions pypiper/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
""" Shared utilities """

from collections import Iterable, Sequence
from collections import Iterable, Mapping, Sequence
import os
import sys
import re
Expand Down Expand Up @@ -284,17 +284,17 @@ def determine_uncallable(
if transformations:
if not isinstance(transformations, Iterable) or \
isinstance(transformations, str) or \
not all(map(lambda func_pair: isinstance(func_pair, tuple)
and len(func_pair) == 2,
transformations)):
not all(map(
lambda func_pair: isinstance(func_pair, tuple) and len(func_pair) == 2,
transformations.values() if isinstance(transformations, Mapping) else transformations)):
raise TypeError(
"Transformations argument should be a collection of pairs; got "
"{} ({})".format(transformations, type(transformations).__name__))
if accumulate:
def finalize(cmd):
for p, t in transformations:
if p(cmd):
return t(cmd)
cmd = t(cmd)
return cmd
else:
if not isinstance(transformations, (tuple, list)):
Expand All @@ -305,8 +305,8 @@ def finalize(cmd):
print("Transformations: {}".format(transformations))
for p, t in transformations:
if p(cmd):
cmd = t(cmd)
return cmd
return t(cmd)
return cmd

else:
finalize = lambda cmd: cmd
Expand Down
52 changes: 51 additions & 1 deletion tests/utils_tests/test_check_command_callability.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import pytest
from pypiper import utils as piper_utils
from ubiquerg import powerset
from veracitools import ExpectContext

__author__ = "Vince Reuter"
Expand Down Expand Up @@ -53,6 +54,7 @@ def pytest_generate_tests(metafunc):
lambda _: False)
])
def test_callability_checker_defaults(tmpdir, filename, setup, pretest, exp_miss):
""" Verify behavior of callability checker with default parameterization. """
cmd = os.path.join(tmpdir.strpath, filename)
setup(cmd)
assert pretest(cmd)
Expand Down Expand Up @@ -85,10 +87,58 @@ def test_check_all_bad_handler_is_type_error_iff_uncallability_exists(
(lambda bads: Exception("{} bad commands: {}".format(len(bads), bads)), Exception),
(lambda bads: "{} bad commands: {}".format(len(bads), bads), False)
])
def test_check_all_result_is_conjunction(create_result, expected, str_list_monad):
def test_check_all_result_is_conjunctive(create_result, expected, str_list_monad):
""" Even one uncallable means result is False or an Exception occurs. """
cmd = "noncmd"
with mock.patch.object(piper_utils, "determine_uncallable",
return_value=[(cmd, cmd)]), \
ExpectContext(expected, piper_utils.check_all_commands) as check:
check(cmds=str_list_monad(cmd), get_bad_result=create_result)


@pytest.mark.parametrize("commands", ["man", "ls", ["man", "ls"]])
@pytest.mark.parametrize(
["transforms", "expectation"],
[(arg, lambda res: isinstance(res, list)) for arg in [None, []]] +
[(arg, TypeError) for arg in [1, "a"]])
def test_check_all_requires_iterable_transformations_argument(
commands, transforms, expectation):
""" If transformations arg is non-null, it must be iterable. """
def call():
return piper_utils.determine_uncallable(commands, transformations=transforms)
if isinstance(expectation, type) and issubclass(expectation, Exception):
with pytest.raises(expectation):
call()
else:
assert expectation(call())


@pytest.mark.parametrize(
"commands", powerset(["ls", "picard.jar", "$ENVVAR"], nonempty=True))
def test_transformation_accumulation(commands):
""" Accumulation of transformations works as expected """
mapjar = lambda c: "java -jar {}".format(c)
envjar = "env.jar"
transforms = [(lambda c: c == "$ENVVAR", lambda _: envjar),
(lambda c: c.endswith(".jar"), mapjar)]
exps = {"ls": "ls", "picard.jar": mapjar("picard.jar"), "$ENVVAR": mapjar(envjar)}
with mock.patch.object(piper_utils, "is_command_callable", return_value=False):
res = piper_utils.determine_uncallable(
commands, transformations=transforms, accumulate=True)
expectation = [(c, exps[c]) for c in commands]
print("EXPECTED: {}".format(expectation))
print("OBSERVED: {}".format(res))
assert expectation == res


@pytest.mark.parametrize("transforms", [
{(lambda _: True, lambda c: c), (lambda _: False, lambda c: c)},
{"id": (lambda _: True, lambda c: c),
"java": (lambda c: c.endswith(".jar"), lambda c: "java -jar {}".format(c))}
])
def test_non_accumulative_but_unordered_transformation_is_exceptional(transforms):
with pytest.raises(Exception) as err_ctx:
piper_utils.determine_uncallable("ls", transformations=transforms)
exp_msg = "If transformations are unordered, non-accumulation of " \
"effects may lead to nondeterministic behavior."
assert str(err_ctx.value) == exp_msg

0 comments on commit 45531b5

Please sign in to comment.