       import Kernel, except: [-: 2]
       import Kernel.ExpansionTarget
 
-      assert expand(quote do: <<x::seventeen>>) ==
-             quote do: (<<x()::integer()-size(17)>>)
-
-      assert expand(quote do: (<<seventeen::seventeen, x::size(seventeen)>> = 1)) ==
-             quote do: (<<seventeen::integer()-size(17), x::integer()-size(seventeen)>> = 1)
+      assert expand(quote(do: <<x::seventeen>>)) == quote(do: <<x()::integer()-size(17)>>)
+
+      assert expand(quote(do: <<seventeen::seventeen, x::size(seventeen)>> = 1)) ==
+               quote(do: <<seventeen::integer()-size(17), x::integer()-size(seventeen)>> = 1)
     end
 
     test "expands macro in args" do
       import Kernel, except: [-: 2]
 
-      assert expand(quote do: (require Kernel.ExpansionTarget; <<x::size(Kernel.ExpansionTarget.seventeen)>>)) ==
-             quote do: (:"Elixir.Kernel.ExpansionTarget"; <<x()::integer()-size(17)>>)
+      before_expansion =
+        quote do
+          require Kernel.ExpansionTarget
+          <<x::size(Kernel.ExpansionTarget.seventeen())>>
+        end
+
+      after_expansion =
+        quote do
+          :"Elixir.Kernel.ExpansionTarget"
+          <<x()::integer()-size(17)>>
+        end
+
+      assert expand(before_expansion) == after_expansion
     end
 
     test "supports dynamic size" do
       import Kernel, except: [-: 2]
-      assert expand(quote do: (var = 1; <<x::size(var)-unit(8)>>)) ==
-             quote do: (var = 1; <<x()::integer()-unit(8)-size(var)>>)
+
+      before_expansion =
+        quote do
+          var = 1
+          <<x::size(var)-unit(8)>>
+        end
+
+      after_expansion =
+        quote do
+          var = 1
+          <<x()::integer()-unit(8)-size(var)>>
+        end
+
+      assert expand(before_expansion) == after_expansion
     end
 
     test "raises on size or unit for literal bitstrings" do
-      assert_raise CompileError, ~r"literal <<>> in bitstring supports only type specifiers", fn ->
-        expand(quote do: << <<"foo">>::32 >>)
+      message = ~r"literal <<>> in bitstring supports only type specifiers"
+
+      assert_raise CompileError, message, fn ->
+        expand(quote(do: <<(<<"foo">>::32)>>))
       end
     end
 
     test "raises on size or unit for literal strings" do
-      assert_raise CompileError, ~r"literal string in bitstring supports only endianness and type specifiers", fn ->
-        expand(quote do: <<"foo"::32>>)
+      message = ~r"literal string in bitstring supports only endianness and type specifiers"
+
+      assert_raise CompileError, message, fn ->
+        expand(quote(do: <<"foo"::32>>))
       end
     end
 
     test "raises for invalid size * unit for floats" do
-      assert_raise CompileError, ~r"float requires size\*unit to be 32 or 64 \(default\), got: 128", fn ->
-        expand(quote do: <<12.3::32*4>>)
-      end
-
-      assert_raise CompileError, ~r"float requires size\*unit to be 32 or 64 \(default\), got: 256", fn ->
-        expand(quote do: <<12.3::256>>)
+      message = ~r"float requires size\*unit to be 32 or 64 \(default\), got: 128"
+
+      assert_raise CompileError, message, fn ->
+        expand(quote(do: <<12.3::32*4>>))
+      end
+
+      message = ~r"float requires size\*unit to be 32 or 64 \(default\), got: 256"
+
+      assert_raise CompileError, message, fn ->
+        expand(quote(do: <<12.3::256>>))
       end
     end
 
     test "raises for invalid size" do
-      assert_raise CompileError, ~r"size in bitstring expects an integer or a variable as argument, got: :oops", fn ->
-        expand(quote do: <<"foo"::size(:oops)>>)
+      message = ~r"size in bitstring expects an integer or a variable as argument, got: :oops"
+
+      assert_raise CompileError, message, fn ->
+        expand(quote(do: <<"foo"::size(:oops)>>))
       end
     end
 
     test "raises for invalid unit" do
-      assert_raise CompileError, ~r"unit in bitstring expects an integer as argument, got: :oops", fn ->
-        expand(quote do: <<"foo"::size(8)-unit(:oops)>>)
+      message = ~r"unit in bitstring expects an integer as argument, got: :oops"
+
+      assert_raise CompileError, message, fn ->
+        expand(quote(do: <<"foo"::size(8)-unit(:oops)>>))
       end
     end
 
     test "raises for unknown specifier" do
       assert_raise CompileError, ~r"unknown bitstring specifier: unknown()", fn ->
-        expand(quote do: <<1::unknown>>)
+        expand(quote(do: <<1::unknown>>))
       end
     end
 
     test "raises for conflicting specifiers" do
       assert_raise CompileError, ~r"conflicting endianness specification for bit field", fn ->
-        expand(quote do: <<1::little-big>>)
+        expand(quote(do: <<1::little-big>>))
       end
 
       assert_raise CompileError, ~r"conflicting unit specification for bit field", fn ->
-        expand(quote do: <<x::bitstring-unit(2)>>)
+        expand(quote(do: <<x::bitstring-unit(2)>>))
       end
     end
 
     test "raises for invalid literals" do
       assert_raise CompileError, ~r"invalid literal :foo in <<>>", fn ->
-        expand(quote do: <<:foo>>)
+        expand(quote(do: <<:foo>>))
       end
 
       assert_raise CompileError, ~r"invalid literal \[\] in <<>>", fn ->
-        expand(quote do: <<[]::size(8)>>)
+        expand(quote(do: <<[]::size(8)>>))
       end
     end
 
     test "raises on binary fields with size in matches" do
-      assert expand(quote do: (<<x::binary-size(3), y::binary>> = "foobar"))
-
-      assert_raise CompileError,
-        ~r"a binary field without size is only allowed at the end of a binary pattern",
-        fn -> expand(quote do: (<<x::binary, y::binary>> = "foobar")) end
+      assert expand(quote(do: <<x::binary-size(3), y::binary>> = "foobar"))
+
+      message = ~r"a binary field without size is only allowed at the end of a binary pattern"
+
+      assert_raise CompileError, message, fn ->
+        expand(quote(do: <<x::binary, y::binary>> = "foobar"))
+      end
     end
   end
 
   describe "op ambiguity" do
     test "raises when a call is ambiguous" do
       message = ~r["a -1" looks like a function call but there is a variable named "a"]
-      assert_raise CompileError, message, fn ->
-        expand(quote do: (a = 1; a -1))
+
+      assert_raise CompileError, message, fn ->
+        # We use string_to_quoted! here to avoid the formatter adding parentheses to "a -1".
+        code =
+          Code.string_to_quoted!("""
+          a = 1
+          a -1
+          """)
+
+        expand(code)
       end
     end
   end
 
   test "handles invalid expressions" do
     assert_raise CompileError, ~r"invalid quoted expression: {1, 2, 3}", fn ->
-      expand(quote do: unquote({1, 2, 3}))
+      expand(quote(do: unquote({1, 2, 3})))
     end
 
     assert_raise CompileError, ~r"invalid quoted expression: #Function<", fn ->
-      expand(quote do: unquote({:sample, fn -> nil end}))
+      expand(quote(do: unquote({:sample, fn -> nil end})))
     end
 
     assert_raise CompileError, ~r"invalid pattern in match", fn ->
-      expand(quote do
-        case true do
-          true && true -> true
-        end
-      end)
+      code =
+        quote do
+          case true do
+            true && true -> true
+          end
+        end
+
+      expand(code)
     end
 
     assert_raise CompileError, ~r"invalid pattern in match", fn ->
-      expand(quote do
-        x = &(&1)
-        case true do
-          x.(false) -> true
-        end
-      end)
+      code =
+        quote do
+          x = & &1
+
+          case true do
+            x.(false) -> true
+          end
+        end
+
+      expand(code)
     end
 
     assert_raise CompileError, ~r"invalid expression in guard", fn ->
-      expand(quote do
-        x = &(&1)
-        case true do
-          true when x.(true) -> true
-        end
-      end)
+      code =
+        quote do
+          x = & &1
+
+          case true do
+            true when x.(true) -> true
+          end
+        end
+
+      expand(code)
     end
 
     assert_raise CompileError, ~r"invalid call foo\(1\)\(2\)", fn ->
-      expand(quote do: foo(1)(2))
+      expand(quote(do: foo(1)(2)))
     end
 
     assert_raise CompileError, ~r"invalid call 1\.foo\(\)", fn ->
-      expand(quote do: 1.foo)
+      expand(quote(do: 1.foo))
     end
 
     assert_raise CompileError, ~r"unhandled operator ->", fn ->
-      expand(quote do: (foo -> bar))
-    end
-
-    assert_raise CompileError,
-      ~r"size in bitstring expects an integer or a variable as argument, got: foo\(\)",
-      fn ->
-        expand(quote do
+      expand(quote(do: (foo -> bar)))
+    end
+
+    message = ~r"size in bitstring expects an integer or a variable as argument, got: foo\(\)"
+
+    assert_raise CompileError, message, fn ->
+      code =
+        quote do
           fn <<_::size(foo)>> -> :ok end
-        end)
-      end
+        end
+
+      expand(code)
+    end
   end
 
   ## Helpers

  describe "structs" do
    test "expanded as arguments" do
      assert expand(quote(do: %User{})) ==
             quote do: %:"Elixir.Kernel.ExpansionTest.User"{age: 0, name: ""}

      assert expand(quote(do: %User{name: "john doe"})) ==
             quote do: %:"Elixir.Kernel.ExpansionTest.User"{age: 0, name: "john doe"}
    end

    test "expects atoms" do
      expand(quote do: %unknown{a: 1} = x)

      assert_raise CompileError, ~r"expected struct name to be a compile time atom or alias", fn ->
        expand(quote do: %unknown{a: 1})
      end

      assert_raise CompileError, ~r"expected struct name to be a compile time atom or alias", fn ->
        expand(quote do: %unquote(1){a: 1})
      end

      assert_raise CompileError, ~r"expected struct name in a match to be a compile time atom, alias or a variable", fn ->
        expand(quote do: %unquote(1){a: 1} = x)
      end
    end

    test "update syntax" do
      expand(quote do: %{%{a: 0} | a: 1})

      assert_raise CompileError, ~r"cannot use map/struct update syntax in match", fn ->
        expand(quote do: %{%{a: 0} | a: 1} = %{})
      end
    end

    test "dynamic syntax expands to itself" do
      assert expand(quote do: (%x{} = 1)) == quote do: (%x{} = 1)
    end

    test "unknown ^keys in structs" do
      message = ~r"unknown key \^my_key for struct Kernel\.ExpansionTest\.User"
      assert_raise CompileError, message, fn ->
        expand(quote do
          my_key = :my_key
          %User{^my_key => :my_value} = %{}
        end)
      end
    end
  end

  describe "quote" do
    test "expanded to raw forms" do
      assert expand(quote do: (quote do: hello)) == {:{}, [], [:hello, [], __MODULE__]}
    end

    test "raises if the :context option is nil or not a compile-time module" do
      assert_raise CompileError, ~r"invalid :context for quote, .*, got: :erlang\.self\(\)", fn ->
        expand(quote do: (quote context: self(), do: :ok))
      end

      assert_raise CompileError, ~r"invalid :context for quote, .*, got: nil", fn ->
        expand(quote do: (quote context: nil, do: :ok))
      end
    end

    test "raises for missing do" do
      assert_raise CompileError, ~r"missing :do option in \"quote\"", fn ->
        expand(quote do: (quote context: Foo))
      end
    end

    test "raises for invalid arguments" do
      assert_raise CompileError, ~r"invalid arguments for \"quote\"", fn ->
        expand(quote do: (quote 1 + 1))
      end
    end

    test "raises unless its options are a keyword list" do
      assert_raise CompileError, ~r"invalid options for quote, expected a keyword list", fn ->
        expand(quote do: (quote :foo, do: :foo))
      end
    end
  end

  describe "anonymous calls" do
    test "expands base and args" do
      assert expand(quote do: a.(b)) == quote do: a().(b())
    end

    test "raises on atom base" do
      assert_raise CompileError, ~r"invalid function call :foo.()", fn ->
        expand(quote do: :foo.(a))
      end
    end
  end

  describe "remotes" do
    test "expands to Erlang" do
      assert expand(quote do: Kernel.is_atom(a)) == quote do: :erlang.is_atom(a())
    end

    test "expands macros" do
      assert expand(quote do: Kernel.ExpansionTest.thirteen) == 13
    end

    test "expands receiver and args" do
      assert expand(quote do: a.is_atom(b)) == quote do: a().is_atom(b())
      assert expand(quote do: (a = :foo).is_atom(a)) == quote do: (a = :foo).is_atom(a())
    end

    test "modules must be required for macros" do
      assert expand(quote do: (require Kernel.ExpansionTarget; Kernel.ExpansionTarget.seventeen)) ==
             quote do: (:"Elixir.Kernel.ExpansionTarget"; 17)
    end

    test "raises when not required" do
      msg = ~r"you must require Kernel\.ExpansionTarget before invoking the macro Kernel\.ExpansionTarget\.seventeen/0"
      assert_raise CompileError, msg, fn ->
        expand(quote do: Kernel.ExpansionTarget.seventeen)
      end
    end

    test "in matches" do
      assert_raise CompileError,
        ~r"cannot invoke remote function Hello.something_that_does_not_exist/0 inside match",
        fn -> expand(quote(do: Hello.something_that_does_not_exist() = :foo)) end

      assert_raise CompileError,
        ~r"cannot invoke remote function :erlang.make_ref/0 inside match",
        fn -> expand(quote(do: make_ref() = :foo)) end
    end

    test "in guards" do
      assert_raise CompileError,
        ~r"cannot invoke remote function Hello.something_that_does_not_exist/1 inside guard",
        fn -> expand(quote do: fn arg when Hello.something_that_does_not_exist(arg) -> arg end) end

      assert_raise CompileError,
        ~r"cannot invoke remote function :erlang.make_ref/0 inside guard",
        fn -> expand(quote do: fn arg when make_ref() -> arg end) end
    end
  end

  describe "comprehensions" do
    test "variables do not leak with enums" do
      assert expand(quote do: (for(a <- b, do: c = 1); c)) ==
             quote do: (for(a <- b(), do: c = 1); c())
    end

    test "variables do not leak with binaries" do
      assert expand(quote do: (for(<<a <- b>>, do: c = 1); c)) ==
             quote do: (for(<< <<a :: integer()>> <- b() >>, do: c = 1); c())
    end

    test "variables inside filters are available in blocks" do
      assert expand(quote do: for(a <- b, c = a, do: c)) ==
             quote do: (for(a <- b(), c = a, do: c))
    end

    test "variables inside options do not leak" do
      assert expand(quote do: (for(a <- c = b, into: [], do: 1); c)) ==
             quote do: (for(a <- c = b(), do: 1, into: []); c())

      assert expand(quote do: (for(a <- b, into: c = [], do: 1); c)) ==
             quote do: (for(a <- b(), do: 1, into: c = []); c())
    end

    test "must start with generators" do
      assert_raise CompileError, ~r"for comprehensions must start with a generator", fn ->
        expand(quote do: (for is_atom(:foo), do: :foo))
      end

      assert_raise CompileError, ~r"for comprehensions must start with a generator", fn ->
        expand(quote do: (for do: :foo))
      end
    end

    test "requires size on binary generators" do
      assert_raise CompileError,
        ~r"a binary field without size is only allowed at the end of a binary pattern",
        fn -> expand(quote do: (for <<x::binary <- "123">>, do: x)) end
    end

    test "require do option" do
      assert_raise CompileError,
        ~r"missing :do option in \"for\"",
        fn -> expand(quote do: for _ <- 1..2) end
    end

    test "raise error for unknown options" do
      assert_raise CompileError,
        ~r"unsupported option :else given to for",
        fn -> expand(quote do: for _ <- 1..2, do: 1, else: 1) end

      assert_raise CompileError,
        ~r"unsupported option :other given to for",
        fn -> expand(quote do: for _ <- 1..2, do: 1, other: 1) end
    end
  end

  describe "with" do
    test "variables do not leak" do
      assert expand(quote(do: (with({foo} <- {bar}, do: baz = :ok); baz)))
             quote(do: (with({foo} <- {bar()}, do: baz = :ok); baz()))
    end

    test "variables are available in do option" do
      assert expand(quote(do: (with({foo} <- {bar}, do: baz = foo); baz))) ==
             quote(do: (with({foo} <- {bar()}, do: baz = foo); baz()))
    end

    test "variables inside else do not leak" do
      assert expand(quote(do: (with({foo} <- {bar}, do: :ok, else: (baz -> baz)); baz))) ==
             quote(do: (with({foo} <- {bar()}, do: :ok, else: (baz -> baz)); baz()))
    end

    test "fails if \"do\" is missing" do
      assert_raise CompileError, ~r"missing :do option in \"with\"", fn ->
        expand(quote do: with(_ <- true, []))
      end
    end



  describe "environment macros" do
    test "__MODULE__" do
      assert expand(quote(do: __MODULE__)) == __MODULE__
    end

    test "__DIR__" do
      assert expand(quote(do: __DIR__)) == __DIR__
    end

    test "__ENV__" do
      env = %{__ENV__ | line: 0}
      assert expand_env(quote(do: __ENV__), env) == {{:%{}, [], Map.to_list(env)}, env}
    end

    test "__ENV__.accessor" do
      env = %{__ENV__ | line: 0}
      assert expand_env(quote(do: __ENV__.file), env) == {__ENV__.file, env}

      assert expand_env(quote(do: __ENV__.unknown), env) ==
               {quote(do: unquote({:%{}, [], Map.to_list(env)}).unknown), env}
    end
  end

