full coverage of inputs linter

and several small improvements

- lint for empty param name / type
- distinct option definition possibilities for selects and selects in
conditionals
- condtional parameter
  - check for exactly 1 conditional param (before only 0)
  - warn if boolean select param for conditional
  - warn for optional and multiple select
This commit is contained in:
Matthias Bernt
2022-01-17 11:07:48 +01:00
parent 1b5f120189
commit 96f0e72887
2 changed files with 270 additions and 60 deletions
+36 -14
View File
@@ -66,14 +66,23 @@ def lint_inputs(tool_xml, lint_ctx):
if "name" in param_attrib and "argument" in param_attrib:
if param_attrib.get("name") == _parse_name(None, param_attrib.get("argument")):
lint_ctx.warn(f"Param input [{param_name}] 'name' attribute is redundant if argument implies the same name.")
if param_name.strip() == "":
lint_ctx.error("Param input with empty name.", line=param.sourceline, xpath=tool_xml.getpath(param))
elif not is_valid_cheetah_placeholder(param_name):
lint_ctx.warn(f"Param input [{param_name}] is not a valid Cheetah placeholder.", line=param.sourceline, xpath=tool_xml.getpath(param))
# TODO lint for params with duplicated name (in inputs & outputs)
if "type" not in param_attrib:
lint_ctx.error(f"Param input [{param_name}] input with no type specified.", line=param.sourceline, xpath=tool_xml.getpath(param))
continue
elif param_attrib["type"].strip() == "":
lint_ctx.error(f"Param input [{param_name}] with empty type specified.", line=param.sourceline, xpath=tool_xml.getpath(param))
continue
param_type = param_attrib["type"]
if not is_valid_cheetah_placeholder(param_name):
lint_ctx.warn(f"Param input [{param_name}] is not a valid Cheetah placeholder.", line=param.sourceline, xpath=tool_xml.getpath(param))
# TODO lint for valid param type - attribute combinations
# TODO lint required attributes for valid each param type
if param_type == "data":
if "format" not in param_attrib:
@@ -89,13 +98,18 @@ def lint_inputs(tool_xml, lint_ctx):
lint_ctx.warn(f"Select parameter [{param_name}] uses deprecated 'dynamic_options' attribute.", line=param.sourceline, xpath=tool_xml.getpath(param))
# check if options are defined by exactly one possibility
if (dynamic_options is not None) + (len(options) > 0) + (len(select_options) > 0) != 1:
lint_ctx.error(f"Select parameter [{param_name}] options have to be defined by either 'option' children elements, a 'options' element or the 'dynamic_options' attribute.", line=param.sourceline, xpath=tool_xml.getpath(param))
if param.getparent().tag != "conditional":
if (dynamic_options is not None) + (len(options) > 0) + (len(select_options) > 0) != 1:
lint_ctx.error(f"Select parameter [{param_name}] options have to be defined by either 'option' children elements, a 'options' element or the 'dynamic_options' attribute.", line=param.sourceline, xpath=tool_xml.getpath(param))
else:
if len(select_options) == 0:
lint_ctx.error(f"Select parameter of a conditional [{param_name}] options have to be defined by 'option' children elements.", line=param.sourceline, xpath=tool_xml.getpath(param))
# lint dynamic options
if len(options) == 1:
filters = options[0].findall("./filter")
# lint filters
# TODO check if dataset is available for filters referring other datasets
filter_adds_options = False
for f in filters:
ftype = f.get("type", None)
@@ -113,6 +127,8 @@ def lint_inputs(tool_xml, lint_ctx):
from_parameter = options[0].get("from_parameter", None)
from_dataset = options[0].get("from_dataset", None)
from_data_table = options[0].get("from_data_table", None)
# TODO check if input param is present for from_dataset
if (from_file is None and from_parameter is None
and from_dataset is None and from_data_table is None
and not filter_adds_options):
@@ -136,7 +152,7 @@ def lint_inputs(tool_xml, lint_ctx):
lint_ctx.warn(f"Select parameter [{param_name}] options uses deprecated 'transform_lines' attribute.", line=options[0].sourceline, xpath=tool_xml.getpath(options[0]))
elif len(options) > 1:
lint_ctx.error(f"Select parameter [{param_name}] contains multiple options elements", line=options[1].sourceline, xpath=tool_xml.getpath(options[1]))
lint_ctx.error(f"Select parameter [{param_name}] contains multiple options elements.", line=options[1].sourceline, xpath=tool_xml.getpath(options[1]))
# lint statically defined options
if any('value' not in option.attrib for option in select_options):
@@ -174,6 +190,7 @@ def lint_inputs(tool_xml, lint_ctx):
# TODO: Validate type, much more...
# lint validators
# TODO check if dataset is available for validators referring other datasets
validators = param.findall("./validator")
for validator in validators:
vtype = validator.attrib['type']
@@ -184,13 +201,13 @@ def lint_inputs(tool_xml, lint_ctx):
if attrib in validator.attrib and vtype not in ATTRIB_VALIDATOR_COMPATIBILITY[attrib]:
lint_ctx.error(f"Parameter [{param_name}]: attribute '{attrib}' is incompatible with validator of type '{vtype}'", line=validator.sourceline, xpath=tool_xml.getpath(validator))
if vtype == "expression" and validator.text is None:
lint_ctx.error(f"Parameter [{param_name}]: expression validator without content")
lint_ctx.error(f"Parameter [{param_name}]: expression validator without content", line=validator.sourceline, xpath=tool_xml.getpath(validator))
if vtype not in ["expression", "regex"] and validator.text is not None:
lint_ctx.warn(f"Parameter [{param_name}]: '{vtype}' validators are not expected to contain text (found '{validator.text}')", line=validator.sourceline, xpath=tool_xml.getpath(validator))
if vtype in ["in_range", "length", "dataset_metadata_in_range"] and ("min" not in validator.attrib and "max" not in validator.attrib):
lint_ctx.error(f"Parameter [{param_name}]: '{vtype}' validators need to define the 'min' or 'max' attribute(s)", line=validator.sourceline, xpath=tool_xml.getpath(validator))
if vtype in ["metadata"] and ("check" not in validator.attrib and "skip" not in validator.attrib):
lint_ctx.error(f"Parameter [{param_name}]: '{vtype}' validators need to define the 'check' or 'skip' attribute(s) {validator.attrib}", line=validator.sourceline, xpath=tool_xml.getpath(validator))
lint_ctx.error(f"Parameter [{param_name}]: '{vtype}' validators need to define the 'check' or 'skip' attribute(s)", line=validator.sourceline, xpath=tool_xml.getpath(validator))
if vtype in ["value_in_data_table", "value_not_in_data_table", "dataset_metadata_in_data_table", "dataset_metadata_not_in_data_table"] and "table_name" not in validator.attrib:
lint_ctx.error(f"Parameter [{param_name}]: '{vtype}' validators need to define the 'table_name' attribute", line=validator.sourceline, xpath=tool_xml.getpath(validator))
@@ -202,14 +219,17 @@ def lint_inputs(tool_xml, lint_ctx):
if conditional.get("value_from"):
# Probably only the upload tool use this, no children elements
continue
first_param = conditional.find("param")
if first_param is None:
lint_ctx.error(f"Conditional [{conditional_name}] has no child <param>", line=conditional.sourceline, xpath=tool_xml.getpath(conditional))
first_param = conditional.findall("param")
if len(first_param) != 1:
lint_ctx.error(f"Conditional [{conditional_name}] needs exactly one child <param> found {len(first_param)}", line=conditional.sourceline, xpath=tool_xml.getpath(conditional))
continue
first_param = first_param[0]
first_param_type = first_param.get('type')
if first_param_type not in ['select', 'boolean']:
lint_ctx.warn(f'Conditional [{conditional_name}] first param should have type="select" /> or type="boolean"', line=first_param.sourceline, xpath=tool_xml.getpath(first_param))
lint_ctx.error(f'Conditional [{conditional_name}] first param should have type="select" (or type="boolean" which is discouraged)', line=first_param.sourceline, xpath=tool_xml.getpath(first_param))
continue
elif first_param_type == 'boolean':
lint_ctx.warn(f'Conditional [{conditional_name}] first param of type="boolean" is discouraged, use a select', line=first_param.sourceline, xpath=tool_xml.getpath(first_param))
if first_param_type == 'select':
select_options = _find_with_attribute(first_param, 'option', 'value')
@@ -220,14 +240,15 @@ def lint_inputs(tool_xml, lint_ctx):
first_param.get('falsevalue', 'false')
]
if string_as_bool(first_param.get('optional', False)):
lint_ctx.warn(f"Conditional [{conditional_name}] test parameter cannot be optional", line=first_param.sourceline, xpath=tool_xml.getpath(first_param))
for incomp in ["optional", "multiple"]:
if string_as_bool(first_param.get(incomp, False)):
lint_ctx.warn(f'Conditional [{conditional_name}] test parameter cannot be {incomp}="true"', line=first_param.sourceline, xpath=tool_xml.getpath(first_param))
whens = conditional.findall('./when')
if any('value' not in when.attrib for when in whens):
lint_ctx.error(f"Conditional [{conditional_name}] when without value", line=conditional.sourceline, xpath=tool_xml.getpath(conditional))
when_ids = [w.get('value') for w in whens]
when_ids = [w.get('value') for w in whens if w.get('value') is not None]
for option_id in option_ids:
if option_id not in when_ids:
@@ -241,6 +262,7 @@ def lint_inputs(tool_xml, lint_ctx):
lint_ctx.warn(f"Conditional [{conditional_name}] no truevalue/falsevalue found for when block '{when_id}'", line=conditional.sourceline, xpath=tool_xml.getpath(conditional))
if datasource:
# TODO only display is subtag of inputs, uihints is a separate top level tag (supporting only attrib minwidth)
for datasource_tag in ('display', 'uihints'):
if not any(param.tag == datasource_tag for param in inputs):
lint_ctx.info(f"{datasource_tag} tag usually present in data sources", line=tool_line, xpath=tool_path)
+234 -46
View File
@@ -75,11 +75,17 @@ HELP_INVALID_RST = """
"""
# test tool xml for inputs linter
NO_INPUTS_SECTION_XML = """
INPUTS_NO_INPUTS = """
<tool>
</tool>
"""
INPUTS_NO_INPUTS_DATASOURCE = """
<tool tool_type="data_source">
<inputs/>
</tool>
"""
INPUTS_REDUNDANT_NAME = """
<tool>
<inputs>
@@ -88,19 +94,99 @@ INPUTS_REDUNDANT_NAME = """
</tool>
"""
NO_WHEN_IN_CONDITIONAL_XML = """
INPUTS_VALID = """
<tool>
<inputs>
<conditional name="labels">
<param name="label_select" type="select" label="Points to label">
<param name="txt_param" type="text"/>
<param name="int_param" type="integer"/>
</inputs>
</tool>
"""
INPUTS_PARAM_NAME = """
<tool>
<inputs>
<param type="text"/>
<param name="" type="text"/>
<param name="2" type="text"/>
<param argument="--valid" type="text"/>
</inputs>
</tool>
"""
INPUTS_PARAM_TYPE = """
<tool>
<inputs>
<param name="valid_name"/>
<param argument="--another-valid-name" type=""/>
</inputs>
</tool>
"""
INPUTS_DATA_PARAM = """
<tool>
<inputs>
<param name="valid_name" type="data"/>
</inputs>
</tool>
"""
INPUTS_CONDITIONAL = """
<tool>
<inputs>
<conditional>
<param name="select" type="select"/>
</conditional>
<conditional name="cond_wo_param">
</conditional>
<conditional name="cond_w_mult_param">
<param name="select3" type="select"><option value="A">A</option><option value="B">B</option></param>
<param name="select4" type="select"><option value="A">A</option><option value="B">B</option></param>
<when value="A"/>
<when value="B"/>
</conditional>
<conditional name="cond_boolean">
<param name="bool" type="boolean"/>
<when value="true"/>
<when value="false"/>
<when value="False"/>
</conditional>
<conditional name="cond_text">
<param name="text" type="text"/>
</conditional>
<conditional name="cond_w_optional_select">
<param name="optionalselect" type="select" optional="true"><option value="A">A</option><option value="B">B</option></param>
<when value="A"/>
<when value="B"/>
</conditional>
<conditional name="cond_w_multiple_select">
<param name="multipleselect" type="select" multiple="true"><option value="A">A</option><option value="B">B</option></param>
<when value="A"/>
<when value="B"/>
</conditional>
<conditional name="when_wo_value">
<param name="select3" type="select"><option value="A">A</option><option value="B">B</option></param>
<when/>
<when value="A"/>
<when value="B"/>
</conditional>
<conditional name="missing_when">
<param name="label_select" type="select">
<option value="none" selected="True">None</option>
</param>
</conditional>
<conditional name="missing_option">
<param name="missing_option" type="select">
<option value="none" selected="True">None</option>
</param>
<when value="none"/>
<when value="absent"/>
</conditional>
</inputs>
</tool>
"""
RADIO_SELECT_INCOMPATIBILITIES = """
INPUTS_SELECT_INCOMPATIBLE_DISPLAY = """
<tool>
<inputs>
<param name="radio_select" type="select" display="radio" optional="true" multiple="true">
@@ -120,7 +206,7 @@ RADIO_SELECT_INCOMPATIBILITIES = """
</tool>
"""
SELECT_DUPLICATED_OPTIONS = """
INPUTS_SELECT_DUPLICATED_OPTIONS = """
<tool>
<inputs>
<param name="select" type="select" optional="true" multiple="true">
@@ -143,6 +229,7 @@ SELECT_DUPLICATED_OPTIONS_WITH_DIFF_SELECTED = """
"""
SELECT_DEPRECATIONS = """
INPUTS_SELECT_DEPRECATIONS = """
<tool>
<inputs>
<param name="select_do" type="select" dynamic_options="blah()"/>
@@ -156,7 +243,7 @@ SELECT_DEPRECATIONS = """
</tool>
"""
SELECT_OPTION_DEFINITIONS = """
INPUTS_SELECT_OPTION_DEFINITIONS = """
<tool>
<inputs>
<param name="select_noopt" type="select"/>
@@ -175,27 +262,44 @@ SELECT_OPTION_DEFINITIONS = """
<option>option wo value</option>
<option value="value"/>
</param>
</inputs>
</tool>
"""
VALIDATOR_INCOMPATIBILITIES = """
<tool name="BWA Mapper" id="bwa" version="1.0.1" display_interface="true" require_login="true" hidden="true">
<description>The BWA Mapper</description>
<version_command interpreter="python">bwa.py --version</version_command>
<inputs>
<param name="param_name" type="text">
<validator type="in_range">TEXT</validator>
<validator type="regex" filename="blah"/>
<param name="select_meta_file_key_incomp" type="select">
<options from_data_table="xyz" meta_file_key="dbkey"/>
</param>
</inputs>
</tool>
"""
VALIDATOR_CORRECT = """
<tool name="BWA Mapper" id="bwa" version="1.0.1" display_interface="true" require_login="true" hidden="true">
<description>The BWA Mapper</description>
<version_command interpreter="python">bwa.py --version</version_command>
INPUTS_SELECT_FILTER = """
<tool>
<inputs>
<param name="select_filter_types" type="select">
<options from_data_table="xyz">
<filter/>
<filter type="unknown_filter_type"/>
</options>
</param>
</inputs>
</tool>
"""
INPUTS_VALIDATOR_INCOMPATIBILITIES = """
<tool>
<inputs>
<param name="param_name" type="text">
<validator type="in_range">TEXT</validator>
<validator type="regex" filename="blah"/>
<validator type="expression"/>
<validator type="value_in_data_table"/>
</param>
<param name="another_param_name" type="data" format="bed">
<validator type="metadata"/>
</param>
</inputs>
</tool>
"""
INPUTS_VALIDATOR_CORRECT = """
<tool>
<inputs>
<param name="data_param" type="data" format="data">
<validator type="metadata" check="md1,md2" skip="md3,md4" message="cutom validation message" negate="true"/>
@@ -237,6 +341,16 @@ VALIDATOR_CORRECT = """
</tool>
"""
REPEATS = """
<tool>
<inputs>
<repeat>
<param name="another_param_name" type="data" format="bed"/>
</repeat>
</inputs>
</tool>
"""
# test tool xml for outputs linter
# check that linter accepts format source for collection elements as means to specify format
@@ -385,10 +499,18 @@ TESTS = [
and len(x.info_messages) == 0 and len(x.valid_messages) == 1 and len(x.warn_messages) == 1 and len(x.error_messages) == 0
),
(
NO_INPUTS_SECTION_XML, inputs.lint_inputs,
INPUTS_NO_INPUTS, inputs.lint_inputs,
lambda x:
'Found no input parameters.' in x.warn_messages
and len(x.warn_messages) == 1 and len(x.error_messages) == 0
and len(x.info_messages) == 0 and len(x.valid_messages) == 0 and len(x.warn_messages) == 1 and len(x.error_messages) == 0
),
(
INPUTS_NO_INPUTS_DATASOURCE, inputs.lint_inputs,
lambda x:
'No input parameters, OK for data sources' in x.info_messages
and 'display tag usually present in data sources' in x.info_messages
and 'uihints tag usually present in data sources' in x.info_messages
and len(x.info_messages) == 3 and len(x.valid_messages) == 0 and len(x.warn_messages) == 0 and len(x.error_messages) == 0
),
(
INPUTS_REDUNDANT_NAME, inputs.lint_inputs,
@@ -397,13 +519,53 @@ TESTS = [
and len(x.warn_messages) == 1 and len(x.error_messages) == 0
),
(
NO_WHEN_IN_CONDITIONAL_XML, inputs.lint_inputs,
INPUTS_VALID, inputs.lint_inputs,
lambda x:
"Conditional [labels] no <when /> block found for select option 'none'" in x.warn_messages
and len(x.warn_messages) == 1 and len(x.error_messages) == 0
"Found 2 input parameters." in x.info_messages
and len(x.info_messages) == 1 and len(x.valid_messages) == 0 and len(x.warn_messages) == 0 and len(x.error_messages) == 0
),
(
RADIO_SELECT_INCOMPATIBILITIES, inputs.lint_inputs,
INPUTS_PARAM_NAME, inputs.lint_inputs,
lambda x:
"Found 4 input parameters." in x.info_messages
and 'Param input [2] is not a valid Cheetah placeholder.' in x.warn_messages
and 'Found param input with no name specified.' in x.error_messages
and 'Param input with empty name.' in x.error_messages
and len(x.info_messages) == 1 and len(x.valid_messages) == 0 and len(x.warn_messages) == 1 and len(x.error_messages) == 2
),
(
INPUTS_PARAM_TYPE, inputs.lint_inputs,
lambda x:
"Found 2 input parameters." in x.info_messages
and 'Param input [valid_name] input with no type specified.' in x.error_messages
and 'Param input [another_valid_name] with empty type specified.' in x.error_messages
and len(x.info_messages) == 1 and len(x.valid_messages) == 0 and len(x.warn_messages) == 0 and len(x.error_messages) == 2
),
(
INPUTS_DATA_PARAM, inputs.lint_inputs,
lambda x:
"Found 1 input parameters." in x.info_messages
and "Param input [valid_name] with no format specified - 'data' format will be assumed." in x.warn_messages
and len(x.info_messages) == 1 and len(x.valid_messages) == 0 and len(x.warn_messages) == 1 and len(x.error_messages) == 0
),
(
INPUTS_CONDITIONAL, inputs.lint_inputs,
lambda x:
"Conditional without a name" in x.error_messages
and "Select parameter of a conditional [select] options have to be defined by 'option' children elements." in x.error_messages
and 'Conditional [cond_wo_param] needs exactly one child <param> found 0' in x.error_messages
and 'Conditional [cond_w_mult_param] needs exactly one child <param> found 2' in x.error_messages
and 'Conditional [cond_text] first param should have type="select" (or type="boolean" which is discouraged)' in x.error_messages
and 'Conditional [cond_boolean] first param of type="boolean" is discouraged, use a select' in x.warn_messages
and "Conditional [cond_boolean] no truevalue/falsevalue found for when block 'False'" in x.warn_messages
and 'Conditional [cond_w_optional_select] test parameter cannot be optional="true"' in x.warn_messages
and 'Conditional [cond_w_multiple_select] test parameter cannot be multiple="true"' in x.warn_messages
and "Conditional [when_wo_value] when without value" in x.error_messages
and "Conditional [missing_when] no <when /> block found for select option 'none'" in x.warn_messages
and len(x.warn_messages) == 6 and len(x.error_messages) == 6
),
(
INPUTS_SELECT_INCOMPATIBLE_DISPLAY, inputs.lint_inputs,
lambda x:
'Select [radio_select] display="radio" is incompatible with optional="true"' in x.error_messages
and 'Select [radio_select] display="radio" is incompatible with multiple="true"' in x.error_messages
@@ -412,7 +574,7 @@ TESTS = [
and len(x.warn_messages) == 0 and len(x.error_messages) == 4
),
(
SELECT_DUPLICATED_OPTIONS, inputs.lint_inputs,
INPUTS_SELECT_DUPLICATED_OPTIONS, inputs.lint_inputs,
lambda x:
'Select parameter [select] has multiple options with the same text content' in x.error_messages
and 'Select parameter [select] has multiple options with the same value' in x.error_messages
@@ -425,6 +587,7 @@ TESTS = [
),
(
SELECT_DEPRECATIONS, inputs.lint_inputs,
INPUTS_SELECT_DEPRECATIONS, inputs.lint_inputs,
lambda x:
"Select parameter [select_do] uses deprecated 'dynamic_options' attribute." in x.warn_messages
and "Select parameter [select_ff] options uses deprecated 'from_file' attribute." in x.warn_messages
@@ -434,30 +597,48 @@ TESTS = [
and len(x.warn_messages) == 5 and len(x.error_messages) == 0
),
(
SELECT_OPTION_DEFINITIONS, inputs.lint_inputs,
INPUTS_SELECT_OPTION_DEFINITIONS, inputs.lint_inputs,
lambda x:
"Select parameter [select_noopt] options have to be defined by either 'option' children elements, a 'options' element or the 'dynamic_options' attribute." in x.error_messages
and "Select parameter [select_noopts] options tag defines no options. Use 'from_dataset', 'from_data_table', or a filter that adds values." in x.error_messages
and "Select parameter [select_fd_op] options have to be defined by either 'option' children elements, a 'options' element or the 'dynamic_options' attribute." in x.error_messages
and "Select parameter [select_fd_op] contains multiple options elements" in x.error_messages
and "Select parameter [select_fd_op] contains multiple options elements." in x.error_messages
and "Select parameter [select_fd_fdt] options uses 'from_dataset' and 'from_data_table' attribute." in x.error_messages
and "Select parameter [select_noval_notext] has option without value" in x.error_messages
and "Select parameter [select_noval_notext] has option without text" in x.warn_messages
and len(x.warn_messages) == 1 and len(x.error_messages) == 6
and "Select parameter [select_meta_file_key_incomp] 'meta_file_key' is only compatible with 'from_dataset'." in x.error_messages
and len(x.warn_messages) == 1 and len(x.error_messages) == 7
),
(
VALIDATOR_INCOMPATIBILITIES, inputs.lint_inputs,
INPUTS_SELECT_FILTER, inputs.lint_inputs,
lambda x:
"Select parameter [select_filter_types] contains filter without type." in x.error_messages
and "Select parameter [select_filter_types] contains filter with unknown type 'unknown_filter_type'." in x.error_messages
and len(x.warn_messages) == 0 and len(x.error_messages) == 2
),
(
INPUTS_VALIDATOR_INCOMPATIBILITIES, inputs.lint_inputs,
lambda x:
"Parameter [param_name]: 'in_range' validators are not expected to contain text (found 'TEXT')" in x.warn_messages
and "Parameter [param_name]: validator with an incompatible type 'in_range'" in x.error_messages
and "Parameter [param_name]: 'in_range' validators need to define the 'min' or 'max' attribute(s)" in x.error_messages
and "Parameter [param_name]: attribute 'filename' is incompatible with validator of type 'regex'" in x.error_messages
and len(x.warn_messages) == 1 and len(x.error_messages) == 3
and "Parameter [param_name]: expression validator without content" in x.error_messages
and "Parameter [another_param_name]: 'metadata' validators need to define the 'check' or 'skip' attribute(s)" in x.error_messages
and "Parameter [param_name]: 'value_in_data_table' validators need to define the 'table_name' attribute" in x.error_messages
and len(x.warn_messages) == 1 and len(x.error_messages) == 6
),
(
VALIDATOR_CORRECT, inputs.lint_inputs,
INPUTS_VALIDATOR_CORRECT, inputs.lint_inputs,
lambda x: len(x.warn_messages) == 0 and len(x.error_messages) == 0
),
(
REPEATS, inputs.lint_repeats,
lambda x:
"Repeat does not specify name attribute." in x.error_messages
and "Repeat does not specify title attribute." in x.error_messages
and len(x.warn_messages) == 0 and len(x.error_messages) == 2
),
(
OUTPUTS_COLLECTION_FORMAT_SOURCE, outputs.lint_output,
lambda x:
@@ -501,16 +682,23 @@ TEST_IDS = [
'help: empty',
'help: with todo',
'help: with invalid restructured text',
'lint no sections',
'input with redundant name',
'lint no when',
'radio select incompatibilities',
'select duplicated options',
'select duplicated options with different selected',
'select deprecations',
'select option definitions',
'validator imcompatibilities',
'validator all correct',
'inputs: no inputs sections',
'inputs: no inputs sections for datasource',
'inputs: redundant param name',
'inputs: valid',
'inputs: param name',
'inputs: param type',
'inputs: data param',
'inputs: conditional',
'inputs: select with incompatible display',
'inputs: select duplicated options',
'inputs: select duplicated options with different selected',
'inputs: select deprecations',
'inputs: select option definitions',
'inputs: select filter',
'inputs: validator incompatibilities',
'inputs: validator all correct',
'repeats',
'outputs collection static elements with format_source',
'outputs discover datatsets with tool provided metadata',
'test without expectations',