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