git @ Cat's Eye Technologies Eightebed / master src / eightebed / tests.py
master

Tree @master (Download .tar.gz)

tests.py @masterraw · history · blame

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Test suite for (Python implementations of) the Eightebed programming language.
"""


def expect_type_error(fun):
    from .parser import TypeError
    try:
        fun()
    except TypeError as e:
        print('Traceback (most recent call last):')
        print('...')
        print('TypeError: {}'.format(e))


class Tests(object):
    """Class containing test cases for Eightebed.

    >>> from .parser import parse, Eightebed
    >>> from .drivers import parse_and_check, load_and_go
    >>> p = parse(Tests.simple_ok)
    >>> isinstance(p, Eightebed)
    True
    >>> p.typedecls
    []
    >>> p.vardecls
    [VarDecl('jim', TypeInt())]
    >>> p.block
    Block([AssignStmt(VarRef('jim'), IntConst(4))])
    >>> p = parse_and_check(Tests.simple_ok)

    >>> parse_and_check(Tests.double_declaration)
    Traceback (most recent call last):
    ...
    KeyError: 'jim already declared'

    >>> expect_type_error(lambda: parse_and_check(Tests.ptr_to_ptr))
    Traceback (most recent call last):
    ...
    TypeError: Pointer type must point to named type

    >>> expect_type_error(lambda: parse_and_check(Tests.ptr_to_int))
    Traceback (most recent call last):
    ...
    TypeError: Pointer type must point to named type

    >>> expect_type_error(lambda: parse_and_check(Tests.struct_within_struct))
    Traceback (most recent call last):
    ...
    TypeError: Structs may not contain other structs

    >>> expect_type_error(lambda: parse_and_check(Tests.named_int))
    Traceback (most recent call last):
    ...
    TypeError: Only structs may be named

    >>> expect_type_error(lambda: parse_and_check(Tests.dereference_outside_conditional))
    Traceback (most recent call last):
    ...
    TypeError: Attempt to dereference jim in non-safe context

    >>> expect_type_error(lambda: parse_and_check(Tests.dereference_outside_safe_area))
    Traceback (most recent call last):
    ...
    TypeError: Attempt to dereference jim in non-safe context

    >>> p = parse_and_check(Tests.dereference_within_nested_safe_area)
    >>> p is None
    False

    >>> expect_type_error(lambda: parse_and_check(Tests.dereference_after_free))
    Traceback (most recent call last):
    ...
    TypeError: Attempt to dereference jim in non-safe context

    Hey!  Enough of the static tests.  Let's run some actual Eightebed
    programs and check their output.

    >>> p = parse_and_check(Tests.allocated_values_initialized)
    >>> load_and_go(p)
    '0 '

    >>> p = parse_and_check(Tests.simple_arith)
    >>> load_and_go(p)
    '4 '

    >>> p = parse_and_check(Tests.loop_1)
    >>> load_and_go(p)
    '5 4 3 2 1 '

    >>> p = parse_and_check(Tests.allocating_loop)
    >>> load_and_go(p)
    ''

    >>> p = parse_and_check(Tests.free_invalidates)
    >>> load_and_go(p)
    '53 '

    >>> p = parse_and_check(Tests.alias_is_invalidated)
    >>> load_and_go(p)
    '100 99 98 97 96 95 94 93 92 91 90 89 88 '

    In principle, this test demonstrates that the memory freed by the
    free command can be re-used by a subsequent malloc expression.  Of
    course, since nothing is actually forcing the backend C compiler's
    implementation of malloc() to re-use memory that was previously
    free()'d, we don't actually test it here.

    >>> p = parse_and_check(Tests.allocate_and_free_loop)
    >>> load_and_go(p)
    '50 '

    """
    simple_ok = """\
    var int jim;
    {
        jim = 4;
    }
"""
    simple_arith = """\
    {
        if (((3 * 3) = (10 - 1)) & (4 > 3)) {
            print ((4 + 8) / 3);
        }
    }
"""
    double_declaration = """\
    var int jim;
    var ptr to node jim;
    {
        print 3;
    }
"""
    ptr_to_ptr = """\
    type node struct {
        int value;
        ptr to ptr to node next;
    };
    var node jim;
    {
        print [jim].value;
    }
"""
    ptr_to_int = """\
    var ptr to int kelly;
    {
        if valid kelly { print @kelly; }
    }
"""
    struct_within_struct = """\
    type kooba struct {
        int value;
        struct {
            int whirlygig;
        } barnard;
    };
    var kooba jim;
    {
        print [jim].value;
    }
"""
    named_int = """\
    type kooba int;
    var kooba jim;
    {
        print jim;
    }
"""
    dereference_outside_conditional = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    {
        jim = malloc node;
        print [@jim].value;
        free jim;
    }
"""
    dereference_outside_safe_area = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    var ptr to node murray;
    {
        jim = malloc node;
        if valid jim {
            jim = murray;
            print [@jim].value;
        }
        free jim;
    }
"""
    dereference_after_free = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    var ptr to node donald;
    {
        jim = malloc node;
        donald = jim;
        if valid jim {
            free donald;
            print [@jim].value;
        }
    }
"""
    dereference_within_nested_safe_area = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    {
        jim = malloc node;
        if valid jim {
            [@jim].next = malloc node;
        }
        if valid jim {
            if valid [@jim].next {
                print [@jim].value;
            }
        }
        free jim;
    }
"""
    allocated_values_initialized = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    var ptr to node nestor;
    {
        jim = malloc node;
        if valid jim {
            print [@jim].value;
            nestor = [@jim].next;
            if valid nestor {
                print 99;
            }
        }
        free jim;
    }
"""
    loop_1 = """\
    var int i;
    {
        i = 5;
        while i {
            print i;
            i = (i - 1);
        }
    }
"""
    allocating_loop = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    var ptr to node harry;
    var int i;
    {
        jim = malloc node;
        harry = jim;
        i = 100;
        while i {
            harry = malloc node;
            if valid jim {
                [@jim].value = i;
            }
            if valid jim {
                [@jim].next = harry;
                if valid harry {
                    jim = harry;
                }
            }
            i = (i - 1);
        }
    }
"""
    free_invalidates = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    {
        jim = malloc node;
        if valid jim {
            free jim;
        }
        if valid jim {
            print 42;
        }
        print 53;
    }
"""
    alias_is_invalidated = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node jim;
    var ptr to node harry;
    var ptr to node bertie;
    var ptr to node albert;
    var int i;
    {
        albert = malloc node;
        jim = albert;
        harry = jim;
        i = 100;
        while i {
            harry = malloc node;
            if valid jim {
                [@jim].value = i;
            }
            if (i = 87) {
                bertie = jim;
            }
            if valid jim {
                [@jim].next = harry;
                if valid harry {
                    jim = harry;
                }
            }
            i = (i - 1);
        }
        free bertie;
        jim = albert;
        while valid jim {
            if valid jim {
                print [@jim].value;
                jim = [@jim].next;
            }
        }
    }
"""
    allocate_and_free_loop = """\
    type node struct {
        int value;
        ptr to node next;
    };
    var ptr to node fred;
    var ptr to node george;
    var int i;
    {
        i = 100;
        while i {
            fred = malloc node;
            if valid fred {
                [@fred].value = i;
            }
            if (i = 50) {
                george = fred;
            } else {
                free fred;
            }
            i = (i - 1);
        }
        if valid george {
            print [@george].value;
        }
    }
"""


if __name__ == "__main__":
    import doctest
    doctest.testmod()