Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

### Fixes
- Do not count documentation length when aligning all columns in settings section [#156](https://github.com/MarketSquare/robotframework-tidy/issues/156)
- Acknowledge ``--lineseparator`` option [#163](https://github.com/MarketSquare/robotframework-tidy/issues/163)

## 1.4.0

Expand Down
6 changes: 4 additions & 2 deletions robotidy/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
from robotidy.utils import (
StatementLinesCollector,
decorate_diff_with_color,
GlobalFormattingConfig
GlobalFormattingConfig,
ModelWriter
)

INCLUDE_EXT = ('.robot', '.resource')
Expand Down Expand Up @@ -74,7 +75,8 @@ def transform(self, model):

def save_model(self, model):
if self.overwrite:
model.save(output=self.output)
output = self.output or model.source
ModelWriter(output=output, newline=self.formatting_config.line_sep).write(model)

def output_diff(self, path: str, old_model: StatementLinesCollector, new_model: StatementLinesCollector):
if not self.show_diff:
Expand Down
18 changes: 18 additions & 0 deletions robotidy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Token
)
from robot.parsing.model import Statement
from robot.utils.robotio import file_writer
from click import style


Expand Down Expand Up @@ -201,3 +202,20 @@ def get_normalized_candidates(candidates):
norm_cand['alignvariables'] = ['AlignVariablesSection']
norm_cand['assignmentnormalizer'] = ['NormalizeAssignments']
return norm_cand


class ModelWriter(ModelVisitor):
def __init__(self, output, newline):
self.writer = file_writer(output, newline=newline)
self.close_writer = True

def write(self, model):
try:
self.visit(model)
finally:
if self.close_writer:
self.writer.close()

def visit_Statement(self, statement): # noqa
for token in statement.tokens:
self.writer.write(token.value)
39 changes: 30 additions & 9 deletions tests/utest/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
from unittest.mock import patch
import os
from pathlib import Path

from unittest.mock import MagicMock, Mock

import pytest
from click import FileError, NoSuchOption

from .utils import run_tidy, save_tmp_model
from robotidy.cli import (
find_project_root,
read_pyproject_config,
read_config
)
from robotidy.utils import node_within_lines
from robotidy.transformers import load_transformers
from robotidy.transformers.AlignSettingsSection import AlignSettingsSection
from robotidy.transformers.ReplaceRunKeywordIf import ReplaceRunKeywordIf
from robotidy.transformers.SmartSortKeywords import SmartSortKeywords
from robotidy.utils import node_within_lines
from robotidy.version import __version__
from .utils import run_tidy


@patch('robotidy.app.Robotidy.save_model', new=save_tmp_model)
class TestCli:
@pytest.mark.parametrize('src', [
None,
Expand Down Expand Up @@ -88,7 +87,7 @@ def test_too_many_arguments_for_transform(self):
def test_find_project_root_from_src(self):
src = Path(Path(__file__).parent, 'testdata', 'nested', 'test.robot')
path = find_project_root([src])
assert path == Path(Path(__file__).parent, 'testdata')
assert path == Path(Path(__file__).parent, 'testdata', 'nested')

def test_read_robotidy_config(self):
""" robotidy.toml follows the same format as pyproject starting from 1.2.0 """
Expand All @@ -101,7 +100,7 @@ def test_read_robotidy_config(self):
'ReplaceRunKeywordIf'
]
}
config_path = str(Path(Path(__file__).parent, 'testdata', 'robotidy.toml'))
config_path = str(Path(Path(__file__).parent, 'testdata', 'config', 'robotidy.toml'))
config = read_pyproject_config(config_path)
assert config == expected_config

Expand Down Expand Up @@ -176,7 +175,7 @@ def test_read_config_from_param(self):
'ReplaceRunKeywordIf'
]
}
config_path = str(Path(Path(__file__).parent, 'testdata', 'robotidy.toml'))
config_path = str(Path(Path(__file__).parent, 'testdata', 'config', 'robotidy.toml'))
ctx_mock = MagicMock()
ctx_mock.command.params = None
param_mock = Mock()
Expand All @@ -193,7 +192,7 @@ def test_read_config_without_param(self):
'ReplaceRunKeywordIf'
]
}
config_path = str(Path(Path(__file__).parent, 'testdata', 'robotidy.toml'))
config_path = str(Path(Path(__file__).parent, 'testdata', 'config', 'robotidy.toml'))
ctx_mock = MagicMock()
ctx_mock.params = {'src': [config_path]}
ctx_mock.command.params = None
Expand Down Expand Up @@ -300,3 +299,25 @@ def test_configure_transformer_overwrite(self):
{'AlignVariablesSection': ['up_to_column=4']}
)
assert transformers[0].up_to_column + 1 == 4

@pytest.mark.parametrize('line_sep', ['unix', 'windows', 'native', None])
def test_line_sep(self, line_sep):
source = Path(Path(__file__).parent, 'testdata', 'line_sep', 'test.robot')
expected = Path(Path(__file__).parent, 'testdata', 'line_sep', 'expected.robot')
actual = Path(Path(__file__).parent, 'actual', 'test.robot')
if line_sep is not None:
run_tidy(['--lineseparator', line_sep, str(source)], output='test.robot')
else:
run_tidy([str(source)], output='test.robot')
line_end = {
'unix': '\n',
'windows': '\r\n',
'native': os.linesep,
None: os.linesep
}[line_sep]
with open(str(expected)) as f:
expected_str = f.read()
expected_str = expected_str.replace('\n', line_end)
with open(str(actual), newline='') as f:
actual_str = f.read()
assert actual_str == expected_str, 'Line endings does not match'
9 changes: 9 additions & 0 deletions tests/utest/testdata/line_sep/expected.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*** Settings ***
Library library.py

Force Tags tag

*** Keywords ***
Keyword
Log information
No Operation
9 changes: 9 additions & 0 deletions tests/utest/testdata/line_sep/test.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*** Settings ***
Library library.py

Force Tags tag

*** Keywords ***
Keyword
Log information
No Operation
8 changes: 8 additions & 0 deletions tests/utest/testdata/nested/robotidy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[tool.robotidy]
overwrite = false
diff = false
spacecount = 4
transform = [
"DiscardEmptySections:allow_only_comments=True",
"ReplaceRunKeywordIf"
]
17 changes: 7 additions & 10 deletions tests/utest/utils.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
from pathlib import Path
from typing import List
from typing import List, Optional

from click.testing import CliRunner

from robotidy.cli import cli


def save_tmp_model(self, model):
""" Decorator that disables default robotidy save to file mechanism and replace with mocked one.
That way we can save output to 'actual' directory for easy comparison with expected files. """
path = Path(Path(__file__).parent, 'actual', Path(model.source).name)
print(path)
model.save(output=path)


def run_tidy(args: List[str] = None, exit_code: int = 0):
def run_tidy(args: List[str] = None, exit_code: int = 0, output: Optional[str] = None):
runner = CliRunner()
arguments = args if args is not None else []
if output:
output_path = str(Path(Path(__file__).parent, 'actual', output))
else:
output_path = str(Path(Path(__file__).parent, 'actual', 'tmp'))
arguments = ['--output', output_path] + arguments
result = runner.invoke(cli, arguments)
if result.exit_code != exit_code:
print(result.output)
Expand Down