mirror of https://github.com/streamlink/streamlink
313 lines
9.8 KiB
Python
313 lines
9.8 KiB
Python
import argparse
|
|
|
|
import pytest
|
|
|
|
from streamlink.options import Argument, Arguments, Options
|
|
from streamlink.utils.args import comma_list_filter
|
|
|
|
|
|
class TestOptions:
|
|
@pytest.fixture()
|
|
def options(self):
|
|
return Options({
|
|
"a_default": "default",
|
|
"another-default": "default2",
|
|
})
|
|
|
|
def test_empty(self):
|
|
options = Options()
|
|
assert not options.defaults
|
|
assert not options.options
|
|
|
|
def test_set(self, options: Options):
|
|
assert options.get("a_default") == "default"
|
|
assert options.get("non_existing") is None
|
|
|
|
options.set("an_option", "option")
|
|
assert options.get("an_option") == "option"
|
|
|
|
def test_update(self, options: Options):
|
|
assert options.get("a_default") == "default"
|
|
assert options.get("non_existing") is None
|
|
|
|
options.update({"an_option": "option"})
|
|
assert options.get("an_option") == "option"
|
|
|
|
def test_name_normalised(self, options: Options):
|
|
assert options.get("a_default") == "default"
|
|
assert options.get("a-default") == "default"
|
|
assert options.get("another-default") == "default2"
|
|
assert options.get("another_default") == "default2"
|
|
|
|
def test_clear(self, options: Options):
|
|
assert options.get("a_default") == "default"
|
|
options.set("a_default", "other")
|
|
assert options.get("a_default") == "other"
|
|
options.clear()
|
|
assert options.get("a_default") == "default"
|
|
|
|
|
|
class TestMappedOptions:
|
|
class MappedOptions(Options):
|
|
def _get_uppercase(self, key):
|
|
return self.get_explicit(key.upper())
|
|
|
|
def _get_add(self, key):
|
|
return int(self.get_explicit(key)) + 1
|
|
|
|
def _set_uppercase(self, key, value):
|
|
self.set_explicit(key.upper(), value)
|
|
|
|
def _set_add(self, key, value):
|
|
self.set_explicit(key, int(value) + 1)
|
|
|
|
_MAP_GETTERS = {
|
|
"foo-bar": _get_uppercase,
|
|
"baz": _get_add,
|
|
}
|
|
|
|
_MAP_SETTERS = {
|
|
"foo-bar": _set_uppercase,
|
|
"baz": _set_add,
|
|
}
|
|
|
|
@pytest.fixture()
|
|
def options(self):
|
|
return self.MappedOptions({"foo-bar": 123, "baz": 100})
|
|
|
|
def test_mapped_key(self, options: MappedOptions):
|
|
assert options.get("foo-bar") is None
|
|
assert options.get("foo_bar") is None
|
|
assert options.get_explicit("foo-bar") == 123
|
|
assert options.get_explicit("foo_bar") == 123
|
|
assert options.get_explicit("FOO-BAR") is None
|
|
assert options.get_explicit("FOO_BAR") is None
|
|
|
|
options.set("foo-bar", 321)
|
|
assert options.get("foo-bar") == 321
|
|
assert options.get("foo_bar") == 321
|
|
assert options.get_explicit("foo-bar") == 123
|
|
assert options.get_explicit("foo_bar") == 123
|
|
assert options.get_explicit("FOO-BAR") == 321
|
|
assert options.get_explicit("FOO_BAR") == 321
|
|
|
|
def test_mapped_value(self, options: MappedOptions):
|
|
assert options.get("baz") == 101
|
|
assert options.get_explicit("baz") == 100
|
|
|
|
options.set("baz", 0)
|
|
assert options.get("baz") == 2
|
|
assert options.get_explicit("baz") == 1
|
|
|
|
def test_mutablemapping_methods(self, options: MappedOptions):
|
|
options["key"] = "value"
|
|
assert options["key"] == "value"
|
|
|
|
assert options["foo-bar"] is None
|
|
|
|
options["baz"] = 0
|
|
assert options["baz"] == 2
|
|
|
|
assert "foo-bar" in options
|
|
assert "qux" not in options
|
|
|
|
assert len(options) == 3
|
|
|
|
assert list(iter(options)) == ["foo-bar", "baz", "key"]
|
|
assert list(options.keys()) == ["foo-bar", "baz", "key"]
|
|
assert list(options.values()) == [123, 1, "value"]
|
|
assert list(options.items()) == [("foo-bar", 123), ("baz", 1), ("key", "value")]
|
|
|
|
|
|
class TestArgument:
|
|
def test_name(self):
|
|
assert Argument("test-arg").argument_name("plugin") == "--plugin-test-arg"
|
|
assert Argument("test-arg").namespace_dest("plugin") == "plugin_test_arg"
|
|
assert Argument("test-arg").dest == "test_arg"
|
|
|
|
def test_name_plugin(self):
|
|
assert Argument("test-arg").argument_name("test_plugin") == "--test-plugin-test-arg"
|
|
assert Argument("test-arg").namespace_dest("test_plugin") == "test_plugin_test_arg"
|
|
assert Argument("test-arg").dest == "test_arg"
|
|
|
|
def test_name_override(self):
|
|
assert Argument("test", argument_name="override-name").argument_name("plugin") == "--override-name"
|
|
assert Argument("test", argument_name="override-name").namespace_dest("plugin") == "override_name"
|
|
assert Argument("test", argument_name="override-name").dest == "test"
|
|
|
|
def test_default(self):
|
|
arg = Argument("test", default=123)
|
|
assert arg.default == 123
|
|
with pytest.raises(AttributeError):
|
|
# noinspection PyPropertyAccess
|
|
arg.default = 456
|
|
|
|
def test_help_suppress(self):
|
|
argA = Argument("test", help="test")
|
|
argB = Argument("test", help=argparse.SUPPRESS)
|
|
argC = Argument("test", help=f"{argparse.SUPPRESS[:1]}{argparse.SUPPRESS[1:]}")
|
|
assert argA.help is not argparse.SUPPRESS
|
|
assert id(argB.help) == id(argparse.SUPPRESS)
|
|
assert id(argC.help) == id(argparse.SUPPRESS)
|
|
|
|
def test_options(self):
|
|
arg = Argument(
|
|
"test",
|
|
action="append",
|
|
nargs=2,
|
|
default=(0, 0),
|
|
type=int,
|
|
choices=[1, 2, 3],
|
|
required=True,
|
|
help=argparse.SUPPRESS,
|
|
metavar=("ONE", "TWO"),
|
|
dest="dest",
|
|
requires=["other"],
|
|
prompt="Test!",
|
|
sensitive=False,
|
|
argument_name=None,
|
|
)
|
|
assert arg.options == {
|
|
"action": "append",
|
|
"nargs": 2,
|
|
"default": (0, 0),
|
|
"type": int,
|
|
"choices": (1, 2, 3),
|
|
"help": argparse.SUPPRESS,
|
|
"metavar": ("ONE", "TWO"),
|
|
"dest": "dest",
|
|
}
|
|
|
|
arg = Argument(
|
|
"test",
|
|
action="store_const",
|
|
const=123,
|
|
)
|
|
assert arg.options == {
|
|
"action": "store_const",
|
|
"const": 123,
|
|
}
|
|
|
|
def test_equality(self):
|
|
a1 = Argument(
|
|
"test",
|
|
action="append",
|
|
nargs=2,
|
|
default=("0", "0"),
|
|
type=comma_list_filter(["1", "2", "3"], unique=True),
|
|
choices=["1", "2", "3"],
|
|
required=True,
|
|
help=argparse.SUPPRESS,
|
|
metavar=("ONE", "TWO"),
|
|
dest="dest",
|
|
requires=["other"],
|
|
prompt="Test!",
|
|
sensitive=False,
|
|
argument_name="custom-name",
|
|
)
|
|
a2 = Argument(
|
|
"test",
|
|
action="append",
|
|
nargs=2,
|
|
default=("0", "0"),
|
|
type=comma_list_filter(["1", "2", "3"], unique=True),
|
|
choices=["1", "2", "3"],
|
|
required=True,
|
|
help=argparse.SUPPRESS,
|
|
metavar=("ONE", "TWO"),
|
|
dest="dest",
|
|
requires=["other"],
|
|
prompt="Test!",
|
|
sensitive=False,
|
|
argument_name="custom-name",
|
|
)
|
|
a3 = Argument("foo")
|
|
assert a1 is not a2
|
|
assert a1 == a2
|
|
assert a1 != a3
|
|
assert a2 != a3
|
|
|
|
|
|
class TestArguments:
|
|
def test_getter(self):
|
|
test1 = Argument("test1")
|
|
test2 = Argument("test2")
|
|
args = Arguments(test1, test2)
|
|
|
|
assert args.get("test1") == test1
|
|
assert args.get("test2") == test2
|
|
assert args.get("test3") is None
|
|
|
|
def test_iter(self):
|
|
test1 = Argument("test1")
|
|
test2 = Argument("test2")
|
|
args = Arguments(test1, test2)
|
|
|
|
i_args = iter(args)
|
|
assert next(i_args) == test1
|
|
assert next(i_args) == test2
|
|
|
|
def test_add(self):
|
|
test1 = Argument("test1")
|
|
test2 = Argument("test2")
|
|
test3 = Argument("test3")
|
|
args = Arguments(test1, test2)
|
|
|
|
assert list(iter(args)) == [test1, test2]
|
|
args.add(test3)
|
|
assert list(iter(args)) == [test3, test1, test2]
|
|
|
|
def test_equality(self):
|
|
test1 = Arguments()
|
|
test1.add(Argument("testA"))
|
|
test1.add(Argument("testB"))
|
|
test2 = Arguments(Argument("testB"), Argument("testA"))
|
|
test3 = Arguments(Argument("testA"), Argument("testB"))
|
|
assert test1 == test2
|
|
assert test1 != test3
|
|
assert test2 != test3
|
|
|
|
def test_requires(self):
|
|
test1 = Argument("test1", requires="test2")
|
|
test2 = Argument("test2", requires="test3")
|
|
test3 = Argument("test3")
|
|
args = Arguments(test1, test2, test3)
|
|
|
|
assert list(args.requires("test1")) == [test2, test3]
|
|
|
|
def test_requires_invalid(self):
|
|
test1 = Argument("test1", requires="test2")
|
|
args = Arguments(test1)
|
|
|
|
with pytest.raises(KeyError) as cm:
|
|
list(args.requires("test1"))
|
|
assert cm.value.args[0] == "test2 is not a valid argument for this plugin"
|
|
|
|
@pytest.mark.parametrize("args", [
|
|
pytest.param(
|
|
Arguments(
|
|
Argument("test1", requires="test2"),
|
|
Argument("test2", requires="test1"),
|
|
),
|
|
id="Cycle",
|
|
),
|
|
pytest.param(
|
|
Arguments(
|
|
Argument("test1", requires="test2"),
|
|
Argument("test2", requires="test3"),
|
|
Argument("test3", requires="test1"),
|
|
),
|
|
id="Cycle deep",
|
|
),
|
|
pytest.param(
|
|
Arguments(
|
|
Argument("test1", requires="test1"),
|
|
),
|
|
id="Cycle self",
|
|
),
|
|
])
|
|
def test_requires_cycle(self, args: Arguments):
|
|
with pytest.raises(RuntimeError) as cm:
|
|
list(args.requires("test1"))
|
|
assert cm.value.args[0] == "cycle detected in plugin argument config"
|