summary refs log blame commit diff stats
path: root/testing/test_abdl.py
blob: cbdcd9dd71f3215520b40b0454cd21c03101bd33 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                  


                                                     
                                    
                       














                                                                                                                                                      
                         


                       

                               




                                         


                                         




                                         


                                         

                                


                                                                  
















































































































                                                                                                                           








                                                                               
                                                                                                                                                  








                                                        














                                                            




                                                                           
                             






                                                        

























                                                                         



                                                                          








                                                                                                  























                                                                                                            
                

                                                        










                                                  
# Tests abdl.py

import abdl

import hypothesis
import hypothesis.strategies as st

import collections.abc

import re

import traceback


abdl.DeprecationError.enable_key_match_compat = False

# use abdl's _pairs for consistency.
pairs = abdl._vm._pairs

# do not put integers, floats, etc here
# do not put bytes, they iterate as integers
hashables = st.deferred(lambda: st.text() | st.frozensets(hashables) | st.lists(hashables).map(tuple))
values = st.deferred(lambda: hashables | objtree)
objtree = st.deferred(lambda: st.text() | st.dictionaries(hashables, values) | st.lists(values) | st.sets(hashables) | st.lists(hashables).map(tuple))

# note: use all() so as to not eat all the RAM :p

class LogAndCompare:
    def __init__(self, left, right):
        self._itl = left
        self._itr = right
        self.left = []
        self.right = []
        self.done = False
    def __iter__(self):
        return self
    def __next__(self):
        if self.done:
            raise StopIteration
        try:
            left = next(self._itl)
        except abdl.ValidationError as e:
            e.tb = traceback.format_exc()
            left = e
        except StopIteration as e:
            e.tb = traceback.format_exc()
            left = e
        try:
            right = next(self._itr)
        except abdl.ValidationError as e:
            e.tb = traceback.format_exc()
            right = e
        except StopIteration as e:
            e.tb = traceback.format_exc()
            right = e
        self.left.append(left)
        self.right.append(right)
        if StopIteration in (type(left), type(right)):
            self.done = True
            return (type(left), type(right)) == (StopIteration,)*2
        return left == right or (type(left), type(right)) == (abdl.ValidationError,)*2
    def __repr__(self):
        return "LogAndCompare(left=" + repr(self.left) + ", right=" + repr(self.right) + ")"


@hypothesis.given(objtree, st.just(abdl.compile("->X")))
def test_basic_iterator(foo, pat):
    assert all(LogAndCompare(pat.match(foo), map(lambda x: {"X": x}, pairs(foo))))

@hypothesis.given(objtree, st.just(abdl.compile("->X->Y")))
def test_two_depths(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            for y in pairs(x[1]):
                yield {"X": x, "Y": y}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->X->Y->Z->W")))
def test_four_depths(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            for y in pairs(x[1]):
                for z in pairs(y[1]):
                    for w in pairs(z[1]):
                        yield {"X": x, "Y": y, "Z": z, "W": w}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(st.dictionaries(st.text(), st.text()) | st.sets(st.text()), st.just(abdl.compile("->/.../")))
def test_regex(foo, pat):
    # no bindings on this one :<
    def deep(foo):
        for x in pairs(foo):
            if re.search("...", x[0]):
                    yield {}
            else:
                raise abdl.ValidationError
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->/.../?")))
def test_regex_skippable_vs_objtree(foo, pat):
    assert all(LogAndCompare(pat.match(foo), ({} for x in pairs(foo) if isinstance(x[0], str) and re.search("...", x[0]))))

@hypothesis.given(st.dictionaries(st.text(), st.text()) | st.sets(st.text()), st.just(abdl.compile("->/.../->Y")))
def test_regex_and_bind(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if re.search("...", x[0]):
                for y in pairs(x[1]):
                    yield {"Y": y}
            else:
                raise abdl.ValidationError
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->/.../?->Y")))
def test_regex_skippable_and_bind_vs_objtree(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[0], str) and re.search("...", x[0]):
                for y in pairs(x[1]):
                    yield {"Y": y}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->/^...$/?->Y")))
def test_regex_anchored_skippable_and_bind_vs_objtree(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[0], str) and re.search("^...$", x[0]):
                for y in pairs(x[1]):
                    yield {"Y": y}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->''?->Y")))
def test_empty_literal_vs_objtree(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if x[0] == '':
                for y in pairs(x[1]):
                    yield {"Y": y}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

defs = {'a': (dict, list, set)}
@hypothesis.given(objtree, st.just(abdl.compile("->X:?$a->Y", defs=defs)))
def test_type(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[1], (dict, list, set)):
                for y in pairs(x[1]):
                    yield {"X": x, "Y": y}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

defs = {'a': (dict, list, set), 'b': (dict, set), 'c': dict}
@hypothesis.given(objtree, st.just(abdl.compile("->X:?$a:?$b:?$c->Y", defs=defs)))
def test_multi_type(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[1], dict):
                for y in pairs(x[1]):
                    yield {"X": x, "Y": y}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

defs = {'a': (dict, list, set), 'b': (dict, set), 'c': dict}
@hypothesis.given(objtree, st.just(abdl.compile("->X:$a:$b:$c->Y", defs=defs)))
@hypothesis.settings(suppress_health_check=[hypothesis.HealthCheck.too_slow])
def test_multi_type_with_validation_errors(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[1], dict):
                for y in pairs(x[1]):
                    yield {"X": x, "Y": y}
            else:
                raise abdl.ValidationError
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

defs = {'a': (dict, list, set), 'b': (dict, set), 'c': dict}
@hypothesis.given(objtree, st.just(abdl.compile("->X:?$a:?$b:?$c", defs=defs)))
def test_multi_type_at_end(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[1], dict):
                    yield {"X": x}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(st.dictionaries(st.frozensets(st.text()), st.text()), st.just(abdl.compile("->[:?$sets->A]->D", {'sets': collections.abc.Set})))
def test_subtree_partial(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[0], collections.abc.Set):
                for a in pairs(x[0]):
                    for d in pairs(x[1]):
                        yield {"A": a, "D": d}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->tag[]")))
def test_tagged_key(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            yield {"tag": x}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->[]->D")))
def test_key_dummy(foo, pat):
    def deep(foo):
        for x in pairs(foo):
                for d in pairs(x[1]):
                    yield {"D": d}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->X->$a->Z", {'a': '0'})))
def test_param(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            try:
                y = x[1]['0']
            except (TypeError, IndexError, KeyError):
                raise abdl.ValidationError
            else:
                for z in pairs(y):
                    yield {"X": x, "Z": z}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->tag/.../?")))
def test_tagged_regex(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[0], str) and re.search("...", x[0]):
                yield {"tag": x}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->tag'0'?")))
def test_tagged_str(foo, pat):
    def deep(foo):
        try:
            yield {"tag": ('0', foo['0'])}
        except (TypeError, IndexError, KeyError):
            pass
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->tag$?a", {'a': '0'})))
def test_tagged_param(foo, pat):
    def deep(foo):
        try:
            yield {"tag": ('0', foo['0'])}
        except (TypeError, IndexError, KeyError):
            pass
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

def test_basic_value_subtree():
    matcher = abdl.match("(->foo'foo')(->bar'bar')", {'foo': 1, 'bar': 2})
    assert list(matcher) == [{'foo': ('foo', 1), 'bar': ('bar', 2)}]

@hypothesis.given(objtree, st.just(abdl.compile("->[:?$sets]->D", {'sets': collections.abc.Set})))
def test_key_predicate(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[0], collections.abc.Set):
                for d in pairs(x[1]):
                    yield {"D": d}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->[:?$sets:?$sets->V]->D", {'sets': collections.abc.Set})))
def test_multi_key_predicate_with_values(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[0], collections.abc.Set):
                if isinstance(x[0], collections.abc.Set):
                    for v in pairs(x[0]):
                        for d in pairs(x[1]):
                            yield {"V": v, "D": d}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("->[:?$sets:?$sets]->D", {'sets': collections.abc.Set})))
def test_multi_key_predicate(foo, pat):
    def deep(foo):
        for x in pairs(foo):
            if isinstance(x[0], collections.abc.Set):
                if isinstance(x[0], collections.abc.Set):
                    for d in pairs(x[1]):
                        yield {"D": d}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

@hypothesis.given(objtree, st.just(abdl.compile("")))
def test_empty(foo, pat):
    def deep(foo):
        yield {}
    assert all(LogAndCompare(pat.match(foo), deep(foo)))

# FIXME
#@hypothesis.given(objtree, st.text())
#def test_exhaustive(foo, pat):
#    hypothesis.assume(not re.match("^%s+$", pat))
#    hypothesis.assume(pat)
#    try:
#        compiled = abdl.compile(pat)
#        print(pat)
#    except abdl.PatternError:
#        hypothesis.assume(False)
#    compiled.match(foo)