248 lines
11 KiB
Python
248 lines
11 KiB
Python
import os
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
from git import Repo
|
|
from rspec_tools.create_rule import (RuleCreator, add_language_to_rule,
|
|
create_new_rule)
|
|
from rspec_tools.errors import InvalidArgumentError
|
|
from rspec_tools.repo import RspecRepo
|
|
from rspec_tools.utils import LANG_TO_SOURCE, is_empty_metadata
|
|
|
|
from tests.conftest import mock_github
|
|
|
|
|
|
@pytest.fixture
|
|
def rule_creator(rspec_repo: RspecRepo):
|
|
return RuleCreator(rspec_repo)
|
|
|
|
|
|
def test_create_new_multi_lang_rule_branch(rule_creator: RuleCreator, mock_git_rspec_repo: Repo):
|
|
'''Test create_new_rule_branch for a multi-language rule.'''
|
|
rule_number = rule_creator.rspec_repo.reserve_rule_number()
|
|
|
|
languages = ['java', 'javascript']
|
|
branch = rule_creator.create_new_rule_branch(rule_number, languages)
|
|
|
|
# Check that the branch was pushed successfully to the origin
|
|
mock_git_rspec_repo.git.checkout(branch)
|
|
rule_dir = Path(mock_git_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
|
|
assert rule_dir.exists()
|
|
|
|
common_root = rule_creator.TEMPLATE_PATH.joinpath('multi_language', 'common')
|
|
for common_item in common_root.glob('**/*'):
|
|
if common_item.is_file():
|
|
expected_content = common_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
|
relative_path = common_item.relative_to(common_root)
|
|
actual_content = rule_dir.joinpath(relative_path).read_text()
|
|
assert actual_content == expected_content
|
|
|
|
lang_root = rule_creator.TEMPLATE_PATH.joinpath('multi_language', 'language_specific')
|
|
for lang in languages:
|
|
for lang_item in lang_root.glob('**/*'):
|
|
if lang_item.is_file():
|
|
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
|
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[os.path.basename(lang)]}')
|
|
relative_path = lang_item.relative_to(lang_root)
|
|
actual_content = rule_dir.joinpath(lang, relative_path).read_text()
|
|
assert actual_content == expected_content
|
|
if lang_item.suffix == '.adoc':
|
|
assert 'source,text' not in actual_content
|
|
assert LANG_TO_SOURCE[os.path.basename(lang)] in actual_content
|
|
|
|
|
|
def test_create_new_single_lang_rule_branch(rule_creator: RuleCreator, mock_git_rspec_repo: Repo):
|
|
'''Test create_new_rule_branch for a single-language rule.'''
|
|
rule_number = rule_creator.rspec_repo.reserve_rule_number()
|
|
|
|
languages = ['cfamily']
|
|
branch = rule_creator.create_new_rule_branch(rule_number, languages)
|
|
|
|
# Check that the branch was pushed successfully to the origin
|
|
mock_git_rspec_repo.git.checkout(branch)
|
|
rule_dir = Path(mock_git_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
|
|
assert rule_dir.exists()
|
|
|
|
common_root = rule_creator.TEMPLATE_PATH.joinpath('single_language', 'common')
|
|
for common_item in common_root.glob('**/*'):
|
|
if common_item.is_file():
|
|
expected_content = common_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
|
relative_path = common_item.relative_to(common_root)
|
|
actual_content = rule_dir.joinpath(relative_path).read_text()
|
|
assert actual_content == expected_content
|
|
|
|
lang_root = rule_creator.TEMPLATE_PATH.joinpath('single_language', 'language_specific')
|
|
for lang in languages:
|
|
for lang_item in lang_root.glob('**/*'):
|
|
if lang_item.is_file():
|
|
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
|
dir_name = os.path.basename(lang)
|
|
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[dir_name]}')
|
|
relative_path = lang_item.relative_to(lang_root)
|
|
actual_content = rule_dir.joinpath(lang, relative_path).read_text()
|
|
assert actual_content == expected_content
|
|
if lang_item.suffix == '.adoc':
|
|
assert 'source,text' not in actual_content
|
|
assert LANG_TO_SOURCE[dir_name] in actual_content
|
|
|
|
|
|
def test_create_new_rule_pull_request(rule_creator: RuleCreator):
|
|
'''Test create_new_rule_branch adds the right user and labels.'''
|
|
rule_number = rule_creator.rspec_repo.reserve_rule_number()
|
|
languages = ['cfamily']
|
|
|
|
with mock_github() as (token, user, mock_repo):
|
|
rule_creator.create_new_rule_pull_request(token, rule_number, languages, ['mylab', 'other-lab'], user)
|
|
|
|
mock_repo.create_pull.assert_called_once();
|
|
assert mock_repo.create_pull.call_args.kwargs['title'].startswith('Create rule S')
|
|
mock_repo.create_pull.return_value.add_to_assignees.assert_called_with(user);
|
|
mock_repo.create_pull.return_value.add_to_labels.assert_called_with('mylab', 'other-lab');
|
|
|
|
|
|
@patch('rspec_tools.create_rule.tmp_rspec_repo')
|
|
@patch('rspec_tools.create_rule.RuleCreator')
|
|
def test_create_new_rule(mockRuleCreator, mock_tmp_rspec_repo):
|
|
prMock = mockRuleCreator.return_value.create_new_rule_pull_request
|
|
create_new_rule('cfamily,php', 'my token', 'testuser')
|
|
prMock.assert_called_once()
|
|
assert set(prMock.call_args.args[2]) == set(['cfamily', 'php'])
|
|
assert set(prMock.call_args.args[3]) == set(['cfamily', 'php'])
|
|
|
|
|
|
@patch('rspec_tools.create_rule.RuleCreator')
|
|
def test_create_new_rule_unsupported_language(mockRuleCreator):
|
|
with pytest.raises(InvalidArgumentError):
|
|
create_new_rule('russian,php', 'my token', 'testuser')
|
|
|
|
|
|
def test_add_lang_singlelang_nonconventional_rule_create_branch(rule_creator: RuleCreator, mock_git_rspec_repo: Repo):
|
|
'''Test add_language_branch for a single-language rule with metadata lifted to the generic rule level.'''
|
|
rule_number = 4727
|
|
language = 'php'
|
|
|
|
mock_git_rspec_repo.git.checkout('master')
|
|
orig_rule_dir = Path(mock_git_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
|
|
assert(not is_empty_metadata(orig_rule_dir)) # nonconventional: singlelang rule with metadata on the upper level
|
|
assert(is_empty_metadata(orig_rule_dir.joinpath('cobol')))
|
|
original_metadata = orig_rule_dir.joinpath('metadata.json').read_text()
|
|
|
|
branch = rule_creator.add_language_branch(rule_number, language)
|
|
|
|
# Check that the branch was pushed successfully to the origin
|
|
mock_git_rspec_repo.git.checkout(branch)
|
|
rule_dir = Path(mock_git_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
|
|
assert rule_dir.exists()
|
|
lang_dir = rule_dir.joinpath(f'{language}')
|
|
assert lang_dir.exists()
|
|
|
|
assert rule_dir.joinpath('metadata.json').read_text() == original_metadata
|
|
assert(is_empty_metadata(rule_dir.joinpath('cobol')))
|
|
|
|
lang_root = rule_creator.TEMPLATE_PATH.joinpath('multi_language', 'language_specific')
|
|
for lang_item in lang_root.glob('**/*'):
|
|
if lang_item.is_file():
|
|
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
|
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[language]}')
|
|
relative_path = lang_item.relative_to(lang_root)
|
|
actual_content = rule_dir.joinpath(language, relative_path).read_text()
|
|
assert actual_content == expected_content
|
|
if lang_item.suffix == '.adoc':
|
|
assert 'source,text' not in actual_content
|
|
assert LANG_TO_SOURCE[language] in actual_content
|
|
|
|
|
|
def test_add_lang_singlelang_conventional_rule_create_branch(rule_creator: RuleCreator, mock_git_rspec_repo: Repo):
|
|
'''Test add_language_branch for a regular single language rule.'''
|
|
rule_number = 1033
|
|
language = 'php'
|
|
|
|
mock_git_rspec_repo.git.checkout('master')
|
|
orig_rule_dir = Path(mock_git_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
|
|
assert(is_empty_metadata(orig_rule_dir)) # conventional: singlelang rule with metadata on the lang-specific level
|
|
assert(not is_empty_metadata(orig_rule_dir.joinpath('cfamily')))
|
|
original_lmetadata = orig_rule_dir.joinpath('cfamily', 'metadata.json').read_text()
|
|
|
|
branch = rule_creator.add_language_branch(rule_number, language)
|
|
|
|
# Check that the branch was pushed successfully to the origin
|
|
mock_git_rspec_repo.git.checkout(branch)
|
|
rule_dir = Path(mock_git_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
|
|
assert rule_dir.exists()
|
|
lang_dir = rule_dir.joinpath(f'{language}')
|
|
assert lang_dir.exists()
|
|
|
|
assert rule_dir.joinpath('metadata.json').read_text() == original_lmetadata
|
|
assert(is_empty_metadata(rule_dir.joinpath('cfamily')))
|
|
|
|
|
|
def test_add_lang_multilang_rule_create_branch(rule_creator: RuleCreator, mock_git_rspec_repo: Repo):
|
|
'''Test add_language_branch for a multi-language rule.'''
|
|
rule_number = 120
|
|
language = 'php'
|
|
|
|
branch = rule_creator.add_language_branch(rule_number, language)
|
|
|
|
# Check that the branch was pushed successfully to the origin
|
|
mock_git_rspec_repo.git.checkout(branch)
|
|
rule_dir = Path(mock_git_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
|
|
assert rule_dir.exists()
|
|
lang_dir = rule_dir.joinpath(f'{language}')
|
|
assert lang_dir.exists()
|
|
|
|
lang_root = rule_creator.TEMPLATE_PATH.joinpath('multi_language', 'language_specific')
|
|
for lang_item in lang_root.glob('**/*'):
|
|
if lang_item.is_file():
|
|
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
|
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[language]}')
|
|
relative_path = lang_item.relative_to(lang_root)
|
|
actual_content = rule_dir.joinpath(language, relative_path).read_text()
|
|
assert actual_content == expected_content
|
|
if lang_item.suffix == '.adoc':
|
|
assert 'source,text' not in actual_content
|
|
assert LANG_TO_SOURCE[language] in actual_content
|
|
|
|
|
|
@patch('rspec_tools.create_rule.RuleCreator')
|
|
def test_add_unsupported_language(mock):
|
|
'''Test language validation.'''
|
|
with pytest.raises(InvalidArgumentError):
|
|
add_language_to_rule('russian', 'S1033', 'my token', 'testuser')
|
|
mock.return_value.add_language_pull_request.assert_not_called()
|
|
|
|
|
|
@patch('rspec_tools.create_rule.tmp_rspec_repo')
|
|
@patch('rspec_tools.create_rule.RuleCreator')
|
|
def test_add_supported_language(mock, mock_tmp_rspec_repo):
|
|
'''Test language validation.'''
|
|
add_language_to_rule('cfamily', 'S1033', 'my token', 'testuser')
|
|
mock.return_value.add_language_pull_request.assert_called_once()
|
|
|
|
|
|
def test_add_language_the_rule_is_already_defined_for(rule_creator: RuleCreator):
|
|
'''Test add_language_branch fails when trying to add a langage already added to the rule.'''
|
|
with pytest.raises(InvalidArgumentError):
|
|
rule_creator.add_language_branch(100, 'cfamily')
|
|
|
|
|
|
def test_add_language_to_nonexistent_rule(rule_creator: RuleCreator):
|
|
'''Test add_language_branch correctly fails when invoked for a non-existent rule.'''
|
|
with pytest.raises(InvalidArgumentError):
|
|
rule_creator.add_language_branch(105, 'cfamily')
|
|
|
|
|
|
def test_add_language_new_pull_request(rule_creator: RuleCreator):
|
|
'''Test add_language_pull_request adds the right user and labels.'''
|
|
rule_number = 120
|
|
language = 'php'
|
|
|
|
with mock_github() as (token, user, mock_repo):
|
|
rule_creator.add_language_pull_request(token, rule_number, language, 'mylab', user)
|
|
|
|
mock_repo.create_pull.assert_called_once();
|
|
assert mock_repo.create_pull.call_args.kwargs['title'].startswith(f'Create rule S{rule_number}')
|
|
assert mock_repo.create_pull.call_args.kwargs['head'].startswith('rule/')
|
|
mock_repo.create_pull.return_value.add_to_assignees.assert_called_with(user)
|
|
mock_repo.create_pull.return_value.add_to_labels.assert_called_with('mylab')
|