mirror of https://github.com/pypa/hatch.git
1194 lines
42 KiB
Python
1194 lines
42 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
from hatch.config.constants import ConfigEnvVars
|
|
from hatch.env.utils import get_env_var
|
|
from hatch.project.core import Project
|
|
from hatch.utils.structures import EnvVars
|
|
|
|
|
|
@pytest.fixture(scope='module', autouse=True)
|
|
def _terminal_width():
|
|
with EnvVars({'COLUMNS': '100'}, exclude=[get_env_var(plugin_name='virtual', option='uv_path')]):
|
|
yield
|
|
|
|
|
|
class TestDefaults:
|
|
def test_basic(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_arguments(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--', '--flag', '--', 'arg1', 'arg2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly --flag -- arg1 arg2', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestArguments:
|
|
def test_default_args(self, hatch, temp_dir, platform, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {'hatch-test': {'default-args': ['tests1', 'foo bar', 'tests2']}}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
escape_char = '"' if platform.windows else "'"
|
|
assert env_run.call_args_list == [
|
|
mocker.call(f'pytest -p no:randomly tests1 {escape_char}foo bar{escape_char} tests2', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_args_override(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {'hatch-test': {'default-args': ['tests1', 'foo bar', 'tests2']}}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--', '--flag', '--', 'arg1', 'arg2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly --flag -- arg1 arg2', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_extra_args(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {'hatch-test': {'extra-args': ['-vv', '--print']}}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -vv --print -p no:randomly tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestCoverage:
|
|
def test_flag(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--cover')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('coverage run -m pytest -p no:randomly tests', shell=True),
|
|
mocker.call('coverage combine', shell=True),
|
|
mocker.call('coverage report', shell=True),
|
|
]
|
|
|
|
root_config_path = data_path / '.config' / 'coverage'
|
|
config_dir = next(root_config_path.iterdir())
|
|
coverage_config_file = next(config_dir.iterdir())
|
|
|
|
assert coverage_config_file.read_text().strip().splitlines()[-2:] == [
|
|
'[tool.coverage.run]',
|
|
'parallel = true',
|
|
]
|
|
|
|
def test_flag_with_arguments(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--cover', '--', '--flag', '--', 'arg1', 'arg2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('coverage run -m pytest -p no:randomly --flag -- arg1 arg2', shell=True),
|
|
mocker.call('coverage combine', shell=True),
|
|
mocker.call('coverage report', shell=True),
|
|
]
|
|
|
|
root_config_path = data_path / '.config' / 'coverage'
|
|
config_dir = next(root_config_path.iterdir())
|
|
coverage_config_file = next(config_dir.iterdir())
|
|
|
|
assert coverage_config_file.read_text().strip().splitlines()[-2:] == [
|
|
'[tool.coverage.run]',
|
|
'parallel = true',
|
|
]
|
|
|
|
def test_quiet_implicitly_enables(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--cover-quiet')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('coverage run -m pytest -p no:randomly tests', shell=True),
|
|
mocker.call('coverage combine', shell=True),
|
|
]
|
|
|
|
root_config_path = data_path / '.config' / 'coverage'
|
|
config_dir = next(root_config_path.iterdir())
|
|
coverage_config_file = next(config_dir.iterdir())
|
|
|
|
assert coverage_config_file.read_text().strip().splitlines()[-2:] == [
|
|
'[tool.coverage.run]',
|
|
'parallel = true',
|
|
]
|
|
|
|
def test_legacy_config_define_section(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
(project_path / '.coveragerc').touch()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--cover')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('coverage run -m pytest -p no:randomly tests', shell=True),
|
|
mocker.call('coverage combine', shell=True),
|
|
mocker.call('coverage report', shell=True),
|
|
]
|
|
|
|
root_config_path = data_path / '.config' / 'coverage'
|
|
config_dir = next(root_config_path.iterdir())
|
|
coverage_config_file = next(config_dir.iterdir())
|
|
|
|
assert coverage_config_file.read_text().strip().splitlines() == [
|
|
'[run]',
|
|
'parallel = true',
|
|
]
|
|
|
|
def test_legacy_config_enable_parallel(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
(project_path / '.coveragerc').write_text('[run]\nparallel = false\nbranch = true\n')
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--cover')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('coverage run -m pytest -p no:randomly tests', shell=True),
|
|
mocker.call('coverage combine', shell=True),
|
|
mocker.call('coverage report', shell=True),
|
|
]
|
|
|
|
root_config_path = data_path / '.config' / 'coverage'
|
|
config_dir = next(root_config_path.iterdir())
|
|
coverage_config_file = next(config_dir.iterdir())
|
|
|
|
assert coverage_config_file.read_text().strip().splitlines() == [
|
|
'[run]',
|
|
'parallel = true',
|
|
'branch = true',
|
|
]
|
|
|
|
|
|
class TestRandomize:
|
|
def test_flag(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--randomize')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_flag_with_arguments(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--randomize', '--', '--flag', '--', 'arg1', 'arg2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest --flag -- arg1 arg2', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_config(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {'hatch-test': {'randomize': True}}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestParallel:
|
|
def test_flag(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--parallel')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -n logical tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_flag_with_arguments(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--parallel', '--', '--flag', '--', 'arg1', 'arg2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -n logical --flag -- arg1 arg2', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_config(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {'hatch-test': {'parallel': True}}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -n logical tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestRetries:
|
|
def test_flag(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--retries', '2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -r aR --reruns 2 tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_flag_with_arguments(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--retries', '2', '--', '--flag', '--', 'arg1', 'arg2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -r aR --reruns 2 --flag -- arg1 arg2', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_config(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {'hatch-test': {'retries': 2}}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -r aR --reruns 2 tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestRetryDelay:
|
|
@pytest.mark.usefixtures('env_run')
|
|
def test_no_retries(self, hatch, temp_dir, config_file):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--retry-delay', '3.14')
|
|
|
|
assert result.exit_code == 1, result.output
|
|
assert result.output == 'The --retry-delay option requires the --retries option to be set as well.\n'
|
|
|
|
def test_flag(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--retries', '2', '--retry-delay', '3.14')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -r aR --reruns 2 --reruns-delay 3.14 tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_flag_with_arguments(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--retries', '2', '--retry-delay', '3.14', '--', '--flag', '--', 'arg1', 'arg2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -r aR --reruns 2 --reruns-delay 3.14 --flag -- arg1 arg2', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_config(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {'hatch-test': {'retry-delay': 1.23}}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--retries', '2')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('pytest -p no:randomly -r aR --reruns 2 --reruns-delay 1.23 tests', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestCustomScripts:
|
|
def test_basic(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'scripts': {
|
|
'run': 'test',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('test', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_coverage(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'scripts': {
|
|
'run': 'test',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--cover')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('test with coverage', shell=True),
|
|
mocker.call('combine coverage', shell=True),
|
|
mocker.call('show coverage', shell=True),
|
|
]
|
|
|
|
root_config_path = data_path / '.config' / 'coverage'
|
|
config_dir = next(root_config_path.iterdir())
|
|
coverage_config_file = next(config_dir.iterdir())
|
|
|
|
assert coverage_config_file.read_text().strip().splitlines()[-2:] == [
|
|
'[tool.coverage.run]',
|
|
'parallel = true',
|
|
]
|
|
|
|
def test_single(self, hatch, temp_dir, config_file, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'scripts': {
|
|
'run': 'test {env_name}',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert not result.output
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call(f'test hatch-test.py{".".join(map(str, sys.version_info[:2]))}', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_matrix(self, hatch, temp_dir, config_file, helpers, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'matrix': [{'python': ['3.12', '3.10', '3.8']}],
|
|
'scripts': {
|
|
'run': 'test {env_name}',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--all')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert result.output == helpers.dedent(
|
|
"""
|
|
──────────────────────────────────────── hatch-test.py3.12 ─────────────────────────────────────────
|
|
──────────────────────────────────────── hatch-test.py3.10 ─────────────────────────────────────────
|
|
───────────────────────────────────────── hatch-test.py3.8 ─────────────────────────────────────────
|
|
"""
|
|
)
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('test hatch-test.py3.12', shell=True),
|
|
mocker.call('test hatch-test.py3.10', shell=True),
|
|
mocker.call('test hatch-test.py3.8', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestFilters:
|
|
@pytest.mark.usefixtures('env_run')
|
|
@pytest.mark.parametrize('option', ['--include', '--exclude'])
|
|
def test_usage_with_all(self, hatch, temp_dir, config_file, helpers, option):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--all', option, 'py=3.10')
|
|
|
|
assert result.exit_code == 1, result.output
|
|
assert result.output == helpers.dedent(
|
|
"""
|
|
The --all option cannot be used with the --include or --exclude options.
|
|
"""
|
|
)
|
|
|
|
def test_include(self, hatch, temp_dir, config_file, helpers, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'matrix': [{'python': ['3.12', '3.10', '3.8']}],
|
|
'scripts': {
|
|
'run': 'test {env_name}',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '-i', 'py=3.10')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert result.output == helpers.dedent(
|
|
"""
|
|
──────────────────────────────────────── hatch-test.py3.10 ─────────────────────────────────────────
|
|
"""
|
|
)
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('test hatch-test.py3.10', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_exclude(self, hatch, temp_dir, config_file, helpers, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'matrix': [{'python': ['3.12', '3.10', '3.8']}],
|
|
'scripts': {
|
|
'run': 'test {env_name}',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '-x', 'py=3.10')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert result.output == helpers.dedent(
|
|
"""
|
|
──────────────────────────────────────── hatch-test.py3.12 ─────────────────────────────────────────
|
|
───────────────────────────────────────── hatch-test.py3.8 ─────────────────────────────────────────
|
|
"""
|
|
)
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('test hatch-test.py3.12', shell=True),
|
|
mocker.call('test hatch-test.py3.8', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
def test_python(self, hatch, temp_dir, config_file, helpers, env_run, mocker):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'matrix': [{'python': ['3.12', '3.10', '3.8']}],
|
|
'scripts': {
|
|
'run': 'test {env_name}',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '-py', '3.10')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert result.output == helpers.dedent(
|
|
"""
|
|
──────────────────────────────────────── hatch-test.py3.10 ─────────────────────────────────────────
|
|
"""
|
|
)
|
|
|
|
assert env_run.call_args_list == [
|
|
mocker.call('test hatch-test.py3.10', shell=True),
|
|
]
|
|
|
|
assert not (data_path / '.config' / 'coverage').exists()
|
|
|
|
|
|
class TestShow:
|
|
def test_default_compact(self, hatch, temp_dir, config_file, helpers):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'matrix': [{'python': ['3.12', '3.10', '3.8']}],
|
|
'dependencies': ['foo', 'bar'],
|
|
'scripts': {
|
|
'run': 'test {env_name}',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('test', '--show')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
|
|
"""
|
|
+------------+---------+-------------------+--------------+-------------+
|
|
| Name | Type | Envs | Dependencies | Scripts |
|
|
+============+=========+===================+==============+=============+
|
|
| hatch-test | virtual | hatch-test.py3.12 | bar | cov-combine |
|
|
| | | hatch-test.py3.10 | foo | cov-report |
|
|
| | | hatch-test.py3.8 | | run |
|
|
| | | | | run-cov |
|
|
+------------+---------+-------------------+--------------+-------------+
|
|
"""
|
|
)
|
|
|
|
def test_verbose(self, hatch, temp_dir, config_file, helpers):
|
|
config_file.model.template.plugins['default']['tests'] = False
|
|
config_file.save()
|
|
|
|
project_name = 'My.App'
|
|
|
|
with temp_dir.as_cwd():
|
|
result = hatch('new', project_name)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
|
|
project_path = temp_dir / 'my-app'
|
|
data_path = temp_dir / 'data'
|
|
data_path.mkdir()
|
|
|
|
project = Project(project_path)
|
|
config = dict(project.raw_config)
|
|
config['tool']['hatch']['envs'] = {
|
|
'hatch-test': {
|
|
'matrix': [{'python': ['3.12', '3.10', '3.8']}],
|
|
'dependencies': ['foo', 'bar'],
|
|
'scripts': {
|
|
'run': 'test {env_name}',
|
|
'run-cov': 'test with coverage',
|
|
'cov-combine': 'combine coverage',
|
|
'cov-report': 'show coverage',
|
|
},
|
|
'overrides': {'matrix': {'python': {'description': {'value': 'test 3.10', 'if': ['3.10']}}}},
|
|
}
|
|
}
|
|
project.save_config(config)
|
|
|
|
with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
|
|
result = hatch('-v', 'test', '--show')
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
|
|
"""
|
|
+-------------------+---------+--------------+-------------+-------------+
|
|
| Name | Type | Dependencies | Scripts | Description |
|
|
+===================+=========+==============+=============+=============+
|
|
| hatch-test.py3.12 | virtual | bar | cov-combine | |
|
|
| | | foo | cov-report | |
|
|
| | | | run | |
|
|
| | | | run-cov | |
|
|
+-------------------+---------+--------------+-------------+-------------+
|
|
| hatch-test.py3.10 | virtual | bar | cov-combine | test 3.10 |
|
|
| | | foo | cov-report | |
|
|
| | | | run | |
|
|
| | | | run-cov | |
|
|
+-------------------+---------+--------------+-------------+-------------+
|
|
| hatch-test.py3.8 | virtual | bar | cov-combine | |
|
|
| | | foo | cov-report | |
|
|
| | | | run | |
|
|
| | | | run-cov | |
|
|
+-------------------+---------+--------------+-------------+-------------+
|
|
"""
|
|
)
|