예제 #1
0
def test_dict_specializers(polar, qvar, qeval, query):
    class Animal:
        def __init__(self, species=None, genus=None, family=None):
            self.genus = genus
            self.species = species

    polar.register_class(Animal)

    rules = """
    what_is(_: {genus: "canis"}, res) if res = "canine";
    what_is(_: {species: "canis lupus", genus: "canis"}, res) if res = "wolf";
    what_is(_: {species: "canis familiaris", genus: "canis"}, res) if res = "dog";
    """
    polar.load_str(rules)

    wolf = 'new Animal(species: "canis lupus", genus: "canis", family: "canidae")'
    dog = 'new Animal(species: "canis familiaris", genus: "canis", family: "canidae")'
    canine = 'new Animal(genus: "canis", family: "canidae")'

    assert len(query(f"what_is({wolf}, res)")) == 2
    assert len(query(f"what_is({dog}, res)")) == 2
    assert len(query(f"what_is({canine}, res)")) == 1

    assert qvar(f"what_is({wolf}, res)", "res") == ["wolf", "canine"]
    assert qvar(f"what_is({dog}, res)", "res") == ["dog", "canine"]
    assert qvar(f"what_is({canine}, res)", "res") == ["canine"]
예제 #2
0
def test_data_conversions(polar, qvar, query):
    polar.load_str('a(1);b("two");c(true);d([1,"two",true]);')
    assert qvar("a(x)", "x", one=True) == 1
    assert qvar("b(x)", "x", one=True) == "two"
    assert qvar("c(x)", "x", one=True)
    assert qvar("d(x)", "x", one=True) == [1, "two", True]
    y = qvar("x = y", "x", one=True)
    assert str(y) == "Variable('y')"
    assert repr(y) == "Variable('y')"
예제 #3
0
def test_field_specializers(load_file, qvar):
    # Contains test queries.
    load_file(Path(__file__).parent / "policies/people.pol")

    # Test method ordering w/field specializers.
    assert qvar('froody(Manager{name: "Sam"}, x)', "x") == [1]
    assert qvar('froody(Manager{name: "Sam", id: 1}, x)', "x") == [2, 1]
    assert qvar(
        'froody(Manager{name: "Sam", id: 1, manager: Person{name: "Sam"}}, x)', "x"
    ) == [3, 2, 1]
예제 #4
0
def test_recursive_rule(tell, qeval, qvar):
    tell('derive("apple", "orange")')
    tell('derive("orange", "avacado")')
    tell('derive("avacado", "juniper_berry")')
    results = qvar('derive("apple", x)', "x")
    assert results == ["orange"]
    tell("derives(a, b) if derive(a, b);")
    tell("derives(a, b) if derive(a, z) and derives(z, b);")
    assert qeval('derives("apple", "juniper_berry")')
    results = qvar('derives("apple", x)', "x")
    assert results == ["orange", "avacado", "juniper_berry"]
예제 #5
0
def test_method_with_kwargs(polar, qvar):
    class Test:
        def kwarg_method(self, x=1, y=2):
            self.x = x
            self.y = y
            return True

    polar.register_class(Test)
    rules = """
    defaults(result) if
        test = new Test() and
        test.kwarg_method() and
        result = [test.x, test.y];

    kwargs(result) if
        test = new Test() and
        test.kwarg_method(y: 4, x: 3) and
        result = [test.x, test.y];

    args(result) if
        test = new Test() and
        test.kwarg_method(5, 6) and
        result = [test.x, test.y];

    mixed(result) if
        test = new Test() and
        test.kwarg_method(7, y: 8) and
        result = [test.x, test.y];
    """
    polar.load_str(rules)
    qvar("defaults(result)", "result") == [1, 2]
    qvar("kwargs(result)", "result") == [3, 4]
    qvar("args(result)", "result") == [5, 6]
    qvar("mixed(result)", "result") == [7, 8]
예제 #6
0
def test_class_field_specializers(polar, qvar, qeval, query):
    class Animal:
        def __init__(self, species=None, genus=None, family=None):
            self.genus = genus
            self.species = species
            self.family = family

    polar.register_class(Animal)

    rules = """
    what_is(_: Animal, res) if res = "animal";
    what_is(_: Animal{genus: "canis"}, res) if res = "canine";
    what_is(_: Animal{family: "canidae"}, res) if res = "canid";
    what_is(_: Animal{species: "canis lupus", genus: "canis"}, res) if res = "wolf";
    what_is(_: Animal{species: "canis familiaris", genus: "canis"}, res) if res = "dog";
    what_is(_: Animal{species: s, genus: "canis"}, res) if res = s;
    """
    polar.load_str(rules)

    wolf = 'new Animal(species: "canis lupus", genus: "canis", family: "canidae")'
    dog = 'new Animal(species: "canis familiaris", genus: "canis", family: "canidae")'
    canine = 'new Animal(genus: "canis", family: "canidae")'
    canid = 'new Animal(family: "canidae")'
    animal = "new Animal()"

    assert len(query(f"what_is({wolf}, res)")) == 5
    assert len(query(f"what_is({dog}, res)")) == 5
    assert len(query(f"what_is({canine}, res)")) == 4
    assert len(query(f"what_is({canid}, res)")) == 2
    assert len(query(f"what_is({animal}, res)")) == 1

    assert qvar(f"what_is({wolf}, res)", "res") == [
        "wolf",
        "canis lupus",
        "canine",
        "canid",
        "animal",
    ]
    assert qvar(f"what_is({dog}, res)", "res") == [
        "dog",
        "canis familiaris",
        "canine",
        "canid",
        "animal",
    ]
    assert qvar(f"what_is({canine}, res)",
                "res") == [None, "canine", "canid", "animal"]
    assert qvar(f"what_is({canid}, res)", "res") == ["canid", "animal"]
    assert qvar(f"what_is({animal}, res)", "res") == ["animal"]
예제 #7
0
def test_iterators(polar, qeval, qvar):
    class Foo:
        pass

    polar.register_class(Foo)
    with pytest.raises(exceptions.InvalidIteratorError) as e:
        qeval("x in new Foo()")

    class Bar(list):
        def sum(self):
            return sum(x for x in self)

    polar.register_class(Bar)
    assert qvar("x in new Bar([1, 2, 3])", "x") == [1, 2, 3]
    assert qvar("x = new Bar([1, 2, 3]).sum()", "x", one=True) == 6
예제 #8
0
파일: test_polar.py 프로젝트: zmilan/oso
def test_dictionaries(tell, qeval, qvar):
    # basic dictionary lookup
    tell('dict({hello: "world", foo: "bar"})')
    assert qeval('dict(d) and d.hello = "world"')

    ### dictionary lookups with variable fields ###
    tell("attr(d, k, d.(k))")

    # k = "hello", {hello: "steve"}.(k) = "steve"
    assert qeval('attr({hello: "steve"}, "hello", "steve")')

    # k = "hello", {hello: "steve"}.(k) = value, value = "steve"
    assert qvar('attr({hello: "steve"}, "hello", value)', "value",
                one=True) == "steve"

    # k = key, {hello: "steve"}.(k) = "steve", key = "hello"
    assert qvar('attr({hello: "steve"}, key, "steve")', "key",
                one=True) == "hello"

    ### nested lookups ###
    assert qeval(
        'attr({hello: {this: {is: "nested"}}}, "hello", {this: {is: "nested"}})'
    )

    tell("deepget(d, d.hello.this.is)")
    assert qeval('deepget({hello: {this: {is: "nested"}}}, "nested")')

    tell("myget(d, d.get.inner)")
    assert qeval('myget({get: {inner: "nested"}}, "nested")')

    tell("x({a: {b:{c:123}}})")
    tell("x({a: {y:{c:456}}})")
    assert qvar("x(d) and d.a.(k).c = value", "value") == [123, 456]

    tell("lookup(dict, result) if result = dict.a.b.c;")
    assert qeval('lookup({a: {b: {c: "nested"}}}, "nested")')

    ### more basic lookup tests ###
    tell('user({name: "steve", job: "programmer", state: "NY"})')
    tell('user({name: "alex", job: "programmer", state: "CO"})')
    tell('user({name: "graham", job: "business", state: "NY"})')
    assert qeval('user(d) and d.name = "steve"')
    assert qvar('user({job: "programmer", name: name, state: state})',
                "name") == [
                    "steve",
                    "alex",
                ]
예제 #9
0
def test_numbers_from_external_call(polar, qeval, qvar, query):
    class Numberer:
        def give_me_an_int(self):
            yield 1

        def give_me_a_float(self):
            yield 1.234

    polar.register_class(Numberer)

    result = qvar("new Numberer().give_me_an_int() = var", "var", one=True)
    assert result == 1
    assert qeval("new Numberer().give_me_an_int() = 1")

    result = qvar("new Numberer().give_me_a_float() = var", "var", one=True)
    assert result == 1.234
    assert qeval("new Numberer().give_me_a_float() = 1.234")
예제 #10
0
def test_bool_from_external_call(polar, qeval, qvar, query):
    class Booler:
        def whats_up(self):
            yield True

    polar.register_class(Booler)

    result = qvar("new Booler().whats_up() = var", "var", one=True)
    assert qeval("new Booler().whats_up()")
예제 #11
0
def test_constructor(polar, qvar):
    """Test that class constructor is called correctly with constructor syntax."""

    class Foo:
        def __init__(self, a, b, bar, baz):
            self.a = a
            self.b = b
            self.bar = bar
            self.baz = baz

    polar.register_class(Foo)

    # test positional args
    instance = qvar(
        "instance = new Foo(1,2,3,4)",
        "instance",
        one=True,
    )
    assert instance.a == 1
    assert instance.b == 2
    assert instance.bar == 3
    assert instance.baz == 4

    # test positional and kwargs
    instance = qvar(
        "instance = new Foo(1, 2, bar: 3, baz: 4)",
        "instance",
        one=True,
    )
    assert instance.a == 1
    assert instance.b == 2
    assert instance.bar == 3
    assert instance.baz == 4

    # test kwargs
    instance = qvar(
        "instance = new Foo(bar: 3, a: 1, baz: 4, b: 2)",
        "instance",
        one=True,
    )
    assert instance.a == 1
    assert instance.b == 2
    assert instance.bar == 3
    assert instance.baz == 4
예제 #12
0
def test_constructor(polar, qvar):
    """Test that class constructor is called correctly with constructor syntax."""

    class TestConstructor:
        def __init__(self, x):
            self.x = x

    polar.register_class(TestConstructor)

    assert (
        qvar("instance = new TestConstructor{x: 1} and y = instance.x", "y", one=True)
        == 1
    )
    assert (
        qvar("instance = new TestConstructor{x: 2} and y = instance.x", "y", one=True)
        == 2
    )
    assert (
        qvar(
            "instance = new TestConstructor{x: new TestConstructor{x: 3}} and y = instance.x.x",
            "y",
            one=True,
        )
        == 3
    )

    class TestConstructorTwo:
        def __init__(self, x, y):
            self.x = x
            self.y = y

    polar.register_class(TestConstructorTwo)

    assert (
        qvar(
            "instance = new TestConstructorTwo{x: 1, y: 2} and x = instance.x and y = instance.y",
            "y",
            one=True,
        )
        == 2
    )
예제 #13
0
def test_load_function(polar, query, qvar):
    """Make sure the load function works."""
    # Loading the same file twice doesn't mess stuff up.
    polar.load_file(Path(__file__).parent / "test_file.polar")
    with pytest.raises(exceptions.PolarRuntimeException) as e:
        polar.load_file(Path(__file__).parent / "test_file.polar")
    assert (
        str(e.value) ==
        f"Problem loading file: File {Path(__file__).parent}/test_file.polar has already been loaded."
    )
    with pytest.raises(exceptions.PolarRuntimeException) as e:
        polar.load_file(Path(__file__).parent / "test_file_renamed.polar")
    assert (
        str(e.value) ==
        f"Problem loading file: A file with the same contents as {Path(__file__).parent}/test_file_renamed.polar named {Path(__file__).parent}/test_file.polar has already been loaded."
    )
    assert query("f(x)") == [{"x": 1}, {"x": 2}, {"x": 3}]
    assert qvar("f(x)", "x") == [1, 2, 3]

    polar.clear()
    polar.load_file(Path(__file__).parent / "test_file.polar")
    polar.load_file(Path(__file__).parent / "test_file_gx.polar")
    assert query("f(x)") == [{"x": 1}, {"x": 2}, {"x": 3}]
    assert query("g(x)") == [{"x": 1}, {"x": 2}, {"x": 3}]
예제 #14
0
def test_specializers_mixed(polar, qvar, qeval, query):
    class Animal:
        def __init__(self, species=None, genus=None, family=None):
            self.genus = genus
            self.species = species
            self.family = family

    polar.register_class(Animal)

    # load rules
    rules = """
    what_is(_: Animal, res) if res = "animal_class";
    what_is(_: Animal{genus: "canis"}, res) if res = "canine_class";
    what_is(_: {genus: "canis"}, res) if res = "canine_dict";
    what_is(_: Animal{family: "canidae"}, res) if res = "canid_class";
    what_is(_: {species: "canis lupus", genus: "canis"}, res) if res = "wolf_dict";
    what_is(_: {species: "canis familiaris", genus: "canis"}, res) if res = "dog_dict";
    what_is(_: Animal{species: "canis lupus", genus: "canis"}, res) if res = "wolf_class";
    what_is(_: Animal{species: "canis familiaris", genus: "canis"}, res) if res = "dog_class";
    """
    polar.load_str(rules)

    wolf = 'new Animal(species: "canis lupus", genus: "canis", family: "canidae")'
    dog = 'new Animal(species: "canis familiaris", genus: "canis", family: "canidae")'
    canine = 'new Animal(genus: "canis", family: "canidae")'

    wolf_dict = '{species: "canis lupus", genus: "canis", family: "canidae"}'
    dog_dict = '{species: "canis familiaris", genus: "canis", family: "canidae"}'
    canine_dict = '{genus: "canis", family: "canidae"}'

    # test number of results
    assert len(query(f"what_is({wolf}, res)")) == 6
    assert len(query(f"what_is({dog}, res)")) == 6
    assert len(query(f"what_is({canine}, res)")) == 4
    assert len(query(f"what_is({wolf_dict}, res)")) == 2
    assert len(query(f"what_is({dog_dict}, res)")) == 2
    assert len(query(f"what_is({canine_dict}, res)")) == 1

    # test rule ordering for instances
    assert qvar(f"what_is({wolf}, res)", "res") == [
        "wolf_class",
        "canine_class",
        "canid_class",
        "animal_class",
        "wolf_dict",
        "canine_dict",
    ]
    assert qvar(f"what_is({dog}, res)", "res") == [
        "dog_class",
        "canine_class",
        "canid_class",
        "animal_class",
        "dog_dict",
        "canine_dict",
    ]
    assert qvar(f"what_is({canine}, res)", "res") == [
        "canine_class",
        "canid_class",
        "animal_class",
        "canine_dict",
    ]

    # test rule ordering for dicts
    assert qvar(f"what_is({wolf_dict}, res)",
                "res") == ["wolf_dict", "canine_dict"]
    assert qvar(f"what_is({dog_dict}, res)",
                "res") == ["dog_dict", "canine_dict"]
    assert qvar(f"what_is({canine_dict}, res)", "res") == ["canine_dict"]
예제 #15
0
def test_external(polar, qvar):
    class Bar:
        def y(self):
            return "y"

    class Foo:
        def __init__(self, a="a"):
            self.a = a

        def b(self):
            yield "b"

        @classmethod
        def c(cls):
            assert issubclass(cls, Foo)
            return "c"

        def d(self, x):
            return x

        def bar(self):
            return Bar()

        def e(self):
            return [1, 2, 3]

        def f(self):
            yield [1, 2, 3]
            yield [4, 5, 6]
            yield 7

        def g(self):
            return {"hello": "world"}

        def h(self):
            return True

    def capital_foo():
        return Foo(a="A")

    polar.register_class(Foo, from_polar=capital_foo)
    assert qvar("new Foo{}.a = x", "x", one=True) == "A"
    assert qvar("new Foo{}.a() = x", "x", one=True) == "A"
    assert qvar("new Foo{}.b = x", "x", one=True) == "b"
    assert qvar("new Foo{}.b() = x", "x", one=True) == "b"
    assert qvar("Foo.c = x", "x", one=True) == "c"
    assert qvar("Foo.c() = x", "x", one=True) == "c"
    assert qvar("new Foo{} = f and f.a() = x", "x", one=True) == "A"
    assert qvar("new Foo{}.bar().y() = x", "x", one=True) == "y"
    assert qvar("new Foo{}.e = x", "x", one=True) == [1, 2, 3]
    assert qvar("new Foo{}.f = x", "x") == [[1, 2, 3], [4, 5, 6], 7]
    assert qvar("new Foo{}.g.hello = x", "x", one=True) == "world"
    assert qvar("new Foo{}.h = x", "x", one=True) is True
예제 #16
0
def test_helpers(polar, load_file, query, qeval, qvar):
    load_file(Path(__file__).parent / "test_file.polar")  # f(1);
    assert query("f(x)") == [{"x": 1}, {"x": 2}, {"x": 3}]
    assert qvar("f(x)", "x") == [1, 2, 3]
예제 #17
0
def test_class_specializers(polar, qvar, qeval, query):
    class A:
        def a(self):
            return "A"

        def x(self):
            return "A"

    class B(A):
        def b(self):
            return "B"

        def x(self):
            return "B"

    class C(B):
        def c(self):
            return "C"

        def x(self):
            return "C"

    class X:
        def x(self):
            return "X"

    polar.register_class(A)
    polar.register_class(B)
    polar.register_class(C)
    polar.register_class(X)

    rules = """
    test(_: A);
    test(_: B);

    try(_: B, res) if res = 2;
    try(_: C, res) if res = 3;
    try(_: A, res) if res = 1;
    """
    polar.load_str(rules)

    assert qvar("new A().a() = x", "x", one=True) == "A"
    assert qvar("new A().x() = x", "x", one=True) == "A"
    assert qvar("new B().a() = x", "x", one=True) == "A"
    assert qvar("new B().b() = x", "x", one=True) == "B"
    assert qvar("new B().x() = x", "x", one=True) == "B"
    assert qvar("new C().a() = x", "x", one=True) == "A"
    assert qvar("new C().b() = x", "x", one=True) == "B"
    assert qvar("new C().c() = x", "x", one=True) == "C"
    assert qvar("new C().x() = x", "x", one=True) == "C"
    assert qvar("new X().x() = x", "x", one=True) == "X"

    assert len(query("test(new A())")) == 1
    assert len(query("test(new B())")) == 2

    assert qvar("try(new A(), x)", "x") == [1]
    assert qvar("try(new B(), x)", "x") == [2, 1]
    assert qvar("try(new C(), x)", "x") == [3, 2, 1]
    assert qvar("try(new X(), x)", "x") == []
예제 #18
0
def test_nil(polar, query, qvar):
    """Test that nil is pre-registered as None."""
    polar.load_str("null(nil);")
    assert qvar("null(x)", "x") == [None]
    assert query(Predicate("null", [None])) == [{}]
    assert not query(Predicate("null", [[]]))
예제 #19
0
def test_query_multiple(tell, qvar):
    tell('a("foo")')
    tell('a("bar")')
    tell('a("baz")')
    results = qvar("a(x)", "x")
    assert results == ["foo", "bar", "baz"]
예제 #20
0
def test_other_constants(polar, qvar, query):
    d = {"a": 1}
    polar.register_constant("d", d)
    assert qvar("x = d.a", "x") == [1]
예제 #21
0
def test_group_field_access(load_file, qvar):
    load_file(Path(__file__).parent / "policies/groups.pol")

    assert qvar('get_bar(Baz{bar: "test"}, val)', "val", one=True) == "test"
예제 #22
0
def test_other_constants(polar, qvar):
    """Test that other objects may be registered as constants."""
    d = {"a": 1}
    polar.register_constant(d, "d")
    assert qvar("x = d.a", "x") == [1]
예제 #23
0
def test_predicate(polar, qvar, query):
    """Test that predicates can be converted to and from python."""
    polar.load_str("f(x) if x = pred(1, 2);")
    assert qvar("f(x)", "x") == [Predicate("pred", [1, 2])]

    assert query(Predicate(name="f", args=[Predicate("pred", [1, 2])])) == [{}]
예제 #24
0
def test_load_file(load_file, tell, qeval, qvar):
    load_file(Path(__file__).parent / "policies/test.polar")
    assert qeval('test("true")')
    tell('b("foo")')
    assert qvar("a(x)", "x", one=True) == "foo"
예제 #25
0
def test_external(polar, qvar, qeval):
    class Bar:
        def y(self):
            return "y"

    class Foo:
        def __init__(self, a="a"):
            self.a = a

        def b(self):
            yield "b"

        @classmethod
        def c(cls):
            assert issubclass(cls, Foo)
            return "c"

        def d(self, x):
            return x

        def bar(self):
            return Bar()

        def e(self):
            return [1, 2, 3]

        def f(self):
            yield [1, 2, 3]
            yield [4, 5, 6]
            yield 7

        def g(self):
            return {"hello": "world"}

        def h(self):
            return True

    def capital_foo():
        return Foo(a="A")

    polar.register_class(Foo, from_polar=capital_foo)
    assert qvar("new Foo().a = x", "x", one=True) == "A"
    with pytest.raises(RuntimeError,
                       match="tried to call 'a' but it is not callable"):
        assert not qeval("new Foo().a() = x")
    assert not qvar("new Foo().b = x", "x", one=True) == "b"
    assert qvar("new Foo().b() = x", "x", one=True) == "b"
    assert not qvar("Foo.c = x", "x", one=True) == "c"
    assert qvar("Foo.c() = x", "x", one=True) == "c"
    assert qvar("new Foo() = f and f.a = x", "x", one=True) == "A"
    assert qvar("new Foo().bar().y() = x", "x", one=True) == "y"
    assert qvar("new Foo().e() = x", "x", one=True) == [1, 2, 3]
    assert qvar("new Foo().f() = x", "x") == [[1, 2, 3], [4, 5, 6], 7]
    assert qvar("new Foo().g().hello = x", "x", one=True) == "world"
    assert qvar("new Foo().h() = x", "x", one=True) is True
예제 #26
0
def test_class_specializers(polar, qvar, qeval, query):
    class A:
        def a(self):
            return "A"

        def x(self):
            return "A"

    class B(A):
        def b(self):
            return "B"

        def x(self):
            return "B"

    class C(B):
        def c(self):
            return "C"

        def x(self):
            return "C"

    class X:
        def x(self):
            return "X"

    polar.register_class(A)
    polar.register_class(B)
    polar.register_class(C)
    polar.register_class(X)

    rules = """
    test(_: A{});
    test(_: B{});

    try(_: B{}, res) if res = 2;
    try(_: C{}, res) if res = 3;
    try(_: A{}, res) if res = 1;
    """
    polar.load_str(rules)

    assert qvar("new A{}.a = x", "x", one=True) == "A"
    assert qvar("new A{}.x = x", "x", one=True) == "A"
    assert qvar("new B{}.a = x", "x", one=True) == "A"
    assert qvar("new B{}.b = x", "x", one=True) == "B"
    assert qvar("new B{}.x = x", "x", one=True) == "B"
    assert qvar("new C{}.a = x", "x", one=True) == "A"
    assert qvar("new C{}.b = x", "x", one=True) == "B"
    assert qvar("new C{}.c = x", "x", one=True) == "C"
    assert qvar("new C{}.x = x", "x", one=True) == "C"
    assert qvar("new X{}.x = x", "x", one=True) == "X"

    assert len(query("test(new A{})")) == 1
    assert len(query("test(new B{})")) == 2

    assert qvar("try(new A{}, x)", "x") == [1]
    assert qvar("try(new B{}, x)", "x") == [2, 1]
    assert qvar("try(new C{}, x)", "x") == [3, 2, 1]
    assert qvar("try(new X{}, x)", "x") == []