Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ commands = [

[tool.tox.env.mypy]
description = "Run type checking tool mypy"
deps = ["mypy"]
# pytest-stub required for type hints to be available
deps = ["mypy", "pytest-stub"]
commands = [
["mypy", "--version"],
["mypy", "{posargs:varlink}"]
Expand Down
249 changes: 150 additions & 99 deletions varlink/tests/test_scanner.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import unittest
import pytest

import varlink


class TestScanner(unittest.TestCase):
def test_scanner_1(self):
interface = varlink.Interface("""# Example Varlink service
def test_scanner_1() -> None:
interface = varlink.Interface("""# Example Varlink service
interface org.example.more

# Enum, returning either start, progress or end
Expand Down Expand Up @@ -35,105 +34,157 @@ def test_scanner_1(self):

error ActionFailed (reason: ?ErrorChain)
""")
self.assertEqual(interface.name, "org.example.more")
self.assertIsNotNone(interface.get_method("Ping"))
self.assertIsNotNone(interface.get_method("TestMore"))
self.assertIsNotNone(interface.get_method("TestMap"))
self.assertIsNotNone(interface.get_method("StopServing"))
self.assertIsInstance(interface.members.get("ActionFailed"), varlink.scanner._Error)
self.assertIsInstance(interface.members.get("State"), varlink.scanner._Alias)

def test_doubleoption(self):
interface = None
try:
interface = varlink.Interface("""
assert interface.name == "org.example.more"
assert interface.get_method("Ping") is not None
assert interface.get_method("TestMore") is not None
assert interface.get_method("TestMap") is not None
assert interface.get_method("StopServing") is not None
assert isinstance(interface.members.get("ActionFailed"), varlink.scanner._Error)
assert isinstance(interface.members.get("State"), varlink.scanner._Alias)


def test_doubleoption() -> None:
interface = None
try:
interface = varlink.Interface("""
interface org.example.doubleoption
method Foo(a: ??string) -> ()
""")
except SyntaxError:
pass
except SyntaxError:
pass

self.assertIsNone(interface)
assert interface is None

def test_complex(self):
interface = varlink.Interface("""
interface org.example.complex


def test_complex() -> None:
interface = varlink.Interface("""
interface org.example.complex

type TypeEnum ( a, b, c )

type TypeFoo (
bool: bool,
int: int,
float: float,
string: ?string,
enum: ?[]( foo, bar, baz ),
type: ?TypeEnum,
anon: ( foo: bool, bar: int, baz: [](a: int, b: int) ),
object: object
)

method Foo(a: (b: bool, c: int), foo: TypeFoo) -> (a: [](b: bool, c: int), foo: TypeFoo)

error ErrorFoo (a: (b: bool, c: int), foo: TypeFoo)
""")

assert interface.name == "org.example.complex"
assert interface.get_method("Foo") is not None
assert isinstance(interface.members.get("ErrorFoo"), varlink.scanner._Error)
assert isinstance(interface.members.get("TypeEnum"), varlink.scanner._Alias)


invalid_interfacenames = [
"interface .a.b.c\nmethod F()->()",
"interface com.-example.leadinghyphen\nmethod F()->()",
"interface com.example-.danglinghyphen-\nmethod F()->()",
"interface co9.example.number-toplevel\nmethod F()->()",
"interface 1om.example.number-toplevel\nmethod F()->()",
"interface ab\nmethod F()->()",
"interface .a.b.c\nmethod F()->()",
"interface a.b.c.\nmethod F()->()",
"interface a..b.c\nmethod F()->()",
"interface 1.b.c\nmethod F()->()",
"interface 8a.0.0\nmethod F()->()",
"interface -a.b.c\nmethod F()->()",
"interface a.b.c-\nmethod F()->()",
"interface a.b-.c-\nmethod F()->()",
"interface a.-b.c-\nmethod F()->()",
"interface a.-.c\nmethod F()->()",
"interface a.*.c\nmethod F()->()",
"interface a.?\nmethod F()->()",
]


@pytest.mark.parametrize("description", invalid_interfacenames)
def test_interfacename_invalid(description) -> None:
with pytest.raises(SyntaxError):
varlink.Interface(description)


valid_interfacenames = [
"interface a.b\nmethod F()->()",
"interface a.b.c\nmethod F()->()",
"interface a.1\nmethod F()->()",
"interface a.0.0\nmethod F()->()",
"interface org.varlink.service\nmethod F()->()",
"interface com.example.0example\nmethod F()->()",
"interface com.example.example-dash\nmethod F()->()",
"interface xn--lgbbat1ad8j.example.algeria\nmethod F()->()",
"interface xn--c1yn36f.xn--c1yn36f.xn--c1yn36f\nmethod F()->()",
]


@pytest.mark.parametrize("description", valid_interfacenames)
def test_interfacename_valid(description) -> None:
assert varlink.Interface(description).name is not None


def test_bad_types() -> None:
interface = varlink.Interface("""
interface org.example.testerrors
type TypeEnum ( a, b, c )

type TypeFoo (
bool: bool,
int: int,
float: float,
string: ?string,
enum: ?[]( foo, bar, baz ),
type: ?TypeEnum,
anon: ( foo: bool, bar: int, baz: [](a: int, b: int) ),
object: object
)

method Foo(a: (b: bool, c: int), foo: TypeFoo) -> (a: [](b: bool, c: int), foo: TypeFoo)

error ErrorFoo (a: (b: bool, c: int), foo: TypeFoo)
type TypeDict (dict: [string]string)

method Foo(param: TypeEnum) -> ()
method Bar(param: TypeDict) -> ()
""")
self.assertEqual(interface.name, "org.example.complex")
self.assertIsNotNone(interface.get_method("Foo"))
self.assertIsInstance(interface.members.get("ErrorFoo"), varlink.scanner._Error)
self.assertIsInstance(interface.members.get("TypeEnum"), varlink.scanner._Alias)

def test_interfacename(self):
self.assertRaises(SyntaxError, varlink.Interface, "interface .a.b.c\nmethod F()->()")
self.assertRaises(
SyntaxError, varlink.Interface, "interface com.-example.leadinghyphen\nmethod F()->()"
)
self.assertRaises(
SyntaxError, varlink.Interface, "interface com.example-.danglinghyphen-\nmethod F()->()"
)
self.assertRaises(
SyntaxError, varlink.Interface, "interface co9.example.number-toplevel\nmethod F()->()"
)
self.assertRaises(
SyntaxError, varlink.Interface, "interface 1om.example.number-toplevel\nmethod F()->()"
)
self.assertRaises(SyntaxError, varlink.Interface, "interface ab\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface .a.b.c\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a.b.c.\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a..b.c\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface 1.b.c\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface 8a.0.0\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface -a.b.c\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a.b.c-\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a.b-.c-\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a.-b.c-\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a.-.c\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a.*.c\nmethod F()->()")
self.assertRaises(SyntaxError, varlink.Interface, "interface a.?\nmethod F()->()")
self.assertIsNotNone(varlink.Interface("interface a.b\nmethod F()->()").name)
self.assertIsNotNone(varlink.Interface("interface a.b.c\nmethod F()->()").name)
self.assertIsNotNone(varlink.Interface("interface a.1\nmethod F()->()").name)
self.assertIsNotNone(varlink.Interface("interface a.0.0\nmethod F()->()").name)
self.assertIsNotNone(varlink.Interface("interface org.varlink.service\nmethod F()->()").name)
self.assertIsNotNone(varlink.Interface("interface com.example.0example\nmethod F()->()").name)
self.assertIsNotNone(varlink.Interface("interface com.example.example-dash\nmethod F()->()").name)
self.assertIsNotNone(
varlink.Interface("interface xn--lgbbat1ad8j.example.algeria\nmethod F()->()").name
)
self.assertIsNotNone(
varlink.Interface("interface xn--c1yn36f.xn--c1yn36f.xn--c1yn36f\nmethod F()->()").name
)

def test_bad_types(self):
interface = varlink.Interface("""
interface org.example.testerrors
type TypeEnum ( a, b, c )
type TypeDict (dict: [string]string)

method Foo(param: TypeEnum) -> ()
method Bar(param: TypeDict) -> ()
""")
foo = interface.get_method("Foo")
with self.assertRaises(varlink.InvalidParameter):
interface.filter_params("test.call", foo.in_type, False, (), {"param": "d"})
bar = interface.get_method("Bar")
with self.assertRaises(varlink.InvalidParameter):
interface.filter_params("test.call", bar.in_type, False, (), {"param": {"dict": [1, 2, 3]}})
foo = interface.get_method("Foo")
with pytest.raises(varlink.InvalidParameter):
interface.filter_params("test.call", foo.in_type, False, (), {"param": "d"})

bar = interface.get_method("Bar")
with pytest.raises(varlink.InvalidParameter):
interface.filter_params("test.call", bar.in_type, False, (), {"param": {"dict": [1, 2, 3]}})


def test_method_not_found() -> None:
interface = varlink.Interface("""
interface org.example.testerrors
""")

with pytest.raises(varlink.MethodNotFound):
interface.get_method("Bar")


def test_struct_errors() -> None:
missing_colon_after_name = """
interface org.example.teststruct

type TypeStruct ( struct ?[](first: int, second: string) )
"""

with pytest.raises(SyntaxError, match="after 'struct'"):
varlink.Interface(missing_colon_after_name)

missing_colon_in_struct = """
interface org.example.teststruct

type MyType (
nullable_array_struct: ?[](first: int, second string)
)
method Start() -> (client_id: string)
"""
with pytest.raises(SyntaxError, match="after 'second'"):
varlink.Interface(missing_colon_in_struct)


def test_unexpected() -> None:
invalid = """
interface org.example.unexpected

invalid
"""

with pytest.raises(SyntaxError, match="expected type, method, or error"):
varlink.Interface(invalid)