# Copyright 2022-2025 The Ramble Authors
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.
"""Perform tests of the Application class"""
import deprecation
import pytest
from ramble.language.language_base import DirectiveError
from ramble.modkit import * # noqa
mod_types = [ModifierBase, BasicModifier] # noqa: F405
[docs]
@deprecation.fail_if_not_removed
@pytest.mark.parametrize("mod_class", mod_types)
def test_modifier_type_features(mod_class):
mod_path = "/path/to/mod"
test_mod = mod_class(mod_path)
assert hasattr(test_mod, "figure_of_merit_contexts")
assert hasattr(test_mod, "archive_patterns")
assert hasattr(test_mod, "figures_of_merit")
assert hasattr(test_mod, "modes")
assert hasattr(test_mod, "variable_modifications")
assert hasattr(test_mod, "software_specs")
assert hasattr(test_mod, "compilers")
assert hasattr(test_mod, "required_packages")
assert hasattr(test_mod, "success_criteria")
assert hasattr(test_mod, "builtins")
assert hasattr(test_mod, "modifier_variables")
assert hasattr(test_mod, "executable_modifiers")
assert hasattr(test_mod, "env_var_modifications")
assert hasattr(test_mod, "maintainers")
assert hasattr(test_mod, "package_manager_configs")
[docs]
def add_mode(mod_inst, mode_num=1):
mode_name = "TestMode%s" % mode_num
mode_desc = "This is a test mode"
mod_inst.mode(mode_name, description=mode_desc) # noqa: F405
mode_def = {"name": mode_name, "description": mode_desc}
return mode_def
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_mode_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_mode(mod_inst).copy())
assert hasattr(mod_inst, "modes")
for test_def in test_defs:
mode_name = test_def["name"]
assert mode_name in mod_inst.modes
assert "description" in mod_inst.modes[mode_name]
assert mod_inst.modes[mode_name]["description"] == test_def["description"]
[docs]
def add_variable_modification(mod_inst, var_mod_num=1):
var_mod_name = f"variable_{var_mod_num}"
var_mod_mod = "test_append"
var_mod_method = "append"
var_mod_mode = "test_mode"
var_mod_modes = ["another_mode1", "another_mode2"]
var_mod_def = {
"name": var_mod_name,
"modification": var_mod_mod,
"method": var_mod_method,
"mode": var_mod_mode,
"modes": var_mod_modes.copy(),
}
mod_inst.variable_modification(
var_mod_name, var_mod_mod, var_mod_method, mode=var_mod_mode, modes=var_mod_modes
)
return var_mod_def
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_variable_modification_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_variable_modification(mod_inst).copy())
test_defs.append(add_variable_modification(mod_inst, 2).copy())
test_defs.append(add_variable_modification(mod_inst).copy())
expected_attrs = ["modification", "method"]
assert hasattr(mod_inst, "variable_modifications")
mod_count = 0
for mode_name in mod_inst.variable_modifications:
for var_name in mod_inst.variable_modifications[mode_name]:
for modification in mod_inst.variable_modifications[mode_name][var_name]:
mod_count += 1
assert mod_count == 9 # Each call to add_variable_modification adds 3 modifications
for test_def in test_defs:
var_name = test_def["name"]
mode_name = test_def["mode"]
assert mode_name in mod_inst.variable_modifications
assert var_name in mod_inst.variable_modifications[mode_name]
found_match = (
False if len(mod_inst.variable_modifications[mode_name][var_name]) > 0 else True
)
for modification in mod_inst.variable_modifications[mode_name][var_name]:
match = True
for attr in expected_attrs:
assert attr in modification
if test_def[attr] != modification[attr]:
match = False
if match:
found_match = True
assert found_match
for mode_name in test_def["modes"]:
found_match = (
False if len(mod_inst.variable_modifications[mode_name][var_name]) > 0 else True
)
assert mode_name in mod_inst.variable_modifications
assert var_name in mod_inst.variable_modifications[mode_name]
for modification in mod_inst.variable_modifications[mode_name][var_name]:
match = True
for attr in expected_attrs:
assert attr in modification
if test_def[attr] != modification[attr]:
match = False
if match:
found_match = True
assert found_match
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_variable_modification_invalid_method(mod_class):
var_mod_name = "invalid_method_variable"
var_mod_mod = "invalid_method_mod"
var_mod_method = "invalid"
var_mod_mode = "invalid_method_mode"
with pytest.raises(
DirectiveError, match="variable_modification directive given an invalid method"
):
mod_inst = mod_class("/not/a/path")
mod_inst.variable_modification(
var_mod_name, var_mod_mod, var_mod_method, mode=var_mod_mode
)
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_variable_modification_missing_mode(mod_class):
var_mod_name = "missing_mode_variable"
var_mod_mod = "missing_mode_mod"
var_mod_method = "set"
with pytest.raises(DirectiveError, match="mode or modes to be defined"):
mod_inst = mod_class("/not/a/path")
mod_inst.variable_modification(var_mod_name, var_mod_mod, var_mod_method)
[docs]
def add_software_spec(mod_inst, spec_num=1):
spec_name = f"SoftwarePackage{spec_num}"
pkg_spec = "pkg@1.1 target=x86_64"
compiler_spec = "pkg@1.1"
compiler = "gcc9"
spec_def = {
"name": spec_name,
"pkg_spec": pkg_spec,
"compiler_spec": compiler_spec,
"compiler": compiler,
}
mod_inst.software_spec(spec_name, pkg_spec, compiler_spec, compiler)
return spec_def
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_software_spec_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_software_spec(mod_inst).copy())
expected_attrs = ["pkg_spec", "compiler_spec", "compiler"]
assert hasattr(mod_inst, "software_specs")
for test_def in test_defs:
spec_name = test_def["name"]
assert spec_name in mod_inst.software_specs
for attr in expected_attrs:
assert attr in mod_inst.software_specs[spec_name]
assert test_def[attr] == mod_inst.software_specs[spec_name][attr]
[docs]
def add_compiler(mod_inst, spec_num=1):
spec_name = f"CompilerPackage{spec_num}"
pkg_spec = "compiler@1.1 target=x86_64"
compiler_spec = "compiler@1.1"
compiler = None
spec_def = {
"name": spec_name,
"pkg_spec": pkg_spec,
"compiler_spec": compiler_spec,
"compiler": compiler,
}
mod_inst.define_compiler(spec_name, pkg_spec, compiler_spec, compiler)
return spec_def
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_define_compiler_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_compiler(mod_inst).copy())
expected_attrs = ["pkg_spec", "compiler_spec", "compiler"]
assert hasattr(mod_inst, "compilers")
for test_def in test_defs:
spec_name = test_def["name"]
assert spec_name in mod_inst.compilers
for attr in expected_attrs:
assert attr in mod_inst.compilers[spec_name]
assert test_def[attr] == mod_inst.compilers[spec_name][attr]
[docs]
def add_required_package(mod_inst, pkg_num=1):
pkg_name = f"RequiredPackage{pkg_num}"
pkg_def = {
"name": pkg_name,
}
mod_inst.required_package(pkg_name)
return pkg_def
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_required_package_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_required_package(mod_inst).copy())
assert hasattr(mod_inst, "required_packages")
for test_def in test_defs:
pkg_name = test_def["name"]
assert pkg_name in mod_inst.required_packages
[docs]
def add_figure_of_merit_context(mod_inst, context_num=1):
name = f"FOMContext{context_num}"
regex = "test(?P<test>[fom]+)regex"
output_format = "{test}"
context_def = {
"name": name,
"regex": regex,
"output_format": output_format,
}
mod_inst.figure_of_merit_context(name, regex, output_format)
return context_def
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_figure_of_merit_context_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_figure_of_merit_context(mod_inst).copy())
expected_attrs = ["regex", "output_format"]
assert hasattr(mod_inst, "figure_of_merit_contexts")
for test_def in test_defs:
name = test_def["name"]
assert name in mod_inst.figure_of_merit_contexts
for attr in expected_attrs:
assert attr in mod_inst.figure_of_merit_contexts[name]
assert test_def[attr] == mod_inst.figure_of_merit_contexts[name][attr]
[docs]
def add_archive_pattern(mod_inst, archive_num=1):
pattern = f"my_archive{archive_num}.*"
mod_inst.archive_pattern(pattern)
return pattern
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_archive_pattern_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_archive_pattern(mod_inst))
assert hasattr(mod_inst, "archive_patterns")
for test_def in test_defs:
pattern = test_def
assert pattern in mod_inst.archive_patterns
assert pattern == mod_inst.archive_patterns[pattern]
[docs]
def add_executable_modifier(mod_inst, exec_mod_num=1):
mod_name = f"exec_mod{exec_mod_num}"
mod_inst.executable_modifier(mod_name)
return mod_name
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_executable_modifier_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_executable_modifier(mod_inst))
assert hasattr(mod_inst, "executable_modifiers")
for test_def in test_defs:
mod_name = test_def
assert mod_name in mod_inst.executable_modifiers
assert mod_name == mod_inst.executable_modifiers[mod_name]
[docs]
def add_env_var_modification(mod_inst, env_var_mod_num=1):
mod_name = f"env_var_mod_{env_var_mod_num}"
mod_val = f"value_{env_var_mod_num}"
mod_method = "set"
mod_mode = "env_var_mod_mode"
test_defs = {"name": mod_name, "modification": mod_val, "method": mod_method, "mode": mod_mode}
mod_inst.env_var_modification(mod_name, mod_val, mode=mod_mode)
return test_defs
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_env_var_modification_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_env_var_modification(mod_inst))
assert hasattr(mod_inst, "env_var_modifications")
for test_def in test_defs:
method = test_def["method"]
mode = test_def["mode"]
assert method in mod_inst.env_var_modifications[mode]
if method == "set":
assert test_def["name"] in mod_inst.env_var_modifications[mode][method]
assert (
test_def["modification"]
== mod_inst.env_var_modifications[mode][method][test_def["name"]]
)
[docs]
def add_modifier_variable(mod_inst, mod_var_num=1):
var_name = f"mod_var_{mod_var_num}"
var_default = f"default_{mod_var_num}"
var_desc = f"Test variable {mod_var_num}"
var_mode = "mod_var_mode"
test_defs = {
"name": var_name,
"default": var_default,
"description": var_desc,
"mode": var_mode,
}
mod_inst.modifier_variable(var_name, default=var_default, description=var_desc, mode=var_mode)
return test_defs
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_modifier_variable_directive(mod_class):
test_defs = []
mod_inst = mod_class("/not/a/path")
test_defs.append(add_modifier_variable(mod_inst))
assert hasattr(mod_inst, "modifier_variables")
for test_def in test_defs:
mode = test_def["mode"]
var_name = test_def["name"]
assert mode in mod_inst.modifier_variables
assert test_def["name"] in mod_inst.modifier_variables[mode]
assert test_def["description"] == mod_inst.modifier_variables[mode][var_name].description
assert test_def["default"] == mod_inst.modifier_variables[mode][var_name].default
[docs]
@pytest.mark.parametrize("mod_class", mod_types)
def test_modifier_class_attributes(mod_class):
mod_inst = mod_class("/not/a/path")
mod_copy = mod_inst.copy()
mod_copy.mode("added_mode", description="Mode added to test attributes")
assert "added_mode" in mod_copy.modes
assert "added_mode" not in mod_inst.modes