 
   test ":__struct__ is ignored when using structs" do
     assert capture_err(fn ->
-      Code.eval_string """
-      assert %Kernel.WarningTest.User{__struct__: Ignored, name: "joe"} ==
-             %Kernel.WarningTest.User{name: "joe"}
-      """, [], __ENV__
-    end) =~ "key :__struct__ is ignored when using structs"
-
-    assert capture_err(fn ->
-      Code.eval_string """
-      user = %Kernel.WarningTest.User{name: "meg"}
-      assert %Kernel.WarningTest.User{user | __struct__: Ignored, name: "joe"} ==
-             %Kernel.WarningTest.User{__struct__: Kernel.WarningTest.User, name: "joe"}
-      """, [], __ENV__
-    end) =~ "key :__struct__ is ignored when using structs"
+             code = """
+             assert %Kernel.WarningTest.User{__struct__: Ignored, name: "joe"} ==
+                    %Kernel.WarningTest.User{name: "joe"}
+             """
+
+             Code.eval_string(code, [], __ENV__)
+           end) =~ "key :__struct__ is ignored when using structs"
+
+    assert capture_err(fn ->
+             code = """
+             user = %Kernel.WarningTest.User{name: "meg"}
+             assert %Kernel.WarningTest.User{user | __struct__: Ignored, name: "joe"} ==
+                    %Kernel.WarningTest.User{__struct__: Kernel.WarningTest.User, name: "joe"}
+             """
+
+             Code.eval_string(code, [], __ENV__)
+           end) =~ "key :__struct__ is ignored when using structs"
   end
 
   test "catch comes before rescue in try block" do
-    output = capture_err(fn ->
-      Code.eval_string """
-      try do
-        :trying
-      catch
-        _ -> :caught
-      rescue
-        _ -> :error
-      end
-      """
-    end)
+    output =
+      capture_err(fn ->
+        Code.eval_string("""
+        try do
+          :trying
+        catch
+          _ -> :caught
+        rescue
+          _ -> :error
+        end
+        """)
+      end)
+
     assert output =~ ~s("catch" should always come after "rescue" in try)
   end
 
   defp purge(list) when is_list(list) do
-    Enum.each list, &purge/1
+    Enum.each(list, &purge/1)
   end
 
   defp purge(module) when is_atom(module) do
-    :code.delete module
-    :code.purge module
+    :code.delete(module)
+    :code.purge(module)
   end
 end

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

defmodule Kernel.WarningTest do
  use ExUnit.Case


  test "unused guard" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def atom_case do
                 v = "bc"
                 case v do
                   _ when is_atom(v) -> :ok
                   _ -> :fail
                 end
               end
             end
             """)
           end) =~ "this check/guard will always yield the same result"
  after
    purge(Sample)
  end

  test "`length(list) == 0` in guard" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def list_case do
                 v = []
                 case v do
                   _ when length(v) == 0 -> :ok
                   _ -> :fail
                 end
               end
             end
             """)
           end) =~
             "\"length(v) == 0\" is discouraged since it has to traverse the whole list to check if it is empty or not"
  after
    purge(Sample)
  end

  test "previous clause always matches" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def binary_cond do
                 v = "bc"
                 cond do
                   is_binary(v) -> :bin
                   true -> :ok
                 end
               end
             end
             """)
           end) =~ "this clause cannot match because a previous clause at line 5 always matches"
  after
    purge(Sample)
  end

  test "empty clause" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample1 do
               def hello
             end
             """)
           end) =~ "implementation not provided for predefined def hello/0"
  after
    purge(Sample1)
  end

  test "used import via alias" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample1 do
               import List, only: [flatten: 1]

               defmacro generate do
                 List.duplicate(quote(do: flatten([1, 2, 3])), 100)
               end
             end

             defmodule Sample2 do
               import Sample1
               generate()
             end
             """)
           end) == ""
  after
    purge([Sample1, Sample2])
  end

  test "clause not match" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def hello, do: nil
               def hello, do: nil
             end
             """)
           end) =~ "this clause cannot match because a previous clause at line 2 always matches"
  after
    purge(Sample)
  end

  test "clause with defaults should be first" do
    assert capture_err(fn ->
             Code.eval_string(~S"""
             defmodule Sample do
               def hello(arg), do: nil
               def hello(arg \\ 0), do: nil
             end
             """)
           end) =~ "definitions with multiple clauses and default values require a header"
  after
    purge(Sample)
  end

  test "clauses with default should use fun head" do
    assert capture_err(fn ->
             Code.eval_string(~S"""
             defmodule Sample do
               def hello(arg \\ 0), do: nil
               def hello(arg), do: nil
             end
             """)
           end) =~ "definitions with multiple clauses and default values require a header"
  after
    purge(Sample)
  end

  test "unused with local with overridable" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def hello, do: world()
               defp world, do: :ok
               defoverridable [hello: 0]
               def hello, do: :ok
             end
             """)
           end) =~ "function world/0 is unused"
  after
    purge(Sample)
  end

  test "undefined module attribute" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               @foo
             end
             """)
           end) =~
             "undefined module attribute @foo, please remove access to @foo or explicitly set it before access"
  after
    purge(Sample)
  end

  test "undefined module attribute in function" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def hello do
                 @foo
               end
             end
             """)
           end) =~
             "undefined module attribute @foo, please remove access to @foo or explicitly set it before access"
  after
    purge(Sample)
  end

  test "undefined module attribute with file" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               @foo
             end
             """)
           end) =~
             "undefined module attribute @foo, please remove access to @foo or explicitly set it before access"
  after
    purge(Sample)
  end

  test "in guard empty list" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def a(x) when x in [], do: x
             end
             """)
           end) =~ "this check/guard will always yield the same result"
  after
    purge(Sample)
  end

  test "no effect operator" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def a(x) do
                 x != :foo
                 :ok
               end
             end
             """)
           end) =~ "use of operator != has no effect"
  after
    purge(Sample)
  end

  test "badarg warning" do
    assert capture_err(fn ->
             assert_raise ArgumentError, fn ->
               Code.eval_string("""
               defmodule Sample do
                 Atom.to_string "abc"
               end
               """)
             end
           end) =~ "this expression will fail with ArgumentError"
  after
    purge([Sample])
  end

  test "undefined function for behaviour" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample1 do
               @callback foo :: term
             end

             defmodule Sample2 do
               @behaviour Sample1
             end
             """)
           end) =~ "undefined behaviour function foo/0 (for behaviour Sample1)"
  after
    purge([Sample1, Sample2])
  end

  test "undefined macro for behaviour" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample1 do
               @macrocallback foo :: Macro.t
             end

             defmodule Sample2 do
               @behaviour Sample1
             end
             """)
           end) =~ "undefined behaviour macro foo/0 (for behaviour Sample1)"
  after
    purge([Sample1, Sample2])
  end

  test "undefined behavior" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               @behavior Hello
             end
             """)
           end) =~ "@behavior attribute is not supported, please use @behaviour instead"
  after
    purge(Sample)
  end

  test "undefined macro for protocol" do
    assert capture_err(fn ->
             Code.eval_string("""
             defprotocol Sample1 do
               def foo(subject)
             end

             defimpl Sample1, for: Atom do
             end
             """)
           end) =~ "undefined protocol function foo/1 (for protocol Sample1)"
  after
    purge([Sample1, Sample1.Atom])
  end

  test "overridden def" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               def foo(x, 1), do: x + 1
               def bar(), do: nil
               def foo(x, 2), do: x * 2
             end
             """)
           end) =~
             "clauses for the same def should be grouped together, def foo/2 was previously defined (nofile:2)"
  after
    purge(Sample)
  end

  test "warning with overridden file" do
    output =
      capture_err(fn ->
        Code.eval_string("""
        defmodule Sample do
          @file "sample"
          def foo(x), do: :ok
        end
        """)
      end)

    assert output =~ "variable \"x\" is unused"
    assert output =~ "sample:3"
  after
    purge(Sample)
  end

  test "with and do clauses emit errors, else clauses do not" do
    assert capture_err(fn ->
             Code.compile_string("""
             with {:first, int} when is_integer(int) <- {:second, Integer.gcd(2, 4)} do
               int
             end
             """)
           end) =~ "this clause cannot match"

    assert capture_err(fn ->
             Code.compile_string("""
             with {:first, int1} when is_integer(int1) <- {:first, Integer.gcd(2, 4)},
                  {:second, int2} when is_integer(int2) <- {:second, Integer.gcd(2, 4)} do
               {:ok, int1 + int2}
             else
               {:first, nil} -> {:error, "first number is not integer"}
               {:second, nil} -> {:error, "second number is not integer"}
             end
             """)
           end) == ""
  after
    purge(Sample1)
    purge(Sample2)
  end

  test "warning on codepoint escape" do
    assert capture_err(fn ->
             Code.eval_string("? ")
           end) =~ "found ? followed by codepoint 0x20 (space), please use \\s instead"
  end

  test "duplicated docs" do
    output =
      capture_err(fn ->
        Code.eval_string("""
        defmodule Sample do
          @doc "Something"
          @doc "Another"
          def foo, do: :ok

          @doc false
          @doc "Doc"
          def bar, do: :ok
        end
        """)
      end)

    assert output =~ "redefining @doc attribute previously set at line 2"
    assert output =~ "nofile:3: Sample (module)"
    refute output =~ "nofile:7"
  after
    purge(Sample)
  end

  test "typedoc on typep" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               @typedoc "Something"
               @typep priv :: any
               @spec foo() :: priv
               def foo(), do: nil
             end
             """)
           end) =~ "type priv/0 is private, @typedoc's are always discarded for private types"
  after
    purge(Sample)
  end

  test "attribute with no use" do
    content =
      capture_err(fn ->
        Code.eval_string("""
        defmodule Sample do
          @at "Something"
        end
        """)
      end)

    assert content =~ "module attribute @at was set but never used"
    assert content =~ "nofile:2"
  after
    purge(Sample)
  end

  test "typedoc with no type" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               @typedoc "Something"
             end
             """)
           end) =~ "module attribute @typedoc was set but no type follows it"
  after
    purge(Sample)
  end

  test "doc with no function" do
    assert capture_err(fn ->
             Code.eval_string("""
             defmodule Sample do
               @doc "Something"
             end
             """)
           end) =~ "module attribute @doc was set but no definition follows it"
  after
    purge(Sample)
  end

  test "pipe without explicit parentheses" do
    assert capture_err(fn ->
             Code.eval_string("""
             [5, 6, 7, 3]
             |> Enum.map_join "", &(Integer.to_string(&1))
             |> String.to_integer
             """)
           end) =~ "parentheses are required when piping into a function call"
  end

  test "variable is being expanded to function call" do
    output =
      capture_err(fn ->
        Code.eval_string("""
        self
        defmodule Sample do
          def my_node(), do: node
        end
        """)
      end)

    assert output =~ "variable \"self\" does not exist and is being expanded to \"self()\""
    assert output =~ "variable \"node\" does not exist and is being expanded to \"node()\""
  after
    purge(Sample)
  end

  defmodule User do
