# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from pathlib
import Path
from unittest
import mock
from unittest.mock
import Mock, patch
import pytest
from mozbuild.base
import MachCommandBase
from mozunit
import main
import mach.decorators
import mach.registrar
from mach.base
import MachError
from mach.decorators
import Command, CommandArgument, SubCommand
from mach.requirements
import MachEnvRequirements
from mach.site
import CommandSiteManager, MozSiteMetadata, SitePackagesSource
@pytest.fixture
def registrar(monkeypatch):
test_registrar = mach.registrar.MachRegistrar()
test_registrar.register_category(
"testing",
"Mach unittest",
"Testing for mach decorators"
)
monkeypatch.setattr(mach.decorators,
"Registrar", test_registrar)
return test_registrar
def test_register_command_with_argument(registrar):
inner_function = Mock()
context = Mock()
context.cwd =
"."
@Command(
"cmd_foo", category=
"testing")
@CommandArgument(
"--arg", default=
None, help=
"Argument help.")
def run_foo(command_context, arg):
inner_function(arg)
registrar.dispatch(
"cmd_foo", context, arg=
"argument")
inner_function.assert_called_with(
"argument")
def test_register_command_with_metrics_path(registrar):
context = Mock()
context.cwd =
"."
metrics_path =
"metrics/path"
metrics_mock = Mock()
context.telemetry.metrics.return_value = metrics_mock
@Command(
"cmd_foo", category=
"testing", metrics_path=metrics_path)
def run_foo(command_context):
assert command_context.metrics == metrics_mock
@SubCommand(
"cmd_foo",
"sub_foo", metrics_path=metrics_path +
"2")
def run_subfoo(command_context):
assert command_context.metrics == metrics_mock
registrar.dispatch(
"cmd_foo", context)
context.telemetry.metrics.assert_called_with(metrics_path)
assert context.handler.metrics_path == metrics_path
registrar.dispatch(
"cmd_foo", context, subcommand=
"sub_foo")
assert context.handler.metrics_path == metrics_path +
"2"
def test_register_command_sets_up_class_at_runtime(registrar):
inner_function = Mock()
context = Mock()
context.cwd =
"."
# We test that the virtualenv is set up properly dynamically on
# the instance that actually runs the command.
@Command(
"cmd_foo", category=
"testing", virtualenv_name=
"env_foo")
def run_foo(command_context):
assert (
Path(command_context.virtualenv_manager.virtualenv_root).name ==
"env_foo"
)
inner_function(
"foo")
@Command(
"cmd_bar", category=
"testing", virtualenv_name=
"env_bar")
def run_bar(command_context):
assert (
Path(command_context.virtualenv_manager.virtualenv_root).name ==
"env_bar"
)
inner_function(
"bar")
def from_environment_patch(
topsrcdir: str, state_dir: str, virtualenv_name, directory: str
):
return CommandSiteManager(
"",
"",
virtualenv_name,
virtualenv_name,
MozSiteMetadata(0,
"mach", SitePackagesSource.VENV,
"",
""),
True,
MachEnvRequirements(),
)
with mock.patch.object(
CommandSiteManager,
"from_environment", from_environment_patch
):
with patch.object(MachCommandBase,
"activate_virtualenv"):
registrar.dispatch(
"cmd_foo", context)
inner_function.assert_called_with(
"foo")
registrar.dispatch(
"cmd_bar", context)
inner_function.assert_called_with(
"bar")
def test_cannot_create_command_nonexisting_category(registrar):
with pytest.raises(MachError):
@Command(
"cmd_foo", category=
"bar")
def run_foo(command_context):
pass
def test_subcommand_requires_parent_to_exist(registrar):
with pytest.raises(MachError):
@SubCommand(
"sub_foo",
"foo")
def run_foo(command_context):
pass
if __name__ ==
"__main__":
main()