From 5d728a26eb0e6844b5993ba80e6d902ec8cd03f7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Hirsz Date: Mon, 11 Mar 2024 14:53:49 +0100 Subject: [PATCH] Disable selected transformers in comment disablers --- docs/releasenotes/unreleased/other.2.rst | 9 ++ docs/source/configuration/index.rst | 14 ++ robotidy/api.py | 2 +- robotidy/app.py | 4 +- robotidy/disablers.py | 142 +++++++++++++----- robotidy/transformers/AlignSettingsSection.py | 2 +- .../transformers/AlignVariablesSection.py | 2 +- robotidy/transformers/InlineIf.py | 2 +- robotidy/transformers/NormalizeAssignments.py | 2 +- robotidy/transformers/NormalizeTags.py | 2 +- robotidy/transformers/OrderTags.py | 2 +- robotidy/transformers/RemoveEmptySettings.py | 2 +- robotidy/transformers/RenameVariables.py | 2 +- robotidy/transformers/SplitTooLongLine.py | 8 +- .../expected/too_long_line_disablers.robot | 32 ++++ .../source/too_long_line_disablers.robot | 17 +++ .../AlignKeywordsSection/test_transformer.py | 3 + .../expected/disablers_selected.robot | 34 +++++ .../source/disablers_selected.robot | 33 ++++ .../test_normalize_new_lines.py | 3 + .../RenameVariables/expected/disablers.robot | 9 +- .../RenameVariables/source/disablers.robot | 11 +- .../SplitTooLongLine/source/disablers.robot | 2 +- tests/utest/test_disablers.py | 28 ++-- .../disablers/file_disabled_in_selected.robot | 23 +++ 25 files changed, 316 insertions(+), 74 deletions(-) create mode 100644 docs/releasenotes/unreleased/other.2.rst create mode 100644 tests/atest/transformers/AlignKeywordsSection/expected/too_long_line_disablers.robot create mode 100644 tests/atest/transformers/AlignKeywordsSection/source/too_long_line_disablers.robot create mode 100644 tests/atest/transformers/NormalizeNewLines/expected/disablers_selected.robot create mode 100644 tests/atest/transformers/NormalizeNewLines/source/disablers_selected.robot create mode 100644 tests/utest/testdata/disablers/file_disabled_in_selected.robot diff --git a/docs/releasenotes/unreleased/other.2.rst b/docs/releasenotes/unreleased/other.2.rst new file mode 100644 index 00000000..a1070b78 --- /dev/null +++ b/docs/releasenotes/unreleased/other.2.rst @@ -0,0 +1,9 @@ +Disable selected transformers (#653) +------------------------------------ + +Robotidy disablers now supports not only disabling all transformers but selected ones:: + + *** Test Cases *** + Test with mixed variables + Keyword call ${global} # robotidy: off = RenameVariables + diff --git a/docs/source/configuration/index.rst b/docs/source/configuration/index.rst index dbe4a1c9..e644df08 100644 --- a/docs/source/configuration/index.rst +++ b/docs/source/configuration/index.rst @@ -154,3 +154,17 @@ You can also disable the formatting in the whole section if you put ``# robotidy *** Keywords *** # robotidy: off Not Formatted Step + +It is possible to disable only selected transformers by passing their names to disabler in comma separated list: + +.. code-block:: robotframework + + *** Test Cases *** + Formatted Partially + Step + ... ${arg} # robotidy: off=AlignTestCasesSection,NormalizeSeparators + Step 2 + + *** Keywords *** # robotidy: off = NormalizeNewLines + Not Formatted + Step diff --git a/robotidy/api.py b/robotidy/api.py index bf32d32c..5a5ef4fa 100644 --- a/robotidy/api.py +++ b/robotidy/api.py @@ -39,7 +39,7 @@ def transform_model(model, root_dir: str, output: Optional[str] = None, **kwargs robotidy_class.config.formatting.start_line, robotidy_class.config.formatting.end_line ) disabler_finder.visit(model) - if disabler_finder.file_disabled: + if disabler_finder.is_disabled_in_file("all"): return None diff, _, new_model = robotidy_class.transform(model, disabler_finder.disablers) if not diff: diff --git a/robotidy/app.py b/robotidy/app.py index e246e55d..d3e5e84b 100644 --- a/robotidy/app.py +++ b/robotidy/app.py @@ -49,7 +49,7 @@ def transform_files(self): model = self.get_model(source) model_path = model.source disabler_finder.visit(model) - if disabler_finder.file_disabled: + if disabler_finder.is_disabled_in_file("all"): continue diff, old_model, new_model, model = self.transform_until_stable(model, disabler_finder) if stdin: @@ -109,6 +109,8 @@ def transform(self, model, disablers): old_model = misc.StatementLinesCollector(model) for transformer in self.config.transformers: setattr(transformer, "disablers", disablers) # set dynamically to allow using external transformers + if disablers.is_disabled_in_file(transformer.__class__.__name__): + continue transformer.visit(model) new_model = misc.StatementLinesCollector(model) return new_model != old_model, old_model, new_model diff --git a/robotidy/disablers.py b/robotidy/disablers.py index 786f800f..fa25a097 100644 --- a/robotidy/disablers.py +++ b/robotidy/disablers.py @@ -1,5 +1,6 @@ import functools import re +from typing import Dict, List, Optional from robot.api.parsing import Comment, CommentSection, ModelVisitor, Token @@ -12,7 +13,8 @@ def skip_if_disabled(func): @functools.wraps(func) def wrapper(self, node, *args, **kwargs): - if self.disablers.is_node_disabled(node): + class_name = self.__class__.__name__ + if self.disablers.is_node_disabled(class_name, node): return node return func(self, node, *args, **kwargs) @@ -39,9 +41,10 @@ def skip_section_if_disabled(func): @functools.wraps(func) def wrapper(self, node, *args, **kwargs): - if self.disablers.is_node_disabled(node): + class_name = self.__class__.__name__ + if self.disablers.is_node_disabled(class_name, node): return node - if self.disablers.is_header_disabled(node.lineno): + if self.disablers.is_header_disabled(class_name, node.lineno): return node if self.skip: section_name = get_section_name_from_header_type(node) @@ -60,6 +63,54 @@ def is_line_start(node): return False +class DisablersInFile: + def __init__(self, start_line: Optional[int], end_line: Optional[int], file_end: Optional[int] = None): + self.start_line = start_line + self.end_line = end_line + self.file_end = file_end + self.disablers = {"all": DisabledLines(start_line, end_line, file_end)} + + def parse_global_disablers(self): + self.disablers["all"].parse_global_disablers() + + def sort_disablers(self): + for disabled_lines in self.disablers.values(): + disabled_lines.sort_disablers() + + def add_disabler(self, transformer: str, start_line: int, end_line: int, file_level: bool = False): + if transformer not in self.disablers: + self.disablers[transformer] = DisabledLines(self.start_line, self.end_line, self.file_end) + self.disablers[transformer].add_disabler(start_line, end_line) + if file_level: + self.disablers[transformer].disabled_whole = file_level + + def add_disabled_header(self, transformer: str, lineno): + if transformer not in self.disablers: + self.disablers[transformer] = DisabledLines(self.start_line, self.end_line, self.file_end) + self.disablers[transformer].disabled_headers.add(lineno) + + def is_disabled_in_file(self, transformer_name: str) -> bool: + if self.disablers["all"].disabled_whole: + return True + if transformer_name not in self.disablers: + return False + return self.disablers[transformer_name].disabled_whole + + def is_header_disabled(self, transformer_name: str, line) -> bool: + if self.disablers["all"].is_header_disabled(line): + return True + if transformer_name not in self.disablers: + return False + return self.disablers[transformer_name].is_header_disabled(line) + + def is_node_disabled(self, transformer_name: str, node, full_match=True) -> bool: + if self.disablers["all"].is_node_disabled(node, full_match): + return True + if transformer_name not in self.disablers: + return False + return self.disablers[transformer_name].is_node_disabled(node, full_match) + + class DisabledLines: def __init__(self, start_line, end_line, file_end): self.start_line = start_line @@ -67,13 +118,7 @@ def __init__(self, start_line, end_line, file_end): self.file_end = file_end self.lines = [] self.disabled_headers = set() - - @property - def file_disabled(self): - """Check if file is disabled. Whole file is only disabled if the first line contains one line disabler.""" - if not self.lines: - return False - return self.lines[0] == (1, 1) + self.disabled_whole = False def add_disabler(self, start_line, end_line): self.lines.append((start_line, end_line)) @@ -97,7 +142,7 @@ def is_header_disabled(self, line): return line in self.disabled_headers def is_node_disabled(self, node, full_match=True): - if not node: + if not node or not self.lines: return False end_lineno = max(node.lineno, node.end_lineno) # workaround for transformers setting -1 as end_lineno if full_match: @@ -116,14 +161,13 @@ class RegisterDisablers(ModelVisitor): def __init__(self, start_line, end_line): self.start_line = start_line self.end_line = end_line - self.disablers = DisabledLines(self.start_line, self.end_line, None) - self.disabler_pattern = re.compile(r"\s*#\s?robotidy:\s?(?Pon|off)") - self.stack = [] - self.file_disabled = False + self.disablers = DisablersInFile(start_line, end_line) + self.disabler_pattern = re.compile(r"\s*#\s?robotidy:\s?(?Pon|off) ?=?(?P[\w,\s]*)") + self.disablers_in_scope: List[Dict[str, int]] = [] self.file_level_disablers = False - def any_disabler_open(self): - return any(disabler for disabler in self.stack) + def is_disabled_in_file(self, transformer_name: str = "all"): + return self.disablers.is_disabled_in_file(transformer_name) def get_disabler(self, comment): if not comment.value: @@ -131,46 +175,55 @@ def get_disabler(self, comment): return self.disabler_pattern.match(comment.value) def close_disabler(self, end_line): - disabler = self.stack.pop() - if disabler: - if self.file_level_disablers: - self.file_disabled = True - self.disablers.add_disabler(disabler, end_line) + disabler = self.disablers_in_scope.pop() + for transformer_name, start_line in disabler.items(): + if not start_line: + continue + self.disablers.add_disabler(transformer_name, start_line, end_line, self.file_level_disablers) def visit_File(self, node): # noqa self.file_level_disablers = False - self.disablers = DisabledLines(self.start_line, self.end_line, node.end_lineno) + self.disablers = DisablersInFile(self.start_line, self.end_line, node.end_lineno) self.disablers.parse_global_disablers() self.stack = [] for index, section in enumerate(node.sections): self.file_level_disablers = index == 0 and isinstance(section, CommentSection) self.visit_Section(section) self.disablers.sort_disablers() - self.file_disabled = self.file_disabled or self.disablers.file_disabled + + @staticmethod + def get_disabler_transformers(match) -> List[str]: + if not match.group("transformers") or "=" not in match.group(0): # robotidy: off or robotidy: off comment + return ["all"] + # robotidy: off=Transformer1, Transformer2 + return [transformer.strip() for transformer in match.group("transformers").split(",") if transformer.strip()] def visit_SectionHeader(self, node): # noqa for comment in node.get_tokens(Token.COMMENT): disabler = self.get_disabler(comment) - if disabler and disabler.group("disabler") == "off": - self.disablers.add_disabled_header(node.lineno) - break + if not disabler or disabler.group("disabler") != "off": + continue + transformers = self.get_disabler_transformers(disabler) + for transformer in transformers: + self.disablers.add_disabled_header(transformer, node.lineno) + break return self.generic_visit(node) def visit_TestCase(self, node): # noqa - self.stack.append(0) + self.disablers_in_scope.append({"all": 0}) self.generic_visit(node) self.close_disabler(node.end_lineno) def visit_Try(self, node): # noqa self.generic_visit(node.header) - self.stack.append(0) + self.disablers_in_scope.append({"all": 0}) for statement in node.body: self.visit(statement) self.close_disabler(node.end_lineno) tail = node while tail.next: self.generic_visit(tail.header) - self.stack.append(0) + self.disablers_in_scope.append({"all": 0}) for statement in tail.body: self.visit(statement) end_line = tail.next.lineno - 1 if tail.next else tail.end_lineno @@ -185,19 +238,26 @@ def visit_Statement(self, node): # noqa disabler = self.get_disabler(comment) if not disabler: return + transformers = self.get_disabler_transformers(disabler) index = 0 if is_line_start(node) else -1 - if disabler.group("disabler") == "on": - if not self.stack[index]: # no disabler open - return - self.disablers.add_disabler(self.stack[index], node.lineno) - self.stack[index] = 0 - elif not self.stack[index]: - self.stack[index] = node.lineno + disabler_start = disabler.group("disabler") == "on" + for transformer in transformers: + if disabler_start: + start_line = self.disablers_in_scope[index].get(transformer) + if not start_line: # no disabler open + continue + self.disablers.add_disabler(transformer, start_line, node.lineno) + self.disablers_in_scope[index][transformer] = 0 + else: + if not self.disablers_in_scope[index].get(transformer): + self.disablers_in_scope[index][transformer] = node.lineno else: # inline disabler - if self.any_disabler_open(): - return for comment in node.get_tokens(Token.COMMENT): disabler = self.get_disabler(comment) - if disabler and disabler.group("disabler") == "off": - self.disablers.add_disabler(node.lineno, node.end_lineno) + if not disabler: + continue + transformers = self.get_disabler_transformers(disabler) + if disabler.group("disabler") == "off": + for transformer in transformers: + self.disablers.add_disabler(transformer, node.lineno, node.end_lineno) diff --git a/robotidy/transformers/AlignSettingsSection.py b/robotidy/transformers/AlignSettingsSection.py index 13fa917f..0a884f36 100644 --- a/robotidy/transformers/AlignSettingsSection.py +++ b/robotidy/transformers/AlignSettingsSection.py @@ -90,7 +90,7 @@ def __init__( def visit_SettingSection(self, node): # noqa statements = [] for child in node.body: - if self.disablers.is_node_disabled(child) or self.is_node_skip(child): + if self.disablers.is_node_disabled("AlignSettingsSection", child) or self.is_node_skip(child): statements.append(child) elif child.type in (Token.EOL, Token.COMMENT): statements.append(misc.left_align(child)) diff --git a/robotidy/transformers/AlignVariablesSection.py b/robotidy/transformers/AlignVariablesSection.py index c78c15bc..6f8ff9cc 100644 --- a/robotidy/transformers/AlignVariablesSection.py +++ b/robotidy/transformers/AlignVariablesSection.py @@ -77,7 +77,7 @@ def should_parse(self, node): def visit_VariableSection(self, node): # noqa statements = [] for child in node.body: - if self.disablers.is_node_disabled(child): + if self.disablers.is_node_disabled("AlignVariablesSection", child): statements.append(child) elif child.type in (Token.EOL, Token.COMMENT): statements.append(misc.left_align(child)) diff --git a/robotidy/transformers/InlineIf.py b/robotidy/transformers/InlineIf.py index 8fac5f9c..c722fa99 100644 --- a/robotidy/transformers/InlineIf.py +++ b/robotidy/transformers/InlineIf.py @@ -71,7 +71,7 @@ def visit_Section(self, node): # noqa def visit_If(self, node: If): # noqa if node.errors or getattr(node.end, "errors", None): return node - if self.disablers.is_node_disabled(node, full_match=False): + if self.disablers.is_node_disabled("InlineIf", node, full_match=False): return node if self.is_inline(node): return self.handle_inline(node) diff --git a/robotidy/transformers/NormalizeAssignments.py b/robotidy/transformers/NormalizeAssignments.py index e1d640fc..48d3afe2 100644 --- a/robotidy/transformers/NormalizeAssignments.py +++ b/robotidy/transformers/NormalizeAssignments.py @@ -123,7 +123,7 @@ def visit_VariableSection(self, node): # noqa for child in node.body: if not isinstance(child, Variable): continue - if self.disablers.is_node_disabled(child): + if self.disablers.is_node_disabled("NormalizeAssignments", child): continue var_token = child.get_token(Token.VARIABLE) self.normalize_equal_sign( diff --git a/robotidy/transformers/NormalizeTags.py b/robotidy/transformers/NormalizeTags.py index 7e680b79..96eb83c5 100644 --- a/robotidy/transformers/NormalizeTags.py +++ b/robotidy/transformers/NormalizeTags.py @@ -64,7 +64,7 @@ def visit_DefaultTags(self, node): # noqa visit_TestTags = visit_ForceTags = visit_DefaultTags def normalize_tags(self, node, indent=False): - if self.disablers.is_node_disabled(node, full_match=False): + if self.disablers.is_node_disabled("NormalizeTags", node, full_match=False): return node if self.preserve_format: return self.normalize_tags_tokens_preserve_formatting(node) diff --git a/robotidy/transformers/OrderTags.py b/robotidy/transformers/OrderTags.py index 7ddf4be1..bcdfe1c7 100644 --- a/robotidy/transformers/OrderTags.py +++ b/robotidy/transformers/OrderTags.py @@ -70,7 +70,7 @@ def visit_ForceTags(self, node): # noqa return self.order_tags(node) if self.force_tags else node def order_tags(self, node, indent=False): - if self.disablers.is_node_disabled(node): + if self.disablers.is_node_disabled("OrderTags", node): return node ordered_tags = sorted( (tag.value for tag in node.data_tokens[1:]), diff --git a/robotidy/transformers/RemoveEmptySettings.py b/robotidy/transformers/RemoveEmptySettings.py index 5d1fb598..de5d2bac 100644 --- a/robotidy/transformers/RemoveEmptySettings.py +++ b/robotidy/transformers/RemoveEmptySettings.py @@ -64,7 +64,7 @@ def visit_Statement(self, node): # noqa # when not setting type or setting type but not empty if node.type not in Token.SETTING_TOKENS or len(node.data_tokens) != 1: return node - if self.disablers.is_node_disabled(node): + if self.disablers.is_node_disabled("RemoveEmptySettings", node): return node # when empty and not overwriting anything - remove if ( diff --git a/robotidy/transformers/RenameVariables.py b/robotidy/transformers/RenameVariables.py index 731ae97f..e46797f6 100644 --- a/robotidy/transformers/RenameVariables.py +++ b/robotidy/transformers/RenameVariables.py @@ -334,7 +334,7 @@ def visit_Keyword(self, node): # noqa def visit_KeywordCall(self, node): # noqa self.handle_set_local_variable(node) - if not self.disablers.is_node_disabled(node): + if not self.disablers.is_node_disabled("RenameVariables", node): for token in node.data_tokens: if token.type == Token.ASSIGN: token.value = self.rename_value(token.value, variable_case="lower", is_var=False) diff --git a/robotidy/transformers/SplitTooLongLine.py b/robotidy/transformers/SplitTooLongLine.py index de54f72a..12ba89c2 100644 --- a/robotidy/transformers/SplitTooLongLine.py +++ b/robotidy/transformers/SplitTooLongLine.py @@ -157,14 +157,16 @@ def visit_KeywordCall(self, node): # noqa return node if not self.should_transform_node(node): return node - if self.disablers.is_node_disabled(node, full_match=False): + if self.disablers.is_node_disabled("SplitTooLongLine", node, full_match=False): return node if self.is_run_keyword(node.keyword): return node return self.split_keyword_call(node) def visit_Var(self, node): # noqa - if self.disablers.is_node_disabled(node, full_match=False) or not self.should_transform_node(node): + if self.disablers.is_node_disabled( + "SplitTooLongLine", node, full_match=False + ) or not self.should_transform_node(node): return node var_name = node.get_token(Token.VARIABLE) if not var_name: @@ -209,7 +211,7 @@ def visit_ForceTags(self, node): # noqa def split_setting_with_args(self, node, settings_section): if not self.should_transform_node(node): return node - if self.disablers.is_node_disabled(node, full_match=False): + if self.disablers.is_node_disabled("SplitTooLongLine", node, full_match=False): return node if settings_section: indent = 0 diff --git a/tests/atest/transformers/AlignKeywordsSection/expected/too_long_line_disablers.robot b/tests/atest/transformers/AlignKeywordsSection/expected/too_long_line_disablers.robot new file mode 100644 index 00000000..f3d788c8 --- /dev/null +++ b/tests/atest/transformers/AlignKeywordsSection/expected/too_long_line_disablers.robot @@ -0,0 +1,32 @@ +*** Keywords *** +Many arguments + # fits without alignment + Keyword + ... argument1 + ... argument2 + ... argument3 + ... argument4 + ... argument5 + ... argument6 + ... argument7 + ... argument8 + + # does not fit before alignment + Longer Keyword Name That Could Happen In Real Life Too argument value with sentence that goes over the characters limit # robotidy: off=SplitTooLongLine,AlignKeywordsSection + + # multiline but fits without alignment + Keyword + ... arg + ... argument1 + ... argument2 + ... argument3 + ... argument4 + ... argument5 + ... argument6 + ... argument7 + ... argument8 + +Many assignments + # robotidy: off=AlignKeywordsSection,all + ${longer_argument} ${longer_argument2} ${longer_argument3} ${longer_argument4} ${longer_argument5} ${longer_argument6} Keyword + ... argument1 argument2 diff --git a/tests/atest/transformers/AlignKeywordsSection/source/too_long_line_disablers.robot b/tests/atest/transformers/AlignKeywordsSection/source/too_long_line_disablers.robot new file mode 100644 index 00000000..9498de6f --- /dev/null +++ b/tests/atest/transformers/AlignKeywordsSection/source/too_long_line_disablers.robot @@ -0,0 +1,17 @@ +*** Keywords *** +Many arguments + # fits without alignment + Keyword argument1 argument2 argument3 argument4 argument5 argument6 argument7 argument8 + + # does not fit before alignment + Longer Keyword Name That Could Happen In Real Life Too argument value with sentence that goes over the characters limit # robotidy: off=SplitTooLongLine,AlignKeywordsSection + + # multiline but fits without alignment + Keyword + ... arg + ... argument1 argument2 argument3 argument4 argument5 argument6 argument7 argument8 + +Many assignments + # robotidy: off=AlignKeywordsSection,all + ${longer_argument} ${longer_argument2} ${longer_argument3} ${longer_argument4} ${longer_argument5} ${longer_argument6} Keyword + ... argument1 argument2 diff --git a/tests/atest/transformers/AlignKeywordsSection/test_transformer.py b/tests/atest/transformers/AlignKeywordsSection/test_transformer.py index 8da0ab62..8b2b2acd 100644 --- a/tests/atest/transformers/AlignKeywordsSection/test_transformer.py +++ b/tests/atest/transformers/AlignKeywordsSection/test_transformer.py @@ -92,6 +92,9 @@ def test_compact_overflow_last_0(self): def test_too_long_line(self): self.compare(source="too_long_line.robot", config=" --transform SplitTooLongLine") + def test_too_long_line_disablers(self): + self.compare(source="too_long_line_disablers.robot", config=" --transform SplitTooLongLine") + def test_error_node(self): self.compare(source="error_node.robot", not_modified=True, target_version=">=5") diff --git a/tests/atest/transformers/NormalizeNewLines/expected/disablers_selected.robot b/tests/atest/transformers/NormalizeNewLines/expected/disablers_selected.robot new file mode 100644 index 00000000..33a29834 --- /dev/null +++ b/tests/atest/transformers/NormalizeNewLines/expected/disablers_selected.robot @@ -0,0 +1,34 @@ +*** Variables *** +# standalone comment +${VALID} Value +MyVar val1 val2 val3 val4 val5 val6 val7 +... val8 val9 val10 # var comment +# robotidy: off=NormalizeNewLines +# standalone + + +*** Test Cases *** # robotidy: off=NormalizeNewLines + + +Test + [Documentation] This is a documentation + ... in two lines + Some Lines + No Operation + [Teardown] 1 minute args + +Test Without Arg +Mid Test + My Step 1 args args 2 args 3 args 4 args 5 args 6 + ... args 7 args 8 args 9 # step 1 comment + +*** Keywords *** # robotidy: off=IDontExist,NormalizeNewLines +Keyword + No Operation +Other Keyword +Another Keyword + There + Are + More +*** Settings *** +Library library.py diff --git a/tests/atest/transformers/NormalizeNewLines/source/disablers_selected.robot b/tests/atest/transformers/NormalizeNewLines/source/disablers_selected.robot new file mode 100644 index 00000000..c60779d1 --- /dev/null +++ b/tests/atest/transformers/NormalizeNewLines/source/disablers_selected.robot @@ -0,0 +1,33 @@ +*** Variables *** +# standalone comment +${VALID} Value +MyVar val1 val2 val3 val4 val5 val6 val7 +... val8 val9 val10 # var comment +# robotidy: off=NormalizeNewLines +# standalone + +*** Test Cases *** # robotidy: off=NormalizeNewLines + + +Test + [Documentation] This is a documentation + ... in two lines + Some Lines + No Operation + [Teardown] 1 minute args + +Test Without Arg +Mid Test + My Step 1 args args 2 args 3 args 4 args 5 args 6 + ... args 7 args 8 args 9 # step 1 comment + +*** Keywords *** # robotidy: off=IDontExist,NormalizeNewLines +Keyword + No Operation +Other Keyword +Another Keyword + There + Are + More +*** Settings *** +Library library.py \ No newline at end of file diff --git a/tests/atest/transformers/NormalizeNewLines/test_normalize_new_lines.py b/tests/atest/transformers/NormalizeNewLines/test_normalize_new_lines.py index 3fff1458..4dd48568 100644 --- a/tests/atest/transformers/NormalizeNewLines/test_normalize_new_lines.py +++ b/tests/atest/transformers/NormalizeNewLines/test_normalize_new_lines.py @@ -54,6 +54,9 @@ def test_inline_if(self, trailing_lines): def test_disablers(self): self.compare(source="disablers.robot", not_modified=True) + def test_disablers_selected(self): + self.compare(source="disablers_selected.robot") + def test_blocks(self): self.compare(source="blocks.robot", target_version=">=5") diff --git a/tests/atest/transformers/RenameVariables/expected/disablers.robot b/tests/atest/transformers/RenameVariables/expected/disablers.robot index 18fb7252..5cf03aaf 100644 --- a/tests/atest/transformers/RenameVariables/expected/disablers.robot +++ b/tests/atest/transformers/RenameVariables/expected/disablers.robot @@ -28,14 +28,17 @@ ${CAMEL_CASE_NAME_WORD_CAMEL_CASE} ${CAMEL_CASE_NAME_WORD_CAMEL_CASE} *** Test Cases *** Assign ${variable} Keyword - ${multiple} - ... ${variables} Keyword + FOR ${var} IN 1 2 + # robotidy: off=NormalizeNewLines, RenameVariables + ${MULTIPLE} + ... ${variables } Keyword + END ${variable} = Keyword ${variable}= Keyword Args Keyword ${VARIABLE} - Keyword ${v a _riAbles} # robotidy: off + Keyword ${v a _riAbles} # robotidy: off = RenameVariables ... value with ${_ variable _} Arguments diff --git a/tests/atest/transformers/RenameVariables/source/disablers.robot b/tests/atest/transformers/RenameVariables/source/disablers.robot index 33f5d890..dc988158 100644 --- a/tests/atest/transformers/RenameVariables/source/disablers.robot +++ b/tests/atest/transformers/RenameVariables/source/disablers.robot @@ -28,14 +28,17 @@ ${camelCASEName_word_camelCase} ${camelCASEName_WORD_camelCase} *** Test Cases *** Assign ${ variable} Keyword - ${MULTIPLE} - ... ${variables } Keyword + FOR ${var} IN 1 2 + # robotidy: off=NormalizeNewLines, RenameVariables + ${MULTIPLE} + ... ${variables } Keyword + END ${variable} = Keyword - ${variable}= Keyword + ${Variable}= Keyword Args Keyword ${variable } - Keyword ${v a _riAbles} # robotidy: off + Keyword ${v a _riAbles} # robotidy: off = RenameVariables ... value with ${_ variable _} Arguments diff --git a/tests/atest/transformers/SplitTooLongLine/source/disablers.robot b/tests/atest/transformers/SplitTooLongLine/source/disablers.robot index 80118583..db9e13f8 100644 --- a/tests/atest/transformers/SplitTooLongLine/source/disablers.robot +++ b/tests/atest/transformers/SplitTooLongLine/source/disablers.robot @@ -50,7 +50,7 @@ For loop FOR ${i} IN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 20 This is a keyword these args do not fit even if you set spacing properly # robotidy: off - This is a keyword these arguments won't fit with that # robotidy: off + This is a keyword these arguments won't fit with that # robotidy: off = SplitTooLongLine This is a keyword these args have an interesting ... # Edge case here →→→→→→→→→→→→→→→→ HERE # robotidy: off diff --git a/tests/utest/test_disablers.py b/tests/utest/test_disablers.py index daa3c1e6..9f800b03 100644 --- a/tests/utest/test_disablers.py +++ b/tests/utest/test_disablers.py @@ -49,24 +49,28 @@ def test_is_node_disabled(check_start, check_end, start_line, end_line, lines, f @pytest.mark.parametrize( - "test_file, expected_lines, file_disabled, rf_version", + "test_file, expected_lines, file_disabled, rf_version, check_transformer", [ - ("file_disabled.robot", [(1, 1), (14, 15)], True, 4), - ("file_disabled_in_comments.robot", [(2, 4), (17, 18)], True, 4), - ("file_disabled_in_comments_no_header.robot", [(2, 4), (17, 18)], True, 4), - ("file_disabled_enabled_in_comments.robot", [(2, 6), (21, 22)], False, 4), - ("file_disabled_and_enabled.robot", [(1, 2), (15, 16)], False, 4), - ("test.robot", [(13, 14), (25, 37), (30, 33), (40, 41), (46, 48), (57, 58), (67, 67)], False, 5), - ("open_disabler_in_section.robot", [(5, 8), (13, 15), (20, 23)], False, 4), - ("empty.robot", [], False, 4), + ("file_disabled.robot", [(1, 1), (14, 15)], True, 4, "all"), + ("file_disabled_in_selected.robot", [(1, 1)], True, 4, "NormalizeNewLines"), + ("file_disabled_in_selected.robot", [(14, 15)], False, 4, "all"), + ("file_disabled_in_selected.robot", [], False, 4, "AlignTestCasesSection"), + ("file_disabled_in_comments.robot", [(2, 4), (17, 18)], True, 4, "all"), + ("file_disabled_in_comments_no_header.robot", [(2, 4), (17, 18)], True, 4, "all"), + ("file_disabled_enabled_in_comments.robot", [(2, 6), (21, 22)], False, 4, "all"), + ("file_disabled_and_enabled.robot", [(1, 2), (15, 16)], False, 4, "all"), + ("test.robot", [(13, 14), (25, 37), (30, 33), (40, 41), (46, 48), (57, 58), (67, 67)], False, 5, "all"), + ("open_disabler_in_section.robot", [(5, 8), (13, 15), (20, 23)], False, 4, "all"), + ("empty.robot", [], False, 4, "all"), ], ) -def test_register_disablers(test_file, expected_lines, file_disabled, rf_version): +def test_register_disablers(test_file, expected_lines, file_disabled, rf_version, check_transformer): if ROBOT_VERSION.major < rf_version: pytest.skip(f"Test enabled only for RF {rf_version}.*") test_file_path = Path(__file__).parent / "testdata" / "disablers" / test_file model = get_model(test_file_path) register_disablers = RegisterDisablers(None, None) register_disablers.visit(model) - assert register_disablers.disablers.lines == expected_lines - assert register_disablers.file_disabled == file_disabled + if check_transformer in register_disablers.disablers.disablers: + assert register_disablers.disablers.disablers[check_transformer].lines == expected_lines + assert register_disablers.is_disabled_in_file(check_transformer) == file_disabled diff --git a/tests/utest/testdata/disablers/file_disabled_in_selected.robot b/tests/utest/testdata/disablers/file_disabled_in_selected.robot new file mode 100644 index 00000000..9838b3a6 --- /dev/null +++ b/tests/utest/testdata/disablers/file_disabled_in_selected.robot @@ -0,0 +1,23 @@ +# robotidy: off = NormalizeNewLines +*** Settings *** +Library SeleniumLibrary + +Metadata Key Value + +*** Test Cases *** +Test + [Documentation] This is doc + Step + FOR ${var} IN RANGE 10 + IF $condition + WHILE ${arg} + ${return} Keyword ${value} + ... ${other_value} # robotidy: off + END + ELSE IF + Step ${arg} + ... value + Step 2 + # comment + END + END