require "spec"
require "../../../src/compiler/crystal/formatter"

private def assert_format(input, output = input, strict = false, flags = nil, file = __FILE__, line = __LINE__, focus = false)
  it "formats #{input.inspect}", file, line, focus: focus do
    output = "#{output}\n" unless strict
    result = Crystal.format(input, flags: flags)
    unless result == output
      message = <<-ERROR
        Expected

        ~~~
        #{input.gsub(/([ \t])\n/, "\\1¶\n")}
        ~~~

        to format to:

        ~~~
        #{output.gsub(/([ \t])\n/, "\\1¶\n")}
        ~~~

        but got:

        ~~~
        #{result.gsub(/([ \t])\n/, "\\1¶\n")}
        ~~~

          assert_format #{input.inspect}, #{result.chomp.inspect}
        ERROR

      fail message, file: file, line: line
    end

    # Check idempotency
    result2 = Crystal.format(result, flags: flags)
    unless result == result2
      fail "Idempotency failed:\nBefore: #{result.inspect}\nAfter:  #{result2.inspect}", file: file, line: line
    end
  end
end

describe Crystal::Formatter do
  assert_format "", "", strict: true

  assert_format "nil"

  assert_format "true"
  assert_format "false"

  assert_format "'\\n'"
  assert_format "'a'"
  assert_format "'\\u{0123}'"

  assert_format ":foo"
  assert_format ":\"foo\""

  assert_format "()"
  assert_format "(())"

  assert_format "1"
  assert_format "1   ;    2", "1; 2"
  assert_format "1   ;\n    2", "1\n2"
  assert_format "1\n\n2", "1\n\n2"
  assert_format "1\n\n\n2", "1\n\n2"
  assert_format "1_234", "1_234"
  assert_format "0x1234_u32", "0x1234_u32"
  assert_format "0_u64", "0_u64"
  assert_format "0u64", "0u64"
  assert_format "0i64", "0i64"

  assert_format "   1", "1"
  assert_format "\n\n1", "1"
  assert_format "\n# hello\n1", "# hello\n1"
  assert_format "\n# hello\n\n1", "# hello\n\n1"
  assert_format "\n# hello\n\n\n1", "# hello\n\n1"
  assert_format "\n   # hello\n\n1", "# hello\n\n1"

  assert_format %("hello")
  assert_format %(%(hello))
  assert_format %(%<hello>)
  assert_format %(%[hello])
  assert_format %(%{hello})
  assert_format %("hel\\nlo")
  assert_format %("hel\nlo")

  assert_format "[] of Foo"
  assert_format "[\n]   of   \n   Foo  ", "[] of Foo"
  assert_format "[1, 2, 3]"
  assert_format "[1, 2, 3] of Foo"
  assert_format "  [   1  ,    2  ,    3  ]  ", "[1, 2, 3]"
  assert_format "[1, 2, 3,  ]", "[1, 2, 3]"
  assert_format "[1,\n2,\n3]", "[1,\n 2,\n 3]"
  assert_format "[1,\n2,\n3\n]", "[1,\n 2,\n 3,\n]"
  assert_format "[\n1,\n2,\n3]", "[\n  1,\n  2,\n  3,\n]"
  assert_format "[\n  [\n    1,\n  ], [\n    2,\n  ], [\n    3,\n  ],\n]"
  assert_format "[\n  {\n    1 => 2,\n  }, {\n    3 => 4,\n  }, {\n    5 => 6,\n  },\n]"
  assert_format "if 1\n[   1  ,    2  ,    3  ]\nend", "if 1\n  [1, 2, 3]\nend"
  assert_format "    [   1,   \n   2   ,   \n   3   ]   ", "[1,\n 2,\n 3]"
  assert_format "Set { 1 , 2 }", "Set{1, 2}"
  assert_format "[\n1,\n\n2]", "[\n  1,\n\n  2,\n]"
  assert_format "[ # foo\n  1,\n]"
  assert_format "Set{ # foo\n  1,\n}"
  assert_format "begin\n  array[\n    0 # Zero\n  ]\nend"
  assert_format "begin\n  array[\n    0, # Zero\n  ]\nend"
  assert_format "[\n  # foo\n] of String"
  assert_format "[\n# foo\n] of String", "[\n  # foo\n] of String"

  assert_format "{1, 2, 3}"
  assert_format "{ {1, 2, 3} }"
  assert_format "{ {1 => 2} }"
  assert_format "{ {1, 2, 3} => 4 }"
  assert_format "{ {foo: 2} }"
  assert_format "{ # foo\n  1,\n}"

  assert_format "{ * 1 * 2,\n*\n3, 4 }", "{*1 * 2,\n *3, 4}"
  assert_format "[ * [ * [ 1 ] ], *    \n[ 2] ]", "[*[*[1]], *[2]]"

  assert_format "{  } of  A   =>   B", "{} of A => B"
  assert_format "{ 1   =>   2 }", "{1 => 2}"
  assert_format "{ 1   =>   2 ,   3  =>  4 }", "{1 => 2, 3 => 4}"
  assert_format "{ 1   =>   2 ,\n   3  =>  4 }", "{1 => 2,\n 3 => 4}"
  assert_format "{\n1   =>   2 ,\n   3  =>  4 }", "{\n  1 => 2,\n  3 => 4,\n}"
  assert_format "{ foo:  1 }", "{foo: 1}"
  assert_format "{ \"foo\":  1 }", "{\"foo\": 1}"
  assert_format "{ \"foo\" =>  1 }", "{\"foo\" => 1}"
  assert_format "{ 1   =>   2 ,\n\n   3  =>  4 }", "{1 => 2,\n\n 3 => 4}"
  assert_format "foo({\nbar: 1,\n})", "foo({\n  bar: 1,\n})"
  assert_format "{ # foo\n  1 => 2,\n}"

  assert_format "Foo"
  assert_format "Foo:: Bar", "Foo::Bar"
  assert_format "Foo:: Bar", "Foo::Bar"
  assert_format "::Foo:: Bar", "::Foo::Bar"
  assert_format "Foo(  )", "Foo()"
  assert_format "Foo( A , 1 )", "Foo(A, 1)"
  assert_format "Foo( x:  Int32  )", "Foo(x: Int32)"
  assert_format "Foo( x:  Int32  ,  y: Float64 )", "Foo(x: Int32, y: Float64)"
  assert_format "Foo(  * T, { * A  ,*\n  B } )", "Foo(*T, {*A, *B})"
  assert_format "Foo( Bar(  ) )", "Foo(Bar())"

  assert_format "NamedTuple(a: Int32,)", "NamedTuple(a: Int32)"
  assert_format "NamedTuple(\n  a: Int32,\n)"
  assert_format "NamedTuple(\n  a: Int32,)", "NamedTuple(\n  a: Int32,\n)"
  assert_format "class Foo\n  NamedTuple(\n    a: Int32,\n  )\nend"

  # Multi-line generic type with inline comments (issue #11328)
  assert_format "Tuple(\n  Int32, # first\n  String, # second\n)", "Tuple(\n  Int32,  # first\n  String, # second\n)"
  assert_format "Tuple(\n  Int32, # first\n  String, # second\n  Bool,\n)", "Tuple(\n  Int32,  # first\n  String, # second\n  Bool,\n)"
  assert_format "Tuple(\n  Int32, # first\n  String # adds trailing comma\n)", "Tuple(\n  Int32,  # first\n  String, # adds trailing comma\n)"
  assert_format "Hash(\n  String, # key\n  Int32, # value\n)", "Hash(\n  String, # key\n  Int32,  # value\n)"
  assert_format "Tuple(\n  Int32,\n  String\n)", "Tuple(\n  Int32,\n  String,\n)"

  assert_format "::Tuple(T)"
  assert_format "::NamedTuple(T)"
  assert_format "::Pointer(T)"
  assert_format "::StaticArray(T)"

  assert_format "Tuple()"
  assert_format "::Tuple()"
  assert_format "NamedTuple()"
  assert_format "::NamedTuple()"

  %w(if unless).each do |keyword|
    assert_format "#{keyword} a\n2\nend", "#{keyword} a\n  2\nend"
    assert_format "#{keyword} a\n2\n3\nend", "#{keyword} a\n  2\n  3\nend"
    assert_format "#{keyword} a\n2\nelse\nend", "#{keyword} a\n  2\nelse\nend"
    assert_format "#{keyword} a\nelse\n2\nend", "#{keyword} a\nelse\n  2\nend"
    assert_format "#{keyword} a\n2\nelse\n3\nend", "#{keyword} a\n  2\nelse\n  3\nend"
    assert_format "#{keyword} a\n2\n3\nelse\n4\n5\nend", "#{keyword} a\n  2\n  3\nelse\n  4\n  5\nend"
    assert_format "#{keyword} a\n#{keyword} b\n3\nelse\n4\nend\nend", "#{keyword} a\n  #{keyword} b\n    3\n  else\n    4\n  end\nend"
    assert_format "#{keyword} a\n#{keyword} b\nelse\n4\nend\nend", "#{keyword} a\n  #{keyword} b\n  else\n    4\n  end\nend"
    assert_format "#{keyword} a\n    # hello\n 2\nend", "#{keyword} a\n  # hello\n  2\nend"
    assert_format "#{keyword} a\n2; 3\nelse\n3\nend", "#{keyword} a\n  2; 3\nelse\n  3\nend"
  end

  assert_format "if 1\n2\nelsif\n3\n4\nend", "if 1\n  2\nelsif 3\n  4\nend"
  assert_format "if 1\n2\nelsif\n3\n4\nelsif 5\n6\nend", "if 1\n  2\nelsif 3\n  4\nelsif 5\n  6\nend"
  assert_format "if 1\n2\nelsif\n3\n4\nelse\n6\nend", "if 1\n  2\nelsif 3\n  4\nelse\n  6\nend"

  assert_format "{% if 1 %}\n  2\n{% end %}\ndef foo\nend"

  assert_format "if 1\n2\nend\nif 3\nend", "if 1\n  2\nend\nif 3\nend"
  assert_format "if 1\nelse\n2\nend\n3", "if 1\nelse\n  2\nend\n3"

  assert_format "1 ? 2 : 3"
  assert_format "1 ?\n  2    :   \n 3", "1 ? 2 : 3"

  assert_format "1   if   2", "1 if 2"
  assert_format "1   unless   2", "1 unless 2"

  assert_format "[] of Int32\n1"

  assert_format "(1)"
  assert_format "  (  1;  2;   3  )  ", "(1; 2; 3)"
  assert_format "(\n  a = 1\n  a\n)"
  assert_format "begin; 1; end", "begin\n  1\nend"
  assert_format "begin\n1\n2\n3\nend", "begin\n  1\n  2\n  3\nend"
  assert_format "begin\n1 ? 2 : 3\nend", "begin\n  1 ? 2 : 3\nend"
  assert_format "begin\n  begin\n\n  end\nend"
  assert_format "begin\n  ()\nend"

  assert_format "def   foo  \n  end", "def foo\nend"
  assert_format "def foo\n1\nend", "def foo\n  1\nend"
  assert_format "def foo\n\n1\n\nend", "def foo\n  1\nend"
  assert_format "def foo()\n1\nend", "def foo\n  1\nend"
  assert_format "def foo   (   )   \n1\nend", "def foo\n  1\nend"
  assert_format "def self . foo\nend", "def self.foo\nend"
  assert_format "def   foo (  x )  \n  end", "def foo(x)\nend"
  assert_format "def   foo (  x , y )  \n  end", "def foo(x, y)\nend"
  assert_format "def   foo (  x , y , )  \n  end", "def foo(x, y)\nend"
  assert_format "def   foo (  x , y ,\n)  \n  end", "def foo(x, y)\nend"
  assert_format "def   foo (  x ,\n y )  \n  end", "def foo(x,\n        y)\nend"
  assert_format "def   foo (\nx ,\n y )  \n  end", "def foo(\n  x,\n  y,\n)\nend"
  assert_format "class Foo\ndef   foo (\nx ,\n y )  \n  end\nend", "class Foo\n  def foo(\n    x,\n    y,\n  )\n  end\nend"
  assert_format "def   foo (  @x)  \n  end", "def foo(@x)\nend"
  assert_format "def   foo (  @x, @y)  \n  end", "def foo(@x, @y)\nend"
  assert_format "def   foo (  @@x)  \n  end", "def foo(@@x)\nend"
  assert_format "def   foo (  &@block)  \n  end", "def foo(&@block)\nend"
  assert_format "def   foo (  @select)  \n  end", "def foo(@select)\nend"
  assert_format "def   foo (  @@select)  \n  end", "def foo(@@select)\nend"
  assert_format "def   foo (  bar  @select)  \n  end", "def foo(bar @select)\nend"
  assert_format "def   foo (  bar  @@select)  \n  end", "def foo(bar @@select)\nend"
  assert_format "def foo(a, &@b)\nend"
  assert_format "def   foo (  x  =   1 )  \n  end", "def foo(x = 1)\nend"
  assert_format "def   foo (  x  :  Int32 )  \n  end", "def foo(x : Int32)\nend"
  assert_format "def   foo (  x  :  self )  \n  end", "def foo(x : self)\nend"
  assert_format "def   foo (  x  :  Foo.class )  \n  end", "def foo(x : Foo.class)\nend"
  assert_format "def   foo (  x  :   Int32  =  1 )  \n  end", "def foo(x : Int32 = 1)\nend"
  assert_format "abstract  def   foo  \n  1", "abstract def foo\n\n1"
  assert_format "def foo( & block )\nend", "def foo(&block)\nend"
  assert_format "def foo( & )\nend", "def foo(&)\nend"
  assert_format "def foo( & \n )\nend", "def foo(&)\nend"
  assert_format "def foo( x , & block )\nend", "def foo(x, &block)\nend"
  assert_format "def foo( x , & block  : Int32 )\nend", "def foo(x, &block : Int32)\nend"
  assert_format "def foo( x , & block  : Int32 ->)\nend", "def foo(x, &block : Int32 ->)\nend"
  assert_format "def foo( x , & block  : Int32->Float64)\nend", "def foo(x, &block : Int32 -> Float64)\nend"
  assert_format "def foo( x , & block  :   ->)\nend", "def foo(x, &block : ->)\nend"
  assert_format "def foo( x , & : Int32 )\nend", "def foo(x, & : Int32)\nend"
  assert_format "def foo(&: Int32)\nend", "def foo(& : Int32)\nend"
  assert_format "def foo(&block: Int32)\nend", "def foo(&block : Int32)\nend"
  assert_format "def foo( x , * y )\nend", "def foo(x, *y)\nend"
  assert_format "class Bar\nprotected def foo(x)\na=b(c)\nend\nend", "class Bar\n  protected def foo(x)\n    a = b(c)\n  end\nend"
  assert_format "def foo=(x)\nend"
  assert_format "def +(x)\nend"
  assert_format "def   foo  :  Int32 \n  end", "def foo : Int32\nend"
  assert_format "def   foo ( x )  :  Int32 \n  end", "def foo(x) : Int32\nend"
  assert_format "def foo: Int32\nend", "def foo : Int32\nend"
  assert_format "def %(x)\n  1\nend"
  assert_format "def //(x)\n  1\nend"
  assert_format "def `(x)\n  1\nend"
  assert_format "def /(x)\n  1\nend"
  assert_format "def foo(x : X)  forall   X ,   Y; end", "def foo(x : X) forall X, Y; end"
  assert_format "def foo(x)\n  self // x\nend"
  assert_format "def foo(x)\n  case self // x\n  when 2\n    3\n  end\nend"
  assert_format "def foo(x)\n  case 1\n  when self // 2\n    3\n  end\nend"
  assert_format "def foo(x)\n  case //\n  when //\n    3\n  end\nend"
  assert_format "foo self // 1"
  assert_format "foo(self // 1)"
  assert_format "foo x, self // 1"
  assert_format "{x => self // 1}"
  assert_format "foo(//, //)"
  assert_format "foo(a: 1 // 2)"
  assert_format "foo(a: //)"
  assert_format "foo(a: //, b: //)"

  assert_format "def foo(a : T) forall T \n  #\nend", "def foo(a : T) forall T\n  #\nend"
  assert_format "def foo(a : T, b : U) forall T, U\n  #\nend", "def foo(a : T, b : U) forall T, U\n  #\nend"
  assert_format "def foo(a : T, b : U) forall T, U         #\n  #\nend", "def foo(a : T, b : U) forall T, U #\n  #\nend"
  assert_format "def foo(a : T) forall T\n  #\n\nend", "def foo(a : T) forall T\n  #\nend"
  assert_format "def foo(a : T) forall T\n  #\n\n\nend", "def foo(a : T) forall T\n  #\nend"
  assert_format "def foo\n  1\n  #\nrescue\nend"
  assert_format "def foo\n  1 #\nrescue\nend"
  assert_format "def foo\n  1 #\nrescue\nend"
  assert_format "def foo\n  1\n  #\n\n\nrescue\nend", "def foo\n  1\n  #\nrescue\nend"

  assert_format "def foo(@[MyAnn] v); end"
  assert_format "def foo(@[MyAnn] &); end"
  assert_format "def foo(@[MyAnn] &block); end"
  assert_format "def foo(@[MyAnn] & : String -> Nil); end"
  assert_format "def foo(  @[MyAnn]  v  ); end", "def foo(@[MyAnn] v); end"
  assert_format "def foo(@[AnnOne] @[AnnTwo] v); end"
  assert_format "def foo(@[AnnOne]   @[AnnTwo] v); end", "def foo(@[AnnOne] @[AnnTwo] v); end"
  assert_format "def foo(@[AnnOne]   @[AnnTwo]   &  ); end", "def foo(@[AnnOne] @[AnnTwo] &); end"
  assert_format "def foo(@[AnnOne]   @[AnnTwo]   &block : Int32 ->  ); end", "def foo(@[AnnOne] @[AnnTwo] &block : Int32 ->); end"
  assert_format <<-CRYSTAL
  def foo(
    @[MyAnn] bar,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    foo,
    @[MyAnn] &block
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    foo,
    @[MyAnn]
    &block
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    foo,

    @[MyAnn]
    &block
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    foo,

    @[MyAnn]
    @[MyAnn]
    & : Nil -> Nil
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
  def foo(
     @[MyAnn]   bar
  ); end
  CRYSTAL
  def foo(
    @[MyAnn] bar,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    @[MyAnn]
    bar,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    @[MyAnn]
    @[MyAnn]
    bar,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    @[MyAnn]
    @[MyAnn]
    bar,
    @[MyAnn] baz,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    @[MyAnn]
    @[MyAnn]
    bar,

    @[MyAnn] baz,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
  def foo(
     @[MyAnn]
   bar
  ); end
  CRYSTAL
  def foo(
    @[MyAnn]
    bar,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
  def foo(
     @[MyAnn]
   bar
  ); end
  CRYSTAL
  def foo(
    @[MyAnn]
    bar,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    @[MyAnn]
    @[MyAnn]
    bar,
    @[MyAnn] @[MyAnn] baz,
    @[MyAnn]
    @[MyAnn]
    biz,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL
  def foo(
    @[MyAnn]
    @[MyAnn]
    bar,

    @[MyAnn] @[MyAnn] baz,

    @[MyAnn]
    @[MyAnn]
    biz,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
  def foo(
    @[MyAnn]
    @[MyAnn]
    bar,

    @[MyAnn]  @[MyAnn]  baz,

    @[MyAnn]

    @[MyAnn]

    biz
  ); end
  CRYSTAL
  def foo(
    @[MyAnn]
    @[MyAnn]
    bar,

    @[MyAnn] @[MyAnn] baz,

    @[MyAnn]
    @[MyAnn]
    biz,
  ); end
  CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
    module M
      @[MyAnn(
        1

      )]
    end
    CRYSTAL
    module M
      @[MyAnn(
        1
      )]
    end
    CRYSTAL

  assert_format "loop do\n  1\nrescue\n  2\nend"
  assert_format "loop do\n  1\n  loop do\n    2\n  rescue\n    3\n  end\n  4\nend"

  assert_format "foo"
  assert_format "foo()"
  assert_format "foo(  )", "foo()"
  assert_format "foo  1", "foo 1"
  assert_format "foo  1  ,   2", "foo 1, 2"
  assert_format "foo(  1  ,   2 )", "foo(1, 2)"

  assert_format "foo . bar", "foo.bar"
  assert_format "foo . bar()", "foo.bar"
  assert_format "foo . bar( x , y )", "foo.bar(x, y)"
  assert_format "foo do  \n x \n end", "foo do\n  x\nend"
  assert_format "foo do  | x | \n x \n end", "foo do |x|\n  x\nend"
  assert_format "foo do  | x , y | \n x \n end", "foo do |x, y|\n  x\nend"
  assert_format "if 1\nfoo do  | x , y | \n x \n end\nend", "if 1\n  foo do |x, y|\n    x\n  end\nend"
  assert_format "foo do   # hello\nend", "foo do # hello\nend"
  assert_format "foo{}", "foo { }"
  assert_format "foo{|x| x}", "foo { |x| x }"
  assert_format "foo{|x|\n x}", "foo { |x|\n  x\n}"
  assert_format "foo   &.bar", "foo &.bar"
  assert_format "foo   &.bar( 1 , 2 )", "foo &.bar(1, 2)"
  assert_format "foo.bar  &.baz( 1 , 2 )", "foo.bar &.baz(1, 2)"
  assert_format "foo   &.bar", "foo &.bar"
  assert_format "foo   &.==(2)", "foo &.==(2)"
  assert_format "foo   &.>=(2)", "foo &.>=(2)"
  assert_format "join io, &.inspect"
  assert_format "foo . bar  =  1", "foo.bar = 1"
  assert_format "foo  x:  1", "foo x: 1"
  assert_format "foo  x:  1,  y:  2", "foo x: 1, y: 2"
  assert_format "foo a , b ,  x:  1", "foo a, b, x: 1"
  assert_format "foo a , *b", "foo a, *b"
  assert_format "foo a , **b", "foo a, **b"
  assert_format "foo   &bar", "foo &bar"
  assert_format "foo 1 ,  &bar", "foo 1, &bar"
  assert_format "foo(&.bar)"
  assert_format "foo.bar(&.baz)"
  assert_format "foo(1, &.bar)"
  assert_format "foo(1,\n  &.bar)"
  assert_format "foo(1, # foo\n  &.bar)"
  assert_format "::foo(1, 2)"
  assert_format "args.any? &.name.baz"
  assert_format "foo(\n  1, 2)", "foo(\n  1, 2)"
  assert_format "foo(\n1,\n 2  \n)", "foo(\n  1,\n  2\n)"
  assert_format "foo(\n1,\n\n 2  \n)", "foo(\n  1,\n\n  2\n)"
  assert_format "foo(\n  1,\n  # 2,\n  3,\n)"
  assert_format "foo(\n  1,\n  # 2,\n  # 3,\n)"
  assert_format "foo 1,\n2", "foo 1,\n  2"
  assert_format "foo 1, a: 1,\nb: 2,\nc: 3", "foo 1, a: 1,\n  b: 2,\n  c: 3"
  assert_format "foo 1,\na: 1,\nb: 2,\nc: 3", "foo 1,\n  a: 1,\n  b: 2,\n  c: 3"
  assert_format "foo bar:baz, qux:other", "foo bar: baz, qux: other"
  assert_format "foo(\n  1, 2, &block)", "foo(\n  1, 2, &block)"
  assert_format "foo(\n  1, 2,\n&block)", "foo(\n  1, 2,\n  &block)"
  assert_format "foo(\n  1,\n  2\n) do\n  1\nend"
  assert_format "foo 1, a: 1,\nb: 2,\nc: 3,\n&block", "foo 1, a: 1,\n  b: 2,\n  c: 3,\n  &block"
  assert_format "foo 1, do\n2\nend", "foo 1 do\n  2\nend"
  assert_format "a.b &.[c]?\n1"
  assert_format "a.b &.[c]\n1"
  assert_format "foo(1, 2,)", "foo(1, 2)"
  assert_format "foo(1, 2,\n)", "foo(1, 2)"
  assert_format "foo(1,\n2,\n)", "foo(1,\n  2,\n)"
  assert_format "foo(out x)", "foo(out x)"
  assert_format "foo(\n  1,\n  a: 1,\n  b: 2,\n)"
  assert_format "foo(1, ) { }", "foo(1) { }"
  assert_format "foo(1, ) do\nend", "foo(1) do\nend"
  assert_format "foo {;1}", "foo { 1 }"
  assert_format "foo {;;1}", "foo { 1 }"
  assert_format "foo.%(bar)"
  assert_format "foo.% bar"
  assert_format "foo.bar(&.%(baz))"
  assert_format "foo.bar(&.% baz)"
  assert_format "if 1\n  foo(\n    bar\n    # comment\n  )\nend"
  assert_format "if 1\n  foo(\n    bar,\n    # comment\n  )\nend"

  assert_format "foo.bar\n.baz", "foo.bar\n  .baz"
  assert_format "foo.bar.baz\n.qux", "foo.bar.baz\n  .qux"
  assert_format "foo\n.bar\n.baz", "foo\n  .bar\n  .baz"

  assert_format "foo.\nbar", "foo\n  .bar"

  assert_format "foo   &.is_a?(T)", "foo &.is_a?(T)"
  assert_format "foo   &.responds_to?(:foo)", "foo &.responds_to?(:foo)"

  assert_format "foo(\n  1,\n  &.foo\n)"

  %w(return break next yield).each do |keyword|
    assert_format keyword
    assert_format "#{keyword}( 1 )", "#{keyword}(1)"
    assert_format "#{keyword}  1", "#{keyword} 1"
    assert_format "#{keyword}( 1 , 2 )", "#{keyword}(1, 2)"
    assert_format "#{keyword}  1 ,  2", "#{keyword} 1, 2"
    assert_format "#{keyword}  *1", "#{keyword} *1"
    assert_format "#{keyword}  1  , *2", "#{keyword} 1, *2"
    assert_format "#{keyword}  *1  ,2", "#{keyword} *1, 2"
    assert_format "#{keyword}  *1  , *2", "#{keyword} *1, *2"
    assert_format "#{keyword}( *1  , *2 )", "#{keyword}(*1, *2)"

    unless keyword == "yield"
      assert_format "#{keyword} { 1 ,  2 }", "#{keyword} {1, 2}"
      assert_format "#{keyword} {1, 2}, 3"
      assert_format "#{keyword} 1, {2, 3}"
      assert_format "#{keyword} {1, 2}, {3, 4}"
      assert_format "#{keyword} { {1, 2}, {3, 4} }"
      assert_format "#{keyword} { {1, 2}, {3, 4} }, 5"
    end
  end

  assert_format "yield 1\n2", "yield 1\n2"
  assert_format "yield 1 , \n2", "yield 1,\n  2"
  assert_format "yield(1 , \n2)", "yield(1,\n  2)"
  assert_format "yield(\n1 , \n2)", "yield(\n  1,\n  2)"

  assert_format "with foo yield bar"

  context "adds `&` to yielding methods that don't have a block parameter (#8764)" do
    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo
        yield
      end
      CRYSTAL
      def foo(&)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo()
        yield
      end
      CRYSTAL
      def foo(&)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
      )
        yield
      end
      CRYSTAL
      def foo(&)
        yield
      end
      CRYSTAL

    # #13091
    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo # bar
        yield
      end
      CRYSTAL
      def foo(&) # bar
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(x)
        yield
      end
      CRYSTAL
      def foo(x, &)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(x ,)
        yield
      end
      CRYSTAL
      def foo(x, &)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(x,
      y)
        yield
      end
      CRYSTAL
      def foo(x,
              y, &)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(x,
      y,)
        yield
      end
      CRYSTAL
      def foo(x,
              y, &)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(x
      )
        yield
      end
      CRYSTAL
      def foo(x,
              &)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(x,
      )
        yield
      end
      CRYSTAL
      def foo(x,
              &)
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
      x)
        yield
      end
      CRYSTAL
      def foo(
        x, &
      )
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
      x, y)
        yield
      end
      CRYSTAL
      def foo(
        x, y, &
      )
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
      x,
      y)
        yield
      end
      CRYSTAL
      def foo(
        x,
        y, &
      )
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
      x,
      )
        yield
      end
      CRYSTAL
      def foo(
        x,
        &
      )
        yield
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(a, **b)
        yield
      end
      CRYSTAL
      def foo(a, **b, &)
        yield
      end
      CRYSTAL

    assert_format "macro f\n yield\n {{ yield }}\nend"
  end

  assert_format <<-CRYSTAL
    def foo(
      a,
      b,
    )
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    def foo(
      a, b,
    )
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    macro foo(
      a,
      *b,
    )
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    macro foo(
      a,
      **b,
    )
    end
    CRYSTAL

  context "adds trailing comma to def multi-line normal, splat, and double splat parameters" do
    assert_format <<-CRYSTAL, <<-CRYSTAL
      macro foo(
        a,
        b
      )
      end
      CRYSTAL
      macro foo(
        a,
        b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      macro foo(
        a,
        *b
      )
      end
      CRYSTAL
      macro foo(
        a,
        *b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      fun foo(
        a : Int32,
        b : Int32
      )
      end
      CRYSTAL
      fun foo(
        a : Int32,
        b : Int32,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      fun foo(
        a : Int32,
        ...
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a,
        b
      )
      end
      CRYSTAL
      def foo(
        a,
        b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a : Int32,
        b : Int32
      )
      end
      CRYSTAL
      def foo(
        a : Int32,
        b : Int32,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a : Int32,
        b : Int32 = 1
      )
      end
      CRYSTAL
      def foo(
        a : Int32,
        b : Int32 = 1,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a,
        b c
      )
      end
      CRYSTAL
      def foo(
        a,
        b c,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a,
        @[Ann] b
      )
      end
      CRYSTAL
      def foo(
        a,
        @[Ann] b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a,
        @[Ann]
        b
      )
      end
      CRYSTAL
      def foo(
        a,
        @[Ann]
        b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a, b
      )
      end
      CRYSTAL
      def foo(
        a, b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a, b,
        c, d
      )
      end
      CRYSTAL
      def foo(
        a, b,
        c, d,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a, # Foo
        b # Bar
      )
      end
      CRYSTAL
      def foo(
        a, # Foo
        b, # Bar
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a,
        *b
      )
      end
      CRYSTAL
      def foo(
        a,
        *b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL, <<-CRYSTAL
      def foo(
        a,
        **b
      )
      end
      CRYSTAL
      def foo(
        a,
        **b,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(
        a,
        &block
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(
        a,
      )
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(a)
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(a, b)
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(a, *args)
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(a, *args, &block)
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(a, **kwargs)
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(a, **kwargs, &block)
      end
      CRYSTAL

    assert_format <<-CRYSTAL
      def foo(a, &block)
      end
      CRYSTAL
  end

  assert_format "1   +   2", "1 + 2"
  assert_format "1   &+   2", "1 &+ 2"
  assert_format "1   >   2", "1 > 2"
  assert_format "1   *   2", "1 * 2"
  assert_format "1*2", "1*2"
  assert_format "1/2", "1/2"
  assert_format "1 / 2", "1 / 2"
  assert_format "10/a", "10/a"
  assert_format "10 / a", "10 / a"
  assert_format "1 // 2", "1 // 2"
  assert_format "10//a", "10//a"
  assert_format "10 // a", "10 // a"
  assert_format "10**a", "10**a"
  assert_format "10 ** a", "10 ** a"
  assert_format %(" " * 2)
  assert_format "foo.bar / 2\n", "foo.bar / 2"

  assert_format "! 1", "!1"
  assert_format "- 1", "-1"
  assert_format "~ 1", "~1"
  assert_format "+ 1", "+1"
  assert_format "&- 1", "&-1"
  assert_format "&+ 1", "&+1"
  assert_format "a-1", "a - 1"
  assert_format "a+1", "a + 1"
  assert_format "a&-1", "a &- 1"
  assert_format "a&+1", "a &+ 1"
  assert_format "1 + \n2", "1 +\n  2"
  assert_format "1 +  # foo\n2", "1 + # foo\n  2"
  assert_format "a = 1 +  #    foo\n2", "a = 1 + #    foo\n    2"
  assert_format "1+2*3", "1 + 2*3"
  assert_format "1&+2&*3", "1 &+ 2 &* 3"

  assert_format "foo(1 + \n2)", "foo(1 +\n    2)"
  assert_format "foo(1 &+ \n2)", "foo(1 &+\n    2)"

  assert_format "foo(1 &- 2)"

  assert_format "foo[]", "foo[]"
  assert_format "foo[ 1 , 2 ]", "foo[1, 2]"
  assert_format "foo[ 1,  2 ]?", "foo[1, 2]?"
  assert_format "foo[] =1", "foo[] = 1"
  assert_format "foo[ 1 , 2 ]   =3", "foo[1, 2] = 3"

  assert_format "foo.[]"
  assert_format "foo.[ 1 , 2 ]", "foo.[1, 2]"
  assert_format "foo.[ 1,  2 ]?", "foo.[1, 2]?"
  assert_format "foo.[] =1", "foo.[] = 1"
  assert_format "foo.[ 1 , 2 ]   =3", "foo.[1, 2] = 3"

  assert_format "foo.[]()", "foo.[]"
  assert_format "foo.[]( 1 , 2 )", "foo.[](1, 2)"
  assert_format "foo.[]?( 1,  2 )", "foo.[]?(1, 2)"
  assert_format "foo.[] =(1)", "foo.[] = (1)"
  assert_format "foo.[]=( 1 , 2 , 3 )", "foo.[]=(1, 2, 3)"

  assert_format "1  ||  2", "1 || 2"
  assert_format "a  ||  b", "a || b"
  assert_format "1  &&  2", "1 && 2"
  assert_format "1 &&\n2", "1 &&\n  2"
  assert_format "1 &&\n2 &&\n3", "1 &&\n  2 &&\n  3"
  assert_format "1 && # foo\n  2 &&\n  3"
  assert_format "if 0\n1 &&\n2 &&\n3\nend", "if 0\n  1 &&\n    2 &&\n    3\nend"
  assert_format "if 1 &&\n2 &&\n3\n4\nend", "if 1 &&\n   2 &&\n   3\n  4\nend"
  assert_format "if 1 &&\n   (2 || 3)\n  1\nelse\n  2\nend"
  assert_format "while 1 &&\n2 &&\n3\n4\nend", "while 1 &&\n      2 &&\n      3\n  4\nend"

  assert_format "def foo(x =  __FILE__ )\nend", "def foo(x = __FILE__)\nend"

  assert_format "a=1", "a = 1"

  assert_format "while 1\n2\nend", "while 1\n  2\nend"
  assert_format "until 1\n2\nend", "until 1\n  2\nend"

  assert_format "a = begin\n1\n2\nend", "a = begin\n  1\n  2\nend"
  assert_format "a = if 1\n2\n3\nend", "a = if 1\n      2\n      3\n    end"
  assert_format "a = if 1\n2\nelse\n3\nend", "a = if 1\n      2\n    else\n      3\n    end"
  assert_format "a = if 1\n2\nelsif 3\n4\nend", "a = if 1\n      2\n    elsif 3\n      4\n    end"
  assert_format "a = [\n1,\n2]", "a = [\n  1,\n  2,\n]"
  assert_format "a = while 1\n2\nend", "a = while 1\n  2\nend"
  assert_format "a = case 1\nwhen 2\n3\nend", "a = case 1\n    when 2\n      3\n    end"
  assert_format "a = case 1\nwhen 2\n3\nelse\n4\nend", "a = case 1\n    when 2\n      3\n    else\n      4\n    end"
  assert_format "a = \nif 1\n2\nend", "a =\n  if 1\n    2\n  end"
  assert_format "a, b = \nif 1\n2\nend", "a, b =\n  if 1\n    2\n  end"
  assert_format "a = b = 1\na, b =\n  b, a"
  assert_format "a = # foo\n  bar(1)"
  assert_format "a = \\\n  # foo\n  bar(1)"
  assert_format "a = \\\n  # foo\n  nil"

  assert_format %(require   "foo"), %(require "foo")

  assert_format "private   getter   foo", "private getter foo"

  assert_format %("foo \#{ 1  +  2 }"), %("foo \#{1 + 2}")
  assert_format %("foo \#{ 1 } \#{ __DIR__ }"), %("foo \#{1} \#{__DIR__}")
  assert_format %("foo \#{ __DIR__ }"), %("foo \#{__DIR__}")
  assert_format "__FILE__", "__FILE__"
  assert_format "__DIR__", "__DIR__"
  assert_format "__LINE__", "__LINE__"

  assert_format %q("\\\"\#\a\b\n\r\t\v\f\e")
  assert_format %q("\a\c\b\d"), %q("\ac\bd")
  assert_format %q("\\\"\#\a\b\n\r\t#{foo}\v\f\e")
  assert_format %q("\a\c#{foo}\b\d"), %q("\ac#{foo}\bd")

  assert_format %("\#{foo = 1\n}"), %("\#{foo = 1}")
  assert_format %("\#{\n  foo = 1\n}")
  assert_format %("\#{\n  foo = 1}"), %("\#{\n  foo = 1\n}")
  assert_format %("\#{ # foo\n  foo = 1\n}")
  assert_format %("\#{"foo"}")
  assert_format %("\#{"\#{foo}"}")
  assert_format %("foo\#{"bar"} Baz \#{"qux"} ")
  assert_format %("1\#{"4\#{"\#{"2"}"}3"}3\#{__DIR__}4\#{5}6")
  assert_format %("1\#{"\#{"2"}"}3\#{"4"}5")

  assert_format "%w(one   two  three)", "%w(one two three)"
  assert_format "%i(one   two  three)", "%i(one two three)"
  assert_format "%w{one(   two(  three)}", "%w{one( two( three)}"
  assert_format "%i{one(   two(  three)}", "%i{one( two( three)}"

  assert_format "/foo/"
  assert_format "/foo/imx"
  assert_format "/foo \#{ bar }/", "/foo \#{bar}/"
  assert_format "%r(foo \#{ bar })", "%r(foo \#{bar})"
  assert_format "foo(/ /)"
  assert_format "foo(1, / /)"
  assert_format "/ /"
  assert_format "begin\n  / /\nend"
  assert_format "a = / /"
  assert_format "1 == / /"
  assert_format "if / /\nend"
  assert_format "while / /\nend"
  assert_format "[/ /, / /]"
  assert_format "{/ / => / /, / / => / /}"
  assert_format "case / /\nwhen / /, /x/\n  / /\nend"
  assert_format "case / /\nwhen /x/, / /\n  / /\nend"
  assert_format "/\#{1}/imx"

  assert_format "`foo`"
  assert_format "`foo \#{ bar }`", "`foo \#{bar}`"
  assert_format "%x(foo \#{ bar })", "%x(foo \#{bar})"

  assert_format "module   Moo \n\n 1  \n\nend", "module Moo\n  1\nend"
  assert_format "class   Foo \n\n 1  \n\nend", "class Foo\n  1\nend"
  assert_format "struct   Foo \n\n 1  \n\nend", "struct Foo\n  1\nend"
  assert_format "class   Foo  < \n  Bar \n\n 1  \n\nend", "class Foo < Bar\n  1\nend"
  assert_format "module Moo ( T )\nend", "module Moo(T)\nend"
  assert_format "class Foo ( T )\nend", "class Foo(T)\nend"
  assert_format "class Foo ( *T, U )\nend", "class Foo(*T, U)\nend"
  assert_format "abstract  class Foo\nend", "abstract class Foo\nend"
  assert_format "class Foo;end", "class Foo; end"
  assert_format "class Foo; 1; end", "class Foo\n  1\nend"
  assert_format "module Foo;end", "module Foo; end"
  assert_format "module Foo; 1; end", "module Foo\n  1\nend"
  assert_format "module Foo ( U, *T ); 1; end", "module Foo(U, *T)\n  1\nend"
  assert_format "enum Foo;end", "enum Foo; end"
  assert_format "enum Foo; A = 1; end", "enum Foo\n  A = 1\nend"

  assert_format "@a", "@a"
  assert_format "@@a", "@@a"
  assert_format "$~", "$~"
  assert_format "$~.bar", "$~.bar"
  assert_format "$~ = 1", "$~ = 1"
  assert_format "$?", "$?"
  assert_format "$?.bar", "$?.bar"
  assert_format "$? = 1", "$? = 1"
  assert_format "$1", "$1"
  assert_format "$1.bar", "$1.bar"
  assert_format "$0", "$0"
  assert_format "$0.bar", "$0.bar"
  assert_format "$1?"

  assert_format "foo . is_a? ( Bar )", "foo.is_a?(Bar)"
  assert_format "foo . responds_to?( :bar )", "foo.responds_to?(:bar)"
  assert_format "foo . is_a? Bar", "foo.is_a? Bar"
  assert_format "foo . responds_to? :bar", "foo.responds_to? :bar"
  assert_format "foo.responds_to? :bar\n1"

  assert_format "include  Foo", "include Foo"
  assert_format "extend  Foo", "extend Foo"

  assert_format "x  :   Int32", "x : Int32"
  assert_format "x  :   Int32*", "x : Int32*"
  assert_format "x  :   Int32**", "x : Int32**"
  assert_format "x  :   A  |  B", "x : A | B"
  assert_format "x  :   A?", "x : A?"
  assert_format "x  :   Int32[ 8 ]", "x : Int32[8]"
  assert_format "x  :   (A | B)", "x : (A | B)"
  assert_format "x  :   (A -> B)", "x : (A -> B)"
  assert_format "x  :   (A -> )", "x : (A ->)"
  assert_format "x  :   (A -> B)?", "x : (A -> B)?"
  assert_format "x  :   {A, B}", "x : {A, B}"
  assert_format "x : { {A, B}, {C, D} }"
  assert_format "x : {A, B, }", "x : {A, B}"
  assert_format "x: Int32", "x : Int32"
  assert_format "class Foo\n@x  : Int32\nend", "class Foo\n  @x : Int32\nend"
  assert_format "class Foo\n@x  :  Int32\nend", "class Foo\n  @x : Int32\nend"
  assert_format "class Foo\nx = 1\nend", "class Foo\n  x = 1\nend"
  assert_format "x  =   uninitialized   Int32", "x = uninitialized Int32"
  assert_format "x  :   Int32  =   1", "x : Int32 = 1"
  assert_format "x : (Foo.class)?"

  assert_format "def foo\n@x  :  Int32\nend", "def foo\n  @x : Int32\nend"
  assert_format "def foo\n@x   =  uninitialized   Int32\nend", "def foo\n  @x = uninitialized Int32\nend"

  assert_format "x = 1\nx    +=   1", "x = 1\nx += 1"
  assert_format "x[ y ] += 1", "x[y] += 1"
  assert_format "@x   ||=   1", "@x ||= 1"
  assert_format "@x   &&=   1", "@x &&= 1"
  assert_format "@x[ 1 ]   ||=   2", "@x[1] ||= 2"
  assert_format "@x[ 1 ]   &&=   2", "@x[1] &&= 2"
  assert_format "@x[ 1 ]   +=   2", "@x[1] += 2"
  assert_format "foo.bar   +=   2", "foo.bar += 2"
  assert_format "a[b] ||= c"

  assert_format "case  1 \n when 2 \n 3 \n end", "case 1\nwhen 2\n  3\nend"
  assert_format "case  1 \n when 2 \n 3 \n else \n 4 \n end", "case 1\nwhen 2\n  3\nelse\n  4\nend"
  assert_format "case  1 \n when 2 , 3 \n 4 \n end", "case 1\nwhen 2, 3\n  4\nend"
  assert_format "case  1 \n when 2 ,\n 3 \n 4 \n end", "case 1\nwhen 2,\n     3\n  4\nend"
  assert_format "case  1 \n when 2 ; 3 \n end", "case 1\nwhen 2; 3\nend"
  assert_format "case  1 \n when 2 ;\n 3 \n end", "case 1\nwhen 2\n  3\nend"
  assert_format "case  1 \n when 2 ; 3 \n when 4 ; 5\nend", "case 1\nwhen 2; 3\nwhen 4; 5\nend"
  assert_format "case  1 \n when 2 then 3 \n end", "case 1\nwhen 2 then 3\nend"
  assert_format "case  1 \n when 2 then \n 3 \n end", "case 1\nwhen 2\n  3\nend"
  assert_format "case  1 \n when 2 \n 3 \n when 4 \n 5 \n end", "case 1\nwhen 2\n  3\nwhen 4\n  5\nend"
  assert_format "if 1\ncase 1\nwhen 2\n3\nend\nend", "if 1\n  case 1\n  when 2\n    3\n  end\nend"
  assert_format "case  1 \n when  .foo? \n 3 \n end", "case 1\nwhen .foo?\n  3\nend"
  assert_format "case 1\nwhen 1 then\n2\nwhen 3\n4\nend", "case 1\nwhen 1\n  2\nwhen 3\n  4\nend"
  assert_format "case  1 \n when 2 \n 3 \n else 4 \n end", "case 1\nwhen 2\n  3\nelse 4\nend"
  assert_format "case 1\nwhen 1, # 1\n     2, # 2\n     3  # 3\n  1\nend"
  assert_format "a = case 1\n    when 1, # 1\n         2, # 2\n         3  # 3\n      1\n    end"
  assert_format "a = 1\ncase\nwhen 2\nelse\n  a /= 3\nend"
  assert_format "case 1\nend"
  assert_format "case 1\nelse\n  2\nend"
  assert_format "case\nend"
  assert_format "case 1\nend"
  assert_format "case\nend"
  assert_format "case\nelse\n  1\nend"

  assert_format "case  1 \n in Int32 \n 3 \n end", "case 1\nin Int32\n  3\nend"

  assert_format <<-CRYSTAL
    case 0
    when 0 then 1; 2
    # Comments
    end
    CRYSTAL

  assert_format "select   \n when  foo \n 2 \n end", "select\nwhen foo\n  2\nend"
  assert_format "select   \n when  foo \n 2 \n when bar \n 3 \n end", "select\nwhen foo\n  2\nwhen bar\n  3\nend"
  assert_format "select   \n when  foo  then  2 \n end", "select\nwhen foo then 2\nend"
  assert_format "select   \n when  foo  ;  2 \n end", "select\nwhen foo; 2\nend"
  assert_format "select   \n when  foo \n 2 \n else \n 3 \n end", "select\nwhen foo\n  2\nelse\n  3\nend"
  assert_format "def foo\nselect   \n when  foo \n 2 \n else \n 3 \nend\nend", "def foo\n  select\n  when foo\n    2\n  else\n    3\n  end\nend"
  assert_format "select\nwhen foo\n  # foo\n  # bar\nelse\n  # foo\n  # bar\nend"
  assert_format "select\nwhen foo # foo\n  # bar\nelse # foo\n  # bar\nend"
  assert_format "begin\n  select\n  when foo\n    # foo\n    # bar\n  else\n    # foo\n    # bar\n  end\nend"

  assert_format "foo.@bar"

  assert_format "@[Foo]"
  assert_format "@[Foo()]", "@[Foo]"
  assert_format "@[Foo( 1, 2 )]", "@[Foo(1, 2)]"
  assert_format "@[Foo( 1, 2, foo: 3 )]", "@[Foo(1, 2, foo: 3)]"
  assert_format "@[Foo]\ndef foo\nend"
  assert_format "@[Foo(\n  1,\n)]"
  assert_format "@[Foo::Bar]"
  assert_format "@[::Foo::Bar]"

  assert_format "1.as   Int32", "1.as Int32"
  assert_format "foo.bar. as   Int32", "foo.bar.as Int32"
  assert_format "1\n.as(Int32)", "1\n  .as(Int32)"

  assert_format "1.as?   Int32", "1.as? Int32"
  assert_format "foo.bar. as?   Int32", "foo.bar.as? Int32"
  assert_format "1\n.as?(Int32)", "1\n  .as?(Int32)"

  assert_format "1 .. 2", "1..2"
  assert_format "1 ... 2", "1...2"
  assert_format "(1 .. )", "(1..)"
  assert_format " .. 2", "..2"

  assert_format "1..\n2"
  assert_format "1\n.."
  assert_format "1\n..2"
  assert_format "...\n2"
  assert_format "1\n..\n2"

  assert_format "typeof( 1, 2, 3 )", "typeof(1, 2, 3)"
  assert_format "sizeof( Int32 )", "sizeof(Int32)"
  assert_format "instance_sizeof( Int32 )", "instance_sizeof(Int32)"
  assert_format "alignof( Int32 )", "alignof(Int32)"
  assert_format "instance_alignof( Int32 )", "instance_alignof(Int32)"
  assert_format "offsetof( String, @length )", "offsetof(String, @length)"
  assert_format "pointerof( @a )", "pointerof(@a)"

  assert_format "_ = 1"
  assert_format "あ.い = 1"

  assert_format "a , b  = 1  ,  2", "a, b = 1, 2"
  assert_format "a[1] , b[2] = 1  ,  2", "a[1], b[2] = 1, 2"
  assert_format " * a = 1 ", "*a = 1"
  assert_format " _ , *_ ,\na.foo  ,a.bar  =  1  ,  2,3", "_, *_, a.foo, a.bar = 1, 2, 3"
  assert_format "あ.い, う.え.お = 1, 2"

  assert_format "begin\n1\nensure\n2\nend", "begin\n  1\nensure\n  2\nend"
  assert_format "begin\n1\nrescue\n3\nensure\n2\nend", "begin\n  1\nrescue\n  3\nensure\n  2\nend"
  assert_format "begin\n1\nrescue   ex\n3\nend", "begin\n  1\nrescue ex\n  3\nend"
  assert_format "begin\n1\nrescue   ex   :   Int32 \n3\nend", "begin\n  1\nrescue ex : Int32\n  3\nend"
  assert_format "begin\n1\nrescue   ex   :   Int32  |  Float64  \n3\nend", "begin\n  1\nrescue ex : Int32 | Float64\n  3\nend"
  assert_format "begin\n1\nrescue   ex\n3\nelse\n4\nend", "begin\n  1\nrescue ex\n  3\nelse\n  4\nend"
  assert_format "begin\n1\nrescue   Int32 \n3\nend", "begin\n  1\nrescue Int32\n  3\nend"
  assert_format "if 1\nbegin\n2\nensure\n3\nend\nend", "if 1\n  begin\n    2\n  ensure\n    3\n  end\nend"
  assert_format "1 rescue 2"
  assert_format "1 ensure 2"
  assert_format "begin\n  call\n  # comment\nrescue\n  call\n  # comment\nelse\n  call\n  # comment\nensure\n  call\n  # comment\nend"

  assert_format "def foo\n1\nrescue\n2\nend", "def foo\n  1\nrescue\n  2\nend"
  assert_format "def foo\n1\nensure\n2\nend", "def foo\n  1\nensure\n  2\nend"
  assert_format "class Foo\ndef foo\n1\nensure\n2\nend\nend", "class Foo\n  def foo\n    1\n  ensure\n    2\n  end\nend"
  assert_format "def run\n\nrescue\n  2\n  3\nend"

  assert_format "def foo(@x)\n\nrescue\nend"

  assert_format "macro foo\nend"
  assert_format "macro foo=(x)\nend"
  assert_format "macro []=(x, y)\nend"
  assert_format "macro foo()\nend", "macro foo\nend"
  assert_format "macro foo( x , y )\nend", "macro foo(x, y)\nend"
  assert_format "macro foo( x  =   1, y  =  2,  &block)\nend", "macro foo(x = 1, y = 2, &block)\nend"
  assert_format "macro foo\n  1 + 2\nend"
  assert_format "macro foo\n  if 1\n 1 + 2\n end\nend", "macro foo\n  if 1\n    1 + 2\n  end\nend"
  assert_format "macro foo\n  {{1 + 2}}\nend", "macro foo\n  {{1 + 2}}\nend"
  assert_format "macro foo\n  {{ 1 + 2 }}\nend", "macro foo\n  {{ 1 + 2 }}\nend"
  assert_format "macro foo\n  {% 1 + 2 %}\nend", "macro foo\n  {% 1 + 2 %}\nend"
  assert_format "macro foo\n  {{ 1 + 2 }}\\\nend", "macro foo\n  {{ 1 + 2 }}\\\nend"
  assert_format "macro foo\n  {{ 1 + 2 }}\\\n 1\n end", "macro foo\n  {{ 1 + 2 }}\\\n 1\n end"
  assert_format "macro foo\n  {%1 + 2%}\\\nend", "macro foo\n  {% 1 + 2 %}\\\nend"
  assert_format "macro foo\n  {% if 1 %} 2 {% end %}\nend"
  assert_format "macro foo\n  {% unless 1 %} 2 {% end %}\nend"
  assert_format "macro foo\n  {% if 1 %} 2 {% else %} 3 {% end %}\nend"
  assert_format "macro foo\n  {% if 1 %}\\ 2 {% else %}\\ 3 {% end %}\\\nend"
  assert_format "macro foo\n  {% for x in y %} 2 {% end %}\nend"
  assert_format "macro foo\n  {% for x in y %}\\ 2 {% end %}\\\nend"
  assert_format "macro foo\n  %foo\nend"
  assert_format "macro foo\n  %foo{x.id+2}\nend", "macro foo\n  %foo{x.id + 2}\nend"
  assert_format "macro foo\n  %foo{x,y}\nend", "macro foo\n  %foo{x, y}\nend"
  assert_format "def foo : Int32\n  1\nend"
  assert_format "class Foo\n  macro foo\n    1\n  end\nend"
  assert_format "   {{ 1 + 2 }}", "{{ 1 + 2 }}"
  assert_format "  {% for x in y %} 2 {% end %}", "{% for x in y %} 2 {% end %}"
  assert_format "  {% if 1 %} 2 {% end %}", "{% if 1 %} 2 {% end %}"
  assert_format "  {% if 1 %} {% if 2 %} 2 {% end %} {% end %}", "{% if 1 %} {% if 2 %} 2 {% end %} {% end %}"
  assert_format "if 1\n  {% if 2 %} {% end %}\nend"
  assert_format "if 1\n  {% for x in y %} {% end %}\nend"
  assert_format "if 1\n  {{1 + 2}}\nend"
  assert_format "def foo : self | Nil\n  nil\nend"
  assert_format "macro foo(x)\n  {% if 1 %} 2 {% end %}\nend"
  assert_format "macro foo()\n  {% if 1 %} 2 {% end %}\nend", "macro foo\n  {% if 1 %} 2 {% end %}\nend"
  assert_format "macro flags\n  {% if 1 %}\\\n  {% end %}\\\nend"
  assert_format "macro flags\n  {% if 1 %}\\\n 1 {% else %}\\\n {% end %}\\\nend"
  assert_format "macro flags\n  {% if 1 %}{{1}}a{{2}}{% end %}\\\nend"
  assert_format "  {% begin %} 2 {% end %}", "{% begin %} 2 {% end %}"
  assert_format "macro foo\n  \\{\nend"
  assert_format "macro foo\n  {% if 1 %} 2 {% elsif 3 %} 4 {% else %} 5 {% end %}\nend"
  assert_format "macro [](x)\nend"
  assert_format "macro foo\n  {% if true %}if true{% end %}\n  {% if true %}end{% end %}\nend"
  assert_format "macro foo\n    1  +  2 \n    end", "macro foo\n  1 + 2\nend"
  assert_format "class Foo\n macro foo\n    1  +  2 \n    end\n end", "class Foo\n  macro foo\n    1 + 2\n  end\nend"
  assert_format "macro foo\n    def   bar  \n  end \n    end", "macro foo\n  def bar\n  end\nend"

  assert_format "def foo\na = bar do\n1\nend\nend", "def foo\n  a = bar do\n    1\n  end\nend"
  assert_format "def foo\nend\ndef bar\nend", "def foo\nend\n\ndef bar\nend"
  assert_format "private def foo\nend\nprivate def bar\nend", "private def foo\nend\n\nprivate def bar\nend"
  assert_format "a = 1\ndef bar\nend", "a = 1\n\ndef bar\nend"
  assert_format "def foo\nend\n\n\n\ndef bar\nend", "def foo\nend\n\ndef bar\nend"
  assert_format "def foo\nend;def bar\nend", "def foo\nend\n\ndef bar\nend"
  assert_format "class Foo\nend\nclass Bar\nend", "class Foo\nend\n\nclass Bar\nend"

  assert_format "alias  Foo  =   Bar", "alias Foo = Bar"
  assert_format "alias  Foo::Bar  =   Baz", "alias Foo::Bar = Baz"
  assert_format "alias A = (B)"
  assert_format "alias A = (B) -> C"
  assert_format "alias Foo=Bar", "alias Foo = Bar"
  assert_format "alias Foo= Bar", "alias Foo = Bar"
  assert_format "alias Foo =Bar", "alias Foo = Bar"
  assert_format "alias Foo::Bar=Baz", "alias Foo::Bar = Baz"
  assert_format "alias Foo::Bar= Baz", "alias Foo::Bar = Baz"
  assert_format "alias Foo::Bar =Baz", "alias Foo::Bar = Baz"
  assert_format <<-CRYSTAL, <<-CRYSTAL
    alias Foo=
    Bar
    CRYSTAL
    alias Foo = Bar
    CRYSTAL
  assert_format "lib Foo\nend"
  assert_format "lib Foo\ntype  Foo  =   Bar\nend", "lib Foo\n  type Foo = Bar\nend"
  assert_format "lib Foo\nfun foo\nend", "lib Foo\n  fun foo\nend"
  assert_format "lib Foo\n  fun Bar\nend"
  assert_format "lib Foo\n  fun bar = Bar\nend"
  assert_format "lib Foo\n  fun Foo = Bar\nend"
  assert_format "lib Foo\nfun foo  :  Int32\nend", "lib Foo\n  fun foo : Int32\nend"
  assert_format "lib Foo\nfun foo()  :  Int32\nend", "lib Foo\n  fun foo : Int32\nend"
  assert_format "lib Foo\nfun foo ()  :  Int32\nend", "lib Foo\n  fun foo : Int32\nend"
  assert_format "lib Foo\nfun foo(x   :   Int32, y   :   Float64)  :  Int32\nend", "lib Foo\n  fun foo(x : Int32, y : Float64) : Int32\nend"
  assert_format "lib Foo\nfun foo(x : Int32,\ny : Float64) : Int32\nend", "lib Foo\n  fun foo(x : Int32,\n          y : Float64) : Int32\nend"
  assert_format "lib Foo\nfun foo( ... )  :  Int32\nend", "lib Foo\n  fun foo(...) : Int32\nend"
  assert_format "lib Foo\nfun foo(x : Int32, ... )  :  Int32\nend", "lib Foo\n  fun foo(x : Int32, ...) : Int32\nend"
  assert_format "lib Foo\n  fun foo(Int32) : Int32\nend"
  assert_format "fun foo(x : Int32) : Int32\n  1\nend"
  assert_format "fun foo(\n  x : Int32,\n  ...\n) : Int32\n  1\nend"
  assert_format <<-CRYSTAL
    lib Foo
      fun foo = bar(Int32) : Int32
    end
    CRYSTAL
  assert_format <<-CRYSTAL
    lib Foo
      fun foo =
        bar : Void
    end
    CRYSTAL
  assert_format <<-CRYSTAL, <<-CRYSTAL
    lib Foo
      fun foo =


        bar : Void
    end
    CRYSTAL
    lib Foo
      fun foo =
        bar : Void
    end
    CRYSTAL
  assert_format <<-CRYSTAL
    lib Foo
      fun foo =
        bar(Int32) : Int32
    end
    CRYSTAL
  assert_format <<-CRYSTAL, <<-CRYSTAL
    lib Foo
      fun foo =


        bar(Int32) : Int32
    end
    CRYSTAL
    lib Foo
      fun foo =
        bar(Int32) : Int32
    end
    CRYSTAL
  assert_format <<-CRYSTAL, <<-CRYSTAL
    lib Foo
      fun foo =
        bar(Int32,
        Int32) : Int32
    end
    CRYSTAL
    lib Foo
      fun foo =
        bar(Int32,
            Int32) : Int32
    end
    CRYSTAL
  assert_format "lib Foo\n  fun foo = bar(Int32) : Int32\nend"
  assert_format <<-CRYSTAL
    lib Foo
      fun foo = "bar"(Int32) : Int32
    end
    CRYSTAL
  assert_format <<-CRYSTAL
    lib Foo
      fun foo =
        "bar"(Int32) : Int32
    end
    CRYSTAL
  assert_format <<-CRYSTAL
    lib Foo
      fun foo =
        "bar"(Int32) : Int32
      # comment
    end
    CRYSTAL
  assert_format "lib Foo\n  $foo  :  Int32 \nend", "lib Foo\n  $foo : Int32\nend"
  assert_format "lib Foo\n  $foo = hello  :  Int32 \nend", "lib Foo\n  $foo = hello : Int32\nend"
  assert_format "lib Foo\nalias  Foo  =  Bar -> \n$a : Int32\nend", "lib Foo\n  alias Foo = Bar ->\n  $a : Int32\nend"
  assert_format "lib Foo\nstruct Foo\nend\nend", "lib Foo\n  struct Foo\n  end\nend"
  assert_format "lib Foo\nstruct Foo\nx  :  Int32\nend\nend", "lib Foo\n  struct Foo\n    x : Int32\n  end\nend"
  assert_format "lib Foo\nstruct Foo\nx  :  Int32\ny : Float64\nend\nend", "lib Foo\n  struct Foo\n    x : Int32\n    y : Float64\n  end\nend"
  assert_format "lib Foo\nstruct Foo\nx  ,  y  :  Int32\nend\nend", "lib Foo\n  struct Foo\n    x, y : Int32\n  end\nend"
  assert_format "lib Foo\nstruct Foo\nx  ,  y  , z :  Int32\nend\nend", "lib Foo\n  struct Foo\n    x, y, z : Int32\n  end\nend"
  assert_format "lib Foo\nunion Foo\nend\nend", "lib Foo\n  union Foo\n  end\nend"

  assert_format "SomeLib.UppercasedFunCall"
  assert_format "SomeLib.UppercasedFunCall 1, 2"

  assert_format "enum Foo\nend"
  assert_format "enum Foo\nA  \nend", "enum Foo\n  A\nend"
  assert_format "enum Foo\nA = 1\nend", "enum Foo\n  A = 1\nend"
  assert_format "enum Foo : Int32\nA = 1\nend", "enum Foo : Int32\n  A = 1\nend"
  assert_format "enum Foo : Int32\nA = 1\ndef foo\n1\nend\nend", "enum Foo : Int32\n  A = 1\n\n  def foo\n    1\n  end\nend"
  assert_format "lib Bar\n  enum Foo\n  end\nend"
  assert_format "lib Bar\n  enum Foo\n    A\n  end\nend"
  assert_format "lib Bar\n  enum Foo\n    A = 1\n  end\nend"

  assert_format "lib Foo::Bar\nend"

  %w(foo foo= foo? foo!).each do |method|
    assert_format "->#{method}"
    assert_format "foo = 1\n->foo.#{method}"
    assert_format "->Foo.#{method}"
    assert_format "->@foo.#{method}"
    assert_format "->@@foo.#{method}"
    assert_format "-> :: #{method}", "->::#{method}"
    assert_format "-> :: Foo . #{method}", "->::Foo.#{method}"
  end

  assert_format "foo = 1\n->foo.bar(Int32)"
  assert_format "foo = 1\n->foo.bar(Int32*)"
  assert_format "foo = 1\n->foo.bar=(Int32)"
  assert_format "foo = 1\n->foo.[](Int32)"
  assert_format "foo = 1\n->foo.[]=(Int32)"

  assert_format "->{ x }", "-> { x }"
  assert_format "->{\nx\n}", "-> {\n  x\n}"
  assert_format "->do\nx\nend", "-> do\n  x\nend"
  assert_format "->( ){ x }", "-> { x }"
  assert_format "->() do x end", "-> do x end"
  assert_format "->( x , y )   { x }", "->(x, y) { x }"
  assert_format "->( x : Int32 , y )   { x }", "->(x : Int32, y) { x }"
  assert_format "->{ x }", "-> { x }"

  # #13232
  assert_format "->{}", "-> { }"
  assert_format "->(){}", "-> { }"
  assert_format "->{1}", "-> { 1 }"
  assert_format "->(x : Int32) {}", "->(x : Int32) { }"
  assert_format "-> : Int32 {}", "-> : Int32 { }"
  assert_format "->do\nend", "-> do\nend"
  assert_format "-> : Int32 {}", "-> : Int32 { }"

  # Allows whitespace around proc literal, but doesn't enforce them
  assert_format "-> { }"
  assert_format "-> { 1 }"
  assert_format "->(x : Int32) { }"
  assert_format "-> : Int32 { }"
  assert_format "-> do\nend"

  assert_format "-> : Int32 { }"
  assert_format "-> : Int32 | String { 1 }"
  assert_format "-> : Array(Int32) {}", "-> : Array(Int32) { }"
  assert_format "-> : Int32? {}", "-> : Int32? { }"
  assert_format "-> : Int32* {}", "-> : Int32* { }"
  assert_format "-> : Int32[1] {}", "-> : Int32[1] { }"
  assert_format "-> : {Int32, String} {}", "-> : {Int32, String} { }"
  assert_format "-> : {Int32} { String }"
  assert_format "-> : {x: Int32, y: String} {}", "-> : {x: Int32, y: String} { }"
  assert_format "->\n:\nInt32\n{\n}", "-> : Int32 {\n}"
  assert_format "->( x )\n:\nInt32 { }", "->(x) : Int32 { }"
  assert_format "->: Int32 do\nx\nend", "-> : Int32 do\n  x\nend"

  {:+, :-, :*, :/, :^, :>>, :<<, :|, :&, :&+, :&-, :&*, :&**}.each do |sym|
    assert_format ":#{sym}"
  end

  assert_format ":\"foo bar\""

  assert_format %("foo" \\\n "bar"), %("foo" \\\n"bar")
  assert_format %("foo" \\\n "bar" \\\n "baz"), %("foo" \\\n"bar" \\\n"baz")
  assert_format %("foo \#{bar}" \\\n "baz"), %("foo \#{bar}" \\\n"baz")

  assert_format %(asm("nop"))
  assert_format %(asm(\n"nop"\n)), %(asm(\n  "nop"\n))
  assert_format %(asm("nop" : : )), %(asm("nop"))
  assert_format %(asm("nop" :: )), %(asm("nop"))
  assert_format %(asm("nop" :: "r"(0))), %(asm("nop" :: "r"(0)))
  assert_format %(asm("nop" : "a"(0) )), %(asm("nop" : "a"(0)))
  assert_format %(asm("nop" : "a"(0), "b"(1) )), %(asm("nop" : "a"(0), "b"(1)))
  assert_format %(asm("nop" : "a"(0) : "b"(1) )), %(asm("nop" : "a"(0) : "b"(1)))
  assert_format %(asm("nop" : "a"(0) : "b"(1), "c"(2) )), %(asm("nop" : "a"(0) : "b"(1), "c"(2)))
  assert_format %(asm("nop" : "a"(0)\n: "b"(1), "c"(2) )), %(asm("nop" : "a"(0)\n          : "b"(1), "c"(2)))
  assert_format %(asm("nop" : "a"(0), "b"(1)\n: "c"(2), "d"(3) )), %(asm("nop" : "a"(0), "b"(1)\n          : "c"(2), "d"(3)))
  assert_format %(asm("nop" : "a"(0),\n"b"(1)\n: "c"(2), "d"(3) )), %(asm("nop" : "a"(0),\n            "b"(1)\n          : "c"(2), "d"(3)))
  assert_format %(asm("nop" : "a"(0)\n: "b"(1),\n"c"(2) )), %(asm("nop" : "a"(0)\n          : "b"(1),\n            "c"(2)))
  assert_format %(asm(\n"nop" : "a"(0), "b"(1) )), %(asm(\n  "nop" : "a"(0), "b"(1)\n))
  assert_format %(asm("nop"\n: "a"(0) )), %(asm("nop"\n        : "a"(0)))
  assert_format %(asm("nop" ::: "eax" )), %(asm("nop" ::: "eax"))
  assert_format %(asm("nop" ::: "eax" ,  "ebx" )), %(asm("nop" ::: "eax", "ebx"))
  assert_format %(asm("nop" :::: "volatile" )), %(asm("nop" :::: "volatile"))
  assert_format %(asm("nop" :::: "volatile"  , "alignstack"  ,  "intel"   )), %(asm("nop" :::: "volatile", "alignstack", "intel"))
  assert_format %(asm("nop" ::: "eax" ,  "ebx" :   "volatile"  ,  "alignstack" )), %(asm("nop" ::: "eax", "ebx" : "volatile", "alignstack"))
  assert_format %(asm("a" : "b"(c) : "d"(e) :: "volatile"))
  assert_format %(asm("a" : "b"(1), "c"(2) : "d"(3) : : "volatile")), %(asm("a" : "b"(1), "c"(2) : "d"(3) :: "volatile"))

  assert_format %(asm("a" : "b"(c)\n)), %(asm("a" : "b"(c)))
  assert_format %(asm("a" :: "d"(e)\n)), %(asm("a" :: "d"(e)))
  assert_format %(asm("a" ::: "f"\n)), %(asm("a" ::: "f"))
  assert_format %(asm("a" :::: "volatile"\n)), %(asm("a" :::: "volatile"))
  assert_format %(asm("a" : : : : "volatile")), %(asm("a" :::: "volatile"))
  assert_format %(asm("a" :: : : "volatile")), %(asm("a" :::: "volatile"))
  assert_format %(asm("a" : :: : "volatile")), %(asm("a" :::: "volatile"))
  assert_format %(asm("a" : : :: "volatile")), %(asm("a" :::: "volatile"))
  assert_format %(asm("a" : "b"(c) : "d"(e)\n        : "f"))
  assert_format %(asm("a" : "b"(c) : "d"(e)\n        : "f",\n          "g"))
  assert_format %(asm("a" ::: "a"\n        : "volatile",\n          "intel"))

  assert_format <<-CRYSTAL, <<-CRYSTAL
    asm(
    # foo
    "nop"
    # bar
    )
    CRYSTAL
    asm(
      # foo
      "nop"
      # bar
    )
    CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
    asm(
      # the assembly template string, following the
      # syntax for LLVM's integrated assembler
      "nop" :               # output operands
    "=r"(foo), "=r"(bar) : # input operands
    "r"(1), "r"(baz) :     # names of clobbered registers
    "eax", "memory" :      # optional flags, corresponding to the LLVM IR
      # sideeffect / alignstack / inteldialect / unwind attributes
    "volatile", "alignstack", "intel", "unwind"
    )
    CRYSTAL
    asm(
      # the assembly template string, following the
      # syntax for LLVM's integrated assembler
      "nop" :                # output operands
      "=r"(foo), "=r"(bar) : # input operands
      "r"(1), "r"(baz) :     # names of clobbered registers
      "eax", "memory" :      # optional flags, corresponding to the LLVM IR
      # sideeffect / alignstack / inteldialect / unwind attributes
      "volatile", "alignstack", "intel", "unwind"
    )
    CRYSTAL

  assert_format "1 # foo\n1234 # bar", "1    # foo\n1234 # bar"
  assert_format "1234 # foo\n1 # bar", "1234 # foo\n1    # bar"
  assert_format "1#foo", "1 # foo"
  assert_format "1 # foo\n1234 # bar\n\n10 # bar", "1    # foo\n1234 # bar\n\n10 # bar"
  assert_format "# foo\na = 1 # bar"
  assert_format "#### ###"
  assert_format "#######"
  assert_format "x\n# foo\n\n# bar"

  assert_format "A = 1\nFOO = 2\n\nEX = 3", "A   = 1\nFOO = 2\n\nEX = 3"
  assert_format "FOO = 2\nA = 1", "FOO = 2\nA   = 1"
  assert_format "FOO = 2 + 3\nA = 1 - 10", "FOO = 2 + 3\nA   = 1 - 10"
  assert_format "private FOO = 2\nprivate A = 1", "private FOO = 2\nprivate A   = 1"
  assert_format "enum Baz\nA = 1\nFOO = 2\n\nEX = 3\nend", "enum Baz\n  A   = 1\n  FOO = 2\n\n  EX = 3\nend"
  assert_format "enum Baz\nA = 1\nFOO\n\nEX = 3\nend", "enum Baz\n  A   = 1\n  FOO\n\n  EX = 3\nend"

  assert_format "1   # foo", "1 # foo"
  assert_format "1  # foo\n2  # bar", "1 # foo\n2 # bar"
  assert_format "1  #foo  \n2  #bar", "1 # foo\n2 # bar"
  assert_format "if 1\n2  # foo\nend", "if 1\n  2 # foo\nend"
  assert_format "if 1\nelse\n2  # foo\nend", "if 1\nelse\n  2 # foo\nend"
  assert_format "if # some comment\n 2 # another\n 3 # final \n end # end ", "if  # some comment\n2   # another\n  3 # final\nend # end"
  assert_format "while 1\n2  # foo\nend", "while 1\n  2 # foo\nend"
  assert_format "def foo\n2  # foo\nend", "def foo\n  2 # foo\nend"
  assert_format "if 1\n# nothing\nend", "if 1\n  # nothing\nend"
  assert_format "if 1\nelse\n# nothing\nend", "if 1\nelse\n  # nothing\nend"
  assert_format "if 1 # foo\n2\nend", "if 1 # foo\n  2\nend"
  assert_format "if 1  # foo\nend", "if 1 # foo\nend"
  assert_format "while 1  # foo\nend", "while 1 # foo\nend"
  assert_format "while 1\n# nothing\nend", "while 1\n  # nothing\nend"
  assert_format "class Foo  # foo\nend", "class Foo # foo\nend"
  assert_format "class Foo\n# nothing\nend", "class Foo\n  # nothing\nend"
  assert_format "module Foo  # foo\nend", "module Foo # foo\nend"
  assert_format "module Foo\n# nothing\nend", "module Foo\n  # nothing\nend"
  assert_format "case 1 # foo\nwhen 2\nend", "case 1 # foo\nwhen 2\nend"
  assert_format "def foo\n# hello\n1\nend", "def foo\n  # hello\n  1\nend"
  assert_format "struct Foo(T)\n# bar\n1\nend", "struct Foo(T)\n  # bar\n  1\nend"
  assert_format "struct Foo\n  # bar\n  # baz\n1\nend", "struct Foo\n  # bar\n  # baz\n  1\nend"
  assert_format "(size - 1).downto(0) do |i|\n  yield @buffer[i]\nend"
  assert_format "(a).b { }\nc"
  assert_format "begin\n  a\nend.b { }\nc"
  assert_format "if a\n  b &c\nend"
  assert_format "foo (1).bar"
  assert_format "foo a: 1\nb"
  assert_format "if 1\n2 && 3\nend", "if 1\n  2 && 3\nend"
  assert_format "if 1\n  node.is_a?(T)\nend"
  assert_format "case 1\nwhen 2\n#comment\nend", "case 1\nwhen 2\n  # comment\nend"
  assert_format "case 1\nwhen 2\n\n#comment\nend", "case 1\nwhen 2\n  # comment\nend"
  assert_format "1 if 2\n# foo", "1 if 2\n# foo"
  assert_format "1 if 2\n# foo\n3"
  assert_format "1\n2\n# foo"
  assert_format "1\n2  \n  # foo", "1\n2\n# foo"
  assert_format "if 1\n2\n3\n# foo\nend", "if 1\n  2\n  3\n  # foo\nend"
  assert_format "def foo\n1\n2\n# foo\nend", "def foo\n  1\n  2\n  # foo\nend"
  assert_format "if 1\nif 2\n3 # foo\nend\nend", "if 1\n  if 2\n    3 # foo\n  end\nend"
  assert_format "class Foo\n1\n\n# foo\nend", "class Foo\n  1\n\n  # foo\nend"
  assert_format "module Foo\n1\n\n# foo\nend", "module Foo\n  1\n\n  # foo\nend"
  assert_format "if 1\n1\n\n# foo\nend", "if 1\n  1\n\n  # foo\nend"
  assert_format "while true\n1\n\n# foo\nend", "while true\n  1\n\n  # foo\nend"
  assert_format "def foo\nend\n\ndef bar\nend\n\n# foo"
  assert_format "1 && (\n  2 || 3\n)"
  assert_format "class Foo\n  def foo\n    # nothing\n  end\nend"
  assert_format <<-CRYSTAL, <<-CRYSTAL
    class Foo
      def bar
      end;

      def baz
      end
    end
    CRYSTAL
    class Foo
      def bar
      end

      def baz
      end
    end
    CRYSTAL
  assert_format <<-CRYSTAL, <<-CRYSTAL
    class Foo
      def bar
      end # foo
      def baz
      end
    end
    CRYSTAL
    class Foo
      def bar
      end # foo

      def baz
      end
    end
    CRYSTAL
  assert_format <<-CRYSTAL, <<-CRYSTAL
    (
      begin
        1
      end;

      2
    )
    CRYSTAL
    (
      begin
        1
      end

      2
    )
    CRYSTAL

  assert_format "while 1 # foo\n  # bar\n  2\nend", "while 1 # foo\n  # bar\n  2\nend"
  assert_format "foo(\n # foo\n1,\n\n # bar\n2,  \n)", "foo(\n  # foo\n  1,\n\n  # bar\n  2,\n)"
  assert_format "foo do;\n1; end", "foo do\n  1\nend"
  assert_format "if 1;\n2; end", "if 1\n  2\nend"
  assert_format "while 1;\n2; end", "while 1\n  2\nend"
  assert_format "if 1;\n2;\nelse;\n3;\nend", "if 1\n  2\nelse\n  3\nend"
  assert_format "if 1;\n2;\nelsif 3;\n4;\nend", "if 1\n  2\nelsif 3\n  4\nend"
  assert_format "def foo\n  1\n  2\nrescue IO\n  1\nend"
  assert_format "def execute\n  begin\n    1\n  ensure\n    2\n  end\n  3\nend"
  assert_format "foo.bar=(2)\n1"
  assert_format "inner &.color=(@color)\n1"
  assert_format "ary.size = (1).to_i"
  assert_format "b &.[c].d"
  assert_format "b &.[c]?.d"
  assert_format "a &.b[c]?"
  assert_format "+ a + d", "+a + d"
  assert_format "  ((1) + 2)", "((1) + 2)"
  assert_format "if 1\n  ((1) + 2)\nend"

  assert_format "def   foo(x   :  self ?) \n  end", "def foo(x : self?)\nend"
  assert_format "def foo(x : (self)?)\nend"

  assert_format "  macro foo\n  end\n\n  :+", "macro foo\nend\n\n:+"
  assert_format "[\n1, # a\n2, # b\n 3 # c\n]", "[\n  1, # a\n  2, # b\n  3, # c\n]"
  assert_format "[\n  a() # b\n]", "[\n  a(), # b\n]"
  assert_format "[\n  a(), # b\n]", "[\n  a(), # b\n]"
  assert_format "[\n  a(),\n]", "[\n  a(),\n]"
  assert_format "if 1\n[\n  a() # b\n]\nend", "if 1\n  [\n    a(), # b\n  ]\nend"
  assert_format "foo(\n# x\n1,\n\n# y\nz: 2\n)", "foo(\n  # x\n  1,\n\n  # y\n  z: 2\n)"
  assert_format "foo(\n# x\n1,\n\n# y\nz: 2,\n\n# a\nb: 3)", "foo(\n  # x\n  1,\n\n  # y\n  z: 2,\n\n  # a\n  b: 3)"
  assert_format "foo(\n 1, # hola\n2, # chau\n )", "foo(\n  1, # hola\n  2, # chau\n)"
  assert_format "foo (1)", "foo(1)"
  assert_format "foo (1), 2"
  assert_format "foo (1; 2)"
  assert_format "foo ((1) ? 2 : 3)", "foo((1) ? 2 : 3)"
  assert_format "foo((1..3))"
  assert_format "foo ()"
  assert_format "foo ( )", "foo ()"
  assert_format "def foo(\n\n#foo\nx,\n\n#bar\nz\n)\nend", "def foo(\n  # foo\n  x,\n\n  # bar\n  z,\n)\nend"
  assert_format "def foo(\nx, #foo\nz #bar\n)\nend", "def foo(\n  x, # foo\n  z, # bar\n)\nend"
  assert_format "a = 1;;; b = 2", "a = 1; b = 2"
  assert_format "a = 1\n;\nb = 2", "a = 1\nb = 2"
  assert_format "foo do\n  # bar\nend"
  assert_format "abstract def foo\nabstract def bar"
  assert_format "if 1\n  ->{ 1 }\nend", "if 1\n  -> { 1 }\nend"
  assert_format "foo.bar do\n  baz\n    .b\nend"
  assert_format "coco.lala\nfoo\n  .bar"
  assert_format "foo.bar = \n1", "foo.bar =\n  1"
  assert_format "foo.bar += \n1", "foo.bar +=\n  1"
  assert_format "->{}", "-> { }"
  assert_format "foo &.[a] = 1"
  assert_format "[\n  # foo\n  1,\n\n  # bar\n  2,\n]"
  assert_format "[c.x]\n  .foo"
  assert_format "foo([\n  1,\n  2,\n  3,\n])"
  assert_format "bar = foo([\n  1,\n  2,\n  3,\n])"
  assert_format "foo({\n  1 => 2,\n  3 => 4,\n  5 => 6,\n})"
  assert_format "bar = foo({\n        1 => 2,\n        3 => 4,\n        5 => 6,\n      })", "bar = foo({\n  1 => 2,\n  3 => 4,\n  5 => 6,\n})"
  assert_format "foo(->{\n  1 + 2\n})", "foo(-> {\n  1 + 2\n})"
  assert_format "bar = foo(->{\n  1 + 2\n})", "bar = foo(-> {\n  1 + 2\n})"
  assert_format "foo(->do\n  1 + 2\nend)", "foo(-> do\n  1 + 2\nend)"
  assert_format "bar = foo(->do\n  1 + 2\nend)", "bar = foo(-> do\n  1 + 2\nend)"
  assert_format "bar = foo(->{\n  1 + 2\n})", "bar = foo(-> {\n  1 + 2\n})"
  assert_format "case 1\nwhen 2\n  3\n  # foo\nelse\n  4\n  # bar\nend"
  assert_format "1 #=> 2", "1 # => 2"
  assert_format "1 #=>2", "1 # => 2"
  assert_format "foo(\n  [\n    1,\n    2,\n  ],\n  [\n    3,\n    4,\n  ]\n)"
  assert_format "%w(\n  one two\n  three four\n)"
  assert_format "a = %w(\n  one two\n  three four\n)"
  assert_format "foo &.bar do\n  1 + 2\nend"
  assert_format "a = foo &.bar do\n  1 + 2\nend"
  assert_format "foo(bar([\n  1,\n]))"
  assert_format "a = foo(bar([\n  1,\n]))"
  assert_format "foo(baz1 do\nend)"
  assert_format "a = foo(baz1 do\nend)"
  assert_format "foo(bar(baz3 do\nend))"
  assert_format "a = foo(bar(baz3 do\nend))"
  assert_format "foo(bar(\n  1,\n  2,\n))"
  assert_format "a = foo(bar(\n  1,\n  2,\n))"
  # assert_format "a = foo(bar([\n          1,\n          2,\n        ]),\n        3,\n       )"
  assert_format "foo(1, 2, {\n  foo: 1,\n  bar: 2,\n})"
  assert_format "a = foo(1, 2, {\n  foo: 1,\n  bar: 2,\n})"
  assert_format "foo([\n  1,\n  bar do\n  end,\n  [\n    2,\n  ],\n])"
  assert_format "foo(bar(\n  1,\n  baz(\n    2,\n    3,\n  )\n))"
  assert_format "foo(bar(\n  1,\n  baz(2,\n      3,\n     )\n))", "foo(bar(\n  1,\n  baz(2,\n    3,\n  )\n))"
  assert_format "foo({\n  1 => 2,\n  3 => {\n    4 => 5,\n  },\n})"
  assert_format "foo([\n  1, 2,\n  3, 4,\n])"
  assert_format "foo(baz(x, y) do\n  1 + 2\nend)"
  assert_format "case 1\nwhen \"foo\"     ; 3\nwhen \"lalalala\"; 4\nelse             5\nend"
  assert_format "case 1\nwhen \"foo\"      then 3\nwhen \"lalalala\" then 4\nelse                 5\nend"
  assert_format "case 1        # foo\nwhen 2 then 3 # bar\nwhen 4 then 5 # baz\nelse        6 # zzz\nend"
  assert_format "case 1\nwhen 8     then 1\nwhen 16    then 2\nwhen 256   then 3\nwhen 'a'   then 5\nwhen \"foo\" then 6\nelse            4\nend"
  assert_format "case 1\nwhen 1      then 1\nwhen 123    then 2\nwhen 1..123 then 3\nelse             4\nend"
  assert_format "macro bar\n  1\nend\n\ncase 1\nwhen  2 then 3\nwhen 45 then 6\nend"
  assert_format "{\n         1 => 2,\n        10 => 30,\n        30 => 40,\n  \"foobar\" => 50,\n  \"coco\"   => 60,\n}"
  assert_format "{1 => 2, 3 => 4}\n{5234234 => 234098234, 7 => 8}"
  assert_format "{\n    1 => 2, 3 => 4,\n  567 => 8910,\n}", "{\n  1 => 2, 3 => 4,\n  567 => 8910,\n}"
  assert_format "{\n  foo:    1,\n  b:      2,\n  barbaz: 3,\n}"
  assert_format "{\n  a:   1,\n  foo: bar,\n}"
  assert_format "%(\n1\n)\n\n{\n    1 => 2,\n  234 => 5,\n}"
  assert_format "class Actor\n  macro inherited\nend\nend\n", "class Actor\n  macro inherited\n  end\nend"
  assert_format "class Actor\n  macro inherited\n\nend\nend\n", "class Actor\n  macro inherited\n  end\nend"
  assert_format "{\n  \"foo\":    1,\n  \"babraz\": 2,\n}"
  assert_format "def foo\n  ((((((((((((((((0_u64\n    ) | ptr[0]) << 8\n    ) | ptr[1]) << 8\n    ) | ptr[2]) << 8\n    ) | ptr[3]) << 8\n    ) | ptr[4]) << 8\n    ) | ptr[5]) << 8\n    ) | ptr[6]) << 8\n    ) | ptr[7])\nend"
  assert_format "yield (1).foo"
  assert_format "module Ton\n  macro foo\n    class {{name.id}}\n    end\n  end\nend"
  assert_format "a = 1\na ||= begin\n  1\nend"
  assert_format "if 1\n  return foo(\n    1,\n    2,\n  )\nend"
  assert_format "1\nyield\n2"
  assert_format "if 1\n  [\n    1,\n  ].none?\nend"
  assert_format "# foo\ndef foo\nend\n# bar\ndef bar\nend", "# foo\ndef foo\nend\n\n# bar\ndef bar\nend"
  assert_format "<<-FOO\n1\nFOO\n\n{\n   1 => 2,\n  10 => 3,\n}"
  assert_format "p = Foo[1, 2, 3,\n        4, 5, 6,\n       ]", "p = Foo[1, 2, 3,\n  4, 5, 6,\n]"
  assert_format "p = Foo[\n  1, 2, 3,\n  4, 5, 6\n]\n", "p = Foo[\n  1, 2, 3,\n  4, 5, 6,\n]"
  assert_format "[1, 2,\n  3, 4]\n", "[1, 2,\n 3, 4]"
  assert_format "{1 => 2,\n  3 => 4, # lala\n}\n", "{1 => 2,\n 3 => 4, # lala\n}"
  assert_format "A = 10\nFOO = 123\nBARBAZ = 1234\n", "A      =   10\nFOO    =  123\nBARBAZ = 1234"
  assert_format "enum Foo\n  A      =   10\n  FOO    =  123\n  BARBAZ = 1234\nend\n", "enum Foo\n  A      =   10\n  FOO    =  123\n  BARBAZ = 1234\nend"
  assert_format "1\n# hello\n\n\n", "1\n# hello"
  assert_format "def foo\n  a = 1; # foo\n  a = 2; # bar\nend\n", "def foo\n  a = 1 # foo\n  a = 2 # bar\nend"
  assert_format "# Hello\n#\n# ```\n# puts 1+2 # bye\n# 1+2 # hello\n#\n# 1+2\n# ```\n\n# ```\n# puts 1+2\n\n# ```\n# puts 1+2\n\n# Hola\n#\n#     1+2\n#     foo do\n#     3+4\n#     end\n\n# Hey\n#\n#     1+2\n#     foo do\n#     3+4\n#     end\n#\n# ```\n# 1+2\n# ```\n#\n#     1+2\n#\n# Bye\n", "# Hello\n#\n# ```\n# puts 1 + 2 # bye\n# 1 + 2      # hello\n#\n# 1 + 2\n# ```\n\n# ```\n# puts 1+2\n\n# ```\n# puts 1+2\n\n# Hola\n#\n#     1+2\n#     foo do\n#     3+4\n#     end\n\n# Hey\n#\n#     1+2\n#     foo do\n#     3+4\n#     end\n#\n# ```\n# 1 + 2\n# ```\n#\n#     1+2\n#\n# Bye"
  assert_format "# Hello\n#\n# ```cr\n#   1\n# ```\n# Bye", "# Hello\n#\n# ```\n# 1\n# ```\n# Bye"
  assert_format "# Hello\n#\n# ```crystal\n#   1\n# ```\n# Bye", "# Hello\n#\n# ```\n# 1\n# ```\n# Bye"
  assert_format "macro foo\n  {% for value, i in values %}\\\n    {% if true %}\\\n    {% end %}\\\n    {{ 1 }}/\n  {% end %}\\\nend\n\n{\n  1 => 2,\n  1234 => 5,\n}\n", "macro foo\n  {% for value, i in values %}\\\n    {% if true %}\\\n    {% end %}\\\n    {{ 1 }}/\n  {% end %}\\\nend\n\n{\n     1 => 2,\n  1234 => 5,\n}"
  assert_format "a = \"\n\"\n1    # 1\n12 # 2\n", "a = \"\n\"\n1  # 1\n12 # 2"
  assert_format "enum Foo\n  A;   B;   C\nend\n", "enum Foo\n  A; B; C\nend"
  assert_format "# ```\n# macro foo\n#   1\n# end\n# ```\n", "# ```\n# macro foo\n#   1\n# end\n# ```"
  assert_format "class Foo\n  # ```\n  # 1\n  # ```\nend\n", "class Foo\n  # ```\n  # 1\n  # ```\nend"
  assert_format "# Here is the doc of a method, and contains an example:\n#\n# ```\n# result = foo\n#\n# puts result\n# ```\ndef foo\n  # ...\nend\n", "# Here is the doc of a method, and contains an example:\n#\n# ```\n# result = foo\n#\n# puts result\n# ```\ndef foo\n  # ...\nend"
  assert_format "foo(\n  a: 1,\n  b: 2,\n  )\n", "foo(\n  a: 1,\n  b: 2,\n)"
  assert_format "  case 1\n  when 2\n    3\n  else #:newline, :eof\n    1 if 2\n    return 3\n  end\n", "case 1\nwhen 2\n  3\nelse # :newline, :eof\n  1 if 2\n  return 3\nend"
  assert_format "a = 1 if 1 == 2 ||\n  3 == 4\n", "a = 1 if 1 == 2 ||\n         3 == 4"
  assert_format "{ A: 1 }\n", "{A: 1}"
  assert_format "class Foo\n  enum Bar\n  A; B; C;\n  D; E; F\nend\nend\n", "class Foo\n  enum Bar\n    A; B; C\n    D; E; F\n  end\nend"
  assert_format "x.is_a? T\n3\n", "x.is_a? T\n3"
  assert_format "a = begin\n  1\nend\n\na =\nbegin\n  1\nend\n\na = if 1\n  2\nend\n\nb = 1\nb ||= begin\n  2\nend\n\nb ||= if 1\n  2\nend\n\nb += if 1\n  2\nend\n\nb +=\nif 1\n  2\nend\n\na, b = begin\n  1\nend\n\na, b =\nbegin\n  1\nend\n\nc[x] = begin\n  2\nend\n\nc[x] =\nbegin\n  2\nend\n\nc[x] = if 1\n  2\nend\n\nc[x] ||= begin 1\n  2\nend\n\nc[x] ||= if 1\n  2\nend\n\nc[x] += if 1\n  2\nend\n\nc[x] += begin 1\n  2\nend\n\nc[x] +=\nbegin\n  1\n  2\nend\n\nfoo.bar = begin\nend\n\nfoo.bar =\nbegin\nend\n\nfoo.bar = if\n  2\nend\n\nfoo.bar += begin\n  2\nend\n\nfoo.bar += if\n  2\nend\n\n", "a = begin\n  1\nend\n\na =\n  begin\n    1\n  end\n\na = if 1\n      2\n    end\n\nb = 1\nb ||= begin\n  2\nend\n\nb ||= if 1\n        2\n      end\n\nb += if 1\n       2\n     end\n\nb +=\n  if 1\n    2\n  end\n\na, b = begin\n  1\nend\n\na, b =\n  begin\n    1\n  end\n\nc[x] = begin\n  2\nend\n\nc[x] =\n  begin\n    2\n  end\n\nc[x] = if 1\n         2\n       end\n\nc[x] ||= begin\n  1\n  2\nend\n\nc[x] ||= if 1\n           2\n         end\n\nc[x] += if 1\n          2\n        end\n\nc[x] += begin\n  1\n  2\nend\n\nc[x] +=\n  begin\n    1\n    2\n  end\n\nfoo.bar = begin\n\nend\n\nfoo.bar =\n  begin\n\n  end\n\nfoo.bar = if 2\n          end\n\nfoo.bar += begin\n  2\nend\n\nfoo.bar += if 2\n           end"
  assert_format "module Foo\n  1 # bar\nend\n\nmodule Foo\n  1\n  # bar\nend\n\nmodule Foo\n  1\n\n  # bar\nend\n\nmodule Foo\n  1\n  2\n  # bar\nend\n\nmodule Foo\n  1\n  2\n\n  # bar\nend\n\nif 1\n  1\n  # bar\nend\n\nif 1\n  1\n\n  # bar\nend\n\n1\n2\n# foo\n\n1\n2\n\n# foo\n", "module Foo\n  1 # bar\nend\n\nmodule Foo\n  1\n  # bar\nend\n\nmodule Foo\n  1\n\n  # bar\nend\n\nmodule Foo\n  1\n  2\n  # bar\nend\n\nmodule Foo\n  1\n  2\n\n  # bar\nend\n\nif 1\n  1\n  # bar\nend\n\nif 1\n  1\n\n  # bar\nend\n\n1\n2\n# foo\n\n1\n2\n\n# foo"
  assert_format "begin\n  #hola\n  1\nend\n", "begin\n  # hola\n  1\nend"
  assert_format "begin\nend\n\n# a\n", "begin\n\nend\n\n# a"
  assert_format "begin\n  1\nend\n\n1\n", "begin\n  1\nend\n\n1"
  assert_format "{\n  \"a\" => 1, \"b\" => 2,\n  \"foo\" => 3, \"bar\" => 4,\n  \"coconio\" => 5, \"lala\" => 6,\n}\n", "{\n  \"a\" => 1, \"b\" => 2,\n  \"foo\" => 3, \"bar\" => 4,\n  \"coconio\" => 5, \"lala\" => 6,\n}"
  assert_format "if 1\n  foo(\n    1,\n    2 # lala\n    )\nend\n", "if 1\n  foo(\n    1,\n    2 # lala\n  )\nend"
  assert_format "case foo\nwhen 1\n  # A\nelse\n# B\nend\n", "case foo\nwhen 1\n  # A\nelse\n  # B\nend"
  assert_format "return 1\n# end"
  assert_format "case\n# hello\nwhen 1\n  2\nend"
  assert_format "case 1\nwhen 2 # a\n  # b\nend"
  assert_format "case 1\nelse # foo\n  # bar\nend"

  assert_format "{} of A => B\n{} of Foo => Bar"

  assert_format "<<-HTML\n  \#{1}x\n  HTML"
  assert_format "<<-HTML\n  \#{1}x\n  y\n  HTML"
  assert_format "<<-HTML\n  \#{1}x\n  y\n  z\n  HTML"
  assert_format %(<<-HTML\n  \#{"foo"}\n  HTML)
  assert_format %(<<-HTML\n  \#{__FILE__}\n  HTML)
  assert_format %(<<-HTML\n  \#{"fo\#{"o"}"}\n  HTML)
  assert_format %(<<-HTML\n  \#{"foo"}\#{1}\n  HTML)
  assert_format %(<<-HTML\n  foo\n  \#{"foo"}\n  HTML)
  assert_format %(<<-HTML\n  \#{"foo"}\n  \#{"bar"}\n  HTML)

  assert_format "  <<-HTML\n   foo\n  HTML", "<<-HTML\n foo\nHTML"
  assert_format "  <<-HTML\n   \#{1}\n  HTML", "<<-HTML\n \#{1}\nHTML"
  assert_format "  <<-HTML\n  \#{1} \#{2}\n  HTML", "<<-HTML\n\#{1} \#{2}\nHTML"
  assert_format "  <<-HTML\n  foo\nHTML", "<<-HTML\n  foo\nHTML"

  assert_format "<<-HTML\n  hello \n  HTML"
  assert_format "<<-HTML\n  hello \n  world   \n  HTML"
  assert_format "  <<-HTML   \n    hello \n    world   \n    HTML", "<<-HTML\n  hello \n  world   \n  HTML"

  assert_format "x, y = <<-FOO, <<-BAR\n  hello\n  FOO\n  world\n  BAR"
  assert_format "x, y, z = <<-FOO, <<-BAR, <<-BAZ\n  hello\n  FOO\n  world\n  BAR\n  qux\nBAZ"

  assert_format "<<-FOO\nFOO"

  assert_format %(<<-FOO\n\#{"foo"}\nFOO)
  assert_format %(<<-FOO\n\#{"foo"}bar\nFOO)
  assert_format %(<<-FOO\nbar\#{"foo"}\nFOO)
  assert_format %(<<-FOO\nbar\#{"foo"}bar\nFOO)
  assert_format %(<<-FOO\nfoo\n\#{"foo"}\nFOO)
  assert_format %(<<-FOO\nfoo\n\#{1}\nFOO)

  assert_format "#!shebang\n1 + 2"

  assert_format "   {{\n1 + 2 }}", "{{\n  1 + 2\n}}"
  assert_format "   {{\n1 + 2\n   }}", "{{\n  1 + 2\n}}"
  assert_format "   {%\na = 1 %}", "{%\n  a = 1\n%}"
  assert_format "   {%\na = 1\n   %}", "{%\n  a = 1\n%}"

  # Multi-line macro expression with comment as first line (issue #14450)
  assert_format "{%\n  # comment\n  a = 1\n%}"
  assert_format "{%\n  # comment 1\n  # comment 2\n  a = 1\n%}"
  assert_format "{{\n  # comment\n  a + 1\n}}"

  assert_format "macro foo\n  {{\n1 + 2 }}\nend", "macro foo\n  {{\n    1 + 2\n  }}\nend"
  assert_format "macro foo\n  def bar\n    {{\n      1 + 2\n    }}\n  end\nend"
  assert_format "foo &.[]"
  assert_format "foo &.[](1, 2)"
  assert_format "foo &.[](  1, 2  )", "foo &.[](1, 2)"
  assert_format "foo &.[]?"
  assert_format "foo &.[]?(1, 2)"
  assert_format "foo &.[]?(  1, 2  )", "foo &.[]?(1, 2)"
  assert_format "foo &.[]=(1, 2)"
  assert_format "foo &.[]=(  1, 2  )", "foo &.[]=(1, 2)"

  assert_format "foo &.@bar"
  assert_format "foo(&.@bar)"

  assert_format "foo[&.bar]"
  assert_format "foo[1, &.bar]"
  assert_format "foo[x: 1, &.bar]"
  assert_format "foo[&.bar]?"
  assert_format "foo[1, &.bar]?"
  assert_format "foo[x: 1, &.bar]?"
  assert_format "foo[&.bar] = 1"
  assert_format "foo[1, &.bar] = 1"
  assert_format "foo[x: 1, &.bar] = 1"
  assert_format "foo[&.bar] ||= 1"
  assert_format "foo[1, &.bar] ||= 1"
  assert_format "foo[x: 1, &.bar] ||= 1"

  assert_format "foo.[]"
  assert_format "foo.[1]"
  assert_format "foo.[] = 1"
  assert_format "foo.[1, 2] = 3"

  %w(<= == >= != []= ===).each do |operator|
    assert_format "1.#{operator} { 3 }"
    assert_format "1.#{operator}() { 3 }"
    assert_format "1.#{operator}(2) { 3 }"
    assert_format "1.#{operator} do\nend"
  end

  assert_format "@foo : Int32 # comment\n\ndef foo\nend"
  assert_format "getter foo # comment\n\ndef foo\nend"
  assert_format "getter foo : Int32 # comment\n\ndef foo\nend"

  assert_format "a &.b.as C", "a &.b.as C"
  assert_format "a &.b.c.as C", "a &.b.c.as C"
  assert_format "a(&.b.c.as C)", "a(&.b.c.as C)"

  assert_format "a &.b.as(C)"
  assert_format "a &.b.c.as(C)"
  assert_format "a(&.b.c.as(C))"

  assert_format "foo : self?"
  assert_format "foo : self? | A"
  assert_format "foo : (self)?"

  assert_format "foo : (A) | D"
  assert_format "foo : (F(A)) | D"
  assert_format "foo : (   A  |  B   )", "foo : (A | B)"

  # #11179
  assert_format "foo : Pointer(Foo)*"
  assert_format "foo : Foo*****"
  assert_format "foo : Foo * * * * *", "foo : Foo*****"
  assert_format "foo : StaticArray(Foo, 12)[34]"

  assert_format "def   foo(x   :  (A | B)) \n  end", "def foo(x : (A | B))\nend"
  assert_format "foo : (String -> String?) | (String)"
  assert_format "foo : (Array(String)?) | String"
  assert_format "foo : (String -> Array(String)?) | (String -> Array(String)) | Nil"
  assert_format "module Readline\n  @@completion_proc : (String -> Array(String)?) | (String -> Array(String)) | Nil\nend"
  assert_format "alias A = (B(C, (C | D)) | E)"
  assert_format "alias A = ((B(C | D) | E) | F)"
  assert_format "alias A = ({A, (B)})"
  assert_format "alias A = (   A  |  B   )", "alias A = (A | B)"

  assert_format "foo : A(B)\nbar : C"
  assert_format "foo : (A -> B)\nbar : C"
  assert_format "def foo(x : A(B), y)\nend"
  assert_format "alias X = (A, B) ->\nbar : C"
  assert_format "def foo : A(B)\n  nil\nend"
  assert_format "def foo : (A, B) ->\n  nil\nend"
  assert_format "def foo : (A | B(C))\n  nil\nend"
  assert_format "def foo : A | B(C)\n  nil\nend"
  assert_format "def foo(x : (   A  |  B   )) : (   A  |  B   )\nend", "def foo(x : (A | B)) : (A | B)\nend"

  describe "ProcNotation" do
    assert_format "G_(A ->)"
    assert_format "G_((A ->))"
    assert_format "G_((A) ->)"

    assert_format "G_(A, B -> R)"
    assert_format "G_((A), B -> R)"
    assert_format "G_((A, B -> R))"
    assert_format "G_((A, B) -> R)"
    assert_format "G_(((A), B) -> R)"
    assert_format "G_((((A), B) -> R))"

    assert_format "G_((A, B ->) | S)"

    assert_format "G_(A, (B -> R))"
    assert_format "G_(A, ->)"
    assert_format "G_(A, (->))"
    pending { assert_format "G_(A, () ->)" } # #16741
    assert_format "G_(A, -> R)"
    assert_format "G_(-> R)"
    pending { assert_format "G_(() -> R)" } # #16741

    assert_format "G_(A -> R | S)"
    assert_format "G_((A -> R | S))"
    assert_format "G_((A) -> R | S)"

    assert_format "G_((A -> R) | S)"

    assert_format "G_(A | B -> R)"
    assert_format "G_((A | B) -> C)"
    assert_format "G_(A | (B -> C))"
  end

  assert_format "foo &.bar.is_a?(Baz)"
  assert_format "foo &.bar.responds_to?(:baz)"

  assert_format "foo &.nil?"
  assert_format "foo &.bar.nil?"
  assert_format "foo &.nil?()", "foo &.nil?"
  assert_format "foo &.bar.nil?()", "foo &.bar.nil?"

  assert_format "1 if nil?\na.b + c"

  assert_format "foo(<<-X,\na\nX\n  1)"
  assert_format "def bar\n  foo(<<-X,\n  a\n  X\n    1)\nend"
  assert_format %(run("a", 1))

  assert_format "foo.bar # comment\n  .baz"
  assert_format "foo.bar(1) # comment\n  .baz"

  assert_format "foo[bar.baz]\n  .qux"

  assert_format "bla.select(&.all?{ |x| x } )", "bla.select(&.all? { |x| x })"
  assert_format "def foo\n  <<-FOO\n  foo \#{1}\n  FOO\nend"

  assert_format "@x : A(B | C)?"

  assert_format "page= <<-HTML\n  foo\nHTML", "page = <<-HTML\n  foo\nHTML"
  assert_format "page= <<-HTML\n  \#{1}foo\nHTML", "page = <<-HTML\n  \#{1}foo\nHTML"

  assert_format "self.as(Int32)"
  assert_format "foo.as ( Int32* )", "foo.as(Int32*)"
  assert_format "foo.as   Int32*", "foo.as Int32*"
  assert_format "foo.as(T).bar"
  assert_format "foo &.as(T)"
  assert_format "foo &.bar.as(T)"
  assert_format "foo &.as(T).bar"
  assert_format "foo &.as?(T).bar"
  assert_format "foo &.is_a?(T).bar"
  assert_format "foo &.responds_to?(:foo).bar"

  assert_format "foo.as? ( Int32* )", "foo.as?(Int32*)"
  assert_format "foo.as?   Int32*", "foo.as? Int32*"
  assert_format "foo.as?(T).bar"
  assert_format "foo &.as?(T)"
  assert_format "foo &.bar.as?(T)"

  assert_format "def foo(x, *, z)\nend"
  assert_format "macro foo(x, *, z)\nend"

  assert_format "def foo(x, *, y, **z)\nend"
  assert_format "def foo(**z)\nend"
  assert_format "def foo(*y, **z)\nend"
  assert_format "def foo(**z, &block)\nend"
  assert_format "def foo(x, **z)\nend"
  assert_format "def foo(x, **z, &block)\nend"
  assert_format "def foo(**z : Foo)\nend"

  assert_format "def foo(x y)\nend"
  assert_format "def foo(x @y)\nend"
  assert_format "def foo(x @@y)\nend"

  assert_format " Array( {x:  Int32,   y:  String } )", "Array({x: Int32, y: String})"

  assert_format "foo { | a, ( b , c ) | a + b + c }", "foo { |a, (b, c)| a + b + c }"
  assert_format "foo { | a, ( b , c, ), | a + b + c }", "foo { |a, (b, c)| a + b + c }"
  assert_format "foo { | a, ( _ , c ) | a + c }", "foo { |a, (_, c)| a + c }"
  assert_format "foo { | a, ( b , (c, d) ) | a + b + c }", "foo { |a, (b, (c, d))| a + b + c }"
  assert_format "foo { | ( a, *b , c ) | a }", "foo { |(a, *b, c)| a }"

  assert_format "def foo\n  {{@type}}\nend"

  assert_format "[\n  1, # foo\n  3,\n]"
  assert_format "[\n  1, 2, # foo\n  3,\n]"
  assert_format "[\n  1, 2, # foo\n  3, 4,\n]"
  assert_format "foo { |x, *y| }"

  assert_format %(foo "bar": 1, "baz qux": 2)
  assert_format %(foo("bar": 1, "baz qux": 2))

  assert_format %(Foo("bar": Int32, "baz qux": Float64))
  assert_format %(x : {"foo bar": Int32})

  assert_format %(def foo("bar baz" qux)\nend)
  assert_format "{ {{FOO}}, nil}", "{ {{FOO}}, nil }"
  assert_format "{ {% begin %}1{% end %}, nil }"
  assert_format "{ {% for x in 1..2 %}3{% end %}, nil }"
  assert_format "{ %() }"
  assert_format "{ %w() }"
  assert_format "{ {1}.foo, 2 }"

  assert_format "String?"
  assert_format "String???"
  assert_format "Foo::Bar?"
  assert_format "Foo::Bar(T, U?)?"
  assert_format "Union(Foo::Bar?, Baz?, Qux(T, U?))"

  assert_format "lib Foo\n  {% if 1 %}\n    fun foo\n  {% end %}\nend\n\nmacro bar\n  1\nend"

  assert_format "x : Int32 |\nString", "x : Int32 |\n    String"

  assert_format %(foo("bar" \\\n"baz")), %(foo("bar" \\\n    "baz"))
  assert_format %(foo("b\#{1}" \\\n"baz")), %(foo("b\#{1}" \\\n    "baz"))

  assert_format "foo(A |\nB |\nC)", "foo(A |\n    B |\n    C)"
  assert_format "def foo\n  case x\n  # z\n  when 1\n  end\nend"
  assert_format "foo { |x| (x).a }"
  assert_format "def foo(\n  &block\n)\nend"
  assert_format "def foo(a,\n        &block)\nend"
  assert_format "def foo(\n  a,\n  &block\n)\nend"
  assert_format "def foo(a,\n        *b)\nend"
  assert_format "def foo(a, # comment\n        *b)\nend", "def foo(a, # comment\n        *b)\nend"
  assert_format "def foo(a,\n        **b)\nend"
  assert_format "def foo(\n  **a\n)\n  1\nend", "def foo(\n  **a,\n)\n  1\nend"
  assert_format "def foo(**a,)\n  1\nend", "def foo(**a)\n  1\nend"
  assert_format "def foo(\n  **a # comment\n)\n  1\nend", "def foo(\n  **a, # comment\n)\n  1\nend"
  assert_format "def foo(\n  **a\n  # comment\n)\n  1\nend", "def foo(\n  **a,\n  # comment\n)\n  1\nend"
  assert_format "def foo(\n  **a\n\n  # comment\n)\n  1\nend", "def foo(\n  **a,\n\n  # comment\n)\n  1\nend"
  assert_format "def foo(**b, # comment\n        &block)\nend"
  assert_format "def foo(a, **b, # comment\n        &block)\nend"

  assert_format "1 +\n  # foo\n  2"
  assert_format "1 +\n  # foo\n  2"
  assert_format "1 ||\n  # foo\n  2"
  assert_format "foo(1 ||\n    # foo\n    2)"

  assert_format "x = a do\n  1 ||\n    2\nend"
  assert_format "case 1\nwhen a; 2\nelse; b\nend", "case 1\nwhen a; 2\nelse    b\nend"
  assert_format "case 1\nwhen a; 2\nelse; ; b\nend", "case 1\nwhen a; 2\nelse    b\nend"

  assert_format "as Foo"
  assert_format "as? Foo"
  assert_format "is_a? Foo"
  assert_format "responds_to? :foo"
  assert_format "nil?"

  assert_format "Union(Int32, String)?"

  assert_format "<<-HEREDOC\n  \#{foo}\n  H\#{bar}\n  HEREDOC"
  assert_format "foo[a, b: 2]"

  assert_format "def a\n  {\n    1, # x\n    # y\n  }\nend"
  assert_format "def a\n  [\n    1, # x\n    # y\n  ]\nend"
  assert_format "def a\n  b(\n    1, # x\n    # y\n  )\nend"
  assert_format "def a\n  b(\n    1, # x\n    # y\n    2\n  )\nend"
  assert_format "def a\n  b(\n    a: 1, # x\n    # y\n    b: 2\n  )\nend"
  assert_format "def a\n  b(\n    1, # x\n    # y\n    a: 1, # x\n    # y\n    b: 2 # z\n  )\nend"

  assert_format "def foo(a, **b : Int32)\nend"

  assert_format "foo\n  \nbar", "foo\n\nbar"

  assert_format "\"\" + <<-END\n  bar\n  END"

  assert_format "1 + \\\n2", "1 + \\\n  2"
  assert_format "1 + \\\n2 + \\\n3", "1 + \\\n  2 + \\\n  3"
  assert_format "1 + \\\n2\n3", "1 + \\\n  2\n3"
  assert_format "1 \\\n+ 2", "1 \\\n  + 2"
  assert_format "foo \\\nbar", "foo \\\n  bar"
  assert_format "1 \\\nif 2", "1 \\\n  if 2"
  assert_format "1 \\\nrescue 2", "1 \\\n  rescue 2"
  assert_format "1 \\\nensure 2", "1 \\\n  ensure 2"
  assert_format "foo bar, \\\nbaz", "foo bar,\n  baz"
  assert_format "x 1, \\\n  2", "x 1,\n  2"
  assert_format "begin\n  1 + \\\n    2\n  3\nend"
  assert_format "begin\n  1 \\\n    + 2\n  3\nend"
  assert_format "foo \\\n  1,\n  2"
  assert_format "foo \\\n  foo: 1,\n  bar: 2"
  assert_format "foo \\\n  1,\n  2\n\nbar \\\n  foo: 1,\n  bar: 2"

  assert_format "alias X = ((Y, Z) ->)"

  assert_format "def x(@y = ->(z) {})\nend", "def x(@y = ->(z) { })\nend"

  assert_format "class X; annotation  FooAnnotation  ;  end ; end", "class X\n  annotation FooAnnotation; end\nend"
  assert_format "class X\n annotation  FooAnnotation  \n  end \n end", "class X\n  annotation FooAnnotation\n  end\nend"

  assert_format "macro foo\n{% verbatim do %}1 + 2{% end %}\nend"
  assert_format "{% verbatim do %}{{1}} + {{2}}{% end %}"
  assert_format "foo({% verbatim do %}{{1}} + {{2}}{% end %})"

  assert_format "{% foo <<-X\nbar\nX\n%}"
  assert_format "foo do\n  {% foo <<-X\n  bar\n  X\n  %}\nend"
  assert_format "{{ foo <<-X\nbar\nX\n}}"
  assert_format "foo do\n  {{ foo <<-X\n  bar\n  X\n  }}\nend"
  assert_format "[foo <<-X\nbar\nX\n]"
  assert_format "foo do\n  [foo <<-X\n  bar\n  X\n  ]\nend"
  assert_format "{1 => foo <<-X\nbar\nX\n}"
  assert_format "foo do\n  {1 => foo <<-X\n  bar\n  X\n  }\nend"
  assert_format "bar do\n  foo <<-X\n  bar\n  X\nend"
  assert_format "foo do\n  bar do\n    foo <<-X\n    bar\n    X\n  end\nend"
  assert_format "call(foo <<-X\nbar\nX\n)"
  assert_format "bar do\n  call(foo <<-X\n  bar\n  X\n  )\nend"

  assert_format "[\n  <<-EOF,\n  foo\n  EOF\n]"
  assert_format "[\n  <<-EOF,\n  foo\n  EOF\n  <<-BAR,\n  bar\n  BAR\n]"
  assert_format "Hash{\n  foo => <<-EOF,\n  foo\n  EOF\n}"
  assert_format "Hash{\n  foo => <<-EOF,\n  foo\n  EOF\n  bar => <<-BAR,\n  bar\n  BAR\n}"
  assert_format "Hash{\n  foo => <<-EOF\n  foo\n  EOF\n}"
  assert_format "{\n  <<-KEY => 1,\n  key\n  KEY\n}"

  # #10734
  assert_format " <<-EOF\n 1\nEOF", "<<-EOF\n 1\nEOF"
  assert_format "  <<-EOF\n   1\n EOF", "<<-EOF\n  1\nEOF"
  assert_format "x =  <<-EOF\n 1\nEOF", "x = <<-EOF\n 1\nEOF"
  assert_format "  <<-EOF\n 1\n  2\n EOF", "<<-EOF\n1\n 2\nEOF"

  # #10735
  assert_format "{\n  variables => true,\n  query     => <<-HEREDOC,\n    foo\n  HEREDOC\n}"
  assert_format "{\n  variables => true,\n  query     => <<-HEREDOC,\n    foo\n  HEREDOC\n  foo => true,\n}"
  assert_format "{\n  query     => <<-HEREDOC,\n    foo\n  HEREDOC\n}", "{\n  query => <<-HEREDOC,\n    foo\n  HEREDOC\n}"
  assert_format "begin\n  query = <<-HEREDOC\n    foo\n  HEREDOC\nend"

  assert_format "begin 0[1] rescue 2 end"
  assert_format "begin\n 0[1] rescue 2 end", "begin 0[1] rescue 2 end"

  assert_format "{%\n  if 1\n    2\n  end\n%}"

  assert_format <<-CRYSTAL
    # ```text
    #  1  +  2
    # ```
    CRYSTAL

  assert_format <<-CRYSTAL
    # ```text
    # 1 + 2
    # ```
    #
    # ```
    # 3 + 4
    # ```
    CRYSTAL

  assert_format <<-CRYSTAL
    X(typeof(begin
      e.is_a?(Y) ? 1 : 2
    end))
    CRYSTAL

  assert_format <<-CRYSTAL
    X(typeof(begin
      e.is_a?(Y)
    end))
    CRYSTAL

  # Keep trailing spaces in macros.
  assert_format(
    "macro foo\n" +
    "  <<-FOO\n" +
    "    hello  \n" +
    "  FOO\n" +
    "end"
  )
  assert_format(
    "{% verbatim do %}\n" +
    "  <<-FOO\n" +
    "    hello  \n" +
    "  FOO\n" +
    "{% end %}"
  )
  assert_format(
    "{% if true %}\n" +
    "  <<-FOO\n" +
    "    hello  \n" +
    "  FOO\n" +
    "{% end %}"
  )
  assert_format(
    "{% for a in %w() %}\n" +
    "  <<-FOO\n" +
    "    hello  \n" +
    "  FOO\n" +
    "{% end %}"
  )
  assert_format(
    "macro foo\n" +
    "  {{x}}" +
    "  <<-FOO\n" +
    "    hello  \n" +
    "  FOO\n" +
    "end"
  )

  # But remove trailing space in macro expression.
  assert_format(
    "macro foo\n" +
    "  1  \n" +
    "  {{  \n" +
    "    42  \n" +
    "  }}  \n" +
    "  2  \n" +
    "end",
    "macro foo\n" +
    "  1  \n" +
    "  {{\n" +
    "    42\n" +
    "  }}  \n" +
    "  2  \n" +
    "end"
  )

  # #7443
  assert_format "long_variable_name = [{\n  :foo => 1,\n}, {\n  :bar => 2,\n}]"
  assert_format "long_variable_name = [\n  {\n    :foo => 1,\n  }, {\n    :bar => 2,\n  },\n]"
  assert_format "long_variable_name = [\n  {\n    :foo => 1,\n  },\n  {\n    :bar => 2,\n  },\n]"
  assert_format "long_variable_name = [1, 2, 3,\n                      4, 5, 6]"
  assert_format "long_variable_name = [1, 2, 3, # foo\n                      4, 5, 6]"

  # #7599
  assert_format "def foo # bar\n  # baz\nend"
  assert_format "def foo(x) # bar\n  # baz\nend"
  assert_format "def foo(x) : Int32 # bar\n  # baz\nend"
  assert_format "def foo(x) forall T # bar\n  # baz\nend"

  # #7608
  assert_format "enum E\n  A # hello\n  B # hello;  C # hello\nend"

  # #7631
  assert_format "x.try &.[] 123"
  assert_format "x.try &.[]= 123, 456"

  # #7684
  assert_format "foo(\n  <<-HERE,\n  hello\n  HERE\n  1,\n)"
  assert_format "foo(\n  <<-HERE,\n  hello\n  HERE\n  foo: 1,\n)"
  assert_format "foo(\n  <<-HERE,\n  hello\n  HERE\n  # foo\n  foo: 1,\n)"

  # #7614
  assert_format "@[ Foo ]\ndef foo\nend", "@[Foo]\ndef foo\nend"
  assert_format "@[ Foo(foo: 1) ]\ndef foo\nend", "@[Foo(foo: 1)]\ndef foo\nend"
  assert_format "@[Foo(\n  foo: 1\n)]\ndef foo\nend"
  assert_format "@[Foo(\n  foo: 1,\n)]\ndef foo\nend"

  # #7550
  assert_format "foo\n  .bar(\n    1\n  )"
  assert_format "foo\n  .bar\n  .baz(\n    1\n  )"
  assert_format "foo.bar\n  .baz(\n    1\n  )"

  assert_format <<-CRYSTAL,
    def foo
      {% if flag?(:foo) %}
        foo  +  bar
      {% else %}
        baz  +  qux
      {% end %}
    end
    CRYSTAL
    <<-CRYSTAL
    def foo
      {% if flag?(:foo) %}
        foo + bar
      {% else %}
        baz + qux
      {% end %}
    end
    CRYSTAL

  assert_format <<-CRYSTAL,
    def foo
      {% for x in y %}
        foo  +  bar
      {% end %}
    end
    CRYSTAL
    <<-CRYSTAL
    def foo
      {% for x in y %}
        foo + bar
      {% end %}
    end
    CRYSTAL

  assert_format <<-CRYSTAL,
    x = {% if flag?(:foo) %}
          foo  +  bar
        {% else %}
          baz  +  qux
        {% end %}
    CRYSTAL
    <<-CRYSTAL
    x = {% if flag?(:foo) %}
          foo + bar
        {% else %}
          baz + qux
        {% end %}
    CRYSTAL

  assert_format <<-CRYSTAL
    {% if flag?(:freebsd) %}
      1 + 2
    {% end %}

    case x
    when 1234 then 1
    else           x
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    {% if z %}
      1
    {% end %}

    def foo
      z =
        123 + # foo
          4   # bar

      1
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    lib LibFoo
      {% begin %}
        fun foo : Int32
      {% end %}
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    lib LibFoo
      struct Bar
        {% begin %}
          x : Int32
        {% end %}
      end
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    enum Foo
      {% begin %}
        A
        B
        C
      {% end %}
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    a = 1
    b, c = 2, 3
    {% begin %}
      a |= 1
      b |= 2
      c |= 3
    {% end %}
    CRYSTAL

  assert_format <<-CRYSTAL
    lib LibFoo
      {% begin %}
        fun x = y(Int32)
      {% end %}
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    {% begin %}
      "
        foo"
    {% end %}
    CRYSTAL

  assert_format <<-CRYSTAL,
    {% if z %}
      class   Foo
      end
    {% end %}
    CRYSTAL
    <<-CRYSTAL
    {% if z %}
      class Foo
      end
    {% end %}
    CRYSTAL

  assert_format <<-CRYSTAL
    {% if true %}
      # x
    {% end %}
    CRYSTAL

  assert_format <<-CRYSTAL
    {% if true %}
      # x
      # y
    {% end %}
    CRYSTAL

  assert_format <<-CRYSTAL
    {% if true %}
      # x
      #
    {% end %}

    # ```
    # x
    # ```
    CRYSTAL

  assert_format <<-CRYSTAL
    def foo(x)
      {% if true %}
        x = x + 2
      {% end %}
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    def foo(x)
      {% if true %}
        # comment
        Foo = 1
        B   = 2
      {% end %}
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    def foo(x)
      {% if true %}
        \\{% if true %}
          x = 1
        \\{% else %}
          x = 2
        \\{% end %}
        \\{% for x in y %}
          x = 1
        \\{% end %}
        \\{{x}}
        \\{% x %}
      {% end %}
    end
    CRYSTAL

  it "gives proper line number in syntax error inside macro" do
    source = <<-CRYSTAL
      a = 1
      b = 2

      {% begin %}
        c |= 3
      {% end %}
    CRYSTAL

    ex = expect_raises(Crystal::SyntaxException) do
      Crystal.format(source)
    end
    ex.line_number.should eq(5)
  end

  # #8197
  assert_format <<-CRYSTAL
    foo
      .foo1(bar
        .bar1
        .bar2)
    CRYSTAL

  assert_format <<-CRYSTAL
    foo.foo1(
      bar
        .bar1
        .bar2)
    CRYSTAL

  assert_format "[] of (Array(T))"
  assert_format "[] of (((Array(T))))"

  assert_format <<-CRYSTAL
    macro foo # bar
      baz
    end
    CRYSTAL

  assert_format "a.!"
  assert_format "a &.!"
  assert_format "a &.a.!"
  assert_format "a &.!.!"

  assert_format <<-CRYSTAL, <<-CRYSTAL
    ->{
      # first comment
      puts "hi"
      # second comment
    }
    CRYSTAL
    -> {
      # first comment
      puts "hi"
      # second comment
    }
    CRYSTAL

  # #9014
  assert_format <<-CRYSTAL
    {%
      unless true
        1
      end
    %}
    CRYSTAL

  assert_format <<-CRYSTAL
    {%
      unless true
        1
      else
        2
      end
    %}
    CRYSTAL

  assert_format <<-CRYSTAL
    {%
      if true
        1
      else
        2
      end
    %}
    CRYSTAL

  # #4626
  assert_format <<-CRYSTAL
    1 # foo
    / 1 /
    CRYSTAL

  assert_format <<-CRYSTAL
    1 # foo
    / \#{1} /
    CRYSTAL

  assert_format <<-CRYSTAL,
    def foo
      # Comment


    end
    CRYSTAL
    <<-CRYSTAL
    def foo
      # Comment
    end
    CRYSTAL

  assert_format <<-CRYSTAL,
    def foo
      1
      # Comment


    end
    CRYSTAL
    <<-CRYSTAL
    def foo
      1
      # Comment
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    def foo
      1
    end

    # Comment

    def bar
      2
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    require "foo"

    @x : Int32

    class Bar
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    x = <<-FOO
      hello
      FOO

    def bar
    end
    CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
    begin
      1
      # Comment


    end
    CRYSTAL
    begin
      1
      # Comment
    end
    CRYSTAL

  assert_format <<-CRYSTAL, <<-CRYSTAL
    begin
      # Comment


    end
    CRYSTAL
    begin
      # Comment
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    foo 1, # comment
      do
      end
    CRYSTAL

  assert_format <<-CRYSTAL
    foo 1, # comment
      # bar
      do
      end
    CRYSTAL

  # #10190
  assert_format <<-CRYSTAL
    foo(
      1,
    ) do
      2
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    foo(
      1,
    ) {
      2
    }
    CRYSTAL

  # #11079
  assert_format <<-CRYSTAL
    foo = [1, [2,
               3],
           4]
    CRYSTAL

  assert_format <<-CRYSTAL
    foo = {1, {2,
               3},
           4}
    CRYSTAL

  # #10817
  assert_format <<-CRYSTAL
    def func # comment
      (1 + 2) / 3
    end
    CRYSTAL

  # #10943
  assert_format <<-CRYSTAL
    foo do # a
      # b
      bar
    end
    CRYSTAL

  # #10499
  assert_format <<-CRYSTAL
    case nil
    else nil; nil # comment
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    case nil
    else nil; nil
    # comment
    end
    CRYSTAL

  # #12493
  assert_format <<-CRYSTAL
    select
    # when foo
    when bar
      break
    end
    CRYSTAL

  assert_format <<-CRYSTAL
    select # some comment
    when bar
      break
    end
    CRYSTAL

  # #12378
  assert_format <<-CRYSTAL
    macro foo
      macro bar
        \\{% begin %}
          \\\\{% puts %}
        \\{% end %}
      end
    end
    CRYSTAL

  # #12964
  assert_format <<-CRYSTAL
    begin
      begin
        a
        # b
      end
    end
    CRYSTAL

  it do
    expect_raises(Crystal::SyntaxException) do
      Crystal.format <<-CRYSTAL
        lib A
          struct B
            {% begin %}
              x : Int32
              else
            {% end %}
          end
        end
        CRYSTAL
    end
  end

  # #14256
  assert_format <<-CRYSTAL
    foo bar # comment

    # doc
    def baz; end
    CRYSTAL

  # 15180
  assert_format <<-CRYSTAL
    x = uninitialized Foo
    {% begin %}
      x = foo(x)
    {% end %}
    CRYSTAL

  # CVE-2021-42574
  describe "Unicode bi-directional control characters" do
    ['\u202A', '\u202B', '\u202C', '\u202D', '\u202E', '\u2066', '\u2067', '\u2068', '\u2069'].each do |char|
      assert_format %("#{char}"), %("#{char.unicode_escape}")
      assert_format %("\\c#{char}"), %("c#{char.unicode_escape}")
      assert_format %("#{char}\#{1}"), %("#{char.unicode_escape}\#{1}")
      assert_format %("\\c#{char}\#{1}"), %("c#{char.unicode_escape}\#{1}")
      assert_format %(%(#{char})), %(%(#{char.unicode_escape}))
      assert_format %(%Q(#{char})), %(%Q(#{char.unicode_escape}))
      assert_format %(%Q(#{char}\#{1})), %(%Q(#{char.unicode_escape}\#{1}))
      assert_format %(<<-EOS\n#{char}\nEOS), %(<<-EOS\n#{char.unicode_escape}\nEOS)
      assert_format %(<<-EOS\n#{char}\#{1}\nEOS), %(<<-EOS\n#{char.unicode_escape}\#{1}\nEOS)
      assert_format %(def foo("#{char}" x)\nend), %(def foo("#{char.unicode_escape}" x)\nend)
      assert_format %(foo("#{char}": 1)), %(foo("#{char.unicode_escape}": 1))
      assert_format %(NamedTuple("#{char}": Int32)), %(NamedTuple("#{char.unicode_escape}": Int32))
      assert_format %({"#{char}": 1}), %({"#{char.unicode_escape}": 1})

      # the following contexts do not accept escape sequences, escaping these
      # control characters would alter the meaning of the source code
      assert_format %(/#{char}/)
      assert_format %(%r(#{char}))
      assert_format %(%q(#{char}))
      assert_format %(%w(#{char}))
      assert_format %(%i(#{char}))
      assert_format %(/#{char}\#{1}/)
      assert_format %(%r(#{char}\#{1}))
      assert_format %(<<-'EOS'\n#{char}\nEOS)
    end
  end

  # #16755
  assert_format <<-CRYSTAL, <<-CRYSTAL
    macro foo
      Foo(
      )
    end

    {
      a:           1,
      description: 2,
    }
    CRYSTAL
    macro foo
      Foo()
    end

    {
      a:           1,
      description: 2,
    }
    CRYSTAL
end
