<commit_before>#!/usr/bin/python
#
# Copyright (c) 2012 <NAME> <<EMAIL>>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# pylint: disable=C0103

from flexmock import flexmock
from nose.tools import assert_equal, assert_raises

from pypeline.common.testing import Monkeypatch

from pypeline.atomiccmd.builder import \
    AtomicCmdBuilder, \
    AtomicCmdBuilderError, \
    AtomicJavaCmdBuilder, \
    AtomicMPICmdBuilder, \
    apply_options, \
    use_customizable_cli_parameters, \
    create_customizable_cli_parameters, \
    JAVA_VERSIONS



################################################################################
################################################################################
## AtomicCmdBuilder: Constructor


def test_builder__simple__call():
    builder = AtomicCmdBuilder(["ls"])
    assert_equal(builder.call, ["ls"])

def test_builder__simple__str():
    builder = AtomicCmdBuilder("ls")
    assert_equal(builder.call, ["ls"])

def test_builder__simple__iterable():
    builder = AtomicCmdBuilder(iter(["ls"]))
    assert_equal(builder.call, ["ls"])

def test_builder__complex():
    builder = AtomicCmdBuilder(["java", "jar", "/a/jar"])
    assert_equal(builder.call, ["java", "jar", "/a/jar"])

def test_builder__kwargs__empty():
    builder = AtomicCmdBuilder(["ls"])
    assert_equal(builder.kwargs, {})

def test_builder__kwargs():
    expected = {"IN_FILE"  : "/abc/def.txt",
                "OUT_FILE" : "/etc/fstab"}
    builder = AtomicCmdBuilder(["ls"], **expected)
    assert_equal(builder.kwargs, expected)

def test_builder__kwargs__set_cwd():
    builder = AtomicCmdBuilder(["ls"], set_cwd = True)
    assert_equal(builder.kwargs, {"set_cwd" : True})



################################################################################
################################################################################
## AtomicCmdBuilder: set_option


def test_builder__set_option():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-name", "*.txt")
    assert_equal(builder.call, ["find", "-name", "*.txt"])

def test_builder__set_option__overwrite():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-name", "*.txt", fixed = False)
    builder.set_option("-name", "*.bat")
    assert_equal(builder.call, ["find", "-name", "*.bat"])

def test_builder__set_option__overwrite_fixed():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-name", "*.txt")
    assert_raises(AtomicCmdBuilderError, builder.set_option, "-name", "*.bat")




################################################################################
################################################################################
## AtomicCmdBuilder: add_option

def test_builder__add_option():
    builder = AtomicCmdBuilder("find")
    builder.add_option("-name", "*.txt")
    assert_equal(builder.call, ["find", "-name", "*.txt"])

def test_builder__add_option__overwrite():
    builder = AtomicCmdBuilder("find")
    builder.add_option("-name", "*.txt")
    builder.add_option("-or")
    builder.add_option("-name", "*.bat")
    assert_equal(builder.call, ["find", "-name", "*.txt", "-or", "-name", "*.bat"])



################################################################################
################################################################################
## AtomicCmdBuilder: add_option / set_option common tests


def test_builder__add_or_set_option__without_value():
    def _do_test_builder__add_or_set_option__without_value(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-delete")
        assert_equal(builder.call, ["find", "-delete"])
    yield _do_test_builder__add_or_set_option__without_value, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__without_value, AtomicCmdBuilder.set_option


def test_builder__add_or_set_option__with_sep():
    def _do_test_builder__add_or_set_option__with_sep(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", "0", sep = "=")
        assert_equal(builder.call, ["find", "-size=0"])
    yield _do_test_builder__add_or_set_option__with_sep, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__with_sep, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__with_non_str_value():
    def _do_test_test_builder__add_or_set_option__with_non_str_value(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", 0)
        assert_equal(builder.call, ["find", "-size", 0])
    yield _do_test_test_builder__add_or_set_option__with_non_str_value, AtomicCmdBuilder.add_option
    yield _do_test_test_builder__add_or_set_option__with_non_str_value, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__add_and_set():
    def _do_test_builder__add_or_set_option__add_and_set(setter_1, setter_2):
        builder = AtomicCmdBuilder("find")
        setter_1(builder, "-name", "*.txt")
        assert_raises(AtomicCmdBuilderError, setter_2, builder, "-name", "*.bat")
    yield _do_test_builder__add_or_set_option__add_and_set, AtomicCmdBuilder.set_option, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__add_and_set, AtomicCmdBuilder.add_option, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__with_non_str_key():
    def _do_test_builder__add_or_set_option__with_non_str_key(setter):
        builder = AtomicCmdBuilder("find")
        assert_raises(TypeError, setter, builder, 7913, "True")
    yield _do_test_builder__add_or_set_option__with_non_str_key, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__with_non_str_key, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__after_finalize():
    def _do_test_builder__add_or_set_option__after_finalize(setter):
        builder = AtomicCmdBuilder("find")
        builder.finalize()
        assert_raises(AtomicCmdBuilderError, setter, builder, "-size", "1")
    yield _do_test_builder__add_or_set_option__after_finalize, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__after_finalize, AtomicCmdBuilder.set_option


def test_builder__add_or_set_option__empty_key():
    def _do_test_builder__add_or_set_option__empty_key(setter):
        builder = AtomicCmdBuilder("find")
        assert_raises(KeyError, setter, builder, "", "1")
    yield _do_test_builder__add_or_set_option__empty_key, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__empty_key, AtomicCmdBuilder.set_option



################################################################################
################################################################################
## AtomicCmdBuilder: pop_option

def test_builder__pop_option():
    def _do_test_builder__pop_option(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", "0", fixed = False)
        builder.pop_option("-size")
        assert_equal(builder.call, ["find"])
    yield _do_test_builder__pop_option, AtomicCmdBuilder.set_option
    yield _do_test_builder__pop_option, AtomicCmdBuilder.add_option


def test_builder__pop_option__last_option():
    builder = AtomicCmdBuilder("find")
    builder.add_option("-size", "0", fixed = False)
    builder.add_option("-size", "1", fixed = False)
    builder.pop_option("-size")
    assert_equal(builder.call, ["find", "-size", "0"])

def test_builder__pop_option__different_options():
    def _do_test_builder__pop_option(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-empty", fixed = False)
        setter(builder, "-size", "1", fixed = False)
        setter(builder, "-name", "*.txt", fixed = False)
        builder.pop_option("-size")
        assert_equal(builder.call, ["find", "-empty", "-name", "*.txt"])
    yield _do_test_builder__pop_option, AtomicCmdBuilder.set_option
    yield _do_test_builder__pop_option, AtomicCmdBuilder.add_option



def test_builder__pop_option__is_fixed():
    def _do_test_builder__pop_option__is_fixed(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", "0")
        assert_raises(AtomicCmdBuilderError, builder.pop_option, "-size")
    yield _do_test_builder__pop_option__is_fixed, AtomicCmdBuilder.set_option
    yield _do_test_builder__pop_option__is_fixed, AtomicCmdBuilder.add_option

def test_builder__pop_option__empty():
    builder = AtomicCmdBuilder("find")
    assert_raises(KeyError, builder.pop_option, "-size")

def test_builder__pop_option__missing_key():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-size", 0)
    assert_raises(KeyError, builder.pop_option, "-isize")

def test_builder__pop_option__with_non_str_key():
    builder = AtomicCmdBuilder("find")
    assert_raises(TypeError, builder.pop_option, 7913)

def test_builder__pop_option__with_empty_key():
    builder = AtomicCmdBuilder("find")
    assert_raises(KeyError, builder.pop_option, "")




################################################################################
################################################################################
## AtomicCmdBuilder: add_value

def test_builder__add_value():
    builder = AtomicCmdBuilder("ls")
    builder.add_value("%(IN_FILE)s")
    assert_equal(builder.call, ["ls", "%(IN_FILE)s"])


def test_builder__add_value__two_values():
    builder = AtomicCmdBuilder("ls")
    builder.add_value("%(IN_FILE)s")
    builder.add_value("%(OUT_FILE)s")
    assert_equal(builder.call, ["ls", "%(IN_FILE)s", "%(OUT_FILE)s"])




################################################################################
################################################################################
## AtomicCmdBuilder: set_kwargs


def test_builder__set_kwargs__called_once():
    expected = {"IN_PATH" : "/a/b/", "OUT_PATH" : "/dst/file"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(**expected)
    assert_equal(builder.kwargs, expected)

def test_builder__set_kwargs__called_twice():
    expected = {"IN_PATH" : "/a/b/", "OUT_PATH" : "/dst/file"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(OUT_PATH = "/dst/file")
    builder.set_kwargs(IN_PATH = "/a/b/")
    assert_equal(builder.kwargs, expected)

def test_builder__set_kwargs__atomiccmdbuilder():
    mock = flexmock(AtomicCmdBuilder("true"))
    mock.should_receive('finalize').and_return("finalized!")
    builder = AtomicCmdBuilder("ls", IN_BUILDER = mock)
    assert_equal(builder.kwargs, {"IN_BUILDER" : "finalized!"})

def test_builder__set_kwargs__after_finalize():
    expected = {"IN_PATH" : "/a/b/"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(IN_PATH = "/a/b/")
    builder.finalize()
    assert_raises(AtomicCmdBuilderError, builder.set_kwargs, OUT_PATH = "/dst/file")
    assert_equal(builder.kwargs, expected)

def test_builder__set__kwargs__overwriting():
    expected = {"IN_PATH" : "/a/b/"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(IN_PATH = "/a/b/")
    assert_raises(AtomicCmdBuilderError, builder.set_kwargs, IN_PATH = "/dst/file")
    assert_equal(builder.kwargs, expected)




################################################################################
################################################################################
## AtomicCmdBuilder: finalize

def test_builder__finalized_call__simple_command():
    builder = AtomicCmdBuilder("echo")
    assert_equal(builder.finalized_call, ["echo"])

def test_builder__finalized_call__kwargs_are_instantiated():
    builder = AtomicCmdBuilder(("echo", "%(ARG1)s", "X=%(ARG2)s"),
                               ARG1 = "/foo/bar",
                               ARG2 = "zod")
    assert_equal(builder.finalized_call, ["echo", "/foo/bar", "X=zod"])

def test_builder__finalized_call__kwargs_are_instantiated__with_temp_dir():
    builder = AtomicCmdBuilder(("echo", "%(ARG)s", "%(TEMP_DIR)s"),
                               ARG = "/foo/bar")
    assert_equal(builder.finalized_call, ["echo", "/foo/bar", "%(TEMP_DIR)"])

def test_builder__finalized_call__kwargs_are_instantiated__with_non_str_arg():
    builder = AtomicCmdBuilder(("echo", "%(ARG)s", 17),
                               ARG = "/foo/bar")
    assert_equal(builder.finalized_call, ["echo", "/foo/bar", "17"])


################################################################################
################################################################################
## AtomicCmdBuilder: finalize

def test_builder__finalize__returns_singleton():
    builder = AtomicCmdBuilder("echo")
    assert builder.finalize() is builder.finalize()

def test_builder__finalize__calls_atomiccmd():
    was_called = []
    class _AtomicCmdMock:
        def __init__(self, *args, **kwargs):
            assert_equal(args, (["echo", "-out", "%(OUT_FILE)s", "%(IN_FILE)s"],))
            assert_equal(kwargs, {"IN_FILE" : "/in/file", "OUT_FILE" : "/out/file", "set_cwd" : True})
            was_called.append(True)

    with Monkeypatch("pypeline.atomiccmd.builder.AtomicCmd", _AtomicCmdMock):
        builder = AtomicCmdBuilder("echo", set_cwd = True)
        builder.add_option("-out", "%(OUT_FILE)s")
        builder.add_value("%(IN_FILE)s")
        builder.set_kwargs(OUT_FILE = "/out/file",
                           IN_FILE  = "/in/file")

        builder.finalize()
        assert was_called


################################################################################
################################################################################
## AtomicCmdBuilder: add_multiple_options

def test_builder__add_multiple_options():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values)

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls",
                                "-i", "%(IN_FILE_01)s",
                                "-i", "%(IN_FILE_02)s"])


def test_builder__add_multiple_options_with_sep():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values, sep="=")

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls",
                                "-i=%(IN_FILE_01)s",
                                "-i=%(IN_FILE_02)s"])


def test_builder__add_multiple_options_with_template():
    values = ("file_a", "file_b")
    expected = {"OUT_BAM_1": "file_a", "OUT_BAM_2": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values, template="OUT_BAM_%i")

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls",
                                "-i", "%(OUT_BAM_1)s",
                                "-i", "%(OUT_BAM_2)s"])


def test_builder__add_multiple_options_with_template_fixed():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values)

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_raises(AtomicCmdBuilderError,
                  builder.add_multiple_options, "-i", values)


###############################################################################
###############################################################################
## AtomicCmdBuilder: add_multiple_options

def test_builder__add_multiple_values():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_values(values)

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls", "%(IN_FILE_01)s", "%(IN_FILE_02)s"])


def test_builder__add_multiple_values_with_template():
    values = ("file_a", "file_b")
    expected = {"OUT_BAM_1": "file_a", "OUT_BAM_2": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_values(values, template="OUT_BAM_%i")

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls", "%(OUT_BAM_1)s", "%(OUT_BAM_2)s"])


################################################################################
################################################################################
## AtomicJavaCmdBuilder

def test_java_builder__default__no_config():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar")
    assert_equal(builder.call, ["java", "-server", "-Xmx4g",
                                "-Djava.io.tmpdir=%(TEMP_DIR)s",
                                "-Djava.awt.headless=true",
                                "-XX:+UseSerialGC",
                                "-jar", "%(AUX_JAR)s"])

def test_java_builder__defaults__call():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar", temp_root = "/disk/tmp")
    assert_equal(builder.call, ["java", "-server", "-Xmx4g",
                                "-Djava.io.tmpdir=/disk/tmp",
                                "-Djava.awt.headless=true",
                                "-XX:+UseSerialGC",
                                "-jar", "%(AUX_JAR)s"])

def test_java_builder__defaults__kwargs():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar")
    assert_equal(builder.kwargs, {"AUX_JAR": "/path/Foo.jar",
                                  "CHECK_JRE": JAVA_VERSIONS[(1, 6)]})

def test_java_builder__multithreaded_gc():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar", temp_root = "/disk/tmp", gc_threads = 3)
    assert_equal(builder.call, ["java", "-server", "-Xmx4g",
                                "-Djava.io.tmpdir=/disk/tmp",
                                "-Djava.awt.headless=true",
                                "-XX:ParallelGCThreads=3",
                                "-jar", "%(AUX_JAR)s"])

def test_java_builder__multithreaded_gc__zero_or_negative_threads():
    assert_raises(ValueError, AtomicJavaCmdBuilder, "/path/Foo.jar", gc_threads = 0)
    assert_raises(ValueError, AtomicJavaCmdBuilder, "/path/Foo.jar", gc_threads = -1)

def test_java_builder__multithreaded_gc__non_int_threads():
    assert_raises(TypeError, AtomicJavaCmdBuilder, "/path/Foo.jar", gc_threads = "3")


def test_java_builder__kwargs():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar", set_cwd=True)
    assert_equal(builder.kwargs, {"AUX_JAR": "/path/Foo.jar",
                                  "set_cwd": True,
                                  "CHECK_JRE": JAVA_VERSIONS[(1, 6)]})



################################################################################
################################################################################
## AtomicMPICmdBuilder

def test_mpi_builder__defaults__str():
    builder = AtomicMPICmdBuilder("ls")
    assert_equal(builder.call, ["ls"])
    assert_equal(builder.kwargs, {"EXEC_MPI" : "mpirun"})

def test_mpi_builder__multithreaded__str():
    builder = AtomicMPICmdBuilder("ls", threads = 3)
    assert_equal(builder.call, ["mpirun", "-n", 3, "ls"])
    assert_equal(builder.kwargs, {"EXEC_MAIN" : "ls"})

def test_mpi_builder__defaults__complex_cmd():
    builder = AtomicMPICmdBuilder(["python", "/foo/run.py"])
    assert_equal(builder.call, ["python", "/foo/run.py"])
    assert_equal(builder.kwargs, {"EXEC_MPI" : "mpirun"})

def test_mpi_builder__multithreaded__complex_cmd():
    builder = AtomicMPICmdBuilder(["python", "/foo/run.py"], threads = 3)
    assert_equal(builder.call, ["mpirun", "-n", 3, "python", "/foo/run.py"])
    assert_equal(builder.kwargs, {"EXEC_MAIN" : "python"})

def test_mpi_builder__kwargs():
    builder = AtomicMPICmdBuilder("ls", set_cwd = True)
    assert_equal(builder.kwargs, {"set_cwd" : True, "EXEC_MPI" : "mpirun"})

def test_mpi_builder__threads__zero_or_negative():
    assert_raises(ValueError, AtomicMPICmdBuilder, "ls", threads =  0)
    assert_raises(ValueError, AtomicMPICmdBuilder, "ls", threads = -1)

def test_mpi_builder__threads__non_int():
    assert_raises(TypeError, AtomicMPICmdBuilder, "ls",  threads = "3")



################################################################################
################################################################################
## create_customizable_cli_parameters

def test_custom_cli__single_named_arg():
    class SingleNamedArg:
        @create_customizable_cli_parameters
        def customize(cls, argument):
            return {}

    value = "A value"
    obj = SingleNamedArg.customize(value)
    assert_equal(obj.argument, value)


def test_custom_cli__adding_new_values():
    class SingleNamedArg:
        @create_customizable_cli_parameters
        def customize(cls):
            return {"dynamic": 12345}

    obj = SingleNamedArg.customize()
    assert_equal(obj.dynamic, 12345)


def test_custom_cli__multiple_named_args():
    class SingleNamedArg:
        @create_customizable_cli_parameters
        def customize(cls, first, second):
            return {}

    obj = SingleNamedArg.customize(123, 456)
    assert_equal(obj.first,  123)
    assert_equal(obj.second, 456)


def test_custom_cli__only_customize_is_valid_function_name():
    try:
        class ClassWithMisnamedFunction:
            @create_customizable_cli_parameters
            def not_called_customize(cls, first, second):
                return {}  # pragma: no coverage

        assert False, "ValueError not raised"  # pragma: no coverage
    except ValueError:
        pass


################################################################################
################################################################################
## use_customizable_cli_parameters





################################################################################
################################################################################
## apply_options


def test_apply_options__single_option__default_pred__set_when_pred_is_true():
    mock = flexmock()
    mock.should_receive('set_option').with_args('--foo', 17).once()
    apply_options(mock, {"--foo" : 17})

def test_apply_options__single_option__default_pred__ignore_when_pred_is_false():
    mock = flexmock()
    apply_options(mock, {"Other" : None})


def _user_pred(key):
    return key.startswith("FOO")

def test_apply_options__single_option__user_pred__set_when_pred_is_true():
    mock = flexmock()
    mock.should_receive('set_option').with_args('FOO_BAR', 17).once()
    apply_options(mock, {"FOO_BAR" : 17}, _user_pred)

def test_apply_options__single_option__user_pred__ignore_when_pred_is_false():
    mock = flexmock()
    apply_options(mock, {"BAR_FOO" : 17}, _user_pred)


def test_apply_options__single_option__boolean__set_when_value_is_true():
    mock = flexmock()
    mock.should_receive('set_option').with_args('-v')
    apply_options(mock, {"-v" : True})

def test_apply_options__single_option__boolean__set_when_value_is_none():
    mock = flexmock()
    mock.should_receive('set_option').with_args('-v')
    apply_options(mock, {"-v" : None})

def test_apply_options__single_option__boolean__pop_when_value_is_false():
    mock = flexmock()
    mock.should_receive('pop_option').with_args('-v')
    apply_options(mock, {"-v" : False})


def test_apply_options__multiple_option():
    mock = flexmock()
    mock.should_receive('add_option').with_args('--foo', 3).once()
    mock.should_receive('add_option').with_args('--foo', 17).once()
    apply_options(mock, {"--foo" : [3, 17]})


def test_apply_options__boolean_and_none_is_single_value_only():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, {"--foo" : [True]})
    assert_raises(TypeError, apply_options, mock, {"--foo" : [False]})
    assert_raises(TypeError, apply_options, mock, {"--foo" : [None]})



def test_apply_options__unexpected_types_in_values():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, {"--foo" : object()})
    assert_raises(TypeError, apply_options, mock, {"--foo" : iter([])})
    assert_raises(TypeError, apply_options, mock, {"--foo" : {}})
    assert_raises(TypeError, apply_options, mock, {"--foo" : set()})

def test_apply_options__non_string_types_in_keys():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, {1 : 17})
    assert_raises(TypeError, apply_options, mock, {("foo",) : 17})

def test_apply_options__not_dict_like():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, None)
    assert_raises(TypeError, apply_options, mock, [1, 2, 3])
<commit_msg>Update tests with new arg. order.<commit_after>#!/usr/bin/python
#
# Copyright (c) 2012 <NAME> <<EMAIL>>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# pylint: disable=C0103

from flexmock import flexmock
from nose.tools import assert_equal, assert_raises

from pypeline.common.testing import Monkeypatch

from pypeline.atomiccmd.builder import \
    AtomicCmdBuilder, \
    AtomicCmdBuilderError, \
    AtomicJavaCmdBuilder, \
    AtomicMPICmdBuilder, \
    apply_options, \
    use_customizable_cli_parameters, \
    create_customizable_cli_parameters, \
    JAVA_VERSIONS



################################################################################
################################################################################
## AtomicCmdBuilder: Constructor


def test_builder__simple__call():
    builder = AtomicCmdBuilder(["ls"])
    assert_equal(builder.call, ["ls"])

def test_builder__simple__str():
    builder = AtomicCmdBuilder("ls")
    assert_equal(builder.call, ["ls"])

def test_builder__simple__iterable():
    builder = AtomicCmdBuilder(iter(["ls"]))
    assert_equal(builder.call, ["ls"])

def test_builder__complex():
    builder = AtomicCmdBuilder(["java", "jar", "/a/jar"])
    assert_equal(builder.call, ["java", "jar", "/a/jar"])

def test_builder__kwargs__empty():
    builder = AtomicCmdBuilder(["ls"])
    assert_equal(builder.kwargs, {})

def test_builder__kwargs():
    expected = {"IN_FILE"  : "/abc/def.txt",
                "OUT_FILE" : "/etc/fstab"}
    builder = AtomicCmdBuilder(["ls"], **expected)
    assert_equal(builder.kwargs, expected)

def test_builder__kwargs__set_cwd():
    builder = AtomicCmdBuilder(["ls"], set_cwd = True)
    assert_equal(builder.kwargs, {"set_cwd" : True})



################################################################################
################################################################################
## AtomicCmdBuilder: set_option


def test_builder__set_option():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-name", "*.txt")
    assert_equal(builder.call, ["find", "-name", "*.txt"])

def test_builder__set_option__overwrite():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-name", "*.txt", fixed = False)
    builder.set_option("-name", "*.bat")
    assert_equal(builder.call, ["find", "-name", "*.bat"])

def test_builder__set_option__overwrite_fixed():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-name", "*.txt")
    assert_raises(AtomicCmdBuilderError, builder.set_option, "-name", "*.bat")




################################################################################
################################################################################
## AtomicCmdBuilder: add_option

def test_builder__add_option():
    builder = AtomicCmdBuilder("find")
    builder.add_option("-name", "*.txt")
    assert_equal(builder.call, ["find", "-name", "*.txt"])

def test_builder__add_option__overwrite():
    builder = AtomicCmdBuilder("find")
    builder.add_option("-name", "*.txt")
    builder.add_option("-or")
    builder.add_option("-name", "*.bat")
    assert_equal(builder.call, ["find", "-name", "*.txt", "-or", "-name", "*.bat"])



################################################################################
################################################################################
## AtomicCmdBuilder: add_option / set_option common tests


def test_builder__add_or_set_option__without_value():
    def _do_test_builder__add_or_set_option__without_value(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-delete")
        assert_equal(builder.call, ["find", "-delete"])
    yield _do_test_builder__add_or_set_option__without_value, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__without_value, AtomicCmdBuilder.set_option


def test_builder__add_or_set_option__with_sep():
    def _do_test_builder__add_or_set_option__with_sep(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", "0", sep = "=")
        assert_equal(builder.call, ["find", "-size=0"])
    yield _do_test_builder__add_or_set_option__with_sep, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__with_sep, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__with_non_str_value():
    def _do_test_test_builder__add_or_set_option__with_non_str_value(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", 0)
        assert_equal(builder.call, ["find", "-size", 0])
    yield _do_test_test_builder__add_or_set_option__with_non_str_value, AtomicCmdBuilder.add_option
    yield _do_test_test_builder__add_or_set_option__with_non_str_value, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__add_and_set():
    def _do_test_builder__add_or_set_option__add_and_set(setter_1, setter_2):
        builder = AtomicCmdBuilder("find")
        setter_1(builder, "-name", "*.txt")
        assert_raises(AtomicCmdBuilderError, setter_2, builder, "-name", "*.bat")
    yield _do_test_builder__add_or_set_option__add_and_set, AtomicCmdBuilder.set_option, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__add_and_set, AtomicCmdBuilder.add_option, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__with_non_str_key():
    def _do_test_builder__add_or_set_option__with_non_str_key(setter):
        builder = AtomicCmdBuilder("find")
        assert_raises(TypeError, setter, builder, 7913, "True")
    yield _do_test_builder__add_or_set_option__with_non_str_key, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__with_non_str_key, AtomicCmdBuilder.set_option

def test_builder__add_or_set_option__after_finalize():
    def _do_test_builder__add_or_set_option__after_finalize(setter):
        builder = AtomicCmdBuilder("find")
        builder.finalize()
        assert_raises(AtomicCmdBuilderError, setter, builder, "-size", "1")
    yield _do_test_builder__add_or_set_option__after_finalize, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__after_finalize, AtomicCmdBuilder.set_option


def test_builder__add_or_set_option__empty_key():
    def _do_test_builder__add_or_set_option__empty_key(setter):
        builder = AtomicCmdBuilder("find")
        assert_raises(KeyError, setter, builder, "", "1")
    yield _do_test_builder__add_or_set_option__empty_key, AtomicCmdBuilder.add_option
    yield _do_test_builder__add_or_set_option__empty_key, AtomicCmdBuilder.set_option



################################################################################
################################################################################
## AtomicCmdBuilder: pop_option

def test_builder__pop_option():
    def _do_test_builder__pop_option(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", "0", fixed = False)
        builder.pop_option("-size")
        assert_equal(builder.call, ["find"])
    yield _do_test_builder__pop_option, AtomicCmdBuilder.set_option
    yield _do_test_builder__pop_option, AtomicCmdBuilder.add_option


def test_builder__pop_option__last_option():
    builder = AtomicCmdBuilder("find")
    builder.add_option("-size", "0", fixed = False)
    builder.add_option("-size", "1", fixed = False)
    builder.pop_option("-size")
    assert_equal(builder.call, ["find", "-size", "0"])

def test_builder__pop_option__different_options():
    def _do_test_builder__pop_option(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-empty", fixed = False)
        setter(builder, "-size", "1", fixed = False)
        setter(builder, "-name", "*.txt", fixed = False)
        builder.pop_option("-size")
        assert_equal(builder.call, ["find", "-empty", "-name", "*.txt"])
    yield _do_test_builder__pop_option, AtomicCmdBuilder.set_option
    yield _do_test_builder__pop_option, AtomicCmdBuilder.add_option



def test_builder__pop_option__is_fixed():
    def _do_test_builder__pop_option__is_fixed(setter):
        builder = AtomicCmdBuilder("find")
        setter(builder, "-size", "0")
        assert_raises(AtomicCmdBuilderError, builder.pop_option, "-size")
    yield _do_test_builder__pop_option__is_fixed, AtomicCmdBuilder.set_option
    yield _do_test_builder__pop_option__is_fixed, AtomicCmdBuilder.add_option

def test_builder__pop_option__empty():
    builder = AtomicCmdBuilder("find")
    assert_raises(KeyError, builder.pop_option, "-size")

def test_builder__pop_option__missing_key():
    builder = AtomicCmdBuilder("find")
    builder.set_option("-size", 0)
    assert_raises(KeyError, builder.pop_option, "-isize")

def test_builder__pop_option__with_non_str_key():
    builder = AtomicCmdBuilder("find")
    assert_raises(TypeError, builder.pop_option, 7913)

def test_builder__pop_option__with_empty_key():
    builder = AtomicCmdBuilder("find")
    assert_raises(KeyError, builder.pop_option, "")




################################################################################
################################################################################
## AtomicCmdBuilder: add_value

def test_builder__add_value():
    builder = AtomicCmdBuilder("ls")
    builder.add_value("%(IN_FILE)s")
    assert_equal(builder.call, ["ls", "%(IN_FILE)s"])


def test_builder__add_value__two_values():
    builder = AtomicCmdBuilder("ls")
    builder.add_value("%(IN_FILE)s")
    builder.add_value("%(OUT_FILE)s")
    assert_equal(builder.call, ["ls", "%(IN_FILE)s", "%(OUT_FILE)s"])




################################################################################
################################################################################
## AtomicCmdBuilder: set_kwargs


def test_builder__set_kwargs__called_once():
    expected = {"IN_PATH" : "/a/b/", "OUT_PATH" : "/dst/file"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(**expected)
    assert_equal(builder.kwargs, expected)

def test_builder__set_kwargs__called_twice():
    expected = {"IN_PATH" : "/a/b/", "OUT_PATH" : "/dst/file"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(OUT_PATH = "/dst/file")
    builder.set_kwargs(IN_PATH = "/a/b/")
    assert_equal(builder.kwargs, expected)

def test_builder__set_kwargs__atomiccmdbuilder():
    mock = flexmock(AtomicCmdBuilder("true"))
    mock.should_receive('finalize').and_return("finalized!")
    builder = AtomicCmdBuilder("ls", IN_BUILDER = mock)
    assert_equal(builder.kwargs, {"IN_BUILDER" : "finalized!"})

def test_builder__set_kwargs__after_finalize():
    expected = {"IN_PATH" : "/a/b/"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(IN_PATH = "/a/b/")
    builder.finalize()
    assert_raises(AtomicCmdBuilderError, builder.set_kwargs, OUT_PATH = "/dst/file")
    assert_equal(builder.kwargs, expected)

def test_builder__set__kwargs__overwriting():
    expected = {"IN_PATH" : "/a/b/"}
    builder = AtomicCmdBuilder("echo")
    builder.set_kwargs(IN_PATH = "/a/b/")
    assert_raises(AtomicCmdBuilderError, builder.set_kwargs, IN_PATH = "/dst/file")
    assert_equal(builder.kwargs, expected)




################################################################################
################################################################################
## AtomicCmdBuilder: finalize

def test_builder__finalized_call__simple_command():
    builder = AtomicCmdBuilder("echo")
    assert_equal(builder.finalized_call, ["echo"])

def test_builder__finalized_call__kwargs_are_instantiated():
    builder = AtomicCmdBuilder(("echo", "%(ARG1)s", "X=%(ARG2)s"),
                               ARG1 = "/foo/bar",
                               ARG2 = "zod")
    assert_equal(builder.finalized_call, ["echo", "/foo/bar", "X=zod"])

def test_builder__finalized_call__kwargs_are_instantiated__with_temp_dir():
    builder = AtomicCmdBuilder(("echo", "%(ARG)s", "%(TEMP_DIR)s"),
                               ARG = "/foo/bar")
    assert_equal(builder.finalized_call, ["echo", "/foo/bar", "%(TEMP_DIR)"])

def test_builder__finalized_call__kwargs_are_instantiated__with_non_str_arg():
    builder = AtomicCmdBuilder(("echo", "%(ARG)s", 17),
                               ARG = "/foo/bar")
    assert_equal(builder.finalized_call, ["echo", "/foo/bar", "17"])


################################################################################
################################################################################
## AtomicCmdBuilder: finalize

def test_builder__finalize__returns_singleton():
    builder = AtomicCmdBuilder("echo")
    assert builder.finalize() is builder.finalize()

def test_builder__finalize__calls_atomiccmd():
    was_called = []
    class _AtomicCmdMock:
        def __init__(self, *args, **kwargs):
            assert_equal(args, (["echo", "-out", "%(OUT_FILE)s", "%(IN_FILE)s"],))
            assert_equal(kwargs, {"IN_FILE" : "/in/file", "OUT_FILE" : "/out/file", "set_cwd" : True})
            was_called.append(True)

    with Monkeypatch("pypeline.atomiccmd.builder.AtomicCmd", _AtomicCmdMock):
        builder = AtomicCmdBuilder("echo", set_cwd = True)
        builder.add_option("-out", "%(OUT_FILE)s")
        builder.add_value("%(IN_FILE)s")
        builder.set_kwargs(OUT_FILE = "/out/file",
                           IN_FILE  = "/in/file")

        builder.finalize()
        assert was_called


################################################################################
################################################################################
## AtomicCmdBuilder: add_multiple_options

def test_builder__add_multiple_options():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values)

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls",
                                "-i", "%(IN_FILE_01)s",
                                "-i", "%(IN_FILE_02)s"])


def test_builder__add_multiple_options_with_sep():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values, sep="=")

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls",
                                "-i=%(IN_FILE_01)s",
                                "-i=%(IN_FILE_02)s"])


def test_builder__add_multiple_options_with_template():
    values = ("file_a", "file_b")
    expected = {"OUT_BAM_1": "file_a", "OUT_BAM_2": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values, template="OUT_BAM_%i")

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls",
                                "-i", "%(OUT_BAM_1)s",
                                "-i", "%(OUT_BAM_2)s"])


def test_builder__add_multiple_options_with_template_fixed():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_options("-i", values)

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_raises(AtomicCmdBuilderError,
                  builder.add_multiple_options, "-i", values)


###############################################################################
###############################################################################
## AtomicCmdBuilder: add_multiple_options

def test_builder__add_multiple_values():
    values = ("file_a", "file_b")
    expected = {"IN_FILE_01": "file_a", "IN_FILE_02": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_values(values)

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls", "%(IN_FILE_01)s", "%(IN_FILE_02)s"])


def test_builder__add_multiple_values_with_template():
    values = ("file_a", "file_b")
    expected = {"OUT_BAM_1": "file_a", "OUT_BAM_2": "file_b"}

    builder = AtomicCmdBuilder("ls")
    kwargs = builder.add_multiple_values(values, template="OUT_BAM_%i")

    assert_equal(kwargs, expected)
    assert_equal(builder.kwargs, expected)
    assert_equal(builder.call, ["ls", "%(OUT_BAM_1)s", "%(OUT_BAM_2)s"])


################################################################################
################################################################################
## AtomicJavaCmdBuilder

def test_java_builder__default__no_config():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar")
    assert_equal(builder.call, ["java",
                                "-server",
                                "-Djava.io.tmpdir=%(TEMP_DIR)s",
                                "-Djava.awt.headless=true",
                                "-Xmx4g",
                                "-XX:+UseSerialGC",
                                "-jar", "%(AUX_JAR)s"])

def test_java_builder__defaults__call():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar", temp_root = "/disk/tmp")
    assert_equal(builder.call, ["java",
                                "-server",
                                "-Djava.io.tmpdir=/disk/tmp",
                                "-Djava.awt.headless=true",
                                "-Xmx4g",
                                "-XX:+UseSerialGC",
                                "-jar", "%(AUX_JAR)s"])

def test_java_builder__defaults__kwargs():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar")
    assert_equal(builder.kwargs, {"AUX_JAR": "/path/Foo.jar",
                                  "CHECK_JRE": JAVA_VERSIONS[(1, 6)]})

def test_java_builder__multithreaded_gc():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar", temp_root = "/disk/tmp", gc_threads = 3)
    assert_equal(builder.call, ["java",
                                "-server",
                                "-Djava.io.tmpdir=/disk/tmp",
                                "-Djava.awt.headless=true",
                                "-Xmx4g",
                                "-XX:ParallelGCThreads=3",
                                "-jar", "%(AUX_JAR)s"])

def test_java_builder__multithreaded_gc__zero_or_negative_threads():
    assert_raises(ValueError, AtomicJavaCmdBuilder, "/path/Foo.jar", gc_threads = 0)
    assert_raises(ValueError, AtomicJavaCmdBuilder, "/path/Foo.jar", gc_threads = -1)

def test_java_builder__multithreaded_gc__non_int_threads():
    assert_raises(TypeError, AtomicJavaCmdBuilder, "/path/Foo.jar", gc_threads = "3")


def test_java_builder__kwargs():
    builder = AtomicJavaCmdBuilder("/path/Foo.jar", set_cwd=True)
    assert_equal(builder.kwargs, {"AUX_JAR": "/path/Foo.jar",
                                  "set_cwd": True,
                                  "CHECK_JRE": JAVA_VERSIONS[(1, 6)]})



################################################################################
################################################################################
## AtomicMPICmdBuilder

def test_mpi_builder__defaults__str():
    builder = AtomicMPICmdBuilder("ls")
    assert_equal(builder.call, ["ls"])
    assert_equal(builder.kwargs, {"EXEC_MPI" : "mpirun"})

def test_mpi_builder__multithreaded__str():
    builder = AtomicMPICmdBuilder("ls", threads = 3)
    assert_equal(builder.call, ["mpirun", "-n", 3, "ls"])
    assert_equal(builder.kwargs, {"EXEC_MAIN" : "ls"})

def test_mpi_builder__defaults__complex_cmd():
    builder = AtomicMPICmdBuilder(["python", "/foo/run.py"])
    assert_equal(builder.call, ["python", "/foo/run.py"])
    assert_equal(builder.kwargs, {"EXEC_MPI" : "mpirun"})

def test_mpi_builder__multithreaded__complex_cmd():
    builder = AtomicMPICmdBuilder(["python", "/foo/run.py"], threads = 3)
    assert_equal(builder.call, ["mpirun", "-n", 3, "python", "/foo/run.py"])
    assert_equal(builder.kwargs, {"EXEC_MAIN" : "python"})

def test_mpi_builder__kwargs():
    builder = AtomicMPICmdBuilder("ls", set_cwd = True)
    assert_equal(builder.kwargs, {"set_cwd" : True, "EXEC_MPI" : "mpirun"})

def test_mpi_builder__threads__zero_or_negative():
    assert_raises(ValueError, AtomicMPICmdBuilder, "ls", threads =  0)
    assert_raises(ValueError, AtomicMPICmdBuilder, "ls", threads = -1)

def test_mpi_builder__threads__non_int():
    assert_raises(TypeError, AtomicMPICmdBuilder, "ls",  threads = "3")



################################################################################
################################################################################
## create_customizable_cli_parameters

def test_custom_cli__single_named_arg():
    class SingleNamedArg:
        @create_customizable_cli_parameters
        def customize(cls, argument):
            return {}

    value = "A value"
    obj = SingleNamedArg.customize(value)
    assert_equal(obj.argument, value)


def test_custom_cli__adding_new_values():
    class SingleNamedArg:
        @create_customizable_cli_parameters
        def customize(cls):
            return {"dynamic": 12345}

    obj = SingleNamedArg.customize()
    assert_equal(obj.dynamic, 12345)


def test_custom_cli__multiple_named_args():
    class SingleNamedArg:
        @create_customizable_cli_parameters
        def customize(cls, first, second):
            return {}

    obj = SingleNamedArg.customize(123, 456)
    assert_equal(obj.first,  123)
    assert_equal(obj.second, 456)


def test_custom_cli__only_customize_is_valid_function_name():
    try:
        class ClassWithMisnamedFunction:
            @create_customizable_cli_parameters
            def not_called_customize(cls, first, second):
                return {}  # pragma: no coverage

        assert False, "ValueError not raised"  # pragma: no coverage
    except ValueError:
        pass


################################################################################
################################################################################
## use_customizable_cli_parameters





################################################################################
################################################################################
## apply_options


def test_apply_options__single_option__default_pred__set_when_pred_is_true():
    mock = flexmock()
    mock.should_receive('set_option').with_args('--foo', 17).once()
    apply_options(mock, {"--foo" : 17})

def test_apply_options__single_option__default_pred__ignore_when_pred_is_false():
    mock = flexmock()
    apply_options(mock, {"Other" : None})


def _user_pred(key):
    return key.startswith("FOO")

def test_apply_options__single_option__user_pred__set_when_pred_is_true():
    mock = flexmock()
    mock.should_receive('set_option').with_args('FOO_BAR', 17).once()
    apply_options(mock, {"FOO_BAR" : 17}, _user_pred)

def test_apply_options__single_option__user_pred__ignore_when_pred_is_false():
    mock = flexmock()
    apply_options(mock, {"BAR_FOO" : 17}, _user_pred)


def test_apply_options__single_option__boolean__set_when_value_is_true():
    mock = flexmock()
    mock.should_receive('set_option').with_args('-v')
    apply_options(mock, {"-v" : True})

def test_apply_options__single_option__boolean__set_when_value_is_none():
    mock = flexmock()
    mock.should_receive('set_option').with_args('-v')
    apply_options(mock, {"-v" : None})

def test_apply_options__single_option__boolean__pop_when_value_is_false():
    mock = flexmock()
    mock.should_receive('pop_option').with_args('-v')
    apply_options(mock, {"-v" : False})


def test_apply_options__multiple_option():
    mock = flexmock()
    mock.should_receive('add_option').with_args('--foo', 3).once()
    mock.should_receive('add_option').with_args('--foo', 17).once()
    apply_options(mock, {"--foo" : [3, 17]})


def test_apply_options__boolean_and_none_is_single_value_only():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, {"--foo" : [True]})
    assert_raises(TypeError, apply_options, mock, {"--foo" : [False]})
    assert_raises(TypeError, apply_options, mock, {"--foo" : [None]})



def test_apply_options__unexpected_types_in_values():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, {"--foo" : object()})
    assert_raises(TypeError, apply_options, mock, {"--foo" : iter([])})
    assert_raises(TypeError, apply_options, mock, {"--foo" : {}})
    assert_raises(TypeError, apply_options, mock, {"--foo" : set()})

def test_apply_options__non_string_types_in_keys():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, {1 : 17})
    assert_raises(TypeError, apply_options, mock, {("foo",) : 17})

def test_apply_options__not_dict_like():
    mock = flexmock()
    assert_raises(TypeError, apply_options, mock, None)
    assert_raises(TypeError, apply_options, mock, [1, 2, 3])

{'fraction_non_alphanumeric': 0.21418642366205884, 'fraction_numerical': 0.005483048884083713, 'mean_word_length': 4.613025574338969, 'pattern_counts': {'":': 36, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1356976', 'n_tokens_mistral': 16001, 'n_tokens_neox': 15222, 'n_words': 2581}