From b84b8462740853c59233df20677e457a6c3091bd Mon Sep 17 00:00:00 2001 From: Bartlomiej Hirsz Date: Sat, 14 Aug 2021 14:18:45 +0200 Subject: [PATCH 1/7] do not order Remote libraries together with standard libs --- CHANGES.md | 1 + robotidy/transformers/OrderSettingsSection.py | 3 ++- .../expected/remote_library.robot | 13 +++++++++++++ .../source/remote_library.robot | 13 +++++++++++++ .../OrderSettingsSection/test_transformer.py | 7 +++++++ 5 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/atest/transformers/OrderSettingsSection/expected/remote_library.robot create mode 100644 tests/atest/transformers/OrderSettingsSection/source/remote_library.robot diff --git a/CHANGES.md b/CHANGES.md index eb2fd18e..04cd5757 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ ### Features - Add extra indent for arguments in Suite Setup/Teardown, Test Setup/Teardown in AlignSettingsSection [#155](https://github.com/MarketSquare/robotframework-tidy/issues/155) - OrderSettingsSection will now preserve order of imports. It can be configured to work as before and other settings order can be also preserved [#167](https://github.com/MarketSquare/robotframework-tidy/issues/167) +- When ordering imports with OrderSettingsSection, Remote library will not be grouped with other standard libs [#175](https://github.com/MarketSquare/robotframework-tidy/issues/175) - Allow to disable selected transformers [#170](https://github.com/MarketSquare/robotframework-tidy/issues/170) ### Fixes diff --git a/robotidy/transformers/OrderSettingsSection.py b/robotidy/transformers/OrderSettingsSection.py index 169609c9..8400c348 100644 --- a/robotidy/transformers/OrderSettingsSection.py +++ b/robotidy/transformers/OrderSettingsSection.py @@ -232,7 +232,8 @@ def fix_eol(node): def sort_builtin_libs(statements): before, after = [], [] for comments, statement in statements: - if isinstance(statement, LibraryImport) and statement.name and statement.name in STDLIBS: + if isinstance(statement, LibraryImport) and statement.name and statement.name != 'Remote' \ + and statement.name in STDLIBS: before.append((comments, statement)) else: after.append((comments, statement)) diff --git a/tests/atest/transformers/OrderSettingsSection/expected/remote_library.robot b/tests/atest/transformers/OrderSettingsSection/expected/remote_library.robot new file mode 100644 index 00000000..f1d39945 --- /dev/null +++ b/tests/atest/transformers/OrderSettingsSection/expected/remote_library.robot @@ -0,0 +1,13 @@ +*** Settings *** +Library Collections +Library DateTime +Library Dialogs +Library OperatingSystem +Library String +Library XML +Library Browser +Library RequestsLibrary +Library Keywords/MyUtilities.py +Library Remote http://localhost:9050/ WITH NAME JDBCDB2 # DB2 +Resource keywords.robot +Resource other_stuff.robot diff --git a/tests/atest/transformers/OrderSettingsSection/source/remote_library.robot b/tests/atest/transformers/OrderSettingsSection/source/remote_library.robot new file mode 100644 index 00000000..a2bb6deb --- /dev/null +++ b/tests/atest/transformers/OrderSettingsSection/source/remote_library.robot @@ -0,0 +1,13 @@ +*** Settings *** +Library Collections +Library DateTime +Library Dialogs +Library OperatingSystem +Library String +Library XML +Library Browser +Library RequestsLibrary +Library Keywords/MyUtilities.py +Resource keywords.robot +Resource other_stuff.robot +Library Remote http://localhost:9050/ WITH NAME JDBCDB2 # DB2 diff --git a/tests/atest/transformers/OrderSettingsSection/test_transformer.py b/tests/atest/transformers/OrderSettingsSection/test_transformer.py index 8d40f085..1affe047 100644 --- a/tests/atest/transformers/OrderSettingsSection/test_transformer.py +++ b/tests/atest/transformers/OrderSettingsSection/test_transformer.py @@ -100,3 +100,10 @@ def test_invalid_token_name_in_order(self): f" Custom order should be provided in comma separated list with valid group names:\n" \ f"['documentation', 'metadata']" assert expected_output in str(result.exception) + + def test_remote_library_as_external(self): + run_tidy_and_compare( + self.TRANSFORMER_NAME, + source='remote_library.robot', + config=':imports_order=library,resource,variables' + ) From ffcaeca7df246ad8e68e15acc1be56f71713515c Mon Sep 17 00:00:00 2001 From: Bartlomiej Hirsz Date: Mon, 30 Aug 2021 19:41:39 +0200 Subject: [PATCH 2/7] update contributing docs --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6faa57a0..ae4c315b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ Contribution guideline Getting started ---------------- -Did you spot bug or you really want to see some feature implemented? It's always best to start with create issue in github. +Did you spot a bug or you really want to see some feature implemented? It's always best to start with creating issue in GitHub. It doesn't matter if you're actually willing to make change on your own. Creating issue allow us to discuss proposed changes ( and cover possible edge cases) and also prevents multiple people from working on the same problem. @@ -33,7 +33,7 @@ TRANSFORMERS lists. This list determines the order of transformers that will be you're not sure how your transformer will work with others just leave the default order. If you don't want to run your transformer with default ones (so it could be run only when selected with -`--transform` or configured with `enabled=True`) add following flag to invoke script: +`--transform` or configured with `enabled=True`) add the following flag to invoke script: ``` invoke add-transformer TRANSFORMER-NAME --disabled ``` From 7b119c469695b41ac733347970af20a247737185 Mon Sep 17 00:00:00 2001 From: Bartlomiej Hirsz Date: Mon, 30 Aug 2021 21:24:48 +0200 Subject: [PATCH 3/7] Add RenameTestCases transformer; refactor descriptions --- docs/source/transformers/RenameTestCases.rst | 37 ++++++++++++ .../source/transformers/SmartSortKeywords.rst | 4 ++ robotidy/transformers/AlignSettingsSection.py | 2 + .../transformers/AlignVariablesSection.py | 8 ++- robotidy/transformers/DiscardEmptySections.py | 2 + .../transformers/MergeAndOrderSections.py | 2 + robotidy/transformers/NormalizeAssignments.py | 5 +- robotidy/transformers/NormalizeNewLines.py | 2 + .../NormalizeSectionHeaderName.py | 8 ++- robotidy/transformers/NormalizeSeparators.py | 2 + robotidy/transformers/NormalizeSettingName.py | 6 +- robotidy/transformers/OrderSettings.py | 6 +- robotidy/transformers/OrderSettingsSection.py | 6 +- robotidy/transformers/RemoveEmptySettings.py | 2 + robotidy/transformers/RenameTestCases.py | 59 +++++++++++++++++++ robotidy/transformers/ReplaceRunKeywordIf.py | 14 +++-- robotidy/transformers/SmartSortKeywords.py | 6 +- robotidy/transformers/SplitTooLongLine.py | 9 ++- robotidy/transformers/__init__.py | 4 +- robotidy/utils.py | 23 +++++++- .../transformers/RenameTestCases/__init__.py | 0 .../expected/empty_test_name.robot | 11 ++++ .../expected/replace_pattern_empty.robot | 16 +++++ .../replace_pattern_placeholder.robot | 16 +++++ .../replace_pattern_special_chars.robot | 16 +++++ .../RenameTestCases/expected/selected.robot | 16 +++++ .../RenameTestCases/expected/test.robot | 16 +++++ .../source/empty_test_name.robot | 11 ++++ .../RenameTestCases/source/test.robot | 16 +++++ .../RenameTestCases/test_transformer.py | 56 ++++++++++++++++++ 30 files changed, 353 insertions(+), 28 deletions(-) create mode 100644 docs/source/transformers/RenameTestCases.rst create mode 100644 robotidy/transformers/RenameTestCases.py create mode 100644 tests/atest/transformers/RenameTestCases/__init__.py create mode 100644 tests/atest/transformers/RenameTestCases/expected/empty_test_name.robot create mode 100644 tests/atest/transformers/RenameTestCases/expected/replace_pattern_empty.robot create mode 100644 tests/atest/transformers/RenameTestCases/expected/replace_pattern_placeholder.robot create mode 100644 tests/atest/transformers/RenameTestCases/expected/replace_pattern_special_chars.robot create mode 100644 tests/atest/transformers/RenameTestCases/expected/selected.robot create mode 100644 tests/atest/transformers/RenameTestCases/expected/test.robot create mode 100644 tests/atest/transformers/RenameTestCases/source/empty_test_name.robot create mode 100644 tests/atest/transformers/RenameTestCases/source/test.robot create mode 100644 tests/atest/transformers/RenameTestCases/test_transformer.py diff --git a/docs/source/transformers/RenameTestCases.rst b/docs/source/transformers/RenameTestCases.rst new file mode 100644 index 00000000..5fc773a1 --- /dev/null +++ b/docs/source/transformers/RenameTestCases.rst @@ -0,0 +1,37 @@ +.. _RenameTestCases: + +RenameTestCases +================================ + +Enforce test case naming. + +RenameTestCases is not included in default transformers that's why you need to call it with ``--transform`` explicitly:: + + robotidy --transform RenameTestCases src + +Or configure `enable` parameter:: + + robotidy --configure RenameTestCases:enabled=True + +This transformer capitalize first letter of test case name, remove trailing dot and strip leading/trailing whitespace. + +It is also possible to configure `replace_pattern` parameter to find and replace regex pattern. Use `replace_to` +to set replacement value. This configuration:: + + robotidy --transform RenameTestCases -c RenameTestCases:replace_pattern=[A-Z]{3,}-\d{2,}:replace_to=foo + +Replaces all occurrences of given pattern with string 'foo': +.. tabs:: + + .. code-tab:: robotframework Before + + *** Test Cases *** + test ABC-123 + No Operation + + .. code-tab:: robotframework After + *** Test Cases *** + Test foo + No Operation + +Supports global formatting params: ``--startline`` and ``--endline``. \ No newline at end of file diff --git a/docs/source/transformers/SmartSortKeywords.rst b/docs/source/transformers/SmartSortKeywords.rst index 0cecb2de..5d38e3b4 100644 --- a/docs/source/transformers/SmartSortKeywords.rst +++ b/docs/source/transformers/SmartSortKeywords.rst @@ -9,6 +9,10 @@ SmartSortKeywords is not included in default transformers that's why you need to robotidy --transform SmartSortKeywords src +Or configure `enable` parameter:: + + robotidy --configure SmartSortKeywords:enabled=True + By default sorting is case insensitive, but keywords with leading underscore go to the bottom. Other underscores are treated as spaces. Empty lines (or lack of them) between keywords are preserved. diff --git a/robotidy/transformers/AlignSettingsSection.py b/robotidy/transformers/AlignSettingsSection.py index 2ae64dba..76b15888 100644 --- a/robotidy/transformers/AlignSettingsSection.py +++ b/robotidy/transformers/AlignSettingsSection.py @@ -58,6 +58,8 @@ class AlignSettingsSection(ModelTransformer): Supports global formatting params: ``--startline``, ``--endline`` and ``--space_count`` (for columns with fixed length). + + See https://robotidy.readthedocs.io/en/latest/transformers/AlignSettingsSection.html for more examples. """ TOKENS_WITH_KEYWORDS = {Token.SUITE_SETUP, Token.SUITE_TEARDOWN, Token.TEST_SETUP, Token.TEST_TEARDOWN} diff --git a/robotidy/transformers/AlignVariablesSection.py b/robotidy/transformers/AlignVariablesSection.py index a0aad059..eacf9744 100644 --- a/robotidy/transformers/AlignVariablesSection.py +++ b/robotidy/transformers/AlignVariablesSection.py @@ -18,7 +18,7 @@ class AlignVariablesSection(ModelTransformer): """ Align variables in *** Variables *** section to columns. - Following code:: + Following code: *** Variables *** ${VAR} 1 @@ -26,7 +26,7 @@ class AlignVariablesSection(ModelTransformer): &{MULTILINE} a=b ... b=c - will be transformed to:: + will be transformed to: *** Variables *** ${VAR} 1 @@ -36,13 +36,15 @@ class AlignVariablesSection(ModelTransformer): You can configure how many columns should be aligned to longest token in given column. The remaining columns will use fixed length separator length ``--space_count``. By default only first two columns are aligned. - To align first three columns:: + To align first three columns: robotidy --transform AlignVariablesSection:up_to_column=3 To align all columns set ``up_to_column`` to 0. Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/AlignVariablesSection.html for more examples. """ def __init__(self, up_to_column: int = 2): self.up_to_column = up_to_column - 1 diff --git a/robotidy/transformers/DiscardEmptySections.py b/robotidy/transformers/DiscardEmptySections.py index 1e31d76c..d4309751 100644 --- a/robotidy/transformers/DiscardEmptySections.py +++ b/robotidy/transformers/DiscardEmptySections.py @@ -18,6 +18,8 @@ class DiscardEmptySections(ModelTransformer): # this section would be removed if not for ``alow_only_comments`` parameter Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/DiscardEmptySections.html for more examples. """ def __init__(self, allow_only_comments: bool = False): # If True then sections only with comments are not is considered to be empty diff --git a/robotidy/transformers/MergeAndOrderSections.py b/robotidy/transformers/MergeAndOrderSections.py index 9ddbf94d..3cc57799 100644 --- a/robotidy/transformers/MergeAndOrderSections.py +++ b/robotidy/transformers/MergeAndOrderSections.py @@ -40,6 +40,8 @@ class MergeAndOrderSections(ModelTransformer): *** Settings *** You can disable this behaviour by setting ``create_comment_section`` to False. + + See https://robotidy.readthedocs.io/en/latest/transformers/MergeAndOrderSections.html for more examples. """ def __init__(self, order: str = '', create_comment_section: bool = True): self.sections_order = self.parse_order(order) diff --git a/robotidy/transformers/NormalizeAssignments.py b/robotidy/transformers/NormalizeAssignments.py index b2d38e6f..999433f8 100644 --- a/robotidy/transformers/NormalizeAssignments.py +++ b/robotidy/transformers/NormalizeAssignments.py @@ -15,7 +15,7 @@ class NormalizeAssignments(ModelTransformer): Normalize assignments. By default it detects most common assignment sign and apply it to every assignment in given file. - In this code most common is no equal sign at all. We should remove ``=`` signs from all lines:: + In this code most common is no equal sign at all. We should remove ``=`` signs from all lines: *** Variables *** ${var} = ${1} @@ -32,7 +32,7 @@ class NormalizeAssignments(ModelTransformer): ${var} Keyword2 ${var}= Keyword - To:: + To: *** Variables *** ${var} ${1} @@ -52,6 +52,7 @@ class NormalizeAssignments(ModelTransformer): You can configure that behaviour to automatically add desired equal sign with ``equal_sign_type`` parameter (possible types are: ``autodetect`` (default), ``remove``, ``equal_sign`` ('='), ``space_and_equal_sign`` (' ='). + See https://robotidy.readthedocs.io/en/latest/transformers/NormalizeAssignments.html for more examples. """ def __init__(self, equal_sign_type: str = 'autodetect'): self.remove_equal_sign = re.compile(r'\s?=$') diff --git a/robotidy/transformers/NormalizeNewLines.py b/robotidy/transformers/NormalizeNewLines.py index 1987137c..d46aac34 100644 --- a/robotidy/transformers/NormalizeNewLines.py +++ b/robotidy/transformers/NormalizeNewLines.py @@ -24,6 +24,8 @@ class NormalizeNewLines(ModelTransformer): If the suite contains Test Template tests will not be separated by empty lines unless ``separate_templated_tests`` is set to True. + + See https://robotidy.readthedocs.io/en/latest/transformers/NormalizeNewLines.html for more examples. """ def __init__(self, test_case_lines: int = 1, keyword_lines: Optional[int] = None, section_lines: int = 1, separate_templated_tests: bool = False, consecutive_lines: int = 1): diff --git a/robotidy/transformers/NormalizeSectionHeaderName.py b/robotidy/transformers/NormalizeSectionHeaderName.py index 15d49785..4d2de559 100644 --- a/robotidy/transformers/NormalizeSectionHeaderName.py +++ b/robotidy/transformers/NormalizeSectionHeaderName.py @@ -9,13 +9,13 @@ class NormalizeSectionHeaderName(ModelTransformer): """ Normalize section headers names. - Robot Framework is quite flexible with the section header naming. Following lines are equal:: + Robot Framework is quite flexible with the section header naming. Following lines are equal: *setting *** SETTINGS *** SettingS *** - This transformer normalize naming to follow ``*** SectionName ***`` format (with plurar variant):: + This transformer normalize naming to follow ``*** SectionName ***`` format (with plurar variant): *** Settings *** *** Keywords *** @@ -24,11 +24,13 @@ class NormalizeSectionHeaderName(ModelTransformer): *** Comments *** Optional data after section header (for example data driven column names) is preserved. - It is possible to upper case section header names by passing ``uppercase=True`` parameter:: + It is possible to upper case section header names by passing ``uppercase=True`` parameter: *** SETTINGS *** Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/NormalizeSectionHeaderName.html for more examples. """ def __init__(self, uppercase: bool = False): self.uppercase = uppercase diff --git a/robotidy/transformers/NormalizeSeparators.py b/robotidy/transformers/NormalizeSeparators.py index c7bbea08..838cc765 100644 --- a/robotidy/transformers/NormalizeSeparators.py +++ b/robotidy/transformers/NormalizeSeparators.py @@ -20,6 +20,8 @@ class NormalizeSeparators(ModelTransformer): ``sections = comments,settings,variables,keywords,testcases`` param. Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/NormalizeSeparators.html for more examples. """ def __init__(self, sections: str = None): self.indent = 0 diff --git a/robotidy/transformers/NormalizeSettingName.py b/robotidy/transformers/NormalizeSettingName.py index 7c437898..6533326f 100644 --- a/robotidy/transformers/NormalizeSettingName.py +++ b/robotidy/transformers/NormalizeSettingName.py @@ -10,7 +10,7 @@ class NormalizeSettingName(ModelTransformer): """ Normalize setting name. - Ensure that setting names are title case without leading or trailing whitespace. For example from:: + Ensure that setting names are title case without leading or trailing whitespace. For example from: *** Settings *** library library.py @@ -22,7 +22,7 @@ class NormalizeSettingName(ModelTransformer): [arguments] ${arg} [ SETUP] Setup Keyword - To:: + To: *** Settings *** Library library.py @@ -35,6 +35,8 @@ class NormalizeSettingName(ModelTransformer): [Setup] Setup Keyword Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/NormalizeSettingName.html for more examples. """ @check_start_end_line def visit_Statement(self, node): # noqa diff --git a/robotidy/transformers/OrderSettings.py b/robotidy/transformers/OrderSettings.py index cff36e27..01cbf24d 100644 --- a/robotidy/transformers/OrderSettings.py +++ b/robotidy/transformers/OrderSettings.py @@ -14,7 +14,7 @@ class OrderSettings(ModelTransformer): Order settings like [Arguments], [Setup], [Return] inside Keywords and Test Cases. Keyword settings [Documentation], [Tags], [Timeout], [Arguments] are put before keyword body and - settings like [Teardown], [Return] are moved to the end of keyword:: + settings like [Teardown], [Return] are moved to the end of keyword: *** Keywords *** Keyword @@ -26,7 +26,7 @@ class OrderSettings(ModelTransformer): [Tags] sanity Pass - To:: + To: *** Keywords *** Keyword @@ -54,6 +54,8 @@ class OrderSettings(ModelTransformer): It will order only test cases because all setting names for keywords are missing. Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/OrderSettings.html for more examples. """ def __init__(self, keyword_before: str = None, keyword_after: str = None, test_before: str = None, test_after: str = None): diff --git a/robotidy/transformers/OrderSettingsSection.py b/robotidy/transformers/OrderSettingsSection.py index 8400c348..ae0e9b65 100644 --- a/robotidy/transformers/OrderSettingsSection.py +++ b/robotidy/transformers/OrderSettingsSection.py @@ -28,16 +28,16 @@ class OrderSettingsSection(ModelTransformer): - ``imports_order = preserved`` - ``settings_order = suite_setup,suite_teardown,test_setup,test_teardown,test_timeout,test_template`` - By default order of imports is preserved. You can overwrite this behaviour:: + By default order of imports is preserved. You can overwrite this behaviour: robotidy --configure OrderSettingsSections:imports_order=library,resource,variables - You can also preserve order inside any group by passing ``preserved`` instead of setting names:: + You can also preserve order inside any group by passing ``preserved`` instead of setting names: robotidy --configure OrderSettingsSections:settings_order=preserved Setting names omitted from custom order will be removed from the file. In following example we are missing metadata - therefore all metadata will be removed:: + therefore all metadata will be removed: robotidy --configure OrderSettingsSection:documentation_order=documentation diff --git a/robotidy/transformers/RemoveEmptySettings.py b/robotidy/transformers/RemoveEmptySettings.py index af67546d..c28020d0 100644 --- a/robotidy/transformers/RemoveEmptySettings.py +++ b/robotidy/transformers/RemoveEmptySettings.py @@ -35,6 +35,8 @@ class RemoveEmptySettings(ModelTransformer): You can disable that behavior by changing ``more_explicit`` parameter value to ``False``. Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/RemoveEmptySettings.html for more examples. """ def __init__(self, work_mode: str = 'overwrite_ok', more_explicit: bool = True): if work_mode not in ('overwrite_ok', 'always'): diff --git a/robotidy/transformers/RenameTestCases.py b/robotidy/transformers/RenameTestCases.py new file mode 100644 index 00000000..04957d9c --- /dev/null +++ b/robotidy/transformers/RenameTestCases.py @@ -0,0 +1,59 @@ +import re +import random +import string +from typing import Optional + +from robot.api.parsing import ModelTransformer, Token +import click + +from robotidy.decorators import check_start_end_line + + +class RenameTestCases(ModelTransformer): + """ + Enforce test case naming. + + Capitalize first letter of test case name, remove trailing dot and strip leading/trailing whitespace. + + It is also possible to configure `replace_pattern` parameter to find and replace regex pattern. Use `replace_to` + to set replacement value. This configuration: + + robotidy --transform RenameTestCases -c RenameTestCases:replace_pattern=[A-Z]{3,}-\d{2,}:replace_to=foo + + will transform following code: + + *** Test Cases *** + test ABC-123 + No Operation + + To: + + *** Test Cases *** + Test foo + No Operation + + Supports global formatting params: ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/RenameTestCases.html for more examples. + """ + def __init__(self, replace_pattern: Optional[str] = None, replace_to: Optional[str] = None): + try: + self.replace_pattern = re.compile(replace_pattern) if replace_pattern is not None else None + except re.error as err: + raise click.BadOptionUsage( + option_name='transform', + message=f"Invalid configurable value: '{replace_pattern}' for replace_pattern in RenameTestCases" + f" transformer. It should be valid regex expression. Regex error: '{err.msg}'") + self.replace_to = '' if replace_to is None else replace_to + + @check_start_end_line + def visit_TestCaseName(self, node): # noqa + token = node.get_token(Token.TESTCASE_NAME) + if token.value: + token.value = token.value[0].upper() + token.value[1:] + if self.replace_pattern is not None: + token.value = self.replace_pattern.sub(repl=self.replace_to, string=token.value) + if token.value.endswith('.'): + token.value = token.value[:-1] + token.value = token.value.strip() + return node diff --git a/robotidy/transformers/ReplaceRunKeywordIf.py b/robotidy/transformers/ReplaceRunKeywordIf.py index 5b0062e5..002dc24a 100644 --- a/robotidy/transformers/ReplaceRunKeywordIf.py +++ b/robotidy/transformers/ReplaceRunKeywordIf.py @@ -25,14 +25,14 @@ class ReplaceRunKeywordIf(ModelTransformer): """ Replace ``Run Keyword If`` keyword calls with IF expressions. - Following code:: + Following code: Run Keyword If ${condition} ... Keyword ${arg} ... ELSE IF ${condition2} Keyword2 ... ELSE Keyword3 - Will be transformed to:: + Will be transformed to: IF ${condition} Keyword ${arg} @@ -42,11 +42,11 @@ class ReplaceRunKeywordIf(ModelTransformer): Keyword3 END - Any return value will be applied to every ELSE/ELSE IF branch:: + Any return value will be applied to every ELSE/ELSE IF branch: ${var} Run Keyword If ${condition} Keyword ELSE Keyword2 - Output:: + Output: IF ${condition} ${var} Keyword @@ -54,11 +54,11 @@ class ReplaceRunKeywordIf(ModelTransformer): ${var} Keyword2 END - Run Keywords inside Run Keyword If will be split into separate keywords:: + Run Keywords inside Run Keyword If will be split into separate keywords: Run Keyword If ${condition} Run Keywords Keyword ${arg} AND Keyword2 - Output:: + Output: IF ${condition} Keyword ${arg} @@ -66,6 +66,8 @@ class ReplaceRunKeywordIf(ModelTransformer): END Supports global formatting params: ``--spacecount``, ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/ReplaceRunKeywordIf.html for more examples. """ @check_start_end_line def visit_KeywordCall(self, node): # noqa diff --git a/robotidy/transformers/SmartSortKeywords.py b/robotidy/transformers/SmartSortKeywords.py index 37bde225..927a06d2 100644 --- a/robotidy/transformers/SmartSortKeywords.py +++ b/robotidy/transformers/SmartSortKeywords.py @@ -10,7 +10,7 @@ class SmartSortKeywords(ModelTransformer): treated as spaces. Empty lines (or lack of them) between keywords are preserved. - Following code:: + Following code: *** Keywords *** _my secrete keyword @@ -24,7 +24,7 @@ class SmartSortKeywords(ModelTransformer): my another keyword Kw3 - Will be transformed to:: + Will be transformed to: *** Keywords *** my_another_cool_keyword @@ -40,6 +40,8 @@ class SmartSortKeywords(ModelTransformer): Default behaviour could be changed using following parameters: ``case_insensitive = True``, ``ignore_leading_underscore = False`` and ``ignore_other_underscore = True``. + + See https://robotidy.readthedocs.io/en/latest/transformers/SmartSortKeywords.html for more examples. """ ENABLED = False diff --git a/robotidy/transformers/SplitTooLongLine.py b/robotidy/transformers/SplitTooLongLine.py index 2aafc114..84297114 100644 --- a/robotidy/transformers/SplitTooLongLine.py +++ b/robotidy/transformers/SplitTooLongLine.py @@ -13,16 +13,17 @@ class SplitTooLongLine(ModelTransformer): """ Split too long lines. If any line in keyword call exceeds given length limit (configurable using ``line_length``, 120 by default) it will be - split:: + split: Keyword With Longer Name ${arg1} ${arg2} ${arg3} # let's assume that arg2 is at 120 char - To:: + To: Keyword With Longer Name ${arg1} ... ${arg2} ${arg3} - Using ``split_on_every_arg`` flag (``False`` by default), you can force the formatter to put every argument in a new line:: + Using ``split_on_every_arg`` flag (``False`` by default), you can force the formatter to put every argument in a + new line: Keyword With Longer Name ... ${arg1} @@ -30,6 +31,8 @@ class SplitTooLongLine(ModelTransformer): ... ${arg3} Supports global formatting params: ``space_count``, ``--startline`` and ``--endline``. + + See https://robotidy.readthedocs.io/en/latest/transformers/SplitTooLongLine.html for more examples. """ def __init__(self, line_length: int = 120, split_on_every_arg: bool = False): super().__init__() diff --git a/robotidy/transformers/__init__.py b/robotidy/transformers/__init__.py index 5754e1f2..d9832a74 100644 --- a/robotidy/transformers/__init__.py +++ b/robotidy/transformers/__init__.py @@ -30,7 +30,9 @@ 'NormalizeSettingName', 'ReplaceRunKeywordIf', 'SplitTooLongLine', - 'SmartSortKeywords' + 'SmartSortKeywords', + 'RenameTestCases', + 'RenameTestCases' ] diff --git a/robotidy/utils.py b/robotidy/utils.py index 32deaca8..a46d6dfa 100644 --- a/robotidy/utils.py +++ b/robotidy/utils.py @@ -98,11 +98,32 @@ def split_args_from_name_or_path(name): index = _get_arg_separator_index_from_name_or_path(name) if index == -1: return name, [] - args = name[index+1:].split(name[index]) + args = _escaped_split(name[index+1:], name[index]) name = name[:index] return name, args +def _escaped_split(string, delim): + ret = [] + current = [] + itr = iter(string) + for ch in itr: + if ch == '\\': + try: + current.append('\\') + current.append(next(itr)) + except StopIteration: + pass + elif ch == delim: + ret.append(''.join(current)) + current = [] + else: + current.append(ch) + if current: + ret.append(''.join(current)) + return ret + + def _get_arg_separator_index_from_name_or_path(name): colon_index = name.find(':') # Handle absolute Windows paths diff --git a/tests/atest/transformers/RenameTestCases/__init__.py b/tests/atest/transformers/RenameTestCases/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/atest/transformers/RenameTestCases/expected/empty_test_name.robot b/tests/atest/transformers/RenameTestCases/expected/empty_test_name.robot new file mode 100644 index 00000000..f1e99d3d --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/expected/empty_test_name.robot @@ -0,0 +1,11 @@ +*** Test Cases *** + +# no test case name!!! + Log To Console hello + +Proper test + [documentation] doc + [tags] sometag + Pass + Keyword + One More diff --git a/tests/atest/transformers/RenameTestCases/expected/replace_pattern_empty.robot b/tests/atest/transformers/RenameTestCases/expected/replace_pattern_empty.robot new file mode 100644 index 00000000..dfd1c6e2 --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/expected/replace_pattern_empty.robot @@ -0,0 +1,16 @@ +*** Test Cases *** +Starting with small case + log 1 + +Ending with dot + No Operation + +Ending with dot and containing variables column name another column + No Operation + +Containing replace pattern + [Tags] tag + No Operation + +Remove special chars: ?$@ + No Operation diff --git a/tests/atest/transformers/RenameTestCases/expected/replace_pattern_placeholder.robot b/tests/atest/transformers/RenameTestCases/expected/replace_pattern_placeholder.robot new file mode 100644 index 00000000..450174b3 --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/expected/replace_pattern_placeholder.robot @@ -0,0 +1,16 @@ +*** Test Cases *** +Starting with small case + log 1 + +Ending with dot + No Operation + +Ending with dot and containing variables column name another column + No Operation + +Containing replace pattern PLACEHOLDER + [Tags] tag + No Operation + +Remove special chars: ?$@ + No Operation diff --git a/tests/atest/transformers/RenameTestCases/expected/replace_pattern_special_chars.robot b/tests/atest/transformers/RenameTestCases/expected/replace_pattern_special_chars.robot new file mode 100644 index 00000000..69c551f7 --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/expected/replace_pattern_special_chars.robot @@ -0,0 +1,16 @@ +*** Test Cases *** +Starting with small case + log 1 + +Ending with dot + No Operation + +Ending with dot and containing variables column name another column + No Operation + +Containing replace pattern JIRA-1234 + [Tags] tag + No Operation + +Remove special chars + No Operation diff --git a/tests/atest/transformers/RenameTestCases/expected/selected.robot b/tests/atest/transformers/RenameTestCases/expected/selected.robot new file mode 100644 index 00000000..e7bd5036 --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/expected/selected.robot @@ -0,0 +1,16 @@ +*** Test Cases *** +starting with small case + log 1 + +Ending with dot + No Operation + +Ending with dot and containing variables . column name another column + No Operation + +Containing replace pattern JIRA-1234 + [Tags] tag + No Operation + +Remove special chars: ?$@ + No Operation diff --git a/tests/atest/transformers/RenameTestCases/expected/test.robot b/tests/atest/transformers/RenameTestCases/expected/test.robot new file mode 100644 index 00000000..ee956401 --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/expected/test.robot @@ -0,0 +1,16 @@ +*** Test Cases *** +Starting with small case + log 1 + +Ending with dot + No Operation + +Ending with dot and containing variables column name another column + No Operation + +Containing replace pattern JIRA-1234 + [Tags] tag + No Operation + +Remove special chars: ?$@ + No Operation diff --git a/tests/atest/transformers/RenameTestCases/source/empty_test_name.robot b/tests/atest/transformers/RenameTestCases/source/empty_test_name.robot new file mode 100644 index 00000000..f1e99d3d --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/source/empty_test_name.robot @@ -0,0 +1,11 @@ +*** Test Cases *** + +# no test case name!!! + Log To Console hello + +Proper test + [documentation] doc + [tags] sometag + Pass + Keyword + One More diff --git a/tests/atest/transformers/RenameTestCases/source/test.robot b/tests/atest/transformers/RenameTestCases/source/test.robot new file mode 100644 index 00000000..d63a4977 --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/source/test.robot @@ -0,0 +1,16 @@ +*** Test Cases *** +starting with small case + log 1 + +Ending with dot. + No Operation + +Ending with dot and containing variables . column name another column + No Operation + +Containing replace pattern JIRA-1234 + [Tags] tag + No Operation + +Remove special chars: ?$@ + No Operation diff --git a/tests/atest/transformers/RenameTestCases/test_transformer.py b/tests/atest/transformers/RenameTestCases/test_transformer.py new file mode 100644 index 00000000..aced3271 --- /dev/null +++ b/tests/atest/transformers/RenameTestCases/test_transformer.py @@ -0,0 +1,56 @@ +from .. import run_tidy_and_compare, run_tidy + + +class TestRenameTestCases: + TRANSFORMER_NAME = 'RenameTestCases' + + def test_transformer(self): + run_tidy_and_compare(self.TRANSFORMER_NAME, source='test.robot', expected='test.robot') + + def test_test_without_name(self): + run_tidy_and_compare(self.TRANSFORMER_NAME, source='empty_test_name.robot', expected='empty_test_name.robot') + + def test_replace_pattern_to_empty(self): + run_tidy_and_compare( + self.TRANSFORMER_NAME, + source='test.robot', + expected='replace_pattern_empty.robot', + config=r':replace_pattern=[A-Z]+-\d{1,}' + ) + + def test_replace_pattern_to_placeholder(self): + run_tidy_and_compare( + self.TRANSFORMER_NAME, + source='test.robot', + expected='replace_pattern_placeholder.robot', + config=r':replace_pattern=[A-Z]+-\d{1,}:replace_to=PLACEHOLDER' + ) + + def test_replace_pattern_special_chars(self): + run_tidy_and_compare( + self.TRANSFORMER_NAME, + source='test.robot', + expected='replace_pattern_special_chars.robot', + config=r':replace_pattern=[\:?$@]' + ) + + def test_selected_lines(self): + run_tidy_and_compare( + self.TRANSFORMER_NAME, + source='test.robot', + expected='selected.robot', + config=' --startline 5 --endline 5' + ) + + def test_invalid_pattern(self): + result = run_tidy( + self.TRANSFORMER_NAME, + args=f'--transform {self.TRANSFORMER_NAME}:replace_pattern=[\911]'.split(), + source='test.robot', + exit_code=1 + ) + expected_output = f"Importing 'robotidy.transformers.{self.TRANSFORMER_NAME}' failed: " \ + "Creating instance failed: BadOptionUsage: Invalid configurable value: " \ + rf"'[\911]' for replace_pattern in {self.TRANSFORMER_NAME} transformer. " \ + "It should be valid regex expression. Regex error: 'bad escape \\9'" + assert expected_output in str(result.exception) From 498aaf08c911c7547ea27e70dd8a4c7d8bcc829a Mon Sep 17 00:00:00 2001 From: Bartlomiej Hirsz Date: Mon, 30 Aug 2021 21:26:54 +0200 Subject: [PATCH 4/7] raw escape --- tests/atest/transformers/RenameTestCases/test_transformer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/atest/transformers/RenameTestCases/test_transformer.py b/tests/atest/transformers/RenameTestCases/test_transformer.py index aced3271..2e77a17e 100644 --- a/tests/atest/transformers/RenameTestCases/test_transformer.py +++ b/tests/atest/transformers/RenameTestCases/test_transformer.py @@ -45,7 +45,7 @@ def test_selected_lines(self): def test_invalid_pattern(self): result = run_tidy( self.TRANSFORMER_NAME, - args=f'--transform {self.TRANSFORMER_NAME}:replace_pattern=[\911]'.split(), + args=rf'--transform {self.TRANSFORMER_NAME}:replace_pattern=[\911]'.split(), source='test.robot', exit_code=1 ) From 5bce4d956a847035237bd632872972051e19adc3 Mon Sep 17 00:00:00 2001 From: Bartlomiej Hirsz Date: Mon, 30 Aug 2021 21:30:22 +0200 Subject: [PATCH 5/7] append new line --- CHANGES.md | 2 ++ docs/source/transformers/RenameTestCases.rst | 1 + 2 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 5bb5bfba..d056570a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,8 @@ ### Features - It is now possible to provide source paths in configuration file [#154](https://github.com/MarketSquare/robotframework-tidy/issues/154) - Non default transformers can be enabled using ``enabled=True`` parameter [#182](https://github.com/MarketSquare/robotframework-tidy/issues/182) +- New non default transformer `RenameTestCases`. It capitalizes first letter of the test case name, remove trailing dot and can replace provided regex pattern with substitute string [#183](https://github.com/MarketSquare/robotframework-tidy/issues/183) +- Semicolon in parameter value can be now escaped with `\:` [#190](https://github.com/MarketSquare/robotframework-tidy/issues/190) ## 1.5.1 diff --git a/docs/source/transformers/RenameTestCases.rst b/docs/source/transformers/RenameTestCases.rst index 5fc773a1..83a57e05 100644 --- a/docs/source/transformers/RenameTestCases.rst +++ b/docs/source/transformers/RenameTestCases.rst @@ -21,6 +21,7 @@ to set replacement value. This configuration:: robotidy --transform RenameTestCases -c RenameTestCases:replace_pattern=[A-Z]{3,}-\d{2,}:replace_to=foo Replaces all occurrences of given pattern with string 'foo': + .. tabs:: .. code-tab:: robotframework Before From 3c172de5d44efea42c6ab96f1704dfe342cebfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Hirsz?= Date: Tue, 31 Aug 2021 08:28:42 +0200 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: Mateusz Nojek --- CHANGES.md | 4 ++-- docs/source/transformers/RenameTestCases.rst | 6 +++--- robotidy/transformers/NormalizeSectionHeaderName.py | 2 +- robotidy/transformers/OrderSettings.py | 2 +- robotidy/transformers/RenameTestCases.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d056570a..b565bb19 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,8 +5,8 @@ ### Features - It is now possible to provide source paths in configuration file [#154](https://github.com/MarketSquare/robotframework-tidy/issues/154) - Non default transformers can be enabled using ``enabled=True`` parameter [#182](https://github.com/MarketSquare/robotframework-tidy/issues/182) -- New non default transformer `RenameTestCases`. It capitalizes first letter of the test case name, remove trailing dot and can replace provided regex pattern with substitute string [#183](https://github.com/MarketSquare/robotframework-tidy/issues/183) -- Semicolon in parameter value can be now escaped with `\:` [#190](https://github.com/MarketSquare/robotframework-tidy/issues/190) +- New non default transformer `RenameTestCases`. It capitalizes first letter of the test case name, removes trailing dot and can replace provided regex pattern with substitute string [#183](https://github.com/MarketSquare/robotframework-tidy/issues/183) +- Semicolon in parameter value can now be escaped with `\:` [#190](https://github.com/MarketSquare/robotframework-tidy/issues/190) ## 1.5.1 diff --git a/docs/source/transformers/RenameTestCases.rst b/docs/source/transformers/RenameTestCases.rst index 83a57e05..98383291 100644 --- a/docs/source/transformers/RenameTestCases.rst +++ b/docs/source/transformers/RenameTestCases.rst @@ -5,7 +5,7 @@ RenameTestCases Enforce test case naming. -RenameTestCases is not included in default transformers that's why you need to call it with ``--transform`` explicitly:: +RenameTestCases is not included in default transformers, that's why you need to call it with ``--transform`` explicitly:: robotidy --transform RenameTestCases src @@ -13,10 +13,10 @@ Or configure `enable` parameter:: robotidy --configure RenameTestCases:enabled=True -This transformer capitalize first letter of test case name, remove trailing dot and strip leading/trailing whitespace. +This transformer capitalizes first letter of test case name, removes trailing dot and strips leading/trailing whitespace. It is also possible to configure `replace_pattern` parameter to find and replace regex pattern. Use `replace_to` -to set replacement value. This configuration:: +to set a replacement value. This configuration:: robotidy --transform RenameTestCases -c RenameTestCases:replace_pattern=[A-Z]{3,}-\d{2,}:replace_to=foo diff --git a/robotidy/transformers/NormalizeSectionHeaderName.py b/robotidy/transformers/NormalizeSectionHeaderName.py index 4d2de559..74076189 100644 --- a/robotidy/transformers/NormalizeSectionHeaderName.py +++ b/robotidy/transformers/NormalizeSectionHeaderName.py @@ -15,7 +15,7 @@ class NormalizeSectionHeaderName(ModelTransformer): *** SETTINGS *** SettingS *** - This transformer normalize naming to follow ``*** SectionName ***`` format (with plurar variant): + This transformer normalizes naming to follow ``*** SectionName ***`` format (with plural variant): *** Settings *** *** Keywords *** diff --git a/robotidy/transformers/OrderSettings.py b/robotidy/transformers/OrderSettings.py index 01cbf24d..24182296 100644 --- a/robotidy/transformers/OrderSettings.py +++ b/robotidy/transformers/OrderSettings.py @@ -14,7 +14,7 @@ class OrderSettings(ModelTransformer): Order settings like [Arguments], [Setup], [Return] inside Keywords and Test Cases. Keyword settings [Documentation], [Tags], [Timeout], [Arguments] are put before keyword body and - settings like [Teardown], [Return] are moved to the end of keyword: + settings like [Teardown], [Return] are moved to the end of the keyword: *** Keywords *** Keyword diff --git a/robotidy/transformers/RenameTestCases.py b/robotidy/transformers/RenameTestCases.py index 04957d9c..d5280196 100644 --- a/robotidy/transformers/RenameTestCases.py +++ b/robotidy/transformers/RenameTestCases.py @@ -43,7 +43,7 @@ def __init__(self, replace_pattern: Optional[str] = None, replace_to: Optional[s raise click.BadOptionUsage( option_name='transform', message=f"Invalid configurable value: '{replace_pattern}' for replace_pattern in RenameTestCases" - f" transformer. It should be valid regex expression. Regex error: '{err.msg}'") + f" transformer. It should be a valid regex expression. Regex error: '{err.msg}'") self.replace_to = '' if replace_to is None else replace_to @check_start_end_line From be50632026e4a5ef9fe5e49646ec844184cf8187 Mon Sep 17 00:00:00 2001 From: Bartlomiej Hirsz Date: Tue, 31 Aug 2021 08:46:54 +0200 Subject: [PATCH 7/7] fix tests --- robotidy/transformers/RenameTestCases.py | 4 +++- tests/atest/transformers/RenameTestCases/test_transformer.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/robotidy/transformers/RenameTestCases.py b/robotidy/transformers/RenameTestCases.py index d5280196..cf3e7c1e 100644 --- a/robotidy/transformers/RenameTestCases.py +++ b/robotidy/transformers/RenameTestCases.py @@ -10,7 +10,7 @@ class RenameTestCases(ModelTransformer): - """ + r""" Enforce test case naming. Capitalize first letter of test case name, remove trailing dot and strip leading/trailing whitespace. @@ -36,6 +36,8 @@ class RenameTestCases(ModelTransformer): See https://robotidy.readthedocs.io/en/latest/transformers/RenameTestCases.html for more examples. """ + ENABLED = False + def __init__(self, replace_pattern: Optional[str] = None, replace_to: Optional[str] = None): try: self.replace_pattern = re.compile(replace_pattern) if replace_pattern is not None else None diff --git a/tests/atest/transformers/RenameTestCases/test_transformer.py b/tests/atest/transformers/RenameTestCases/test_transformer.py index 2e77a17e..8d91c591 100644 --- a/tests/atest/transformers/RenameTestCases/test_transformer.py +++ b/tests/atest/transformers/RenameTestCases/test_transformer.py @@ -52,5 +52,5 @@ def test_invalid_pattern(self): expected_output = f"Importing 'robotidy.transformers.{self.TRANSFORMER_NAME}' failed: " \ "Creating instance failed: BadOptionUsage: Invalid configurable value: " \ rf"'[\911]' for replace_pattern in {self.TRANSFORMER_NAME} transformer. " \ - "It should be valid regex expression. Regex error: 'bad escape \\9'" + "It should be a valid regex expression. Regex error: 'bad escape \\9'" assert expected_output in str(result.exception)