rspec/rspec-tools/tests/test_create_rule.py
2021-02-18 11:32:08 +01:00

108 lines
4.1 KiB
Python

from git import Repo, Head
from pathlib import Path
import pytest
from rspec_tools.create_rule import RuleCreator
@pytest.fixture
def git_config():
'''Create a mock git configuration.'''
return {
'user.name': 'testuser',
'user.email': 'testuser@mock.mock'
}
@pytest.fixture
def mock_rspec_repo(tmpdir):
repo_dir = tmpdir.mkdir("mock_rspec")
repo = Repo.init(str(repo_dir))
repo.init()
with repo.config_writer() as config_writer:
config_writer.set_value('user', 'name', 'originuser')
config_writer.set_value('user', 'email', 'originuser@mock.mock')
rules_dir = repo_dir.mkdir('rules')
# create a file just to have a "rules" directory
gitignore = rules_dir.join('.gitignore')
gitignore.ensure()
repo.index.add([str(gitignore)])
repo.index.commit('init rules')
# Create the id counter branch. Note that it is an orphan branch.
repo.head.reference = Head(repo, f'refs/heads/{RuleCreator.ID_COUNTER_BRANCH}')
repo.git.reset('--hard')
counter_file = repo_dir.join(RuleCreator.ID_COUNTER_FILENAME)
counter_file.write('0')
repo.index.add([str(counter_file)])
commit = repo.index.commit('init counter', parent_commits=None)
# Checkout a specific commit so that the repo can be pushed to without
# making the index and work tree inconsistent.
repo.git.checkout(commit.hexsha)
return repo
@pytest.fixture
def rule_creator(tmpdir, mock_rspec_repo: Repo, git_config: dict[str, str]):
cloned_repo = tmpdir.mkdir("cloned_repo")
return RuleCreator(mock_rspec_repo.working_dir, str(cloned_repo), git_config)
def test_reserve_rule_number_simple(rule_creator: RuleCreator, mock_rspec_repo: Repo):
'''Test that RuleCreator.reserve_rule_id() increments the id and returns the old value.'''
assert rule_creator.reserve_rule_number() == 0
assert read_counter_file(mock_rspec_repo) == '1'
def test_reserve_rule_number_parallel_reservations(tmpdir, mock_rspec_repo: Repo, git_config):
'''Test that RuleCreator.reserve_rule_id() works when multiple reservations are done in parallel.'''
cloned_repo1 = tmpdir.mkdir("cloned_repo1")
rule_creator1 = RuleCreator(mock_rspec_repo.working_dir, str(cloned_repo1), git_config)
cloned_repo2 = tmpdir.mkdir("cloned_repo2")
rule_creator2 = RuleCreator(mock_rspec_repo.working_dir, str(cloned_repo2), git_config)
assert rule_creator1.reserve_rule_number() == 0
assert rule_creator2.reserve_rule_number() == 1
assert rule_creator1.reserve_rule_number() == 2
assert read_counter_file(mock_rspec_repo) == '3'
def read_counter_file(repo):
'''Reads the counter file from the provided repository and returns its content.'''
repo.git.checkout(RuleCreator.ID_COUNTER_BRANCH)
counter_path = Path(repo.working_dir).joinpath(RuleCreator.ID_COUNTER_FILENAME)
return counter_path.read_text()
def test_create_new_rule_branch(rule_creator: RuleCreator, mock_rspec_repo: Repo):
'''Test create_new_rule_branch.'''
rule_number = rule_creator.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_rspec_repo.git.checkout(branch)
rule_dir = Path(mock_rspec_repo.working_dir).joinpath('rules', f'S{rule_number}')
assert rule_dir.exists()
common_root = rule_creator.TEMPLATE_PATH.joinpath('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('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))
relative_path = lang_item.relative_to(lang_root)
actual_content = rule_dir.joinpath(lang, relative_path).read_text()
assert actual_content == expected_content