# mode: run
# tag: cpp, cpp11, pthread
# cython: experimental_cpp_class_def=True, language_level=2

from libcythonplus.dict cimport cypdict
from libcythonplus.list cimport cyplist
from libcythonplus.set cimport cypset


cdef cypclass Leaf activable:
    int value

def test_recover_isolated_leaf():
    """
    >>> test_recover_isolated_leaf()
    0
    """
    try:
        l = recover Leaf()
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_isolated_named_leaf():
    """
    >>> test_recover_isolated_named_leaf()
    0
    """
    leaf = Leaf()
    try:
        l = recover leaf
        if leaf is not NULL:
            return -1
        return 0
    except TypeError as e:
        print(e)
        return -2

def test_recover_aliased_leaf():
    """
    >>> test_recover_aliased_leaf()
    'recover' operand is not isolated
    0
    """
    leaf = Leaf()
    leaf2 = leaf
    try:
        l = recover leaf
        return -1
    except TypeError as e:
        print(e)
        return 0

def test_nogil_recover_isolated_leaf():
    """
    >>> test_nogil_recover_isolated_leaf()
    0
    """
    try:
        with nogil:
            l = recover Leaf()
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_nogil_recover_aliased_leaf():
    """
    >>> test_nogil_recover_aliased_leaf()
    'recover' operand is not isolated
    0
    """
    leaf = Leaf()
    leaf2 = leaf
    try:
        with nogil:
            l = recover leaf
        return -1
    except TypeError as e:
        print(e)
        return 0


cdef cypclass Convertible:
    Leaf __Leaf__(self):
        return Leaf()

def test_recover_isolated_cast_named_leaf():
    """
    >>> test_recover_isolated_cast_named_leaf()
    0
    """
    leaf = Leaf()
    try:
        l = recover <Leaf> leaf
        if leaf is not NULL:
            return -1
        return 0
    except TypeError as e:
        print(e)
        return -2

def test_recover_isolated_cast_converted_leaf():
    """
    >>> test_recover_isolated_cast_converted_leaf()
    0
    """
    try:
        l = recover <Leaf> Convertible()
        return 0
    except TypeError as e:
        print(e)
        return -2

cdef cypclass Field:
    Field foo(self, Field other):
        return other

cdef cypclass Origin:
    Field field

    __init__(self):
        self.field = Field()

def test_recover_isolated_origin():
    """
    >>> test_recover_isolated_origin()
    0
    """
    try:
        o = recover Origin()
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_origin_with_aliased_field():
    """
    >>> test_recover_origin_with_aliased_field()
    'recover' operand is not isolated
    0
    """
    origin = Origin()
    field = origin.field
    try:
        o = recover origin
        return -1
    except TypeError as e:
        print(e)
        return 0

def test_recover_field():
    """
    >>> test_recover_field()
    0
    """
    origin = Origin()
    try:
        f = recover origin.field
        if origin.field is not NULL:
            return -1
        return 0
    except TypeError as e:
        print(e)
        return -2

def test_recover_field_from_temporary_origin():
    """
    >>> test_recover_field_from_temporary_origin()
    0
    """
    try:
        f = recover Origin().field
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_aliased_field():
    """
    >>> test_recover_aliased_field()
    'recover' operand is not isolated
    0
    """
    origin = Origin()
    field = origin.field
    try:
        f = recover origin.field
        return -1
    except TypeError as e:
        print(e)
        return 0


cdef cypclass DoubleOrigin(Origin):
    Field field2

    __init__(self):
        self.field2 = self.field = Field()


def test_recover_isolated_double_origin():
    """
    >>> test_recover_isolated_double_origin()
    0
    """
    try:
        o = recover DoubleOrigin()
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_double_origin_with_aliased_field():
    """
    >>> test_recover_double_origin_with_aliased_field()
    'recover' operand is not isolated
    0
    """
    origin = DoubleOrigin()
    field = origin.field
    try:
        o = recover origin
        return -1
    except TypeError as e:
        print(e)
        return 0

def test_recover_field_from_double_origin():
    """
    >>> test_recover_field_from_double_origin()
    'recover' operand is not isolated
    0
    """
    try:
        f = recover DoubleOrigin().field
        return -1
    except TypeError as e:
        print(e)
        return 0


cdef cypclass Cycle:
    Cycle field

    __init__(self):
        self.field = self

def test_recover_isolated_cycle():
    """
    >>> test_recover_isolated_cycle()
    0
    """
    try:
        c = recover Cycle()
        return 0
    except TypeError as e:
        print(e)
        return -1


cdef iso Leaf recover_arg(Leaf arg) except NULL:
    return recover arg

def test_recover_isolated_arg():
    """
    >>> test_recover_isolated_arg()
    0
    """
    try:
        l = recover_arg(Leaf())
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_aliased_arg():
    """
    >>> test_recover_aliased_arg()
    'recover' operand is not isolated
    0
    """
    leaf = Leaf()
    try:
        l = recover_arg(leaf)
        return -1
    except TypeError as e:
        print(e)
        return 0


def test_recover_isolated_leaf_list():
    """
    >>> test_recover_isolated_leaf_list()
    0
    """
    leaflist = cyplist[Leaf]()
    for i in range(5):
        leaflist.append(Leaf())

    try:
        l = recover leaflist
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_leaf_list_with_aliased_element():
    """
    >>> test_recover_leaf_list_with_aliased_element()
    'recover' operand is not isolated
    0
    """
    leaflist = cyplist[Leaf]()
    for i in range(5):
        leaflist.append(Leaf())
    leaf = leaflist[0]

    try:
        l = recover leaflist
        return -1
    except TypeError as e:
        print(e)
        return 0


def test_recover_isolated_leaf_set():
    """
    >>> test_recover_isolated_leaf_set()
    0
    """
    leafset = cypset[Leaf]()
    for i in range(5):
        leafset.add(Leaf())

    try:
        s = recover leafset
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_leaf_set_with_aliased_element():
    """
    >>> test_recover_leaf_set_with_aliased_element()
    'recover' operand is not isolated
    0
    """
    leafset = cypset[Leaf]()
    for i in range(4):
        leafset.add(Leaf())
    leaf = Leaf()
    leafset.add(leaf)

    try:
        s = recover leafset
        return -1
    except TypeError as e:
        print(e)
        return 0


def test_recover_isolated_leaf_dict():
    """
    >>> test_recover_isolated_leaf_set()
    0
    """
    leafdict = cypdict[Leaf, Leaf]()
    for i in range(5):
        leafdict[Leaf()] = Leaf()

    try:
        d = recover leafdict
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_leaf_dict_with_aliased_key():
    """
    >>> test_recover_leaf_dict_with_aliased_key()
    'recover' operand is not isolated
    0
    """
    leafdict = cypdict[Leaf, Leaf]()
    for i in range(5):
        leafdict[Leaf()] = Leaf()
    leaf = Leaf()
    leafdict[leaf] = Leaf()

    try:
        d = recover leafdict
        return -1
    except TypeError as e:
        print(e)
        return 0

def test_recover_leaf_dict_with_aliased_value():
    """
    >>> test_recover_leaf_dict_with_aliased_value()
    'recover' operand is not isolated
    0
    """
    leafdict = cypdict[Leaf, Leaf]()
    for i in range(5):
        leafdict[Leaf()] = Leaf()
    leaf = Leaf()
    leafdict[Leaf()] = leaf

    try:
        d = recover leafdict
        return -1
    except TypeError as e:
        print(e)
        return 0


def test_recover_isolated_nested_container():
    """
    >>> test_recover_isolated_nested_container()
    0
    """
    nestedlist = cyplist[cyplist[Leaf]]()
    for i in range(5):
        innerlist = cyplist[Leaf]()
        for i in range(5):
            innerlist.append(Leaf())
        nestedlist.append(innerlist)
        del innerlist

    try:
        l = recover nestedlist
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_nested_container_with_aliased_leaf():
    """
    >>> test_recover_nested_container_with_aliased_leaf()
    'recover' operand is not isolated
    0
    """
    nestedlist = cyplist[cyplist[Leaf]]()
    for i in range(5):
        innerlist = cyplist[Leaf]()
        for i in range(5):
            innerlist.append(Leaf())
        nestedlist.append(innerlist)
    leaf = nestedlist[0][0]

    try:
        l = recover nestedlist
        return -1
    except TypeError as e:
        print(e)
        return 0

def test_recover_nested_container_with_aliased_list():
    """
    >>> test_recover_nested_container_with_aliased_list()
    'recover' operand is not isolated
    0
    """
    nestedlist = cyplist[cyplist[Leaf]]()
    for i in range(5):
        innerlist = cyplist[Leaf]()
        for i in range(5):
            innerlist.append(Leaf())
        nestedlist.append(innerlist)
    leaflist = nestedlist[0]

    try:
        l = recover nestedlist
        return -1
    except TypeError as e:
        print(e)
        return 0


cdef cypclass Template[T]:
    T field

def test_recover_isolated_template():
    """
    >>> test_recover_isolated_template()
    0
    """
    template = Template[Leaf]()
    template.field = Leaf()

    try:
        t = recover template
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_template_with_aliased_field():
    """
    >>> test_recover_template_with_aliased_field()
    'recover' operand is not isolated
    0
    """
    template = Template[Leaf]()
    leaf = Leaf()
    template.field = leaf

    try:
        t = recover template
        return -1
    except TypeError as e:
        print(e)
        return 0

def test_recover_template_with_aliased_lock_field():
    """
    >>> test_recover_template_with_aliased_lock_field()
    0
    """
    template = <Template[lock Leaf]> new Template[lock Leaf]()
    leaf = <lock Leaf> recover Leaf()
    template.field = leaf

    try:
        t = recover template
        return 0
    except TypeError as e:
        print(e)
        return -1

def test_recover_template_with_aliased_active_field():
    """
    >>> test_recover_template_with_aliased_active_field()
    0
    """
    template = <Template[active Leaf]> new Template[active Leaf]()
    leaf = activate(recover Leaf())
    template.field = leaf

    try:
        t = recover template
        return 0
    except TypeError as e:
        print(e)
        return -1

