text: from unittest.mock import Mock, patch
  
  import click
  import pytest
  
  from cumulusci.cli.runtime import CliRuntime
  from cumulusci.core.config import BaseProjectConfig
  from cumulusci.core.exceptions import CumulusCIUsageError
  
  from .. import task
  from .utils import DummyTask, run_click_command
  
  color_opts = {"options": {"color": {}}}
  multiple_opts = {"options": {"foo": {}, "bar": {}, "baz": {}}}
  
  test_tasks = {
      "dummy-task": {
          "class_path": "cumulusci.cli.tests.utils.DummyTask",
          "description": "This is a dummy task.",
      },
      "dummy-derived-task": {
          "class_path": "cumulusci.cli.tests.test_run_task.DummyDerivedTask"
      },
  }
  
  
  @pytest.fixture
  def runtime():
      runtime = CliRuntime(load_keychain=False)
      runtime.project_config.config["tasks"] = {**test_tasks}
  
      runtime.keychain = Mock()
      runtime.keychain.get_default_org.return_value = (None, None)
      runtime._load_keychain = Mock()
  
      yield runtime
  
  
  def test_task_run(runtime):
      DummyTask._run_task = Mock()
      multi_cmd = task.RunTaskCommand()
      with click.Context(multi_cmd, obj=runtime) as ctx:
          cmd = multi_cmd.get_command(ctx, "dummy-task")
          cmd.callback(runtime, "dummy-task", color="blue")
  
      DummyTask._run_task.assert_called_once()
  
  
  def test_task_run__no_project(runtime):
      runtime.project_config = None
      runtime.project_config_error = Exception("Broken")
      multi_cmd = task.RunTaskCommand()
      with pytest.raises(Exception, match="Broken"):
          with click.Context(multi_cmd, obj=runtime) as ctx:
              multi_cmd.get_command(ctx, "dummy-task")
  
  
  def test_task_run__debug_before(runtime):
      DummyTask._run_task = Mock()
      multi_cmd = task.RunTaskCommand()
      set_trace = Mock(side_effect=SetTrace)
  
      with click.Context(multi_cmd, obj=runtime) as ctx:
          with patch("pdb.set_trace", set_trace):
              with pytest.raises(SetTrace):
                  cmd = multi_cmd.get_command(ctx, "dummy-task")
                  cmd.callback(
                      runtime,
                      "dummy_task",
                      color="blue",
                      debug_before=True,
                      debug_after=False,
                  )
  
  
  def test_task_run__debug_after(runtime):
      DummyTask._run_task = Mock()
      multi_cmd = task.RunTaskCommand()
      set_trace = Mock(side_effect=SetTrace)
  
      with click.Context(multi_cmd, obj=runtime) as ctx:
          with patch("pdb.set_trace", set_trace):
              with pytest.raises(SetTrace):
                  cmd = multi_cmd.get_command(ctx, "dummy-task")
                  cmd.callback(
                      runtime,
                      "dummy-task",
                      color="blue",
                      debug_before=False,
                      debug_after=True,
                  )
  
  
  def test_task_run__help(runtime):
      DummyTask._run_task = Mock()
      multi_cmd = task.RunTaskCommand()
      with click.Context(multi_cmd, obj=runtime) as ctx:
          cmd = multi_cmd.get_command(ctx, "dummy-task")
  
      assert "This is a dummy task." in cmd.help  # task description
  
  
  def test_task_run__list_commands(runtime):
      multi_cmd = task.RunTaskCommand()
      with click.Context(multi_cmd, obj=runtime) as ctx:
          commands = multi_cmd.list_commands(ctx)
      assert commands == ["dummy-derived-task", "dummy-task"]
  
  
  def test_format_help(runtime):
      with patch("click.echo") as echo:
          runtime.universal_config = Mock()
          multi_cmd = task.RunTaskCommand()
          with click.Context(multi_cmd, obj=runtime) as ctx:
              multi_cmd.format_help(ctx, Mock())
          assert 4 == echo.call_count
  
          assert 0 == len(runtime.universal_config.method_calls)
  
  
  def test_get_default_command_options():
      opts = task.RunTaskCommand()._get_default_command_options(is_salesforce_task=False)
      assert len(opts) == 4
  
      opts = task.RunTaskCommand()._get_default_command_options(is_salesforce_task=True)
      assert len(opts) == 5
      assert any([o.name == "org" for o in opts])
  
  
  def test_collect_task_options():
      new_options = {"debug-before": None}
      old_options = (("color", "green"),)
  
      opts = task.RunTaskCommand()._collect_task_options(
          new_options, old_options, "dummy-task", color_opts["options"]
      )
      assert opts == {"color": "green"}
  
  
  def test_collect_task_options__duplicate():
      new_options = {"color": "aqua"}
      old_options = (("color", "green"),)
  
      with pytest.raises(CumulusCIUsageError):
          task.RunTaskCommand()._collect_task_options(
              new_options, old_options, "dummy-task", color_opts["options"]
          )
  
  
  def test_collect_task_options__not_in_task():
      new_options = {}
      old_options = (("color", "green"),)
  
      with pytest.raises(CumulusCIUsageError):
          task.RunTaskCommand()._collect_task_options(
              new_options, old_options, "dummy-task", {"not-color": {}}
          )
  
  
  @patch("cumulusci.cli.task.CliTable")
  def test_task_list(cli_tbl):
      runtime = Mock()
      runtime.universal_config.cli__plain_output = None
      runtime.get_available_tasks.return_value = [
          {"name": "test_task", "description": "Test Task", "group": "Test Group"}
      ]
  
      run_click_command(task.task_list, runtime=runtime, plain=False, print_json=False)
  
      cli_tbl.assert_called_with(
          [["Task", "Description"], ["test_task", "Test Task"]],
          "Test Group",
          wrap_cols=["Description"],
      )
  
  
  @patch("json.dumps")
  def test_task_list_json(json_):
      task_dicts = {
          "name": "test_task",
          "description": "Test Task",
          "group": "Test Group",
      }
      runtime = Mock()
      runtime.universal_config.cli__plain_output = None
      runtime.get_available_tasks.return_value = [task_dicts]
  
      run_click_command(task.task_list, runtime=runtime, plain=False, print_json=True)
  
      json_.assert_called_with([task_dicts])
  
  
  @patch("cumulusci.cli.task.doc_task", return_value="docs")
  def test_task_doc(doc_task):
      runtime = Mock()
      runtime.universal_config.tasks = {"test": {}}
      run_click_command(task.task_doc, runtime=runtime, project=False)
      doc_task.assert_called()
  
  
  def test_task_doc__project__outside_project():
      runtime = Mock()
      runtime.project_config = None
      with pytest.raises(click.UsageError):
          run_click_command(task.task_doc, runtime=runtime, project=True)
  
  
  @patch("click.echo")
  @patch("cumulusci.cli.task.doc_task", return_value="docs")
  def test_task_doc_project(doc_task, echo):
      runtime = Mock()
      runtime.universal_config = {"tasks": {}}
      runtime.project_config = BaseProjectConfig(
          runtime.universal_config,
          {
              "project": {"name": "Test"},
              "tasks": {"task1": {"a": "b"}, "task2": {}},
          },
      )
      runtime.project_config.config_project = {"tasks": {"task1": {"a": "b"}}}
      run_click_command(task.task_doc, runtime=runtime, project=True)
      doc_task.assert_called()
      echo.assert_called()
  
  
  @patch("cumulusci.cli.task.Path")
  @patch("click.echo")
  @patch("cumulusci.cli.task.doc_task", return_value="docs")
  def test_task_doc_project_write(doc_task, echo, Path):
      runtime = Mock()
      runtime.universal_config.tasks = {"test": {}}
      runtime.project_config = BaseProjectConfig(
          runtime.universal_config,
          {
              "project": {"name": "Test"},
              "tasks": {"option": {"a": "b"}},
          },
      )
      runtime.project_config.config_project = {"tasks": {"option": {"a": "b"}}}
      run_click_command(task.task_doc, runtime=runtime, project=True, write=True)
      doc_task.assert_called()
      echo.assert_not_called()
  
  
  @patch("cumulusci.cli.task.rst2ansi")
  @patch("cumulusci.cli.task.doc_task")
  def test_task_info(doc_task, rst2ansi):
      runtime = Mock()
      runtime.project_config.tasks__test = {"options": {}}
      run_click_command(task.task_info, runtime=runtime, task_name="test")
      doc_task.assert_called_once()
      rst2ansi.assert_called_once()
  
  
  class SetTrace(Exception):
      pass
  
  
  class DummyDerivedTask(DummyTask):
      def _run_task(self):
          click.echo(f"<{self.__class__}>\n\tcolor: {self.options['color']}")
  