def test_scalar_invoke_uniq_declns_valid_intrinsic():
    ''' Tests that all valid intrinsic types for user-defined scalar
    arguments ('real', 'integer' and 'logical') are accepted by
    Invoke.unique_declarations().

    '''
    _, invoke_info = parse(os.path.join(BASE_PATH,
                                        "1.7_single_invoke_3scalar.f90"),
                           api=TEST_API)
    psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info)
    invoke = psy.invokes.invoke_list[0]

    # Test 'real' scalars
    const = LFRicConstants()
    scalars_real_args = invoke.unique_declarations(const.VALID_SCALAR_NAMES,
                                                   intrinsic_type="real")
    scalars_real = [arg.declaration_name for arg in scalars_real_args]
    assert scalars_real == ["a"]

    # Test 'integer' scalars
    scalars_integer_args = invoke.unique_declarations(const.VALID_SCALAR_NAMES,
                                                      intrinsic_type="integer")
    scalars_integer = [arg.declaration_name for arg in scalars_integer_args]
    assert scalars_integer == ["istep"]

    # Test 'logical' scalars
    scalars_logical_args = invoke.unique_declarations(const.VALID_SCALAR_NAMES,
                                                      intrinsic_type="logical")
    scalars_logical = [arg.declaration_name for arg in scalars_logical_args]
    assert scalars_logical == ["lswitch"]
def test_ad_scalar_type_no_inc():
    ''' Tests that an error is raised when the argument descriptor
    metadata for a scalar specifies 'GH_INC' access. '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    name = "testkern_qr_type"
    const = LFRicConstants()
    for argname in const.VALID_SCALAR_NAMES:
        code = CODE.replace("arg_type(" + argname + ",   gh_real,    gh_read)",
                            "arg_type(" + argname + ",   gh_real, gh_inc)", 1)
        ast = fpapi.parse(code, ignore_comments=False)
        with pytest.raises(ParseError) as excinfo:
            _ = DynKernMetadata(ast, name=name)
        assert ("scalar arguments must have read-only ('gh_read') or a "
                "reduction ['gh_sum'] access but found 'gh_inc'"
                in str(excinfo.value))
def test_ad_scalar_invalid_data_type():
    ''' Tests that an error is raised when the argument descriptor
    metadata for a scalar has an invalid data type. '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    name = "testkern_qr_type"
    code = CODE.replace("arg_type(gh_scalar,   gh_real,    gh_read)",
                        "arg_type(gh_scalar, gh_unreal, gh_read)", 1)
    ast = fpapi.parse(code, ignore_comments=False)
    const = LFRicConstants()
    with pytest.raises(ParseError) as excinfo:
        _ = DynKernMetadata(ast, name=name)
    assert ("In the LFRic API the 2nd argument of a 'meta_arg' entry should "
            "be a valid data type (one of {0}), but found 'gh_unreal' in "
            "'arg_type(gh_scalar, gh_unreal, gh_read)'.".format(
                const.VALID_SCALAR_DATA_TYPES) in str(excinfo.value))
def test_no_vector_scalar():
    ''' Tests that we raise an error when kernel metadata erroneously
    specifies a vector scalar argument. '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    name = "testkern_qr_type"
    const = LFRicConstants()
    for argname in const.VALID_SCALAR_NAMES:
        vectname = argname + " * 3"
        code = CODE.replace("arg_type(" + argname + ",   gh_real,    gh_read)",
                            "arg_type(" + vectname + ", gh_real, gh_read)", 1)
        ast = fpapi.parse(code, ignore_comments=False)
        with pytest.raises(ParseError) as excinfo:
            _ = DynKernMetadata(ast, name=name)
        assert ("vector notation is only supported for ['gh_field'] "
                "argument types but found '{0}'".format(vectname)
                in str(excinfo.value))
def test_scalar_different_data_types_invoke():
    ''' Tests that the same scalar cannot have different data types
    in different kernels within the same Invoke.

    '''
    _, invoke_info = parse(os.path.join(
        BASE_PATH, "4.16_multikernel_invokes_real_int_scalar_invalid.f90"),
                           api=TEST_API)
    psy = PSyFactory(TEST_API, distributed_memory=False).create(invoke_info)

    const = LFRicConstants()
    with pytest.raises(GenerationError) as excinfo:
        _ = psy.gen
    assert ("Scalar argument(s) ['b'] in Invoke "
            "'invoke_real_and_integer_scalars' have different metadata for "
            "data type ({0}) in different kernels. This is invalid.".format(
                const.VALID_SCALAR_DATA_TYPES) in str(excinfo.value))
def test_ad_scalar_type_too_many_args():
    ''' Tests that an error is raised when the argument descriptor
    metadata for a scalar has more than 3 args. '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    name = "testkern_qr_type"
    const = LFRicConstants()
    for argname in const.VALID_SCALAR_NAMES:
        code = CODE.replace(
            "arg_type(" + argname + ",   gh_integer, gh_read)",
            "arg_type(" + argname + ",   gh_integer, gh_read, w1)", 1)
        ast = fpapi.parse(code, ignore_comments=False)
        with pytest.raises(ParseError) as excinfo:
            _ = DynKernMetadata(ast, name=name)
        assert ("each 'meta_arg' entry must have 3 arguments if its first "
                "argument is 'gh_scalar', but found 4 in "
                "'arg_type(gh_scalar, gh_integer, gh_read, w1)'."
                in str(excinfo.value))
def test_ad_scalar_type_too_few_args():
    ''' Tests that an error is raised when the argument descriptor
    metadata for a scalar has fewer than 3 args.
    Note: This general check is also valid for all other argument types.

    '''
    fparser.logging.disable(fparser.logging.CRITICAL)
    name = "testkern_qr_type"
    const = LFRicConstants()
    for argname in const.VALID_SCALAR_NAMES:
        code = CODE.replace("arg_type(" + argname + ",   gh_real,    gh_read)",
                            "arg_type(" + argname + ",   gh_real)", 1)
        ast = fpapi.parse(code, ignore_comments=False)
        with pytest.raises(ParseError) as excinfo:
            _ = DynKernMetadata(ast, name=name)
        assert ("In the LFRic API each 'meta_arg' entry must have at least "
                "3 args, but found 2 in 'arg_type(gh_scalar, gh_real)'."
                in str(excinfo.value))
def test_ad_scalar_init_wrong_data_type(monkeypatch):
    ''' Test that an error is raised if an invalid data type
    is passed to the LFRicArgDescriptor._init_scalar() method. '''
    ast = fpapi.parse(CODE, ignore_comments=False)
    name = "testkern_qr_type"
    metadata = DynKernMetadata(ast, name=name)
    # Get a scalar argument descriptor and set a wrong data type
    scalar_arg = metadata._inits[0]
    scalar_arg.args[1].name = "gh_double"
    const = LFRicConstants()
    # Now try to trip the error by making the initial test think
    # that 'gh_double' is actually a valid data type
    monkeypatch.setattr(target=LFRicConstants,
                        name="VALID_ARG_DATA_TYPES",
                        value=LFRicConstants.VALID_ARG_DATA_TYPES +
                        ["gh_double"])
    with pytest.raises(InternalError) as excinfo:
        LFRicArgDescriptor(scalar_arg,
                           metadata.iterates_over)._init_scalar(scalar_arg)
    assert ("Expected one of {0} as the scalar data type but got 'gh_double'.".
            format(const.VALID_SCALAR_DATA_TYPES) in str(excinfo.value))