Application.app_dir for template path in new task

defmodule Mix.Tasks.Phoenix.New do
  use Mix.Task
  alias Phoenix.Naming

  @shortdoc "Creates Phoenix application"

  @template_priv_dir "template"

  @doc """
  Creates Phoenix application.
  """
  def run([name, path]) do
    application_name = Naming.underscore(name)
    application_module = Naming.camelize(application_name)
    project_path = make_project_path(path, application_name)

    bindings = [application_name: application_name,
                application_module: application_module,
                secret_key_base: random_string(64)]

    Mix.Generator.create_directory(project_path)

    for source_path <- template_files do
      destination_path = make_destination_path(project_path, source_path, application_name)

      if File.dir?(source_path) do
        Mix.Generator.create_directory(destination_path)
      else
        contents = eval_file(source_path, bindings)
        Mix.Generator.create_file(destination_path, contents)
      end
    end
  end

  @doc """
  Display instructions on how to create a Phoenix application.
  """
  def run(_) do
    Mix.shell.info """
    Supply application name and destination path.

    e.g.
      mix phoenix.new photo_blog /home/johndoe/
    """
  end

  defp eval_file(source_path, bindings) do
    if String.ends_with?(source_path, ".html.eex") do
      File.read!(source_path)
    else
      EEx.eval_file(source_path, bindings)
    end
  end

  def random_string(length) do
    :crypto.strong_rand_bytes(length) |> Base.encode64
  end

  defp make_project_path(path, application_name) do
    basename = Naming.underscore(Path.basename(path))

    if basename == application_name do
      path
    else
      Path.join(path, application_name)
    end
  end

  defp template_files do
    file_pattern = Path.join(template_path, "**/*")

    Path.wildcard(file_pattern, match_dot: true)
  end

  defp make_destination_path(project_path, file, application_name) do
    new_path = String.replace(file, "application_name", application_name)
    relative_path = Path.relative_to(new_path, template_path)

    Path.join(project_path, relative_path)
  end

  def template_path do
    Path.join(Application.app_dir(:phoenix, "priv"), @template_priv_dir)
  end
end

defmodule Mix.Tasks.Phoenix.New do
  use Mix.Task
  alias Phoenix.Naming

  @shortdoc "Creates Phoenix application"

  @template_dir "priv/template"

  @doc """
  Creates Phoenix application.
  """
  def run([name, path]) do
    application_name = Naming.underscore(name)
    application_module = Naming.camelize(application_name)
    project_path = make_project_path(path, application_name)

    bindings = [application_name: application_name,
                application_module: application_module,
                secret_key_base: random_string(64)]

    Mix.Generator.create_directory(project_path)

    for source_path <- template_files do
      destination_path = make_destination_path(project_path, source_path, application_name)

      if File.dir?(source_path) do
        Mix.Generator.create_directory(destination_path)
      else
        contents = eval_file(source_path, bindings)
        Mix.Generator.create_file(destination_path, contents)
      end
    end
  end

  @doc """
  Display instructions on how to create a Phoenix application.
  """
  def run(_) do
    Mix.shell.info """
    Supply application name and destination path.

    e.g.
      mix phoenix.new photo_blog /home/johndoe/
    """
  end

  defp eval_file(source_path, bindings) do
    if String.ends_with?(source_path, ".html.eex") do
      File.read!(source_path)
    else
      EEx.eval_file(source_path, bindings)
    end
  end

  def random_string(length) do
    :crypto.strong_rand_bytes(length) |> Base.encode64
  end

  defp make_project_path(path, application_name) do
    basename = Naming.underscore(Path.basename(path))

    if basename == application_name do
      path
    else
      Path.join(path, application_name)
    end
  end

  defp template_files do
    file_pattern = Path.join(template_path, "**/*")

    Path.wildcard(file_pattern, match_dot: true)
  end

  defp make_destination_path(project_path, file, application_name) do
    new_path = String.replace(file, "application_name", application_name)
    relative_path = Path.relative_to(new_path, template_path)

    Path.join(project_path, relative_path)
  end

  defp template_path do
    Path.join(File.cwd!, @template_dir)
  end
end


Avoid filesystem race condition in test (#9474)

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

defmodule Mix.UmbrellaTest do
  use MixTest.Case

  test "apps_paths" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      assert Mix.Project.apps_paths() == nil

      Mix.Project.in_project(:umbrella, ".", fn _ ->
        assert Mix.Project.apps_paths() == %{bar: "apps/bar", foo: "apps/foo"}

        assert_received {:mix_shell, :error,
                         ["warning: path \"apps/dont_error_on_missing_mixfile\"" <> _]}

        refute_received {:mix_shell, :error, ["warning: path \"apps/dont_error_on_files\"" <> _]}
      end)
    end)
  end

  test "apps_paths with selection" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", [apps: [:foo, :bar]], fn _ ->
        File.mkdir_p!("apps/errors")
        File.write!("apps/errors/mix.exs", "raise :oops")
        assert Mix.Project.apps_paths() == %{bar: "apps/bar", foo: "apps/foo"}
      end)
    end)
  end

  test "umbrella app dir and the app name defined in mix.exs should be equal" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :baz,
             version: "0.1.0",
             deps: []]
          end
        end
        """)

        assert_raise Mix.Error, ~r/^Umbrella app :baz is located at directory bar/, fn ->
          Mix.Task.run("deps")
        end
      end)
    end)
  end

  test "compiles umbrella" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("deps")
        assert_received {:mix_shell, :info, ["* bar (apps/bar) (mix)"]}
        assert_received {:mix_shell, :info, ["* foo (apps/foo) (mix)"]}

        # Ensure we can compile and run checks
        Mix.Task.run("deps.compile")
        Mix.Task.run("deps.loadpaths")
        Mix.Task.run("compile", ["--verbose"])

        assert_received {:mix_shell, :info, ["==> bar"]}
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert File.regular?("_build/dev/lib/bar/ebin/Elixir.Bar.beam")
        assert_received {:mix_shell, :info, ["==> foo"]}
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert File.regular?("_build/dev/lib/foo/ebin/Elixir.Foo.beam")

        # Ensure foo was loaded and in the same env as Mix.env
        assert_received {:mix_shell, :info, [":foo env is dev"]}
        assert_received {:mix_shell, :info, [":bar env is dev"]}

        Mix.Task.clear()
        Mix.Task.run("app.start", ["--no-compile"])
      end)
    end)
  end

  test "compiles umbrella with protocol consolidation" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile", ["--verbose"])
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert File.regular?("_build/dev/consolidated/Elixir.Enumerable.beam")
        purge([Enumerable])

        assert Mix.Tasks.App.Start.run([])
        assert Protocol.consolidated?(Enumerable)
      end)
    end)
  end

  test "recompiles umbrella on config change" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile", [])
        bar = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        foo = File.stat!("_build/dev/lib/foo/.mix/compile.elixir").mtime

        ensure_touched("mix.exs", max(foo, bar))

        Mix.Task.clear()
        Mix.Task.run("compile", [])
        assert File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime > bar
        assert File.stat!("_build/dev/lib/foo/.mix/compile.elixir").mtime > foo
      end)
    end)
  end

  test "recursively compiles umbrella with protocol consolidation" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        defmodule Elixir.Mix.Tasks.Umbrella.Recur do
          use Mix.Task
          @recursive true

          def run(_) do
            assert Mix.Task.recursing?()
            Mix.Task.run("compile", ["--verbose"])
          end
        end

        Mix.Task.run("umbrella.recur")
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert File.regular?("_build/dev/consolidated/Elixir.Enumerable.beam")
        purge([Enumerable])

        assert Mix.Tasks.App.Start.run([])
        assert Protocol.consolidated?(Enumerable)
      end)
    end)
  end

  defmodule UmbrellaDeps do
    def project do
      [apps_path: "apps", deps: [{:some_dep, path: "deps/some_dep"}]]
    end
  end

  test "loads umbrella dependencies" do
    Mix.Project.push(UmbrellaDeps)

    in_fixture("umbrella_dep/deps/umbrella", fn ->
      File.mkdir_p!("deps/some_dep/ebin")
      File.mkdir_p!("_build/dev/lib/some_dep/ebin")
      File.mkdir_p!("_build/dev/lib/foo/ebin")
      File.mkdir_p!("_build/dev/lib/bar/ebin")

      Mix.Task.run("loadpaths", ["--no-deps-check", "--no-elixir-version-check"])
      assert to_charlist(Path.expand("_build/dev/lib/some_dep/ebin")) in :code.get_path()
      assert to_charlist(Path.expand("_build/dev/lib/foo/ebin")) in :code.get_path()
      assert to_charlist(Path.expand("_build/dev/lib/bar/ebin")) in :code.get_path()
    end)
  end

  test "loads umbrella child dependencies in all environments" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:git_repo, git: MixTest.Case.fixture_path("git_repo"), only: :other}]]
          end
        end
        """)

        # Does not fetch when filtered
        Mix.Tasks.Deps.Get.run(["--only", "dev"])
        refute_received {:mix_shell, :info, ["* Getting git_repo" <> _]}

        # But works across all environments
        Mix.Tasks.Deps.Get.run([])
        assert_received {:mix_shell, :info, ["* Getting git_repo" <> _]}

        # Does not show by default
        Mix.Tasks.Deps.run([])
        refute_received {:mix_shell, :info, ["* git_repo" <> _]}

        # But shows on proper environment
        Mix.env(:other)
        Mix.Tasks.Deps.run([])
        assert_received {:mix_shell, :info, ["* git_repo " <> _]}
      end)
    end)
  after
    Mix.env(:test)
  end

  test "loads umbrella child optional dependencies" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:git_repo, git: MixTest.Case.fixture_path("git_repo"), optional: true}]]
          end
        end
        """)

        Mix.Tasks.Deps.run([])
        assert_received {:mix_shell, :info, ["* git_repo " <> _]}
      end)
    end)
  end

  test "loads umbrella sibling dependencies with :in_umbrella" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:foo, in_umbrella: true}]]
          end
        end
        """)

        # Running from umbrella should not cause conflicts
        Mix.Tasks.Deps.Get.run([])
        Mix.Tasks.Run.run([])
      end)
    end)
  end

  test "conflicts with umbrella sibling dependencies in :in_umbrella" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:foo, in_umbrella: true, env: :unknown}]]
          end
        end
        """)

        assert_raise Mix.Error, fn ->
          Mix.Tasks.Deps.Get.run([])
        end

        assert_received {:mix_shell, :error, ["Dependencies have diverged:"]}

        assert_received {:mix_shell, :error,
                         ["  the dependency foo in mix.exs is overriding a child" <> message]}

        assert message =~ "Please remove the conflicting options from your definition"
      end)
    end)
  end

  ## Umbrellas as a dependency

  test "list deps for umbrella as dependency" do
    in_fixture("umbrella_dep", fn ->
      Mix.Project.in_project(:umbrella_dep, ".", fn _ ->
        Mix.Task.run("deps")
        assert_received {:mix_shell, :info, ["* umbrella (deps/umbrella) (mix)"]}
        assert_received {:mix_shell, :info, ["* foo (apps/foo) (mix)"]}
      end)
    end)
  end

  test "compile for umbrella as dependency" do
    in_fixture("umbrella_dep", fn ->
      Mix.Project.in_project(:umbrella_dep, ".", fn _ ->
        Mix.Task.run("deps.compile")
        assert Bar.bar() == "hello world"
      end)
    end)
  end

  defmodule CycleDeps do
    def project do
      [
        app: :umbrella_dep,
        deps: [
          {:bar, path: "deps/umbrella/apps/bar"},
          {:umbrella, path: "deps/umbrella"}
        ]
      ]
    end
  end

  test "handles dependencies with cycles" do
    Mix.Project.push(CycleDeps)

    in_fixture("umbrella_dep", fn ->
      assert Enum.map(Mix.Dep.load_on_environment([]), & &1.app) == [:foo, :bar, :umbrella]
    end)
  end

  test "handles dependencies with cycles and overridden deps" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/foo/mix.exs", """
        defmodule Foo.MixProject do
          use Mix.Project

          def project do
            # Ensure we have the proper environment
            :dev = Mix.env

            [app: :foo,
             version: "0.1.0",
             deps: [{:bar, in_umbrella: true}]]
          end
        end
        """)

        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            # Ensure we have the proper environment
            :dev = Mix.env

            [app: :bar,
             version: "0.1.0",
             deps: [{:a, path: "deps/a"},
                    {:b, path: "deps/b"}]]
          end
        end
        """)

        assert Enum.map(Mix.Dep.load_on_environment([]), & &1.app) == [:a, :b, :bar, :foo]
      end)
    end)
  end

  test "uses dependency aliases" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             aliases: ["compile.all": fn _ -> Mix.shell.info "no compile bar" end]]
          end
        end
        """)

        Mix.Task.run("compile", ["--verbose"])
        assert_receive {:mix_shell, :info, ["no compile bar"]}
        refute_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "halts when sibling fails to compile" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/foo/lib/foo.ex", "raise ~s[oops]")

        ExUnit.CaptureIO.capture_io(fn ->
          assert catch_exit(Mix.Task.run("compile", ["--verbose"]))
        end)

        refute_received {:mix_shell, :info, ["Generated foo app"]}
        refute_received {:mix_shell, :info, ["Generated bar app"]}
        refute Code.ensure_loaded?(Bar)
      end)
    end)
  end

  test "recompiles after runtime path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        Mix.Task.run("compile", ["--verbose"])
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert File.regular?("_build/dev/lib/foo/ebin/Elixir.Foo.beam")
        assert File.regular?("_build/dev/lib/bar/ebin/Elixir.Bar.beam")

        # Noop by default
        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:noop, []}
        Mix.Shell.Process.flush()

        # Ok but no compilation when there is no runtime dependency
        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)

        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/.mix/compile.elixir", mtime)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        refute_received {:mix_shell, :info, ["Compiled " <> _]}

        # Add runtime dependency
        File.write!("lib/bar.ex", """
        defmodule Bar do
          def bar, do: Foo.foo
        end
        """)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_received {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "recompiles after compile time path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        Mix.Task.run("compile", ["--verbose"])

        # Add compile time dependency
        File.write!("lib/bar.ex", "defmodule Bar, do: Foo.foo")

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}

        # Recompiles for compile time dependencies
        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)
        ensure_touched("_build/dev/lib/foo/.mix/compile.elixir", mtime)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "recompiles after struct path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        File.write!("../foo/lib/foo.ex", "defmodule Foo, do: defstruct [:bar]")

        Mix.Task.run("compile", ["--verbose"])

        # Add struct dependency
        File.write!("lib/bar.ex", "defmodule Bar, do: %Foo{bar: true}")

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}

        # Recompiles for struct dependencies
        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)
        ensure_touched("_build/dev/lib/foo/.mix/compile.elixir", mtime)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "reconsolidates after path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        # Add a protocol dependency
        File.write!("../foo/lib/foo.ex", """
        defprotocol Foo do
          def foo(arg)
        end
        defimpl Foo, for: List do
          def foo(list), do: list
        end
        """)

        Mix.Task.run("compile")
        assert File.regular?("_build/dev/lib/bar/consolidated/Elixir.Foo.beam")
        assert Mix.Tasks.Compile.Protocols.run([]) == :noop

        # Mark protocol as outdated
        File.touch!("_build/dev/lib/bar/consolidated/Elixir.Foo.beam", {{2010, 1, 1}, {0, 0, 0}})

        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.protocols").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)

        assert Mix.Tasks.Compile.Protocols.run([]) == :ok

        # Check new timestamp
        mtime = File.stat!("_build/dev/lib/bar/consolidated/Elixir.Foo.beam").mtime
        assert mtime > {{2010, 1, 1}, {0, 0, 0}}
      end)
    end)
  end

  test "reconsolidates using umbrella parent information on shared _build" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      File.write!("apps/bar/lib/bar.ex", """
      defprotocol Bar do
        def bar(arg)
      end
      defimpl Bar, for: List do
        def bar(list), do: list
      end
      """)

      Mix.Project.in_project(:foo, "apps/foo", [build_path: "../../_build"], fn _ ->
        Mix.Task.run("compile.protocols")
        refute Code.ensure_loaded?(Bar)
      end)

      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile.protocols")
        Mix.Task.run("app.start")
        assert Protocol.consolidated?(Bar)
      end)
    end)
  end

  test "reconsolidates using umbrella child information on shared _build" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      File.write!("apps/bar/lib/bar.ex", """
      defprotocol Bar do
        def foo(arg)
      end
      defimpl Bar, for: List do
        def foo(list), do: list
      end
      """)

      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile.protocols")
      end)

      # Emulate the dependency being removed
      Mix.Project.in_project(:foo, "apps/foo", [build_path: "../../_build", deps: []], fn _ ->
        File.rm_rf("../../_build/dev/lib/bar")
        Mix.Task.run("compile.protocols")
      end)
    end)
  end

  test "apps cannot refer to themselves as a dep" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:bar, in_umbrella: true}]]
          end
        end
        """)

        assert_raise Mix.Error, "App bar lists itself as a dependency", fn ->
          Mix.Task.run("deps.get", ["--verbose"]) == [:ok, :ok]
        end
      end)
    end)
  end
end

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

defmodule Mix.UmbrellaTest do
  use MixTest.Case

  test "apps_paths" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      assert Mix.Project.apps_paths() == nil

      Mix.Project.in_project(:umbrella, ".", fn _ ->
        assert Mix.Project.apps_paths() == %{bar: "apps/bar", foo: "apps/foo"}

        assert_received {:mix_shell, :error,
                         ["warning: path \"apps/dont_error_on_missing_mixfile\"" <> _]}

        refute_received {:mix_shell, :error, ["warning: path \"apps/dont_error_on_files\"" <> _]}
      end)
    end)
  end

  test "apps_paths with selection" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", [apps: [:foo, :bar]], fn _ ->
        File.mkdir_p!("apps/errors")
        File.write!("apps/errors/mix.exs", "raise :oops")
        assert Mix.Project.apps_paths() == %{bar: "apps/bar", foo: "apps/foo"}
      end)
    end)
  end

  test "umbrella app dir and the app name defined in mix.exs should be equal" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :baz,
             version: "0.1.0",
             deps: []]
          end
        end
        """)

        assert_raise Mix.Error, ~r/^Umbrella app :baz is located at directory bar/, fn ->
          Mix.Task.run("deps")
        end
      end)
    end)
  end

  test "compiles umbrella" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("deps")
        assert_received {:mix_shell, :info, ["* bar (apps/bar) (mix)"]}
        assert_received {:mix_shell, :info, ["* foo (apps/foo) (mix)"]}

        # Ensure we can compile and run checks
        Mix.Task.run("deps.compile")
        Mix.Task.run("deps.loadpaths")
        Mix.Task.run("compile", ["--verbose"])

        assert_received {:mix_shell, :info, ["==> bar"]}
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert File.regular?("_build/dev/lib/bar/ebin/Elixir.Bar.beam")
        assert_received {:mix_shell, :info, ["==> foo"]}
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert File.regular?("_build/dev/lib/foo/ebin/Elixir.Foo.beam")

        # Ensure foo was loaded and in the same env as Mix.env
        assert_received {:mix_shell, :info, [":foo env is dev"]}
        assert_received {:mix_shell, :info, [":bar env is dev"]}

        Mix.Task.clear()
        Mix.Task.run("app.start", ["--no-compile"])
      end)
    end)
  end

  test "compiles umbrella with protocol consolidation" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile", ["--verbose"])
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert File.regular?("_build/dev/consolidated/Elixir.Enumerable.beam")
        purge([Enumerable])

        assert Mix.Tasks.App.Start.run([])
        assert Protocol.consolidated?(Enumerable)
      end)
    end)
  end

  test "recompiles umbrella on conffig hange" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile", [])
        bar = File.stat!("_build/dev/lib/bar/ebin/Elixir.Bar.beam").mtime
        foo = File.stat!("_build/dev/lib/foo/ebin/Elixir.Foo.beam").mtime

        ensure_touched("mix.exs")

        Mix.Task.clear()
        Mix.Task.run("compile", [])
        assert File.stat!("_build/dev/lib/bar/ebin/Elixir.Bar.beam").mtime > bar
        assert File.stat!("_build/dev/lib/foo/ebin/Elixir.Foo.beam").mtime > foo
      end)
    end)
  end

  test "recursively compiles umbrella with protocol consolidation" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        defmodule Elixir.Mix.Tasks.Umbrella.Recur do
          use Mix.Task
          @recursive true

          def run(_) do
            assert Mix.Task.recursing?()
            Mix.Task.run("compile", ["--verbose"])
          end
        end

        Mix.Task.run("umbrella.recur")
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert File.regular?("_build/dev/consolidated/Elixir.Enumerable.beam")
        purge([Enumerable])

        assert Mix.Tasks.App.Start.run([])
        assert Protocol.consolidated?(Enumerable)
      end)
    end)
  end

  defmodule UmbrellaDeps do
    def project do
      [apps_path: "apps", deps: [{:some_dep, path: "deps/some_dep"}]]
    end
  end

  test "loads umbrella dependencies" do
    Mix.Project.push(UmbrellaDeps)

    in_fixture("umbrella_dep/deps/umbrella", fn ->
      File.mkdir_p!("deps/some_dep/ebin")
      File.mkdir_p!("_build/dev/lib/some_dep/ebin")
      File.mkdir_p!("_build/dev/lib/foo/ebin")
      File.mkdir_p!("_build/dev/lib/bar/ebin")

      Mix.Task.run("loadpaths", ["--no-deps-check", "--no-elixir-version-check"])
      assert to_charlist(Path.expand("_build/dev/lib/some_dep/ebin")) in :code.get_path()
      assert to_charlist(Path.expand("_build/dev/lib/foo/ebin")) in :code.get_path()
      assert to_charlist(Path.expand("_build/dev/lib/bar/ebin")) in :code.get_path()
    end)
  end

  test "loads umbrella child dependencies in all environments" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:git_repo, git: MixTest.Case.fixture_path("git_repo"), only: :other}]]
          end
        end
        """)

        # Does not fetch when filtered
        Mix.Tasks.Deps.Get.run(["--only", "dev"])
        refute_received {:mix_shell, :info, ["* Getting git_repo" <> _]}

        # But works across all environments
        Mix.Tasks.Deps.Get.run([])
        assert_received {:mix_shell, :info, ["* Getting git_repo" <> _]}

        # Does not show by default
        Mix.Tasks.Deps.run([])
        refute_received {:mix_shell, :info, ["* git_repo" <> _]}

        # But shows on proper environment
        Mix.env(:other)
        Mix.Tasks.Deps.run([])
        assert_received {:mix_shell, :info, ["* git_repo " <> _]}
      end)
    end)
  after
    Mix.env(:test)
  end

  test "loads umbrella child optional dependencies" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:git_repo, git: MixTest.Case.fixture_path("git_repo"), optional: true}]]
          end
        end
        """)

        Mix.Tasks.Deps.run([])
        assert_received {:mix_shell, :info, ["* git_repo " <> _]}
      end)
    end)
  end

  test "loads umbrella sibling dependencies with :in_umbrella" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:foo, in_umbrella: true}]]
          end
        end
        """)

        # Running from umbrella should not cause conflicts
        Mix.Tasks.Deps.Get.run([])
        Mix.Tasks.Run.run([])
      end)
    end)
  end

  test "conflicts with umbrella sibling dependencies in :in_umbrella" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:foo, in_umbrella: true, env: :unknown}]]
          end
        end
        """)

        assert_raise Mix.Error, fn ->
          Mix.Tasks.Deps.Get.run([])
        end

        assert_received {:mix_shell, :error, ["Dependencies have diverged:"]}

        assert_received {:mix_shell, :error,
                         ["  the dependency foo in mix.exs is overriding a child" <> message]}

        assert message =~ "Please remove the conflicting options from your definition"
      end)
    end)
  end

  ## Umbrellas as a dependency

  test "list deps for umbrella as dependency" do
    in_fixture("umbrella_dep", fn ->
      Mix.Project.in_project(:umbrella_dep, ".", fn _ ->
        Mix.Task.run("deps")
        assert_received {:mix_shell, :info, ["* umbrella (deps/umbrella) (mix)"]}
        assert_received {:mix_shell, :info, ["* foo (apps/foo) (mix)"]}
      end)
    end)
  end

  test "compile for umbrella as dependency" do
    in_fixture("umbrella_dep", fn ->
      Mix.Project.in_project(:umbrella_dep, ".", fn _ ->
        Mix.Task.run("deps.compile")
        assert Bar.bar() == "hello world"
      end)
    end)
  end

  defmodule CycleDeps do
    def project do
      [
        app: :umbrella_dep,
        deps: [
          {:bar, path: "deps/umbrella/apps/bar"},
          {:umbrella, path: "deps/umbrella"}
        ]
      ]
    end
  end

  test "handles dependencies with cycles" do
    Mix.Project.push(CycleDeps)

    in_fixture("umbrella_dep", fn ->
      assert Enum.map(Mix.Dep.load_on_environment([]), & &1.app) == [:foo, :bar, :umbrella]
    end)
  end

  test "handles dependencies with cycles and overridden deps" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/foo/mix.exs", """
        defmodule Foo.MixProject do
          use Mix.Project

          def project do
            # Ensure we have the proper environment
            :dev = Mix.env

            [app: :foo,
             version: "0.1.0",
             deps: [{:bar, in_umbrella: true}]]
          end
        end
        """)

        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            # Ensure we have the proper environment
            :dev = Mix.env

            [app: :bar,
             version: "0.1.0",
             deps: [{:a, path: "deps/a"},
                    {:b, path: "deps/b"}]]
          end
        end
        """)

        assert Enum.map(Mix.Dep.load_on_environment([]), & &1.app) == [:a, :b, :bar, :foo]
      end)
    end)
  end

  test "uses dependency aliases" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             aliases: ["compile.all": fn _ -> Mix.shell.info "no compile bar" end]]
          end
        end
        """)

        Mix.Task.run("compile", ["--verbose"])
        assert_receive {:mix_shell, :info, ["no compile bar"]}
        refute_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "halts when sibling fails to compile" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/foo/lib/foo.ex", "raise ~s[oops]")

        ExUnit.CaptureIO.capture_io(fn ->
          assert catch_exit(Mix.Task.run("compile", ["--verbose"]))
        end)

        refute_received {:mix_shell, :info, ["Generated foo app"]}
        refute_received {:mix_shell, :info, ["Generated bar app"]}
        refute Code.ensure_loaded?(Bar)
      end)
    end)
  end

  test "recompiles after runtime path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        Mix.Task.run("compile", ["--verbose"])
        assert_received {:mix_shell, :info, ["Generated foo app"]}
        assert_received {:mix_shell, :info, ["Generated bar app"]}
        assert File.regular?("_build/dev/lib/foo/ebin/Elixir.Foo.beam")
        assert File.regular?("_build/dev/lib/bar/ebin/Elixir.Bar.beam")

        # Noop by default
        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:noop, []}
        Mix.Shell.Process.flush()

        # Ok but no compilation when there is no runtime dependency
        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)

        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/.mix/compile.elixir", mtime)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        refute_received {:mix_shell, :info, ["Compiled " <> _]}

        # Add runtime dependency
        File.write!("lib/bar.ex", """
        defmodule Bar do
          def bar, do: Foo.foo
        end
        """)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_received {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "recompiles after compile time path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        Mix.Task.run("compile", ["--verbose"])

        # Add compile time dependency
        File.write!("lib/bar.ex", "defmodule Bar, do: Foo.foo")

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}

        # Recompiles for compile time dependencies
        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)
        ensure_touched("_build/dev/lib/foo/.mix/compile.elixir", mtime)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "recompiles after struct path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        File.write!("../foo/lib/foo.ex", "defmodule Foo, do: defstruct [:bar]")

        Mix.Task.run("compile", ["--verbose"])

        # Add struct dependency
        File.write!("lib/bar.ex", "defmodule Bar, do: %Foo{bar: true}")

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}

        # Recompiles for struct dependencies
        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.elixir").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)
        ensure_touched("_build/dev/lib/foo/.mix/compile.elixir", mtime)

        assert Mix.Tasks.Compile.Elixir.run(["--verbose"]) == {:ok, []}
        assert_receive {:mix_shell, :info, ["Compiled lib/bar.ex"]}
      end)
    end)
  end

  test "reconsolidates after path dependency changes" do
    in_fixture("umbrella_dep/deps/umbrella/apps", fn ->
      Mix.Project.in_project(:bar, "bar", fn _ ->
        # Add a protocol dependency
        File.write!("../foo/lib/foo.ex", """
        defprotocol Foo do
          def foo(arg)
        end
        defimpl Foo, for: List do
          def foo(list), do: list
        end
        """)

        Mix.Task.run("compile")
        assert File.regular?("_build/dev/lib/bar/consolidated/Elixir.Foo.beam")
        assert Mix.Tasks.Compile.Protocols.run([]) == :noop

        # Mark protocol as outdated
        File.touch!("_build/dev/lib/bar/consolidated/Elixir.Foo.beam", {{2010, 1, 1}, {0, 0, 0}})

        mtime = File.stat!("_build/dev/lib/bar/.mix/compile.protocols").mtime
        ensure_touched("_build/dev/lib/foo/ebin/Elixir.Foo.beam", mtime)

        assert Mix.Tasks.Compile.Protocols.run([]) == :ok

        # Check new timestamp
        mtime = File.stat!("_build/dev/lib/bar/consolidated/Elixir.Foo.beam").mtime
        assert mtime > {{2010, 1, 1}, {0, 0, 0}}
      end)
    end)
  end

  test "reconsolidates using umbrella parent information on shared _build" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      File.write!("apps/bar/lib/bar.ex", """
      defprotocol Bar do
        def bar(arg)
      end
      defimpl Bar, for: List do
        def bar(list), do: list
      end
      """)

      Mix.Project.in_project(:foo, "apps/foo", [build_path: "../../_build"], fn _ ->
        Mix.Task.run("compile.protocols")
        refute Code.ensure_loaded?(Bar)
      end)

      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile.protocols")
        Mix.Task.run("app.start")
        assert Protocol.consolidated?(Bar)
      end)
    end)
  end

  test "reconsolidates using umbrella child information on shared _build" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      File.write!("apps/bar/lib/bar.ex", """
      defprotocol Bar do
        def foo(arg)
      end
      defimpl Bar, for: List do
        def foo(list), do: list
      end
      """)

      Mix.Project.in_project(:umbrella, ".", fn _ ->
        Mix.Task.run("compile.protocols")
      end)

      # Emulate the dependency being removed
      Mix.Project.in_project(:foo, "apps/foo", [build_path: "../../_build", deps: []], fn _ ->
        File.rm_rf("../../_build/dev/lib/bar")
        Mix.Task.run("compile.protocols")
      end)
    end)
  end

  test "apps cannot refer to themselves as a dep" do
    in_fixture("umbrella_dep/deps/umbrella", fn ->
      Mix.Project.in_project(:umbrella, ".", fn _ ->
        File.write!("apps/bar/mix.exs", """
        defmodule Bar.MixProject do
          use Mix.Project

          def project do
            [app: :bar,
             version: "0.1.0",
             deps: [{:bar, in_umbrella: true}]]
          end
        end
        """)

        assert_raise Mix.Error, "App bar lists itself as a dependency", fn ->
          Mix.Task.run("deps.get", ["--verbose"]) == [:ok, :ok]
        end
      end)
    end)
  end
end


Warn when plug :action is used

Warn when plug :action is used

defmodule Phoenix.Controller.Pipeline do
  @moduledoc """
  This module implements the controller pipeline responsible for handling requests.

  ## The pipeline

  The goal of a controller is to receive a request and invoke the desired
  action. The whole flow of the controller is managed by a single pipeline:

      defmodule UserController do
        use Phoenix.Controller
        require Logger

        plug :log_message, "before action"

        def show(conn, _params) do
          Logger.debug "show/2"
          send_resp(conn, 200, "OK")
        end

        defp log_message(conn, msg) do
          Logger.debug msg
          conn
        end
      end

  When invoked, this pipeline will print:

      before action
      show/2

  As any other Plug pipeline, we can halt at any step by calling
  `Plug.Conn.halt/1` (which is by default imported into controllers).
  If we change `log_message/2` to:

      def log_message(conn, msg) do
        Logger.debug msg
        halt(conn)
      end

  it will print only:

      before action

  As the rest of the pipeline (the action and the after action plug)
  will never be invoked.

  ## Guards

  `plug/2` supports guards, allowing a developer to configure a plug to only
  run in some particular action:

      plug :log_message, "before show and edit" when action in [:show, :edit]
      plug :log_message, "before all but index" when not action in [:index]

  The first plug will run only when action is show and edit.
  The second plug will always run, except for the index action.

  Those guards work like regular Elixir guards and the only variables accessible
  in the guard are `conn`, the `action` as an atom and the `controller` as an
  alias.

  ## Controllers are plugs

  Like routers, controllers are plugs, but they are wired to dispatch
  to a particular function which is called an action.

  For example, the route:

      get "/users/:id", UserController, :show

  will invoke `UserController` as a plug:

      UserController.call(conn, :show)

  which will trigger the plug pipeline and which will eventually
  invoke the inner action plug that dispatches to the `show/2`
  function in the `UserController`.

  As controllers are plugs, they implement both `init/1` and
  `call/2`, and it also provides a function named `action/2`
  which is responsible for dispatching the appropriate action
  after the plug stack (and is also overridable).
  """

  @doc false
  defmacro __using__(_) do
    quote do
      @behaviour Plug

      import Phoenix.Controller.Pipeline
      Module.register_attribute(__MODULE__, :plugs, accumulate: true)
      @before_compile Phoenix.Controller.Pipeline

      def init(action) when is_atom(action) do
        action
      end

      def call(conn, action) do
        conn = update_in conn.private,
                 &(&1 |> Map.put(:phoenix_controller, __MODULE__)
                      |> Map.put(:phoenix_action, action))
        phoenix_controller_pipeline(conn, action)
      end

      def action(%{private: %{phoenix_action: action}} = conn, _options) do
        apply(__MODULE__, action, [conn, conn.params])
      end

      defoverridable [init: 1, call: 2, action: 2]
    end
  end

  @doc false
  defmacro __before_compile__(env) do
    action = {:action, [], true}
    plugs  = Module.get_attribute(env.module, :plugs)

    plugs =
      if action in plugs do
        IO.write :stderr, "plug :action is no longer required in controllers, " <>
                          "please remove it from #{inspect env.module}"
        plugs
      else
        [action|plugs]
      end

    {conn, body} = Plug.Builder.compile(env, plugs, log_on_halt: :debug)
    quote do
      defp phoenix_controller_pipeline(unquote(conn), var!(action)) do
        var!(conn) = unquote(conn)
        var!(controller) = __MODULE__
        _ = var!(conn)
        _ = var!(controller)
        _ = var!(action)

        unquote(body)
      end
    end
  end

  @doc """
  Stores a plug to be executed as part of the plug pipeline.
  """
  defmacro plug(plug)

  defmacro plug({:when, _, [plug, guards]}), do:
    plug(plug, [], guards)

  defmacro plug(plug), do:
    plug(plug, [], true)

  @doc """
  Stores a plug with the given options to be executed as part of
  the plug pipeline.
  """
  defmacro plug(plug, opts)

  defmacro plug(plug, {:when, _, [opts, guards]}), do:
    plug(plug, opts, guards)

  defmacro plug(plug, opts), do:
    plug(plug, opts, true)

  defp plug(plug, opts, guards) do
    quote do
      @plugs {unquote(plug), unquote(opts), unquote(Macro.escape(guards))}
    end
  end
end

defmodule Phoenix.Controller.Pipeline do
  @moduledoc """
  This module implements the controller pipeline responsible for handling requests.

  ## The pipeline

  The goal of a controller is to receive a request and invoke the desired
  action. The whole flow of the controller is managed by a single pipeline:

      defmodule UserController do
        use Phoenix.Controller
        require Logger

        plug :log_message, "before action"

        def show(conn, _params) do
          Logger.debug "show/2"
          send_resp(conn, 200, "OK")
        end

        defp log_message(conn, msg) do
          Logger.debug msg
          conn
        end
      end

  When invoked, this pipeline will print:

      before action
      show/2

  As any other Plug pipeline, we can halt at any step by calling
  `Plug.Conn.halt/1` (which is by default imported into controllers).
  If we change `log_message/2` to:

      def log_message(conn, msg) do
        Logger.debug msg
        halt(conn)
      end

  it will print only:

      before action

  As the rest of the pipeline (the action and the after action plug)
  will never be invoked.

  ## Guards

  `plug/2` supports guards, allowing a developer to configure a plug to only
  run in some particular action:

      plug :log_message, "before show and edit" when action in [:show, :edit]
      plug :log_message, "before all but index" when not action in [:index]

  The first plug will run only when action is show and edit.
  The second plug will always run, except for the index action.

  Those guards work like regular Elixir guards and the only variables accessible
  in the guard are `conn`, the `action` as an atom and the `controller` as an
  alias.

  ## Controllers are plugs

  Like routers, controllers are plugs, but they are wired to dispatch
  to a particular function which is called an action.

  For example, the route:

      get "/users/:id", UserController, :show

  will invoke `UserController` as a plug:

      UserController.call(conn, :show)

  which will trigger the plug pipeline and which will eventually
  invoke the inner action plug that dispatches to the `show/2`
  function in the `UserController`.

  As controllers are plugs, they implement both `init/1` and
  `call/2`, and it also provides a function named `action/2`
  which is responsible for dispatching the appropriate action
  in the middle of the plug stack (and is also overridable).
  """

  @doc false
  defmacro __using__(_) do
    quote do
      @behaviour Plug

      import Phoenix.Controller.Pipeline
      Module.register_attribute(__MODULE__, :plugs, accumulate: true)
      @before_compile Phoenix.Controller.Pipeline

      def init(action) when is_atom(action) do
        action
      end

      def call(conn, action) do
        conn = update_in conn.private,
                 &(&1 |> Map.put(:phoenix_controller, __MODULE__)
                      |> Map.put(:phoenix_action, action))
        phoenix_controller_pipeline(conn, action)
      end

      def action(%{private: %{phoenix_action: action}} = conn, _options) do
        apply(__MODULE__, action, [conn, conn.params])
      end

      defoverridable [init: 1, call: 2, action: 2]
    end
  end

  @doc false
  defmacro __before_compile__(env) do
    plugs = [{:action, [], true} | Module.get_attribute(env.module, :plugs)]

    {conn, body} = Plug.Builder.compile(env, plugs, log_on_halt: :debug)
    quote do
      defp phoenix_controller_pipeline(unquote(conn), var!(action)) do
        var!(conn) = unquote(conn)
        var!(controller) = __MODULE__
        _ = var!(conn)
        _ = var!(controller)
        _ = var!(action)

        unquote(body)
      end
    end
  end

  @doc """
  Stores a plug to be executed as part of the plug pipeline.
  """
  defmacro plug(plug)

  defmacro plug({:when, _, [plug, guards]}), do:
    plug(plug, [], guards)

  defmacro plug(plug), do:
    plug(plug, [], true)

  @doc """
  Stores a plug with the given options to be executed as part of
  the plug pipeline.
  """
  defmacro plug(plug, opts)

  defmacro plug(plug, {:when, _, [opts, guards]}), do:
    plug(plug, opts, guards)

  defmacro plug(plug, opts), do:
    plug(plug, opts, true)

  defp plug(plug, opts, guards) do
    quote do
      @plugs {unquote(plug), unquote(opts), unquote(Macro.escape(guards))}
    end
  end
end


Fixed spec to match name of compile_stop_callbacks/2. (#2164)

defmodule Phoenix.Endpoint.Instrument do
  @moduledoc false

  # This is the arity that event callbacks in the instrumenter modules must
  # have.
  @event_callback_arity 3

  @doc false
  def definstrument(otp_app, endpoint) do
    app_instrumenters = app_instrumenters(otp_app, endpoint)

    quote bind_quoted: [app_instrumenters: app_instrumenters] do
      require Logger

      @doc """
      Instruments the given function.

      `event` is the event identifier (usually an atom) that specifies which
      instrumenting function to call in the instrumenter modules. `runtime` is
      metadata to be associated with the event at runtime (e.g., the query being
      issued if the event to instrument is a DB query).

      ## Examples

          instrument :render_view, %{view: "index.html"}, fn ->
            render conn, "index.html"
          end

      """
      defmacro instrument(event, runtime \\ Macro.escape(%{}), fun) do
        compile = Macro.escape(Phoenix.Endpoint.Instrument.strip_caller(__CALLER__))

        quote do
          unquote(__MODULE__).instrument(
            unquote(event),
            unquote(compile),
            unquote(runtime),
            unquote(fun)
          )
        end
      end

      # For each event in any of the instrumenters, we must generate a
      # clause of the `instrument/4` function. It'll look like this:
      #
      #   def instrument(:my_event, compile, runtime, fun) do
      #     res0 = Inst0.my_event(:start, compile, runtime)
      #     ...
      #
      #     start = :erlang.monotonic_time
      #     try do
      #       fun.()
      #     after
      #       diff = ...
      #       Inst0.my_event(:stop, diff, res0)
      #       ...
      #     end
      #   end
      #
      @doc false
      def instrument(event, compile, runtime, fun)

      for {event, instrumenters} <- app_instrumenters do
        def instrument(unquote(event), var!(compile), var!(runtime), fun)
            when is_map(var!(compile)) and is_map(var!(runtime)) and is_function(fun, 0) do
          unquote(Phoenix.Endpoint.Instrument.compile_start_callbacks(event, instrumenters))
          start = :erlang.monotonic_time
          try do
            fun.()
          after
            var!(diff) = :erlang.monotonic_time - start
            unquote(Phoenix.Endpoint.Instrument.compile_stop_callbacks(event, instrumenters))
          end
        end
      end

      # Catch-all clause
      def instrument(event, compile, runtime, fun)
          when is_atom(event) and is_map(compile) and is_map(runtime) and is_function(fun, 0) do
        fun.()
      end
    end
  end

  # Reads a list of the instrumenters from the config of `otp_app` and finds all
  # events in those instrumenters. The return value is a list of `{event,
  # instrumenters}` tuples, one for each event defined by any instrumenters
  # (with no duplicated events); `instrumenters` is the list of instrumenters
  # interested in `event`.
  defp app_instrumenters(otp_app, endpoint) do
    config        = Application.get_env(otp_app, endpoint, [])
    instrumenters = config[:instrumenters] || []

    unless is_list(instrumenters) and Enum.all?(instrumenters, &is_atom/1) do
      raise ":instrumenters must be a list of instrumenter modules"
    end

    events_to_instrumenters([Phoenix.Logger | instrumenters])
  end

  # Strips a `Macro.Env` struct, leaving only interesting compile-time metadata.
  @doc false
  @spec strip_caller(Macro.Env.t) :: %{}
  def strip_caller(%Macro.Env{module: mod, function: fun, file: file, line: line}) do
    caller = %{module: mod, function: form_fa(fun), file: file, line: line}

    if app = Application.get_env(:logger, :compile_time_application) do
       Map.put(caller, :application, app)
    else
      caller
    end
  end

  defp form_fa({name, arity}), do: Atom.to_string(name) <> "/" <> Integer.to_string(arity)
  defp form_fa(nil), do: nil

  # called by Phoenix.Endpoint.instrument/4, see docs there
  @doc false
  @spec extract_endpoint(Plug.Conn.t | Phoenix.Socket.t | module) :: module | nil
  def extract_endpoint(endpoint_or_conn_or_socket) do
    case endpoint_or_conn_or_socket do
      %Plug.Conn{private: %{phoenix_endpoint: endpoint}} -> endpoint
      %Phoenix.Socket{endpoint: endpoint} -> endpoint
      %{__struct__: struct} when struct in [Plug.Conn, Phoenix.Socket] -> nil
      endpoint -> endpoint
    end
  end

  # Returns the AST for all the calls to the "start event" callbacks in the given
  # list of `instrumenters`.
  # Each function call looks like this:
  #
  #     res0 = Instr0.my_event(:start, compile, runtime)
  #
  @doc false
  @spec compile_start_callbacks(term, [module]) :: Macro.t
  def compile_start_callbacks(event, instrumenters) do
    Enum.map Enum.with_index(instrumenters), fn {inst, index} ->
      error_prefix = "Instrumenter #{inspect inst}.#{event}/3 failed.\n"
      quote do
        unquote(build_result_variable(index)) =
          try do
            unquote(inst).unquote(event)(:start, var!(compile), var!(runtime))
          catch
            kind, error ->
              Logger.error unquote(error_prefix) <> Exception.format(kind, error)
          end
      end
    end
  end

  # Returns the AST for all the calls to the "stop event" callbacks in the given
  # list of `instrumenters`.
  # Each function call looks like this:
  #
  #     Instr0.my_event(:stop, diff, res0)
  #
  @doc false
  @spec compile_stop_callbacks(term, [module]) :: Macro.t
  def compile_stop_callbacks(event, instrumenters) do
    Enum.map Enum.with_index(instrumenters), fn {inst, index} ->
      error_prefix = "Instrumenter #{inspect inst}.#{event}/3 failed.\n"
      quote do
        try do
          unquote(inst).unquote(event)(:stop, var!(diff), unquote(build_result_variable(index)))
        catch
          kind, error ->
            Logger.error unquote(error_prefix) <> Exception.format(kind, error)
        end
      end
    end
  end

  # Takes a list of instrumenter modules and returns a list of `{event,
  # instrumenters}` tuples where each tuple represents an event and all the
  # modules interested in that event.
  defp events_to_instrumenters(instrumenters) do
    instrumenters                                              # [Ins1, Ins2, ...]
    |> instrumenters_and_events()                              # [{Ins1, e1}, {Ins2, e1}, ...]
    |> Enum.group_by(fn {_inst, e} -> e end)                   # %{e1 => [{Ins1, e1}, ...], ...}
    |> Enum.map(fn {e, insts} -> {e, strip_events(insts)} end) # [{e1, [Ins1, Ins2]}, ...]
  end

  defp instrumenters_and_events(instrumenters) do
    # We're only interested in functions (events) with the given arity.
    for inst <- instrumenters,
        {event, @event_callback_arity} <- inst.__info__(:functions),
        do: {inst, event}
  end

  defp strip_events(instrumenters) do
    for {inst, _evt} <- instrumenters, do: inst
  end

  defp build_result_variable(index) when is_integer(index) do
    "res#{index}" |> String.to_atom() |> Macro.var(nil)
  end
end

defmodule Phoenix.Endpoint.Instrument do
  @moduledoc false

  # This is the arity that event callbacks in the instrumenter modules must
  # have.
  @event_callback_arity 3

  @doc false
  def definstrument(otp_app, endpoint) do
    app_instrumenters = app_instrumenters(otp_app, endpoint)

    quote bind_quoted: [app_instrumenters: app_instrumenters] do
      require Logger

      @doc """
      Instruments the given function.

      `event` is the event identifier (usually an atom) that specifies which
      instrumenting function to call in the instrumenter modules. `runtime` is
      metadata to be associated with the event at runtime (e.g., the query being
      issued if the event to instrument is a DB query).

      ## Examples

          instrument :render_view, %{view: "index.html"}, fn ->
            render conn, "index.html"
          end

      """
      defmacro instrument(event, runtime \\ Macro.escape(%{}), fun) do
        compile = Macro.escape(Phoenix.Endpoint.Instrument.strip_caller(__CALLER__))

        quote do
          unquote(__MODULE__).instrument(
            unquote(event),
            unquote(compile),
            unquote(runtime),
            unquote(fun)
          )
        end
      end

      # For each event in any of the instrumenters, we must generate a
      # clause of the `instrument/4` function. It'll look like this:
      #
      #   def instrument(:my_event, compile, runtime, fun) do
      #     res0 = Inst0.my_event(:start, compile, runtime)
      #     ...
      #
      #     start = :erlang.monotonic_time
      #     try do
      #       fun.()
      #     after
      #       diff = ...
      #       Inst0.my_event(:stop, diff, res0)
      #       ...
      #     end
      #   end
      #
      @doc false
      def instrument(event, compile, runtime, fun)

      for {event, instrumenters} <- app_instrumenters do
        def instrument(unquote(event), var!(compile), var!(runtime), fun)
            when is_map(var!(compile)) and is_map(var!(runtime)) and is_function(fun, 0) do
          unquote(Phoenix.Endpoint.Instrument.compile_start_callbacks(event, instrumenters))
          start = :erlang.monotonic_time
          try do
            fun.()
          after
            var!(diff) = :erlang.monotonic_time - start
            unquote(Phoenix.Endpoint.Instrument.compile_stop_callbacks(event, instrumenters))
          end
        end
      end

      # Catch-all clause
      def instrument(event, compile, runtime, fun)
          when is_atom(event) and is_map(compile) and is_map(runtime) and is_function(fun, 0) do
        fun.()
      end
    end
  end

  # Reads a list of the instrumenters from the config of `otp_app` and finds all
  # events in those instrumenters. The return value is a list of `{event,
  # instrumenters}` tuples, one for each event defined by any instrumenters
  # (with no duplicated events); `instrumenters` is the list of instrumenters
  # interested in `event`.
  defp app_instrumenters(otp_app, endpoint) do
    config        = Application.get_env(otp_app, endpoint, [])
    instrumenters = config[:instrumenters] || []

    unless is_list(instrumenters) and Enum.all?(instrumenters, &is_atom/1) do
      raise ":instrumenters must be a list of instrumenter modules"
    end

    events_to_instrumenters([Phoenix.Logger | instrumenters])
  end

  # Strips a `Macro.Env` struct, leaving only interesting compile-time metadata.
  @doc false
  @spec strip_caller(Macro.Env.t) :: %{}
  def strip_caller(%Macro.Env{module: mod, function: fun, file: file, line: line}) do
    caller = %{module: mod, function: form_fa(fun), file: file, line: line}

    if app = Application.get_env(:logger, :compile_time_application) do
       Map.put(caller, :application, app)
    else
      caller
    end
  end

  defp form_fa({name, arity}), do: Atom.to_string(name) <> "/" <> Integer.to_string(arity)
  defp form_fa(nil), do: nil

  # called by Phoenix.Endpoint.instrument/4, see docs there
  @doc false
  @spec extract_endpoint(Plug.Conn.t | Phoenix.Socket.t | module) :: module | nil
  def extract_endpoint(endpoint_or_conn_or_socket) do
    case endpoint_or_conn_or_socket do
      %Plug.Conn{private: %{phoenix_endpoint: endpoint}} -> endpoint
      %Phoenix.Socket{endpoint: endpoint} -> endpoint
      %{__struct__: struct} when struct in [Plug.Conn, Phoenix.Socket] -> nil
      endpoint -> endpoint
    end
  end

  # Returns the AST for all the calls to the "start event" callbacks in the given
  # list of `instrumenters`.
  # Each function call looks like this:
  #
  #     res0 = Instr0.my_event(:start, compile, runtime)
  #
  @doc false
  @spec compile_start_callbacks(term, [module]) :: Macro.t
  def compile_start_callbacks(event, instrumenters) do
    Enum.map Enum.with_index(instrumenters), fn {inst, index} ->
      error_prefix = "Instrumenter #{inspect inst}.#{event}/3 failed.\n"
      quote do
        unquote(build_result_variable(index)) =
          try do
            unquote(inst).unquote(event)(:start, var!(compile), var!(runtime))
          catch
            kind, error ->
              Logger.error unquote(error_prefix) <> Exception.format(kind, error)
          end
      end
    end
  end

  # Returns the AST for all the calls to the "stop event" callbacks in the given
  # list of `instrumenters`.
  # Each function call looks like this:
  #
  #     Instr0.my_event(:stop, diff, res0)
  #
  @doc false
  @spec compile_start_callbacks(term, [module]) :: Macro.t
  def compile_stop_callbacks(event, instrumenters) do
    Enum.map Enum.with_index(instrumenters), fn {inst, index} ->
      error_prefix = "Instrumenter #{inspect inst}.#{event}/3 failed.\n"
      quote do
        try do
          unquote(inst).unquote(event)(:stop, var!(diff), unquote(build_result_variable(index)))
        catch
          kind, error ->
            Logger.error unquote(error_prefix) <> Exception.format(kind, error)
        end
      end
    end
  end

  # Takes a list of instrumenter modules and returns a list of `{event,
  # instrumenters}` tuples where each tuple represents an event and all the
  # modules interested in that event.
  defp events_to_instrumenters(instrumenters) do
    instrumenters                                              # [Ins1, Ins2, ...]
    |> instrumenters_and_events()                              # [{Ins1, e1}, {Ins2, e1}, ...]
    |> Enum.group_by(fn {_inst, e} -> e end)                   # %{e1 => [{Ins1, e1}, ...], ...}
    |> Enum.map(fn {e, insts} -> {e, strip_events(insts)} end) # [{e1, [Ins1, Ins2]}, ...]
  end

  defp instrumenters_and_events(instrumenters) do
    # We're only interested in functions (events) with the given arity.
    for inst <- instrumenters,
        {event, @event_callback_arity} <- inst.__info__(:functions),
        do: {inst, event}
  end

  defp strip_events(instrumenters) do
    for {inst, _evt} <- instrumenters, do: inst
  end

  defp build_result_variable(index) when is_integer(index) do
    "res#{index}" |> String.to_atom() |> Macro.var(nil)
  end
end


Remove dependency between loadconfig tests

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

defmodule Mix.Tasks.LoadconfigTest do
  use MixTest.Case

  @tag apps: [:my_app]
  test "reads and persists project configuration", context do
    Mix.Project.push MixTest.Case.Sample

    in_tmp context.test, fn ->
      write_config """
      [my_app: [key: :project]]
      """

      assert Application.fetch_env(:my_app, :key) == :error
      Mix.Task.run "loadconfig", []
      assert Application.fetch_env(:my_app, :key) == {:ok, :project}

      # App configuration should have lower precedence
      :ok = :application.load({:application, :my_app, [vsn: '1.0.0', env: [key: :app]]})
      assert Application.fetch_env(:my_app, :key) == {:ok, :project}

      # laodconfig can be called multiple times
      # Later values should have higher precedence
      Mix.Task.run "loadconfig", [fixture_path("configs/good_config.exs")]
      assert Application.fetch_env(:my_app, :key) == {:ok, :value}
    end
  end

  @tag apps: [:config_app]
  test "reads from custom config_path", context do
    Mix.ProjectStack.post_config [config_path: "fresh.config"]
    Mix.Project.push MixTest.Case.Sample

    in_tmp context.test, fn ->
      write_config "fresh.config", """
      [config_app: [key: :value]]
      """
      assert Application.fetch_env(:config_app, :key) == :error
      Mix.Task.run "loadconfig", []
      assert Application.fetch_env(:config_app, :key) == {:ok, :value}
    end
  end

  defp write_config(path \\ "config/config.exs", contents) do
    File.mkdir_p! Path.dirname(path)
    File.write! path, contents
  end
end

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

defmodule Mix.Tasks.LoadconfigTest do
  use MixTest.Case

  @tag apps: [:my_app]
  test "reads and persists project configuration", context do
    Mix.Project.push MixTest.Case.Sample

    in_tmp context.test, fn ->
      write_config """
      [my_app: [key: :project]]
      """

      assert Application.fetch_env(:my_app, :key) == :error
      Mix.Task.run "loadconfig", []
      assert Application.fetch_env(:my_app, :key) == {:ok, :project}

      # App configuration should have lower precedence
      :ok = :application.load({:application, :my_app, [vsn: '1.0.0', env: [key: :app]]})
      assert Application.fetch_env(:my_app, :key) == {:ok, :project}

      # laodconfig can be called multiple times
      # Later values should have higher precedence
      Mix.Task.run "loadconfig", [fixture_path("configs/good_config.exs")]
      assert Application.fetch_env(:my_app, :key) == {:ok, :value}
    end
  end

  @tag apps: [:my_app]
  test "reads from custom config_path", context do
    Mix.ProjectStack.post_config [config_path: fixture_path("configs/good_config.exs")]
    Mix.Project.push MixTest.Case.Sample

    in_tmp context.test, fn ->
      assert Application.fetch_env(:my_app, :key) == :error
      Mix.Task.run "loadconfig", []
      assert Application.fetch_env(:my_app, :key) == {:ok, :value}
    end
  end

  defp write_config(path \\ "config/config.exs", contents) do
    File.mkdir_p! Path.dirname(path)
    File.write! path, contents
  end
end


Fix tests

Fix tests

defmodule CoursePlanner.TeacherControllerTest do
  use CoursePlanner.ConnCase

  alias CoursePlanner.{Repo, User, Teachers}
  import CoursePlanner.Factory

  @valid_attrs %{name: "some content", email: "valid@email"}
  @invalid_attrs %{}

  setup do
    {:ok, conn: login_as(:coordinator)}
  end

  defp login_as(user_type) do
    user = insert(user_type)

    Phoenix.ConnTest.build_conn()
    |> assign(:current_user, user)
  end

  test "lists all entries on index", %{conn: conn} do
    conn = get conn, teacher_path(conn, :index)
    assert html_response(conn, 200) =~ "Teachers"
  end

  test "shows chosen resource", %{conn: conn} do
    teacher = insert(:teacher)
    conn = get conn, teacher_path(conn, :show, teacher)
    assert html_response(conn, 200) =~ "#{teacher.name} #{teacher.family_name}"
  end

  test "renders page not found when id is nonexistent", %{conn: conn} do
    assert_error_sent 404, fn ->
      get conn, teacher_path(conn, :show, -1)
    end
  end

  test "renders form for editing chosen resource", %{conn: conn} do
    teacher = Repo.insert! %User{name: "Foo", family_name: "Bar"}
    conn = get conn, teacher_path(conn, :edit, teacher)
    assert html_response(conn, 200) =~ "Foo Bar"
  end

  test "updates chosen resource and redirects when data is valid", %{conn: conn} do
    teacher = Repo.insert! %User{}
    conn = put conn, teacher_path(conn, :update, teacher), user: @valid_attrs
    assert redirected_to(conn) == teacher_path(conn, :show, teacher)
    assert Repo.get_by(User, @valid_attrs)
  end

  test "does not update chosen resource and renders errors when data is invalid", %{conn: conn} do
    teacher = Repo.insert! %User{name: "Foo", family_name: "Bar"}
    conn = put conn, teacher_path(conn, :update, teacher), user: @invalid_attrs
    assert html_response(conn, 200) =~ "Foo Bar"
  end

  test "deletes chosen resource", %{conn: conn} do
    {:ok, teacher} = Teachers.new(@valid_attrs, "whatever")
    conn = delete conn, teacher_path(conn, :delete, teacher)
    assert redirected_to(conn) == teacher_path(conn, :index)
    refute Repo.get(User, teacher.id)
  end

  test "renders form for new resources", %{conn: conn} do
    conn = get conn, teacher_path(conn, :new)
    assert html_response(conn, 200) =~ "New teacher"
  end

  test "does not shows chosen resource for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = get student_conn, teacher_path(student_conn, :show, teacher)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :show, teacher)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :show, teacher)
    assert html_response(conn, 403)
  end

  test "does not list entries on index for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    conn = get student_conn, teacher_path(student_conn, :index)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :index)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :index)
    assert html_response(conn, 403)
  end

  test "does not renders form for editing chosen resource for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = get student_conn, teacher_path(student_conn, :edit, teacher)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :edit, teacher)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :edit, teacher)
    assert html_response(conn, 403)
  end

  test "does not delete a chosen resource for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = delete student_conn, teacher_path(student_conn, :delete, teacher.id)
    assert html_response(conn, 403)

    conn = delete teacher_conn, teacher_path(teacher_conn, :delete, teacher.id)
    assert html_response(conn, 403)

    conn = delete volunteer_conn, teacher_path(volunteer_conn, :delete, teacher.id)
    assert html_response(conn, 403)
  end

  test "does not render form for new class for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    conn = get student_conn, teacher_path(student_conn, :new)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :new)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :new)
    assert html_response(conn, 403)
  end

  test "does not create class for non coordinator use", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = post student_conn, teacher_path(student_conn, :create), class: teacher
    assert html_response(conn, 403)

    conn = post teacher_conn, teacher_path(teacher_conn, :create), class: teacher
    assert html_response(conn, 403)

    conn = post volunteer_conn, teacher_path(volunteer_conn, :create), class: teacher
    assert html_response(conn, 403)
  end

  test "does not update chosen teacher for non coordinator use", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = Repo.insert! %User{}

    conn = put student_conn, teacher_path(student_conn, :update, teacher), teacher: @valid_attrs
    assert html_response(conn, 403)

    conn = put teacher_conn, teacher_path(teacher_conn, :update, teacher), teacher: @valid_attrs
    assert html_response(conn, 403)

    conn = put volunteer_conn, teacher_path(volunteer_conn, :update, teacher), teacher: @valid_attrs
    assert html_response(conn, 403)
  end

  test "show the teacher himself" do
    teacher = insert(:teacher)
    teacher_conn = Phoenix.ConnTest.build_conn()
    |> assign(:current_user, teacher)

    conn = get teacher_conn, teacher_path(teacher_conn, :show, teacher)
    assert html_response(conn, 200) =~ "#{teacher.name} #{teacher.family_name}"
  end

  test "edit the teacher himself" do
    teacher = insert(:teacher, name: "Foo", family_name: "Bar")
    teacher_conn = Phoenix.ConnTest.build_conn()
    |> assign(:current_user, teacher)

    conn = get teacher_conn, teacher_path(teacher_conn, :edit, teacher)
    assert html_response(conn, 200) =~ "Foo Bar"
  end

  test "update the teacher himself" do
    teacher = insert(:teacher)
    teacher_conn = Phoenix.ConnTest.build_conn()
    |> assign(:current_user, teacher)

    conn = put teacher_conn, teacher_path(teacher_conn, :update, teacher), user: @valid_attrs
    assert redirected_to(conn) == teacher_path(conn, :show, teacher)
    assert Repo.get_by(User, @valid_attrs)
  end

end

defmodule CoursePlanner.TeacherControllerTest do
  use CoursePlanner.ConnCase

  alias CoursePlanner.{Repo, User, Teachers}
  import CoursePlanner.Factory

  @valid_attrs %{name: "some content", email: "valid@email"}
  @invalid_attrs %{}

  setup do
    {:ok, conn: login_as(:coordinator)}
  end

  defp login_as(user_type) do
    user = insert(user_type)

    Phoenix.ConnTest.build_conn()
    |> assign(:current_user, user)
  end

  test "lists all entries on index", %{conn: conn} do
    conn = get conn, teacher_path(conn, :index)
    assert html_response(conn, 200) =~ "Teachers"
  end

  test "shows chosen resource", %{conn: conn} do
    teacher = Repo.insert! %User{}
    conn = get conn, teacher_path(conn, :show, teacher)
    assert html_response(conn, 200) =~ "Show teacher"
  end

  test "renders page not found when id is nonexistent", %{conn: conn} do
    assert_error_sent 404, fn ->
      get conn, teacher_path(conn, :show, -1)
    end
  end

  test "renders form for editing chosen resource", %{conn: conn} do
    teacher = Repo.insert! %User{name: "Foo", family_name: "Bar"}
    conn = get conn, teacher_path(conn, :edit, teacher)
    assert html_response(conn, 200) =~ "Foo Bar"
  end

  test "updates chosen resource and redirects when data is valid", %{conn: conn} do
    teacher = Repo.insert! %User{}
    conn = put conn, teacher_path(conn, :update, teacher), user: @valid_attrs
    assert redirected_to(conn) == teacher_path(conn, :show, teacher)
    assert Repo.get_by(User, @valid_attrs)
  end

  test "does not update chosen resource and renders errors when data is invalid", %{conn: conn} do
    teacher = Repo.insert! %User{name: "Foo", family_name: "Bar"}
    conn = put conn, teacher_path(conn, :update, teacher), user: @invalid_attrs
    assert html_response(conn, 200) =~ "Foo Bar"
  end

  test "deletes chosen resource", %{conn: conn} do
    {:ok, teacher} = Teachers.new(@valid_attrs, "whatever")
    conn = delete conn, teacher_path(conn, :delete, teacher)
    assert redirected_to(conn) == teacher_path(conn, :index)
    refute Repo.get(User, teacher.id)
  end

  test "renders form for new resources", %{conn: conn} do
    conn = get conn, teacher_path(conn, :new)
    assert html_response(conn, 200) =~ "New teacher"
  end

  test "does not shows chosen resource for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = get student_conn, teacher_path(student_conn, :show, teacher)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :show, teacher)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :show, teacher)
    assert html_response(conn, 403)
  end

  test "does not list entries on index for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    conn = get student_conn, teacher_path(student_conn, :index)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :index)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :index)
    assert html_response(conn, 403)
  end

  test "does not renders form for editing chosen resource for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = get student_conn, teacher_path(student_conn, :edit, teacher)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :edit, teacher)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :edit, teacher)
    assert html_response(conn, 403)
  end

  test "does not delete a chosen resource for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = delete student_conn, teacher_path(student_conn, :delete, teacher.id)
    assert html_response(conn, 403)

    conn = delete teacher_conn, teacher_path(teacher_conn, :delete, teacher.id)
    assert html_response(conn, 403)

    conn = delete volunteer_conn, teacher_path(volunteer_conn, :delete, teacher.id)
    assert html_response(conn, 403)
  end

  test "does not render form for new class for non coordinator user", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    conn = get student_conn, teacher_path(student_conn, :new)
    assert html_response(conn, 403)

    conn = get teacher_conn, teacher_path(teacher_conn, :new)
    assert html_response(conn, 403)

    conn = get volunteer_conn, teacher_path(volunteer_conn, :new)
    assert html_response(conn, 403)
  end

  test "does not create class for non coordinator use", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = insert(:teacher)

    conn = post student_conn, teacher_path(student_conn, :create), class: teacher
    assert html_response(conn, 403)

    conn = post teacher_conn, teacher_path(teacher_conn, :create), class: teacher
    assert html_response(conn, 403)

    conn = post volunteer_conn, teacher_path(volunteer_conn, :create), class: teacher
    assert html_response(conn, 403)
  end

  test "does not update chosen teacher for non coordinator use", %{conn: _conn} do
    student_conn   = login_as(:student)
    teacher_conn   = login_as(:teacher)
    volunteer_conn = login_as(:volunteer)

    teacher = Repo.insert! %User{}

    conn = put student_conn, teacher_path(student_conn, :update, teacher), teacher: @valid_attrs
    assert html_response(conn, 403)

    conn = put teacher_conn, teacher_path(teacher_conn, :update, teacher), teacher: @valid_attrs
    assert html_response(conn, 403)

    conn = put volunteer_conn, teacher_path(volunteer_conn, :update, teacher), teacher: @valid_attrs
    assert html_response(conn, 403)
  end

  test "show the teacher himself" do
    teacher = insert(:teacher)
    teacher_conn = Phoenix.ConnTest.build_conn()
    |> assign(:current_user, teacher)

    conn = get teacher_conn, teacher_path(teacher_conn, :show, teacher)
    assert html_response(conn, 200) =~ "Show teacher"
  end

  test "edit the teacher himself" do
    teacher = insert(:teacher, name: "Foo", family_name: "Bar")
    teacher_conn = Phoenix.ConnTest.build_conn()
    |> assign(:current_user, teacher)

    conn = get teacher_conn, teacher_path(teacher_conn, :edit, teacher)
    assert html_response(conn, 200) =~ "Foo Bar"
  end

  test "update the teacher himself" do
    teacher = insert(:teacher)
    teacher_conn = Phoenix.ConnTest.build_conn()
    |> assign(:current_user, teacher)

    conn = put teacher_conn, teacher_path(teacher_conn, :update, teacher), user: @valid_attrs
    assert redirected_to(conn) == teacher_path(conn, :show, teacher)
    assert Repo.get_by(User, @valid_attrs)
  end

end


default-world > removing a comment that doesn't need to be there

defmodule Default.Stage.Level do
  import Moongate.Stage

  @playable_archetypes {"elf"}
  meta %{}
  pools [Character, Event, Particle, Pickup, Projectile]
  takes :move, :player_move, {:int, :int}
  takes :stop, :player_stop, {:int, :int}
  takes :attack, :player_attack

  def arrival(event) do
    new(event, Character, [
      origin: event.origin,
      archetype: random_from(@playable_archetypes),
      x: random(640),
      y: random(512)
    ])
    new(event, Event, [])
  end

  def departure(event) do
    player = first Character, [origin: event.origin]
    drop(event, player)
  end

  def echo(event, Character, {:add_particle, {x, y, type, lifespan}}) do
    echo(event, Character, {:add_particle, {x, y, type, lifespan, "default"}})
  end
  def echo(event, Character, {:add_particle, {x, y, type, lifespan, d}}) do
    new(event, Particle, [
      direction: d,
      lifespan: 400,
      type: type,
      x: x,
      y: y
    ])
  end

  def echo(event, Character, {:reset_stance}) do
    cast(event, event.this, :reset_stance)
  end

  def echo(event, Particle, {:drop}) do
    drop(event, event.this)
  end

  def player_attack(event, params) do
    player = first Character, [origin: event.origin]
    cast(event, player, :attack)
  end

  def player_move(event, params) do
    player = first Character, [origin: event.origin]
    cast(event, player, :move, params)
  end

  def player_stop(event, params) do
    player = first Character, [origin: event.origin]
    cast(event, player, :stop, params)
  end
end

defmodule Default.Stage.Level do
  import Moongate.Stage

  @playable_archetypes {"elf"}
  # @playable_archetypes {"elf", "mage", "skeleton"}
  meta %{}
  pools [Character, Event, Particle, Pickup, Projectile]
  takes :move, :player_move, {:int, :int}
  takes :stop, :player_stop, {:int, :int}
  takes :attack, :player_attack

  def arrival(event) do
    new(event, Character, [
      origin: event.origin,
      archetype: random_from(@playable_archetypes),
      x: random(640),
      y: random(512)
    ])
    new(event, Event, [])
  end

  def departure(event) do
    player = first Character, [origin: event.origin]
    drop(event, player)
  end

  def echo(event, Character, {:add_particle, {x, y, type, lifespan}}) do
    echo(event, Character, {:add_particle, {x, y, type, lifespan, "default"}})
  end
  def echo(event, Character, {:add_particle, {x, y, type, lifespan, d}}) do
    new(event, Particle, [
      direction: d,
      lifespan: 400,
      type: type,
      x: x,
      y: y
    ])
  end

  def echo(event, Character, {:reset_stance}) do
    cast(event, event.this, :reset_stance)
  end

  def echo(event, Particle, {:drop}) do
    drop(event, event.this)
  end

  def player_attack(event, params) do
    player = first Character, [origin: event.origin]
    cast(event, player, :attack)
  end

  def player_move(event, params) do
    player = first Character, [origin: event.origin]
    cast(event, player, :move, params)
  end

  def player_stop(event, params) do
    player = first Character, [origin: event.origin]
    cast(event, player, :stop, params)
  end
end