xref: /aosp_15_r20/external/ktfmt/core/src/test/java/com/facebook/ktfmt/format/FormatterTest.kt (revision 5be3f65c8cf0e6db0a7e312df5006e8e93cdf9ec)
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.facebook.ktfmt.format
18 
19 import com.facebook.ktfmt.format.Formatter.META_FORMAT
20 import com.facebook.ktfmt.testutil.assertFormatted
21 import com.facebook.ktfmt.testutil.assertThatFormatting
22 import com.facebook.ktfmt.testutil.defaultTestFormattingOptions
23 import com.google.common.truth.Truth.assertThat
24 import org.junit.Assert.fail
25 import org.junit.BeforeClass
26 import org.junit.Test
27 import org.junit.runner.RunWith
28 import org.junit.runners.JUnit4
29 
30 @Suppress("FunctionNaming")
31 @RunWith(JUnit4::class)
32 class FormatterTest {
33 
34   @Test
support script (kts) filesnull35   fun `support script (kts) files`() =
36       assertFormatted(
37           """
38         |package foo
39         |
40         |import java.io.File
41         |
42         |val one: String
43         |
44         |val two: String
45         |
46         |fun f() {
47         |  println("asd")
48         |}
49         |
50         |println("Called with args:")
51         |
52         |args.forEach { println(File + "-") }
53         |"""
54               .trimMargin())
55 
56   @Test
57   fun `support script (kts) files with a shebang`() =
58       assertFormatted(
59           """
60         |#!/usr/bin/env kscript
61         |package foo
62         |
63         |println("Called")
64         |"""
65               .trimMargin())
66 
67   @Test
68   fun `call chains`() =
69       assertFormatted(
70           """
71       |//////////////////////////////////////////////////
72       |fun f() {
73       |  // Static method calls are attached to the class name.
74       |  ImmutableList.newBuilder()
75       |      .add(1)
76       |      .add(1)
77       |      .add(1)
78       |      .add(1)
79       |      .add(1)
80       |      .add(1)
81       |      .add(1)
82       |      .add(1)
83       |      .add(1)
84       |      .add(1)
85       |      .build()
86       |
87       |  // Multiple call expressions --> each on its own line.
88       |  ImmutableList()
89       |      .newBuilder()
90       |      .add(1)
91       |      .add(1)
92       |      .add(1)
93       |      .add(1)
94       |      .add(1)
95       |      .add(1)
96       |      .add(1)
97       |      .add(1)
98       |      .add(1)
99       |      .add(1)
100       |      .build()
101       |}
102       |"""
103               .trimMargin(),
104           deduceMaxWidth = true)
105 
106   @Test
107   fun `line breaks in function arguments`() =
108       assertFormatted(
109           """
110       |//////////////////////////////////////////////////
111       |fun f() {
112       |  computeBreaks(
113       |      javaOutput.commentsHelper,
114       |      maxWidth,
115       |      Doc.State(+0, 0))
116       |  computeBreaks(
117       |      output.commentsHelper, maxWidth, State(0))
118       |  doc.computeBreaks(
119       |      javaOutput.commentsHelper,
120       |      maxWidth,
121       |      Doc.State(+0, 0))
122       |  doc.computeBreaks(
123       |      output.commentsHelper, maxWidth, State(0))
124       |}
125       |"""
126               .trimMargin(),
127           deduceMaxWidth = true)
128 
129   @Test
130   fun `parameters and return type in function definitions`() =
131       assertFormatted(
132           """
133       |////////////////////////////////////////
134       |fun format(
135       |    code: String,
136       |    maxWidth: Int =
137       |        DEFAULT_MAX_WIDTH_VERY_LONG
138       |): String {
139       |  val a = 0
140       |}
141       |
142       |fun print(
143       |    code: String,
144       |    maxWidth: Int =
145       |        DEFAULT_MAX_WIDTH_VERY_LONG
146       |) {
147       |  val a = 0
148       |}
149       |"""
150               .trimMargin(),
151           deduceMaxWidth = true)
152 
153   @Test
154   fun `kitchen sink of tests`() {
155     // Don't add more tests here
156     val code =
157         """
158         |fun
159         |f  (
160         |a : Int
161         | , b: Double , c:String) {           var result = 0
162         | val aVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVar = 43
163         |          foo.bar.zed.accept(
164         |
165         |          )
166         |
167         |          foo(
168         |
169         |          )
170         |
171         |          foo.bar.zed.accept(
172         |                DoSomething.bar()
173         |          )
174         |
175         |          bar(
176         |          ImmutableList.newBuilder().add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).build())
177         |
178         |
179         |          ImmutableList.newBuilder().add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).build()
180         |     }
181         |"""
182             .trimMargin()
183 
184     val expected =
185         """
186         |fun f(a: Int, b: Double, c: String) {
187         |  var result = 0
188         |  val aVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVar =
189         |      43
190         |  foo.bar.zed.accept()
191         |
192         |  foo()
193         |
194         |  foo.bar.zed.accept(DoSomething.bar())
195         |
196         |  bar(
197         |      ImmutableList.newBuilder()
198         |          .add(1)
199         |          .add(1)
200         |          .add(1)
201         |          .add(1)
202         |          .add(1)
203         |          .add(1)
204         |          .add(1)
205         |          .add(1)
206         |          .add(1)
207         |          .add(1)
208         |          .build())
209         |
210         |  ImmutableList.newBuilder()
211         |      .add(1)
212         |      .add(1)
213         |      .add(1)
214         |      .add(1)
215         |      .add(1)
216         |      .add(1)
217         |      .add(1)
218         |      .add(1)
219         |      .add(1)
220         |      .add(1)
221         |      .build()
222         |}
223         |"""
224             .trimMargin()
225 
226     assertThatFormatting(code).isEqualTo(expected)
227     // Don't add more tests here
228   }
229 
230   @Test
spacing around variable declarationsnull231   fun `spacing around variable declarations`() =
232       assertFormatted(
233           """
234       |fun f() {
235       |  var x: Int = 4
236       |  val y = 0
237       |}
238       |"""
239               .trimMargin())
240 
241   @Test fun `class without a body nor properties`() = assertFormatted("class Foo\n")
242 
243   @Test fun `interface without a body nor properties`() = assertFormatted("interface Foo\n")
244 
245   @Test fun `preserve empty primary constructor`() = assertFormatted("class Foo()\n")
246 
247   @Test
248   fun `simple fun interface`() =
249       assertFormatted(
250           """fun interface MyRunnable {
251         |  fun runIt()
252         |}
253         |"""
254               .trimMargin())
255 
256   @Test
257   fun `handle complex fun interface without body`() =
258       assertFormatted("public fun interface Function<T : List<*>> : (Int, T?) -> T?\n")
259 
260   @Test
261   fun `class without a body, with explicit ctor params`() =
262       assertFormatted("class Foo(a: Int, var b: Double, val c: String)\n")
263 
264   @Test
265   fun `class with a body and explicit ctor params`() =
266       assertFormatted(
267           """
268       |class Foo(a: Int, var b: Double, val c: String) {
269       |  val x = 2
270       |
271       |  fun method() {}
272       |
273       |  class Bar
274       |}
275       |"""
276               .trimMargin())
277 
278   @Test
279   fun `properties and fields with modifiers`() =
280       assertFormatted(
281           """
282       |class Foo(public val p1: Int, private val p2: Int, open val p3: Int, final val p4: Int) {
283       |  private var f1 = 0
284       |
285       |  public var f2 = 0
286       |
287       |  open var f3 = 0
288       |
289       |  final var f4 = 0
290       |}
291       |"""
292               .trimMargin())
293 
294   @Test
295   fun `properties with multiple modifiers`() =
296       assertFormatted(
297           """
298       |class Foo(public open inner val p1: Int) {
299       |  public open inner var f2 = 0
300       |}
301       |"""
302               .trimMargin())
303 
304   @Test
305   fun `spaces around binary operations`() =
306       assertFormatted(
307           """
308       |fun foo() {
309       |  a = 5
310       |  x + 1
311       |}
312       |"""
313               .trimMargin())
314 
315   @Test
316   fun `breaking long binary operations`() =
317       assertFormatted(
318           """
319       |////////////////////
320       |fun foo() {
321       |  val finalWidth =
322       |      value1 +
323       |          value2 +
324       |          (value3 +
325       |              value4 +
326       |              value5) +
327       |          foo(v) +
328       |          (1 + 2) +
329       |          function(
330       |              value7,
331       |              value8) +
332       |          value9
333       |}
334       |"""
335               .trimMargin(),
336           deduceMaxWidth = true)
337 
338   @Test
339   fun `prioritize according to associativity`() =
340       assertFormatted(
341           """
342       |//////////////////////////////////////
343       |fun foo() {
344       |  return expression1 != expression2 ||
345       |      expression2 != expression1
346       |}
347       |"""
348               .trimMargin(),
349           deduceMaxWidth = true)
350 
351   @Test
352   fun `once a binary expression is broken, split on every line`() =
353       assertFormatted(
354           """
355         |//////////////////////////////////////
356         |fun foo() {
357         |  val sentence =
358         |      "The" +
359         |          "quick" +
360         |          ("brown" + "fox") +
361         |          "jumps" +
362         |          "over" +
363         |          "the" +
364         |          "lazy" +
365         |          "dog"
366         |}
367         |"""
368               .trimMargin(),
369           deduceMaxWidth = true)
370 
371   @Test
372   fun `long binary expressions with ranges in the middle`() =
373       assertFormatted(
374           """
375         |//////////////////////////////////////
376         |fun foo() {
377         |  val sentence =
378         |      "The" +
379         |          "quick" +
380         |          ("brown".."fox") +
381         |          ("brown"..<"fox") +
382         |          "jumps" +
383         |          "over" +
384         |          "the".."lazy" + "dog"
385         |}
386         |"""
387               .trimMargin(),
388           deduceMaxWidth = true)
389 
390   @Test
391   fun `assignment expressions with scoping functions are block-like`() =
392       assertFormatted(
393           """
394         |///////////////////////////
395         |fun f() {
396         |  name.sub = scope { x ->
397         |    //
398         |  }
399         |  name.sub += scope { x ->
400         |    //
401         |  }
402         |  name.sub -= scope { x ->
403         |    //
404         |  }
405         |  name.sub *= scope { x ->
406         |    //
407         |  }
408         |  name.sub /= scope { x ->
409         |    //
410         |  }
411         |  name.sub %= scope { x ->
412         |    //
413         |  }
414         |}
415         |
416         |fun h() {
417         |  long.name.sub =
418         |      scope { x ->
419         |        //
420         |      }
421         |  long.name.sub +=
422         |      scope { x ->
423         |        //
424         |      }
425         |  long.name.sub -=
426         |      scope { x ->
427         |        //
428         |      }
429         |  long.name.sub *=
430         |      scope { x ->
431         |        //
432         |      }
433         |  long.name.sub /=
434         |      scope { x ->
435         |        //
436         |      }
437         |  long.name.sub %=
438         |      scope { x ->
439         |        //
440         |      }
441         |}
442         |"""
443               .trimMargin(),
444           deduceMaxWidth = true)
445 
446   @Test
447   fun `don't keep adding newlines between these two comments when they're at end of file`() {
448     assertFormatted(
449         """
450      |package foo
451      |// a
452      |
453      |/* Another comment */
454      |"""
455             .trimMargin())
456 
457     assertFormatted(
458         """
459      |// Comment as first element
460      |package foo
461      |// a
462      |
463      |/* Another comment */
464      |"""
465             .trimMargin())
466 
467     assertFormatted(
468         """
469      |// Comment as first element then blank line
470      |
471      |package foo
472      |// a
473      |
474      |/* Another comment */
475      |"""
476             .trimMargin())
477 
478     assertFormatted(
479         """
480      |// Comment as first element
481      |package foo
482      |// Adjacent line comments
483      |// Don't separate
484      |"""
485             .trimMargin())
486   }
487 
488   @Test
properties with line comment above initializernull489   fun `properties with line comment above initializer`() =
490       assertFormatted(
491           """
492       |class Foo {
493       |  var x: Int =
494       |      // Comment
495       |      0
496       |
497       |  var y: Int =
498       |      // Comment
499       |      scope {
500       |        0 //
501       |      }
502       |
503       |  var z: Int =
504       |      // Comment
505       |      if (cond) {
506       |        0
507       |      } else {
508       |        1
509       |      }
510       |}
511       |"""
512               .trimMargin())
513 
514   @Test
515   fun `properties with line comment above delegate`() =
516       assertFormatted(
517           """
518       |class Foo {
519       |  var x: Int by
520       |      // Comment
521       |      0
522       |
523       |  var y: Int by
524       |      // Comment
525       |      scope {
526       |        0 //
527       |      }
528       |
529       |  var z: Int by
530       |      // Comment
531       |      if (cond) {
532       |        0
533       |      } else {
534       |        1
535       |      }
536       |}
537       |"""
538               .trimMargin())
539 
540   @Test
541   fun `properties with accessors`() =
542       assertFormatted(
543           """
544       |class Foo {
545       |  var x: Int
546       |    get() = field
547       |
548       |  var y: Boolean
549       |    get() = x.equals(123)
550       |    set(value) {
551       |      field = value
552       |    }
553       |
554       |  var z: Boolean
555       |    get() {
556       |      x.equals(123)
557       |    }
558       |
559       |  var zz = false
560       |    private set
561       |}
562       |"""
563               .trimMargin())
564 
565   @Test
566   fun `properties with accessors and semicolons on same line`() {
567     val code =
568         """
569       |class Foo {
570       |  var x = false; private set
571       |
572       |  internal val a by lazy { 5 }; internal get
573       |
574       |  var foo: Int; get() = 6; set(x) {};
575       |}
576       |"""
577             .trimMargin()
578 
579     val expected =
580         """
581       |class Foo {
582       |  var x = false
583       |    private set
584       |
585       |  internal val a by lazy { 5 }
586       |    internal get
587       |
588       |  var foo: Int
589       |    get() = 6
590       |    set(x) {}
591       |}
592       |"""
593             .trimMargin()
594 
595     assertThatFormatting(code).isEqualTo(expected)
596   }
597 
598   @Test
a property with a too long name being broken on multiple linesnull599   fun `a property with a too long name being broken on multiple lines`() =
600       assertFormatted(
601           """
602       |////////////////////
603       |class Foo {
604       |  val thisIsALongName:
605       |      String =
606       |      "Hello there this is long"
607       |    get() = field
608       |}
609       |"""
610               .trimMargin(),
611           deduceMaxWidth = true)
612 
613   @Test
614   fun `multi-character unary and binary operators such as ==`() =
615       assertFormatted(
616           """
617       |fun f() {
618       |  3 == 4
619       |  true && false
620       |  a++
621       |  a === b
622       |}
623       |"""
624               .trimMargin())
625 
626   @Test
627   fun `package names stay in one line`() {
628     val code =
629         """
630       | package  com  .example. subexample
631       |
632       |fun f() = 1
633       |"""
634             .trimMargin()
635     val expected =
636         """
637       |package com.example.subexample
638       |
639       |fun f() = 1
640       |"""
641             .trimMargin()
642 
643     assertThatFormatting(code).isEqualTo(expected)
644   }
645 
646   @Test
handle package name and imports with escapes and spacesnull647   fun `handle package name and imports with escapes and spaces`() =
648       assertFormatted(
649           """
650       |package com.`fun times`.`with package names`
651       |
652       |import `nothing stops`.`us`.`from doing this`
653       |
654       |fun f() = `from doing this`()
655       |"""
656               .trimMargin())
657 
658   @Test
659   fun `safe dot operator expression`() =
660       assertFormatted(
661           """
662       |fun f() {
663       |  node?.name
664       |}
665       |"""
666               .trimMargin())
667 
668   @Test
669   fun `safe dot operator expression with normal`() =
670       assertFormatted(
671           """
672       |fun f() {
673       |  node?.name.hello
674       |}
675       |"""
676               .trimMargin())
677 
678   @Test
679   fun `safe dot operator expression chain in expression function`() =
680       assertFormatted(
681           """
682       |//////////////////////////////////////////////////
683       |fun f(number: Int) =
684       |    Something.doStuff(number)?.size
685       |"""
686               .trimMargin(),
687           deduceMaxWidth = true)
688 
689   @Test
690   fun `avoid breaking suspected package names`() =
691       assertFormatted(
692           """
693       |///////////////////////
694       |fun f() {
695       |  com.facebook.Foo
696       |      .format()
697       |  org.facebook.Foo
698       |      .format()
699       |  java.lang.stuff.Foo
700       |      .format()
701       |  javax.lang.stuff.Foo
702       |      .format()
703       |  kotlin.lang.Foo
704       |      .format()
705       |  foo.facebook.Foo
706       |      .format()
707       |}
708       |"""
709               .trimMargin(),
710           deduceMaxWidth = true)
711 
712   @Test
713   fun `an assortment of tests for emitQualifiedExpression`() =
714       assertFormatted(
715           """
716       |/////////////////////////////////////
717       |fun f() {
718       |  // Regression test: https://github.com/facebook/ktfmt/issues/56
719       |  kjsdfglkjdfgkjdfkgjhkerjghkdfj
720       |      ?.methodName1()
721       |
722       |  // a series of field accesses followed by a single call expression
723       |  // is kept together.
724       |  abcdefghijkl.abcdefghijkl
725       |      ?.methodName2()
726       |
727       |  // Similar to above.
728       |  abcdefghijkl.abcdefghijkl
729       |      ?.methodName3
730       |      ?.abcdefghijkl()
731       |
732       |  // Multiple call expressions cause each part of the expression
733       |  // to be placed on its own line.
734       |  abcdefghijkl
735       |      ?.abcdefghijkl
736       |      ?.methodName4()
737       |      ?.abcdefghijkl()
738       |
739       |  // Don't break first call expression if it fits.
740       |  foIt(something.something.happens())
741       |      .thenReturn(result)
742       |
743       |  // Break after `longerThanFour(` because it's longer than 4 chars
744       |  longerThanFour(
745       |          something.something
746       |              .happens())
747       |      .thenReturn(result)
748       |
749       |  // Similarly to above, when part of qualified expression.
750       |  foo.longerThanFour(
751       |          something.something
752       |              .happens())
753       |      .thenReturn(result)
754       |
755       |  // Keep 'super' attached to the method name
756       |  super.abcdefghijkl
757       |      .methodName4()
758       |      .abcdefghijkl()
759       |}
760       |"""
761               .trimMargin(),
762           deduceMaxWidth = true)
763 
764   @Test
765   fun `an assortment of tests for emitQualifiedExpression with lambdas`() =
766       assertFormatted(
767           """
768       |////////////////////////////////////////////////////////////////////////////
769       |fun f() {
770       |  val items =
771       |      items.toMutableList.apply {
772       |        //
773       |        foo
774       |      }
775       |
776       |  val items =
777       |      items.toMutableList().apply {
778       |        //
779       |        foo
780       |      }
781       |
782       |  // All dereferences are on one line (because they fit), even though
783       |  // the apply() at the end requires a line break.
784       |  val items =
785       |      items.toMutableList.sdfkjsdf.sdfjksdflk.sdlfkjsldfj.apply {
786       |        //
787       |        foo
788       |      }
789       |
790       |  // All method calls are on one line (because they fit), even though
791       |  // the apply() at the end requires a line break.
792       |  val items =
793       |      items.toMutableList().sdfkjsdf().sdfjksdflk().sdlfkjsldfj().apply {
794       |        //
795       |        foo
796       |      }
797       |
798       |  // All method calls with lambdas could fit, but we avoid a block like syntax
799       |  // and break to one call per line
800       |  val items =
801       |      items
802       |          .map { it + 1 }
803       |          .filter { it > 0 }
804       |          .apply {
805       |            //
806       |            foo
807       |          }
808       |
809       |  // the lambda is indented properly with the break before it
810       |  val items =
811       |      items.fieldName.sdfkjsdf.sdfjksdflk.sdlfkjsldfj.sdfjksdflk.sdlfkjsldfj
812       |          .sdlfkjsldfj
813       |          .apply {
814       |            //
815       |            foo
816       |          }
817       |  items.fieldName.sdfkjsdf.sdfjksdflk.sdlfkjsldfj.sdfjksdflk.sdlfkjsldfj
818       |      .apply {
819       |        //
820       |        foo
821       |      }
822       |
823       |  // When there are multiple method calls, and they don't fit on one
824       |  // line, put each on a new line.
825       |  val items =
826       |      items
827       |          .toMutableList()
828       |          .sdfkjsdf()
829       |          .sdfjksdflk()
830       |          .sdlfkjsldfj()
831       |          .sdfjksdflk()
832       |          .sdlfkjsldfj()
833       |          .apply {
834       |            //
835       |            foo
836       |          }
837       |}
838       |"""
839               .trimMargin(),
840           deduceMaxWidth = true)
841 
842   @Test
843   fun `when two lambdas are in a chain, avoid block syntax`() =
844       assertFormatted(
845           """
846       |class Foo : Bar() {
847       |  fun doIt() {
848       |    fruit.onlyBananas().forEach { banana ->
849       |      val seeds = banana.find { it.type == SEED }
850       |      println(seeds)
851       |    }
852       |
853       |    fruit
854       |        .filter { isBanana(it, Bananas.types) }
855       |        .forEach { banana ->
856       |          val seeds = banana.find { it.type == SEED }
857       |          println(seeds)
858       |        }
859       |  }
860       |}
861       |"""
862               .trimMargin())
863 
864   @Test
865   fun `don't one-line lambdas following argument breaks`() =
866       assertFormatted(
867           """
868       |////////////////////////////////////////////////////////////////////////
869       |class Foo : Bar() {
870       |  fun doIt() {
871       |    // don't break in lambda, no argument breaks found
872       |    fruit.forEach { eat(it) }
873       |
874       |    // break in the lambda, without comma
875       |    fruit.forEach(
876       |        someVeryLongParameterNameThatWillCauseABreak,
877       |        evenWithoutATrailingCommaOnTheParameterListSoLetsSeeIt) {
878       |          eat(it)
879       |        }
880       |
881       |    // break in the lambda, with comma
882       |    fruit.forEach(
883       |        fromTheVine = true,
884       |    ) {
885       |      eat(it)
886       |    }
887       |
888       |    // don't break in the inner lambda, as nesting doesn't respect outer levels
889       |    fruit.forEach(
890       |        fromTheVine = true,
891       |    ) {
892       |      fruit.forEach { eat(it) }
893       |    }
894       |
895       |    // don't break in the lambda, as breaks don't propagate
896       |    fruit
897       |        .onlyBananas(
898       |            fromTheVine = true,
899       |        )
900       |        .forEach { eat(it) }
901       |
902       |    // don't break in the inner lambda, as breaks don't propagate to parameters
903       |    fruit.onlyBananas(
904       |        fromTheVine = true,
905       |        processThem = { eat(it) },
906       |    ) {
907       |      eat(it)
908       |    }
909       |
910       |    // don't break in the inner lambda, as breaks don't propagate to the body
911       |    fruit.onlyBananas(
912       |        fromTheVine = true,
913       |    ) {
914       |      val anon = { eat(it) }
915       |    }
916       |  }
917       |}
918       |"""
919               .trimMargin(),
920           deduceMaxWidth = true)
921 
922   @Test
indent parameters after a break when there's a lambda afterwardsnull923   fun `indent parameters after a break when there's a lambda afterwards`() =
924       assertFormatted(
925           """
926       |///////////////////////////
927       |class C {
928       |  fun method() {
929       |    Foo.FooBar(
930       |            param1, param2)
931       |        .apply {
932       |          //
933       |          foo
934       |        }
935       |  }
936       |}
937       |"""
938               .trimMargin(),
939           deduceMaxWidth = true)
940 
941   @Test
no forward propagation of breaks in call expressions (at trailing lambda)null942   fun `no forward propagation of breaks in call expressions (at trailing lambda)`() =
943       assertFormatted(
944           """
945       |//////////////////////////
946       |fun test() {
947       |  foo_bar_baz__zip<A>(b) {
948       |    c
949       |  }
950       |  foo.bar(baz).zip<A>(b) {
951       |    c
952       |  }
953       |}
954       |"""
955               .trimMargin(),
956           deduceMaxWidth = true)
957 
958   @Test
forward propagation of breaks in call expressions (at value args)null959   fun `forward propagation of breaks in call expressions (at value args)`() =
960       assertFormatted(
961           """
962       |//////////////////////
963       |fun test() {
964       |  foo_bar_baz__zip<A>(
965       |      b) {
966       |        c
967       |      }
968       |}
969       |
970       |fun test() {
971       |  foo.bar(baz).zip<A>(
972       |      b) {
973       |        c
974       |      }
975       |}
976       |"""
977               .trimMargin(),
978           deduceMaxWidth = true)
979 
980   @Test
forward propagation of breaks in call expressions (at type args)null981   fun `forward propagation of breaks in call expressions (at type args)`() =
982       assertFormatted(
983           """
984       |///////////////////
985       |fun test() {
986       |  foo_bar_baz__zip<
987       |      A>(
988       |      b) {
989       |        c
990       |      }
991       |  foo.bar(baz).zip<
992       |      A>(
993       |      b) {
994       |        c
995       |      }
996       |}
997       |"""
998               .trimMargin(),
999           deduceMaxWidth = true)
1000 
1001   @Test
expected indent in methods following single-line stringsnull1002   fun `expected indent in methods following single-line strings`() =
1003       assertFormatted(
1004           """
1005       |/////////////////////////
1006       |"Hello %s"
1007       |    .format(expression)
1008       |"""
1009               .trimMargin(),
1010           deduceMaxWidth = true)
1011 
1012   @Test
1013   fun `forced break between multi-line strings and their selectors`() =
1014       assertFormatted(
1015           """
1016       |/////////////////////////
1017       |val STRING =
1018       |    $TQ
1019       |    |foo
1020       |    |$TQ
1021       |        .wouldFit()
1022       |
1023       |val STRING =
1024       |    $TQ
1025       |    |foo
1026       |    |//////////////////////////////////$TQ
1027       |        .wouldntFit()
1028       |
1029       |val STRING =
1030       |    $TQ
1031       |    |foo
1032       |    |$TQ
1033       |        .firstLink()
1034       |        .secondLink()
1035       |"""
1036               .trimMargin(),
1037           deduceMaxWidth = true)
1038 
1039   @Test
1040   fun `import list`() {
1041     val code =
1042         """
1043       | import  com .example.common.reality. FooBar
1044       |  import  com .example.common.reality. FooBar2  as  foosBars
1045       |   import com .example.common.reality. *
1046       | import  foo.bar // Test
1047       |  import  abc.def /*
1048       |                  test */
1049       |
1050       |val x = FooBar.def { foosBars(bar) }
1051       |"""
1052             .trimMargin()
1053     val expected =
1054         """
1055       |import abc.def /*
1056       |               test */
1057       |import com.example.common.reality.*
1058       |import com.example.common.reality.FooBar
1059       |import com.example.common.reality.FooBar2 as foosBars
1060       |import foo.bar // Test
1061       |
1062       |val x = FooBar.def { foosBars(bar) }
1063       |"""
1064             .trimMargin()
1065     assertThatFormatting(code).isEqualTo(expected)
1066   }
1067 
1068   @Test
imports with trailing comments and expressionsnull1069   fun `imports with trailing comments and expressions`() {
1070     val code =
1071         """
1072         |import com.example.zab // test
1073         |import com.example.foo ; val x = Sample(foo, zab)
1074         |"""
1075             .trimMargin()
1076 
1077     val expected =
1078         """
1079         |import com.example.foo
1080         |import com.example.zab // test
1081         |
1082         |val x = Sample(foo, zab)
1083         |"""
1084             .trimMargin()
1085 
1086     assertThatFormatting(code).isEqualTo(expected)
1087   }
1088 
1089   @Test
backticks are ignored in import sort ordernull1090   fun `backticks are ignored in import sort order`() =
1091       assertFormatted(
1092           """
1093       |import com.example.`if`
1094       |import com.example.we
1095       |import com.example.`when`
1096       |import com.example.wow
1097       |
1098       |val x = `if` { we.`when`(wow) }
1099       |"""
1100               .trimMargin())
1101 
1102   @Test
backticks are ignored in import sort order ('as' directory)null1103   fun `backticks are ignored in import sort order ('as' directory)`() =
1104       assertFormatted(
1105           """
1106       |import com.example.a as `if`
1107       |import com.example.a as we
1108       |import com.example.a as `when`
1109       |import com.example.a as wow
1110       |
1111       |val x = `if` { we.`when`(wow) }
1112       |"""
1113               .trimMargin())
1114 
1115   @Test
imports are deduplicatednull1116   fun `imports are deduplicated`() {
1117     val code =
1118         """
1119       |import com.example.b.*
1120       |import com.example.b
1121       |import com.example.a as `if`
1122       |import com.example.a as we
1123       |import com.example.a as `when`
1124       |import com.example.a as wow
1125       |import com.example.a as `when`
1126       |
1127       |val x = `if` { we.`when`(wow) } ?: b
1128       |"""
1129             .trimMargin()
1130     val expected =
1131         """
1132       |import com.example.a as `if`
1133       |import com.example.a as we
1134       |import com.example.a as `when`
1135       |import com.example.a as wow
1136       |import com.example.b
1137       |import com.example.b.*
1138       |
1139       |val x = `if` { we.`when`(wow) } ?: b
1140       |"""
1141             .trimMargin()
1142     assertThatFormatting(code).isEqualTo(expected)
1143   }
1144 
1145   @Test
unused imports are removednull1146   fun `unused imports are removed`() {
1147     val code =
1148         """
1149       |import com.unused.Sample
1150       |import com.used.FooBarBaz as Baz
1151       |import com.used.bar // test
1152       |import com.used.`class`
1153       |import com.used.a.*
1154       |import com.used.b as `if`
1155       |import com.used.b as we
1156       |import com.unused.a as `when`
1157       |import com.unused.a as wow
1158       |
1159       |fun test(input: we) {
1160       |  Baz(`class`)
1161       |  `if` { bar }
1162       |  val x = unused()
1163       |}
1164       |"""
1165             .trimMargin()
1166     val expected =
1167         """
1168       |import com.used.FooBarBaz as Baz
1169       |import com.used.a.*
1170       |import com.used.b as `if`
1171       |import com.used.b as we
1172       |import com.used.bar // test
1173       |import com.used.`class`
1174       |
1175       |fun test(input: we) {
1176       |  Baz(`class`)
1177       |  `if` { bar }
1178       |  val x = unused()
1179       |}
1180       |"""
1181             .trimMargin()
1182     assertThatFormatting(code).isEqualTo(expected)
1183   }
1184 
1185   @Test
used imports from this package are removednull1186   fun `used imports from this package are removed`() {
1187     val code =
1188         """
1189             |package com.example
1190             |
1191             |import com.example.Sample
1192             |import com.example.Sample.CONSTANT
1193             |import com.example.a.foo
1194             |
1195             |fun test() {
1196             |  foo(CONSTANT, Sample())
1197             |}
1198             |"""
1199             .trimMargin()
1200     val expected =
1201         """
1202             |package com.example
1203             |
1204             |import com.example.Sample.CONSTANT
1205             |import com.example.a.foo
1206             |
1207             |fun test() {
1208             |  foo(CONSTANT, Sample())
1209             |}
1210             |"""
1211             .trimMargin()
1212     assertThatFormatting(code).isEqualTo(expected)
1213   }
1214 
1215   @Test
potentially unused imports from this package are kept if they are overloadednull1216   fun `potentially unused imports from this package are kept if they are overloaded`() {
1217     val code =
1218         """
1219             |package com.example
1220             |
1221             |import com.example.a
1222             |import com.example.b
1223             |import com.example.c
1224             |import com.notexample.a
1225             |import com.notexample.b
1226             |import com.notexample.notC as c
1227             |
1228             |fun test() {
1229             |  a("hello")
1230             |  c("hello")
1231             |}
1232             |"""
1233             .trimMargin()
1234     val expected =
1235         """
1236             |package com.example
1237             |
1238             |import com.example.a
1239             |import com.example.c
1240             |import com.notexample.a
1241             |import com.notexample.notC as c
1242             |
1243             |fun test() {
1244             |  a("hello")
1245             |  c("hello")
1246             |}
1247             |"""
1248             .trimMargin()
1249     assertThatFormatting(code).isEqualTo(expected)
1250   }
1251 
1252   @Test
used imports from this package are kept if they are aliasednull1253   fun `used imports from this package are kept if they are aliased`() {
1254     val code =
1255         """
1256             |package com.example
1257             |
1258             |import com.example.b as a
1259             |import com.example.c
1260             |
1261             |fun test() {
1262             |  a("hello")
1263             |}
1264             |"""
1265             .trimMargin()
1266     val expected =
1267         """
1268             |package com.example
1269             |
1270             |import com.example.b as a
1271             |
1272             |fun test() {
1273             |  a("hello")
1274             |}
1275             |"""
1276             .trimMargin()
1277     assertThatFormatting(code).isEqualTo(expected)
1278   }
1279 
1280   @Test
unused imports are computed using only the alias name if presentnull1281   fun `unused imports are computed using only the alias name if present`() {
1282     val code =
1283         """
1284             |package com.example
1285             |
1286             |import com.notexample.a as b
1287             |
1288             |fun test() {
1289             |  a("hello")
1290             |}
1291             |"""
1292             .trimMargin()
1293     val expected =
1294         """
1295             |package com.example
1296             |
1297             |fun test() {
1298             |  a("hello")
1299             |}
1300             |"""
1301             .trimMargin()
1302     assertThatFormatting(code).isEqualTo(expected)
1303   }
1304 
1305   @Test
keep import elements only mentioned in kdocnull1306   fun `keep import elements only mentioned in kdoc`() {
1307     val code =
1308         """
1309             |package com.example.kdoc
1310             |
1311             |import com.example.Bar
1312             |import com.example.Example
1313             |import com.example.Foo
1314             |import com.example.JavaDocLink
1315             |import com.example.Param
1316             |import com.example.R
1317             |import com.example.ReturnedValue
1318             |import com.example.Sample
1319             |import com.example.unused
1320             |import com.example.exception.AnException
1321             |import com.example.kdoc.Doc
1322             |
1323             |/**
1324             | * [Foo] is something only mentioned here, just like [R.layout.test] and [Doc].
1325             | *
1326             | * Old {@link JavaDocLink} that gets removed.
1327             | *
1328             | * @throws AnException
1329             | * @exception Sample.SampleException
1330             | * @param unused [Param]
1331             | * @property JavaDocLink [Param]
1332             | * @return [Unit] as [ReturnedValue]
1333             | * @sample Example
1334             | * @see Bar for more info
1335             | * @throws AnException
1336             | */
1337             |class Dummy
1338             |"""
1339             .trimMargin()
1340     val expected =
1341         """
1342             |package com.example.kdoc
1343             |
1344             |import com.example.Bar
1345             |import com.example.Example
1346             |import com.example.Foo
1347             |import com.example.Param
1348             |import com.example.R
1349             |import com.example.ReturnedValue
1350             |import com.example.Sample
1351             |import com.example.exception.AnException
1352             |
1353             |/**
1354             | * [Foo] is something only mentioned here, just like [R.layout.test] and [Doc].
1355             | *
1356             | * Old {@link JavaDocLink} that gets removed.
1357             | *
1358             | * @param unused [Param]
1359             | * @property JavaDocLink [Param]
1360             | * @return [Unit] as [ReturnedValue]
1361             | * @throws AnException
1362             | * @throws AnException
1363             | * @exception Sample.SampleException
1364             | * @sample Example
1365             | * @see Bar for more info
1366             | */
1367             |class Dummy
1368             |"""
1369             .trimMargin()
1370     assertThatFormatting(code).isEqualTo(expected)
1371   }
1372 
1373   @Test
1374   fun `keep import elements only mentioned in kdoc, single line`() {
1375     assertFormatted(
1376         """
1377             |import com.shopping.Bag
1378             |
1379             |/**
1380             | * Some summary.
1381             | *
1382             | * @param count you can fit this many in a [Bag]
1383             | */
1384             |fun fetchBananas(count: Int)
1385             |"""
1386             .trimMargin())
1387   }
1388 
1389   @Test
1390   fun `keep import elements only mentioned in kdoc, multiline`() {
1391     assertFormatted(
1392         """
1393             |import com.shopping.Bag
1394             |
1395             |/**
1396             | * Some summary.
1397             | *
1398             | * @param count this is how many of these wonderful fruit you can fit into the useful object that
1399             | *   you may refer to as a [Bag]
1400             | */
1401             |fun fetchBananas(count: Int)
1402             |"""
1403             .trimMargin())
1404   }
1405 
1406   @Test
1407   fun `keep component imports`() =
1408       assertFormatted(
1409           """
1410               |import com.example.component1
1411               |import com.example.component10
1412               |import com.example.component120
1413               |import com.example.component2
1414               |import com.example.component3
1415               |import com.example.component4
1416               |import com.example.component5
1417               |"""
1418               .trimMargin())
1419 
1420   @Test
1421   fun `keep operator imports`() =
1422       assertFormatted(
1423           """
1424               |import com.example.and
1425               |import com.example.compareTo
1426               |import com.example.contains
1427               |import com.example.dec
1428               |import com.example.div
1429               |import com.example.divAssign
1430               |import com.example.equals
1431               |import com.example.get
1432               |import com.example.getValue
1433               |import com.example.hasNext
1434               |import com.example.inc
1435               |import com.example.invoke
1436               |import com.example.iterator
1437               |import com.example.minus
1438               |import com.example.minusAssign
1439               |import com.example.mod
1440               |import com.example.modAssign
1441               |import com.example.next
1442               |import com.example.not
1443               |import com.example.or
1444               |import com.example.plus
1445               |import com.example.plusAssign
1446               |import com.example.provideDelegate
1447               |import com.example.rangeTo
1448               |import com.example.rem
1449               |import com.example.remAssign
1450               |import com.example.set
1451               |import com.example.setValue
1452               |import com.example.times
1453               |import com.example.timesAssign
1454               |import com.example.unaryMinus
1455               |import com.example.unaryPlus
1456               |import org.gradle.kotlin.dsl.assign
1457               |"""
1458               .trimMargin())
1459 
1460   @Test
1461   fun `keep unused imports when formatting options has feature turned off`() {
1462     val code =
1463         """
1464             |import com.unused.FooBarBaz as Baz
1465             |import com.unused.Sample
1466             |import com.unused.a as `when`
1467             |import com.unused.a as wow
1468             |import com.unused.a.*
1469             |import com.unused.b as `if`
1470             |import com.unused.b as we
1471             |import com.unused.bar // test
1472             |import com.unused.`class`
1473             |"""
1474             .trimMargin()
1475 
1476     assertThatFormatting(code)
1477         .withOptions(defaultTestFormattingOptions.copy(removeUnusedImports = false))
1478         .isEqualTo(code)
1479   }
1480 
1481   @Test
1482   fun `comments between imports are moved above import list`() {
1483     val code =
1484         """
1485             |package com.facebook.ktfmt
1486             |
1487             |/* leading comment */
1488             |import com.example.abc
1489             |/* internal comment 1 */
1490             |import com.example.bcd
1491             |// internal comment 2
1492             |import com.example.Sample
1493             |// trailing comment
1494             |
1495             |val x = Sample(abc, bcd)
1496             |"""
1497             .trimMargin()
1498     val expected =
1499         """
1500             |package com.facebook.ktfmt
1501             |
1502             |/* leading comment */
1503             |/* internal comment 1 */
1504             |// internal comment 2
1505             |import com.example.Sample
1506             |import com.example.abc
1507             |import com.example.bcd
1508             |
1509             |// trailing comment
1510             |
1511             |val x = Sample(abc, bcd)
1512             |"""
1513             .trimMargin()
1514     assertThatFormatting(code).isEqualTo(expected)
1515   }
1516 
1517   @Test
1518   fun `no redundant newlines when there are no imports`() =
1519       assertFormatted(
1520           """
1521               |package foo123
1522               |
1523               |/*
1524               |bar
1525               |*/
1526               |"""
1527               .trimMargin())
1528 
1529   @Test
1530   fun `basic annotations`() =
1531       assertFormatted(
1532           """
1533       |@Fancy
1534       |class Foo {
1535       |  @Fancy
1536       |  fun baz(@Fancy foo: Int) {
1537       |    @Fancy val a = 1 + foo
1538       |  }
1539       |}
1540       |"""
1541               .trimMargin())
1542 
1543   @Test
function calls with multiple argumentsnull1544   fun `function calls with multiple arguments`() =
1545       assertFormatted(
1546           """
1547       |fun f() {
1548       |  foo(1, 2, 3)
1549       |
1550       |  foo(
1551       |      123456789012345678901234567890,
1552       |      123456789012345678901234567890,
1553       |      123456789012345678901234567890)
1554       |}
1555       |"""
1556               .trimMargin())
1557 
1558   @Test
function calls with multiple named argumentsnull1559   fun `function calls with multiple named arguments`() =
1560       assertFormatted(
1561           """
1562       |fun f() {
1563       |  foo(1, b = 2, c = 3)
1564       |
1565       |  foo(
1566       |      123456789012345678901234567890,
1567       |      b = 23456789012345678901234567890,
1568       |      c = 3456789012345678901234567890)
1569       |}
1570       |"""
1571               .trimMargin())
1572 
1573   @Test
named arguments indent their value expressionnull1574   fun `named arguments indent their value expression`() =
1575       assertFormatted(
1576           """
1577       |fun f() =
1578       |    Bar(
1579       |        tokens =
1580       |            mutableListOf<Token>().apply {
1581       |              // Printing
1582       |              print()
1583       |            },
1584       |        duration = duration)
1585       |"""
1586               .trimMargin())
1587 
1588   @Test
Trailing comma forces variable value in list onto new line with manageTrailingCommas turned offnull1589   fun `Trailing comma forces variable value in list onto new line with manageTrailingCommas turned off`() =
1590       assertFormatted(
1591           """
1592             val aVar =
1593                 setOf(
1594                     Env.Dev,
1595                     Env.Prod,
1596                 )
1597             val aVar = setOf(Env.Dev, Env.Prod)
1598 
1599             """
1600               .trimIndent(),
1601           deduceMaxWidth = false,
1602       )
1603 
1604   @Test
1605   fun `nested functions, maps, and statements in named parameters - default`() =
1606       assertFormatted(
1607           """
1608             |////////////////////////////////////////////////////////////////////
1609             |function(
1610             |    param =
1611             |        (rate downTo min step step).drop(1).map {
1612             |          nestedFun(
1613             |              rate =
1614             |                  rate(
1615             |                      value =
1616             |                          firstArg<Input>().info.get(0).rate.value))
1617             |        })
1618             |"""
1619               .trimMargin(),
1620           deduceMaxWidth = true,
1621       )
1622 
1623   @Test
nested functions, maps, and statements in named parameters kotlin lang formats differently than defaultnull1624   fun `nested functions, maps, and statements in named parameters kotlin lang formats differently than default`() =
1625       assertFormatted(
1626           """
1627             |/////////////////////////////////////////////////////////////////////
1628             |function(
1629             |    param =
1630             |        (rate downTo min step step).drop(1).map {
1631             |            nestedFun(
1632             |                rate =
1633             |                    rate(
1634             |                        value =
1635             |                            firstArg<Input>().info.get(0).rate.value
1636             |                    )
1637             |            )
1638             |        }
1639             |)
1640             |"""
1641               .trimMargin(),
1642           formattingOptions = Formatter.KOTLINLANG_FORMAT,
1643           deduceMaxWidth = true,
1644       )
1645 
1646   @Test
complex calls and calculation in named parameters without wrappingnull1647   fun `complex calls and calculation in named parameters without wrapping`() =
1648       assertFormatted(
1649           """
1650             calculateMath(
1651                 r = apr.sc(10) / BigDecimal(100) / BigDecimal(12),
1652                 n = 12 * term,
1653                 numerator = ((BigDecimal.ONE + r).pow(n)) - BigDecimal.ONE,
1654                 denominator = r * (BigDecimal.ONE + r).pow(n),
1655             )
1656 
1657             """
1658               .trimIndent(),
1659           deduceMaxWidth = false,
1660       )
1661 
1662   @Test
1663   fun `Arguments are blocks`() =
1664       assertFormatted(
1665           """
1666       |//////////////////////////////////////////////////
1667       |override fun visitProperty(property: KtProperty) {
1668       |  builder.sync(property)
1669       |  builder.block(ZERO) {
1670       |    declareOne(
1671       |        kind = DeclarationKind.FIELD,
1672       |        modifiers = property.modifierList,
1673       |        valOrVarKeyword =
1674       |            property.valOrVarKeyword.text,
1675       |        typeParameters =
1676       |            property.typeParameterList,
1677       |        receiver = property.receiverTypeReference,
1678       |        name = property.nameIdentifier?.text,
1679       |        type = property.typeReference,
1680       |        typeConstraintList =
1681       |            property.typeConstraintList,
1682       |        delegate = property.delegate,
1683       |        initializer = property.initializer)
1684       |  }
1685       |}
1686       |"""
1687               .trimMargin(),
1688           deduceMaxWidth = true)
1689 
1690   @Test
anonymous functionnull1691   fun `anonymous function`() =
1692       assertFormatted(
1693           """
1694       |fun f() {
1695       |  setListener(
1696       |      fun(number: Int) {
1697       |        println(number)
1698       |      })
1699       |}
1700       |"""
1701               .trimMargin())
1702 
1703   @Test
anonymous function with receivernull1704   fun `anonymous function with receiver`() =
1705       assertFormatted(
1706           """
1707       |fun f() {
1708       |  setListener(
1709       |      fun View.() {
1710       |        println(this)
1711       |      })
1712       |}
1713       |"""
1714               .trimMargin())
1715 
1716   @Test
newlines between clauses of when() are preservednull1717   fun `newlines between clauses of when() are preserved`() {
1718     assertThatFormatting(
1719             """
1720         |fun f(x: Int) {
1721         |  when (x) {
1722         |
1723         |
1724         |    1 -> print(1)
1725         |    2 -> print(2)
1726         |
1727         |
1728         |    3 ->
1729         |        // Comment
1730         |        print(3)
1731         |
1732         |    else -> {
1733         |      print("else")
1734         |    }
1735         |
1736         |  }
1737         |}
1738         |"""
1739                 .trimMargin())
1740         .isEqualTo(
1741             """
1742         |fun f(x: Int) {
1743         |  when (x) {
1744         |    1 -> print(1)
1745         |    2 -> print(2)
1746         |
1747         |    3 ->
1748         |        // Comment
1749         |        print(3)
1750         |
1751         |    else -> {
1752         |      print("else")
1753         |    }
1754         |  }
1755         |}
1756         |"""
1757                 .trimMargin())
1758   }
1759 
1760   @Test
when() with a subject expressionnull1761   fun `when() with a subject expression`() =
1762       assertFormatted(
1763           """
1764       |fun f(x: Int) {
1765       |  when (x) {
1766       |    1 -> print(1)
1767       |    2 -> print(2)
1768       |    3 ->
1769       |        // Comment
1770       |        print(3)
1771       |    else -> {
1772       |      print("else")
1773       |    }
1774       |  }
1775       |}
1776       |"""
1777               .trimMargin())
1778 
1779   @Test
when() expression with complex predicatesnull1780   fun `when() expression with complex predicates`() =
1781       assertFormatted(
1782           """
1783       |fun f(x: Int) {
1784       |  when {
1785       |    x == 1 || x == 2 -> print(1)
1786       |    x == 3 && x != 4 -> print(2)
1787       |    else -> {
1788       |      print(3)
1789       |    }
1790       |  }
1791       |}
1792       |"""
1793               .trimMargin())
1794 
1795   @Test
when() expression with several conditionsnull1796   fun `when() expression with several conditions`() =
1797       assertFormatted(
1798           """
1799       |fun f(x: Int) {
1800       |  when {
1801       |    0,
1802       |    1 -> print(1)
1803       |    else -> print(0)
1804       |  }
1805       |}
1806       |"""
1807               .trimMargin())
1808 
1809   @Test
when() expression with is and innull1810   fun `when() expression with is and in`() =
1811       assertFormatted(
1812           """
1813       |fun f(x: Int) {
1814       |  when (x) {
1815       |    is String -> print(1)
1816       |    !is String -> print(2)
1817       |    in 1..3 -> print()
1818       |    in a..b -> print()
1819       |    in a..3 -> print()
1820       |    in 1..b -> print()
1821       |    !in 1..b -> print()
1822       |    in 1..<b -> print()
1823       |    else -> print(3)
1824       |  }
1825       |}
1826       |"""
1827               .trimMargin())
1828 
1829   @Test
when() expression with enum valuesnull1830   fun `when() expression with enum values`() =
1831       assertFormatted(
1832           """
1833       |fun f(x: Color) {
1834       |  when (x) {
1835       |    is Color.Red -> print(1)
1836       |    is Color.Green -> print(2)
1837       |    else -> print(3)
1838       |  }
1839       |}
1840       |"""
1841               .trimMargin())
1842 
1843   @Test
when() expression with generic matcher and exhaustivenull1844   fun `when() expression with generic matcher and exhaustive`() =
1845       assertFormatted(
1846           """
1847       |fun f(x: Result) {
1848       |  when (x) {
1849       |    is Success<*> -> print(1)
1850       |    is Failure -> print(2)
1851       |  }.exhaustive
1852       |}
1853       |"""
1854               .trimMargin())
1855 
1856   @Test
when() expression with multiline conditionnull1857   fun `when() expression with multiline condition`() =
1858       assertFormatted(
1859           """
1860       |//////////////////////////
1861       |fun foo() {
1862       |  when (expressions1 +
1863       |      expression2 +
1864       |      expression3) {
1865       |    1 -> print(1)
1866       |    2 -> print(2)
1867       |  }
1868       |
1869       |  when (foo(
1870       |      expressions1 &&
1871       |          expression2 &&
1872       |          expression3)) {
1873       |    1 -> print(1)
1874       |    2 -> print(2)
1875       |  }
1876       |}
1877       |"""
1878               .trimMargin(),
1879           deduceMaxWidth = true)
1880 
1881   @Test
lambda assigned to variable does not break before bracenull1882   fun `lambda assigned to variable does not break before brace`() =
1883       assertFormatted(
1884           """
1885       |fun doIt() {
1886       |  val lambda = {
1887       |    doItOnce()
1888       |    doItTwice()
1889       |  }
1890       |}
1891       |
1892       |fun foo() = {
1893       |  doItOnce()
1894       |  doItTwice()
1895       |}
1896       |"""
1897               .trimMargin())
1898 
1899   @Test
when() expression storing in local variablenull1900   fun `when() expression storing in local variable`() =
1901       assertFormatted(
1902           """
1903       |fun f(x: Result) {
1904       |  when (val y = x.improved()) {
1905       |    is Success<*> -> print(y)
1906       |    is Failure -> print(2)
1907       |  }
1908       |}
1909       |"""
1910               .trimMargin())
1911 
1912   @Test
line breaks inside when expressions and conditionsnull1913   fun `line breaks inside when expressions and conditions`() =
1914       assertFormatted(
1915           """
1916       |fun f() {
1917       |  return Text.create(c)
1918       |      .onTouch {
1919       |        when (it.motionEvent.action) {
1920       |          ACTION_DOWN ->
1921       |              Toast.makeText(it.view.context, "Down!", Toast.LENGTH_SHORT, blablabla).show()
1922       |          ACTION_UP -> Toast.makeText(it.view.context, "Up!", Toast.LENGTH_SHORT).show()
1923       |          ACTION_DOWN ->
1924       |              Toast.makeText(
1925       |                      it.view.context, "Down!", Toast.LENGTH_SHORT, blablabla, blablabl, blabla)
1926       |                  .show()
1927       |        }
1928       |      }
1929       |      .build()
1930       |}
1931       |"""
1932               .trimMargin())
1933 
1934   @Test
function return typesnull1935   fun `function return types`() =
1936       assertFormatted(
1937           """
1938       |fun f1(): Int = 0
1939       |
1940       |fun f2(): Int {}
1941       |"""
1942               .trimMargin())
1943 
1944   @Test
multi line function without a block bodynull1945   fun `multi line function without a block body`() =
1946       assertFormatted(
1947           """
1948       |/////////////////////////
1949       |fun longFunctionNoBlock():
1950       |    Int =
1951       |    1234567 + 1234567
1952       |
1953       |fun shortFun(): Int =
1954       |    1234567 + 1234567
1955       |"""
1956               .trimMargin(),
1957           deduceMaxWidth = true)
1958 
1959   @Test
1960   fun `return type doesn't fit in one line`() =
1961       assertFormatted(
1962           """
1963       |//////////////////////////////////////////////////
1964       |interface X {
1965       |  fun f(
1966       |      arg1: Arg1Type,
1967       |      arg2: Arg2Type
1968       |  ): Map<String, Map<String, Double>>? {
1969       |    //
1970       |  }
1971       |
1972       |  fun functionWithGenericReturnType(
1973       |      arg1: Arg1Type,
1974       |      arg2: Arg2Type
1975       |  ): Map<String, Map<String, Double>>? {
1976       |    //
1977       |  }
1978       |}
1979       |"""
1980               .trimMargin(),
1981           deduceMaxWidth = true)
1982 
1983   @Test
list of superclassesnull1984   fun `list of superclasses`() =
1985       assertFormatted(
1986           """
1987       |class Derived2 : Super1, Super2 {}
1988       |
1989       |class Derived1 : Super1, Super2
1990       |
1991       |class Derived3(a: Int) : Super1(a)
1992       |
1993       |class Derived4 : Super1()
1994       |
1995       |class Derived5 : Super3<Int>()
1996       |"""
1997               .trimMargin())
1998 
1999   @Test
list of superclasses over multiple linesnull2000   fun `list of superclasses over multiple lines`() =
2001       assertFormatted(
2002           """
2003       |////////////////////
2004       |class Derived2 :
2005       |    Super1,
2006       |    Super2 {}
2007       |
2008       |class Derived1 :
2009       |    Super1, Super2
2010       |
2011       |class Derived3(
2012       |    a: Int
2013       |) : Super1(a)
2014       |
2015       |class Derived4 :
2016       |    Super1()
2017       |
2018       |class Derived5 :
2019       |    Super3<Int>()
2020       |"""
2021               .trimMargin(),
2022           deduceMaxWidth = true)
2023 
2024   @Test
annotations with parametersnull2025   fun `annotations with parameters`() =
2026       assertFormatted(
2027           """
2028       |@AnnWithArrayValue(1, 2, 3) class C
2029       |"""
2030               .trimMargin())
2031 
2032   @Test
2033   fun `method modifiers`() =
2034       assertFormatted(
2035           """
2036       |override internal fun f() {}
2037       |"""
2038               .trimMargin())
2039 
2040   @Test
class modifiersnull2041   fun `class modifiers`() =
2042       assertFormatted(
2043           """
2044       |abstract class Foo
2045       |
2046       |inner class Foo
2047       |
2048       |final class Foo
2049       |
2050       |open class Foo
2051       |"""
2052               .trimMargin())
2053 
2054   @Test
2055   fun `kdoc comments`() {
2056     val code =
2057         """
2058       |/**
2059       | * foo
2060       | */ class F {
2061       |
2062       | }
2063       |"""
2064             .trimMargin()
2065     val expected =
2066         """
2067       |/** foo */
2068       |class F {}
2069       |"""
2070             .trimMargin()
2071     assertThatFormatting(code).isEqualTo(expected)
2072   }
2073 
2074   @Test
nested kdoc commentsnull2075   fun `nested kdoc comments`() {
2076     val code =
2077         """
2078       |/**
2079       | * foo /* bla */
2080       | */ class F {
2081       |
2082       | }
2083       |"""
2084             .trimMargin()
2085     val expected =
2086         """
2087       |/** foo /* bla */ */
2088       |class F {}
2089       |"""
2090             .trimMargin()
2091     assertThatFormatting(code).isEqualTo(expected)
2092   }
2093 
2094   @Test
nested kdoc inside code blocknull2095   fun `nested kdoc inside code block`() =
2096       assertFormatted(
2097           """
2098       |/**
2099       | * ```
2100       | * edit -> { /* open edit screen */ }
2101       | * ```
2102       | */
2103       |fun foo() {}
2104       |"""
2105               .trimMargin())
2106 
2107   @Test
formatting kdoc doesn't add p HTML tagsnull2108   fun `formatting kdoc doesn't add p HTML tags`() =
2109       assertFormatted(
2110           """
2111       |/**
2112       | * Bla bla bla bla
2113       | *
2114       | * This is an inferred paragraph, and as you can see, we don't add a p tag to it, even though bla
2115       | * bla.
2116       | *
2117       | * <p>On the other hand, we respect existing tags, and don't remove them.
2118       | */
2119       |"""
2120               .trimMargin())
2121 
2122   @Test
2123   fun `formatting kdoc preserves lists`() =
2124       assertFormatted(
2125           """
2126       |/**
2127       | * Here are some fruit I like:
2128       | * - Banana
2129       | * - Apple
2130       | *
2131       | * This is another paragraph
2132       | */
2133       |"""
2134               .trimMargin())
2135 
2136   @Test
2137   fun `formatting kdoc lists with line wraps breaks and merges correctly`() {
2138     val code =
2139         """
2140       |/**
2141       | * Here are some fruit I like:
2142       | * - Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana
2143       | * - Apple Apple Apple Apple
2144       | *   Apple Apple
2145       | *
2146       | * This is another paragraph
2147       | */
2148       |"""
2149             .trimMargin()
2150     val expected =
2151         """
2152       |/**
2153       | * Here are some fruit I like:
2154       | * - Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana
2155       | *   Banana Banana Banana Banana Banana
2156       | * - Apple Apple Apple Apple Apple Apple
2157       | *
2158       | * This is another paragraph
2159       | */
2160       |"""
2161             .trimMargin()
2162     assertThatFormatting(code).isEqualTo(expected)
2163   }
2164 
2165   @Test
2166   fun `formatting kdoc preserves lists of asterisks`() =
2167       assertFormatted(
2168           """
2169       |/**
2170       | * Here are some fruit I like:
2171       | * * Banana
2172       | * * Apple
2173       | *
2174       | * This is another paragraph
2175       | */
2176       |"""
2177               .trimMargin())
2178 
2179   @Test
2180   fun `formatting kdoc preserves numbered`() =
2181       assertFormatted(
2182           """
2183       |/**
2184       | * Here are some fruit I like:
2185       | * 1. Banana
2186       | * 2. Apple
2187       | *
2188       | * This is another paragraph
2189       | */
2190       |"""
2191               .trimMargin())
2192 
2193   @Test
2194   fun `formatting kdoc with markdown errors`() =
2195       assertFormatted(
2196           """
2197       |/** \[ */
2198       |fun markdownError() = Unit
2199       |"""
2200               .trimMargin())
2201 
2202   @Test
2203   fun `return statement with value`() =
2204       assertFormatted(
2205           """
2206       |fun random(): Int {
2207       |  return 4
2208       |}
2209       |"""
2210               .trimMargin())
2211 
2212   @Test
return statement without valuenull2213   fun `return statement without value`() =
2214       assertFormatted(
2215           """
2216       |fun print(b: Boolean) {
2217       |  print(b)
2218       |  return
2219       |}
2220       |"""
2221               .trimMargin())
2222 
2223   @Test
return expression without valuenull2224   fun `return expression without value`() =
2225       assertFormatted(
2226           """
2227       |fun print(b: Boolean?) {
2228       |  print(b ?: return)
2229       |}
2230       |"""
2231               .trimMargin())
2232 
2233   @Test
if statement without elsenull2234   fun `if statement without else`() =
2235       assertFormatted(
2236           """
2237       |fun maybePrint(b: Boolean) {
2238       |  if (b) {
2239       |    println(b)
2240       |  }
2241       |}
2242       |"""
2243               .trimMargin())
2244 
2245   @Test
if statement with elsenull2246   fun `if statement with else`() =
2247       assertFormatted(
2248           """
2249       |fun maybePrint(b: Boolean) {
2250       |  if (b) {
2251       |    println(2)
2252       |  } else {
2253       |    println(1)
2254       |  }
2255       |}
2256       |"""
2257               .trimMargin())
2258 
2259   @Test
if expression with elsenull2260   fun `if expression with else`() =
2261       assertFormatted(
2262           """
2263       |fun maybePrint(b: Boolean) {
2264       |  println(if (b) 1 else 2)
2265       |  println(
2266       |      if (b) {
2267       |        val a = 1 + 1
2268       |        2 * a
2269       |      } else 2)
2270       |  return if (b) 1 else 2
2271       |}
2272       |"""
2273               .trimMargin())
2274 
2275   @Test
if expression with break before elsenull2276   fun `if expression with break before else`() =
2277       assertFormatted(
2278           """
2279       |//////////////////////////////
2280       |fun compute(b: Boolean) {
2281       |  val c =
2282       |      if (a + b < 20) a + b
2283       |      else a
2284       |  return if (a + b < 20) a + b
2285       |  else c
2286       |}
2287       |"""
2288               .trimMargin(),
2289           deduceMaxWidth = true)
2290 
2291   @Test
if expression with break before expressionsnull2292   fun `if expression with break before expressions`() =
2293       assertFormatted(
2294           """
2295       |//////////////////////////
2296       |fun compute(b: Boolean) {
2297       |  val c =
2298       |      if (a + b < 20)
2299       |          a + b
2300       |      else if (a < 20) a
2301       |      else
2302       |          a + b + b + 1000
2303       |  return if (a + b < 20)
2304       |      a + b
2305       |  else c
2306       |}
2307       |"""
2308               .trimMargin(),
2309           deduceMaxWidth = true)
2310 
2311   @Test
blocky expressions in if-elsenull2312   fun `blocky expressions in if-else`() =
2313       assertFormatted(
2314           """
2315       |fun numbers() {
2316       |  if (true)
2317       |      do {
2318       |        eat("is")
2319       |        matches += type()
2320       |      } while (eat(","))
2321       |  else
2322       |      while (1 < 2) {
2323       |        println("Everything is okay")
2324       |      }
2325       |}
2326       |"""
2327               .trimMargin())
2328 
2329   @Test
if expression with multiline conditionnull2330   fun `if expression with multiline condition`() =
2331       assertFormatted(
2332           """
2333       |////////////////////////////
2334       |fun foo() {
2335       |  if (expressions1 &&
2336       |      expression2 &&
2337       |      expression3) {
2338       |    bar()
2339       |  }
2340       |
2341       |  if (foo(
2342       |      expressions1 &&
2343       |          expression2 &&
2344       |          expression3)) {
2345       |    bar()
2346       |  }
2347       |}
2348       |"""
2349               .trimMargin(),
2350           deduceMaxWidth = true)
2351 
2352   @Test
assignment expression on multiple linesnull2353   fun `assignment expression on multiple lines`() =
2354       assertFormatted(
2355           """
2356       |//////////////////////////////////////////////////
2357       |fun f() {
2358       |  var myVariable = 5
2359       |  myVariable =
2360       |      function1(4, 60, 8) + function2(57, 39, 20)
2361       |}
2362       |"""
2363               .trimMargin(),
2364           deduceMaxWidth = true)
2365 
2366   @Test
A program that tickled a bug in KotlinInputnull2367   fun `A program that tickled a bug in KotlinInput`() =
2368       assertFormatted(
2369           """
2370       |val x = 2
2371       |"""
2372               .trimMargin())
2373 
2374   @Test
2375   fun `a few variations of constructors`() =
2376       assertFormatted(
2377           """
2378       |//////////////////////////////////////////////////////
2379       |class Foo constructor(number: Int) {}
2380       |
2381       |class Foo2 private constructor(number: Int) {}
2382       |
2383       |class Foo3 @Inject constructor(number: Int) {}
2384       |
2385       |class Foo4 @Inject private constructor(number: Int) {}
2386       |
2387       |class Foo5
2388       |@Inject
2389       |private constructor(
2390       |    number: Int,
2391       |    number2: Int,
2392       |    number3: Int,
2393       |    number4: Int,
2394       |    number5: Int,
2395       |    number6: Int
2396       |) {}
2397       |
2398       |class Foo6
2399       |@Inject
2400       |private constructor(hasSpaceForAnnos: Innnt) {
2401       |  //                                           @Inject
2402       |}
2403       |
2404       |class FooTooLongForCtorAndSupertypes
2405       |@Inject
2406       |private constructor(x: Int) : NoooooooSpaceForAnnos {}
2407       |"""
2408               .trimMargin(),
2409           deduceMaxWidth = true)
2410 
2411   @Test
a primary constructor without a class bodynull2412   fun `a primary constructor without a class body `() =
2413       assertFormatted(
2414           """
2415       |/////////////////////////
2416       |data class Foo(
2417       |    val number: Int = 0
2418       |)
2419       |"""
2420               .trimMargin(),
2421           deduceMaxWidth = true)
2422 
2423   @Test
2424   fun `a secondary constructor without a body`() =
2425       assertFormatted(
2426           """
2427       |///////////////////////////
2428       |data class Foo {
2429       |  constructor(
2430       |      val number: Int = 0
2431       |  )
2432       |}
2433       |"""
2434               .trimMargin(),
2435           deduceMaxWidth = true)
2436 
2437   @Test
a secondary constructor with a body breaks before closing parenthesisnull2438   fun `a secondary constructor with a body breaks before closing parenthesis`() =
2439       assertFormatted(
2440           """
2441       |///////////////////////////
2442       |data class Foo {
2443       |  constructor(
2444       |      val number: Int = 0
2445       |  ) {}
2446       |}
2447       |"""
2448               .trimMargin(),
2449           deduceMaxWidth = true)
2450 
2451   @Test
a constructor with many arguments over breaking to next linenull2452   fun `a constructor with many arguments over breaking to next line`() =
2453       assertFormatted(
2454           """
2455       |data class Foo(
2456       |    val number: Int,
2457       |    val name: String,
2458       |    val age: Int,
2459       |    val title: String,
2460       |    val offspring2: List<Foo>
2461       |) {}
2462       |"""
2463               .trimMargin())
2464 
2465   @Test
a constructor with keyword and many arguments over breaking to next linenull2466   fun `a constructor with keyword and many arguments over breaking to next line`() =
2467       assertFormatted(
2468           """
2469       |data class Foo
2470       |constructor(
2471       |    val name: String,
2472       |    val age: Int,
2473       |    val title: String,
2474       |    val offspring: List<Foo>,
2475       |    val foo: String
2476       |) {}
2477       |"""
2478               .trimMargin())
2479 
2480   @Test
a constructor with many arguments over multiple linesnull2481   fun `a constructor with many arguments over multiple lines`() =
2482       assertFormatted(
2483           """
2484       |//////////////////////////////////////////////////
2485       |data class Foo
2486       |constructor(
2487       |    val number: Int,
2488       |    val name: String,
2489       |    val age: Int,
2490       |    val title: String,
2491       |    val offspring: List<Foo>
2492       |) {}
2493       |"""
2494               .trimMargin(),
2495           deduceMaxWidth = true)
2496 
2497   @Test
handle secondary constructorsnull2498   fun `handle secondary constructors`() =
2499       assertFormatted(
2500           """
2501       |class Foo private constructor(number: Int) {
2502       |  private constructor(n: Float) : this(1)
2503       |
2504       |  private constructor(n: Double) : this(1) {
2505       |    println("built")
2506       |  }
2507       |}
2508       |"""
2509               .trimMargin())
2510 
2511   @Test
a secondary constructor with many arguments over multiple linesnull2512   fun `a secondary constructor with many arguments over multiple lines`() =
2513       assertFormatted(
2514           """
2515       |//////////////////////////////////////////////////
2516       |data class Foo {
2517       |  constructor(
2518       |      val number: Int,
2519       |      val name: String,
2520       |      val age: Int,
2521       |      val title: String,
2522       |      val offspring: List<Foo>
2523       |  )
2524       |}
2525       |"""
2526               .trimMargin(),
2527           deduceMaxWidth = true)
2528 
2529   @Test
a secondary constructor with many arguments passed to delegatenull2530   fun `a secondary constructor with many arguments passed to delegate`() =
2531       assertFormatted(
2532           """
2533       |//////////////////////////////////////////////////
2534       |data class Foo {
2535       |  constructor(
2536       |      val number: Int,
2537       |      val name: String,
2538       |      val age: Int,
2539       |      val title: String,
2540       |      val offspring: List<Foo>
2541       |  ) : this(
2542       |      number,
2543       |      name,
2544       |      age,
2545       |      title,
2546       |      offspring,
2547       |      offspring)
2548       |}
2549       |"""
2550               .trimMargin(),
2551           deduceMaxWidth = true)
2552 
2553   @Test
a secondary constructor with no arguments passed to delegatenull2554   fun `a secondary constructor with no arguments passed to delegate`() =
2555       assertFormatted(
2556           """
2557       |//////////////////////////////////////////////////
2558       |data class Foo {
2559       |  constructor() :
2560       |      this(
2561       |          Foo.createSpeciallyDesignedParameter(),
2562       |          Foo.createSpeciallyDesignedParameter(),
2563       |      )
2564       |}
2565       |"""
2566               .trimMargin(),
2567           deduceMaxWidth = true)
2568 
2569   @Test
secondary constructor with param list that fits in one line, with delegatenull2570   fun `secondary constructor with param list that fits in one line, with delegate`() =
2571       assertFormatted(
2572           """
2573       |class C {
2574       |  constructor(
2575       |      context: Context?,
2576       |      attrs: AttributeSet?,
2577       |      defStyleAttr: Int,
2578       |      defStyleRes: Int
2579       |  ) : super(context, attrs, defStyleAttr, defStyleRes) {
2580       |    init(attrs)
2581       |  }
2582       |}
2583       |"""
2584               .trimMargin())
2585 
2586   @Test
handle calling super constructor in secondary constructornull2587   fun `handle calling super constructor in secondary constructor`() =
2588       assertFormatted(
2589           """
2590       |class Foo : Bar {
2591       |  internal constructor(number: Int) : super(number) {}
2592       |}
2593       |"""
2594               .trimMargin())
2595 
2596   @Test
handle super statement with with type argumentnull2597   fun `handle super statement with with type argument`() =
2598       assertFormatted(
2599           """
2600       |class Foo : Bar(), FooBar {
2601       |  override fun doIt() {
2602       |    super<FooBar>.doIt()
2603       |  }
2604       |}
2605       |"""
2606               .trimMargin())
2607 
2608   @Test
handle super statement with with label argumentnull2609   fun `handle super statement with with label argument`() =
2610       assertFormatted(
2611           """
2612       |class Foo : Bar(), FooBar {
2613       |  override fun doIt() {
2614       |    foo.doThat {
2615       |      super<FooBar>@Foo.doIt()
2616       |
2617       |      // this one is actually generics on the call expression, not super
2618       |      super@Foo<FooBar>.doIt()
2619       |    }
2620       |  }
2621       |}
2622       |"""
2623               .trimMargin())
2624 
2625   @Test
primary constructor without parameters with a KDocnull2626   fun `primary constructor without parameters with a KDoc`() =
2627       assertFormatted(
2628           """
2629       |class Class
2630       |/** A comment */
2631       |constructor() {}
2632       |"""
2633               .trimMargin())
2634 
2635   @Test
handle objectsnull2636   fun `handle objects`() =
2637       assertFormatted(
2638           """
2639       |object Foo(n: Int) {}
2640       |"""
2641               .trimMargin())
2642 
2643   @Test
handle object expressionnull2644   fun `handle object expression`() =
2645       assertFormatted(
2646           """
2647       |fun f(): Any {
2648       |  return object : Adapter() {}
2649       |}
2650       |"""
2651               .trimMargin())
2652 
2653   @Test
handle object expression in parenthesisnull2654   fun `handle object expression in parenthesis`() =
2655       assertFormatted(
2656           """
2657       |fun f(): Any {
2658       |  return (object : Adapter() {})
2659       |}
2660       |"""
2661               .trimMargin())
2662 
2663   @Test
handle array indexing operatornull2664   fun `handle array indexing operator`() =
2665       assertFormatted(
2666           """
2667       |fun f(a: Magic) {
2668       |  a[3]
2669       |  b[3, 4]
2670       |}
2671       |"""
2672               .trimMargin())
2673 
2674   @Test
keep array indexing grouped with expression is possiblenull2675   fun `keep array indexing grouped with expression is possible`() =
2676       assertFormatted(
2677           """
2678       |///////////////////////
2679       |fun f(a: Magic) {
2680       |  foo.bar()
2681       |      .foobar[1, 2, 3]
2682       |  foo.bar()
2683       |      .foobar[
2684       |          1,
2685       |          2,
2686       |          3,
2687       |          4,
2688       |          5]
2689       |  foo.bar()
2690       |      .foobar[1, 2, 3]
2691       |      .barfoo[3, 2, 1]
2692       |}
2693       |"""
2694               .trimMargin(),
2695           deduceMaxWidth = true)
2696 
2697   @Test
mixed chainsnull2698   fun `mixed chains`() =
2699       assertFormatted(
2700           """
2701       |///////////////////////
2702       |fun f(a: Magic) {
2703       |  foo.bar()
2704       |      .foobar[1, 2, 3]
2705       |  foo.bar()
2706       |      .foobar[
2707       |          1,
2708       |          2,
2709       |          3,
2710       |          4,
2711       |          5]
2712       |  foo.bar()
2713       |      .foobar[1, 2, 3]
2714       |      .barfoo[3, 2, 1]
2715       |}
2716       |"""
2717               .trimMargin(),
2718           deduceMaxWidth = true)
2719 
2720   @Test
handle destructuring declarationnull2721   fun `handle destructuring declaration`() =
2722       assertFormatted(
2723           """
2724       |///////////////////////////////////////////////
2725       |fun f() {
2726       |  val (a, b: Int) = listOf(1, 2)
2727       |  val (asd, asd, asd, asd, asd, asd, asd) =
2728       |      foo.bar(asdasd, asdasd)
2729       |
2730       |  val (accountType, accountId) =
2731       |      oneTwoThreeFourFiveSixSeven(
2732       |          foo, bar, zed, boo)
2733       |}
2734       |"""
2735               .trimMargin(),
2736           deduceMaxWidth = true)
2737 
2738   @Test
chains with derferences and array indexingnull2739   fun `chains with derferences and array indexing`() =
2740       assertFormatted(
2741           """
2742       |///////////////////////
2743       |fun f() {
2744       |  foo.bam()
2745       |      .uber!![0, 1, 2]
2746       |      .boom()[1, 3, 5]
2747       |      .lah
2748       |      .doo { it }
2749       |      .feep[1]
2750       |      as Boo
2751       |}
2752       |"""
2753               .trimMargin(),
2754           deduceMaxWidth = true)
2755 
2756   @Test
block like syntax after dereferences and indexing with short linesnull2757   fun `block like syntax after dereferences and indexing with short lines`() =
2758       assertFormatted(
2759           """
2760       |///////////////////////
2761       |fun f() {
2762       |  foo.bam()
2763       |      .uber!![0, 1, 2]
2764       |      .forEach {
2765       |        println(it)
2766       |      }
2767       |}
2768       |"""
2769               .trimMargin(),
2770           deduceMaxWidth = true)
2771 
2772   @Test
block like syntax after dereferences and indexing with long linesnull2773   fun `block like syntax after dereferences and indexing with long lines`() =
2774       assertFormatted(
2775           """
2776       |//////////////////////////////////
2777       |fun f() {
2778       |  foo.uber!![0, 1, 2].forEach {
2779       |    println(it)
2780       |  }
2781       |}
2782       |"""
2783               .trimMargin(),
2784           deduceMaxWidth = true)
2785 
2786   @Test
try to keep type names togethernull2787   fun `try to keep type names together`() =
2788       assertFormatted(
2789           """
2790       |///////////////////////
2791       |fun f() {
2792       |  com.facebook.foo.Foo(
2793       |      1, 2)
2794       |  com.facebook.foo
2795       |      .Foo(1, 2)
2796       |      .andAlsoThis()
2797       |  com.facebook.Foo.foo(
2798       |      1, 2)
2799       |  com.facebook
2800       |      .foobarFoo
2801       |      .foo(1, 2)
2802       |  foo.invoke(
2803       |      foo, bar, bar)
2804       |  foo.invoke(foo, bar)
2805       |      .invoke()
2806       |  FooFoo.foooooooo()
2807       |      .foooooooo()
2808       |}
2809       |"""
2810               .trimMargin(),
2811           deduceMaxWidth = true)
2812 
2813   @Test
avoid breaking brackets and keep them with array namenull2814   fun `avoid breaking brackets and keep them with array name`() =
2815       assertFormatted(
2816           """
2817       |/////////////////////////////////////////////////////////////////////////
2818       |fun f() {
2819       |  val a =
2820       |      invokeIt(context.packageName)
2821       |          .getInternalMutablePackageInfo(context.packageName)
2822       |          .someItems[0]
2823       |          .getInternalMutablePackageInfo(context.packageName)
2824       |          .someItems[0]
2825       |          .doIt()
2826       |}
2827       |"""
2828               .trimMargin(),
2829           deduceMaxWidth = true)
2830 
2831   @Test
keep function call with type name even if array expression is nextnull2832   fun `keep function call with type name even if array expression is next`() =
2833       assertFormatted(
2834           """
2835       |class f {
2836       |  private val somePropertyWithBackingOne
2837       |    get() =
2838       |        _somePropertyWithBackingOne
2839       |            ?: Classname.getStuff<SomePropertyRelatedClassProvider>(requireContext())[
2840       |                    somePropertiesProvider, somePropertyCallbacks]
2841       |                .also { _somePropertyWithBackingOne = it }
2842       |}
2843       |"""
2844               .trimMargin())
2845 
2846   @Test
array access in middle of chain and end of it behaves similarlynull2847   fun `array access in middle of chain and end of it behaves similarly`() =
2848       assertFormatted(
2849           """
2850       |//////////////////////////////////////
2851       |fun f() {
2852       |  if (aaaaa == null ||
2853       |      aaaaa.bbbbb[0] == null ||
2854       |      aaaaa.bbbbb[0].cc == null ||
2855       |      aaaaa.bbbbb[0].dddd == null) {
2856       |    println()
2857       |  }
2858       |}
2859       |"""
2860               .trimMargin(),
2861           deduceMaxWidth = true)
2862 
2863   @Test
handle qmark for nullable typesnull2864   fun `handle qmark for nullable types`() =
2865       assertFormatted(
2866           """
2867       |var x: Int? = null
2868       |var x: (Int)? = null
2869       |var x: (Int?) = null
2870       |var x: ((Int))? = null
2871       |var x: ((Int?)) = null
2872       |var x: ((Int)?) = null
2873       |
2874       |var x: @Anno Int? = null
2875       |var x: @Anno() (Int)? = null
2876       |var x: @Anno (Int?) = null
2877       |var x: (@Anno Int)? = null
2878       |var x: (@Anno Int?) = null
2879       |var x: (@Anno() (Int))? = null
2880       |var x: (@Anno (Int?)) = null
2881       |var x: (@Anno() (Int)?) = null
2882       |"""
2883               .trimMargin())
2884 
2885   @Test
2886   fun `nullable function type`() =
2887       assertFormatted(
2888           """
2889       |var listener: ((Boolean) -> Unit)? = null
2890       |"""
2891               .trimMargin())
2892 
2893   @Test
2894   fun `redundant parenthesis in function types`() =
2895       assertFormatted(
2896           """
2897       |val a: (Int) = 7
2898       |
2899       |var listener: ((Boolean) -> Unit) = foo
2900       |"""
2901               .trimMargin())
2902 
2903   @Test
2904   fun `handle string literals`() =
2905       assertFormatted(
2906           """
2907       |fun doIt(world: String) {
2908       |  println("Hello world!")
2909       |  println("Hello! ${'$'}world")
2910       |  println("Hello! ${'$'}{"wor" + "ld"}")
2911       |}
2912       |"""
2913               .trimMargin())
2914 
2915   @Test
handle multiline string literalsnull2916   fun `handle multiline string literals`() =
2917       assertFormatted(
2918           """
2919       |fun doIt(world: String) {
2920       |  println(
2921       |      ${TQ}Hello
2922       |      world!${TQ})
2923       |  println(
2924       |      ${TQ}Hello
2925       |      world!${TQ},
2926       |      ${TQ}Goodbye
2927       |      world!${TQ})
2928       |}
2929       |"""
2930               .trimMargin())
2931 
2932   @Test
Trailing whitespaces are preserved in multiline stringsnull2933   fun `Trailing whitespaces are preserved in multiline strings`() {
2934     val code =
2935         listOf(
2936                 "fun doIt(world: String) {",
2937                 "  println(",
2938                 "      ${TQ}This line has trailing whitespace         ",
2939                 "      world!${TQ})",
2940                 "  println(",
2941                 "      ${TQ}This line has trailing whitespace \$s     ",
2942                 "      world!${TQ})",
2943                 "  println(",
2944                 "      ${TQ}This line has trailing whitespace \${s}   ",
2945                 "      world!${TQ})",
2946                 "  println(",
2947                 "      ${TQ}This line has trailing whitespace \$      ",
2948                 "      world!${TQ})",
2949                 "}",
2950                 "")
2951             .joinToString("\n")
2952     assertThatFormatting(code).allowTrailingWhitespace().isEqualTo(code)
2953   }
2954 
2955   @Test
2956   fun `Consecutive line breaks in multiline strings are preserved`() =
2957       assertFormatted(
2958           """
2959       |val x =
2960       |    $TQ
2961       |
2962       |
2963       |
2964       |Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
2965       |$TQ
2966       |"""
2967               .trimMargin())
2968 
2969   @Test
2970   fun `Trailing spaces in a comment are not preserved`() {
2971     val before =
2972         listOf("// trailing spaces in a comment are not preserved       ", "").joinToString("\n")
2973     val after = listOf("// trailing spaces in a comment are not preserved", "").joinToString("\n")
2974     assertThatFormatting(before).allowTrailingWhitespace().isEqualTo(after)
2975   }
2976 
2977   @Test
2978   fun `Code with tombstones is not supported`() {
2979     val code =
2980         """
2981       |fun good() {
2982       |  // ${'\u0003'}
2983       |}
2984       |"""
2985             .trimMargin()
2986     try {
2987       Formatter.format(code)
2988       fail()
2989     } catch (e: ParseError) {
2990       assertThat(e.errorDescription).contains("\\u0003")
2991       assertThat(e.lineColumn.line).isEqualTo(1)
2992       assertThat(e.lineColumn.column).isEqualTo(5)
2993     }
2994   }
2995 
2996   @Test
handle some basic generics scenariosnull2997   fun `handle some basic generics scenarios`() =
2998       assertFormatted(
2999           """
3000       |fun <T> doIt(a: List<T>): List<Int>? {
3001       |  val b: List<Int> = convert<Int>(listOf(5, 4))
3002       |  return b
3003       |}
3004       |
3005       |class Foo<T>
3006       |"""
3007               .trimMargin())
3008 
3009   @Test
handle for loopsnull3010   fun `handle for loops`() =
3011       assertFormatted(
3012           """
3013       |fun f(a: List<Int>) {
3014       |  for (i in a.indices) {
3015       |    println(i)
3016       |  }
3017       |}
3018       |"""
3019               .trimMargin())
3020 
3021   @Test
handle for loops with long dot chainsnull3022   fun `handle for loops with long dot chains`() =
3023       assertFormatted(
3024           """
3025       |///////////////////////////////////
3026       |fun f(a: Node<Int>) {
3027       |  for (child in node.next.data()) {
3028       |    println(child)
3029       |  }
3030       |  for (child in
3031       |      node.next.next.data()) {
3032       |    println(child)
3033       |  }
3034       |  for (child in
3035       |      node.next.next.next.next
3036       |          .data()) {
3037       |    println(child)
3038       |  }
3039       |}
3040       |"""
3041               .trimMargin(),
3042           deduceMaxWidth = true)
3043 
3044   @Test
when two lambdas following a call, indent the lambda properlynull3045   fun `when two lambdas following a call, indent the lambda properly`() =
3046       assertFormatted(
3047           """
3048       |////////////////////////////
3049       |fun f() {
3050       |  doIt()
3051       |      .apply {
3052       |        number =
3053       |            computeNumber1()
3054       |      }
3055       |      .apply {
3056       |        number = 2 * number
3057       |      }
3058       |}
3059       |"""
3060               .trimMargin(),
3061           deduceMaxWidth = true)
3062 
3063   @Test
when two lambdas following a field, indent the lambda properlynull3064   fun `when two lambdas following a field, indent the lambda properly`() =
3065       assertFormatted(
3066           """
3067       |////////////////////////////
3068       |fun f() {
3069       |  field
3070       |      .apply {
3071       |        number =
3072       |            computeNumber1()
3073       |      }
3074       |      .apply {
3075       |        number = 2 * number
3076       |      }
3077       |}
3078       |"""
3079               .trimMargin(),
3080           deduceMaxWidth = true)
3081 
3082   @Test
break after 'four' (even though it's 4 chars long) because there's a lambda afterwardsnull3083   fun `break after 'four' (even though it's 4 chars long) because there's a lambda afterwards`() =
3084       assertFormatted(
3085           """
3086       |fun f() {
3087       |  four
3088       |      .let {
3089       |        //
3090       |        foo()
3091       |      }
3092       |      .methodCall()
3093       |}
3094       |"""
3095               .trimMargin())
3096 
3097   @Test
keep last expression in qualified indentednull3098   fun `keep last expression in qualified indented`() =
3099       assertFormatted(
3100           """
3101       |////////////////////////////
3102       |fun f() {
3103       |  Stuff()
3104       |      .doIt(
3105       |          Foo.doIt()
3106       |              .doThat())
3107       |      .doIt(
3108       |          Foo.doIt()
3109       |              .doThat())
3110       |}
3111       |"""
3112               .trimMargin(),
3113           deduceMaxWidth = true)
3114 
3115   @Test
properly place lambda arguments into blocksnull3116   fun `properly place lambda arguments into blocks`() =
3117       assertFormatted(
3118           """
3119       |///////////////////////
3120       |fun f() {
3121       |  foo {
3122       |    red.orange.yellow()
3123       |  }
3124       |
3125       |  foo.bar {
3126       |    red.orange.yellow()
3127       |  }
3128       |}
3129       |"""
3130               .trimMargin(),
3131           deduceMaxWidth = true)
3132 
3133   @Test
properly handle one statement lambda with commentnull3134   fun `properly handle one statement lambda with comment`() =
3135       assertFormatted(
3136           """
3137       |///////////////////////
3138       |fun f() {
3139       |  foo {
3140       |    // this is a comment
3141       |    red.orange.yellow()
3142       |  }
3143       |  foo {
3144       |    /* this is also a comment */
3145       |    red.orange.yellow()
3146       |  }
3147       |  foo.bar {
3148       |    // this is a comment
3149       |    red.orange.yellow()
3150       |  }
3151       |  foo.bar() {
3152       |    // this is a comment
3153       |    red.orange.yellow()
3154       |  }
3155       |  foo.bar {
3156       |    /* this is also a comment */
3157       |    red.orange.yellow()
3158       |  }
3159       |}
3160       |"""
3161               .trimMargin(),
3162           deduceMaxWidth = true)
3163 
3164   @Test
properly handle one statement lambda with comment after body statementsnull3165   fun `properly handle one statement lambda with comment after body statements`() =
3166       assertFormatted(
3167           """
3168       |///////////////////////
3169       |fun f() {
3170       |  foo {
3171       |    red.orange.yellow()
3172       |    // this is a comment
3173       |  }
3174       |  foo {
3175       |    red.orange.yellow()
3176       |    /* this is also a comment */
3177       |  }
3178       |  foo.bar {
3179       |    red.orange.yellow()
3180       |    // this is a comment
3181       |  }
3182       |  foo.bar() {
3183       |    red.orange.yellow()
3184       |    // this is a comment
3185       |  }
3186       |  foo.bar {
3187       |    red.orange.yellow()
3188       |    /* this is also a comment */
3189       |  }
3190       |  red.orange.yellow()
3191       |  // this is a comment
3192       |}
3193       |"""
3194               .trimMargin(),
3195           deduceMaxWidth = true)
3196 
3197   @Test
try to keep expression in the same line until the first lambdanull3198   fun `try to keep expression in the same line until the first lambda`() =
3199       assertFormatted(
3200           """
3201       |/////////////////////////
3202       |fun f() {
3203       |  foo.bar.bar?.let {
3204       |    a()
3205       |  }
3206       |  foo.bar.bar?.let {
3207       |    action()
3208       |    action2()
3209       |  }
3210       |  foo.bar.bar.bar.bar
3211       |      ?.let { a() }
3212       |  foo.bar.bar.bar.bar
3213       |      ?.let {
3214       |        action()
3215       |        action2()
3216       |      }
3217       |}
3218       |"""
3219               .trimMargin(),
3220           deduceMaxWidth = true)
3221 
3222   @Test
different indentation in chained callsnull3223   fun `different indentation in chained calls`() =
3224       assertFormatted(
3225           """
3226       |///////////////////////////
3227       |fun f() {
3228       |  fooDdoIt(
3229       |      foo1, foo2, foo3)
3230       |  foo.doIt(
3231       |      foo1, foo2, foo3)
3232       |  foo.doIt(
3233       |          foo1, foo2, foo3)
3234       |      .doThat()
3235       |}
3236       |"""
3237               .trimMargin(),
3238           deduceMaxWidth = true)
3239 
3240   @Test
always add a conditional break for a lambda which is not lastnull3241   fun `always add a conditional break for a lambda which is not last`() =
3242       assertFormatted(
3243           """
3244       |////////////////////
3245       |fun f() {
3246       |  foofoo
3247       |      .doIt {
3248       |        doStuff()
3249       |      }
3250       |      .doIt {
3251       |        doStuff()
3252       |      }
3253       |}
3254       |"""
3255               .trimMargin(),
3256           deduceMaxWidth = true)
3257 
3258   @Test
keep parenthesis and braces together when there's only one lambda argumentnull3259   fun `keep parenthesis and braces together when there's only one lambda argument`() =
3260       assertFormatted(
3261           """
3262       |fun f() {
3263       |  doIt({})
3264       |  doIt({ it + it })
3265       |  doIt({
3266       |    val a = it
3267       |    a + a
3268       |  })
3269       |  doIt(functor = { it + it })
3270       |  doIt(
3271       |      functor = {
3272       |        val a = it
3273       |        a + a
3274       |      })
3275       |}
3276       |"""
3277               .trimMargin())
3278 
3279   @Test
Qualified typenull3280   fun `Qualified type`() =
3281       assertFormatted(
3282           """
3283       |fun f() {
3284       |  var plusFour: Indent.Const
3285       |  var x: Map.Entry<String, Integer>
3286       |  var x: List<String>.Iterator
3287       |}
3288       |"""
3289               .trimMargin())
3290 
3291   @Test
handle destructuring declaration in for loopnull3292   fun `handle destructuring declaration in for loop`() =
3293       assertFormatted(
3294           """
3295       |fun f(a: List<Pair<Int, Int>>) {
3296       |  for ((x, y: Int) in a) {}
3297       |}
3298       |"""
3299               .trimMargin())
3300 
3301   @Test
handle function referencesnull3302   fun `handle function references`() =
3303       assertFormatted(
3304           """
3305       |////////////////////////////////
3306       |fun f(a: List<Int>) {
3307       |  a.forEach(::println)
3308       |  a.map(Int::toString)
3309       |  a.map(String?::isNullOrEmpty)
3310       |  a.map(
3311       |      SuperLongClassName?::
3312       |          functionName)
3313       |  val f =
3314       |      SuperLongClassName::
3315       |          functionName
3316       |  val g =
3317       |      invoke(a, b)::functionName
3318       |  val h =
3319       |      invoke(a, b, c)::
3320       |          functionName
3321       |}
3322       |"""
3323               .trimMargin(),
3324           deduceMaxWidth = true)
3325 
3326   @Test
handle escaped identifiernull3327   fun `handle escaped identifier`() =
3328       assertFormatted(
3329           """
3330       |import foo as `foo foo`
3331       |import org.mockito.Mockito.`when` as `yay yay`
3332       |
3333       |fun `spaces in functions`() {
3334       |  val `when` = NEVER
3335       |  val (`do not`, `ever write`) = SERIOUSLY
3336       |  val `a a`: Int
3337       |  `yay yay`(`foo foo`)
3338       |}
3339       |
3340       |class `more spaces`
3341       |"""
3342               .trimMargin())
3343 
3344   @Test
handle annotations with argumentsnull3345   fun `handle annotations with arguments`() =
3346       assertFormatted(
3347           """
3348       |@Px fun f(): Int = 5
3349       |
3350       |@Dimenstion(unit = DP) fun g(): Int = 5
3351       |
3352       |@RunWith(MagicRunner::class)
3353       |@Px
3354       |class Test {
3355       |  //
3356       |}
3357       |"""
3358               .trimMargin())
3359 
3360   @Test
no newlines after annotations if entire expr fits in one linenull3361   fun `no newlines after annotations if entire expr fits in one line`() =
3362       assertFormatted(
3363           """
3364       |///////////////////////////////////////////////
3365       |@Px @Px fun f(): Int = 5
3366       |
3367       |@Px
3368       |@Px
3369       |@Px
3370       |@Px
3371       |@Px
3372       |@Px
3373       |@Px
3374       |@Px
3375       |fun f(): Int = 5
3376       |
3377       |@Px
3378       |@Px
3379       |fun f(): Int {
3380       |  return 5
3381       |}
3382       |
3383       |@Dimenstion(unit = DP) @Px fun g(): Int = 5
3384       |
3385       |@Dimenstion(unit = DP)
3386       |@Px
3387       |fun g(): Int {
3388       |  return 5
3389       |}
3390       |
3391       |@RunWith @Px class Test
3392       |
3393       |@RunWith(MagicRunner::class) @Px class Test
3394       |
3395       |@RunWith @Px class Test {}
3396       |
3397       |@RunWith(MagicRunner::class) @Px class Test {}
3398       |
3399       |@RunWith(MagicRunner::class)
3400       |@Px
3401       |@Px
3402       |class Test {}
3403       |
3404       |@RunWith(MagicRunner::class)
3405       |@Px
3406       |class Test {
3407       |  //
3408       |}
3409       |
3410       |fun f() {
3411       |  if (@Stuff(Magic::class) isGood()) {
3412       |    println("")
3413       |  }
3414       |}
3415       |"""
3416               .trimMargin(),
3417           deduceMaxWidth = true)
3418 
3419   @Test
no newlines after annotations on properties if entire expression fits in one linenull3420   fun `no newlines after annotations on properties if entire expression fits in one line`() =
3421       assertFormatted(
3422           """
3423       |////////////////////////////////////////////
3424       |@Suppress("UnsafeCast")
3425       |val ClassA.methodA
3426       |  get() = foo as Bar
3427       |"""
3428               .trimMargin(),
3429           deduceMaxWidth = true)
3430 
3431   @Test
3432   fun `when annotations cause line breaks, and constant has no type dont break before value`() =
3433       assertFormatted(
3434           """
3435       |//////////////////////////////////////////////////////////
3436       |object Foo {
3437       |  @LongLongLongLongAnnotation
3438       |  @LongLongLongLongLongAnnotation
3439       |  private val ROW_HEIGHT = 72
3440       |}
3441       |"""
3442               .trimMargin(),
3443           deduceMaxWidth = true)
3444 
3445   @Test
annotations in literal function typesnull3446   fun `annotations in literal function types`() =
3447       assertFormatted(
3448           """
3449       |val callback: (@Anno List<@JvmSuppressWildcards String>) -> Unit = foo
3450       |"""
3451               .trimMargin())
3452 
3453   @Test
3454   fun `annotations on type parameters`() =
3455       assertFormatted(
3456           """
3457       |class Foo<@Anno out @Anno T, @Anno in @Anno U> {
3458       |  inline fun <@Anno reified @Anno X, @Anno reified @Anno Y> bar() {}
3459       |}
3460       |"""
3461               .trimMargin())
3462 
3463   @Test
annotations on type constraintsnull3464   fun `annotations on type constraints`() =
3465       assertFormatted(
3466           """
3467       |class Foo<T : @Anno Kip, U> where U : @Anno Kip, U : @Anno Qux {
3468       |  fun <T : @Anno Kip, U> bar() where U : @Anno Kip, U : @Anno Qux {}
3469       |}
3470       |"""
3471               .trimMargin())
3472 
3473   @Test
annotations on type argumentsnull3474   fun `annotations on type arguments`() =
3475       assertFormatted(
3476           """
3477       |fun foo(x: Foo<in @Anno Int>) {}
3478       |"""
3479               .trimMargin())
3480 
3481   @Test
annotations on destructuring declaration elementsnull3482   fun `annotations on destructuring declaration elements`() =
3483       assertFormatted(
3484           """
3485       |val x = { (@Anno x, @Anno y) -> x }
3486       |"""
3487               .trimMargin())
3488 
3489   @Test
annotations on exceptionsnull3490   fun `annotations on exceptions`() =
3491       assertFormatted(
3492           """
3493       |fun doIt() {
3494       |  try {
3495       |    doItAgain()
3496       |  } catch (@Nullable e: Exception) {
3497       |    //
3498       |  } catch (@Suppress("GeneralException") e: Exception) {}
3499       |}
3500       |"""
3501               .trimMargin())
3502 
3503   @Test
annotations on return statementsnull3504   fun `annotations on return statements`() =
3505       assertFormatted(
3506           """
3507       |fun foo(): Map<String, Any> {
3508       |  @Suppress("AsCollectionCall")
3509       |  return map.asMap()
3510       |}
3511       |"""
3512               .trimMargin())
3513 
3514   @Test
Unary prefix expressionsnull3515   fun `Unary prefix expressions`() =
3516       assertFormatted(
3517           """
3518       |fun f() {
3519       |  !a
3520       |  -4
3521       |  val x = -foo()
3522       |  +4
3523       |  ++a
3524       |  --a
3525       |
3526       |  + +a
3527       |  +-a
3528       |  +!a
3529       |  -+a
3530       |  - -a
3531       |  -!a
3532       |  !+a
3533       |  !a
3534       |  ! !a
3535       |
3536       |  + ++a
3537       |  +--a
3538       |  -++a
3539       |  - --a
3540       |  !++a
3541       |  !--a
3542       |}
3543       |"""
3544               .trimMargin())
3545 
3546   @Test
Unary postfix expressionsnull3547   fun `Unary postfix expressions`() =
3548       assertFormatted(
3549           """
3550       |fun f() {
3551       |  a!!
3552       |  a++
3553       |  a--
3554       |
3555       |  a--!!
3556       |  a++!!
3557       |
3558       |  a!! !!
3559       |}
3560       |"""
3561               .trimMargin())
3562 
3563   @Test
handle wildcard genericsnull3564   fun `handle wildcard generics`() =
3565       assertFormatted(
3566           """
3567       |fun f() {
3568       |  val l: List<*>
3569       |  val p: Pair<*, *>
3570       |}
3571       |"""
3572               .trimMargin())
3573 
3574   @Test
handle intersection genericsnull3575   fun `handle intersection generics`() =
3576       assertFormatted(
3577           """
3578       |fun f() {
3579       |  val l: Decl<A & B & C>
3580       |  val p = Ctor<A & B & C, T & Y & Z>
3581       |}
3582       |"""
3583               .trimMargin())
3584 
3585   @Test
handle covariant and contravariant type argumentsnull3586   fun `handle covariant and contravariant type arguments`() =
3587       assertFormatted(
3588           """
3589       |val p: Pair<in T, out S>
3590       |"""
3591               .trimMargin())
3592 
3593   @Test
3594   fun `handle covariant and contravariant type parameters`() =
3595       assertFormatted(
3596           """
3597       |class Foo<in T, out S>
3598       |"""
3599               .trimMargin())
3600 
3601   @Test
3602   fun `handle bounds for type parameters`() =
3603       assertFormatted(
3604           """
3605       |class Foo<in T : List<*>, out S : Any?>
3606       |"""
3607               .trimMargin())
3608 
3609   @Test
3610   fun `handle compound generic bounds on classes`() =
3611       assertFormatted(
3612           """
3613       |class Foo<T>(n: Int) where T : Bar, T : FooBar {}
3614       |"""
3615               .trimMargin())
3616 
3617   @Test
handle compound generic bounds on functionsnull3618   fun `handle compound generic bounds on functions`() =
3619       assertFormatted(
3620           """
3621       |fun <T> foo(n: Int) where T : Bar, T : FooBar {}
3622       |"""
3623               .trimMargin())
3624 
3625   @Test
handle compound generic bounds on propertiesnull3626   fun `handle compound generic bounds on properties`() =
3627       assertFormatted(
3628           """
3629       |val <T> List<T>.twiceSum: Int where T : Int
3630       |  get() {
3631       |    return 2 * sum()
3632       |  }
3633       |"""
3634               .trimMargin())
3635 
3636   @Test
handle compound generic bounds on class with delegatenull3637   fun `handle compound generic bounds on class with delegate`() =
3638       assertFormatted(
3639           """
3640       |class Foo<T>() : Bar by bar
3641       |where T : Qux
3642       |"""
3643               .trimMargin())
3644 
3645   @Test
3646   fun `explicit type on property getter`() =
3647       assertFormatted(
3648           """
3649       |class Foo {
3650       |  val silly: Int
3651       |    get(): Int = 1
3652       |}
3653       |"""
3654               .trimMargin())
3655 
3656   @Test
handle method calls with lambda arg onlynull3657   fun `handle method calls with lambda arg only`() =
3658       assertFormatted(
3659           """
3660       |fun f() {
3661       |  val a = g { 1 + 1 }
3662       |}
3663       |"""
3664               .trimMargin())
3665 
3666   @Test
handle method calls value args and a lambda argnull3667   fun `handle method calls value args and a lambda arg`() =
3668       assertFormatted(
3669           """
3670       |fun f() {
3671       |  val a = g(1, 2) { 1 + 1 }
3672       |}
3673       |"""
3674               .trimMargin())
3675 
3676   @Test
handle top level constantsnull3677   fun `handle top level constants`() =
3678       assertFormatted(
3679           """
3680       |/////////////////////////////
3681       |val a = 5
3682       |
3683       |const val b = "a"
3684       |
3685       |val a = 5
3686       |"""
3687               .trimMargin(),
3688           deduceMaxWidth = true)
3689 
3690   @Test
3691   fun `handle lambda arg with named arguments`() =
3692       assertFormatted(
3693           """
3694       |fun f() {
3695       |  val b = { x: Int, y: Int -> x + y }
3696       |}
3697       |"""
3698               .trimMargin())
3699 
3700   @Test
avoid newline before lambda argument if it is namednull3701   fun `avoid newline before lambda argument if it is named`() =
3702       assertFormatted(
3703           """
3704       |private fun f(items: List<Int>) {
3705       |  doSomethingCool(
3706       |      items,
3707       |      lambdaArgument = {
3708       |        step1()
3709       |        step2()
3710       |      }) {
3711       |        it.doIt()
3712       |      }
3713       |}
3714       |"""
3715               .trimMargin())
3716 
3717   @Test
handle labeled this pointernull3718   fun `handle labeled this pointer`() =
3719       assertFormatted(
3720           """
3721       |class Foo {
3722       |  fun f() {
3723       |    g { println(this@Foo) }
3724       |  }
3725       |}
3726       |"""
3727               .trimMargin())
3728 
3729   @Test
handle extension and operator functionsnull3730   fun `handle extension and operator functions`() =
3731       assertFormatted(
3732           """
3733       |operator fun Point.component1() = x
3734       |"""
3735               .trimMargin())
3736 
3737   @Test
3738   fun `handle extension methods with very long names`() =
3739       assertFormatted(
3740           """
3741       |//////////////////////////////////////////
3742       |fun LongReceiverNameThatRequiresBreaking
3743       |    .doIt() {}
3744       |
3745       |fun LongButNotTooLong.doIt(
3746       |    n: Int,
3747       |    f: Float
3748       |) {}
3749       |"""
3750               .trimMargin(),
3751           deduceMaxWidth = true)
3752 
3753   @Test
handle extension propertiesnull3754   fun `handle extension properties`() =
3755       assertFormatted(
3756           """
3757       |val Int.isPrime: Boolean
3758       |  get() = runMillerRabinPrimality(this)
3759       |"""
3760               .trimMargin())
3761 
3762   @Test
3763   fun `generic extension property`() =
3764       assertFormatted(
3765           """
3766       |val <T> List<T>.twiceSize = 2 * size()
3767       |"""
3768               .trimMargin())
3769 
3770   @Test
3771   fun `handle file annotations`() {
3772     assertFormatted(
3773         """
3774       |@file:JvmName("DifferentName")
3775       |
3776       |package com.somecompany.example
3777       |
3778       |import com.somecompany.example2
3779       |
3780       |class Foo {
3781       |  val a = example2("and 1")
3782       |}
3783       |"""
3784             .trimMargin())
3785 
3786     assertFormatted(
3787         """
3788       |@file:JvmName("DifferentName") // Comment
3789       |
3790       |package com.somecompany.example
3791       |
3792       |import com.somecompany.example2
3793       |
3794       |class Foo {
3795       |  val a = example2("and 1")
3796       |}
3797       |"""
3798             .trimMargin())
3799 
3800     assertFormatted(
3801         """
3802       |@file:JvmName("DifferentName")
3803       |
3804       |// Comment
3805       |
3806       |package com.somecompany.example
3807       |
3808       |import com.somecompany.example2
3809       |
3810       |class Foo {
3811       |  val a = example2("and 1")
3812       |}
3813       |"""
3814             .trimMargin())
3815 
3816     assertFormatted(
3817         """
3818       |@file:JvmName("DifferentName")
3819       |
3820       |// Comment
3821       |package com.somecompany.example
3822       |
3823       |import com.somecompany.example2
3824       |
3825       |class Foo {
3826       |  val a = example2("and 1")
3827       |}
3828       |"""
3829             .trimMargin())
3830   }
3831 
3832   @Test
handle init blocknull3833   fun `handle init block`() =
3834       assertFormatted(
3835           """
3836       |class Foo {
3837       |  init {
3838       |    println("Init!")
3839       |  }
3840       |}
3841       |"""
3842               .trimMargin())
3843 
3844   @Test
handle interface delegationnull3845   fun `handle interface delegation`() =
3846       assertFormatted(
3847           """
3848       |class MyList(impl: List<Int>) : Collection<Int> by impl
3849       |"""
3850               .trimMargin())
3851 
3852   @Test
3853   fun `handle property delegation`() =
3854       assertFormatted(
3855           """
3856       |val a by lazy { 1 + 1 }
3857       |"""
3858               .trimMargin())
3859 
3860   @Test
handle property delegation with type and breaksnull3861   fun `handle property delegation with type and breaks`() =
3862       assertFormatted(
3863           """
3864       |/////////////////////////////////
3865       |val importantValue: Int by lazy {
3866       |  1 + 1
3867       |}
3868       |
3869       |val importantValue: Int by lazy {
3870       |  val b = 1 + 1
3871       |  b + b
3872       |}
3873       |
3874       |val importantValueLonger:
3875       |    Int by lazy { 1 + 1 }
3876       |
3877       |val importantValue: Int by
3878       |    doIt(1 + 1)
3879       |"""
3880               .trimMargin(),
3881           deduceMaxWidth = true)
3882 
3883   @Test
handle multi-annotations with use-site targetsnull3884   fun `handle multi-annotations with use-site targets`() =
3885       assertFormatted(
3886           """
3887     |class Something {
3888     |  @field:[Inject Named("WEB_VIEW")]
3889     |  internal lateinit var httpClient: OkHttpClient
3890     |
3891     |  @field:[Inject Named("WEB_VIEW")]
3892     |  var httpClient: OkHttpClient
3893     |
3894     |  @Px
3895     |  @field:[Inject Named("WEB_VIEW")]
3896     |  var httpClient: OkHttpClient
3897     |}
3898     |
3899     """
3900               .trimMargin())
3901 
3902   @Test
handle parameters with annoations with parametersnull3903   fun `handle parameters with annoations with parameters`() =
3904       assertFormatted(
3905           """
3906     |class Something {
3907     |  fun doIt(@Magic(withHat = true) foo: Foo) {
3908     |    println(foo)
3909     |  }
3910     |}
3911     |
3912     """
3913               .trimMargin())
3914 
3915   @Test
handle lambda typesnull3916   fun `handle lambda types`() =
3917       assertFormatted(
3918           """
3919       |val listener1: (Boolean) -> Unit = { b -> !b }
3920       |
3921       |val listener2: () -> Unit = {}
3922       |
3923       |val listener3: (Int, Double) -> Int = { a, b -> a }
3924       |
3925       |val listener4: Int.(Int, Boolean) -> Unit
3926       |"""
3927               .trimMargin())
3928 
3929   @Test
handle unicode in string literalsnull3930   fun `handle unicode in string literals`() =
3931       assertFormatted(
3932           """
3933       |val a = "\uD83D\uDC4D"
3934       |"""
3935               .trimMargin())
3936 
3937   @Test
3938   fun `handle casting`() =
3939       assertFormatted(
3940           """
3941       |fun castIt(o: Object) {
3942       |  println(o is Double)
3943       |  println(o !is Double)
3944       |  doIt(o as Int)
3945       |  doIt(o as? Int)
3946       |}
3947       |"""
3948               .trimMargin())
3949 
3950   @Test
handle casting with breaksnull3951   fun `handle casting with breaks`() =
3952       assertFormatted(
3953           """
3954       |///////////////////////
3955       |fun castIt(
3956       |    something: Any
3957       |) {
3958       |  doIt(
3959       |      something
3960       |          as List<*>)
3961       |  doIt(
3962       |      something
3963       |          is List<*>)
3964       |  println(
3965       |      something
3966       |          is
3967       |          List<String>)
3968       |  doIt(
3969       |      something
3970       |          as
3971       |          List<String>)
3972       |  println(
3973       |      something
3974       |          is
3975       |          PairList<
3976       |              String,
3977       |              Int>)
3978       |  doIt(
3979       |      something
3980       |          as
3981       |          PairList<
3982       |              String,
3983       |              Int>)
3984       |  println(
3985       |      a is Int &&
3986       |          b is String)
3987       |  l.b?.s?.sOrNull() is
3988       |      SomethingLongEnough
3989       |}
3990       |
3991       |val a =
3992       |    l.sOrNull() is
3993       |        SomethingLongEnough
3994       |"""
3995               .trimMargin(),
3996           deduceMaxWidth = true)
3997 
3998   @Test
handle collection literals in annotationsnull3999   fun `handle collection literals in annotations`() =
4000       assertFormatted(
4001           """
4002       |@Foo(a = [1, 2])
4003       |fun doIt(o: Object) {
4004       |  //
4005       |}
4006       |"""
4007               .trimMargin())
4008 
4009   @Test
handle try, catch and finallynull4010   fun `handle try, catch and finally`() =
4011       assertFormatted(
4012           """
4013       |fun foo() {
4014       |  try {
4015       |    bar()
4016       |  } catch (e: Exception) {
4017       |    throw e
4018       |  } finally {
4019       |    println("finally")
4020       |  }
4021       |}
4022       |"""
4023               .trimMargin())
4024 
4025   @Test
handle infix methodsnull4026   fun `handle infix methods`() =
4027       assertFormatted(
4028           """
4029       |fun numbers() {
4030       |  (0 until 100).size
4031       |}
4032       |"""
4033               .trimMargin())
4034 
4035   @Test
handle while loopsnull4036   fun `handle while loops`() =
4037       assertFormatted(
4038           """
4039       |fun numbers() {
4040       |  while (1 < 2) {
4041       |    println("Everything is okay")
4042       |  }
4043       |}
4044       |"""
4045               .trimMargin())
4046 
4047   @Test
handle do while loopsnull4048   fun `handle do while loops`() =
4049       assertFormatted(
4050           """
4051       |fun numbers() {
4052       |  do {
4053       |    println("Everything is okay")
4054       |  } while (1 < 2)
4055       |
4056       |  do while (1 < 2)
4057       |}
4058       |"""
4059               .trimMargin())
4060 
4061   @Test
handle break and continuenull4062   fun `handle break and continue`() =
4063       assertFormatted(
4064           """
4065       |fun numbers() {
4066       |  while (1 < 2) {
4067       |    if (true) {
4068       |      break
4069       |    }
4070       |    if (false) {
4071       |      continue
4072       |    }
4073       |  }
4074       |}
4075       |"""
4076               .trimMargin())
4077 
4078   @Test
handle all kinds of labels and jumpsnull4079   fun `handle all kinds of labels and jumps`() =
4080       assertFormatted(
4081           """
4082       |fun f(a: List<Int>) {
4083       |  a.map {
4084       |    myloop@ for (i in a) {
4085       |      if (true) {
4086       |        break@myloop
4087       |      } else if (false) {
4088       |        continue@myloop
4089       |      } else {
4090       |        a.map `inner map`@{
4091       |          return@`inner map`
4092       |        }
4093       |      }
4094       |    }
4095       |    return@map 2 * it
4096       |  }
4097       |}
4098       |"""
4099               .trimMargin())
4100 
4101   @Test
don't crash on top level statements with semicolonsnull4102   fun `don't crash on top level statements with semicolons`() {
4103     val code =
4104         """
4105       |val x = { 0 };
4106       |
4107       |foo({ 0 });
4108       |
4109       |foo { 0 };
4110       |
4111       |val fill = 0;
4112       |"""
4113             .trimMargin()
4114     val expected =
4115         """
4116       |val x = { 0 }
4117       |
4118       |foo({ 0 })
4119       |
4120       |foo { 0 }
4121       |
4122       |val fill = 0
4123       |"""
4124             .trimMargin()
4125     assertThatFormatting(code).isEqualTo(expected)
4126   }
4127 
4128   @Test
preserve semicolons in enumsnull4129   fun `preserve semicolons in enums`() {
4130     val code =
4131         """
4132       |enum class SemiColonIsNotRequired {
4133       |  TRUE, FALSE;
4134       |}
4135       |
4136       |enum class SemiColonIsRequired {
4137       |  ONE, TWO;
4138       |
4139       |  fun isOne(): Boolean = this == ONE
4140       |}
4141       |"""
4142             .trimMargin()
4143     val expected =
4144         """
4145       |enum class SemiColonIsNotRequired {
4146       |  TRUE,
4147       |  FALSE
4148       |}
4149       |
4150       |enum class SemiColonIsRequired {
4151       |  ONE,
4152       |  TWO;
4153       |
4154       |  fun isOne(): Boolean = this == ONE
4155       |}
4156       |"""
4157             .trimMargin()
4158     assertThatFormatting(code).isEqualTo(expected)
4159   }
4160 
4161   @Test
preserve semicolons in comments and stringsnull4162   fun `preserve semicolons in comments and strings`() {
4163     val code =
4164         """
4165       |fun f() {
4166       |  val x = ";"
4167       |  val x = $TQ  don't touch ; in raw strings $TQ
4168       |}
4169       |
4170       |// Don't touch ; inside comments.
4171       |
4172       |/** Don't touch ; inside comments. */
4173       |"""
4174             .trimMargin()
4175     val expected =
4176         """
4177       |fun f() {
4178       |  val x = ";"
4179       |  val x = $TQ  don't touch ; in raw strings $TQ
4180       |}
4181       |
4182       |// Don't touch ; inside comments.
4183       |
4184       |/** Don't touch ; inside comments. */
4185       |"""
4186             .trimMargin()
4187     assertThatFormatting(code).isEqualTo(expected)
4188   }
4189 
4190   @Test
4191   fun `preserve semicolons in empty if-s and while-s`() {
4192     val code =
4193         """
4194       |fun f() {
4195       |  while (true);
4196       |  while (true) /** a */ ;
4197       |
4198       |  if (true);
4199       |  if (true) /** a */ ;
4200       |
4201       |  if (true)
4202       |    else
4203       |  ;
4204       |}
4205       |"""
4206             .trimMargin()
4207     val expected =
4208         """
4209       |fun f() {
4210       |  while (true) ;
4211       |  while (true)
4212       |  /** a */
4213       |  ;
4214       |
4215       |  if (true) ;
4216       |  if (true)
4217       |  /** a */
4218       |   ;
4219       |
4220       |  if (true)  else ;
4221       |}
4222       |"""
4223             .trimMargin()
4224     assertThatFormatting(code).isEqualTo(expected)
4225   }
4226 
4227   @Test
4228   fun `preserve semicolons between calls and dead lambdas`() {
4229     val code =
4230         """
4231       |fun f() {
4232       |  foo(0); { dead -> lambda }
4233       |
4234       |  foo(0) ; { dead -> lambda }
4235       |
4236       |  foo(0) /** a */ ; /** b */ { dead -> lambda }
4237       |
4238       |  foo(0) { trailing -> lambda }; { dead -> lambda }
4239       |
4240       |  foo { trailing -> lambda }; { dead -> lambda }
4241       |
4242       |  val x = foo(); { dead -> lambda }
4243       |
4244       |  val x = bar() && foo(); { dead -> lambda }
4245       |
4246       |  // `z` has a property and a method both named `bar`
4247       |  val x = z.bar; { dead -> lambda }
4248       |
4249       |  // `this` has a property and a method both named `bar`
4250       |  val x = bar; { dead -> lambda }
4251       |
4252       |  // Literally any callable expression is dangerous
4253       |  val x = (if (cond) x::foo else x::bar); { dead -> lambda }
4254       |
4255       |  funcCall(); { dead -> lambda }.withChained(call)
4256       |}
4257       |"""
4258             .trimMargin()
4259     val expected =
4260         """
4261       |fun f() {
4262       |  foo(0);
4263       |  { dead -> lambda }
4264       |
4265       |  foo(0);
4266       |  { dead -> lambda }
4267       |
4268       |  foo(0)
4269       |  /** a */
4270       |  ;
4271       |  /** b */
4272       |  { dead -> lambda }
4273       |
4274       |  foo(0) { trailing -> lambda };
4275       |  { dead -> lambda }
4276       |
4277       |  foo { trailing -> lambda };
4278       |  { dead -> lambda }
4279       |
4280       |  val x = foo();
4281       |  { dead -> lambda }
4282       |
4283       |  val x = bar() && foo();
4284       |  { dead -> lambda }
4285       |
4286       |  // `z` has a property and a method both named `bar`
4287       |  val x = z.bar;
4288       |  { dead -> lambda }
4289       |
4290       |  // `this` has a property and a method both named `bar`
4291       |  val x = bar;
4292       |  { dead -> lambda }
4293       |
4294       |  // Literally any callable expression is dangerous
4295       |  val x = (if (cond) x::foo else x::bar);
4296       |  { dead -> lambda }
4297       |
4298       |  funcCall();
4299       |  { dead -> lambda }.withChained(call)
4300       |}
4301       |"""
4302             .trimMargin()
4303     assertThatFormatting(code).isEqualTo(expected)
4304   }
4305 
4306   @Test
4307   fun `drop redundant semicolons`() {
4308     val code =
4309         """
4310       |package org.examples;
4311       |import org.examples.wow.MuchWow;
4312       |import org.examples.wow.ManyAmaze
4313       |
4314       |typealias Int2 = Int;
4315       |
4316       |fun f() {
4317       |  val a = 3;
4318       |  val x = 5 ; val y = ManyAmaze();
4319       |  myThingMap.forEach { val (key, value) = it; println("mapped ${"$"}MuchWow") }
4320       |  when {
4321       |    true -> "1"; false -> "0"
4322       |  }
4323       |  someLongVariableName.let {
4324       |    someReallyLongFunctionNameThatMakesThisNotFitInOneLineWithTheAboveVariable();
4325       |  }
4326       |  if (cond) ; else 6
4327       |} ;
4328       |
4329       |"""
4330             .trimMargin()
4331     val expected =
4332         """
4333       |package org.examples
4334       |
4335       |import org.examples.wow.ManyAmaze
4336       |import org.examples.wow.MuchWow
4337       |
4338       |typealias Int2 = Int
4339       |
4340       |fun f() {
4341       |  val a = 3
4342       |  val x = 5
4343       |  val y = ManyAmaze()
4344       |  myThingMap.forEach {
4345       |    val (key, value) = it
4346       |    println("mapped ${"$"}MuchWow")
4347       |  }
4348       |  when {
4349       |    true -> "1"
4350       |    false -> "0"
4351       |  }
4352       |  someLongVariableName.let {
4353       |    someReallyLongFunctionNameThatMakesThisNotFitInOneLineWithTheAboveVariable()
4354       |  }
4355       |  if (cond)  else 6
4356       |}
4357       |"""
4358             .trimMargin()
4359     assertThatFormatting(code).isEqualTo(expected)
4360   }
4361 
4362   @Test
4363   fun `pretty-print after dropping redundant semicolons`() {
4364     val code =
4365         """
4366       |fun f() {
4367       |  val veryLongName = 5;
4368       |}
4369       |"""
4370             .trimMargin()
4371     val expected =
4372         """
4373       |fun f() {
4374       |  val veryLongName = 5
4375       |}
4376       |"""
4377             .trimMargin()
4378     assertThatFormatting(code)
4379         .withOptions(defaultTestFormattingOptions.copy(maxWidth = 22))
4380         .isEqualTo(expected)
4381   }
4382 
4383   @Test
4384   fun `handle no parenthesis in lambda calls`() =
4385       assertFormatted(
4386           """
4387       |fun f() {
4388       |  a { println("a") }
4389       |}
4390       |"""
4391               .trimMargin())
4392 
4393   @Test
4394   fun `handle multi statement lambdas`() =
4395       assertFormatted(
4396           """
4397       |fun f() {
4398       |  a {
4399       |    println("a")
4400       |    println("b")
4401       |  }
4402       |}
4403       |"""
4404               .trimMargin())
4405 
4406   @Test
4407   fun `handle multi line one statement lambda`() =
4408       assertFormatted(
4409           """
4410       |/////////////////////////
4411       |fun f() {
4412       |  a {
4413       |    println(foo.bar.boom)
4414       |  }
4415       |}
4416       |"""
4417               .trimMargin(),
4418           deduceMaxWidth = true)
4419 
4420   @Test
4421   fun `statements are wrapped in blocks`() =
4422       assertFormatted(
4423           """
4424       |fun f() {
4425       |  builder.block {
4426       |    getArgumentName().accept
4427       |    return
4428       |  }
4429       |}
4430       |"""
4431               .trimMargin())
4432 
4433   @Test
4434   fun `properly break fully qualified nested user types`() =
4435       assertFormatted(
4436           """
4437       |///////////////////////////////////////////////////////
4438       |val complicated:
4439       |    com.example.interesting.SomeType<
4440       |        com.example.interesting.SomeType<Int, Nothing>,
4441       |        com.example.interesting.SomeType<
4442       |            com.example.interesting.SomeType<
4443       |                Int, Nothing>,
4444       |            Nothing>> =
4445       |    DUMMY
4446       |"""
4447               .trimMargin(),
4448           deduceMaxWidth = true)
4449 
4450   @Test
4451   fun `handle multi-line lambdas within lambdas and calling chains`() =
4452       assertFormatted(
4453           """
4454       |fun f() {
4455       |  builder.block(ZERO) {
4456       |    builder.token("when")
4457       |    expression1.let { subjectExp ->
4458       |      builder.token(")")
4459       |      return
4460       |    }
4461       |  }
4462       |  builder.block(ZERO) {
4463       |    expression2.subjectExpression.let { subjectExp ->
4464       |      builder.token(")")
4465       |      return
4466       |    }
4467       |  }
4468       |  builder.block(ZERO) {
4469       |    expression2.subjectExpression
4470       |        .let { subjectExp ->
4471       |          builder.token(")")
4472       |          return
4473       |        }
4474       |        .sum
4475       |  }
4476       |}
4477       |"""
4478               .trimMargin())
4479 
4480   @Test
4481   fun `handle multi line lambdas with explicit args`() =
4482       assertFormatted(
4483           """
4484       |////////////////////
4485       |fun f() {
4486       |  a { (x, y) ->
4487       |    x + y
4488       |  }
4489       |}
4490       |"""
4491               .trimMargin(),
4492           deduceMaxWidth = true)
4493 
4494   @Test
4495   fun `handle lambda with destructuring and type`() =
4496       assertFormatted(
4497           """
4498       |fun f() {
4499       |  g { (a, b): List<Int> -> a }
4500       |  g { (a, b): List<Int>, (c, d): List<Int> -> a }
4501       |}
4502       |"""
4503               .trimMargin())
4504 
4505   @Test
4506   fun `handle parenthesis in lambda calls for now`() =
4507       assertFormatted(
4508           """
4509       |fun f() {
4510       |  a() { println("a") }
4511       |}
4512       |"""
4513               .trimMargin())
4514 
4515   @Test
4516   fun `handle chaining of calls with lambdas`() =
4517       assertFormatted(
4518           """
4519       |fun f() {
4520       |  bobby
4521       |      .map { x -> x * x }
4522       |      .map { x -> x * x }
4523       |      ?.map { x ->
4524       |        val y = x * x
4525       |        y
4526       |      }
4527       |      .sum
4528       |}
4529       |"""
4530               .trimMargin())
4531 
4532   @Test
4533   fun `handle break of lambda args per line with indentation`() =
4534       assertFormatted(
4535           """
4536       |///////////
4537       |fun f() {
4538       |  a() {
4539       |      arg1,
4540       |      arg2,
4541       |      x ->
4542       |    doIt()
4543       |    doIt()
4544       |  }
4545       |  a() {
4546       |      arg1,
4547       |      arg2,
4548       |      arg3
4549       |    ->
4550       |    doIt()
4551       |    doIt()
4552       |  }
4553       |}
4554       |"""
4555               .trimMargin(),
4556           deduceMaxWidth = true)
4557 
4558   @Test
4559   fun `handle trailing comma in lambda`() =
4560       assertFormatted(
4561           """
4562       |///////////
4563       |fun f() {
4564       |  a() {
4565       |      arg1,
4566       |      arg2,
4567       |      x,
4568       |    ->
4569       |    doIt()
4570       |    doIt()
4571       |  }
4572       |}
4573       |"""
4574               .trimMargin(),
4575           deduceMaxWidth = true)
4576 
4577   @Test
4578   fun `break before Elvis operator`() =
4579       assertFormatted(
4580           """
4581         |//////////////////////////////////////////////////
4582         |fun f() {
4583         |  someObject
4584         |      .someMethodReturningCollection()
4585         |      .map { it.someProperty }
4586         |      .find { it.contains(someSearchValue) }
4587         |      ?: someDefaultValue
4588         |}
4589         |"""
4590               .trimMargin(),
4591           deduceMaxWidth = true)
4592 
4593   @Test
4594   fun `chain of Elvis operator`() =
4595       assertFormatted(
4596           """
4597         |///////////////////////////
4598         |fun f() {
4599         |  return option1()
4600         |      ?: option2()
4601         |      ?: option3()
4602         |      ?: option4()
4603         |      ?: option5()
4604         |}
4605         |"""
4606               .trimMargin(),
4607           deduceMaxWidth = true)
4608 
4609   @Test
4610   fun `Elvis operator mixed with plus operator breaking on plus`() =
4611       assertFormatted(
4612           """
4613         |////////////////////////
4614         |fun f() {
4615         |  return option1()
4616         |      ?: option2() +
4617         |          option3()
4618         |      ?: option4() +
4619         |          option5()
4620         |}
4621         |"""
4622               .trimMargin(),
4623           deduceMaxWidth = true)
4624 
4625   @Test
4626   fun `Elvis operator mixed with plus operator breaking on elvis`() =
4627       assertFormatted(
4628           """
4629         |/////////////////////////////////
4630         |fun f() {
4631         |  return option1()
4632         |      ?: option2() + option3()
4633         |      ?: option4() + option5()
4634         |}
4635         |"""
4636               .trimMargin(),
4637           deduceMaxWidth = true)
4638 
4639   @Test
4640   fun `handle comments in the middle of calling chain`() =
4641       assertFormatted(
4642           """
4643         |///////////////////////////
4644         |fun f() {
4645         |  someObject
4646         |      .letsDoIt()
4647         |      // this is a comment
4648         |      .doItOnce()
4649         |      // this is a comment
4650         |      .doItTwice()
4651         |}
4652         |"""
4653               .trimMargin(),
4654           deduceMaxWidth = true)
4655 
4656   @Test
4657   fun `handle reified types`() =
4658       assertFormatted(
4659           """
4660       |inline fun <reified T> foo(t: T) {
4661       |  println(t)
4662       |}
4663       |
4664       |inline fun <reified in T> foo2(t: T) {
4665       |  println(t)
4666       |}
4667       |"""
4668               .trimMargin())
4669 
4670   @Test
4671   fun `handle suspended types`() =
4672       assertFormatted(
4673           """
4674       |private val reader: suspend (Key) -> Output?
4675       |
4676       |private val delete: (suspend (Key) -> Unit)? = null
4677       |
4678       |inline fun <R> foo(noinline block: suspend () -> R): suspend () -> R
4679       |
4680       |inline fun <R> bar(noinline block: (suspend () -> R)?): (suspend () -> R)?
4681       |"""
4682               .trimMargin())
4683 
4684   @Test
4685   fun `handle simple enum classes`() =
4686       assertFormatted(
4687           """
4688       |enum class BetterBoolean {
4689       |  TRUE,
4690       |  FALSE,
4691       |  FILE_NOT_FOUND,
4692       |}
4693       |"""
4694               .trimMargin())
4695 
4696   @Test
4697   fun `handle enum class with functions`() =
4698       assertFormatted(
4699           """
4700       |enum class BetterBoolean {
4701       |  TRUE,
4702       |  FALSE,
4703       |  FILE_NOT_FOUND;
4704       |
4705       |  fun isGood(): Boolean {
4706       |    return true
4707       |  }
4708       |}
4709       |"""
4710               .trimMargin())
4711 
4712   @Test
4713   fun `handle enum with annotations`() =
4714       assertFormatted(
4715           """
4716       |enum class BetterBoolean {
4717       |  @True TRUE,
4718       |  @False @WhatIsTruth FALSE,
4719       |}
4720       |"""
4721               .trimMargin())
4722 
4723   @Test
4724   fun `handle enum constructor calls`() =
4725       assertFormatted(
4726           """
4727       |enum class BetterBoolean(val name: String, val value: Boolean = true) {
4728       |  TRUE("true"),
4729       |  FALSE("false", false),
4730       |}
4731       |"""
4732               .trimMargin())
4733 
4734   @Test
4735   fun `handle enum entries with body`() =
4736       assertFormatted(
4737           """
4738       |enum class Animal(canWalk: Boolean = true) {
4739       |  DOG {
4740       |    fun speak() = "woof"
4741       |  },
4742       |  FISH(false) {},
4743       |}
4744       |"""
4745               .trimMargin())
4746 
4747   @Test
4748   fun `handle empty enum`() =
4749       assertFormatted(
4750           """
4751       |enum class YTho {}
4752       |"""
4753               .trimMargin())
4754 
4755   @Test
4756   fun `expect enum class`() =
4757       assertFormatted(
4758           """
4759       |expect enum class ExpectedEnum
4760       |"""
4761               .trimMargin())
4762 
4763   @Test
4764   fun `enum without trailing comma`() =
4765       assertFormatted(
4766           """
4767       |enum class Highlander {
4768       |  ONE
4769       |}
4770       |"""
4771               .trimMargin())
4772 
4773   @Test
4774   fun `enum comma and semicolon`() {
4775     assertThatFormatting(
4776             """
4777         |enum class Highlander {
4778         |  ONE,;
4779         |}
4780         |"""
4781                 .trimMargin())
4782         .isEqualTo(
4783             """
4784         |enum class Highlander {
4785         |  ONE,
4786         |}
4787         |"""
4788                 .trimMargin())
4789   }
4790 
4791   @Test
4792   fun `empty enum with semicolons`() {
4793     assertThatFormatting(
4794             """
4795         |enum class Empty {
4796         |  ;
4797         |}
4798         |"""
4799                 .trimMargin())
4800         .isEqualTo(
4801             """
4802         |enum class Empty {}
4803         |"""
4804                 .trimMargin())
4805 
4806     assertThatFormatting(
4807             """
4808         |enum class Empty {
4809         |  ;
4810         |  ;
4811         |  ;
4812         |}
4813         |"""
4814                 .trimMargin())
4815         .isEqualTo(
4816             """
4817         |enum class Empty {}
4818         |"""
4819                 .trimMargin())
4820   }
4821 
4822   @Test
4823   fun `semicolon is placed on next line when there's a trailing comma in an enum declaration`() =
4824       assertFormatted(
4825           """
4826         |enum class Highlander {
4827         |  ONE,
4828         |  TWO,
4829         |  ;
4830         |
4831         |  fun f() {}
4832         |}
4833         |"""
4834               .trimMargin())
4835 
4836   @Test
4837   fun `semicolon is removed from empty enum`() {
4838     val code =
4839         """
4840         |enum class SingleSemi {
4841         |  ;
4842         |}
4843         |
4844         |enum class MultSemi {
4845         |  // a
4846         |  ;
4847         |  // b
4848         |  ;
4849         |  // c
4850         |  ;
4851         |}
4852         |"""
4853             .trimMargin()
4854     val expected =
4855         """
4856         |enum class SingleSemi {}
4857         |
4858         |enum class MultSemi {
4859         |  // a
4860         |
4861         |  // b
4862         |
4863         |  // c
4864         |
4865         |}
4866         |"""
4867             .trimMargin()
4868     assertThatFormatting(code).isEqualTo(expected)
4869   }
4870 
4871   @Test
4872   fun `semicolon management in enum with no entries but other members`() {
4873     val code =
4874         """
4875         |enum class Empty {
4876         |  ;
4877         |
4878         |  fun f() {}
4879         |  ;
4880         |  fun g() {}
4881         |}
4882         |"""
4883             .trimMargin()
4884     val expected =
4885         """
4886         |enum class Empty {
4887         |  ;
4888         |
4889         |  fun f() {}
4890         |
4891         |  fun g() {}
4892         |}
4893         |"""
4894             .trimMargin()
4895     assertThatFormatting(code).isEqualTo(expected)
4896   }
4897 
4898   @Test
4899   fun `handle varargs and spread operator`() =
4900       assertFormatted(
4901           """
4902       |fun foo(vararg args: String) {
4903       |  foo2(*args)
4904       |  foo3(options = *args)
4905       |}
4906       |"""
4907               .trimMargin())
4908 
4909   @Test
4910   fun `handle typealias`() =
4911       assertFormatted(
4912           """
4913       |//////////////////////////////////////////////
4914       |private typealias TextChangedListener =
4915       |    (string: String) -> Unit
4916       |
4917       |typealias PairPair<X, Y> = Pair<Pair<X, Y>, X>
4918       |
4919       |class Foo
4920       |"""
4921               .trimMargin(),
4922           deduceMaxWidth = true)
4923 
4924   @Test
4925   fun `handle the 'dynamic' type`() =
4926       assertFormatted(
4927           """
4928       |fun x(): dynamic = "x"
4929       |
4930       |val dyn: dynamic = 1
4931       |"""
4932               .trimMargin())
4933 
4934   @Test
4935   fun `handle class expression with generics`() =
4936       assertFormatted(
4937           """
4938       |fun f() {
4939       |  println(Array<String>::class.java)
4940       |}
4941       |"""
4942               .trimMargin())
4943 
4944   @Test
4945   fun `ParseError contains correct line and column numbers`() {
4946     val code =
4947         """
4948       |// Foo
4949       |fun good() {
4950       |  //
4951       |}
4952       |
4953       |fn (
4954       |"""
4955             .trimMargin()
4956     try {
4957       Formatter.format(code)
4958       fail()
4959     } catch (e: ParseError) {
4960       assertThat(e.lineColumn.line).isEqualTo(6)
4961       assertThat(e.lineColumn.column).isEqualTo(0)
4962       assertThat(e.errorDescription).contains("Expecting an expression")
4963     }
4964   }
4965 
4966   @Test
4967   fun `fail() reports line+column number`() {
4968     val code =
4969         """
4970       |// Foo
4971       |fun good() {
4972       |  return@ 5
4973       |}
4974       |"""
4975             .trimMargin()
4976     try {
4977       Formatter.format(code)
4978       fail()
4979     } catch (e: ParseError) {
4980       assertThat(e.lineColumn.line).isEqualTo(2)
4981       assertThat(e.lineColumn.column).isEqualTo(8)
4982     }
4983   }
4984 
4985   @Test
4986   fun `annotations on class, fun, parameters and literals`() =
4987       assertFormatted(
4988           """
4989       |@Fancy
4990       |class Foo {
4991       |  @Fancy
4992       |  fun baz(@Fancy foo: Int): Int {
4993       |    return (@Fancy 1)
4994       |  }
4995       |}
4996       |"""
4997               .trimMargin())
4998 
4999   @Test
5000   fun `annotations on function types`() =
5001       assertFormatted(
5002           """
5003       |fun foo(bar: @StringRes Int) {}
5004       |
5005       |fun foo(error: @Composable ((x) -> Unit)) {}
5006       |
5007       |fun foo(error: (@Composable (x) -> Unit)) {}
5008       |
5009       |fun foo(
5010       |    error:
5011       |        @field:[Inject Named("WEB_VIEW")]
5012       |        ((x) -> Unit)
5013       |) {}
5014       |
5015       |fun foo(
5016       |    error:
5017       |        (@field:[Inject Named("WEB_VIEW")]
5018       |        (x) -> Unit)
5019       |) {}
5020       |"""
5021               .trimMargin())
5022 
5023   @Test
5024   fun `handle annotations with use-site targets`() =
5025       assertFormatted(
5026           """
5027       |class FooTest {
5028       |  @get:Rule val exceptionRule: ExpectedException = ExpectedException.none()
5029       |
5030       |  @set:Magic(name = "Jane") var field: String
5031       |}
5032       |"""
5033               .trimMargin())
5034 
5035   @Test
5036   fun `handle annotations mixed with keywords since we cannot reorder them for now`() =
5037       assertFormatted(
5038           """
5039       |public @Magic final class Foo
5040       |
5041       |public @Magic(1) final class Foo
5042       |
5043       |@Magic(1) public final class Foo
5044       |"""
5045               .trimMargin())
5046 
5047   @Test
5048   fun `handle annotations more`() =
5049       assertFormatted(
5050           """
5051       |/////////////////////////////////////////////////
5052       |@Anno1
5053       |@Anno2(param = Param1::class)
5054       |@Anno3
5055       |@Anno4(param = Param2::class)
5056       |class MyClass {}
5057       |
5058       |fun f() {
5059       |  @Suppress("MagicNumber") add(10)
5060       |
5061       |  @Annotation // test a comment after annotations
5062       |  return 5
5063       |}
5064       |"""
5065               .trimMargin(),
5066           deduceMaxWidth = true)
5067 
5068   @Test
5069   fun `annotated expressions`() =
5070       assertFormatted(
5071           """
5072       |////////////////////////////////////////////////
5073       |fun f() {
5074       |  @Suppress("MagicNumber") add(10) && add(20)
5075       |
5076       |  @Suppress("MagicNumber")
5077       |  add(10) && add(20)
5078       |
5079       |  @Anno1 @Anno2(param = Param1::class)
5080       |  add(10) && add(20)
5081       |
5082       |  @Anno1
5083       |  @Anno2(param = Param1::class)
5084       |  @Anno3
5085       |  @Anno4(param = Param2::class)
5086       |  add(10) && add(20)
5087       |
5088       |  @Anno1
5089       |  @Anno2(param = Param1::class)
5090       |  @Anno3
5091       |  @Anno4(param = Param2::class)
5092       |  add(10) && add(20)
5093       |
5094       |  @Suppress("MagicNumber") add(10) &&
5095       |      add(20) &&
5096       |      add(30)
5097       |
5098       |  add(@Suppress("MagicNumber") 10) &&
5099       |      add(20) &&
5100       |      add(30)
5101       |}
5102       |"""
5103               .trimMargin(),
5104           deduceMaxWidth = true)
5105 
5106   @Test
5107   fun `annotated function declarations`() =
5108       assertFormatted(
5109           """
5110       |@Anno
5111       |fun f() {
5112       |  add(10)
5113       |}
5114       |
5115       |@Anno(param = 1)
5116       |fun f() {
5117       |  add(10)
5118       |}
5119       |"""
5120               .trimMargin())
5121 
5122   @Test
5123   fun `annotated class declarations`() =
5124       assertFormatted(
5125           """
5126       |@Anno class F
5127       |
5128       |@Anno(param = 1) class F
5129       |
5130       |@Anno(P)
5131       |// Foo
5132       |@Anno("param")
5133       |class F
5134       |"""
5135               .trimMargin())
5136 
5137   @Test
5138   fun `handle type arguments in annotations`() =
5139       assertFormatted(
5140           """
5141       |@TypeParceler<UUID, UUIDParceler>() class MyClass {}
5142       |"""
5143               .trimMargin())
5144 
5145   @Test
5146   fun `handle one line KDoc`() =
5147       assertFormatted(
5148           """
5149       |/** Hi, I am a one line kdoc */
5150       |class MyClass {}
5151       |"""
5152               .trimMargin())
5153 
5154   @Test
5155   fun `handle KDoc with Link`() =
5156       assertFormatted(
5157           """
5158       |/** This links to [AnotherClass] */
5159       |class MyClass {}
5160       |"""
5161               .trimMargin())
5162 
5163   @Test
5164   fun `handle KDoc with paragraphs`() =
5165       assertFormatted(
5166           """
5167       |/**
5168       | * Hi, I am a two paragraphs kdoc
5169       | *
5170       | * There's a space line to preserve between them
5171       | */
5172       |class MyClass {}
5173       |"""
5174               .trimMargin())
5175 
5176   @Test
5177   fun `handle KDoc with blocks`() =
5178       assertFormatted(
5179           """
5180       |/**
5181       | * Hi, I am a two paragraphs kdoc
5182       | *
5183       | * @param param1 this is param1
5184       | * @param[param2] this is param2
5185       | */
5186       |class MyClass {}
5187       |"""
5188               .trimMargin())
5189 
5190   @Test
5191   fun `handle KDoc with code examples`() =
5192       assertFormatted(
5193           """
5194       |/**
5195       | * This is how you write a simple hello world in Kotlin:
5196       | * ```
5197       | * fun main(args: Array<String>) {
5198       | *   println("Hello World!")
5199       | * }
5200       | * ```
5201       | *
5202       | * Amazing ah?
5203       | *
5204       | * ```
5205       | * fun `code can be with a blank line above it` () {}
5206       | * ```
5207       | *
5208       | * Or after it!
5209       | */
5210       |class MyClass {}
5211       |"""
5212               .trimMargin())
5213 
5214   @Test
5215   fun `handle KDoc with tagged code examples`() =
5216       assertFormatted(
5217           """
5218       |/**
5219       | * ```kotlin
5220       | * fun main(args: Array<String>) {
5221       | *   println("Hello World!")
5222       | * }
5223       | * ```
5224       | */
5225       |class MyClass {}
5226       |"""
5227               .trimMargin())
5228 
5229   @Test
5230   fun `handle stray code markers in lines and produce stable output`() {
5231     val code =
5232         """
5233       |/**
5234       | * Look! code: ``` aaa
5235       | * fun f() = Unit
5236       | * foo
5237       | * ```
5238       | */
5239       |class MyClass {}
5240       |"""
5241             .trimMargin()
5242     assertFormatted(Formatter.format(code))
5243   }
5244 
5245   @Test
5246   fun `code block with triple backtick`() {
5247     val code =
5248         """
5249       |/**
5250       | * Look! code:
5251       | * ```
5252       | * aaa ``` wow
5253       | * ```
5254       | */
5255       |class MyClass {}
5256       |"""
5257             .trimMargin()
5258     val expected =
5259         """
5260       |/**
5261       | * Look! code:
5262       | * ```
5263       | * aaa ``` wow
5264       | * ```
5265       | */
5266       |class MyClass {}
5267       |"""
5268             .trimMargin()
5269     assertThatFormatting(code).isEqualTo(expected)
5270   }
5271 
5272   @Test
5273   fun `when code closer in mid of line, produce stable output`() {
5274     val code =
5275         """
5276       |/**
5277       | * Look! code: ``` aaa
5278       | * fun f() = Unit
5279       | * foo ``` wow
5280       | */
5281       |class MyClass {}
5282       |"""
5283             .trimMargin()
5284     assertFormatted(Formatter.format(code))
5285   }
5286 
5287   @Test
5288   fun `handle KDoc with link reference`() =
5289       assertFormatted(
5290           """
5291       |/** Doc line with a reference to [AnotherClass] in the middle of a sentence */
5292       |class MyClass {}
5293       |"""
5294               .trimMargin())
5295 
5296   @Test
5297   fun `handle KDoc with links one after another`() =
5298       assertFormatted(
5299           """
5300       |/** Here are some links [AnotherClass] [AnotherClass2] */
5301       |class MyClass {}
5302       |"""
5303               .trimMargin())
5304 
5305   @Test
5306   fun `don't add spaces after links in Kdoc`() =
5307       assertFormatted(
5308           """
5309       |/** Here are some links [AnotherClass][AnotherClass2]hello */
5310       |class MyClass {}
5311       |"""
5312               .trimMargin())
5313 
5314   @Test
5315   fun `don't remove spaces after links in Kdoc`() =
5316       assertFormatted(
5317           """
5318       |/** Please see [onNext] (which has more details) */
5319       |class MyClass {}
5320       |"""
5321               .trimMargin())
5322 
5323   @Test
5324   fun `link anchor in KDoc are preserved`() =
5325       assertFormatted(
5326           """
5327       |/** [link anchor](the URL for the link anchor goes here) */
5328       |class MyClass {}
5329       |"""
5330               .trimMargin())
5331 
5332   @Test
5333   fun `don't add spaces between links in KDoc (because they're actually references)`() =
5334       assertFormatted(
5335           """
5336       |/** Here are some links [AnotherClass][AnotherClass2] */
5337       |class MyClass {}
5338       |
5339       |/** The final produced value may have [size][ByteString.size] < [bufferSize]. */
5340       |class MyClass {}
5341       |"""
5342               .trimMargin())
5343 
5344   @Test
5345   fun `collapse spaces after links in KDoc`() {
5346     val code =
5347         """
5348       |/** Here are some links [Class1], [Class2]   [Class3]. hello */
5349       |class MyClass {}
5350       |"""
5351             .trimMargin()
5352     val expected =
5353         """
5354       |/** Here are some links [Class1], [Class2] [Class3]. hello */
5355       |class MyClass {}
5356       |"""
5357             .trimMargin()
5358     assertThatFormatting(code).isEqualTo(expected)
5359   }
5360 
5361   @Test
5362   fun `collapse newlines after links in KDoc`() {
5363     val code =
5364         """
5365       |/**
5366       | * Here are some links [Class1]
5367       | * [Class2]
5368       | */
5369       |class MyClass {}
5370       |"""
5371             .trimMargin()
5372     val expected =
5373         """
5374       |/** Here are some links [Class1] [Class2] */
5375       |class MyClass {}
5376       |"""
5377             .trimMargin()
5378     assertThatFormatting(code).isEqualTo(expected)
5379   }
5380 
5381   @Test
5382   fun `do not crash because of malformed KDocs and produce stable output`() {
5383     val code =
5384         """
5385       |/** Surprise ``` */
5386       |class MyClass {}
5387       |"""
5388             .trimMargin()
5389     assertFormatted(Formatter.format(code))
5390   }
5391 
5392   @Test
5393   fun `Respect spacing of text after link`() =
5394       assertFormatted(
5395           """
5396       |/** Enjoy this link [linkstuff]. */
5397       |class MyClass {}
5398       |
5399       |/** There are many [FooObject]s. */
5400       |class MyClass {}
5401       |"""
5402               .trimMargin())
5403 
5404   @Test
5405   fun `handle KDoc with multiple separated param tags, breaking and merging lines and missing asterisk`() {
5406     val code =
5407         """
5408       |/**
5409       | * Trims leading whitespace characters followed by [marginPrefix] from every line of a source string and removes
5410       | * the first and the last lines if they are blank (notice difference blank vs empty).
5411       |
5412       | * Doesn't affect a line if it doesn't contain [marginPrefix] except the first and the last blank lines.
5413       | *
5414       | * Doesn't preserve the original line endings.
5415       | *
5416       | * @param marginPrefix non-blank string, which is used as a margin delimiter. Default is `|` (pipe character).
5417       | *
5418       | * @sample samples.text.Strings.trimMargin
5419       | * @see trimIndent
5420       | * @see kotlin.text.isWhitespace
5421       | */
5422       |class ThisWasCopiedFromTheTrimMarginMethod {}
5423       |"""
5424             .trimMargin()
5425     val expected =
5426         """
5427       |/**
5428       | * Trims leading whitespace characters followed by [marginPrefix] from every line of a source string
5429       | * and removes the first and the last lines if they are blank (notice difference blank vs empty).
5430       | *
5431       | * Doesn't affect a line if it doesn't contain [marginPrefix] except the first and the last blank
5432       | * lines.
5433       | *
5434       | * Doesn't preserve the original line endings.
5435       | *
5436       | * @param marginPrefix non-blank string, which is used as a margin delimiter. Default is `|` (pipe
5437       | *   character).
5438       | * @sample samples.text.Strings.trimMargin
5439       | * @see trimIndent
5440       | * @see kotlin.text.isWhitespace
5441       | */
5442       |class ThisWasCopiedFromTheTrimMarginMethod {}
5443       |"""
5444             .trimMargin()
5445     assertThatFormatting(code).isEqualTo(expected)
5446   }
5447 
5448   @Test
5449   fun `KDoc is reflowed`() {
5450     val code =
5451         """
5452       |/** Lorem ipsum dolor sit amet, consectetur */
5453       |class MyClass {}
5454       |"""
5455             .trimMargin()
5456     val expected =
5457         """
5458       |/**
5459       | * Lorem ipsum dolor sit amet,
5460       | * consectetur
5461       | */
5462       |class MyClass {}
5463       |"""
5464             .trimMargin()
5465     assertThatFormatting(code)
5466         .withOptions(defaultTestFormattingOptions.copy(maxWidth = 33))
5467         .isEqualTo(expected)
5468   }
5469 
5470   @Test
5471   fun `sanity - block and continuation indents are 4`() {
5472     val code =
5473         """
5474         |fun f() {
5475         |    for (child in
5476         |        node.next.next.next.next
5477         |            .data()) {
5478         |        println(child)
5479         |    }
5480         |}
5481         |"""
5482             .trimMargin()
5483     assertThatFormatting(code)
5484         .withOptions(
5485             FormattingOptions(
5486                 maxWidth = 35,
5487                 blockIndent = 4,
5488                 continuationIndent = 4,
5489                 manageTrailingCommas = false,
5490             ),
5491         )
5492         .isEqualTo(code)
5493   }
5494 
5495   @Test
5496   fun `comment after a block is stable and does not add space lines`() =
5497       assertFormatted(
5498           """
5499       |fun doIt() {}
5500       |
5501       |/* this is the first comment */
5502       |"""
5503               .trimMargin())
5504 
5505   @Test
5506   fun `preserve LF, CRLF and CR line endings`() {
5507     val lines = listOf("fun main() {", "  println(\"test\")", "}")
5508     for (ending in listOf("\n", "\r\n", "\r")) {
5509       val code = lines.joinToString(ending) + ending
5510       assertThatFormatting(code).isEqualTo(code)
5511     }
5512   }
5513 
5514   @Test
5515   fun `handle trailing commas (constructors)`() =
5516       assertFormatted(
5517           """
5518       |////////////////////
5519       |class Foo(
5520       |    a: Int,
5521       |)
5522       |
5523       |class Foo(
5524       |    a: Int,
5525       |    b: Int,
5526       |)
5527       |
5528       |class Foo(
5529       |    a: Int,
5530       |    b: Int
5531       |)
5532       |"""
5533               .trimMargin(),
5534           deduceMaxWidth = true)
5535 
5536   @Test
5537   fun `handle trailing commas (explicit constructors)`() =
5538       assertFormatted(
5539           """
5540       |////////////////////////
5541       |class Foo
5542       |constructor(
5543       |    a: Int,
5544       |)
5545       |
5546       |class Foo
5547       |constructor(
5548       |    a: Int,
5549       |    b: Int,
5550       |)
5551       |
5552       |class Foo
5553       |constructor(
5554       |    a: Int,
5555       |    b: Int
5556       |)
5557       |"""
5558               .trimMargin(),
5559           deduceMaxWidth = true)
5560 
5561   @Test
5562   fun `handle trailing commas (secondary constructors)`() =
5563       assertFormatted(
5564           """
5565       |////////////////////////
5566       |class Foo {
5567       |  constructor(
5568       |      a: Int,
5569       |  )
5570       |}
5571       |
5572       |class Foo {
5573       |  constructor(
5574       |      a: Int,
5575       |      b: Int,
5576       |  )
5577       |}
5578       |
5579       |class Foo {
5580       |  constructor(
5581       |      a: Int,
5582       |      b: Int
5583       |  )
5584       |}
5585       |"""
5586               .trimMargin(),
5587           deduceMaxWidth = true)
5588 
5589   @Test
5590   fun `handle trailing commas (function definitions)`() =
5591       assertFormatted(
5592           """
5593       |////////////////////////
5594       |fun <
5595       |    T,
5596       |> foo() {}
5597       |
5598       |fun <
5599       |    T,
5600       |    S,
5601       |> foo() {}
5602       |
5603       |fun foo(
5604       |    a: Int,
5605       |) {}
5606       |
5607       |fun foo(
5608       |    a: Int,
5609       |    b: Int
5610       |) {}
5611       |
5612       |fun foo(
5613       |    a: Int,
5614       |    b: Int,
5615       |) {}
5616       |
5617       |fun foo(
5618       |    a: Int,
5619       |    b: Int,
5620       |    c: Int,
5621       |) {}
5622       |"""
5623               .trimMargin(),
5624           deduceMaxWidth = true)
5625 
5626   @Test
5627   fun `handle trailing commas (function calls)`() =
5628       assertFormatted(
5629           """
5630       |////////////////////////
5631       |fun main() {
5632       |  foo(
5633       |      3,
5634       |  )
5635       |
5636       |  foo<Int>(
5637       |      3,
5638       |  )
5639       |
5640       |  foo<
5641       |      Int,
5642       |  >(
5643       |      3,
5644       |  )
5645       |
5646       |  foo<Int>(
5647       |      "asdf", "asdf")
5648       |
5649       |  foo<
5650       |      Int,
5651       |  >(
5652       |      "asd",
5653       |      "asd",
5654       |  )
5655       |
5656       |  foo<
5657       |      Int,
5658       |      Boolean,
5659       |  >(
5660       |      3,
5661       |  )
5662       |}
5663       |"""
5664               .trimMargin(),
5665           deduceMaxWidth = true)
5666 
5667   @Test
5668   fun `handle trailing commas (proprties)`() =
5669       assertFormatted(
5670           """
5671       |//////////////////////////
5672       |val foo: String
5673       |  set(
5674       |      value,
5675       |  ) {}
5676       |"""
5677               .trimMargin(),
5678           deduceMaxWidth = true)
5679 
5680   @Test
5681   fun `handle trailing commas (higher-order functions)`() =
5682       assertFormatted(
5683           """
5684       |//////////////////////////
5685       |fun foo(
5686       |    x:
5687       |        (
5688       |            Int,
5689       |        ) -> Unit
5690       |) {}
5691       |"""
5692               .trimMargin(),
5693           deduceMaxWidth = true)
5694 
5695   @Test
5696   fun `handle trailing commas (after lambda arg)`() =
5697       assertFormatted(
5698           """
5699       |//////////////////////////
5700       |fun foo() {
5701       |  foo(
5702       |      { it },
5703       |  )
5704       |}
5705       |"""
5706               .trimMargin(),
5707           deduceMaxWidth = true)
5708 
5709   @Test
5710   fun `handle trailing commas (other)`() =
5711       assertFormatted(
5712           """
5713       |//////////////////////////
5714       |fun main() {
5715       |  val (
5716       |      x: Int,
5717       |  ) = foo()
5718       |  val (
5719       |      x: Int,
5720       |      y: Int,
5721       |  ) = foo()
5722       |
5723       |  val (
5724       |      x: Int,
5725       |  ) = foo(
5726       |      blablablablFoobar,
5727       |      alskdjasld)
5728       |
5729       |  val (
5730       |      x: Int,
5731       |      y: Int,
5732       |  ) = foo(
5733       |      blablablablFoobar,
5734       |      asldkalsd)
5735       |
5736       |  a[
5737       |      0,
5738       |  ] = 43
5739       |  a[
5740       |      0,
5741       |      1,
5742       |  ] = 43
5743       |
5744       |  [
5745       |      0,
5746       |  ]
5747       |  [
5748       |      0,
5749       |      1,
5750       |  ]
5751       |
5752       |  when (foo) {
5753       |    'x', -> 43
5754       |    'x',
5755       |    'y', -> 43
5756       |    'x',
5757       |    'y',
5758       |    'z',
5759       |    'w',
5760       |    'a',
5761       |    'b', -> 43
5762       |  }
5763       |
5764       |  try {
5765       |    //
5766       |  } catch (e: Error,) {
5767       |    //
5768       |  }
5769       |}
5770       |"""
5771               .trimMargin(),
5772           deduceMaxWidth = true)
5773 
5774   @Test
5775   fun `assignment of a scoping function`() =
5776       assertFormatted(
5777           """
5778       |////////////////////////////
5779       |val foo = coroutineScope {
5780       |  foo()
5781       |  //
5782       |}
5783       |
5784       |fun foo() = coroutineScope {
5785       |  foo()
5786       |  //
5787       |}
5788       |
5789       |fun foo() = use { x ->
5790       |  foo()
5791       |  //
5792       |}
5793       |
5794       |fun foo() = scope label@{
5795       |  foo()
5796       |  //
5797       |}
5798       |
5799       |fun foo() =
5800       |    coroutineScope { x ->
5801       |      foo()
5802       |      //
5803       |    }
5804       |
5805       |fun foo() =
5806       |    coroutineScope label@{
5807       |      foo()
5808       |      //
5809       |    }
5810       |
5811       |fun foo() =
5812       |    Runnable @Px {
5813       |      foo()
5814       |      //
5815       |    }
5816       |
5817       |fun longName() =
5818       |    coroutineScope {
5819       |      foo()
5820       |      //
5821       |    }
5822       |"""
5823               .trimMargin(),
5824           deduceMaxWidth = true)
5825 
5826   @Test
5827   fun `top level properties with other types preserve newline spacing`() {
5828     assertFormatted(
5829         """
5830       |/////////////////////////////////
5831       |fun something() {
5832       |  println("hi")
5833       |}
5834       |
5835       |const val SOME_CONST = 1
5836       |val SOME_STR = "hi"
5837       |// Single comment
5838       |val SOME_INT = 1
5839       |
5840       |// Intentional space above single comment
5841       |val SOME_INT2 = 1
5842       |
5843       |val FOO = 2
5844       |const val BAR = 3
5845       |
5846       |fun baz() = 1
5847       |
5848       |val d = 1
5849       |
5850       |class Bar {}
5851       |
5852       |val e = 1
5853       |/** Doc block */
5854       |val f = 1
5855       |
5856       |/** Intent. space above doc */
5857       |val g = 1
5858       |
5859       |data class Qux(val foo: String)
5860       |"""
5861             .trimMargin(),
5862         deduceMaxWidth = true)
5863 
5864     assertThatFormatting(
5865             """
5866       |import com.example.foo
5867       |import com.example.bar
5868       |const val SOME_CONST = foo.a
5869       |val SOME_STR = bar.a
5870       |"""
5871                 .trimMargin())
5872         .isEqualTo(
5873             """
5874       |import com.example.bar
5875       |import com.example.foo
5876       |
5877       |const val SOME_CONST = foo.a
5878       |val SOME_STR = bar.a
5879       |"""
5880                 .trimMargin())
5881   }
5882 
5883   @Test
5884   fun `first line is never empty`() =
5885       assertThatFormatting(
5886               """
5887       |
5888       |fun f() {}
5889       |"""
5890                   .trimMargin())
5891           .isEqualTo(
5892               """
5893       |fun f() {}
5894       |"""
5895                   .trimMargin())
5896 
5897   @Test
5898   fun `at most one newline between any adjacent top-level elements`() =
5899       assertThatFormatting(
5900               """
5901       |import com.Bar
5902       |
5903       |
5904       |import com.Foo
5905       |
5906       |
5907       |fun f() {}
5908       |
5909       |
5910       |fun f() {}
5911       |
5912       |
5913       |class C {}
5914       |
5915       |
5916       |class C {}
5917       |
5918       |
5919       |val x = Foo()
5920       |
5921       |
5922       |val x = Bar()
5923       |"""
5924                   .trimMargin())
5925           .isEqualTo(
5926               """
5927       |import com.Bar
5928       |import com.Foo
5929       |
5930       |fun f() {}
5931       |
5932       |fun f() {}
5933       |
5934       |class C {}
5935       |
5936       |class C {}
5937       |
5938       |val x = Foo()
5939       |
5940       |val x = Bar()
5941       |"""
5942                   .trimMargin())
5943 
5944   @Test
5945   fun `at least one newline between any adjacent top-level elements, unless it's a property`() =
5946       assertThatFormatting(
5947               """
5948       |import com.Bar
5949       |import com.Foo
5950       |fun f() {}
5951       |fun f() {}
5952       |class C {}
5953       |class C {}
5954       |val x = Foo()
5955       |val x = Bar()
5956       |"""
5957                   .trimMargin())
5958           .isEqualTo(
5959               """
5960       |import com.Bar
5961       |import com.Foo
5962       |
5963       |fun f() {}
5964       |
5965       |fun f() {}
5966       |
5967       |class C {}
5968       |
5969       |class C {}
5970       |
5971       |val x = Foo()
5972       |val x = Bar()
5973       |"""
5974                   .trimMargin())
5975 
5976   @Test
5977   fun `handle array of annotations with field prefix`() {
5978     val code: String =
5979         """
5980     |class MyClass {
5981     |  @field:[JvmStatic Volatile]
5982     |  var myVar: String? = null
5983     |}
5984     |
5985     """
5986             .trimMargin()
5987     assertThatFormatting(code).isEqualTo(code)
5988   }
5989 
5990   @Test
5991   fun `handle array of annotations without field prefix`() {
5992     val code: String =
5993         """
5994     |class MyClass {
5995     |  @[JvmStatic Volatile]
5996     |  var myVar: String? = null
5997     |}
5998     |
5999     """
6000             .trimMargin()
6001     assertThatFormatting(code).isEqualTo(code)
6002   }
6003 
6004   // Regression test against https://github.com/facebook/ktfmt/issues/243
6005   @Test
6006   fun `regression test against Issue 243`() {
6007     val code =
6008         """
6009       |class Foo {
6010       |  companion object {
6011       |    var instance: Foo? = null
6012       |
6013       |    fun getInstance() {
6014       |      return instance ?: synchronized(Foo::class) {
6015       |        Foo().also { instance = it }
6016       |      }
6017       |    }
6018       |  }
6019       |}
6020       |"""
6021             .trimMargin()
6022 
6023     // Don't throw.
6024     Formatter.format(code)
6025   }
6026 
6027   @Test
6028   fun `lambda with required arrow`() =
6029       assertFormatted(
6030           """
6031       |val a = { x: Int -> }
6032       |val b = { x: Int -> 0 }
6033       |val c = { x: Int ->
6034       |  val y = 0
6035       |  y
6036       |}
6037       |"""
6038               .trimMargin())
6039 
6040   @Test
6041   fun `lambda with optional arrow`() =
6042       assertFormatted(
6043           """
6044       |val a = { -> }
6045       |val b = { -> 0 }
6046       |val c = { ->
6047       |  val y = 0
6048       |  y
6049       |}
6050       |"""
6051               .trimMargin())
6052 
6053   @Test
6054   fun `lambda missing optional arrow`() =
6055       assertFormatted(
6056           """
6057       |val a = {}
6058       |val b = { 0 }
6059       |val c = {
6060       |  val y = 0
6061       |  y
6062       |}
6063       |"""
6064               .trimMargin())
6065 
6066   @Test
6067   fun `lambda with only comments`() {
6068     assertFormatted(
6069         """
6070         |val a = { /* do nothing */ }
6071         |val b = { /* do nothing */ /* also do nothing */ }
6072         |val c = { -> /* do nothing */ }
6073         |val d = { _ -> /* do nothing */ }
6074         |private val e = Runnable {
6075         |  // do nothing
6076         |}
6077         |private val f: () -> Unit = {
6078         |  // no-op
6079         |}
6080         |private val g: () -> Unit = { /* no-op */ }
6081         |"""
6082             .trimMargin())
6083 
6084     assertFormatted(
6085         """
6086         |//////////////////////////////
6087         |val a = { /* do nothing */ }
6088         |val b =
6089         |    { /* do nothing */ /* also do nothing */
6090         |    }
6091         |val c = { -> /* do nothing */
6092         |}
6093         |val d =
6094         |    { _ -> /* do nothing */
6095         |    }
6096         |private val e = Runnable {
6097         |  // do nothing
6098         |}
6099         |private val f: () -> Unit = {
6100         |  // no-op
6101         |}
6102         |private val g: () -> Unit =
6103         |    { /* no-op */
6104         |    }
6105         |"""
6106             .trimMargin(),
6107         deduceMaxWidth = true)
6108   }
6109 
6110   @Test
6111   fun `lambda block with single and multiple statements`() =
6112       assertFormatted(
6113           """
6114       |private val a = Runnable {
6115       |  foo()
6116       |  TODO("implement me")
6117       |}
6118       |
6119       |private val b = Runnable { TODO("implement me") }
6120       |
6121       |private val c: () -> Unit = {
6122       |  foo()
6123       |  TODO("implement me")
6124       |}
6125       |
6126       |private val d: () -> Unit = { TODO("implement me") }
6127       |"""
6128               .trimMargin())
6129 
6130   @Test
6131   fun `lambda block with comments and statements mix`() =
6132       assertFormatted(
6133           """
6134       |private val a = Runnable {
6135       |  // no-op
6136       |  TODO("implement me")
6137       |}
6138       |
6139       |private val b = Runnable {
6140       |  TODO("implement me")
6141       |  // no-op
6142       |}
6143       |
6144       |private val c: () -> Unit = {
6145       |  /* no-op */ TODO("implement me")
6146       |}
6147       |
6148       |private val d: () -> Unit = { ->
6149       |  /* no-op */ TODO("implement me")
6150       |}
6151       |
6152       |private val e: (String, Int) -> Unit = { _, i -> foo(i) /* do nothing ... */ }
6153       |"""
6154               .trimMargin())
6155 
6156   @Test
6157   fun `lambda block with comments and with statements have same formatting treatment`() =
6158       assertFormatted(
6159           """
6160       |private val a = Runnable { /* no-op */ }
6161       |private val A = Runnable { TODO("...") }
6162       |
6163       |private val b = Runnable {
6164       |  /* no-op 1 */
6165       |  /* no-op 2 */
6166       |}
6167       |private val B = Runnable {
6168       |  TODO("no-op")
6169       |  TODO("no-op")
6170       |}
6171       |
6172       |private val c: () -> Unit = {
6173       |  /* no-op */
6174       |}
6175       |private val C: () -> Unit = { TODO("...") }
6176       |
6177       |private val d: () -> Unit = {
6178       |  /*.*/
6179       |  /* do nothing ... */
6180       |}
6181       |private val D: () -> Unit = {
6182       |  foo()
6183       |  TODO("implement me")
6184       |}
6185       |"""
6186               .trimMargin())
6187 
6188   @Test
6189   fun `last parameter with comment and with statements have same formatting treatment`() {
6190     assertFormatted(
6191         """
6192         |private val a =
6193         |    call(param) {
6194         |      // no-op
6195         |      /* comment */
6196         |    }
6197         |private val A =
6198         |    call(param) {
6199         |      a.run()
6200         |      TODO("implement me")
6201         |    }
6202         |
6203         |private val b = call(param) { /* no-op */ }
6204         |private val B = call(param) { TODO("implement me") }
6205         |
6206         |private val c = firstCall().prop.call(param) { /* no-op */ }
6207         |private val C = firstCall().prop.call(param) { TODO("implement me") }
6208         |"""
6209             .trimMargin())
6210 
6211     assertFormatted(
6212         """
6213         |////////////////////////////////////////
6214         |private val a =
6215         |    firstCall().prop.call(
6216         |        mySuperInterestingParameter) {
6217         |          /* no-op */
6218         |        }
6219         |private val A =
6220         |    firstCall().prop.call(
6221         |        mySuperInterestingParameter) {
6222         |          TODO("...")
6223         |        }
6224         |
6225         |fun b() {
6226         |  myProp.funCall(param) { /* 12345 */ }
6227         |  myProp.funCall(param) { TODO("123") }
6228         |
6229         |  myProp.funCall(param) { /* 123456 */ }
6230         |  myProp.funCall(param) { TODO("1234") }
6231         |
6232         |  myProp.funCall(param) { /* 1234567 */
6233         |  }
6234         |  myProp.funCall(param) {
6235         |    TODO("12345")
6236         |  }
6237         |
6238         |  myProp.funCall(param) { /* 12345678 */
6239         |  }
6240         |  myProp.funCall(param) {
6241         |    TODO("123456")
6242         |  }
6243         |
6244         |  myProp.funCall(
6245         |      param) { /* 123456789 */
6246         |      }
6247         |  myProp.funCall(param) {
6248         |    TODO("1234567")
6249         |  }
6250         |
6251         |  myProp.funCall(
6252         |      param) { /* very_very_long_comment_that_should_go_on_its_own_line */
6253         |      }
6254         |  myProp.funCall(param) {
6255         |    TODO(
6256         |        "_a_very_long_comment_that_should_go_on_its_own_line")
6257         |  }
6258         |}
6259         |
6260         |private val c =
6261         |    firstCall().prop.call(param) {
6262         |      /* no-op */
6263         |    }
6264         |private val C =
6265         |    firstCall().prop.call(param) {
6266         |      TODO("...")
6267         |    }
6268         |"""
6269             .trimMargin(),
6270         deduceMaxWidth = true)
6271   }
6272 
6273   @Test
6274   fun `chaining - many dereferences`() =
6275       assertFormatted(
6276           """
6277       |/////////////////////////
6278       |rainbow.red.orange.yellow
6279       |    .green
6280       |    .blue
6281       |    .indigo
6282       |    .violet
6283       |    .cyan
6284       |    .magenta
6285       |    .key
6286       |"""
6287               .trimMargin(),
6288           deduceMaxWidth = true)
6289 
6290   @Test
6291   fun `chaining - many dereferences, fit on one line`() =
6292       assertFormatted(
6293           """
6294       |///////////////////////////////////////////////////////////////////////////
6295       |rainbow.red.orange.yellow.green.blue.indigo.violet.cyan.magenta.key
6296       |"""
6297               .trimMargin(),
6298           deduceMaxWidth = true)
6299 
6300   @Test
6301   fun `chaining - many dereferences, one invocation at end`() =
6302       assertFormatted(
6303           """
6304       |/////////////////////////
6305       |rainbow.red.orange.yellow
6306       |    .green
6307       |    .blue
6308       |    .indigo
6309       |    .violet
6310       |    .cyan
6311       |    .magenta
6312       |    .key
6313       |    .build()
6314       |"""
6315               .trimMargin(),
6316           deduceMaxWidth = true)
6317 
6318   @Test
6319   fun `chaining - many dereferences, one invocation at end, fit on one line`() =
6320       assertFormatted(
6321           """
6322       |///////////////////////////////////////////////////////////////////////////
6323       |rainbow.red.orange.yellow.green.blue.indigo.violet.cyan.magenta.key.build()
6324       |"""
6325               .trimMargin(),
6326           deduceMaxWidth = true)
6327 
6328   @Test
6329   fun `chaining - many dereferences, two invocations at end`() =
6330       assertFormatted(
6331           """
6332       |/////////////////////////
6333       |rainbow.red.orange.yellow
6334       |    .green
6335       |    .blue
6336       |    .indigo
6337       |    .violet
6338       |    .cyan
6339       |    .magenta
6340       |    .key
6341       |    .build()
6342       |    .shine()
6343       |"""
6344               .trimMargin(),
6345           deduceMaxWidth = true)
6346 
6347   @Test
6348   fun `chaining - many dereferences, one invocation in the middle`() =
6349       assertFormatted(
6350           """
6351       |/////////////////////////
6352       |rainbow.red.orange.yellow
6353       |    .green
6354       |    .blue
6355       |    .shine()
6356       |    .indigo
6357       |    .violet
6358       |    .cyan
6359       |    .magenta
6360       |    .key
6361       |"""
6362               .trimMargin(),
6363           deduceMaxWidth = true)
6364 
6365   @Test
6366   fun `chaining - many dereferences, two invocations in the middle`() =
6367       assertFormatted(
6368           """
6369       |/////////////////////////
6370       |rainbow.red.orange.yellow
6371       |    .green
6372       |    .blue
6373       |    .indigo
6374       |    .shine()
6375       |    .bright()
6376       |    .violet
6377       |    .cyan
6378       |    .magenta
6379       |    .key
6380       |"""
6381               .trimMargin(),
6382           deduceMaxWidth = true)
6383 
6384   @Test
6385   fun `chaining - many dereferences, one lambda at end`() =
6386       assertFormatted(
6387           """
6388       |/////////////////////////
6389       |rainbow.red.orange.yellow
6390       |    .green
6391       |    .blue
6392       |    .indigo
6393       |    .violet
6394       |    .cyan
6395       |    .magenta
6396       |    .key
6397       |    .build { it.appear }
6398       |"""
6399               .trimMargin(),
6400           deduceMaxWidth = true)
6401 
6402   @Test
6403   fun `chaining - many dereferences, one short lambda at end`() =
6404       assertFormatted(
6405           """
6406       |/////////////////////////
6407       |rainbow.red.orange.yellow
6408       |    .green
6409       |    .blue
6410       |    .indigo
6411       |    .violet
6412       |    .cyan
6413       |    .magenta
6414       |    .key
6415       |    .z { it }
6416       |"""
6417               .trimMargin(),
6418           deduceMaxWidth = true)
6419 
6420   @Test
6421   fun `chaining - many dereferences, one multiline lambda at end`() =
6422       assertFormatted(
6423           """
6424       |/////////////////////////
6425       |rainbow.red.orange.yellow
6426       |    .green
6427       |    .blue
6428       |    .indigo
6429       |    .violet
6430       |    .cyan
6431       |    .magenta
6432       |    .key
6433       |    .z {
6434       |      it
6435       |      it
6436       |    }
6437       |"""
6438               .trimMargin(),
6439           deduceMaxWidth = true)
6440 
6441   @Test
6442   fun `chaining - many dereferences, one short lambda in the middle`() =
6443       assertFormatted(
6444           """
6445       |/////////////////////////
6446       |rainbow.red.orange.yellow
6447       |    .green
6448       |    .blue
6449       |    .z { it }
6450       |    .indigo
6451       |    .violet
6452       |    .cyan
6453       |    .magenta
6454       |    .key
6455       |"""
6456               .trimMargin(),
6457           deduceMaxWidth = true)
6458 
6459   @Test
6460   fun `chaining - many dereferences, one multiline lambda in the middle`() =
6461       assertFormatted(
6462           """
6463       |/////////////////////////
6464       |rainbow.red.orange.yellow
6465       |    .green
6466       |    .blue
6467       |    .z {
6468       |      it
6469       |      it
6470       |    }
6471       |    .indigo
6472       |    .violet
6473       |    .cyan
6474       |    .magenta
6475       |    .key
6476       |"""
6477               .trimMargin(),
6478           deduceMaxWidth = true)
6479 
6480   @Test
6481   fun `chaining - many dereferences, one multiline lambda in the middle, remainder could fit on one line`() =
6482       assertFormatted(
6483           """
6484       |/////////////////////////////////////////////////////////////////////////////////////////
6485       |rainbow.red.orange.yellow.green.blue
6486       |    .z {
6487       |      it
6488       |      it
6489       |    }
6490       |    .indigo
6491       |    .violet
6492       |    .cyan
6493       |    .magenta
6494       |    .key
6495       |"""
6496               .trimMargin(),
6497           deduceMaxWidth = true)
6498 
6499   @Test
6500   fun `chaining - many dereferences, one multiline lambda and two invocations in the middle, remainder could fit on one line`() =
6501       assertFormatted(
6502           """
6503       |/////////////////////////////////////////////////////////////////////////////////////////
6504       |rainbow.red.orange.yellow.green.blue
6505       |    .z {
6506       |      it
6507       |      it
6508       |    }
6509       |    .shine()
6510       |    .bright()
6511       |    .indigo
6512       |    .violet
6513       |    .cyan
6514       |    .magenta
6515       |    .key
6516       |"""
6517               .trimMargin(),
6518           deduceMaxWidth = true)
6519 
6520   @Test
6521   fun `chaining - many dereferences, one lambda and invocation at end`() =
6522       assertFormatted(
6523           """
6524       |/////////////////////////
6525       |rainbow.red.orange.yellow
6526       |    .green
6527       |    .blue
6528       |    .indigo
6529       |    .violet
6530       |    .cyan
6531       |    .magenta
6532       |    .key
6533       |    .z { it }
6534       |    .shine()
6535       |"""
6536               .trimMargin(),
6537           deduceMaxWidth = true)
6538 
6539   @Test
6540   fun `chaining - many dereferences, one multiline lambda and invocation at end`() =
6541       assertFormatted(
6542           """
6543       |/////////////////////////
6544       |rainbow.red.orange.yellow
6545       |    .green
6546       |    .blue
6547       |    .indigo
6548       |    .violet
6549       |    .cyan
6550       |    .magenta
6551       |    .key
6552       |    .z {
6553       |      it
6554       |      it
6555       |    }
6556       |    .shine()
6557       |"""
6558               .trimMargin(),
6559           deduceMaxWidth = true)
6560 
6561   @Test
6562   fun `chaining - many dereferences, one invocation and lambda at end`() =
6563       assertFormatted(
6564           """
6565       |/////////////////////////
6566       |rainbow.red.orange.yellow
6567       |    .green
6568       |    .blue
6569       |    .indigo
6570       |    .violet
6571       |    .cyan
6572       |    .magenta
6573       |    .key
6574       |    .shine()
6575       |    .z { it }
6576       |"""
6577               .trimMargin(),
6578           deduceMaxWidth = true)
6579 
6580   @Test
6581   fun `chaining - many dereferences, one short lambda and invocation in the middle`() =
6582       assertFormatted(
6583           """
6584       |/////////////////////////
6585       |rainbow.red.orange.yellow
6586       |    .green
6587       |    .blue
6588       |    .indigo
6589       |    .z { it }
6590       |    .shine()
6591       |    .violet
6592       |    .cyan
6593       |    .magenta
6594       |    .key
6595       |"""
6596               .trimMargin(),
6597           deduceMaxWidth = true)
6598 
6599   @Test
6600   fun `chaining - many dereferences, invocation and one short lambda in the middle`() =
6601       assertFormatted(
6602           """
6603       |/////////////////////////
6604       |rainbow.red.orange.yellow
6605       |    .green
6606       |    .blue
6607       |    .indigo
6608       |    .shine()
6609       |    .z { it }
6610       |    .violet
6611       |    .cyan
6612       |    .magenta
6613       |    .key
6614       |"""
6615               .trimMargin(),
6616           deduceMaxWidth = true)
6617 
6618   @Test
6619   fun `chaining - many dereferences, starting with this`() =
6620       assertFormatted(
6621           """
6622       |/////////////////////////
6623       |this.red.orange.yellow
6624       |    .green
6625       |    .blue
6626       |    .indigo
6627       |    .violet
6628       |    .cyan
6629       |    .magenta
6630       |    .key
6631       |"""
6632               .trimMargin(),
6633           deduceMaxWidth = true)
6634 
6635   @Test
6636   fun `chaining - many dereferences, starting with this, one invocation at end`() =
6637       assertFormatted(
6638           """
6639       |/////////////////////////
6640       |this.red.orange.yellow
6641       |    .green
6642       |    .blue
6643       |    .indigo
6644       |    .violet
6645       |    .cyan
6646       |    .magenta
6647       |    .key
6648       |    .build()
6649       |"""
6650               .trimMargin(),
6651           deduceMaxWidth = true)
6652 
6653   @Test
6654   fun `chaining - many dereferences, starting with super`() =
6655       assertFormatted(
6656           """
6657       |/////////////////////////
6658       |super.red.orange.yellow
6659       |    .green
6660       |    .blue
6661       |    .indigo
6662       |    .violet
6663       |    .cyan
6664       |    .magenta
6665       |    .key
6666       |"""
6667               .trimMargin(),
6668           deduceMaxWidth = true)
6669 
6670   @Test
6671   fun `chaining - many dereferences, starting with super, one invocation at end`() =
6672       assertFormatted(
6673           """
6674       |/////////////////////////
6675       |super.red.orange.yellow
6676       |    .green
6677       |    .blue
6678       |    .indigo
6679       |    .violet
6680       |    .cyan
6681       |    .magenta
6682       |    .key
6683       |    .build()
6684       |"""
6685               .trimMargin(),
6686           deduceMaxWidth = true)
6687 
6688   @Test
6689   fun `chaining - many dereferences, starting with short variable`() =
6690       assertFormatted(
6691           """
6692       |/////////////////////////
6693       |z123.red.orange.yellow
6694       |    .green
6695       |    .blue
6696       |    .indigo
6697       |    .violet
6698       |    .cyan
6699       |    .magenta
6700       |    .key
6701       |"""
6702               .trimMargin(),
6703           deduceMaxWidth = true)
6704 
6705   @Test
6706   fun `chaining - many dereferences, starting with short variable, one invocation at end`() =
6707       assertFormatted(
6708           """
6709       |/////////////////////////
6710       |z123.red.orange.yellow
6711       |    .green
6712       |    .blue
6713       |    .indigo
6714       |    .violet
6715       |    .cyan
6716       |    .magenta
6717       |    .key
6718       |    .build()
6719       |"""
6720               .trimMargin(),
6721           deduceMaxWidth = true)
6722 
6723   @Test
6724   fun `chaining - many dereferences, starting with short variable and lambda, invocation at end`() =
6725       assertFormatted(
6726           """
6727       |/////////////////////////
6728       |z12.z { it }
6729       |    .red
6730       |    .orange
6731       |    .yellow
6732       |    .green
6733       |    .blue
6734       |    .indigo
6735       |    .violet
6736       |    .cyan
6737       |    .magenta
6738       |    .key
6739       |    .shine()
6740       |"""
6741               .trimMargin(),
6742           deduceMaxWidth = true)
6743 
6744   @Test
6745   fun `chaining - many dereferences, starting with this and lambda, invocation at end`() =
6746       assertFormatted(
6747           """
6748       |/////////////////////////
6749       |this.z { it }
6750       |    .red
6751       |    .orange
6752       |    .yellow
6753       |    .green
6754       |    .blue
6755       |    .indigo
6756       |    .violet
6757       |    .cyan
6758       |    .magenta
6759       |    .key
6760       |    .shine()
6761       |"""
6762               .trimMargin(),
6763           deduceMaxWidth = true)
6764 
6765   @Test
6766   fun `chaining - many invocations`() =
6767       assertFormatted(
6768           """
6769       |/////////////////////////
6770       |rainbow.a().b().c()
6771       |"""
6772               .trimMargin(),
6773           deduceMaxWidth = true)
6774 
6775   @Test
6776   fun `chaining - many invocations, with multiline lambda at end`() =
6777       assertFormatted(
6778           """
6779       |/////////////////////////
6780       |rainbow.a().b().c().zz {
6781       |  it
6782       |  it
6783       |}
6784       |"""
6785               .trimMargin(),
6786           deduceMaxWidth = true)
6787 
6788   @Test
6789   fun `chaining - many dereferences, starting type name`() =
6790       assertFormatted(
6791           """
6792       |/////////////////////////
6793       |com.sky.Rainbow.red
6794       |    .orange
6795       |    .yellow
6796       |    .green
6797       |    .blue
6798       |    .indigo
6799       |    .violet
6800       |    .cyan
6801       |    .magenta
6802       |    .key
6803       |"""
6804               .trimMargin(),
6805           deduceMaxWidth = true)
6806 
6807   @Test
6808   fun `chaining - many invocations, starting with short variable, lambda at end`() =
6809       assertFormatted(
6810           """
6811       |/////////////
6812       |z12.shine()
6813       |    .bright()
6814       |    .z { it }
6815       |"""
6816               .trimMargin(),
6817           deduceMaxWidth = true)
6818 
6819   @Test
6820   fun `chaining - start with invocation, lambda at end`() =
6821       assertFormatted(
6822           """
6823       |/////////////////////
6824       |getRainbow(
6825       |        aa, bb, cc)
6826       |    .z { it }
6827       |"""
6828               .trimMargin(),
6829           deduceMaxWidth = true)
6830 
6831   @Test
6832   fun `chaining - many invocations, start with lambda`() =
6833       assertFormatted(
6834           """
6835       |/////////////////////
6836       |z { it }
6837       |    .shine()
6838       |    .bright()
6839       |"""
6840               .trimMargin(),
6841           deduceMaxWidth = true)
6842 
6843   @Test
6844   fun `chaining - start with type name, end with invocation`() =
6845       assertFormatted(
6846           """
6847       |/////////////////////////
6848       |com.sky.Rainbow
6849       |    .colorFactory
6850       |    .build()
6851       |"""
6852               .trimMargin(),
6853           deduceMaxWidth = true)
6854 
6855   @Test
6856   fun `chaining (indentation) - multiline lambda`() =
6857       assertFormatted(
6858           """
6859       |/////////////////////////
6860       |rainbow.z {
6861       |  it
6862       |  it
6863       |}
6864       |"""
6865               .trimMargin(),
6866           deduceMaxWidth = true)
6867 
6868   @Test
6869   fun `chaining (indentation) - multiline lambda with trailing dereferences`() =
6870       assertFormatted(
6871           """
6872       |/////////////////////////
6873       |rainbow
6874       |    .z {
6875       |      it
6876       |      it
6877       |    }
6878       |    .red
6879       |"""
6880               .trimMargin(),
6881           deduceMaxWidth = true)
6882 
6883   @Test
6884   fun `chaining (indentation) - multiline lambda with long name`() =
6885       assertFormatted(
6886           """
6887       |/////////////////////////
6888       |rainbow
6889       |    .someLongLambdaName {
6890       |      it
6891       |      it
6892       |    }
6893       |"""
6894               .trimMargin(),
6895           deduceMaxWidth = true)
6896 
6897   @Test
6898   fun `chaining (indentation) - multiline lambda with long name and trailing dereferences`() =
6899       assertFormatted(
6900           """
6901       |/////////////////////////
6902       |rainbow
6903       |    .someLongLambdaName {
6904       |      it
6905       |      it
6906       |    }
6907       |    .red
6908       |"""
6909               .trimMargin(),
6910           deduceMaxWidth = true)
6911 
6912   @Test
6913   fun `chaining (indentation) - multiline lambda with prefix`() =
6914       assertFormatted(
6915           """
6916       |/////////////////////////
6917       |rainbow.red.z {
6918       |  it
6919       |  it
6920       |}
6921       |"""
6922               .trimMargin(),
6923           deduceMaxWidth = true)
6924 
6925   @Test
6926   fun `chaining (indentation) - multiline lambda with prefix, forced to next line`() =
6927       assertFormatted(
6928           """
6929       |/////////////////////////
6930       |rainbow.red.orange.yellow
6931       |    .longLambdaName {
6932       |      it
6933       |      it
6934       |    }
6935       |"""
6936               .trimMargin(),
6937           deduceMaxWidth = true)
6938 
6939   @Test
6940   fun `chaining (indentation) - multiline lambda with prefix, forced to next line with another expression`() =
6941       assertFormatted(
6942           """
6943       |/////////////////////////
6944       |rainbow.red.orange.yellow
6945       |    .key
6946       |    .longLambdaName {
6947       |      it
6948       |      it
6949       |    }
6950       |"""
6951               .trimMargin(),
6952           deduceMaxWidth = true)
6953 
6954   @Test
6955   fun `chaining (indentation) - multiline arguments`() =
6956       assertFormatted(
6957           """
6958       |/////////////////////////
6959       |rainbow.shine(
6960       |    infrared,
6961       |    ultraviolet,
6962       |)
6963       |"""
6964               .trimMargin(),
6965           deduceMaxWidth = true)
6966 
6967   @Test
6968   fun `chaining (indentation) - multiline arguments with trailing dereferences`() =
6969       assertFormatted(
6970           """
6971       |/////////////////////////
6972       |rainbow
6973       |    .shine(
6974       |        infrared,
6975       |        ultraviolet,
6976       |    )
6977       |    .red
6978       |"""
6979               .trimMargin(),
6980           deduceMaxWidth = true)
6981 
6982   @Test
6983   fun `chaining (indentation) - multiline arguments, forced to next line`() =
6984       assertFormatted(
6985           """
6986       |/////////////////////////
6987       |rainbow.red.orange.yellow
6988       |    .shine(
6989       |        infrared,
6990       |        ultraviolet,
6991       |    )
6992       |"""
6993               .trimMargin(),
6994           deduceMaxWidth = true)
6995 
6996   @Test
6997   fun `chaining (indentation) - multiline arguments, forced to next line with another expression`() =
6998       assertFormatted(
6999           """
7000       |/////////////////////////
7001       |rainbow.red.orange.yellow
7002       |    .key
7003       |    .shine(
7004       |        infrared,
7005       |        ultraviolet,
7006       |    )
7007       |"""
7008               .trimMargin(),
7009           deduceMaxWidth = true)
7010 
7011   @Test
7012   fun `chaining (indentation) - multiline arguments, forced to next line with another expression, with trailing dereferences`() =
7013       assertFormatted(
7014           """
7015       |/////////////////////////
7016       |rainbow.red.orange.yellow
7017       |    .key
7018       |    .shine(
7019       |        infrared,
7020       |        ultraviolet,
7021       |    )
7022       |    .red
7023       |"""
7024               .trimMargin(),
7025           deduceMaxWidth = true)
7026 
7027   @Test
7028   fun `chaining (indentation) - multiline arguments, with trailing invocation`() =
7029       assertFormatted(
7030           """
7031       |/////////////////////////
7032       |rainbow
7033       |    .shine(
7034       |        infrared,
7035       |        ultraviolet,
7036       |    )
7037       |    .bright()
7038       |"""
7039               .trimMargin(),
7040           deduceMaxWidth = true)
7041 
7042   @Test
7043   fun `chaining (indentation) - multiline arguments, with trailing lambda`() =
7044       assertFormatted(
7045           """
7046       |/////////////////////////
7047       |rainbow
7048       |    .shine(
7049       |        infrared,
7050       |        ultraviolet,
7051       |    )
7052       |    .z { it }
7053       |"""
7054               .trimMargin(),
7055           deduceMaxWidth = true)
7056 
7057   @Test
7058   fun `chaining (indentation) - multiline arguments, prefixed with super, with trailing invocation`() =
7059       assertFormatted(
7060           """
7061       |/////////////////////////
7062       |super.shine(
7063       |        infrared,
7064       |        ultraviolet,
7065       |    )
7066       |    .bright()
7067       |"""
7068               .trimMargin(),
7069           deduceMaxWidth = true)
7070 
7071   @Test
7072   fun `chaining (indentation) - multiline arguments, starting with short variable, with trailing invocation`() =
7073       assertFormatted(
7074           """
7075       |/////////////////////////
7076       |z12.shine(
7077       |        infrared,
7078       |        ultraviolet,
7079       |    )
7080       |    .bright()
7081       |"""
7082               .trimMargin(),
7083           deduceMaxWidth = true)
7084 
7085   @Test
7086   fun `chaining (indentation) - start with multiline arguments`() =
7087       assertFormatted(
7088           """
7089       |/////////////////////////
7090       |getRainbow(
7091       |    infrared,
7092       |    ultraviolet,
7093       |)
7094       |"""
7095               .trimMargin(),
7096           deduceMaxWidth = true)
7097 
7098   @Test
7099   fun `chaining (indentation) - start with multiline arguments, with trailing invocation`() =
7100       assertFormatted(
7101           """
7102       |/////////////////////////
7103       |getRainbow(
7104       |        infrared,
7105       |        ultraviolet,
7106       |    )
7107       |    .z { it }
7108       |"""
7109               .trimMargin(),
7110           deduceMaxWidth = true)
7111 
7112   @Test
7113   fun `annotations for expressions`() =
7114       assertFormatted(
7115           """
7116       |fun f() {
7117       |  var b
7118       |  @Suppress("UNCHECKED_CAST") b = f(1) as Int
7119       |  @Suppress("UNCHECKED_CAST")
7120       |  b = f(1) as Int
7121       |
7122       |  @Suppress("UNCHECKED_CAST") b = f(1) to 5
7123       |  @Suppress("UNCHECKED_CAST")
7124       |  b = f(1) to 5
7125       |
7126       |  @Suppress("UNCHECKED_CAST") f(1) as Int + 5
7127       |  @Suppress("UNCHECKED_CAST")
7128       |  f(1) as Int + 5
7129       |
7130       |  @Anno1 /* comment */ @Anno2 f(1) as Int
7131       |}
7132       |"""
7133               .trimMargin())
7134 
7135   @Test
7136   fun `annotations for expressions 2`() {
7137     val code =
7138         """
7139       |fun f() {
7140       |  @Suppress("UNCHECKED_CAST") f(1 + f(1) as Int)
7141       |  @Suppress("UNCHECKED_CAST")
7142       |  f(1 + f(1) as Int)
7143       |}
7144       |"""
7145             .trimMargin()
7146 
7147     val expected =
7148         """
7149       |fun f() {
7150       |  @Suppress("UNCHECKED_CAST") f(1 + f(1) as Int)
7151       |  @Suppress("UNCHECKED_CAST") f(1 + f(1) as Int)
7152       |}
7153       |"""
7154             .trimMargin()
7155 
7156     assertThatFormatting(code).isEqualTo(expected)
7157   }
7158 
7159   @Test
7160   fun `function call following long multiline string`() =
7161       assertFormatted(
7162           """
7163       |////////////////////////////////
7164       |fun stringFitsButNotMethod() {
7165       |  val str1 =
7166       |      $TQ Some string $TQ
7167       |          .trimIndent()
7168       |
7169       |  val str2 =
7170       |      $TQ Some string $TQ
7171       |          .trimIndent(someArg)
7172       |}
7173       |
7174       |fun stringTooLong() {
7175       |  val str1 =
7176       |      $TQ
7177       |      Some very long string that might mess things up
7178       |      $TQ
7179       |          .trimIndent()
7180       |
7181       |  val str2 =
7182       |      $TQ
7183       |      Some very long string that might mess things up
7184       |      $TQ
7185       |          .trimIndent(someArg)
7186       |}
7187       |"""
7188               .trimMargin(),
7189           deduceMaxWidth = true)
7190 
7191   @Test
7192   fun `array-literal in annotation`() =
7193       assertFormatted(
7194           """
7195       |////////////////////////////////
7196       |@Anno(
7197       |    array =
7198       |        [
7199       |            someItem,
7200       |            andAnother,
7201       |            noTrailingComma])
7202       |class Host
7203       |
7204       |@Anno(
7205       |    array =
7206       |        [
7207       |            someItem,
7208       |            andAnother,
7209       |            withTrailingComma,
7210       |        ])
7211       |class Host
7212       |
7213       |@Anno(
7214       |    array =
7215       |        [
7216       |            // Comment
7217       |            someItem,
7218       |            // Comment
7219       |            andAnother,
7220       |            // Comment
7221       |            withTrailingComment
7222       |            // Comment
7223       |            // Comment
7224       |            ])
7225       |class Host
7226       |"""
7227               .trimMargin(),
7228           deduceMaxWidth = true)
7229 
7230   @Test
7231   fun `force blank line between class members`() {
7232     val code =
7233         """
7234       |class Foo {
7235       |  val x = 0
7236       |  fun foo() {}
7237       |  class Bar {}
7238       |  enum class Enum {
7239       |    A {
7240       |      val x = 0
7241       |      fun foo() {}
7242       |    };
7243       |    abstract fun foo(): Unit
7244       |  }
7245       |}
7246       |"""
7247             .trimMargin()
7248 
7249     val expected =
7250         """
7251       |class Foo {
7252       |  val x = 0
7253       |
7254       |  fun foo() {}
7255       |
7256       |  class Bar {}
7257       |
7258       |  enum class Enum {
7259       |    A {
7260       |      val x = 0
7261       |
7262       |      fun foo() {}
7263       |    };
7264       |
7265       |    abstract fun foo(): Unit
7266       |  }
7267       |}
7268       |"""
7269             .trimMargin()
7270 
7271     assertThatFormatting(code).isEqualTo(expected)
7272   }
7273 
7274   @Test
7275   fun `preserve blank line between class members between properties`() {
7276     val code =
7277         """
7278       |class Foo {
7279       |  val x = 0
7280       |  val x = 0
7281       |
7282       |  val x = 0
7283       |}
7284       |"""
7285             .trimMargin()
7286 
7287     assertThatFormatting(code).isEqualTo(code)
7288   }
7289 
7290   @Test
7291   fun `force blank line between class members preserved between properties with accessors`() {
7292     val code =
7293         """
7294       |class Foo {
7295       |  val _x = 0
7296       |  val x = 0
7297       |    private get
7298       |  val y = 0
7299       |}
7300       |
7301       |class Foo {
7302       |  val _x = 0
7303       |  val x = 0
7304       |    private set
7305       |  val y = 0
7306       |}
7307       |"""
7308             .trimMargin()
7309 
7310     val expected =
7311         """
7312       |class Foo {
7313       |  val _x = 0
7314       |  val x = 0
7315       |    private get
7316       |
7317       |  val y = 0
7318       |}
7319       |
7320       |class Foo {
7321       |  val _x = 0
7322       |  val x = 0
7323       |    private set
7324       |
7325       |  val y = 0
7326       |}
7327       |"""
7328             .trimMargin()
7329 
7330     assertThatFormatting(code).isEqualTo(expected)
7331   }
7332 
7333   @Test
7334   fun `context receivers`() {
7335     val code =
7336         """
7337       |context(Something)
7338       |
7339       |class A {
7340       |  context(
7341       |  // Test comment.
7342       |  Logger, Raise<Error>)
7343       |
7344       |  @SomeAnnotation
7345       |
7346       |  fun doNothing() {}
7347       |
7348       |  context(SomethingElse)
7349       |
7350       |  private class NestedClass {}
7351       |
7352       |  fun <T> testSuspend(
7353       |    mock: T,
7354       |    block: suspend context(SomeContext) T.() -> Unit,
7355       |  ) = startCoroutine {
7356       |    T.block()
7357       |  }
7358       |}
7359       |"""
7360             .trimMargin()
7361 
7362     val expected =
7363         """
7364       |context(Something)
7365       |class A {
7366       |  context(
7367       |  // Test comment.
7368       |  Logger,
7369       |  Raise<Error>)
7370       |  @SomeAnnotation
7371       |  fun doNothing() {}
7372       |
7373       |  context(SomethingElse)
7374       |  private class NestedClass {}
7375       |
7376       |  fun <T> testSuspend(
7377       |      mock: T,
7378       |      block:
7379       |          suspend context(SomeContext)
7380       |          T.() -> Unit,
7381       |  ) = startCoroutine { T.block() }
7382       |}
7383       |"""
7384             .trimMargin()
7385 
7386     assertThatFormatting(code).isEqualTo(expected)
7387   }
7388 
7389   @Test
7390   fun `trailing comment after function in class`() =
7391       assertFormatted(
7392           """
7393       |class Host {
7394       |  fun fooBlock() {
7395       |    return
7396       |  } // Trailing after fn
7397       |  // Hanging after fn
7398       |
7399       |  // End of class
7400       |}
7401       |
7402       |class Host {
7403       |  fun fooExpr() = 0 // Trailing after fn
7404       |  // Hanging after fn
7405       |
7406       |  // End of class
7407       |}
7408       |
7409       |class Host {
7410       |  constructor() {} // Trailing after fn
7411       |  // Hanging after fn
7412       |
7413       |  // End of class
7414       |}
7415       |
7416       |class Host
7417       |// Primary constructor
7418       |constructor() // Trailing after fn
7419       |  // Hanging after fn
7420       |{
7421       |  // End of class
7422       |}
7423       |
7424       |class Host {
7425       |  fun fooBlock() {
7426       |    return
7427       |  }
7428       |
7429       |  // Between elements
7430       |
7431       |  fun fooExpr() = 0
7432       |
7433       |  // Between elements
7434       |
7435       |  fun fooBlock() {
7436       |    return
7437       |  }
7438       |}
7439       |"""
7440               .trimMargin())
7441 
7442   @Test
7443   fun `trailing comment after function top-level`() {
7444     assertFormatted(
7445         """
7446       |fun fooBlock() {
7447       |  return
7448       |} // Trailing after fn
7449       |// Hanging after fn
7450       |
7451       |// End of file
7452       |"""
7453             .trimMargin())
7454 
7455     assertFormatted(
7456         """
7457       |fun fooExpr() = 0 // Trailing after fn
7458       |// Hanging after fn
7459       |
7460       |// End of file
7461       |"""
7462             .trimMargin())
7463 
7464     assertFormatted(
7465         """
7466       |fun fooBlock() {
7467       |  return
7468       |}
7469       |
7470       |// Between elements
7471       |
7472       |fun fooExpr() = 0
7473       |
7474       |// Between elements
7475       |
7476       |fun fooBlock() {
7477       |  return
7478       |}
7479       |"""
7480             .trimMargin())
7481   }
7482 
7483   @Test
7484   fun `line break on base class`() =
7485       assertFormatted(
7486           """
7487       |///////////////////////////
7488       |class Basket<T>() :
7489       |    WovenObject {
7490       |  // some body
7491       |}
7492       |"""
7493               .trimMargin(),
7494           deduceMaxWidth = true)
7495 
7496   @Test
7497   fun `line break on type specifier`() =
7498       assertFormatted(
7499           """
7500       |///////////////////////////
7501       |class Basket<T>() where
7502       |T : Fruit {
7503       |  // some body
7504       |}
7505       |"""
7506               .trimMargin(),
7507           deduceMaxWidth = true)
7508 
7509   @Test
7510   fun `don't crash on empty enum with semicolons`() {
7511     assertFormatted(
7512         """
7513       |///////////////////////////
7514       |enum class Foo {
7515       |  ;
7516       |
7517       |  fun foo(): Unit
7518       |}
7519       |"""
7520             .trimMargin(),
7521         deduceMaxWidth = true)
7522 
7523     assertFormatted(
7524         """
7525       |///////////////////////////
7526       |enum class Foo {
7527       |  ;
7528       |
7529       |  companion object Bar
7530       |}
7531       |"""
7532             .trimMargin(),
7533         deduceMaxWidth = true)
7534 
7535     assertThatFormatting(
7536             """
7537       |enum class Foo {
7538       |  ;
7539       |  ;
7540       |  ;
7541       |
7542       |  fun foo(): Unit
7543       |}
7544       |"""
7545                 .trimMargin())
7546         .isEqualTo(
7547             """
7548       |enum class Foo {
7549       |  ;
7550       |
7551       |  fun foo(): Unit
7552       |}
7553       |"""
7554                 .trimMargin())
7555   }
7556 
7557   @Test
7558   fun `comment stable test`() {
7559     // currently unstable
7560     val first =
7561         """
7562         |class Foo { // This is a very long comment that is very long and needs to be line broken because it is long
7563         |}
7564         |"""
7565             .trimMargin()
7566     val second =
7567         """
7568         |class Foo { // This is a very long comment that is very long and needs to be line broken because it
7569         |            // is long
7570         |}
7571         |"""
7572             .trimMargin()
7573     val third =
7574         """
7575         |class Foo { // This is a very long comment that is very long and needs to be line broken because it
7576         |  // is long
7577         |}
7578         |"""
7579             .trimMargin()
7580 
7581     assertThatFormatting(first).isEqualTo(second)
7582     assertThatFormatting(second).isEqualTo(third)
7583     assertFormatted(third)
7584   }
7585 
7586   @Test
7587   fun `comment stable test - no block`() {
7588     val first =
7589         """
7590         |class Fooez // This is a very long comment that is very long and needs to be line broken because it is long
7591         |"""
7592             .trimMargin()
7593     val second =
7594         """
7595         |class Fooez // This is a very long comment that is very long and needs to be line broken because it
7596         |            // is long
7597         |"""
7598             .trimMargin()
7599 
7600     assertThatFormatting(first).isEqualTo(second)
7601     assertFormatted(second)
7602   }
7603 
7604   @Test
7605   fun `comment stable test - two blocks`() {
7606     // currently unstable
7607     val first =
7608         """
7609         |class Fooez // This is a very long comment that is very long and needs to be line broken because it is long
7610         |class Bar
7611         |"""
7612             .trimMargin()
7613     val second =
7614         """
7615         |class Fooez // This is a very long comment that is very long and needs to be line broken because it
7616         |            // is long
7617         |
7618         |class Bar
7619         |"""
7620             .trimMargin()
7621     val third =
7622         """
7623         |class Fooez // This is a very long comment that is very long and needs to be line broken because it
7624         |
7625         |// is long
7626         |
7627         |class Bar
7628         |"""
7629             .trimMargin()
7630 
7631     assertThatFormatting(first).isEqualTo(second)
7632     assertThatFormatting(second).isEqualTo(third)
7633     assertFormatted(third)
7634   }
7635 
7636   @Test
7637   fun `comment stable test - within block`() {
7638     // currently unstable
7639     val first =
7640         """
7641         |class Foo {
7642         |  class Bar // This is a very long comment that is very long and needs to be line broken because it is long
7643         |}
7644         |"""
7645             .trimMargin()
7646     val second =
7647         """
7648         |class Foo {
7649         |  class Bar // This is a very long comment that is very long and needs to be line broken because it
7650         |            // is long
7651         |}
7652         |"""
7653             .trimMargin()
7654     val third =
7655         """
7656         |class Foo {
7657         |  class Bar // This is a very long comment that is very long and needs to be line broken because it
7658         |  // is long
7659         |}
7660         |"""
7661             .trimMargin()
7662 
7663     assertThatFormatting(first).isEqualTo(second)
7664     assertThatFormatting(second).isEqualTo(third)
7665     assertFormatted(third)
7666   }
7667 
7668   companion object {
7669     /** Triple quotes, useful to use within triple-quoted strings. */
7670     private const val TQ = "\"\"\""
7671 
7672     @JvmStatic
7673     @BeforeClass
7674     fun setUp(): Unit {
7675       defaultTestFormattingOptions = META_FORMAT.copy(manageTrailingCommas = false)
7676     }
7677   }
7678 }
7679