test_helpers.py
240 lines
| 8.6 KiB
| text/x-python
|
PythonLexer
r1 | ||||
r5088 | # Copyright (C) 2010-2023 RhodeCode GmbH | |||
r1 | # | |||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU Affero General Public License, version 3 | ||||
# (only), as published by the Free Software Foundation. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU Affero General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
# | ||||
# This program is dual-licensed. If you wish to learn more about the | ||||
# RhodeCode Enterprise Edition, including its added features, Support services, | ||||
# and proprietary license terms, please see https://rhodecode.com/licenses/ | ||||
import copy | ||||
import mock | ||||
import pytest | ||||
from rhodecode.lib import helpers | ||||
from rhodecode.lib.utils2 import AttributeDict | ||||
from rhodecode.model.settings import IssueTrackerSettingsModel | ||||
r1774 | from rhodecode.tests import no_newline_id_generator | |||
r1 | ||||
@pytest.mark.parametrize('url, expected_url', [ | ||||
r5149 | (r'https://rc.com', '<a href="https://rc.com">http://rc.com</a>'), | |||
(r'https://rc.com/test', '<a href="https://rc.com/test">https://rc.com/test</a>'), | ||||
(r'https://rc.com/!foo', '<a href="https://rc.com/!foo">https://rc.com/!foo</a>'), | ||||
(r'https://rc.com/&foo', '<a href="https://rc.com/&foo">https://rc.com/&foo</a>'), | ||||
(r'https://rc.com/?foo-1&bar=1', '<a href="https://rc.com/?foo-1&bar=1">https://rc.com/?foo-1&bar=1</a>'), | ||||
(r'https://rc.com?foo-1&bar=1', '<a href="https://rc.com?foo-1&bar=1">https://rc.com?foo-1&bar=1</a>'), | ||||
(r'https://rc.com/#foo', '<a href="https://rc.com/#foo">https://rc.com/#foo</a>'), | ||||
(r'https://rc.com/@foo', '<a href="https://rc.com/@foo">https://rc.com/@foo</a>'), | ||||
r1 | ]) | |||
def test_urlify_text(url, expected_url): | ||||
assert helpers.urlify_text(url) == expected_url | ||||
@pytest.mark.parametrize('repo_name, commit_id, path, expected_result', [ | ||||
r3741 | # Simple case 1 | |||
('repo', 'commit', 'a/b', | ||||
'<a href="/repo/files/commit/"><i class="icon-home"></i></a>' | ||||
' / ' | ||||
'<a href="/repo/files/commit/a">a</a>' | ||||
' / ' | ||||
'b'), | ||||
# Simple case | ||||
r1 | ('rX<X', 'cX<X', 'pX<X/aX<X/bX<X', | |||
r3741 | '<a href="/rX%3CX/files/cX%3CX/"><i class="icon-home"></i></a>' | |||
' / ' | ||||
'<a href="/rX%3CX/files/cX%3CX/pX%3CX">pX<X</a>' | ||||
' / ' | ||||
'<a href="/rX%3CX/files/cX%3CX/pX%3CX/aX%3CX">aX<X</a>' | ||||
' / ' | ||||
'bX<X'), | ||||
r1 | # Path with only one segment | |||
('rX<X', 'cX<X', 'pX<X', | ||||
r3741 | '<a href="/rX%3CX/files/cX%3CX/"><i class="icon-home"></i></a>' | |||
' / ' | ||||
'pX<X'), | ||||
r1 | # Empty path | |||
r3741 | ('rX<X', 'cX<X', '', | |||
'<i class="icon-home"></i>'), | ||||
# simple quote | ||||
r1 | ('rX"X', 'cX"X', 'pX"X/aX"X/bX"X', | |||
r3741 | '<a href="/rX%22X/files/cX%22X/"><i class="icon-home"></i></a>' | |||
' / ' | ||||
'<a href="/rX%22X/files/cX%22X/pX%22X">pX"X</a>' | ||||
' / ' | ||||
'<a href="/rX%22X/files/cX%22X/pX%22X/aX%22X">aX"X</a>' | ||||
' / ' | ||||
'bX"X'), | ||||
], ids=['simple1', 'simple2', 'one_segment', 'empty_path', 'simple_quote']) | ||||
r4372 | def test_files_breadcrumbs_xss(repo_name, commit_id, path, app, expected_result): | |||
result = helpers.files_breadcrumbs(repo_name, 'hg', commit_id, path) | ||||
r1 | # Expect it to encode all path fragments properly. This is important | |||
# because it returns an instance of `literal`. | ||||
r3741 | if path != '': | |||
expected_result = expected_result + helpers.files_icon.format(helpers.escape(path)) | ||||
r1 | assert result == expected_result | |||
def test_format_binary(): | ||||
assert helpers.format_byte_size_binary(298489462784) == '278.0 GiB' | ||||
r411 | @pytest.mark.parametrize('text_string, pattern, expected', [ | |||
r5149 | ('No issue here', r'(?:#)(?P<issue_id>\d+)', []), | |||
r411 | ('Fix #42', '(?:#)(?P<issue_id>\d+)', | |||
r5149 | [{'url': 'https://r.io/{repo}/i/42', 'id': '42'}]), | |||
r411 | ('Fix #42, #53', '(?:#)(?P<issue_id>\d+)', [ | |||
r5149 | {'url': 'https://r.io/{repo}/i/42', 'id': '42'}, | |||
{'url': 'https://r.io/{repo}/i/53', 'id': '53'}]), | ||||
r411 | ('Fix #42', '(?:#)?<issue_id>\d+)', []), # Broken regex | |||
]) | ||||
def test_extract_issues(backend, text_string, pattern, expected): | ||||
repo = backend.create_repo() | ||||
config = { | ||||
'123': { | ||||
'uid': '123', | ||||
'pat': pattern, | ||||
r5149 | 'url': r'https://r.io/${repo}/i/${issue_id}', | |||
r411 | 'pref': '#', | |||
r4033 | 'desc': 'Test Pattern' | |||
r411 | } | |||
} | ||||
def get_settings_mock(self, cache=True): | ||||
return config | ||||
with mock.patch.object(IssueTrackerSettingsModel, | ||||
'get_settings', get_settings_mock): | ||||
r4498 | text, issues, errors = helpers.process_patterns(text_string, repo.repo_name) | |||
r411 | ||||
expected = copy.deepcopy(expected) | ||||
for item in expected: | ||||
item['url'] = item['url'].format(repo=repo.repo_name) | ||||
assert issues == expected | ||||
r1672 | @pytest.mark.parametrize('text_string, pattern, link_format, expected_text', [ | |||
('Fix #42', '(?:#)(?P<issue_id>\d+)', 'html', | ||||
r4033 | 'Fix <a class="tooltip issue-tracker-link" href="http://r.io/{repo}/i/42" title="Test Pattern">#42</a>'), | |||
r1672 | ||||
('Fix #42', '(?:#)(?P<issue_id>\d+)', 'markdown', | ||||
'Fix [#42](http://r.io/{repo}/i/42)'), | ||||
('Fix #42', '(?:#)(?P<issue_id>\d+)', 'rst', | ||||
'Fix `#42 <http://r.io/{repo}/i/42>`_'), | ||||
('Fix #42', '(?:#)?<issue_id>\d+)', 'html', | ||||
'Fix #42'), # Broken regex | ||||
r1 | ]) | |||
r1672 | def test_process_patterns_repo(backend, text_string, pattern, expected_text, link_format): | |||
r1 | repo = backend.create_repo() | |||
r273 | ||||
def get_settings_mock(self, cache=True): | ||||
r1672 | return { | |||
'123': { | ||||
'uid': '123', | ||||
'pat': pattern, | ||||
'url': 'http://r.io/${repo}/i/${issue_id}', | ||||
'pref': '#', | ||||
r4033 | 'desc': 'Test Pattern' | |||
r1672 | } | |||
} | ||||
r273 | ||||
r1 | with mock.patch.object(IssueTrackerSettingsModel, | |||
r273 | 'get_settings', get_settings_mock): | |||
r4498 | processed_text, issues, error = helpers.process_patterns( | |||
r1672 | text_string, repo.repo_name, link_format) | |||
r1 | ||||
assert processed_text == expected_text.format(repo=repo.repo_name) | ||||
@pytest.mark.parametrize('text_string, pattern, expected_text', [ | ||||
('Fix #42', '(?:#)(?P<issue_id>\d+)', | ||||
r4033 | 'Fix <a class="tooltip issue-tracker-link" href="http://r.io/i/42" title="Test Pattern">#42</a>'), | |||
r1672 | ('Fix #42', '(?:#)?<issue_id>\d+)', | |||
'Fix #42'), # Broken regex | ||||
r1 | ]) | |||
def test_process_patterns_no_repo(text_string, pattern, expected_text): | ||||
r273 | ||||
def get_settings_mock(self, cache=True): | ||||
r1672 | return { | |||
'123': { | ||||
'uid': '123', | ||||
'pat': pattern, | ||||
'url': 'http://r.io/i/${issue_id}', | ||||
'pref': '#', | ||||
r4033 | 'desc': 'Test Pattern' | |||
r1672 | } | |||
} | ||||
r273 | ||||
r1 | with mock.patch.object(IssueTrackerSettingsModel, | |||
r273 | 'get_global_settings', get_settings_mock): | |||
r4498 | processed_text, issues, errors = helpers.process_patterns( | |||
r1672 | text_string, '') | |||
r1 | ||||
assert processed_text == expected_text | ||||
def test_process_patterns_non_existent_repo_name(backend): | ||||
text_string = 'Fix #42' | ||||
pattern = '(?:#)(?P<issue_id>\d+)' | ||||
r4033 | expected_text = ('Fix <a class="tooltip issue-tracker-link" ' | |||
'href="http://r.io/do-not-exist/i/42" title="Test Pattern">#42</a>') | ||||
r273 | ||||
def get_settings_mock(self, cache=True): | ||||
r1672 | return { | |||
'123': { | ||||
'uid': '123', | ||||
'pat': pattern, | ||||
'url': 'http://r.io/${repo}/i/${issue_id}', | ||||
'pref': '#', | ||||
r4033 | 'desc': 'Test Pattern' | |||
r1672 | } | |||
} | ||||
r273 | ||||
r1 | with mock.patch.object(IssueTrackerSettingsModel, | |||
r273 | 'get_global_settings', get_settings_mock): | |||
r4498 | processed_text, issues, errors = helpers.process_patterns( | |||
r1672 | text_string, 'do-not-exist') | |||
r1 | ||||
assert processed_text == expected_text | ||||
r2351 | def test_get_visual_attr(baseapp): | |||
from rhodecode.apps._base import TemplateArgs | ||||
c = TemplateArgs() | ||||
r1 | assert None is helpers.get_visual_attr(c, 'fakse') | |||
# emulate the c.visual behaviour | ||||
c.visual = AttributeDict({}) | ||||
assert None is helpers.get_visual_attr(c, 'some_var') | ||||
c.visual.some_var = 'foobar' | ||||
assert 'foobar' == helpers.get_visual_attr(c, 'some_var') | ||||
@pytest.mark.parametrize('test_text, inclusive, expected_text', [ | ||||
('just a string', False, 'just a string'), | ||||
('just a string\n', False, 'just a string'), | ||||
('just a string\n next line', False, 'just a string...'), | ||||
('just a string\n next line', True, 'just a string\n...'), | ||||
r1774 | ], ids=no_newline_id_generator) | |||
r1 | def test_chop_at(test_text, inclusive, expected_text): | |||
assert helpers.chop_at_smart( | ||||
test_text, '\n', inclusive, '...') == expected_text | ||||