Update docs for Mix.target to remove experimental (#10056)

defmodule Mix do
  @moduledoc ~S"""
  Mix is a build tool that provides tasks for creating, compiling,
  and testing Elixir projects, managing its dependencies, and more.

  ## Mix.Project

  The foundation of Mix is a project. A project can be defined by using
  `Mix.Project` in a module, usually placed in a file named `mix.exs`:

      defmodule MyApp.MixProject do
        use Mix.Project

        def project do
          [
            app: :my_app,
            version: "1.0.0"
          ]
        end
      end

  See the `Mix.Project` module for detailed documentation on Mix projects.

  Once the project is defined, a number of default Mix tasks can be run
  directly from the command line:

    * `mix compile` - compiles the current project
    * `mix test` - runs tests for the given project
    * `mix run` - runs a particular command inside the project

  Each task has its own options and sometimes specific configuration
  to be defined in the `project/0` function. You can use `mix help`
  to list all available tasks and `mix help NAME` to show help for
  a particular task.

  The best way to get started with your first project is by calling
  `mix new my_project` from the command line.

  ## Mix.Task

  Tasks are what make Mix extensible.

  Projects can extend Mix behaviour by adding their own tasks. For
  example, adding the task below inside your project will
  make it available to everyone that uses your project:

      defmodule Mix.Tasks.Hello do
        use Mix.Task

        def run(_) do
          Mix.shell().info("Hello world")
        end
      end

  The task can now be invoked with `mix hello`.

  See the `Mix.Task` behaviour for detailed documentation on Mix tasks.

  ## Dependencies

  Mix also manages your dependencies and integrates nicely with the [Hex package
  manager](https://hex.pm).

  In order to use dependencies, you need to add a `:deps` key
  to your project configuration. We often extract the list of dependencies
  into its own function:

      defmodule MyApp.MixProject do
        use Mix.Project

        def project do
          [
            app: :my_app,
            version: "1.0.0",
            deps: deps()
          ]
        end

        defp deps do
          [
            {:ecto, "~> 2.0"},
            {:plug, github: "elixir-lang/plug"}
          ]
        end
      end

  You can run `mix help deps` to learn more about dependencies in Mix.

  ## Environments

  Mix supports different environments. Environments allow developers
  to prepare and organize their project specifically for different
  scenarios. By default, Mix provides three environments:

    * `:dev` - the default environment
    * `:test` - the environment `mix test` runs on
    * `:prod` - the environment your dependencies run on

  The environment can be changed via the command line by setting
  the `MIX_ENV` environment variable, for example:

      $ MIX_ENV=prod mix run server.exs

  You can also specify that certain dependencies are available only for
  certain environments:

      {:some_test_dependency, "~> 1.0", only: :test}

  The environment can be read via `Mix.env/0`.

  ## Targets

  Besides environments, Mix supports targets. Targets are useful when a
  project needs to compile to different architectures and some of the
  dependencies are only available to some of them. By default, the target
  is `:host` but it can be set via the `MIX_TARGET` environment variable.
  The target can be read via `Mix.target/0`.

  ## Aliases

  Aliases are shortcuts or tasks specific to the current project.

  In the "Mix.Task" section, we have defined a task that would be
  available to everyone using our project as a dependency. What if
  we wanted the task to only be available for our project? Just
  define an alias:

      defmodule MyApp.MixProject do
        use Mix.Project

        def project do
          [
            app: :my_app,
            version: "1.0.0",
            aliases: aliases()
          ]
        end

        defp aliases do
          [
            c: "compile",
            hello: &hello/1
          ]
        end

        defp hello(_) do
          Mix.shell().info("Hello world")
        end
      end

  In the example above, we have defined two aliases. One is `mix c`
  which is a shortcut for `mix compile`. The other is named
  `mix hello`, which is the equivalent to the `Mix.Tasks.Hello`
  we have defined in the "Mix.Task" section.

  Aliases may also be lists, specifying multiple tasks to be run
  consecutively:

      [all: [&hello/1, "deps.get --only #{Mix.env()}", "compile"]]

  In the example above, we have defined an alias named `mix all`,
  that prints "Hello world", then fetches dependencies specific
  to the current environment, and compiles the project.

  Aliases can also be used to augment existing tasks. Let's suppose
  you want to augment `mix clean` to clean another directory Mix does
  not know about:

      [clean: ["clean", &clean_extra/1]]

  Where `&clean_extra/1` would be a function in your `mix.exs`
  with extra cleanup logic.

  Arguments given to the alias will be appended to the arguments of
  the last task in the list. Except when overriding an existing task.
  In this case, the arguments will be given to the original task,
  in order to preserve semantics. For example, in the `:clean` alias
  above, the arguments given to the alias will be passed to "clean"
  and not to `clean_extra/1`.

  Aliases defined in the current project do not affect its dependencies
  and aliases defined in dependencies are not accessible from the
  current project.

  Aliases can be used very powerfully to also run Elixir scripts and
  shell commands, for example:

      # priv/hello1.exs
      IO.puts("Hello One")

      # priv/hello2.exs
      IO.puts("Hello Two")

      # priv/world.sh
      #!/bin/sh
      echo "world!"

      # mix.exs
      defp aliases do
        [
          some_alias: ["hex.info", "run priv/hello1.exs", "cmd priv/world.sh"]
        ]
      end

  In the example above we have created the alias `some_alias` that will
  run the task `mix hex.info`, then `mix run` to run an Elixir script,
  then `mix cmd` to execute a command line shell script. This shows how
  powerful aliases mixed with Mix tasks can be.

  Mix tasks are designed to run only once. This prevents the same task
  to be executed multiple times. For example, if there are several tasks
  depending on `mix compile`, the code will be compiled once. Tasks can
  be executed again if they are explicitly reenabled using `Mix.Task.reenable/1`:

      another_alias: [
        "format --check-formatted priv/hello1.exs",
        "cmd priv/world.sh",
        fn _ -> Mix.Task.reenable("format") end,
        "format --check-formatted priv/hello2.exs"
      ]

  Some tasks are automatically reenabled though, as they are expected to
  be invoked multiple times. They are: `mix cmd`, `mix do`, `mix loadconfig`,
  `mix profile.cprof`, `mix profile.eprof`, `mix profile.fprof`, `mix run`,
  and `mix xref`.

  It is worth mentioning that some tasks, such as in the case of the
  `mix format` command in the example above, can accept multiple files so it
  could be rewritten as:

      another_alias: ["format --check-formatted priv/hello1.exs priv/hello2.exs"]

  ## Environment variables

  Several environment variables can be used to modify Mix's behaviour.

  Mix responds to the following variables:

    * `MIX_ARCHIVES` - specifies the directory into which the archives should be installed
      (default: `~/.mix/archives`)
    * `MIX_BUILD_PATH` - sets the project `Mix.Project.build_path/0` config. This option
      must always point to a subdirectory inside a temporary directory. For instance,
      never "/tmp" or "_build" but "_build/PROD" or "/tmp/PROD", as required by Mix
    * `MIX_DEPS_PATH` - sets the project `Mix.Project.deps_path/0` config (default: `deps`)
    * `MIX_DEBUG` - outputs debug information about each task before running it
    * `MIX_ENV` - specifies which environment should be used. See [Environments](#module-environments)
    * `MIX_TARGET` - specifies which target should be used. See [Targets](#module-targets)
    * `MIX_EXS` - changes the full path to the `mix.exs` file
    * `MIX_HOME` - path to Mix's home directory, stores configuration files and scripts used by Mix
      (default: `~/.mix`)
    * `MIX_PATH` - appends extra code paths
    * `MIX_QUIET` - does not print information messages to the terminal
    * `MIX_REBAR` - path to rebar command that overrides the one Mix installs
      (default: `~/.mix/rebar`)
    * `MIX_REBAR3` - path to rebar3 command that overrides the one Mix installs
      (default: `~/.mix/rebar3`)
    * `MIX_XDG` - asks Mix to follow the [XDG Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
      for its home directory and configuration files. This behaviour needs to
      be opt-in due to backwards compatibility. `MIX_HOME` has higher preference
      than `MIX_XDG`. If none of the variables are set, the default directory
      `~/.mix` will be used

  Environment variables that are not meant to hold a value (and act basically as
  flags) should be set to either `1` or `true`, for example:

      $ MIX_DEBUG=1 mix compile

  """

  use Application

  @doc false
  def start do
    {:ok, _} = Application.ensure_all_started(:mix)
    :ok
  end

  @doc false
  def start(_type, []) do
    children = [Mix.State, Mix.TasksServer, Mix.ProjectStack]
    opts = [strategy: :one_for_one, name: Mix.Supervisor, max_restarts: 0]
    Supervisor.start_link(children, opts)
  end

  @doc """
  Returns the current Mix environment.

  This function should not be used at runtime in application code (as opposed
  to infrastructure and build code like Mix tasks). Mix is a build tool and may
  not be available after the code is compiled (for example in a release).

  To differentiate the program behavior depending on the environment, it is
  recommended to use application environment through `Application.get_env/3`.
  Proper configuration can be set in config files, often per-environment
  (see the `Config` module for more information).
  """
  @spec env() :: atom()
  def env do
    # env is not available on bootstrapping, so set a :dev default
    Mix.State.get(:env, :dev)
  end

  @doc """
  Changes the current Mix environment to `env`.

  Be careful when invoking this function as any project
  configuration won't be reloaded.

  This function should not be used at runtime in application code
  (see `env/0` for more information).
  """
  @spec env(atom()) :: :ok
  def env(env) when is_atom(env) do
    Mix.State.put(:env, env)
  end

  @doc """
  Returns the Mix target.
  """
  @spec target() :: atom()
  def target do
    # target is not available on bootstrapping, so set a :host default
    Mix.State.get(:target, :host)
  end

  @doc """
  Changes the current Mix target to `target`.

  Be careful when invoking this function as any project
  configuration won't be reloaded.
  """
  @spec target(atom()) :: :ok
  def target(target) when is_atom(target) do
    Mix.State.put(:target, target)
  end

  @doc """
  Returns the default compilers used by Mix.

  It can be used in your `mix.exs` to prepend or
  append new compilers to Mix:

      def project do
        [compilers: Mix.compilers() ++ [:foo, :bar]]
      end

  """
  @spec compilers() :: [atom()]
  def compilers do
    [:yecc, :leex, :erlang, :elixir, :app]
  end

  @doc """
  Returns the current shell.

  `shell/0` can be used as a wrapper for the current shell. It contains
  conveniences for requesting information from the user, printing to the
  shell and so forth. The Mix shell is swappable (see `shell/1`), allowing
  developers to use a test shell that simply sends messages to the current
  process instead of performing IO (see `Mix.Shell.Process`).

  By default, this returns `Mix.Shell.IO`.

  ## Examples

      Mix.shell().info("Preparing to do something dangerous...")

      if Mix.shell().yes?("Are you sure?") do
        # do something dangerous
      end

  """
  @spec shell() :: module
  def shell do
    Mix.State.get(:shell, Mix.Shell.IO)
  end

  @doc """
  Sets the current shell.

  As an argument you may pass `Mix.Shell.IO`, `Mix.Shell.Process`,
  `Mix.Shell.Quiet`, or any module that implements the `Mix.Shell`
  behaviour.

  After calling this function, `shell` becomes the shell that is
  returned by `shell/0`.

  ## Examples

      iex> Mix.shell(Mix.Shell.IO)
      :ok

  You can use `shell/0` and `shell/1` to temporarily switch shells,
  for example, if you want to run a Mix Task that normally produces
  a lot of output:

      shell = Mix.shell()
      Mix.shell(Mix.Shell.Quiet)

      try do
        Mix.Task.run("noisy.task")
      after
        Mix.shell(shell)
      end

  """
  @spec shell(module) :: :ok
  def shell(shell) do
    Mix.State.put(:shell, shell)
  end

  @doc """
  Returns `true` if Mix is in debug mode, `false` otherwise.
  """
  @spec debug?() :: boolean()
  def debug? do
    Mix.State.get(:debug, false)
  end

  @doc """
  Sets Mix debug mode.
  """
  @spec debug(boolean()) :: :ok
  def debug(debug) when is_boolean(debug) do
    Mix.State.put(:debug, debug)
  end

  @doc """
  Raises a Mix error that is nicely formatted.
  """
  @spec raise(binary) :: no_return
  def raise(message) when is_binary(message) do
    Kernel.raise(Mix.Error, mix: true, message: message)
  end

  @doc """
  The path for local archives or escripts.
  """
  @doc since: "1.10.0"
  @spec path_for(:archives | :escripts) :: String.t()
  def path_for(:archives) do
    System.get_env("MIX_ARCHIVES") || Path.join(Mix.Utils.mix_home(), "archives")
  end

  def path_for(:escripts) do
    Path.join(Mix.Utils.mix_home(), "escripts")
  end
end

defmodule Mix do
  @moduledoc ~S"""
  Mix is a build tool that provides tasks for creating, compiling,
  and testing Elixir projects, managing its dependencies, and more.

  ## Mix.Project

  The foundation of Mix is a project. A project can be defined by using
  `Mix.Project` in a module, usually placed in a file named `mix.exs`:

      defmodule MyApp.MixProject do
        use Mix.Project

        def project do
          [
            app: :my_app,
            version: "1.0.0"
          ]
        end
      end

  See the `Mix.Project` module for detailed documentation on Mix projects.

  Once the project is defined, a number of default Mix tasks can be run
  directly from the command line:

    * `mix compile` - compiles the current project
    * `mix test` - runs tests for the given project
    * `mix run` - runs a particular command inside the project

  Each task has its own options and sometimes specific configuration
  to be defined in the `project/0` function. You can use `mix help`
  to list all available tasks and `mix help NAME` to show help for
  a particular task.

  The best way to get started with your first project is by calling
  `mix new my_project` from the command line.

  ## Mix.Task

  Tasks are what make Mix extensible.

  Projects can extend Mix behaviour by adding their own tasks. For
  example, adding the task below inside your project will
  make it available to everyone that uses your project:

      defmodule Mix.Tasks.Hello do
        use Mix.Task

        def run(_) do
          Mix.shell().info("Hello world")
        end
      end

  The task can now be invoked with `mix hello`.

  See the `Mix.Task` behaviour for detailed documentation on Mix tasks.

  ## Dependencies

  Mix also manages your dependencies and integrates nicely with the [Hex package
  manager](https://hex.pm).

  In order to use dependencies, you need to add a `:deps` key
  to your project configuration. We often extract the list of dependencies
  into its own function:

      defmodule MyApp.MixProject do
        use Mix.Project

        def project do
          [
            app: :my_app,
            version: "1.0.0",
            deps: deps()
          ]
        end

        defp deps do
          [
            {:ecto, "~> 2.0"},
            {:plug, github: "elixir-lang/plug"}
          ]
        end
      end

  You can run `mix help deps` to learn more about dependencies in Mix.

  ## Environments

  Mix supports different environments. Environments allow developers
  to prepare and organize their project specifically for different
  scenarios. By default, Mix provides three environments:

    * `:dev` - the default environment
    * `:test` - the environment `mix test` runs on
    * `:prod` - the environment your dependencies run on

  The environment can be changed via the command line by setting
  the `MIX_ENV` environment variable, for example:

      $ MIX_ENV=prod mix run server.exs

  You can also specify that certain dependencies are available only for
  certain environments:

      {:some_test_dependency, "~> 1.0", only: :test}

  The environment can be read via `Mix.env/0`.

  ## Targets

  Besides environments, Mix supports targets. Targets are useful when a
  project needs to compile to different architectures and some of the
  dependencies are only available to some of them. By default, the target
  is `:host` but it can be set via the `MIX_TARGET` environment variable.
  The target can be read via `Mix.target/0`.

  This feature is considered experimental and may change in future releases.

  ## Aliases

  Aliases are shortcuts or tasks specific to the current project.

  In the "Mix.Task" section, we have defined a task that would be
  available to everyone using our project as a dependency. What if
  we wanted the task to only be available for our project? Just
  define an alias:

      defmodule MyApp.MixProject do
        use Mix.Project

        def project do
          [
            app: :my_app,
            version: "1.0.0",
            aliases: aliases()
          ]
        end

        defp aliases do
          [
            c: "compile",
            hello: &hello/1
          ]
        end

        defp hello(_) do
          Mix.shell().info("Hello world")
        end
      end

  In the example above, we have defined two aliases. One is `mix c`
  which is a shortcut for `mix compile`. The other is named
  `mix hello`, which is the equivalent to the `Mix.Tasks.Hello`
  we have defined in the "Mix.Task" section.

  Aliases may also be lists, specifying multiple tasks to be run
  consecutively:

      [all: [&hello/1, "deps.get --only #{Mix.env()}", "compile"]]

  In the example above, we have defined an alias named `mix all`,
  that prints "Hello world", then fetches dependencies specific
  to the current environment, and compiles the project.

  Aliases can also be used to augment existing tasks. Let's suppose
  you want to augment `mix clean` to clean another directory Mix does
  not know about:

      [clean: ["clean", &clean_extra/1]]

  Where `&clean_extra/1` would be a function in your `mix.exs`
  with extra cleanup logic.

  Arguments given to the alias will be appended to the arguments of
  the last task in the list. Except when overriding an existing task.
  In this case, the arguments will be given to the original task,
  in order to preserve semantics. For example, in the `:clean` alias
  above, the arguments given to the alias will be passed to "clean"
  and not to `clean_extra/1`.

  Aliases defined in the current project do not affect its dependencies
  and aliases defined in dependencies are not accessible from the
  current project.

  Aliases can be used very powerfully to also run Elixir scripts and
  shell commands, for example:

      # priv/hello1.exs
      IO.puts("Hello One")

      # priv/hello2.exs
      IO.puts("Hello Two")

      # priv/world.sh
      #!/bin/sh
      echo "world!"

      # mix.exs
      defp aliases do
        [
          some_alias: ["hex.info", "run priv/hello1.exs", "cmd priv/world.sh"]
        ]
      end

  In the example above we have created the alias `some_alias` that will
  run the task `mix hex.info`, then `mix run` to run an Elixir script,
  then `mix cmd` to execute a command line shell script. This shows how
  powerful aliases mixed with Mix tasks can be.

  Mix tasks are designed to run only once. This prevents the same task
  to be executed multiple times. For example, if there are several tasks
  depending on `mix compile`, the code will be compiled once. Tasks can
  be executed again if they are explicitly reenabled using `Mix.Task.reenable/1`:

      another_alias: [
        "format --check-formatted priv/hello1.exs",
        "cmd priv/world.sh",
        fn _ -> Mix.Task.reenable("format") end,
        "format --check-formatted priv/hello2.exs"
      ]

  Some tasks are automatically reenabled though, as they are expected to
  be invoked multiple times. They are: `mix cmd`, `mix do`, `mix loadconfig`,
  `mix profile.cprof`, `mix profile.eprof`, `mix profile.fprof`, `mix run`,
  and `mix xref`.

  It is worth mentioning that some tasks, such as in the case of the
  `mix format` command in the example above, can accept multiple files so it
  could be rewritten as:

      another_alias: ["format --check-formatted priv/hello1.exs priv/hello2.exs"]

  ## Environment variables

  Several environment variables can be used to modify Mix's behaviour.

  Mix responds to the following variables:

    * `MIX_ARCHIVES` - specifies the directory into which the archives should be installed
      (default: `~/.mix/archives`)
    * `MIX_BUILD_PATH` - sets the project `Mix.Project.build_path/0` config. This option
      must always point to a subdirectory inside a temporary directory. For instance,
      never "/tmp" or "_build" but "_build/PROD" or "/tmp/PROD", as required by Mix
    * `MIX_DEPS_PATH` - sets the project `Mix.Project.deps_path/0` config (default: `deps`)
    * `MIX_DEBUG` - outputs debug information about each task before running it
    * `MIX_ENV` - specifies which environment should be used. See [Environments](#module-environments)
    * `MIX_TARGET` - specifies which target should be used. See [Targets](#module-targets)
    * `MIX_EXS` - changes the full path to the `mix.exs` file
    * `MIX_HOME` - path to Mix's home directory, stores configuration files and scripts used by Mix
      (default: `~/.mix`)
    * `MIX_PATH` - appends extra code paths
    * `MIX_QUIET` - does not print information messages to the terminal
    * `MIX_REBAR` - path to rebar command that overrides the one Mix installs
      (default: `~/.mix/rebar`)
    * `MIX_REBAR3` - path to rebar3 command that overrides the one Mix installs
      (default: `~/.mix/rebar3`)
    * `MIX_XDG` - asks Mix to follow the [XDG Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
      for its home directory and configuration files. This behaviour needs to
      be opt-in due to backwards compatibility. `MIX_HOME` has higher preference
      than `MIX_XDG`. If none of the variables are set, the default directory
      `~/.mix` will be used

  Environment variables that are not meant to hold a value (and act basically as
  flags) should be set to either `1` or `true`, for example:

      $ MIX_DEBUG=1 mix compile

  """

  use Application

  @doc false
  def start do
    {:ok, _} = Application.ensure_all_started(:mix)
    :ok
  end

  @doc false
  def start(_type, []) do
    children = [Mix.State, Mix.TasksServer, Mix.ProjectStack]
    opts = [strategy: :one_for_one, name: Mix.Supervisor, max_restarts: 0]
    Supervisor.start_link(children, opts)
  end

  @doc """
  Returns the current Mix environment.

  This function should not be used at runtime in application code (as opposed
  to infrastructure and build code like Mix tasks). Mix is a build tool and may
  not be available after the code is compiled (for example in a release).

  To differentiate the program behavior depending on the environment, it is
  recommended to use application environment through `Application.get_env/3`.
  Proper configuration can be set in config files, often per-environment
  (see the `Config` module for more information).
  """
  @spec env() :: atom()
  def env do
    # env is not available on bootstrapping, so set a :dev default
    Mix.State.get(:env, :dev)
  end

  @doc """
  Changes the current Mix environment to `env`.

  Be careful when invoking this function as any project
  configuration won't be reloaded.

  This function should not be used at runtime in application code
  (see `env/0` for more information).
  """
  @spec env(atom()) :: :ok
  def env(env) when is_atom(env) do
    Mix.State.put(:env, env)
  end

  @doc """
  Returns the Mix target.
  """
  @spec target() :: atom()
  def target do
    # target is not available on bootstrapping, so set a :host default
    Mix.State.get(:target, :host)
  end

  @doc """
  Changes the current Mix target to `target`.

  Be careful when invoking this function as any project
  configuration won't be reloaded.
  """
  @spec target(atom()) :: :ok
  def target(target) when is_atom(target) do
    Mix.State.put(:target, target)
  end

  @doc """
  Returns the default compilers used by Mix.

  It can be used in your `mix.exs` to prepend or
  append new compilers to Mix:

      def project do
        [compilers: Mix.compilers() ++ [:foo, :bar]]
      end

  """
  @spec compilers() :: [atom()]
  def compilers do
    [:yecc, :leex, :erlang, :elixir, :app]
  end

  @doc """
  Returns the current shell.

  `shell/0` can be used as a wrapper for the current shell. It contains
  conveniences for requesting information from the user, printing to the
  shell and so forth. The Mix shell is swappable (see `shell/1`), allowing
  developers to use a test shell that simply sends messages to the current
  process instead of performing IO (see `Mix.Shell.Process`).

  By default, this returns `Mix.Shell.IO`.

  ## Examples

      Mix.shell().info("Preparing to do something dangerous...")

      if Mix.shell().yes?("Are you sure?") do
        # do something dangerous
      end

  """
  @spec shell() :: module
  def shell do
    Mix.State.get(:shell, Mix.Shell.IO)
  end

  @doc """
  Sets the current shell.

  As an argument you may pass `Mix.Shell.IO`, `Mix.Shell.Process`,
  `Mix.Shell.Quiet`, or any module that implements the `Mix.Shell`
  behaviour.

  After calling this function, `shell` becomes the shell that is
  returned by `shell/0`.

  ## Examples

      iex> Mix.shell(Mix.Shell.IO)
      :ok

  You can use `shell/0` and `shell/1` to temporarily switch shells,
  for example, if you want to run a Mix Task that normally produces
  a lot of output:

      shell = Mix.shell()
      Mix.shell(Mix.Shell.Quiet)

      try do
        Mix.Task.run("noisy.task")
      after
        Mix.shell(shell)
      end

  """
  @spec shell(module) :: :ok
  def shell(shell) do
    Mix.State.put(:shell, shell)
  end

  @doc """
  Returns `true` if Mix is in debug mode, `false` otherwise.
  """
  @spec debug?() :: boolean()
  def debug? do
    Mix.State.get(:debug, false)
  end

  @doc """
  Sets Mix debug mode.
  """
  @spec debug(boolean()) :: :ok
  def debug(debug) when is_boolean(debug) do
    Mix.State.put(:debug, debug)
  end

  @doc """
  Raises a Mix error that is nicely formatted.
  """
  @spec raise(binary) :: no_return
  def raise(message) when is_binary(message) do
    Kernel.raise(Mix.Error, mix: true, message: message)
  end

  @doc """
  The path for local archives or escripts.
  """
  @doc since: "1.10.0"
  @spec path_for(:archives | :escripts) :: String.t()
  def path_for(:archives) do
    System.get_env("MIX_ARCHIVES") || Path.join(Mix.Utils.mix_home(), "archives")
  end

  def path_for(:escripts) do
    Path.join(Mix.Utils.mix_home(), "escripts")
  end
end


Ensure workers are running in parallel

Ensure workers are running in parallel


fix tcp socket bug

fix tcp socket bug

# Copyright 2019 Volvo Cars
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# ”License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# “AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

defmodule SocketSupervisor do
  use Supervisor
  require Logger

  def start_link(arg) do
    name = SocketSupervisor.Supervisor
    Logger.info "Starting TCP socket `#{inspect name}`"
    Supervisor.start_link(__MODULE__, arg, name: name)
  end

  def init(_arg) do
    supervise [worker(AppTelnet.SocketHolder, [], restart: :transient)], strategy: :simple_one_for_one
  end
end

# Copyright 2019 Volvo Cars
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# ”License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# “AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

defmodule SocketSupervisor do
  use Supervisor
  require Logger

  def start_link(arg) do
    name = SocketSupervisor.Supervisor
    Logger.info "Starting TCP socket `#{inspect name}`"
    Supervisor.start_link(__MODULE__, arg, name: name)
  end

  def init(_arg) do
    supervise [worker(SocketHolder, [], restart: :transient)], strategy: :simple_one_for_one
  end
end


Run formatter on lib/elixir/test/elixir/float_test.exs (#6773)


Refactor Task tests to use describe/2

Refactor Task tests to use describe/2

Code.require_file "test_helper.exs", __DIR__

defmodule TaskTest do
  use ExUnit.Case
  doctest Task

  setup do
    Logger.remove_backend(:console)
    on_exit fn -> Logger.add_backend(:console, flush: true) end
    :ok
  end

  def wait_and_send(caller, atom) do
    send caller, :ready
    receive do: (true -> true)
    send caller, atom
  end

  defp create_task_in_other_process do
    caller = self()
    spawn fn -> send caller, Task.async(fn -> nil end) end
    receive do: (task -> task)
  end

  defp create_dummy_task(reason) do
    {pid, ref} = spawn_monitor(Kernel, :exit, [reason])
    receive do
      {:DOWN, ^ref, _, _, _} ->
        %Task{ref: ref, pid: pid, owner: self()}
    end
  end

  test "async/1" do
    parent = self()
    fun = fn -> wait_and_send(parent, :done) end
    task = Task.async(fun)

    # Assert the struct
    assert task.__struct__ == Task
    assert is_pid task.pid
    assert is_reference task.ref

    # Assert the link
    {:links, links} = Process.info(self(), :links)
    assert task.pid in links

    receive do: (:ready -> :ok)

    # Assert the initial call
    {:name, fun_name} = :erlang.fun_info(fun, :name)
    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(task.pid)

    # Run the task
    send task.pid, true

    # Assert response and monitoring messages
    ref = task.ref
    assert_receive {^ref, :done}
    assert_receive {:DOWN, ^ref, _, _, :normal}
  end

  test "async/3" do
    task = Task.async(__MODULE__, :wait_and_send, [self(), :done])
    assert task.__struct__ == Task

    {:links, links} = Process.info(self(), :links)
    assert task.pid in links

    receive do: (:ready -> :ok)

    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(task.pid)

    send(task.pid, true)

    assert Task.await(task) === :done
    assert_receive :done
  end

  test "start/1" do
    parent = self()
    fun = fn -> wait_and_send(parent, :done) end
    {:ok, pid} = Task.start(fun)

    {:links, links} = Process.info(self(), :links)
    refute pid in links

    receive do: (:ready -> :ok)

    {:name, fun_name} = :erlang.fun_info(fun, :name)
    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  test "start/3" do
    {:ok, pid} = Task.start(__MODULE__, :wait_and_send, [self(), :done])

    {:links, links} = Process.info(self(), :links)
    refute pid in links

    receive do: (:ready -> :ok)

    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  test "start_link/1" do
    parent = self()
    fun = fn -> wait_and_send(parent, :done) end
    {:ok, pid} = Task.start_link(fun)

    {:links, links} = Process.info(self(), :links)
    assert pid in links

    receive do: (:ready -> :ok)

    {:name, fun_name} = :erlang.fun_info(fun, :name)
    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  test "start_link/3" do
    {:ok, pid} = Task.start_link(__MODULE__, :wait_and_send, [self(), :done])

    {:links, links} = Process.info(self(), :links)
    assert pid in links

    receive do: (:ready -> :ok)

    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  describe "await/2" do
    test "exits on timeout" do
      task = %Task{ref: make_ref(), owner: self()}
      assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}
    end

    test "exits on normal exit" do
      task = Task.async(fn -> exit :normal end)
      assert catch_exit(Task.await(task)) == {:normal, {Task, :await, [task, 5000]}}
    end

    test "exits on task throw" do
      Process.flag(:trap_exit, true)
      task = Task.async(fn -> throw :unknown end)
      assert {{{:nocatch, :unknown}, _}, {Task, :await, [^task, 5000]}} =
             catch_exit(Task.await(task))
    end

    test "exits on task error" do
      Process.flag(:trap_exit, true)
      task = Task.async(fn -> raise "oops" end)
      assert {{%RuntimeError{}, _}, {Task, :await, [^task, 5000]}} =
             catch_exit(Task.await(task))
    end

    test "exits on task undef module error" do
      Process.flag(:trap_exit, true)
      task = Task.async(&:module_does_not_exist.undef/0)
      assert {{:undef, [{:module_does_not_exist, :undef, _, _} | _]},
              {Task, :await, [^task, 5000]}} =
             catch_exit(Task.await(task))
    end

    test "exits on task undef function error" do
      Process.flag(:trap_exit, true)
      task = Task.async(&TaskTest.undef/0)
      assert {{:undef, [{TaskTest, :undef, _, _} | _]},
              {Task, :await, [^task, 5000]}} =
             catch_exit(Task.await(task))
    end

    test "exits on task exit" do
      Process.flag(:trap_exit, true)
      task = Task.async(fn -> exit :unknown end)
      assert {:unknown, {Task, :await, [^task, 5000]}} =
             catch_exit(Task.await(task))
    end

    test "exits on :noconnection" do
      ref  = make_ref()
      task = %Task{ref: ref, pid: self(), owner: self()}
      send self(), {:DOWN, ref, :process, self(), :noconnection}
      assert catch_exit(Task.await(task)) |> elem(0) == {:nodedown, :nonode@nohost}
    end

    test "exits on :noconnection from named monitor" do
      ref  = make_ref()
      task = %Task{ref: ref, pid: nil, owner: self()}
      send self(), {:DOWN, ref, :process, {:name, :node}, :noconnection}
      assert catch_exit(Task.await(task)) |> elem(0) == {:nodedown, :node}
    end

    test "raises when invoked from a non-owner process" do
      task = create_task_in_other_process()
      message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
      assert_raise ArgumentError, message, fn -> Task.await(task, 1) end
    end
  end

  describe "yield/2" do
    test "returns {:ok, result} when reply and :DOWN in message queue" do
      task = %Task{ref: make_ref(), owner: self()}
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, self(), :abnormal})
      assert Task.yield(task, 0) == {:ok, :result}
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns nil on timeout" do
      task = %Task{ref: make_ref(), owner: self()}
      assert Task.yield(task, 0) == nil
    end

    test "return exit on normal exit" do
      task = Task.async(fn -> exit :normal end)
      assert Task.yield(task) == {:exit, :normal}
    end

    test "exits on :noconnection" do
      ref  = make_ref()
      task = %Task{ref: ref, pid: self(), owner: self()}
      send self(), {:DOWN, ref, self(), self(), :noconnection}
      assert catch_exit(Task.yield(task)) |> elem(0) == {:nodedown, :nonode@nohost}
    end

    test "raises when invoked from a non-owner process" do
      task = create_task_in_other_process()
      message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
      assert_raise ArgumentError, message, fn -> Task.yield(task, 1) end
    end
  end

  describe "yield_many/2" do
    test "returns {:ok, result} when reply and :DOWN in message queue" do
      task = %Task{ref: make_ref(), owner: self()}
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, self(), :abnormal})
      assert Task.yield_many([task], 0) == [{task, {:ok, :result}}]
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns nil on timeout" do
      task = %Task{ref: make_ref(), owner: self()}
      assert Task.yield_many([task], 0) == [{task, nil}]
    end

    test "return exit on normal exit" do
      task = Task.async(fn -> exit :normal end)
      assert Task.yield_many([task]) == [{task, {:exit, :normal}}]
    end

    test "exits on :noconnection" do
      ref  = make_ref()
      task = %Task{ref: ref, pid: self(), owner: self()}
      send self(), {:DOWN, ref, self(), self(), :noconnection}
      assert catch_exit(Task.yield_many([task])) |> elem(0) == {:nodedown, :nonode@nohost}
    end

    test "raises when invoked from a non-owner process" do
      task = create_task_in_other_process()
      message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
      assert_raise ArgumentError, message, fn -> Task.yield_many([task], 1) end
    end

    test "returns results from multiple tasks" do
      task1 = %Task{ref: make_ref(), owner: self()}
      task2 = %Task{ref: make_ref(), owner: self()}
      task3 = Task.async(fn -> exit :normal end)

      send(self(), {task1.ref, :result})
      ref = Process.monitor(task3.pid)
      assert_receive {:DOWN, ^ref, _, _, :normal}

      assert Task.yield_many([task1, task2, task3], 0) ==
             [{task1, {:ok, :result}}, {task2, nil}, {task3, {:exit, :normal}}]
    end
  end

  describe "shutdown/2" do
    test "returns {:ok, result} when reply and abnormal :DOWN in message queue" do
      task = create_dummy_task(:abnormal)
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
      assert Task.shutdown(task) == {:ok, :result}
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns {:ok, result} when reply and normal :DOWN in message queue" do
      task = create_dummy_task(:normal)
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
      assert Task.shutdown(task) == {:ok, :result}
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns {:ok, result} when reply and shutdown :DOWN in message queue" do
      task = create_dummy_task(:shutdown)
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
      assert Task.shutdown(task) == {:ok, :result}
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns nil on shutting down task" do
      task = Task.async(:timer, :sleep, [:infinity])
      assert Task.shutdown(task) == nil
    end

    test "returns exit on abnormal :DOWN in message queue" do
      task = create_dummy_task(:abnormal)
      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
      assert Task.shutdown(task) == {:exit, :abnormal}
    end

    test "returns exit on normal :DOWN in message queue" do
      task = create_dummy_task(:normal)
      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
      assert Task.shutdown(task) == {:exit, :normal}
    end

    test "returns nil on shutdown :DOWN in message queue" do
      task = create_dummy_task(:shutdown)
      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
      assert Task.shutdown(task) == nil
    end

    test "returns exit on killed :DOWN in message queue" do
      task = create_dummy_task(:killed)
      send(self(), {:DOWN, task.ref, :process, task.pid, :killed})
      assert Task.shutdown(task) == {:exit, :killed}
    end

    test "exits on noconnection :DOWN in message queue" do
      task = create_dummy_task(:noconnection)
      send(self(), {:DOWN, task.ref, :process, task.pid, :noconnection})
      assert catch_exit(Task.shutdown(task)) ==
        {{:nodedown, node()}, {Task, :shutdown, [task, 5000]}}
    end

    test "raises if task PID is nil" do
      task = %Task{ref: make_ref(), pid: nil}
      assert_raise ArgumentError, "task #{inspect task} does not have an associated task process",
        fn -> Task.shutdown(task) end
    end

    test "raises when invoked from a non-owner process" do
      task = create_task_in_other_process()
      message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
      assert_raise ArgumentError, message, fn -> Task.shutdown(task) end
    end

    test "shutdown/2 returns nil on killing task" do
      caller = self()

      task = Task.async(fn() ->
        Process.flag(:trap_exit, true)
        wait_and_send(caller, :ready)
        :timer.sleep(:infinity)
      end)

      receive do: (:ready -> :ok)

      assert Task.shutdown(task, :brutal_kill) == nil
      refute_received {:DOWN, _, _, _, _}
    end

    test "shutdown/2 returns {:exit, :noproc} if task handled" do
      task = create_dummy_task(:noproc)
      assert Task.shutdown(task) == {:exit, :noproc}
    end
  end

  describe "shutdown/2 with :brutal_kill" do
    test "returns {:ok, result} when reply and abnormal :DOWN in message queue" do
      task = create_dummy_task(:abnormal)
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
      assert Task.shutdown(task, :brutal_kill) == {:ok, :result}
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns {:ok, result} when reply and normal :DOWN in message queue" do
      task = create_dummy_task(:normal)
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
      assert Task.shutdown(task, :brutal_kill) == {:ok, :result}
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns {:ok, result} when reply and shutdown :DOWN in message queue" do
      task = create_dummy_task(:shutdown)
      send(self(), {task.ref, :result})
      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
      assert Task.shutdown(task, :brutal_kill) == {:ok, :result}
      refute_received {:DOWN, _, _, _, _}
    end

    test "returns nil on killed :DOWN in message queue" do
      task = create_dummy_task(:killed)
      send(self(), {:DOWN, task.ref, :process, task.pid, :killed})
      assert Task.shutdown(task, :brutal_kill) == nil
    end

    test "returns exit on abnormal :DOWN in message queue" do
      task = create_dummy_task(:abnormal)
      send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
      assert Task.shutdown(task, :brutal_kill) == {:exit, :abnormal}
    end

    test "returns exit on normal :DOWN in message queue" do
      task = create_dummy_task(:normal)
      send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
      assert Task.shutdown(task, :brutal_kill) == {:exit, :normal}
    end

    test "returns exit on shutdown :DOWN in message queue" do
      task = create_dummy_task(:shutdown)
      send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
      assert Task.shutdown(task, :brutal_kill) == {:exit, :shutdown}
    end

    test "exits on noconnection :DOWN in message queue" do
      task = create_dummy_task(:noconnection)
      send(self(), {:DOWN, task.ref, :process, task.pid, :noconnection})
      assert catch_exit(Task.shutdown(task, :brutal_kill)) ==
        {{:nodedown, node()}, {Task, :shutdown, [task, :brutal_kill]}}
    end

    test "returns exit on killing task after shutdown timeout" do
      caller = self()

      task = Task.async(fn() ->
        Process.flag(:trap_exit, true)
        wait_and_send(caller, :ready)
        :timer.sleep(:infinity)
      end)

      receive do: (:ready -> :ok)
      assert Task.shutdown(task, 1) == {:exit, :killed}
    end

    test "shutdown/2 returns {:exit, :noproc} if task handled" do
      task = create_dummy_task(:noproc)
      assert Task.shutdown(task, :brutal_kill) == {:exit, :noproc}
    end
  end
end

Code.require_file "test_helper.exs", __DIR__

defmodule TaskTest do
  use ExUnit.Case
  doctest Task

  setup do
    Logger.remove_backend(:console)
    on_exit fn -> Logger.add_backend(:console, flush: true) end
    :ok
  end

  def wait_and_send(caller, atom) do
    send caller, :ready
    receive do: (true -> true)
    send caller, atom
  end

  defp create_task_in_other_process do
    caller = self()
    spawn fn -> send caller, Task.async(fn -> nil end) end
    receive do: (task -> task)
  end

  defp create_dummy_task(reason) do
    {pid, ref} = spawn_monitor(Kernel, :exit, [reason])
    receive do
      {:DOWN, ^ref, _, _, _} ->
        %Task{ref: ref, pid: pid, owner: self()}
    end
  end

  test "async/1" do
    parent = self()
    fun = fn -> wait_and_send(parent, :done) end
    task = Task.async(fun)

    # Assert the struct
    assert task.__struct__ == Task
    assert is_pid task.pid
    assert is_reference task.ref

    # Assert the link
    {:links, links} = Process.info(self(), :links)
    assert task.pid in links

    receive do: (:ready -> :ok)

    # Assert the initial call
    {:name, fun_name} = :erlang.fun_info(fun, :name)
    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(task.pid)

    # Run the task
    send task.pid, true

    # Assert response and monitoring messages
    ref = task.ref
    assert_receive {^ref, :done}
    assert_receive {:DOWN, ^ref, _, _, :normal}
  end

  test "async/3" do
    task = Task.async(__MODULE__, :wait_and_send, [self(), :done])
    assert task.__struct__ == Task

    {:links, links} = Process.info(self(), :links)
    assert task.pid in links

    receive do: (:ready -> :ok)

    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(task.pid)

    send(task.pid, true)

    assert Task.await(task) === :done
    assert_receive :done
  end

  test "start/1" do
    parent = self()
    fun = fn -> wait_and_send(parent, :done) end
    {:ok, pid} = Task.start(fun)

    {:links, links} = Process.info(self(), :links)
    refute pid in links

    receive do: (:ready -> :ok)

    {:name, fun_name} = :erlang.fun_info(fun, :name)
    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  test "start/3" do
    {:ok, pid} = Task.start(__MODULE__, :wait_and_send, [self(), :done])

    {:links, links} = Process.info(self(), :links)
    refute pid in links

    receive do: (:ready -> :ok)

    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  test "start_link/1" do
    parent = self()
    fun = fn -> wait_and_send(parent, :done) end
    {:ok, pid} = Task.start_link(fun)

    {:links, links} = Process.info(self(), :links)
    assert pid in links

    receive do: (:ready -> :ok)

    {:name, fun_name} = :erlang.fun_info(fun, :name)
    assert {__MODULE__, fun_name, 0} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  test "start_link/3" do
    {:ok, pid} = Task.start_link(__MODULE__, :wait_and_send, [self(), :done])

    {:links, links} = Process.info(self(), :links)
    assert pid in links

    receive do: (:ready -> :ok)

    assert {__MODULE__, :wait_and_send, 2} === :proc_lib.translate_initial_call(pid)

    send pid, true
    assert_receive :done
  end

  test "await/2 exits on timeout" do
    task = %Task{ref: make_ref(), owner: self()}
    assert catch_exit(Task.await(task, 0)) == {:timeout, {Task, :await, [task, 0]}}
  end

  test "await/2 exits on normal exit" do
    task = Task.async(fn -> exit :normal end)
    assert catch_exit(Task.await(task)) == {:normal, {Task, :await, [task, 5000]}}
  end

  test "await/2 exits on task throw" do
    Process.flag(:trap_exit, true)
    task = Task.async(fn -> throw :unknown end)
    assert {{{:nocatch, :unknown}, _}, {Task, :await, [^task, 5000]}} =
           catch_exit(Task.await(task))
  end

  test "await/2 exits on task error" do
    Process.flag(:trap_exit, true)
    task = Task.async(fn -> raise "oops" end)
    assert {{%RuntimeError{}, _}, {Task, :await, [^task, 5000]}} =
           catch_exit(Task.await(task))
  end

  test "await/2 exits on task undef module error" do
    Process.flag(:trap_exit, true)
    task = Task.async(&:module_does_not_exist.undef/0)
    assert {{:undef, [{:module_does_not_exist, :undef, _, _} | _]},
            {Task, :await, [^task, 5000]}} =
           catch_exit(Task.await(task))
  end

  test "await/2 exits on task undef function error" do
    Process.flag(:trap_exit, true)
    task = Task.async(&TaskTest.undef/0)
    assert {{:undef, [{TaskTest, :undef, _, _} | _]},
            {Task, :await, [^task, 5000]}} =
           catch_exit(Task.await(task))
  end

  test "await/2 exits on task exit" do
    Process.flag(:trap_exit, true)
    task = Task.async(fn -> exit :unknown end)
    assert {:unknown, {Task, :await, [^task, 5000]}} =
           catch_exit(Task.await(task))
  end

  test "await/2 exits on :noconnection" do
    ref  = make_ref()
    task = %Task{ref: ref, pid: self(), owner: self()}
    send self(), {:DOWN, ref, :process, self(), :noconnection}
    assert catch_exit(Task.await(task)) |> elem(0) == {:nodedown, :nonode@nohost}
  end

  test "await/2 exits on :noconnection from named monitor" do
    ref  = make_ref()
    task = %Task{ref: ref, pid: nil, owner: self()}
    send self(), {:DOWN, ref, :process, {:name, :node}, :noconnection}
    assert catch_exit(Task.await(task)) |> elem(0) == {:nodedown, :node}
  end

  test "await/2 raises when invoked from a non-owner process" do
    task = create_task_in_other_process()
    message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
    assert_raise ArgumentError, message, fn -> Task.await(task, 1) end
  end

  test "yield/2 returns {:ok, result} when reply and :DOWN in message queue" do
    task = %Task{ref: make_ref(), owner: self()}
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, self(), :abnormal})
    assert Task.yield(task, 0) == {:ok, :result}
    refute_received {:DOWN, _, _, _, _}
  end

  test "yield/2 returns nil on timeout" do
    task = %Task{ref: make_ref(), owner: self()}
    assert Task.yield(task, 0) == nil
  end

  test "yield/2 return exit on normal exit" do
    task = Task.async(fn -> exit :normal end)
    assert Task.yield(task) == {:exit, :normal}
  end

  test "yield/2 exits on :noconnection" do
    ref  = make_ref()
    task = %Task{ref: ref, pid: self(), owner: self()}
    send self(), {:DOWN, ref, self(), self(), :noconnection}
    assert catch_exit(Task.yield(task)) |> elem(0) == {:nodedown, :nonode@nohost}
  end

  test "yield/2 raises when invoked from a non-owner process" do
    task = create_task_in_other_process()
    message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
    assert_raise ArgumentError, message, fn -> Task.yield(task, 1) end
  end

  test "yield_many/2 returns {:ok, result} when reply and :DOWN in message queue" do
    task = %Task{ref: make_ref(), owner: self()}
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, self(), :abnormal})
    assert Task.yield_many([task], 0) == [{task, {:ok, :result}}]
    refute_received {:DOWN, _, _, _, _}
  end

  test "yield_many/2 returns nil on timeout" do
    task = %Task{ref: make_ref(), owner: self()}
    assert Task.yield_many([task], 0) == [{task, nil}]
  end

  test "yield_many/2 return exit on normal exit" do
    task = Task.async(fn -> exit :normal end)
    assert Task.yield_many([task]) == [{task, {:exit, :normal}}]
  end

  test "yield_many/2 exits on :noconnection" do
    ref  = make_ref()
    task = %Task{ref: ref, pid: self(), owner: self()}
    send self(), {:DOWN, ref, self(), self(), :noconnection}
    assert catch_exit(Task.yield_many([task])) |> elem(0) == {:nodedown, :nonode@nohost}
  end

  test "yield_many/2 raises when invoked from a non-owner process" do
    task = create_task_in_other_process()
    message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
    assert_raise ArgumentError, message, fn -> Task.yield_many([task], 1) end
  end

  test "yield_many/2 returns results from multiple tasks" do
    task1 = %Task{ref: make_ref(), owner: self()}
    task2 = %Task{ref: make_ref(), owner: self()}
    task3 = Task.async(fn -> exit :normal end)

    send(self(), {task1.ref, :result})
    ref = Process.monitor(task3.pid)
    assert_receive {:DOWN, ^ref, _, _, :normal}

    assert Task.yield_many([task1, task2, task3], 0) ==
           [{task1, {:ok, :result}}, {task2, nil}, {task3, {:exit, :normal}}]
  end

  test "shutdown/2 returns {:ok, result} when reply and abnormal :DOWN in message queue" do
    task = create_dummy_task(:abnormal)
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
    assert Task.shutdown(task) == {:ok, :result}
    refute_received {:DOWN, _, _, _, _}
  end

  test "shutdown/2 returns {:ok, result} when reply and normal :DOWN in message queue" do
    task = create_dummy_task(:normal)
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
    assert Task.shutdown(task) == {:ok, :result}
    refute_received {:DOWN, _, _, _, _}
  end

  test "shutdown/2 returns {:ok, result} when reply and shutdown :DOWN in message queue" do
    task = create_dummy_task(:shutdown)
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
    assert Task.shutdown(task) == {:ok, :result}
    refute_received {:DOWN, _, _, _, _}
  end

  test "shutdown/2 returns nil on shutting down task" do
    task = Task.async(:timer, :sleep, [:infinity])
    assert Task.shutdown(task) == nil
  end

  test "shutdown/2 return exit on abnormal :DOWN in message queue" do
    task = create_dummy_task(:abnormal)
    send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
    assert Task.shutdown(task) == {:exit, :abnormal}
  end

  test "shutdown/2 return exit on normal :DOWN in message queue" do
    task = create_dummy_task(:normal)
    send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
    assert Task.shutdown(task) == {:exit, :normal}
  end

  test "shutdown/2 returns nil on shutdown :DOWN in message queue" do
    task = create_dummy_task(:shutdown)
    send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
    assert Task.shutdown(task) == nil
  end

  test "shutdown/2 return exit on killed :DOWN in message queue" do
    task = create_dummy_task(:killed)
    send(self(), {:DOWN, task.ref, :process, task.pid, :killed})
    assert Task.shutdown(task) == {:exit, :killed}
  end

  test "shutdown/2 exits on noconnection :DOWN in message queue" do
    task = create_dummy_task(:noconnection)
    send(self(), {:DOWN, task.ref, :process, task.pid, :noconnection})
    assert catch_exit(Task.shutdown(task)) ==
      {{:nodedown, node()}, {Task, :shutdown, [task, 5000]}}
  end

  test "shutdown/2 raises if task PID is nil" do
    task = %Task{ref: make_ref(), pid: nil}
    assert_raise ArgumentError, "task #{inspect task} does not have an associated task process",
      fn -> Task.shutdown(task) end
  end

  test "shutdown/2 raises when invoked from a non-owner process" do
    task = create_task_in_other_process()
    message = "task #{inspect task} must be queried from the owner but was queried from #{inspect self()}"
    assert_raise ArgumentError, message, fn -> Task.shutdown(task) end
  end

  test "shutdown/2 brutal_ kill returns {:ok, result} when reply and abnormal :DOWN in message queue" do
    task = create_dummy_task(:abnormal)
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
    assert Task.shutdown(task, :brutal_kill) == {:ok, :result}
    refute_received {:DOWN, _, _, _, _}
  end

  test "shutdown/2 brutal kill returns {:ok, result} when reply and normal :DOWN in message queue" do
    task = create_dummy_task(:normal)
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
    assert Task.shutdown(task, :brutal_kill) == {:ok, :result}
    refute_received {:DOWN, _, _, _, _}
  end

  test "shutdown/2 brutal kill returns {:ok, result} when reply and shutdown :DOWN in message queue" do
    task = create_dummy_task(:shutdown)
    send(self(), {task.ref, :result})
    send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
    assert Task.shutdown(task, :brutal_kill) == {:ok, :result}
    refute_received {:DOWN, _, _, _, _}
  end

  test "shutdown/2 brutal kill returns nil on killed :DOWN in message queue" do
    task = create_dummy_task(:killed)
    send(self(), {:DOWN, task.ref, :process, task.pid, :killed})
    assert Task.shutdown(task, :brutal_kill) == nil
  end

  test "shutdown/2 brutal kill returns exit on abnormal :DOWN in message queue" do
    task = create_dummy_task(:abnormal)
    send(self(), {:DOWN, task.ref, :process, task.pid, :abnormal})
    assert Task.shutdown(task, :brutal_kill) == {:exit, :abnormal}
  end

  test "shutdown/2 brutal kill returns exit on normal :DOWN in message queue" do
    task = create_dummy_task(:normal)
    send(self(), {:DOWN, task.ref, :process, task.pid, :normal})
    assert Task.shutdown(task, :brutal_kill) == {:exit, :normal}
  end

  test "shutdown/2 brutal kill returns exit on shutdown :DOWN in message queue" do
    task = create_dummy_task(:shutdown)
    send(self(), {:DOWN, task.ref, :process, task.pid, :shutdown})
    assert Task.shutdown(task, :brutal_kill) == {:exit, :shutdown}
  end

  test "shutdown/2 brutal kill exits on noconnection :DOWN in message queue" do
    task = create_dummy_task(:noconnection)
    send(self(), {:DOWN, task.ref, :process, task.pid, :noconnection})
    assert catch_exit(Task.shutdown(task, :brutal_kill)) ==
      {{:nodedown, node()}, {Task, :shutdown, [task, :brutal_kill]}}
  end

  test "shutdown/2 returns exit on killing task after shutdown timeout" do
    caller = self()

    task = Task.async(fn() ->
      Process.flag(:trap_exit, true)
      wait_and_send(caller, :ready)
      :timer.sleep(:infinity)
    end)

    receive do: (:ready -> :ok)
    assert Task.shutdown(task, 1) == {:exit, :killed}
  end

  test "shutdown/2 returns nil on killing task" do
    caller = self()

    task = Task.async(fn() ->
      Process.flag(:trap_exit, true)
      wait_and_send(caller, :ready)
      :timer.sleep(:infinity)
    end)

    receive do: (:ready -> :ok)

    assert Task.shutdown(task, :brutal_kill) == nil
    refute_received {:DOWN, _, _, _, _}
  end

  test "shutdown/2 returns {:exit, :noproc} if task handled" do
    task = create_dummy_task(:noproc)
    assert Task.shutdown(task) == {:exit, :noproc}
  end

  test "shutdown/2 brutal kill returns {:exit, :noproc} if task handled" do
    task = create_dummy_task(:noproc)
    assert Task.shutdown(task, :brutal_kill) == {:exit, :noproc}
  end
end


Typo fix

Typo fix

defmodule Mix.Tasks.Deps.Unlock do
  use Mix.Task

  @shortdoc "Unlock the given dependencies"

  @moduledoc """
  Unlock the given dependencies.

  Since this is a destructive action, unlocking of dependencies
  can only happen by passing arguments/options:

    * `dep1 dep2` - the name of dependency to be unlocked
    * `--all` - unlocks all dependencies
    * `--unused` - unlocks only unused dependencies (no longer mentioned
      in the `mix.exs` file)

  """

  @switches [all: :boolean, unused: :boolean]

  def run(args) do
    Mix.Project.get!
    {opts, apps, _} = OptionParser.parse(args, switches: @switches)

    cond do
      opts[:all] ->
        Mix.Dep.Lock.write([])
      opts[:unused] ->
        apps = Mix.Dep.loaded([]) |> Enum.map(& &1.app)
        Mix.Dep.Lock.read() |> Map.take(apps) |> Mix.Dep.Lock.write()

      apps != [] ->
        lock =
          Enum.reduce apps, Mix.Dep.Lock.read, fn(app, lock) ->
            Map.delete(lock, String.to_atom(app))
          end
        Mix.Dep.Lock.write(lock)

      true ->
        Mix.raise "mix deps.unlock expects dependencies as arguments or " <>
                  "the --all option to unlock all dependencies"
    end
  end
end

defmodule Mix.Tasks.Deps.Unlock do
  use Mix.Task

  @shortdoc "Unlock the given dependencies"

  @moduledoc """
  Unlock the given dependencies.

  Since this is a destructive action, unlocking of dependencies
  can only happen by passing arguments/options:

    * `dep1 dep2` - the name of dependency to be unlocked
    * `--all` - unlcks all dependencies
    * `--unused` - unlocks only unused dependencies (no longer mentioned
      in the `mix.exs` file)

  """

  @switches [all: :boolean, unused: :boolean]

  def run(args) do
    Mix.Project.get!
    {opts, apps, _} = OptionParser.parse(args, switches: @switches)

    cond do
      opts[:all] ->
        Mix.Dep.Lock.write([])
      opts[:unused] ->
        apps = Mix.Dep.loaded([]) |> Enum.map(& &1.app)
        Mix.Dep.Lock.read() |> Map.take(apps) |> Mix.Dep.Lock.write()

      apps != [] ->
        lock =
          Enum.reduce apps, Mix.Dep.Lock.read, fn(app, lock) ->
            Map.delete(lock, String.to_atom(app))
          end
        Mix.Dep.Lock.write(lock)

      true ->
        Mix.raise "mix deps.unlock expects dependencies as arguments or " <>
                  "the --all option to unlock all dependencies"
    end
  end
end


Full Module Name in Example

Full Module Name in Example

defmodule Mix.Tasks.Phoenix.Gen.Channel do
  use Mix.Task

  @shortdoc "Generates a Phoenix channel"

  @moduledoc """
  Generates a Phoenix channel.

      mix phoenix.gen.channel Room rooms

  The first argument is the module name for the channel.
  The second argument is the plural used as the topic.

  The generated model will contain:

    * a channel in web/channels
    * a channel_test in test/channels

  """
  def run(args) do
    [singular, plural] = validate_args!(args)

    binding = Mix.Phoenix.inflect(singular)
    path    = binding[:path]

    binding = binding ++ [plural: plural]

    Mix.Phoenix.check_module_name_availability!(binding[:module] <> "Channel")

    Mix.Phoenix.copy_from paths(), "priv/templates/phoenix.gen.channel", "", binding, [
      {:eex, "channel.ex",       "web/channels/#{path}_channel.ex"},
      {:eex, "channel_test.exs", "test/channels/#{path}_channel_test.exs"},
    ]

    Mix.shell.info """

    Add the channel to your `web/channels/user_socket.ex` handler, for example:

        channel "#{plural}:lobby", #{binding[:module]}Channel
    """
  end

  defp raise_with_help do
    Mix.raise """
    mix phoenix.gen.channel expects just the module name and topic name:

        mix phoenix.gen.channel Room rooms
    """
  end

  defp validate_args!(args) do
    unless length(args) == 2 do
      raise_with_help
    end
    args
  end

  defp paths do
    [".", :phoenix]
  end
end

defmodule Mix.Tasks.Phoenix.Gen.Channel do
  use Mix.Task

  @shortdoc "Generates a Phoenix channel"

  @moduledoc """
  Generates a Phoenix channel.

      mix phoenix.gen.channel Room rooms

  The first argument is the module name for the channel.
  The second argument is the plural used as the topic.

  The generated model will contain:

    * a channel in web/channels
    * a channel_test in test/channels

  """
  def run(args) do
    [singular, plural] = validate_args!(args)

    binding = Mix.Phoenix.inflect(singular)
    path    = binding[:path]

    binding = binding ++ [plural: plural]

    Mix.Phoenix.check_module_name_availability!(binding[:module] <> "Channel")

    Mix.Phoenix.copy_from paths(), "priv/templates/phoenix.gen.channel", "", binding, [
      {:eex, "channel.ex",       "web/channels/#{path}_channel.ex"},
      {:eex, "channel_test.exs", "test/channels/#{path}_channel_test.exs"},
    ]

    Mix.shell.info """

    Add the channel to your `web/channels/user_socket.ex` handler, for example:

        channel "#{plural}:lobby", #{binding[:scoped]}Channel
    """
  end

  defp raise_with_help do
    Mix.raise """
    mix phoenix.gen.channel expects just the module name and topic name:

        mix phoenix.gen.channel Room rooms
    """
  end

  defp validate_args!(args) do
    unless length(args) == 2 do
      raise_with_help
    end
    args
  end

  defp paths do
    [".", :phoenix]
  end
end


Update `mix test --failed` test comment (#10792)

Code.require_file("../../test_helper.exs", __DIR__)

defmodule Mix.Tasks.TestTest do
  use MixTest.Case

  describe "ex_unit_opts/1" do
    test "returns ex unit options" do
      assert ex_unit_opts_from_given(unknown: "ok", seed: 13) == [seed: 13]
    end

    test "returns includes and excludes" do
      included = [include: [:focus, key: "val"]]
      assert ex_unit_opts_from_given(include: "focus", include: "key:val") == included

      excluded = [exclude: [:focus, key: "val"]]
      assert ex_unit_opts_from_given(exclude: "focus", exclude: "key:val") == excluded
    end

    test "translates :only into includes and excludes" do
      assert ex_unit_opts_from_given(only: "focus") == [include: [:focus], exclude: [:test]]

      only = [include: [:focus, :special], exclude: [:test]]
      assert ex_unit_opts_from_given(only: "focus", include: "special") == only
    end

    test "translates :color into list containing an enabled key-value pair" do
      assert ex_unit_opts_from_given(color: false) == [colors: [enabled: false]]
      assert ex_unit_opts_from_given(color: true) == [colors: [enabled: true]]
    end

    test "translates :formatter into list of modules" do
      assert ex_unit_opts_from_given(formatter: "A.B") == [formatters: [A.B]]
    end

    test "includes some default options" do
      assert ex_unit_opts([]) == [
               autorun: false,
               failures_manifest_file:
                 Path.join(Mix.Project.manifest_path(), ".mix_test_failures")
             ]
    end

    defp ex_unit_opts(opts) do
      {ex_unit_opts, _allowed_files} = Mix.Tasks.Test.process_ex_unit_opts(opts)
      ex_unit_opts
    end

    defp ex_unit_opts_from_given(passed) do
      passed
      |> ex_unit_opts()
      |> Keyword.drop([:failures_manifest_file, :autorun])
    end
  end

  describe "--stale" do
    test "runs all tests for first run, then none on second" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        assert_stale_run_output("""
        No stale tests
        """)
      end)
    end

    test "runs tests that depend on modified modules" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()
        File.touch!("lib/b.ex")

        assert_stale_run_output("1 test, 0 failures")

        set_all_mtimes()
        File.touch!("lib/a.ex")

        assert_stale_run_output("2 tests, 0 failures")
      end)
    end

    test "doesn't write manifest when there are failures" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()

        File.write!("lib/b.ex", """
        defmodule B do
          def f, do: :error
        end
        """)

        assert_stale_run_output("1 test, 1 failure")

        assert_stale_run_output("1 test, 1 failure")
      end)
    end

    test "runs tests that have changed" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()
        File.touch!("test/a_test_stale.exs")

        assert_stale_run_output("1 test, 0 failures")
      end)
    end

    test "runs tests that have changed test_helpers" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()
        File.touch!("test/test_helper.exs")

        assert_stale_run_output("2 tests, 0 failures")
      end)
    end

    test "runs all tests no matter what with --force" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        assert_stale_run_output(~w[--force], "2 tests, 0 failures")
      end)
    end
  end

  describe "--cover" do
    test "reports the coverage of each app's modules in an umbrella" do
      in_fixture("umbrella_test", fn ->
        output = mix(["test", "--cover"])

        assert output =~ "3 tests, 0 failures"

        # For bar, we do regular --cover and also test protocols
        assert output =~ """
               Generating cover results ...

               Percentage | Module
               -----------|--------------------------
                  100.00% | Bar.Protocol
                  100.00% | Bar.Protocol.BitString
               -----------|--------------------------
                  100.00% | Total
               """

        assert output =~ "1 test, 0 failures"

        # For foo, we do regular --cover and test it does not include bar
        assert output =~ """
               Generating cover results ...

               Percentage | Module
               -----------|--------------------------
                  100.00% | Foo
               -----------|--------------------------
                  100.00% | Total
               """
      end)
    end

    test "supports unified reports by using test.coverage" do
      in_fixture("umbrella_test", fn ->
        assert mix(["test", "--export-coverage", "default", "--cover"]) =~
                 "Run \"mix test.coverage\" once all exports complete"

        assert mix(["test.coverage"]) =~ """
               Importing cover results: apps/bar/cover/default.coverdata
               Importing cover results: apps/foo/cover/default.coverdata

               Percentage | Module
               -----------|--------------------------
                  100.00% | Bar
                  100.00% | Bar.Protocol
                  100.00% | Bar.Protocol.BitString
                  100.00% | Foo
               -----------|--------------------------
                  100.00% | Total
               """
      end)
    end
  end

  describe "--failed" do
    test "loads only files with failures and runs just the failures" do
      in_fixture("test_failed", fn ->
        loading_only_passing_test_msg = "loading OnlyPassingTest"

        # Run `mix test` once to record failures...
        output = mix(["test"])
        assert output =~ loading_only_passing_test_msg
        assert output =~ "4 tests, 2 failures"

        # `mix test --failed` runs only failed tests and avoids loading files with no failures
        output = mix(["test", "--failed"])
        refute output =~ loading_only_passing_test_msg
        assert output =~ "2 tests, 2 failures"

        # `mix test --failed` can be applied to a directory or file
        output = mix(["test", "test/passing_and_failing_test_failed.exs", "--failed"])
        assert output =~ "1 test, 1 failure"

        # `--failed` composes with an `--only` filter by running the intersection.
        # Of the failing tests, 1 is tagged with `@tag :foo`.
        # Of the passing tests, 1 is tagged with `@tag :foo`.
        # But only the failing test with that tag should run.
        output = mix(["test", "--failed", "--only", "foo"])
        assert output =~ "2 tests, 1 failure, 1 excluded"

        # Run again to give it a chance to record as passed
        System.put_env("PASS_FAILING_TESTS", "true")
        assert mix(["test", "--failed"]) =~ "2 tests, 0 failures"

        # All tests should be run if we try it again with no failing tests.
        # This prevents `mix test --failed` from passing in cases where
        # `mix test` had a compilation error before having failing tests.
        # It also provides a better workflow as you can always run with --failed.
        output = mix(["test", "--failed"])
        assert output =~ "No pending --failed tests, re-running all available tests..."
        assert output =~ "4 tests, 0 failures"

        # `--failed` and `--stale` cannot be combined
        output = mix(["test", "--failed", "--stale"])
        assert output =~ "Combining --failed and --stale is not supported"
      end)
    after
      System.delete_env("PASS_FAILING_TESTS")
    end
  end

  describe "--listen-on-stdin" do
    test "runs tests after input" do
      in_fixture("test_stale", fn ->
        port = mix_port(~w[test --stale --listen-on-stdin])

        assert receive_until_match(port, "seed", "") =~ "2 tests"

        Port.command(port, "\n")

        assert receive_until_match(port, "No stale tests", "") =~ "Restarting..."
      end)
    end

    test "does not exit on compilation failure" do
      in_fixture("test_stale", fn ->
        File.write!("lib/b.ex", """
        defmodule B do
          def f, do: error_not_a_var
        end
        """)

        port = mix_port(~w[test --listen-on-stdin])

        assert receive_until_match(port, "error", "") =~ "lib/b.ex"

        File.write!("lib/b.ex", """
        defmodule B do
          def f, do: A.f
        end
        """)

        Port.command(port, "\n")

        assert receive_until_match(port, "seed", "") =~ "2 tests"

        File.write!("test/b_test_stale.exs", """
        defmodule BTest do
          use ExUnit.Case

          test "f" do
            assert B.f() == error_not_a_var
          end
        end
        """)

        Port.command(port, "\n")

        message = "undefined function error_not_a_var"
        assert receive_until_match(port, message, "") =~ "test/b_test_stale.exs"

        File.write!("test/b_test_stale.exs", """
        defmodule BTest do
          use ExUnit.Case

          test "f" do
            assert B.f() == :ok
          end
        end
        """)

        Port.command(port, "\n")

        assert receive_until_match(port, "seed", "") =~ "2 tests"
      end)
    end
  end

  describe "--partitions" do
    test "splits tests into partitions" do
      in_fixture("test_stale", fn ->
        assert mix(["test", "--partitions", "3", "--cover"], [{"MIX_TEST_PARTITION", "1"}]) =~
                 "1 test, 0 failures"

        assert mix(["test", "--partitions", "3", "--cover"], [{"MIX_TEST_PARTITION", "2"}]) =~
                 "1 test, 0 failures"

        assert mix(["test", "--partitions", "3", "--cover"], [{"MIX_TEST_PARTITION", "3"}]) =~
                 "There are no tests to run"

        assert File.regular?("cover/1.coverdata")
        assert File.regular?("cover/2.coverdata")
        refute File.regular?("cover/3.coverdata")

        assert mix(["test.coverage"]) == """
               Importing cover results: cover/1.coverdata
               Importing cover results: cover/2.coverdata

               Percentage | Module
               -----------|--------------------------
                  100.00% | A
                  100.00% | B
               -----------|--------------------------
                  100.00% | Total

               Generated HTML coverage results in \"cover\" directory
               """
      end)
    end

    test "raises when no partition is given even with Mix.shell() change" do
      in_fixture("test_stale", fn ->
        File.write!("test/test_helper.exs", """
        Mix.shell(Mix.Shell.Process)
        ExUnit.start()
        """)

        assert_run_output(
          ["--partitions", "4"],
          "The MIX_TEST_PARTITION environment variable must be set"
        )
      end)
    end
  end

  describe "logs and errors" do
    test "logs test absence for a project with no test paths" do
      in_fixture("test_stale", fn ->
        File.rm_rf!("test")

        assert_run_output("There are no tests to run")
      end)
    end

    test "raises when no test runs even with Mix.shell() change" do
      in_fixture("test_stale", fn ->
        File.write!("test/test_helper.exs", """
        Mix.shell(Mix.Shell.Process)
        ExUnit.start()
        """)

        assert_run_output(
          ["--only", "unknown"],
          "The --only option was given to \"mix test\" but no test was executed"
        )
      end)
    end

    test "raises an exception if line numbers are given with multiple files" do
      in_fixture("test_stale", fn ->
        assert_run_output(
          [
            "test/a_test_stale.exs",
            "test/b_test_stale.exs:4"
          ],
          "Line numbers can only be used when running a single test file"
        )
      end)
    end

    test "umbrella with file path" do
      in_fixture("umbrella_test", fn ->
        # Run false positive test first so at least the code is compiled
        # and we can perform more aggressive assertions later
        assert mix(["test", "apps/unknown_app/test"]) =~ """
               ==> bar
               Paths given to "mix test" did not match any directory/file: apps/unknown_app/test
               ==> foo
               Paths given to "mix test" did not match any directory/file: apps/unknown_app/test
               """

        output = mix(["test", "apps/bar/test/bar_tests.exs"])

        assert output =~ """
               ==> bar
               ...
               """

        refute output =~ "==> foo"
        refute output =~ "Paths given to \"mix test\" did not match any directory/file"

        output = mix(["test", "apps/bar/test/bar_tests.exs:10"])

        assert output =~ """
               ==> bar
               Excluding tags: [:test]
               Including tags: [line: \"10\"]

               .
               """

        refute output =~ "==> foo"
        refute output =~ "Paths given to \"mix test\" did not match any directory/file"
      end)
    end
  end

  describe "--warnings-as-errors" do
    test "fail on warning in tests" do
      in_fixture("test_stale", fn ->
        File.write!("lib/warning.ex", """
        unused_compile_var = 1
        """)

        File.write!("test/warning_test.exs", """
        defmodule WarningTest do
          use ExUnit.Case

          test "warning" do
            unused_test_var = 1
          end
        end
        """)

        output = mix(["test", "--warnings-as-errors", "test/warning_test.exs"])
        assert output =~ "variable \"unused_compile_var\" is unused"
        assert output =~ "variable \"unused_test_var\" is unused"
        assert output =~ "Compilation failed due to warnings"
      end)
    end
  end

  defp receive_until_match(port, expected, acc) do
    receive do
      {^port, {:data, output}} ->
        acc = acc <> output

        if output =~ expected do
          acc
        else
          receive_until_match(port, expected, acc)
        end
    end
  end

  defp set_all_mtimes(time \\ {{2010, 1, 1}, {0, 0, 0}}) do
    Enum.each(Path.wildcard("**", match_dot: true), &File.touch!(&1, time))
  end

  defp assert_stale_run_output(opts \\ [], expected) do
    assert_run_output(["--stale" | opts], expected)
  end

  defp assert_run_output(opts \\ [], expected) do
    assert mix(["test" | opts]) =~ expected
  end
end

Code.require_file("../../test_helper.exs", __DIR__)

defmodule Mix.Tasks.TestTest do
  use MixTest.Case

  describe "ex_unit_opts/1" do
    test "returns ex unit options" do
      assert ex_unit_opts_from_given(unknown: "ok", seed: 13) == [seed: 13]
    end

    test "returns includes and excludes" do
      included = [include: [:focus, key: "val"]]
      assert ex_unit_opts_from_given(include: "focus", include: "key:val") == included

      excluded = [exclude: [:focus, key: "val"]]
      assert ex_unit_opts_from_given(exclude: "focus", exclude: "key:val") == excluded
    end

    test "translates :only into includes and excludes" do
      assert ex_unit_opts_from_given(only: "focus") == [include: [:focus], exclude: [:test]]

      only = [include: [:focus, :special], exclude: [:test]]
      assert ex_unit_opts_from_given(only: "focus", include: "special") == only
    end

    test "translates :color into list containing an enabled key-value pair" do
      assert ex_unit_opts_from_given(color: false) == [colors: [enabled: false]]
      assert ex_unit_opts_from_given(color: true) == [colors: [enabled: true]]
    end

    test "translates :formatter into list of modules" do
      assert ex_unit_opts_from_given(formatter: "A.B") == [formatters: [A.B]]
    end

    test "includes some default options" do
      assert ex_unit_opts([]) == [
               autorun: false,
               failures_manifest_file:
                 Path.join(Mix.Project.manifest_path(), ".mix_test_failures")
             ]
    end

    defp ex_unit_opts(opts) do
      {ex_unit_opts, _allowed_files} = Mix.Tasks.Test.process_ex_unit_opts(opts)
      ex_unit_opts
    end

    defp ex_unit_opts_from_given(passed) do
      passed
      |> ex_unit_opts()
      |> Keyword.drop([:failures_manifest_file, :autorun])
    end
  end

  describe "--stale" do
    test "runs all tests for first run, then none on second" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        assert_stale_run_output("""
        No stale tests
        """)
      end)
    end

    test "runs tests that depend on modified modules" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()
        File.touch!("lib/b.ex")

        assert_stale_run_output("1 test, 0 failures")

        set_all_mtimes()
        File.touch!("lib/a.ex")

        assert_stale_run_output("2 tests, 0 failures")
      end)
    end

    test "doesn't write manifest when there are failures" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()

        File.write!("lib/b.ex", """
        defmodule B do
          def f, do: :error
        end
        """)

        assert_stale_run_output("1 test, 1 failure")

        assert_stale_run_output("1 test, 1 failure")
      end)
    end

    test "runs tests that have changed" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()
        File.touch!("test/a_test_stale.exs")

        assert_stale_run_output("1 test, 0 failures")
      end)
    end

    test "runs tests that have changed test_helpers" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        set_all_mtimes()
        File.touch!("test/test_helper.exs")

        assert_stale_run_output("2 tests, 0 failures")
      end)
    end

    test "runs all tests no matter what with --force" do
      in_fixture("test_stale", fn ->
        assert_stale_run_output("2 tests, 0 failures")

        assert_stale_run_output(~w[--force], "2 tests, 0 failures")
      end)
    end
  end

  describe "--cover" do
    test "reports the coverage of each app's modules in an umbrella" do
      in_fixture("umbrella_test", fn ->
        output = mix(["test", "--cover"])

        assert output =~ "3 tests, 0 failures"

        # For bar, we do regular --cover and also test protocols
        assert output =~ """
               Generating cover results ...

               Percentage | Module
               -----------|--------------------------
                  100.00% | Bar.Protocol
                  100.00% | Bar.Protocol.BitString
               -----------|--------------------------
                  100.00% | Total
               """

        assert output =~ "1 test, 0 failures"

        # For foo, we do regular --cover and test it does not include bar
        assert output =~ """
               Generating cover results ...

               Percentage | Module
               -----------|--------------------------
                  100.00% | Foo
               -----------|--------------------------
                  100.00% | Total
               """
      end)
    end

    test "supports unified reports by using test.coverage" do
      in_fixture("umbrella_test", fn ->
        assert mix(["test", "--export-coverage", "default", "--cover"]) =~
                 "Run \"mix test.coverage\" once all exports complete"

        assert mix(["test.coverage"]) =~ """
               Importing cover results: apps/bar/cover/default.coverdata
               Importing cover results: apps/foo/cover/default.coverdata

               Percentage | Module
               -----------|--------------------------
                  100.00% | Bar
                  100.00% | Bar.Protocol
                  100.00% | Bar.Protocol.BitString
                  100.00% | Foo
               -----------|--------------------------
                  100.00% | Total
               """
      end)
    end
  end

  describe "--failed" do
    test "loads only files with failures and runs just the failures" do
      in_fixture("test_failed", fn ->
        loading_only_passing_test_msg = "loading OnlyPassingTest"

        # Run `mix test` once to record failures...
        output = mix(["test"])
        assert output =~ loading_only_passing_test_msg
        assert output =~ "4 tests, 2 failures"

        # `mix test --failed` runs only failed tests and avoids loading files with no failures
        output = mix(["test", "--failed"])
        refute output =~ loading_only_passing_test_msg
        assert output =~ "2 tests, 2 failures"

        # `mix test --failed` can be applied to a directory or file
        output = mix(["test", "test/passing_and_failing_test_failed.exs", "--failed"])
        assert output =~ "1 test, 1 failure"

        # `--failed` composes with an `--only` filter by running the intersection.
        # Of the failing tests, 1 is tagged with `@tag :foo`.
        # Of the passing tests, 1 is tagged with `@tag :foo`.
        # But only the failing test with that tag should run.
        output = mix(["test", "--failed", "--only", "foo"])
        assert output =~ "2 tests, 1 failure, 1 excluded"

        # Run again to give it a chance to record as passed
        System.put_env("PASS_FAILING_TESTS", "true")
        assert mix(["test", "--failed"]) =~ "2 tests, 0 failures"

        # Nothing should get run if we try it again since everything is passing.
        output = mix(["test", "--failed"])
        assert output =~ "No pending --failed tests, re-running all available tests..."
        assert output =~ "4 tests, 0 failures"

        # `--failed` and `--stale` cannot be combined
        output = mix(["test", "--failed", "--stale"])
        assert output =~ "Combining --failed and --stale is not supported"
      end)
    after
      System.delete_env("PASS_FAILING_TESTS")
    end
  end

  describe "--listen-on-stdin" do
    test "runs tests after input" do
      in_fixture("test_stale", fn ->
        port = mix_port(~w[test --stale --listen-on-stdin])

        assert receive_until_match(port, "seed", "") =~ "2 tests"

        Port.command(port, "\n")

        assert receive_until_match(port, "No stale tests", "") =~ "Restarting..."
      end)
    end

    test "does not exit on compilation failure" do
      in_fixture("test_stale", fn ->
        File.write!("lib/b.ex", """
        defmodule B do
          def f, do: error_not_a_var
        end
        """)

        port = mix_port(~w[test --listen-on-stdin])

        assert receive_until_match(port, "error", "") =~ "lib/b.ex"

        File.write!("lib/b.ex", """
        defmodule B do
          def f, do: A.f
        end
        """)

        Port.command(port, "\n")

        assert receive_until_match(port, "seed", "") =~ "2 tests"

        File.write!("test/b_test_stale.exs", """
        defmodule BTest do
          use ExUnit.Case

          test "f" do
            assert B.f() == error_not_a_var
          end
        end
        """)

        Port.command(port, "\n")

        message = "undefined function error_not_a_var"
        assert receive_until_match(port, message, "") =~ "test/b_test_stale.exs"

        File.write!("test/b_test_stale.exs", """
        defmodule BTest do
          use ExUnit.Case

          test "f" do
            assert B.f() == :ok
          end
        end
        """)

        Port.command(port, "\n")

        assert receive_until_match(port, "seed", "") =~ "2 tests"
      end)
    end
  end

  describe "--partitions" do
    test "splits tests into partitions" do
      in_fixture("test_stale", fn ->
        assert mix(["test", "--partitions", "3", "--cover"], [{"MIX_TEST_PARTITION", "1"}]) =~
                 "1 test, 0 failures"

        assert mix(["test", "--partitions", "3", "--cover"], [{"MIX_TEST_PARTITION", "2"}]) =~
                 "1 test, 0 failures"

        assert mix(["test", "--partitions", "3", "--cover"], [{"MIX_TEST_PARTITION", "3"}]) =~
                 "There are no tests to run"

        assert File.regular?("cover/1.coverdata")
        assert File.regular?("cover/2.coverdata")
        refute File.regular?("cover/3.coverdata")

        assert mix(["test.coverage"]) == """
               Importing cover results: cover/1.coverdata
               Importing cover results: cover/2.coverdata

               Percentage | Module
               -----------|--------------------------
                  100.00% | A
                  100.00% | B
               -----------|--------------------------
                  100.00% | Total

               Generated HTML coverage results in \"cover\" directory
               """
      end)
    end

    test "raises when no partition is given even with Mix.shell() change" do
      in_fixture("test_stale", fn ->
        File.write!("test/test_helper.exs", """
        Mix.shell(Mix.Shell.Process)
        ExUnit.start()
        """)

        assert_run_output(
          ["--partitions", "4"],
          "The MIX_TEST_PARTITION environment variable must be set"
        )
      end)
    end
  end

  describe "logs and errors" do
    test "logs test absence for a project with no test paths" do
      in_fixture("test_stale", fn ->
        File.rm_rf!("test")

        assert_run_output("There are no tests to run")
      end)
    end

    test "raises when no test runs even with Mix.shell() change" do
      in_fixture("test_stale", fn ->
        File.write!("test/test_helper.exs", """
        Mix.shell(Mix.Shell.Process)
        ExUnit.start()
        """)

        assert_run_output(
          ["--only", "unknown"],
          "The --only option was given to \"mix test\" but no test was executed"
        )
      end)
    end

    test "raises an exception if line numbers are given with multiple files" do
      in_fixture("test_stale", fn ->
        assert_run_output(
          [
            "test/a_test_stale.exs",
            "test/b_test_stale.exs:4"
          ],
          "Line numbers can only be used when running a single test file"
        )
      end)
    end

    test "umbrella with file path" do
      in_fixture("umbrella_test", fn ->
        # Run false positive test first so at least the code is compiled
        # and we can perform more aggressive assertions later
        assert mix(["test", "apps/unknown_app/test"]) =~ """
               ==> bar
               Paths given to "mix test" did not match any directory/file: apps/unknown_app/test
               ==> foo
               Paths given to "mix test" did not match any directory/file: apps/unknown_app/test
               """

        output = mix(["test", "apps/bar/test/bar_tests.exs"])

        assert output =~ """
               ==> bar
               ...
               """

        refute output =~ "==> foo"
        refute output =~ "Paths given to \"mix test\" did not match any directory/file"

        output = mix(["test", "apps/bar/test/bar_tests.exs:10"])

        assert output =~ """
               ==> bar
               Excluding tags: [:test]
               Including tags: [line: \"10\"]

               .
               """

        refute output =~ "==> foo"
        refute output =~ "Paths given to \"mix test\" did not match any directory/file"
      end)
    end
  end

  describe "--warnings-as-errors" do
    test "fail on warning in tests" do
      in_fixture("test_stale", fn ->
        File.write!("lib/warning.ex", """
        unused_compile_var = 1
        """)

        File.write!("test/warning_test.exs", """
        defmodule WarningTest do
          use ExUnit.Case

          test "warning" do
            unused_test_var = 1
          end
        end
        """)

        output = mix(["test", "--warnings-as-errors", "test/warning_test.exs"])
        assert output =~ "variable \"unused_compile_var\" is unused"
        assert output =~ "variable \"unused_test_var\" is unused"
        assert output =~ "Compilation failed due to warnings"
      end)
    end
  end

  defp receive_until_match(port, expected, acc) do
    receive do
      {^port, {:data, output}} ->
        acc = acc <> output

        if output =~ expected do
          acc
        else
          receive_until_match(port, expected, acc)
        end
    end
  end

  defp set_all_mtimes(time \\ {{2010, 1, 1}, {0, 0, 0}}) do
    Enum.each(Path.wildcard("**", match_dot: true), &File.touch!(&1, time))
  end

  defp assert_stale_run_output(opts \\ [], expected) do
    assert_run_output(["--stale" | opts], expected)
  end

  defp assert_run_output(opts \\ [], expected) do
    assert mix(["test" | opts]) =~ expected
  end
end


Simplify

Simplify

defmodule Core.Layout do

  @core_fields ["id", "identifier", "shortDescription", "type", "geometry", "georeference", "groups"]

  def to_layouted_document(doc, %{ "de" => configuration }) do

    %{ "groups" => config_groups } = Core.CategoryTreeList.find_by_name(doc["resource"]["type"], configuration)

    doc
    |> update_in(["resource"], &(add_groups(&1, config_groups)))
    |> update_in(["resource"], &(Map.take(&1, @core_fields)))
  end

  defp add_groups(resource, config_groups) do

    put_in(resource, ["groups"], scan_and_add(&scan_group/2, config_groups, resource))
  end

  defp scan_group(config_group, resource) do

    %{
      "fields" => config_group_fields,
      "name" => config_group_name,
      "relations" => config_group_relations
    } = config_group

    fields = scan_and_add(&scan_field/2, config_group_fields, resource)
    relations = scan_and_add(&scan_relation/2, config_group_relations, resource)

    if length(fields) == 0 and length(relations) == 0 do
      nil
    else
      %{
        fields: fields,
        relations: relations,
        name: config_group_name
      }
    end
  end

  defp scan_relation(%{ "name" => config_relation_name}, resource) do

    if Map.has_key?(get_in(resource, ["relations"]), config_relation_name) do
      %{
        name: config_relation_name,
        targets: get_in(resource, ["relations", config_relation_name])
      }
    else
      nil
    end
  end

  defp scan_field(%{ "name" => config_field_name }, resource) do

    if Map.has_key?(resource, config_field_name) do
      %{
        name: config_field_name,
        value: get_in(resource, [config_field_name])
      }
    else
      nil
    end
  end

  defp scan_and_add(scan_f, coll, resource) do
    Enum.reduce(coll, [],
      fn coll_item, out_coll ->
        append(out_coll, apply(scan_f, [coll_item, resource]))
      end
    )
  end

  defp append(list, nil), do: list
  defp append(list, item), do: list ++ [item]
end

defmodule Core.Layout do

  @core_fields ["id", "identifier", "shortDescription", "type", "geometry", "georeference", "groups"]

  def to_layouted_document(doc, %{ "de" => configuration }) do

    %{ "groups" => config_groups } = Core.CategoryTreeList.find_by_name(doc["resource"]["type"], configuration)

    doc
    |> update_in(["resource"], &(add_groups(&1, config_groups)))
    |> update_in(["resource"], &(Map.take(&1, @core_fields)))
  end

  defp add_groups(resource, config_groups) do

    groups = scan_and_add(&scan_group/2, config_groups, put_in(resource, ["groups"], []))
    put_in(resource, ["groups"], groups)
  end

  defp scan_group(config_group, resource) do

    %{
      "fields" => config_group_fields,
      "name" => config_group_name,
      "relations" => config_group_relations
    } = config_group

    fields = scan_and_add(&scan_field/2, config_group_fields, resource)
    relations = scan_and_add(&scan_relation/2, config_group_relations, resource)

    if length(fields) == 0 and length(relations) == 0 do
      nil
    else
      %{
        fields: fields,
        relations: relations,
        name: config_group_name
      }
    end
  end

  defp scan_relation(%{ "name" => config_relation_name}, resource) do

    if Map.has_key?(get_in(resource, ["relations"]), config_relation_name) do
      %{
        name: config_relation_name,
        targets: get_in(resource, ["relations", config_relation_name])
      }
    else
      nil
    end
  end

  defp scan_field(%{ "name" => config_field_name }, resource) do

    if Map.has_key?(resource, config_field_name) do
      %{
        name: config_field_name,
        value: get_in(resource, [config_field_name])
      }
    else
      nil
    end
  end

  defp scan_and_add(scan_f, coll, resource) do
    Enum.reduce(coll, [],
      fn coll_item, out_coll ->
        append(out_coll, apply(scan_f, [coll_item, resource]))
      end
    )
  end

  defp append(list, nil), do: list
  defp append(list, item), do: list ++ [item]
end