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, _): 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)
def __init__(self, ast, name=None): # Initialise the base class KernelType.__init__(self, ast, name=name) # What grid offset scheme this kernel expects self._index_offset = self._ktype.get_variable('index_offset').init if self._index_offset is None: raise ParseError("Meta-data error in kernel {0}: an INDEX_OFFSET " "must be specified and must be one of {1}".format( name, VALID_OFFSET_NAMES)) if self._index_offset.lower() not in VALID_OFFSET_NAMES: raise ParseError("Meta-data error in kernel {0}: INDEX_OFFSET " "has value '{1}' but must be one of {2}".format( name, self._index_offset, VALID_OFFSET_NAMES)) # Check that the meta-data for this kernel is valid if self._iterates_over is None: raise ParseError("Meta-data error in kernel {0}: ITERATES_OVER " "is missing. (Valid values are: {1})".format( name, VALID_ITERATES_OVER)) if self._iterates_over.lower() not in VALID_ITERATES_OVER: raise ParseError("Meta-data error in kernel {0}: ITERATES_OVER " "has value '{1}' but must be one of {2}".format( name, self._iterates_over.lower(), VALID_ITERATES_OVER)) # The list of kernel arguments self._arg_descriptors = [] have_grid_prop = False for init in self._inits: if init.name != 'arg': raise ParseError("Each meta_arg value must be of type " + "'arg' for the gocean1.0 api, but " + "found '{0}'".format(init.name)) # Pass in the name of this kernel for the purposes # of error reporting new_arg = GO1p0Descriptor(name, init) # Keep track of whether this kernel requires any # grid properties have_grid_prop = (have_grid_prop or (new_arg.type == "grid_property")) self._arg_descriptors.append(new_arg) # If this kernel expects a grid property then check that it # has at least one field object as an argument (which we # can use to access the grid) if have_grid_prop: have_fld = False for arg in self.arg_descriptors: if arg.type == "field": have_fld = True break if not have_fld: raise ParseError( "Kernel {0} requires a property of the grid but does " "not have any field objects as arguments.".format(name))
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))
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))
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))
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(RuntimeError) as err: _ = KernelType(ast) assert ("Kernel type testkern_eval_type does not bind a specific " "procedure" in str(err))
def test_get_int_array_err2(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 = fpapi.parse(MDATA, 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, _): 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)
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))
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"]
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"