예제 #1
0
def test_get_int_array_section_subscript_err(monkeypatch):
    ''' Check that we raise the appropriate error if the parse tree for the
    LHS of the array declaration is broken. '''
    from fparser.two import Fortran2003
    # First create a valid KernelType object
    ast = parse(DIFF_BASIS, ignore_comments=False)
    ktype = KernelType(ast)
    # Create a valid fparser2 result
    assign = Fortran2003.Assignment_Stmt("gh_evaluator_targets(2) = [1, 2]")
    # Break the array constructor expression by replacing the
    # Section_Subscript_List with a str
    assign.children[0].items = (assign.children[0].items[0], "hello")

    # Use monkeypatch to ensure that that's the result that is returned
    # when we attempt to use fparser2 from within the routine under test

    def my_init(self, _):
        ''' dummy constructor '''
        self.items = assign.items

    monkeypatch.setattr(Fortran2003.Assignment_Stmt, "__init__", my_init)

    with pytest.raises(InternalError) as err:
        _ = ktype.get_integer_array("gh_evaluator_targets")
    assert ("expected array declaration to have a Section_Subscript_List but "
            "found" in str(err.value))
예제 #2
0
def test_get_int_array_err1(monkeypatch):
    ''' Tests that we raise the correct error if there is something wrong
    with the assignment statement obtained from fparser2. '''
    from fparser.two import Fortran2003
    # This is difficult as we have to break the result returned by fparser2.
    # We therefore create a valid KernelType object
    ast = fpapi.parse(MDATA, ignore_comments=False)
    ktype = KernelType(ast)
    # Next we create a valid fparser2 result
    my_assign = Fortran2003.Assignment_Stmt("my_array(2) = [1, 2]")
    # Break its `items` property by replacing the Name object with a string
    # (tuples are immutable so make a new one)
    broken_items = tuple(["invalid"] + list(my_assign.items[1:]))

    # Use monkeypatch to ensure that that the Assignment_Stmt that
    # is returned when we attempt to use fparser2 from within the
    # routine under test now has the broken tuple of items.

    def my_init(self, _):
        ''' dummy class '''
        self.items = broken_items
    monkeypatch.setattr(Fortran2003.Assignment_Stmt, "__init__", my_init)

    with pytest.raises(InternalError) as err:
        _ = ktype.get_integer_array("gh_evaluator_targets")
    assert "Unsupported assignment statement: 'invalid = [1, 2]'" in str(err)
예제 #3
0
def test_get_int_array_constructor_err(monkeypatch):
    ''' Check that we raise the appropriate error if we fail to parse the
    array constructor expression. '''
    from fparser.two import Fortran2003
    # First create a valid KernelType object
    ast = parse(DIFF_BASIS, ignore_comments=False)
    ktype = KernelType(ast)
    # Create a valid fparser2 result
    assign = Fortran2003.Assignment_Stmt("gh_evaluator_targets(2) = [1, 2]")
    # Break the array constructor expression (tuples are immutable so make a
    # new one)
    assign.items[2].items[1].items = tuple(["hello", "goodbye"])

    # Use monkeypatch to ensure that that's the result that is returned
    # when we attempt to use fparser2 from within the routine under test

    def my_init(self, _):
        ''' dummy class '''
        self.items = assign.items

    monkeypatch.setattr(Fortran2003.Assignment_Stmt, "__init__", my_init)
    with pytest.raises(InternalError) as err:
        _ = ktype.get_integer_array("gh_evaluator_targets")
    assert ("Failed to parse array constructor: '[hello, goodbye]'"
            in str(err.value))
예제 #4
0
def test_get_int_array_not_array():
    ''' Test that get_integer_array returns the expected error if the
    requested variable is not an array. '''
    ast = fpapi.parse(MDATA, ignore_comments=False)
    ktype = KernelType(ast)
    # Erroneously call get_integer_array with the name of a scalar meta-data
    # entry
    with pytest.raises(ParseError) as err:
        _ = ktype.get_integer_array("iterates_over")
    assert ("RHS of assignment is not an array constructor: 'iterates_over = "
            "cells'" in str(err))
예제 #5
0
def test_kerneltype_operates_on(operates):
    ''' Test the parsing of the 'operates_on' metadata element. '''
    code = CODE.replace("cell_column", operates)
    parse_tree = parse(code)
    ktype = KernelType(parse_tree)
    assert ktype.iterates_over == operates
    # Check that the parsing is not case sensitive
    code = CODE.replace("cell_column", operates.upper())
    parse_tree = parse(code)
    ktype = KernelType(parse_tree)
    assert ktype.iterates_over == operates
예제 #6
0
def test_kerneltype_iterates_over(iterates):
    ''' Test the parsing of the 'iterates_over' metadata element.
        TODO #870 remove this test. '''
    code = ITERATES_OVER_CODE.replace("cells", iterates)
    parse_tree = parse(code)
    ktype = KernelType(parse_tree)
    assert ktype.iterates_over == iterates
    # Check that the parsing is not case sensitive
    code = ITERATES_OVER_CODE.replace("cells", iterates.upper())
    parse_tree = parse(code)
    ktype = KernelType(parse_tree)
    assert ktype.iterates_over == iterates
예제 #7
0
def test_kerneltype_repr():
    '''Test that the __repr__ method in KernelType() behaves as expected.'''
    # With operates_on set
    parse_tree = parse(CODE)

    tmp = KernelType(parse_tree)
    assert repr(tmp) == "KernelType(test_type, cell_column)"

    # With iterates_over set
    parse_tree = parse(ITERATES_OVER_CODE)

    tmp = KernelType(parse_tree)
    assert repr(tmp) == "KernelType(test_type, cells)"
예제 #8
0
def test_kerneltype_repr():
    '''Test that the __repr__ method in KernelType() behaves as expected.'''

    parse_tree = parse(CODE)

    tmp = KernelType(parse_tree)
    assert repr(tmp) == "KernelType(test_type, cells)"
예제 #9
0
 def __init__(self, ast, name=None):
     KernelType.__init__(self, ast, name=name)
     self._arg_descriptors = []
     for init in self._inits:
         if init.name != 'arg_type':
             raise ParseError(
                 "dynamo0p1.py:DynKernelType:__init__: Each meta_arg "
                 "value must be of type 'arg_type' for the "
                 "dynamo0.1 api, but found '{0}'.".format(init.name))
         access = init.args[0].name
         funcspace = init.args[1].name
         stencil = init.args[2].name
         x1 = init.args[3].name
         x2 = init.args[4].name
         x3 = init.args[5].name
         self._arg_descriptors.append(
             DynDescriptor(access, funcspace, stencil, x1, x2, x3))
예제 #10
0
def test_get_int_err():
    ''' Tests that we raise the expected error if the meta-data contains
    an integer literal instead of a name. '''
    mdata = MDATA.replace("= cells", "= 1")
    ast = fpapi.parse(mdata, ignore_comments=False)
    with pytest.raises(ParseError) as err:
        _ = KernelType(ast)
    assert ("RHS of assignment is not a variable name: 'iterates_over = 1'" in
            str(err))
예제 #11
0
def test_kernel_binding_not_code():
    ''' Check that we raise the expected error when Kernel meta-data uses
    a specific binding but does not have 'code' as the generic name. '''
    mdata = MDATA.replace("code => test", "my_code => test")
    ast = fpapi.parse(mdata)
    with pytest.raises(ParseError) as err:
        _ = KernelType(ast)
    assert ("binds to a specific procedure but does not use 'code' as the "
            "generic name" in str(err))
예제 #12
0
def test_get_integer_variable_err():
    ''' Tests that we raise the expected error if the meta-data contains
    an integer literal instead of a name. '''
    mdata = DIFF_BASIS.replace("= cell_column", "= 1")
    ast = parse(mdata, ignore_comments=False)
    with pytest.raises(ParseError) as err:
        _ = KernelType(ast)
    assert ("RHS of assignment is not a variable name: 'operates_on = 1'"
            in str(err.value))
예제 #13
0
def test_kernel_binding_missing():
    ''' Check that we raise the correct error when the Kernel meta-data is
    missing the type-bound procedure giving the name of the subroutine. '''
    mdata = MDATA.replace(
        "contains\n    procedure, nopass :: code => testkern_eval_code\n", "")
    ast = fpapi.parse(mdata)
    with pytest.raises(ParseError) as err:
        _ = KernelType(ast)
    assert ("Kernel type testkern_eval_type does not bind a specific "
            "procedure" in str(err))
예제 #14
0
파일: gocean0p1.py 프로젝트: stfc/PSyclone
 def __init__(self, ast, name=None):
     KernelType.__init__(self, ast, name=name)
     self._arg_descriptors = []
     for init in self._inits:
         if init.name != 'arg':
             raise ParseError(
                 "gocean0p1.py:GOKernelType:__init__: Each meta_arg value "
                 "must be of type 'arg' for the gocean0.1 api, but found "
                 "'{0}'.".format(init.name))
         access = init.args[0].name
         funcspace = init.args[1].name
         stencil = init.args[2].name
         if len(init.args) != 3:
             raise ParseError(
                 "gocean0p1.py:GOKernelType:__init__: 'arg' type expects "
                 "3 arguments but found {0} in '{1}'".format(
                     str(len(init.args)), init.args))
         self._arg_descriptors.append(
             GODescriptor(access, funcspace, stencil))
예제 #15
0
def test_kerneltype_both_operates_on_iterates_over():
    ''' Check that KernelType raises the expected error if the kernel
    metadata specifies *both* operates_on and iterates_over. '''
    code = ITERATES_OVER_CODE.replace(
        "   contains\n", "     integer :: operates_on = cell_column\n"
        "   contains\n")
    parse_tree = parse(code)
    with pytest.raises(ParseError) as err:
        KernelType(parse_tree)
    assert ("kernel 'test_type' contains both 'operates_on' and "
            "'iterates_over'" in str(err.value))
예제 #16
0
def test_kerneltype_typename():
    '''Test that an exception is raised if the metadata type name is not
    what was expected.

    '''
    my_code = CODE.replace("meta_args", "invalid_name")
    parse_tree = parse(my_code)

    with pytest.raises(ParseError) as excinfo:
        _ = KernelType(parse_tree)
    assert "No kernel metadata with type name 'meta_args' found." \
        in str(excinfo.value)
예제 #17
0
def test_kerneltype_dimensions():
    '''Test that an exception is raised if the metadata variable is a
    multi-dimensional array.

    '''
    my_code = CODE.replace("dimension(1)", "dimension(1,1)")
    parse_tree = parse(my_code)

    with pytest.raises(ParseError) as excinfo:
        _ = KernelType(parse_tree)
    assert ("In kernel metadata 'test_type': 'meta_args' variable must be a "
            "1 dimensional array") in str(excinfo.value)
예제 #18
0
def test_kerneltype_nargs():
    '''Test that an exception is raised if the number of arguments does
    not match the specified number of arguments in the kernel
    metadata.

    '''
    my_code = CODE.replace("dimension(1)", "dimension(2)")
    parse_tree = parse(my_code)

    with pytest.raises(ParseError) as excinfo:
        _ = KernelType(parse_tree)
    assert ("In the 'meta_args' metadata, the number of args '2' and extent "
            "of the dimension '1' do not match.") in str(excinfo.value)
예제 #19
0
def test_kerneltype_brackets():
    '''Test that an exception is raised if the metadata is supplied within
    square brackets as this is not supported within the parser.

    '''
    my_code = CODE.replace("(/", "[")
    my_code = my_code.replace("/)", "]")
    parse_tree = parse(my_code)

    with pytest.raises(ParseError) as excinfo:
        _ = KernelType(parse_tree)
    assert ("Parser does not currently support [...] initialisation for "
            "'meta_args', please use (/.../) instead.") in str(excinfo.value)
예제 #20
0
def test_empty_kernel_name(monkeypatch):
    ''' Check that we raise the correct error when we get a blank string for
    the name of the Kernel subroutine. '''
    import fparser
    mdata = MDATA.replace("procedure, nopass :: code => testkern_eval_code",
                          "procedure, nopass :: testkern_eval_code")
    ast = fpapi.parse(mdata)
    # Break the AST
    for statement, _ in fpapi.walk(ast, -1):
        if isinstance(statement, fparser.one.statements.SpecificBinding):
            monkeypatch.setattr(statement, "name", "")
            break
    with pytest.raises(InternalError) as err:
        _ = KernelType(ast)
    assert ("Empty Kernel name returned for Kernel type testkern_eval_type"
            in str(err))
예제 #21
0
def test_get_int_array():
    ''' Tests for the KernelType.get_integer_array() method. '''
    ast = fpapi.parse(MDATA, ignore_comments=False)
    ktype = KernelType(ast)
    targets = ktype.get_integer_array("gh_evaluator_targets")
    assert targets == ["w0", "w1"]
    mdata = MDATA.replace("[W0, W1]", "(/W0, W1/)")
    ast = fpapi.parse(mdata, ignore_comments=False)
    ktype = KernelType(ast)
    targets = ktype.get_integer_array("gh_evaluator_targets")
    assert targets == ["w0", "w1"]
예제 #22
0
def test_kerneltype_both_operates_on_iterates_over():
    ''' Check that KernelType raises the expected error if the kernel
    metadata specifies *both* operates_on and iterates_over (the GOcean API
    uses iterates_over while LFRic uses operates_on).

    TODO #1204 this test can be removed once the check for this metadata
    has been moved into the API-specific subclasses.

    '''
    code = CODE.replace(
        "   contains\n", "     integer :: iterates_over = cell_column\n"
        "   contains\n")
    parse_tree = parse(code)
    with pytest.raises(ParseError) as err:
        KernelType(parse_tree)
    assert ("kernel 'test_type' contains both 'operates_on' and "
            "'iterates_over'" in str(err.value))
예제 #23
0
def test_get_integer_variable():
    ''' Test that the KernelType get_integer_variable method works as
    expected. '''
    parse_tree = parse(DIFF_BASIS)
    tmp = KernelType(parse_tree)
    # Check that we return None if the matched name is an array
    assert tmp.get_integer_variable("GH_SHAPE") is None
    assert tmp.get_integer_variable("gh_shape") is None

    new_code = DIFF_BASIS.replace(
        "integer :: gh_shape(2) = (/gh_quadrature_XYoZ, gh_quadrature_edge/)",
        "integer :: gh_shape = gh_quadrature_face")
    parse_tree = parse(new_code)
    tmp = KernelType(parse_tree)
    assert tmp.get_integer_variable("GH_SHAPE") == "gh_quadrature_face"
    assert tmp.get_integer_variable("Gh_Shape") == "gh_quadrature_face"
예제 #24
0
def test_get_int():
    ''' Tests for the KernelType.get_integer(). method '''
    ast = fpapi.parse(MDATA, ignore_comments=False)
    ktype = KernelType(ast)
    iter_val = ktype.get_integer_variable("iterates_over")
    assert iter_val == "cells"
예제 #25
0
def test_get_integer_array():
    ''' Test that the KernelType get_integer_array method works as
    expected. '''
    parse_tree = parse(DIFF_BASIS)
    tmp = KernelType(parse_tree)
    assert tmp.get_integer_array("gh_shape") == [
        'gh_quadrature_xyoz', 'gh_quadrature_edge'
    ]
    assert tmp.get_integer_array("GH_SHAPE") == [
        'gh_quadrature_xyoz', 'gh_quadrature_edge'
    ]
    new_code = DIFF_BASIS.replace("(/gh_quadrature_XYoZ, gh_quadrature_edge/)",
                                  "[gh_quadrature_XYoZ, gh_quadrature_edge]")
    parse_tree = parse(new_code)
    tmp = KernelType(parse_tree)
    assert tmp.get_integer_array("GH_SHAPE") == [
        'gh_quadrature_xyoz', 'gh_quadrature_edge'
    ]

    new_code = DIFF_BASIS.replace("gh_shape(2)", "gh_shape(3)")
    parse_tree = parse(new_code)
    tmp = KernelType(parse_tree)
    with pytest.raises(ParseError) as err:
        tmp.get_integer_array("gh_shape")
    assert ("declared length of array 'gh_shape' is 3 but constructor only "
            "contains 2 names: 'gh_shape" in str(err.value))

    # Use variable name instead of integer to dimension array
    new_code = DIFF_BASIS.replace("gh_shape(2)", "gh_shape(npts)")
    parse_tree = parse(new_code)
    tmp = KernelType(parse_tree)
    with pytest.raises(ParseError) as err:
        tmp.get_integer_array("gh_shape")
    assert ("array extent must be specified using an integer literal but "
            "found 'npts' for array 'gh_shape'" in str(err.value))

    # Only 1D arrays are supported
    new_code = DIFF_BASIS.replace("gh_shape(2)", "gh_shape(2,2)")
    parse_tree = parse(new_code)
    tmp = KernelType(parse_tree)
    with pytest.raises(ParseError) as err:
        tmp.get_integer_array("gh_shape")
    assert ("array must be 1D but found an array with 2 dimensions for name "
            "'gh_shape'" in str(err.value))

    # Break RHS so that it is not an array constructor
    new_code = DIFF_BASIS.replace("(/gh_quadrature_XYoZ, gh_quadrature_edge/)",
                                  "gh_quadrature_XYoZ")
    parse_tree = parse(new_code)
    tmp = KernelType(parse_tree)
    with pytest.raises(ParseError) as err:
        tmp.get_integer_array("gh_shape")
    assert "RHS of assignment is not an array constructor" in str(err.value)

    # Check that we return an empty list if the matched name is a scalar
    new_code = DIFF_BASIS.replace(
        "integer :: gh_shape(2) = (/gh_quadrature_XYoZ, gh_quadrature_edge/)",
        "integer :: gh_shape = gh_quadrature_face")
    parse_tree = parse(new_code)
    tmp = KernelType(parse_tree)
    assert tmp.get_integer_array("gh_shape") == []