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.testutil.assertFormatted 20 import com.facebook.ktfmt.testutil.assertThatFormatting 21 import com.google.common.truth.Truth.assertThat 22 import org.junit.Assert.fail 23 import org.junit.Test 24 import org.junit.runner.RunWith 25 import org.junit.runners.JUnit4 26 27 @Suppress("FunctionNaming") 28 @RunWith(JUnit4::class) 29 class FormatterTest { 30 31 @Test support script (kts) filesnull32 fun `support script (kts) files`() = 33 assertFormatted( 34 """ 35 |package foo 36 | 37 |import java.io.File 38 | 39 |val one: String 40 | 41 |val two: String 42 | 43 |fun f() { 44 | println("asd") 45 |} 46 | 47 |println("Called with args:") 48 | 49 |args.forEach { println(File + "-") } 50 |""" 51 .trimMargin()) 52 53 @Test 54 fun `support script (kts) files with a shebang`() = 55 assertFormatted( 56 """ 57 |#!/usr/bin/env kscript 58 |package foo 59 | 60 |println("Called") 61 |""" 62 .trimMargin()) 63 64 @Test 65 fun `call chains`() = 66 assertFormatted( 67 """ 68 |-------------------------------------------------- 69 |fun f() { 70 | // Static method calls are attached to the class name. 71 | ImmutableList.newBuilder() 72 | .add(1) 73 | .add(1) 74 | .add(1) 75 | .add(1) 76 | .add(1) 77 | .add(1) 78 | .add(1) 79 | .add(1) 80 | .add(1) 81 | .add(1) 82 | .build() 83 | 84 | // Multiple call expressions --> each on its own line. 85 | ImmutableList() 86 | .newBuilder() 87 | .add(1) 88 | .add(1) 89 | .add(1) 90 | .add(1) 91 | .add(1) 92 | .add(1) 93 | .add(1) 94 | .add(1) 95 | .add(1) 96 | .add(1) 97 | .build() 98 |} 99 |""" 100 .trimMargin(), 101 deduceMaxWidth = true) 102 103 @Test 104 fun `line breaks in function arguments`() = 105 assertFormatted( 106 """ 107 |-------------------------------------------------- 108 |fun f() { 109 | computeBreaks( 110 | javaOutput.commentsHelper, 111 | maxWidth, 112 | Doc.State(+0, 0)) 113 | computeBreaks( 114 | output.commentsHelper, maxWidth, State(0)) 115 | doc.computeBreaks( 116 | javaOutput.commentsHelper, 117 | maxWidth, 118 | Doc.State(+0, 0)) 119 | doc.computeBreaks( 120 | output.commentsHelper, maxWidth, State(0)) 121 |} 122 |""" 123 .trimMargin(), 124 deduceMaxWidth = true) 125 126 @Test 127 fun `parameters and return type in function definitions`() = 128 assertFormatted( 129 """ 130 |---------------------------------------- 131 |fun format( 132 | code: String, 133 | maxWidth: Int = 134 | DEFAULT_MAX_WIDTH_VERY_LONG 135 |): String { 136 | val a = 0 137 |} 138 | 139 |fun print( 140 | code: String, 141 | maxWidth: Int = 142 | DEFAULT_MAX_WIDTH_VERY_LONG 143 |) { 144 | val a = 0 145 |} 146 |""" 147 .trimMargin(), 148 deduceMaxWidth = true) 149 150 @Test 151 fun `kitchen sink of tests`() { 152 // Don't add more tests here 153 val code = 154 """ 155 |fun 156 |f ( 157 |a : Int 158 | , b: Double , c:String) { var result = 0 159 | val aVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVar = 43 160 | foo.bar.zed.accept( 161 | 162 | ) 163 | 164 | foo( 165 | 166 | ) 167 | 168 | foo.bar.zed.accept( 169 | DoSomething.bar() 170 | ) 171 | 172 | bar( 173 | ImmutableList.newBuilder().add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).add(1).build()) 174 | 175 | 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 .trimMargin() 180 181 val expected = 182 """ 183 |fun f(a: Int, b: Double, c: String) { 184 | var result = 0 185 | val aVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVar = 186 | 43 187 | foo.bar.zed.accept() 188 | 189 | foo() 190 | 191 | foo.bar.zed.accept(DoSomething.bar()) 192 | 193 | bar( 194 | ImmutableList.newBuilder() 195 | .add(1) 196 | .add(1) 197 | .add(1) 198 | .add(1) 199 | .add(1) 200 | .add(1) 201 | .add(1) 202 | .add(1) 203 | .add(1) 204 | .add(1) 205 | .build()) 206 | 207 | ImmutableList.newBuilder() 208 | .add(1) 209 | .add(1) 210 | .add(1) 211 | .add(1) 212 | .add(1) 213 | .add(1) 214 | .add(1) 215 | .add(1) 216 | .add(1) 217 | .add(1) 218 | .build() 219 |} 220 |""" 221 .trimMargin() 222 223 assertThatFormatting(code).isEqualTo(expected) 224 // Don't add more tests here 225 } 226 227 @Test spacing around variable declarationsnull228 fun `spacing around variable declarations`() = 229 assertFormatted( 230 """ 231 |fun f() { 232 | var x: Int = 4 233 | val y = 0 234 |} 235 |""" 236 .trimMargin()) 237 238 @Test fun `class without a body nor properties`() = assertFormatted("class Foo\n") 239 240 @Test fun `interface without a body nor properties`() = assertFormatted("interface Foo\n") 241 242 @Test fun `preserve empty primary constructor`() = assertFormatted("class Foo()\n") 243 244 @Test 245 fun `simple fun interface`() = 246 assertFormatted( 247 """fun interface MyRunnable { 248 | fun runIt() 249 |} 250 |""" 251 .trimMargin()) 252 253 @Test 254 fun `handle complex fun interface without body`() = 255 assertFormatted("public fun interface Function<T : List<*>> : (Int, T?) -> T?\n") 256 257 @Test 258 fun `class without a body, with explicit ctor params`() = 259 assertFormatted("class Foo(a: Int, var b: Double, val c: String)\n") 260 261 @Test 262 fun `class with a body and explicit ctor params`() = 263 assertFormatted( 264 """ 265 |class Foo(a: Int, var b: Double, val c: String) { 266 | val x = 2 267 | fun method() {} 268 | class Bar 269 |} 270 |""" 271 .trimMargin()) 272 273 @Test 274 fun `properties and fields with modifiers`() = 275 assertFormatted( 276 """ 277 |class Foo(public val p1: Int, private val p2: Int, open val p3: Int, final val p4: Int) { 278 | private var f1 = 0 279 | public var f2 = 0 280 | open var f3 = 0 281 | final var f4 = 0 282 |} 283 |""" 284 .trimMargin()) 285 286 @Test 287 fun `properties with multiple modifiers`() = 288 assertFormatted( 289 """ 290 |class Foo(public open inner val p1: Int) { 291 | public open inner var f2 = 0 292 |} 293 |""" 294 .trimMargin()) 295 296 @Test 297 fun `spaces around binary operations`() = 298 assertFormatted( 299 """ 300 |fun foo() { 301 | a = 5 302 | x + 1 303 |} 304 |""" 305 .trimMargin()) 306 307 @Test 308 fun `breaking long binary operations`() = 309 assertFormatted( 310 """ 311 |-------------------- 312 |fun foo() { 313 | val finalWidth = 314 | value1 + 315 | value2 + 316 | (value3 + 317 | value4 + 318 | value5) + 319 | foo(v) + 320 | (1 + 2) + 321 | function( 322 | value7, 323 | value8) + 324 | value9 325 |} 326 |""" 327 .trimMargin(), 328 deduceMaxWidth = true) 329 330 @Test 331 fun `prioritize according to associativity`() = 332 assertFormatted( 333 """ 334 |-------------------------------------- 335 |fun foo() { 336 | return expression1 != expression2 || 337 | expression2 != expression1 338 |} 339 |""" 340 .trimMargin(), 341 deduceMaxWidth = true) 342 343 @Test 344 fun `once a binary expression is broken, split on every line`() = 345 assertFormatted( 346 """ 347 |-------------------------------------- 348 |fun foo() { 349 | val sentence = 350 | "The" + 351 | "quick" + 352 | ("brown" + "fox") + 353 | "jumps" + 354 | "over" + 355 | "the" + 356 | "lazy" + 357 | "dog" 358 |} 359 |""" 360 .trimMargin(), 361 deduceMaxWidth = true) 362 363 @Test 364 fun `long binary expressions with ranges in the middle`() = 365 assertFormatted( 366 """ 367 |-------------------------------------- 368 |fun foo() { 369 | val sentence = 370 | "The" + 371 | "quick" + 372 | ("brown".."fox") + 373 | "jumps" + 374 | "over" + 375 | "the".."lazy" + "dog" 376 |} 377 |""" 378 .trimMargin(), 379 deduceMaxWidth = true) 380 381 @Test 382 fun `assignment expressions with scoping functions are block-like`() = 383 assertFormatted( 384 """ 385 |--------------------------- 386 |fun f() { 387 | name.sub = scope { x -> 388 | // 389 | } 390 | name.sub += scope { x -> 391 | // 392 | } 393 | name.sub -= scope { x -> 394 | // 395 | } 396 | name.sub *= scope { x -> 397 | // 398 | } 399 | name.sub /= scope { x -> 400 | // 401 | } 402 | name.sub %= scope { x -> 403 | // 404 | } 405 |} 406 | 407 |fun h() { 408 | long.name.sub = 409 | scope { x -> 410 | // 411 | } 412 | long.name.sub += 413 | scope { x -> 414 | // 415 | } 416 | long.name.sub -= 417 | scope { x -> 418 | // 419 | } 420 | long.name.sub *= 421 | scope { x -> 422 | // 423 | } 424 | long.name.sub /= 425 | scope { x -> 426 | // 427 | } 428 | long.name.sub %= 429 | scope { x -> 430 | // 431 | } 432 |} 433 |""" 434 .trimMargin(), 435 deduceMaxWidth = true) 436 437 @Test 438 fun `don't keep adding newlines between these two comments when they're at end of file`() = 439 assertFormatted( 440 """ 441 |package foo 442 |// a 443 | 444 |/* Another comment */ 445 |""" 446 .trimMargin()) 447 448 @Test 449 fun `properties with line comment above initializer`() = 450 assertFormatted( 451 """ 452 |class Foo { 453 | var x: Int = 454 | // Comment 455 | 0 456 | 457 | var y: Int = 458 | // Comment 459 | scope { 460 | 0 // 461 | } 462 | 463 | var z: Int = 464 | // Comment 465 | if (cond) { 466 | 0 467 | } else { 468 | 1 469 | } 470 |} 471 |""" 472 .trimMargin()) 473 474 @Test 475 fun `properties with line comment above delegate`() = 476 assertFormatted( 477 """ 478 |class Foo { 479 | var x: Int by 480 | // Comment 481 | 0 482 | 483 | var y: Int by 484 | // Comment 485 | scope { 486 | 0 // 487 | } 488 | 489 | var z: Int by 490 | // Comment 491 | if (cond) { 492 | 0 493 | } else { 494 | 1 495 | } 496 |} 497 |""" 498 .trimMargin()) 499 500 @Test 501 fun `properties with accessors`() = 502 assertFormatted( 503 """ 504 |class Foo { 505 | var x: Int 506 | get() = field 507 | var y: Boolean 508 | get() = x.equals(123) 509 | set(value) { 510 | field = value 511 | } 512 | var z: Boolean 513 | get() { 514 | x.equals(123) 515 | } 516 | var zz = false 517 | private set 518 |} 519 |""" 520 .trimMargin()) 521 522 @Test 523 fun `properties with accessors and semicolons on same line`() { 524 val code = 525 """ 526 |class Foo { 527 | var x = false; private set 528 | internal val a by lazy { 5 }; internal get 529 | var foo: Int; get() = 6; set(x) {}; 530 |} 531 |""" 532 .trimMargin() 533 534 val expected = 535 """ 536 |class Foo { 537 | var x = false 538 | private set 539 | internal val a by lazy { 5 } 540 | internal get 541 | var foo: Int 542 | get() = 6 543 | set(x) {} 544 |} 545 |""" 546 .trimMargin() 547 548 assertThatFormatting(code).isEqualTo(expected) 549 } 550 551 @Test a property with a too long name being broken on multiple linesnull552 fun `a property with a too long name being broken on multiple lines`() = 553 assertFormatted( 554 """ 555 |-------------------- 556 |class Foo { 557 | val thisIsALongName: 558 | String = 559 | "Hello there this is long" 560 | get() = field 561 |} 562 |""" 563 .trimMargin(), 564 deduceMaxWidth = true) 565 566 @Test 567 fun `multi-character unary and binary operators such as ==`() = 568 assertFormatted( 569 """ 570 |fun f() { 571 | 3 == 4 572 | true && false 573 | a++ 574 | a === b 575 |} 576 |""" 577 .trimMargin()) 578 579 @Test 580 fun `package names stay in one line`() { 581 val code = 582 """ 583 | package com .example. subexample 584 | 585 |fun f() = 1 586 |""" 587 .trimMargin() 588 val expected = 589 """ 590 |package com.example.subexample 591 | 592 |fun f() = 1 593 |""" 594 .trimMargin() 595 596 assertThatFormatting(code).isEqualTo(expected) 597 } 598 599 @Test handle package name and imports with escapes and spacesnull600 fun `handle package name and imports with escapes and spaces`() = 601 assertFormatted( 602 """ 603 |package com.`fun times`.`with package names` 604 | 605 |import `nothing stops`.`us`.`from doing this` 606 | 607 |fun f() = `from doing this`() 608 |""" 609 .trimMargin()) 610 611 @Test 612 fun `safe dot operator expression`() = 613 assertFormatted( 614 """ 615 |fun f() { 616 | node?.name 617 |} 618 |""" 619 .trimMargin()) 620 621 @Test 622 fun `safe dot operator expression with normal`() = 623 assertFormatted( 624 """ 625 |fun f() { 626 | node?.name.hello 627 |} 628 |""" 629 .trimMargin()) 630 631 @Test 632 fun `safe dot operator expression chain in expression function`() = 633 assertFormatted( 634 """ 635 |-------------------------------------------------- 636 |fun f(number: Int) = 637 | Something.doStuff(number)?.size 638 |""" 639 .trimMargin(), 640 deduceMaxWidth = true) 641 642 @Test 643 fun `avoid breaking suspected package names`() = 644 assertFormatted( 645 """ 646 |----------------------- 647 |fun f() { 648 | com.facebook.Foo 649 | .format() 650 | org.facebook.Foo 651 | .format() 652 | java.lang.stuff.Foo 653 | .format() 654 | javax.lang.stuff.Foo 655 | .format() 656 | kotlin.lang.Foo 657 | .format() 658 | foo.facebook.Foo 659 | .format() 660 |} 661 |""" 662 .trimMargin(), 663 deduceMaxWidth = true) 664 665 @Test 666 fun `an assortment of tests for emitQualifiedExpression`() = 667 assertFormatted( 668 """ 669 |------------------------------------- 670 |fun f() { 671 | // Regression test: https://github.com/facebookincubator/ktfmt/issues/56 672 | kjsdfglkjdfgkjdfkgjhkerjghkdfj 673 | ?.methodName1() 674 | 675 | // a series of field accesses followed by a single call expression 676 | // is kept together. 677 | abcdefghijkl.abcdefghijkl 678 | ?.methodName2() 679 | 680 | // Similar to above. 681 | abcdefghijkl.abcdefghijkl 682 | ?.methodName3 683 | ?.abcdefghijkl() 684 | 685 | // Multiple call expressions cause each part of the expression 686 | // to be placed on its own line. 687 | abcdefghijkl 688 | ?.abcdefghijkl 689 | ?.methodName4() 690 | ?.abcdefghijkl() 691 | 692 | // Don't break first call expression if it fits. 693 | foIt(something.something.happens()) 694 | .thenReturn(result) 695 | 696 | // Break after `longerThanFour(` because it's longer than 4 chars 697 | longerThanFour( 698 | something.something 699 | .happens()) 700 | .thenReturn(result) 701 | 702 | // Similarly to above, when part of qualified expression. 703 | foo.longerThanFour( 704 | something.something 705 | .happens()) 706 | .thenReturn(result) 707 | 708 | // Keep 'super' attached to the method name 709 | super.abcdefghijkl 710 | .methodName4() 711 | .abcdefghijkl() 712 |} 713 |""" 714 .trimMargin(), 715 deduceMaxWidth = true) 716 717 @Test 718 fun `an assortment of tests for emitQualifiedExpression with lambdas`() = 719 assertFormatted( 720 """ 721 |---------------------------------------------------------------------------- 722 |fun f() { 723 | val items = 724 | items.toMutableList.apply { 725 | // 726 | foo 727 | } 728 | 729 | val items = 730 | items.toMutableList().apply { 731 | // 732 | foo 733 | } 734 | 735 | // All dereferences are on one line (because they fit), even though 736 | // the apply() at the end requires a line break. 737 | val items = 738 | items.toMutableList.sdfkjsdf.sdfjksdflk.sdlfkjsldfj.apply { 739 | // 740 | foo 741 | } 742 | 743 | // All method calls are on one line (because they fit), even though 744 | // the apply() at the end requires a line break. 745 | val items = 746 | items.toMutableList().sdfkjsdf().sdfjksdflk().sdlfkjsldfj().apply { 747 | // 748 | foo 749 | } 750 | 751 | // All method calls with lambdas could fit, but we avoid a block like syntax 752 | // and break to one call per line 753 | val items = 754 | items 755 | .map { it + 1 } 756 | .filter { it > 0 } 757 | .apply { 758 | // 759 | foo 760 | } 761 | 762 | // the lambda is indented properly with the break before it 763 | val items = 764 | items.fieldName.sdfkjsdf.sdfjksdflk.sdlfkjsldfj.sdfjksdflk.sdlfkjsldfj 765 | .sdlfkjsldfj 766 | .apply { 767 | // 768 | foo 769 | } 770 | items.fieldName.sdfkjsdf.sdfjksdflk.sdlfkjsldfj.sdfjksdflk.sdlfkjsldfj 771 | .apply { 772 | // 773 | foo 774 | } 775 | 776 | // When there are multiple method calls, and they don't fit on one 777 | // line, put each on a new line. 778 | val items = 779 | items 780 | .toMutableList() 781 | .sdfkjsdf() 782 | .sdfjksdflk() 783 | .sdlfkjsldfj() 784 | .sdfjksdflk() 785 | .sdlfkjsldfj() 786 | .apply { 787 | // 788 | foo 789 | } 790 |} 791 |""" 792 .trimMargin(), 793 deduceMaxWidth = true) 794 795 @Test 796 fun `when two lambdas are in a chain, avoid block syntax`() = 797 assertFormatted( 798 """ 799 |class Foo : Bar() { 800 | fun doIt() { 801 | fruit.onlyBananas().forEach { banana -> 802 | val seeds = banana.find { it.type == SEED } 803 | println(seeds) 804 | } 805 | 806 | fruit 807 | .filter { isBanana(it, Bananas.types) } 808 | .forEach { banana -> 809 | val seeds = banana.find { it.type == SEED } 810 | println(seeds) 811 | } 812 | } 813 |} 814 |""" 815 .trimMargin()) 816 817 @Test 818 fun `don't one-line lambdas following argument breaks`() = 819 assertFormatted( 820 """ 821 |------------------------------------------------------------------------ 822 |class Foo : Bar() { 823 | fun doIt() { 824 | // don't break in lambda, no argument breaks found 825 | fruit.forEach { eat(it) } 826 | 827 | // break in the lambda, without comma 828 | fruit.forEach( 829 | someVeryLongParameterNameThatWillCauseABreak, 830 | evenWithoutATrailingCommaOnTheParameterListSoLetsSeeIt) { 831 | eat(it) 832 | } 833 | 834 | // break in the lambda, with comma 835 | fruit.forEach( 836 | fromTheVine = true, 837 | ) { 838 | eat(it) 839 | } 840 | 841 | // don't break in the inner lambda, as nesting doesn't respect outer levels 842 | fruit.forEach( 843 | fromTheVine = true, 844 | ) { 845 | fruit.forEach { eat(it) } 846 | } 847 | 848 | // don't break in the lambda, as breaks don't propagate 849 | fruit 850 | .onlyBananas( 851 | fromTheVine = true, 852 | ) 853 | .forEach { eat(it) } 854 | 855 | // don't break in the inner lambda, as breaks don't propagate to parameters 856 | fruit.onlyBananas( 857 | fromTheVine = true, 858 | processThem = { eat(it) }, 859 | ) { 860 | eat(it) 861 | } 862 | 863 | // don't break in the inner lambda, as breaks don't propagate to the body 864 | fruit.onlyBananas( 865 | fromTheVine = true, 866 | ) { 867 | val anon = { eat(it) } 868 | } 869 | } 870 |} 871 |""" 872 .trimMargin(), 873 deduceMaxWidth = true) 874 875 @Test indent parameters after a break when there's a lambda afterwardsnull876 fun `indent parameters after a break when there's a lambda afterwards`() = 877 assertFormatted( 878 """ 879 |--------------------------- 880 |class C { 881 | fun method() { 882 | Foo.FooBar( 883 | param1, param2) 884 | .apply { 885 | // 886 | foo 887 | } 888 | } 889 |} 890 |""" 891 .trimMargin(), 892 deduceMaxWidth = true) 893 894 @Test no forward propagation of breaks in call expressions (at trailing lambda)null895 fun `no forward propagation of breaks in call expressions (at trailing lambda)`() = 896 assertFormatted( 897 """ 898 |-------------------------- 899 |fun test() { 900 | foo_bar_baz__zip<A>(b) { 901 | c 902 | } 903 | foo.bar(baz).zip<A>(b) { 904 | c 905 | } 906 |} 907 |""" 908 .trimMargin(), 909 deduceMaxWidth = true) 910 911 @Test forward propagation of breaks in call expressions (at value args)null912 fun `forward propagation of breaks in call expressions (at value args)`() = 913 assertFormatted( 914 """ 915 |---------------------- 916 |fun test() { 917 | foo_bar_baz__zip<A>( 918 | b) { 919 | c 920 | } 921 |} 922 | 923 |fun test() { 924 | foo.bar(baz).zip<A>( 925 | b) { 926 | c 927 | } 928 |} 929 |""" 930 .trimMargin(), 931 deduceMaxWidth = true) 932 933 @Test forward propagation of breaks in call expressions (at type args)null934 fun `forward propagation of breaks in call expressions (at type args)`() = 935 assertFormatted( 936 """ 937 |------------------- 938 |fun test() { 939 | foo_bar_baz__zip< 940 | A>( 941 | b) { 942 | c 943 | } 944 | foo.bar(baz).zip< 945 | A>( 946 | b) { 947 | c 948 | } 949 |} 950 |""" 951 .trimMargin(), 952 deduceMaxWidth = true) 953 954 @Test expected indent in methods following single-line stringsnull955 fun `expected indent in methods following single-line strings`() = 956 assertFormatted( 957 """ 958 |------------------------- 959 |"Hello %s".format( 960 | someLongExpression) 961 |""" 962 .trimMargin(), 963 deduceMaxWidth = true) 964 965 @Test 966 fun `forced break between multi-line strings and their selectors`() = 967 assertFormatted( 968 """ 969 |------------------------- 970 |val STRING = 971 | $TQ 972 | |foo 973 | |$TQ 974 | .wouldFit() 975 | 976 |val STRING = 977 | $TQ 978 | |foo 979 | |----------------------------------$TQ 980 | .wouldntFit() 981 | 982 |val STRING = 983 | $TQ 984 | |foo 985 | |$TQ 986 | .firstLink() 987 | .secondLink() 988 |""" 989 .trimMargin(), 990 deduceMaxWidth = true) 991 992 @Test 993 fun `import list`() { 994 val code = 995 """ 996 | import com .example.common.reality. FooBar 997 | import com .example.common.reality. FooBar2 as foosBars 998 | import com .example.common.reality. * 999 | import foo.bar // Test 1000 | import abc.def /* 1001 | test */ 1002 | 1003 |val x = FooBar.def { foosBars(bar) } 1004 |""" 1005 .trimMargin() 1006 val expected = 1007 """ 1008 |import abc.def /* 1009 | test */ 1010 |import com.example.common.reality.* 1011 |import com.example.common.reality.FooBar 1012 |import com.example.common.reality.FooBar2 as foosBars 1013 |import foo.bar // Test 1014 | 1015 |val x = FooBar.def { foosBars(bar) } 1016 |""" 1017 .trimMargin() 1018 assertThatFormatting(code).isEqualTo(expected) 1019 } 1020 1021 @Test imports with trailing comments and expressionsnull1022 fun `imports with trailing comments and expressions`() { 1023 val code = 1024 """ 1025 |import com.example.zab // test 1026 |import com.example.foo ; val x = Sample(foo, zab) 1027 |""" 1028 .trimMargin() 1029 1030 val expected = 1031 """ 1032 |import com.example.foo 1033 |import com.example.zab // test 1034 | 1035 |val x = Sample(foo, zab) 1036 |""" 1037 .trimMargin() 1038 1039 assertThatFormatting(code).isEqualTo(expected) 1040 } 1041 1042 @Test backticks are ignored in import sort ordernull1043 fun `backticks are ignored in import sort order`() = 1044 assertFormatted( 1045 """ 1046 |import com.example.`if` 1047 |import com.example.we 1048 |import com.example.`when` 1049 |import com.example.wow 1050 | 1051 |val x = `if` { we.`when`(wow) } 1052 |""" 1053 .trimMargin()) 1054 1055 @Test backticks are ignored in import sort order ('as' directory)null1056 fun `backticks are ignored in import sort order ('as' directory)`() = 1057 assertFormatted( 1058 """ 1059 |import com.example.a as `if` 1060 |import com.example.a as we 1061 |import com.example.a as `when` 1062 |import com.example.a as wow 1063 | 1064 |val x = `if` { we.`when`(wow) } 1065 |""" 1066 .trimMargin()) 1067 1068 @Test imports are deduplicatednull1069 fun `imports are deduplicated`() { 1070 val code = 1071 """ 1072 |import com.example.b.* 1073 |import com.example.b 1074 |import com.example.a as `if` 1075 |import com.example.a as we 1076 |import com.example.a as `when` 1077 |import com.example.a as wow 1078 |import com.example.a as `when` 1079 | 1080 |val x = `if` { we.`when`(wow) } ?: b 1081 |""" 1082 .trimMargin() 1083 val expected = 1084 """ 1085 |import com.example.a as `if` 1086 |import com.example.a as we 1087 |import com.example.a as `when` 1088 |import com.example.a as wow 1089 |import com.example.b 1090 |import com.example.b.* 1091 | 1092 |val x = `if` { we.`when`(wow) } ?: b 1093 |""" 1094 .trimMargin() 1095 assertThatFormatting(code).isEqualTo(expected) 1096 } 1097 1098 @Test unused imports are removednull1099 fun `unused imports are removed`() { 1100 val code = 1101 """ 1102 |import com.unused.Sample 1103 |import com.used.FooBarBaz as Baz 1104 |import com.used.bar // test 1105 |import com.used.`class` 1106 |import com.used.a.* 1107 |import com.used.b as `if` 1108 |import com.used.b as we 1109 |import com.unused.a as `when` 1110 |import com.unused.a as wow 1111 | 1112 |fun test(input: we) { 1113 | Baz(`class`) 1114 | `if` { bar } 1115 | val x = unused() 1116 |} 1117 |""" 1118 .trimMargin() 1119 val expected = 1120 """ 1121 |import com.used.FooBarBaz as Baz 1122 |import com.used.a.* 1123 |import com.used.b as `if` 1124 |import com.used.b as we 1125 |import com.used.bar // test 1126 |import com.used.`class` 1127 | 1128 |fun test(input: we) { 1129 | Baz(`class`) 1130 | `if` { bar } 1131 | val x = unused() 1132 |} 1133 |""" 1134 .trimMargin() 1135 assertThatFormatting(code).isEqualTo(expected) 1136 } 1137 1138 @Test imports from the same package are removednull1139 fun `imports from the same package are removed`() { 1140 val code = 1141 """ 1142 |package com.example 1143 | 1144 |import com.example.Sample 1145 |import com.example.Sample.CONSTANT 1146 |import com.example.a.foo 1147 | 1148 |fun test() { 1149 | foo(CONSTANT, Sample()) 1150 |} 1151 |""" 1152 .trimMargin() 1153 val expected = 1154 """ 1155 |package com.example 1156 | 1157 |import com.example.Sample.CONSTANT 1158 |import com.example.a.foo 1159 | 1160 |fun test() { 1161 | foo(CONSTANT, Sample()) 1162 |} 1163 |""" 1164 .trimMargin() 1165 assertThatFormatting(code).isEqualTo(expected) 1166 } 1167 1168 @Test keep import elements only mentioned in kdocnull1169 fun `keep import elements only mentioned in kdoc`() { 1170 val code = 1171 """ 1172 |package com.example.kdoc 1173 | 1174 |import com.example.Bar 1175 |import com.example.Example 1176 |import com.example.Foo 1177 |import com.example.JavaDocLink 1178 |import com.example.Param 1179 |import com.example.R 1180 |import com.example.ReturnedValue 1181 |import com.example.Sample 1182 |import com.example.unused 1183 |import com.example.exception.AnException 1184 |import com.example.kdoc.Doc 1185 | 1186 |/** 1187 | * [Foo] is something only mentioned here, just like [R.layout.test] and [Doc]. 1188 | * 1189 | * Old {@link JavaDocLink} that gets removed. 1190 | * 1191 | * @throws AnException 1192 | * @exception Sample.SampleException 1193 | * @param unused [Param] 1194 | * @property JavaDocLink [Param] 1195 | * @return [Unit] as [ReturnedValue] 1196 | * @sample Example 1197 | * @see Bar for more info 1198 | * @throws AnException 1199 | */ 1200 |class Dummy 1201 |""" 1202 .trimMargin() 1203 val expected = 1204 """ 1205 |package com.example.kdoc 1206 | 1207 |import com.example.Bar 1208 |import com.example.Example 1209 |import com.example.Foo 1210 |import com.example.Param 1211 |import com.example.R 1212 |import com.example.ReturnedValue 1213 |import com.example.Sample 1214 |import com.example.exception.AnException 1215 | 1216 |/** 1217 | * [Foo] is something only mentioned here, just like [R.layout.test] and [Doc]. 1218 | * 1219 | * Old {@link JavaDocLink} that gets removed. 1220 | * 1221 | * @param unused [Param] 1222 | * @return [Unit] as [ReturnedValue] 1223 | * @property JavaDocLink [Param] 1224 | * @throws AnException 1225 | * @throws AnException 1226 | * @exception Sample.SampleException 1227 | * @sample Example 1228 | * @see Bar for more info 1229 | */ 1230 |class Dummy 1231 |""" 1232 .trimMargin() 1233 assertThatFormatting(code).isEqualTo(expected) 1234 } 1235 1236 @Test 1237 fun `keep import elements only mentioned in kdoc, single line`() { 1238 assertFormatted( 1239 """ 1240 |import com.shopping.Bag 1241 | 1242 |/** 1243 | * Some summary. 1244 | * 1245 | * @param count you can fit this many in a [Bag] 1246 | */ 1247 |fun fetchBananas(count: Int) 1248 |""" 1249 .trimMargin()) 1250 } 1251 1252 @Test 1253 fun `keep import elements only mentioned in kdoc, multiline`() { 1254 assertFormatted( 1255 """ 1256 |import com.shopping.Bag 1257 | 1258 |/** 1259 | * Some summary. 1260 | * 1261 | * @param count this is how many of these wonderful fruit you can fit into the useful object that 1262 | * you may refer to as a [Bag] 1263 | */ 1264 |fun fetchBananas(count: Int) 1265 |""" 1266 .trimMargin()) 1267 } 1268 1269 @Test 1270 fun `keep component imports`() = 1271 assertFormatted( 1272 """ 1273 |import com.example.component1 1274 |import com.example.component10 1275 |import com.example.component120 1276 |import com.example.component2 1277 |import com.example.component3 1278 |import com.example.component4 1279 |import com.example.component5 1280 |""" 1281 .trimMargin()) 1282 1283 @Test 1284 fun `keep operator imports`() = 1285 assertFormatted( 1286 """ 1287 |import com.example.and 1288 |import com.example.compareTo 1289 |import com.example.contains 1290 |import com.example.dec 1291 |import com.example.div 1292 |import com.example.divAssign 1293 |import com.example.equals 1294 |import com.example.get 1295 |import com.example.getValue 1296 |import com.example.hasNext 1297 |import com.example.inc 1298 |import com.example.invoke 1299 |import com.example.iterator 1300 |import com.example.minus 1301 |import com.example.minusAssign 1302 |import com.example.mod 1303 |import com.example.modAssign 1304 |import com.example.next 1305 |import com.example.not 1306 |import com.example.or 1307 |import com.example.plus 1308 |import com.example.plusAssign 1309 |import com.example.provideDelegate 1310 |import com.example.rangeTo 1311 |import com.example.rem 1312 |import com.example.remAssign 1313 |import com.example.set 1314 |import com.example.setValue 1315 |import com.example.times 1316 |import com.example.timesAssign 1317 |import com.example.unaryMinus 1318 |import com.example.unaryPlus 1319 |""" 1320 .trimMargin()) 1321 1322 @Test 1323 fun `keep unused imports when formatting options has feature turned off`() { 1324 val code = 1325 """ 1326 |import com.unused.FooBarBaz as Baz 1327 |import com.unused.Sample 1328 |import com.unused.a as `when` 1329 |import com.unused.a as wow 1330 |import com.unused.a.* 1331 |import com.unused.b as `if` 1332 |import com.unused.b as we 1333 |import com.unused.bar // test 1334 |import com.unused.`class` 1335 |""" 1336 .trimMargin() 1337 1338 assertThatFormatting(code) 1339 .withOptions(FormattingOptions(removeUnusedImports = false)) 1340 .isEqualTo(code) 1341 } 1342 1343 @Test 1344 fun `comments between imports are moved above import list`() { 1345 val code = 1346 """ 1347 |package com.facebook.ktfmt 1348 | 1349 |/* leading comment */ 1350 |import com.example.abc 1351 |/* internal comment 1 */ 1352 |import com.example.bcd 1353 |// internal comment 2 1354 |import com.example.Sample 1355 |// trailing comment 1356 | 1357 |val x = Sample(abc, bcd) 1358 |""" 1359 .trimMargin() 1360 val expected = 1361 """ 1362 |package com.facebook.ktfmt 1363 | 1364 |/* leading comment */ 1365 |/* internal comment 1 */ 1366 |// internal comment 2 1367 |import com.example.Sample 1368 |import com.example.abc 1369 |import com.example.bcd 1370 | 1371 |// trailing comment 1372 | 1373 |val x = Sample(abc, bcd) 1374 |""" 1375 .trimMargin() 1376 assertThatFormatting(code).isEqualTo(expected) 1377 } 1378 1379 @Test 1380 fun `no redundant newlines when there are no imports`() = 1381 assertFormatted( 1382 """ 1383 |package foo123 1384 | 1385 |/* 1386 |bar 1387 |*/ 1388 |""" 1389 .trimMargin()) 1390 1391 @Test 1392 fun `basic annotations`() = 1393 assertFormatted( 1394 """ 1395 |@Fancy 1396 |class Foo { 1397 | @Fancy 1398 | fun baz(@Fancy foo: Int) { 1399 | @Fancy val a = 1 + foo 1400 | } 1401 |} 1402 |""" 1403 .trimMargin()) 1404 1405 @Test function calls with multiple argumentsnull1406 fun `function calls with multiple arguments`() = 1407 assertFormatted( 1408 """ 1409 |fun f() { 1410 | foo(1, 2, 3) 1411 | 1412 | foo( 1413 | 123456789012345678901234567890, 1414 | 123456789012345678901234567890, 1415 | 123456789012345678901234567890) 1416 |} 1417 |""" 1418 .trimMargin()) 1419 1420 @Test function calls with multiple named argumentsnull1421 fun `function calls with multiple named arguments`() = 1422 assertFormatted( 1423 """ 1424 |fun f() { 1425 | foo(1, b = 2, c = 3) 1426 | 1427 | foo( 1428 | 123456789012345678901234567890, 1429 | b = 23456789012345678901234567890, 1430 | c = 3456789012345678901234567890) 1431 |} 1432 |""" 1433 .trimMargin()) 1434 1435 @Test named arguments indent their value expressionnull1436 fun `named arguments indent their value expression`() = 1437 assertFormatted( 1438 """ 1439 |fun f() = 1440 | Bar( 1441 | tokens = 1442 | mutableListOf<Token>().apply { 1443 | // Printing 1444 | print() 1445 | }, 1446 | duration = duration) 1447 |""" 1448 .trimMargin()) 1449 1450 @Test Arguments are blocksnull1451 fun `Arguments are blocks`() = 1452 assertFormatted( 1453 """ 1454 |-------------------------------------------------- 1455 |override fun visitProperty(property: KtProperty) { 1456 | builder.sync(property) 1457 | builder.block(ZERO) { 1458 | declareOne( 1459 | kind = DeclarationKind.FIELD, 1460 | modifiers = property.modifierList, 1461 | valOrVarKeyword = 1462 | property.valOrVarKeyword.text, 1463 | typeParameters = 1464 | property.typeParameterList, 1465 | receiver = property.receiverTypeReference, 1466 | name = property.nameIdentifier?.text, 1467 | type = property.typeReference, 1468 | typeConstraintList = 1469 | property.typeConstraintList, 1470 | delegate = property.delegate, 1471 | initializer = property.initializer) 1472 | } 1473 |} 1474 |""" 1475 .trimMargin(), 1476 deduceMaxWidth = true) 1477 1478 @Test anonymous functionnull1479 fun `anonymous function`() = 1480 assertFormatted( 1481 """ 1482 |fun f() { 1483 | setListener( 1484 | fun(number: Int) { 1485 | println(number) 1486 | }) 1487 |} 1488 |""" 1489 .trimMargin()) 1490 1491 @Test anonymous function with receivernull1492 fun `anonymous function with receiver`() = 1493 assertFormatted( 1494 """ 1495 |fun f() { 1496 | setListener( 1497 | fun View.() { 1498 | println(this) 1499 | }) 1500 |} 1501 |""" 1502 .trimMargin()) 1503 1504 @Test when() with a subject expressionnull1505 fun `when() with a subject expression`() = 1506 assertFormatted( 1507 """ 1508 |fun f(x: Int) { 1509 | when (x) { 1510 | 1 -> print(1) 1511 | 2 -> print(2) 1512 | 3 -> 1513 | // Comment 1514 | print(3) 1515 | else -> { 1516 | print("else") 1517 | } 1518 | } 1519 |} 1520 |""" 1521 .trimMargin()) 1522 1523 @Test when() expression with complex predicatesnull1524 fun `when() expression with complex predicates`() = 1525 assertFormatted( 1526 """ 1527 |fun f(x: Int) { 1528 | when { 1529 | x == 1 || x == 2 -> print(1) 1530 | x == 3 && x != 4 -> print(2) 1531 | else -> { 1532 | print(3) 1533 | } 1534 | } 1535 |} 1536 |""" 1537 .trimMargin()) 1538 1539 @Test when() expression with several conditionsnull1540 fun `when() expression with several conditions`() = 1541 assertFormatted( 1542 """ 1543 |fun f(x: Int) { 1544 | when { 1545 | 0, 1546 | 1 -> print(1) 1547 | else -> print(0) 1548 | } 1549 |} 1550 |""" 1551 .trimMargin()) 1552 1553 @Test when() expression with is and innull1554 fun `when() expression with is and in`() = 1555 assertFormatted( 1556 """ 1557 |fun f(x: Int) { 1558 | when (x) { 1559 | is String -> print(1) 1560 | !is String -> print(2) 1561 | in 1..3 -> print() 1562 | in a..b -> print() 1563 | in a..3 -> print() 1564 | in 1..b -> print() 1565 | !in 1..b -> print() 1566 | else -> print(3) 1567 | } 1568 |} 1569 |""" 1570 .trimMargin()) 1571 1572 @Test when() expression with enum valuesnull1573 fun `when() expression with enum values`() = 1574 assertFormatted( 1575 """ 1576 |fun f(x: Color) { 1577 | when (x) { 1578 | is Color.Red -> print(1) 1579 | is Color.Green -> print(2) 1580 | else -> print(3) 1581 | } 1582 |} 1583 |""" 1584 .trimMargin()) 1585 1586 @Test when() expression with generic matcher and exhaustivenull1587 fun `when() expression with generic matcher and exhaustive`() = 1588 assertFormatted( 1589 """ 1590 |fun f(x: Result) { 1591 | when (x) { 1592 | is Success<*> -> print(1) 1593 | is Failure -> print(2) 1594 | }.exhaustive 1595 |} 1596 |""" 1597 .trimMargin()) 1598 1599 @Test when() expression with multiline conditionnull1600 fun `when() expression with multiline condition`() = 1601 assertFormatted( 1602 """ 1603 |-------------------------- 1604 |fun foo() { 1605 | when (expressions1 + 1606 | expression2 + 1607 | expression3) { 1608 | 1 -> print(1) 1609 | 2 -> print(2) 1610 | } 1611 | 1612 | when (foo( 1613 | expressions1 && 1614 | expression2 && 1615 | expression3)) { 1616 | 1 -> print(1) 1617 | 2 -> print(2) 1618 | } 1619 |} 1620 |""" 1621 .trimMargin(), 1622 deduceMaxWidth = true) 1623 1624 @Test lambda assigned to variable does not break before bracenull1625 fun `lambda assigned to variable does not break before brace`() = 1626 assertFormatted( 1627 """ 1628 |fun doIt() { 1629 | val lambda = { 1630 | doItOnce() 1631 | doItTwice() 1632 | } 1633 |} 1634 | 1635 |fun foo() = { 1636 | doItOnce() 1637 | doItTwice() 1638 |} 1639 |""" 1640 .trimMargin()) 1641 1642 @Test when() expression storing in local variablenull1643 fun `when() expression storing in local variable`() = 1644 assertFormatted( 1645 """ 1646 |fun f(x: Result) { 1647 | when (val y = x.improved()) { 1648 | is Success<*> -> print(y) 1649 | is Failure -> print(2) 1650 | } 1651 |} 1652 |""" 1653 .trimMargin()) 1654 1655 @Test line breaks inside when expressions and conditionsnull1656 fun `line breaks inside when expressions and conditions`() = 1657 assertFormatted( 1658 """ 1659 |fun f() { 1660 | return Text.create(c) 1661 | .onTouch { 1662 | when (it.motionEvent.action) { 1663 | ACTION_DOWN -> 1664 | Toast.makeText(it.view.context, "Down!", Toast.LENGTH_SHORT, blablabla).show() 1665 | ACTION_UP -> Toast.makeText(it.view.context, "Up!", Toast.LENGTH_SHORT).show() 1666 | ACTION_DOWN -> 1667 | Toast.makeText( 1668 | it.view.context, "Down!", Toast.LENGTH_SHORT, blablabla, blablabl, blabla) 1669 | .show() 1670 | } 1671 | } 1672 | .build() 1673 |} 1674 |""" 1675 .trimMargin()) 1676 1677 @Test function return typesnull1678 fun `function return types`() = 1679 assertFormatted( 1680 """ 1681 |fun f1(): Int = 0 1682 | 1683 |fun f2(): Int {} 1684 |""" 1685 .trimMargin()) 1686 1687 @Test multi line function without a block bodynull1688 fun `multi line function without a block body`() = 1689 assertFormatted( 1690 """ 1691 |------------------------- 1692 |fun longFunctionNoBlock(): 1693 | Int = 1694 | 1234567 + 1234567 1695 | 1696 |fun shortFun(): Int = 1697 | 1234567 + 1234567 1698 |""" 1699 .trimMargin(), 1700 deduceMaxWidth = true) 1701 1702 @Test 1703 fun `return type doesn't fit in one line`() = 1704 assertFormatted( 1705 """ 1706 |-------------------------------------------------- 1707 |interface X { 1708 | fun f( 1709 | arg1: Arg1Type, 1710 | arg2: Arg2Type 1711 | ): Map<String, Map<String, Double>>? { 1712 | // 1713 | } 1714 | 1715 | fun functionWithGenericReturnType( 1716 | arg1: Arg1Type, 1717 | arg2: Arg2Type 1718 | ): Map<String, Map<String, Double>>? { 1719 | // 1720 | } 1721 |} 1722 |""" 1723 .trimMargin(), 1724 deduceMaxWidth = true) 1725 1726 @Test list of superclassesnull1727 fun `list of superclasses`() = 1728 assertFormatted( 1729 """ 1730 |class Derived2 : Super1, Super2 {} 1731 | 1732 |class Derived1 : Super1, Super2 1733 | 1734 |class Derived3(a: Int) : Super1(a) 1735 | 1736 |class Derived4 : Super1() 1737 | 1738 |class Derived5 : Super3<Int>() 1739 |""" 1740 .trimMargin()) 1741 1742 @Test list of superclasses over multiple linesnull1743 fun `list of superclasses over multiple lines`() = 1744 assertFormatted( 1745 """ 1746 |-------------------- 1747 |class Derived2 : 1748 | Super1, 1749 | Super2 {} 1750 | 1751 |class Derived1 : 1752 | Super1, Super2 1753 | 1754 |class Derived3( 1755 | a: Int 1756 |) : Super1(a) 1757 | 1758 |class Derived4 : 1759 | Super1() 1760 | 1761 |class Derived5 : 1762 | Super3<Int>() 1763 |""" 1764 .trimMargin(), 1765 deduceMaxWidth = true) 1766 1767 @Test annotations with parametersnull1768 fun `annotations with parameters`() = 1769 assertFormatted( 1770 """ 1771 |@AnnWithArrayValue(1, 2, 3) class C 1772 |""" 1773 .trimMargin()) 1774 1775 @Test 1776 fun `method modifiers`() = 1777 assertFormatted( 1778 """ 1779 |override internal fun f() {} 1780 |""" 1781 .trimMargin()) 1782 1783 @Test class modifiersnull1784 fun `class modifiers`() = 1785 assertFormatted( 1786 """ 1787 |abstract class Foo 1788 | 1789 |inner class Foo 1790 | 1791 |final class Foo 1792 | 1793 |open class Foo 1794 |""" 1795 .trimMargin()) 1796 1797 @Test 1798 fun `kdoc comments`() { 1799 val code = 1800 """ 1801 |/** 1802 | * foo 1803 | */ class F { 1804 | 1805 | } 1806 |""" 1807 .trimMargin() 1808 val expected = 1809 """ 1810 |/** foo */ 1811 |class F {} 1812 |""" 1813 .trimMargin() 1814 assertThatFormatting(code).isEqualTo(expected) 1815 } 1816 1817 @Test nested kdoc commentsnull1818 fun `nested kdoc comments`() { 1819 val code = 1820 """ 1821 |/** 1822 | * foo /* bla */ 1823 | */ class F { 1824 | 1825 | } 1826 |""" 1827 .trimMargin() 1828 val expected = 1829 """ 1830 |/** foo /* bla */ */ 1831 |class F {} 1832 |""" 1833 .trimMargin() 1834 assertThatFormatting(code).isEqualTo(expected) 1835 } 1836 1837 @Test nested kdoc inside code blocknull1838 fun `nested kdoc inside code block`() = 1839 assertFormatted( 1840 """ 1841 |/** 1842 | * ``` 1843 | * edit -> { /* open edit screen */ } 1844 | * ``` 1845 | */ 1846 |fun foo() {} 1847 |""" 1848 .trimMargin()) 1849 1850 @Test formatting kdoc doesn't add p HTML tagsnull1851 fun `formatting kdoc doesn't add p HTML tags`() = 1852 assertFormatted( 1853 """ 1854 |/** 1855 | * Bla bla bla bla 1856 | * 1857 | * This is an inferred paragraph, and as you can see, we don't add a p tag to it, even though bla 1858 | * bla. 1859 | * 1860 | * <p>On the other hand, we respect existing tags, and don't remove them. 1861 | */ 1862 |""" 1863 .trimMargin()) 1864 1865 @Test 1866 fun `formatting kdoc preserves lists`() = 1867 assertFormatted( 1868 """ 1869 |/** 1870 | * Here are some fruit I like: 1871 | * - Banana 1872 | * - Apple 1873 | * 1874 | * This is another paragraph 1875 | */ 1876 |""" 1877 .trimMargin()) 1878 1879 @Test 1880 fun `formatting kdoc lists with line wraps breaks and merges correctly`() { 1881 val code = 1882 """ 1883 |/** 1884 | * Here are some fruit I like: 1885 | * - Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana 1886 | * - Apple Apple Apple Apple 1887 | * Apple Apple 1888 | * 1889 | * This is another paragraph 1890 | */ 1891 |""" 1892 .trimMargin() 1893 val expected = 1894 """ 1895 |/** 1896 | * Here are some fruit I like: 1897 | * - Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana Banana 1898 | * Banana Banana Banana Banana Banana 1899 | * - Apple Apple Apple Apple Apple Apple 1900 | * 1901 | * This is another paragraph 1902 | */ 1903 |""" 1904 .trimMargin() 1905 assertThatFormatting(code).isEqualTo(expected) 1906 } 1907 1908 @Test 1909 fun `formatting kdoc preserves lists of asterisks`() = 1910 assertFormatted( 1911 """ 1912 |/** 1913 | * Here are some fruit I like: 1914 | * * Banana 1915 | * * Apple 1916 | * 1917 | * This is another paragraph 1918 | */ 1919 |""" 1920 .trimMargin()) 1921 1922 @Test 1923 fun `formatting kdoc preserves numbered`() = 1924 assertFormatted( 1925 """ 1926 |/** 1927 | * Here are some fruit I like: 1928 | * 1. Banana 1929 | * 2. Apple 1930 | * 1931 | * This is another paragraph 1932 | */ 1933 |""" 1934 .trimMargin()) 1935 1936 @Test 1937 fun `formatting kdoc with markdown errors`() = 1938 assertFormatted( 1939 """ 1940 |/** \[ */ 1941 |fun markdownError() = Unit 1942 |""" 1943 .trimMargin()) 1944 1945 @Test 1946 fun `return statement with value`() = 1947 assertFormatted( 1948 """ 1949 |fun random(): Int { 1950 | return 4 1951 |} 1952 |""" 1953 .trimMargin()) 1954 1955 @Test return statement without valuenull1956 fun `return statement without value`() = 1957 assertFormatted( 1958 """ 1959 |fun print(b: Boolean) { 1960 | print(b) 1961 | return 1962 |} 1963 |""" 1964 .trimMargin()) 1965 1966 @Test return expression without valuenull1967 fun `return expression without value`() = 1968 assertFormatted( 1969 """ 1970 |fun print(b: Boolean?) { 1971 | print(b ?: return) 1972 |} 1973 |""" 1974 .trimMargin()) 1975 1976 @Test if statement without elsenull1977 fun `if statement without else`() = 1978 assertFormatted( 1979 """ 1980 |fun maybePrint(b: Boolean) { 1981 | if (b) { 1982 | println(b) 1983 | } 1984 |} 1985 |""" 1986 .trimMargin()) 1987 1988 @Test if statement with elsenull1989 fun `if statement with else`() = 1990 assertFormatted( 1991 """ 1992 |fun maybePrint(b: Boolean) { 1993 | if (b) { 1994 | println(2) 1995 | } else { 1996 | println(1) 1997 | } 1998 |} 1999 |""" 2000 .trimMargin()) 2001 2002 @Test if expression with elsenull2003 fun `if expression with else`() = 2004 assertFormatted( 2005 """ 2006 |fun maybePrint(b: Boolean) { 2007 | println(if (b) 1 else 2) 2008 | println( 2009 | if (b) { 2010 | val a = 1 + 1 2011 | 2 * a 2012 | } else 2) 2013 | return if (b) 1 else 2 2014 |} 2015 |""" 2016 .trimMargin()) 2017 2018 @Test if expression with break before elsenull2019 fun `if expression with break before else`() = 2020 assertFormatted( 2021 """ 2022 |------------------------------ 2023 |fun compute(b: Boolean) { 2024 | val c = 2025 | if (a + b < 20) a + b 2026 | else a 2027 | return if (a + b < 20) a + b 2028 | else c 2029 |} 2030 |""" 2031 .trimMargin(), 2032 deduceMaxWidth = true) 2033 2034 @Test if expression with break before expressionsnull2035 fun `if expression with break before expressions`() = 2036 assertFormatted( 2037 """ 2038 |-------------------------- 2039 |fun compute(b: Boolean) { 2040 | val c = 2041 | if (a + b < 20) 2042 | a + b 2043 | else if (a < 20) a 2044 | else 2045 | a + b + b + 1000 2046 | return if (a + b < 20) 2047 | a + b 2048 | else c 2049 |} 2050 |""" 2051 .trimMargin(), 2052 deduceMaxWidth = true) 2053 2054 @Test blocky expressions in if-elsenull2055 fun `blocky expressions in if-else`() = 2056 assertFormatted( 2057 """ 2058 |fun numbers() { 2059 | if (true) 2060 | do { 2061 | eat("is") 2062 | matches += type() 2063 | } while (eat(",")) 2064 | else 2065 | while (1 < 2) { 2066 | println("Everything is okay") 2067 | } 2068 |} 2069 |""" 2070 .trimMargin()) 2071 2072 @Test if expression with multiline conditionnull2073 fun `if expression with multiline condition`() = 2074 assertFormatted( 2075 """ 2076 |---------------------------- 2077 |fun foo() { 2078 | if (expressions1 && 2079 | expression2 && 2080 | expression3) { 2081 | bar() 2082 | } 2083 | 2084 | if (foo( 2085 | expressions1 && 2086 | expression2 && 2087 | expression3)) { 2088 | bar() 2089 | } 2090 |} 2091 |""" 2092 .trimMargin(), 2093 deduceMaxWidth = true) 2094 2095 @Test assignment expression on multiple linesnull2096 fun `assignment expression on multiple lines`() = 2097 assertFormatted( 2098 """ 2099 |-------------------------------------------------- 2100 |fun f() { 2101 | var myVariable = 5 2102 | myVariable = 2103 | function1(4, 60, 8) + function2(57, 39, 20) 2104 |} 2105 |""" 2106 .trimMargin(), 2107 deduceMaxWidth = true) 2108 2109 @Test A program that tickled a bug in KotlinInputnull2110 fun `A program that tickled a bug in KotlinInput`() = 2111 assertFormatted( 2112 """ 2113 |val x = 2 2114 |""" 2115 .trimMargin()) 2116 2117 @Test 2118 fun `a few variations of constructors`() = 2119 assertFormatted( 2120 """ 2121 |class Foo constructor(number: Int) {} 2122 | 2123 |class Foo2 private constructor(number: Int) {} 2124 | 2125 |class Foo3 @Inject constructor(number: Int) {} 2126 | 2127 |class Foo4 @Inject private constructor(number: Int) {} 2128 | 2129 |class Foo5 2130 |@Inject 2131 |private constructor( 2132 | number: Int, 2133 | number2: Int, 2134 | number3: Int, 2135 | number4: Int, 2136 | number5: Int, 2137 | number6: Int 2138 |) {} 2139 |""" 2140 .trimMargin()) 2141 2142 @Test a primary constructor without a class bodynull2143 fun `a primary constructor without a class body `() = 2144 assertFormatted( 2145 """ 2146 |------------------------- 2147 |data class Foo( 2148 | val number: Int = 0 2149 |) 2150 |""" 2151 .trimMargin(), 2152 deduceMaxWidth = true) 2153 2154 @Test 2155 fun `a secondary constructor without a body`() = 2156 assertFormatted( 2157 """ 2158 |--------------------------- 2159 |data class Foo { 2160 | constructor( 2161 | val number: Int = 0 2162 | ) 2163 |} 2164 |""" 2165 .trimMargin(), 2166 deduceMaxWidth = true) 2167 2168 @Test a secondary constructor with a body breaks before closing parenthesisnull2169 fun `a secondary constructor with a body breaks before closing parenthesis`() = 2170 assertFormatted( 2171 """ 2172 |--------------------------- 2173 |data class Foo { 2174 | constructor( 2175 | val number: Int = 0 2176 | ) {} 2177 |} 2178 |""" 2179 .trimMargin(), 2180 deduceMaxWidth = true) 2181 2182 @Test a constructor with many arguments over breaking to next linenull2183 fun `a constructor with many arguments over breaking to next line`() = 2184 assertFormatted( 2185 """ 2186 |data class Foo( 2187 | val number: Int, 2188 | val name: String, 2189 | val age: Int, 2190 | val title: String, 2191 | val offspring2: List<Foo> 2192 |) {} 2193 |""" 2194 .trimMargin()) 2195 2196 @Test a constructor with keyword and many arguments over breaking to next linenull2197 fun `a constructor with keyword and many arguments over breaking to next line`() = 2198 assertFormatted( 2199 """ 2200 |data class Foo 2201 |constructor( 2202 | val name: String, 2203 | val age: Int, 2204 | val title: String, 2205 | val offspring: List<Foo>, 2206 | val foo: String 2207 |) {} 2208 |""" 2209 .trimMargin()) 2210 2211 @Test a constructor with many arguments over multiple linesnull2212 fun `a constructor with many arguments over multiple lines`() = 2213 assertFormatted( 2214 """ 2215 |-------------------------------------------------- 2216 |data class Foo 2217 |constructor( 2218 | val number: Int, 2219 | val name: String, 2220 | val age: Int, 2221 | val title: String, 2222 | val offspring: List<Foo> 2223 |) {} 2224 |""" 2225 .trimMargin(), 2226 deduceMaxWidth = true) 2227 2228 @Test handle secondary constructorsnull2229 fun `handle secondary constructors`() = 2230 assertFormatted( 2231 """ 2232 |class Foo private constructor(number: Int) { 2233 | private constructor(n: Float) : this(1) 2234 | private constructor(n: Double) : this(1) { 2235 | println("built") 2236 | } 2237 |} 2238 |""" 2239 .trimMargin()) 2240 2241 @Test a secondary constructor with many arguments over multiple linesnull2242 fun `a secondary constructor with many arguments over multiple lines`() = 2243 assertFormatted( 2244 """ 2245 |-------------------------------------------------- 2246 |data class Foo { 2247 | constructor( 2248 | val number: Int, 2249 | val name: String, 2250 | val age: Int, 2251 | val title: String, 2252 | val offspring: List<Foo> 2253 | ) 2254 |} 2255 |""" 2256 .trimMargin(), 2257 deduceMaxWidth = true) 2258 2259 @Test a secondary constructor with many arguments passed to delegatenull2260 fun `a secondary constructor with many arguments passed to delegate`() = 2261 assertFormatted( 2262 """ 2263 |-------------------------------------------------- 2264 |data class Foo { 2265 | constructor( 2266 | val number: Int, 2267 | val name: String, 2268 | val age: Int, 2269 | val title: String, 2270 | val offspring: List<Foo> 2271 | ) : this( 2272 | number, 2273 | name, 2274 | age, 2275 | title, 2276 | offspring, 2277 | offspring) 2278 |} 2279 |""" 2280 .trimMargin(), 2281 deduceMaxWidth = true) 2282 2283 @Test a secondary constructor with no arguments passed to delegatenull2284 fun `a secondary constructor with no arguments passed to delegate`() = 2285 assertFormatted( 2286 """ 2287 |-------------------------------------------------- 2288 |data class Foo { 2289 | constructor() : 2290 | this( 2291 | Foo.createSpeciallyDesignedParameter(), 2292 | Foo.createSpeciallyDesignedParameter(), 2293 | ) 2294 |} 2295 |""" 2296 .trimMargin(), 2297 deduceMaxWidth = true) 2298 2299 @Test secondary constructor with param list that fits in one line, with delegatenull2300 fun `secondary constructor with param list that fits in one line, with delegate`() = 2301 assertFormatted( 2302 """ 2303 |class C { 2304 | constructor( 2305 | context: Context?, 2306 | attrs: AttributeSet?, 2307 | defStyleAttr: Int, 2308 | defStyleRes: Int 2309 | ) : super(context, attrs, defStyleAttr, defStyleRes) { 2310 | init(attrs) 2311 | } 2312 |} 2313 |""" 2314 .trimMargin()) 2315 2316 @Test handle calling super constructor in secondary constructornull2317 fun `handle calling super constructor in secondary constructor`() = 2318 assertFormatted( 2319 """ 2320 |class Foo : Bar { 2321 | internal constructor(number: Int) : super(number) {} 2322 |} 2323 |""" 2324 .trimMargin()) 2325 2326 @Test handle super statement with with type argumentnull2327 fun `handle super statement with with type argument`() = 2328 assertFormatted( 2329 """ 2330 |class Foo : Bar(), FooBar { 2331 | override fun doIt() { 2332 | super<FooBar>.doIt() 2333 | } 2334 |} 2335 |""" 2336 .trimMargin()) 2337 2338 @Test handle super statement with with label argumentnull2339 fun `handle super statement with with label argument`() = 2340 assertFormatted( 2341 """ 2342 |class Foo : Bar(), FooBar { 2343 | override fun doIt() { 2344 | foo.doThat { 2345 | super<FooBar>@Foo.doIt() 2346 | 2347 | // this one is actually generics on the call expression, not super 2348 | super@Foo<FooBar>.doIt() 2349 | } 2350 | } 2351 |} 2352 |""" 2353 .trimMargin()) 2354 2355 @Test primary constructor without parameters with a KDocnull2356 fun `primary constructor without parameters with a KDoc`() = 2357 assertFormatted( 2358 """ 2359 |class Class 2360 |/** A comment */ 2361 |constructor() {} 2362 |""" 2363 .trimMargin()) 2364 2365 @Test handle objectsnull2366 fun `handle objects`() = 2367 assertFormatted( 2368 """ 2369 |object Foo(n: Int) {} 2370 |""" 2371 .trimMargin()) 2372 2373 @Test handle object expressionnull2374 fun `handle object expression`() = 2375 assertFormatted( 2376 """ 2377 |fun f(): Any { 2378 | return object : Adapter() {} 2379 |} 2380 |""" 2381 .trimMargin()) 2382 2383 @Test handle object expression in parenthesisnull2384 fun `handle object expression in parenthesis`() = 2385 assertFormatted( 2386 """ 2387 |fun f(): Any { 2388 | return (object : Adapter() {}) 2389 |} 2390 |""" 2391 .trimMargin()) 2392 2393 @Test handle array indexing operatornull2394 fun `handle array indexing operator`() = 2395 assertFormatted( 2396 """ 2397 |fun f(a: Magic) { 2398 | a[3] 2399 | b[3, 4] 2400 |} 2401 |""" 2402 .trimMargin()) 2403 2404 @Test keep array indexing grouped with expression is possiblenull2405 fun `keep array indexing grouped with expression is possible`() = 2406 assertFormatted( 2407 """ 2408 |----------------------- 2409 |fun f(a: Magic) { 2410 | foo.bar() 2411 | .foobar[1, 2, 3] 2412 | foo.bar() 2413 | .foobar[ 2414 | 1, 2415 | 2, 2416 | 3, 2417 | 4, 2418 | 5] 2419 | foo.bar() 2420 | .foobar[1, 2, 3] 2421 | .barfoo[3, 2, 1] 2422 |} 2423 |""" 2424 .trimMargin(), 2425 deduceMaxWidth = true) 2426 2427 @Test mixed chainsnull2428 fun `mixed chains`() = 2429 assertFormatted( 2430 """ 2431 |----------------------- 2432 |fun f(a: Magic) { 2433 | foo.bar() 2434 | .foobar[1, 2, 3] 2435 | foo.bar() 2436 | .foobar[ 2437 | 1, 2438 | 2, 2439 | 3, 2440 | 4, 2441 | 5] 2442 | foo.bar() 2443 | .foobar[1, 2, 3] 2444 | .barfoo[3, 2, 1] 2445 |} 2446 |""" 2447 .trimMargin(), 2448 deduceMaxWidth = true) 2449 2450 @Test handle destructuring declarationnull2451 fun `handle destructuring declaration`() = 2452 assertFormatted( 2453 """ 2454 |----------------------------------------------- 2455 |fun f() { 2456 | val (a, b: Int) = listOf(1, 2) 2457 | val (asd, asd, asd, asd, asd, asd, asd) = 2458 | foo.bar(asdasd, asdasd) 2459 | 2460 | val (accountType, accountId) = 2461 | oneTwoThreeFourFiveSixSeven( 2462 | foo, bar, zed, boo) 2463 |} 2464 |""" 2465 .trimMargin(), 2466 deduceMaxWidth = true) 2467 @Test chains with derferences and array indexingnull2468 fun `chains with derferences and array indexing`() = 2469 assertFormatted( 2470 """ 2471 |----------------------- 2472 |fun f() { 2473 | foo.bam() 2474 | .uber!![0, 1, 2] 2475 | .boom()[1, 3, 5] 2476 | .lah 2477 | .doo { it } 2478 | .feep[1] 2479 | as Boo 2480 |} 2481 |""" 2482 .trimMargin(), 2483 deduceMaxWidth = true) 2484 2485 @Test block like syntax after dereferences and indexing with short linesnull2486 fun `block like syntax after dereferences and indexing with short lines`() = 2487 assertFormatted( 2488 """ 2489 |----------------------- 2490 |fun f() { 2491 | foo.bam() 2492 | .uber!![0, 1, 2] 2493 | .forEach { 2494 | println(it) 2495 | } 2496 |} 2497 |""" 2498 .trimMargin(), 2499 deduceMaxWidth = true) 2500 2501 @Test block like syntax after dereferences and indexing with long linesnull2502 fun `block like syntax after dereferences and indexing with long lines`() = 2503 assertFormatted( 2504 """ 2505 |---------------------------------- 2506 |fun f() { 2507 | foo.uber!![0, 1, 2].forEach { 2508 | println(it) 2509 | } 2510 |} 2511 |""" 2512 .trimMargin(), 2513 deduceMaxWidth = true) 2514 2515 @Test try to keep type names togethernull2516 fun `try to keep type names together`() = 2517 assertFormatted( 2518 """ 2519 |----------------------- 2520 |fun f() { 2521 | com.facebook.foo.Foo( 2522 | 1, 2) 2523 | com.facebook.foo 2524 | .Foo(1, 2) 2525 | .andAlsoThis() 2526 | com.facebook.Foo.foo( 2527 | 1, 2) 2528 | com.facebook 2529 | .foobarFoo 2530 | .foo(1, 2) 2531 | foo.invoke( 2532 | foo, bar, bar) 2533 | foo.invoke(foo, bar) 2534 | .invoke() 2535 | FooFoo.foooooooo() 2536 | .foooooooo() 2537 |} 2538 |""" 2539 .trimMargin(), 2540 deduceMaxWidth = true) 2541 2542 @Test avoid breaking brackets and keep them with array namenull2543 fun `avoid breaking brackets and keep them with array name`() = 2544 assertFormatted( 2545 """ 2546 |------------------------------------------------------------------------- 2547 |fun f() { 2548 | val a = 2549 | invokeIt(context.packageName) 2550 | .getInternalMutablePackageInfo(context.packageName) 2551 | .someItems[0] 2552 | .getInternalMutablePackageInfo(context.packageName) 2553 | .someItems[0] 2554 | .doIt() 2555 |} 2556 |""" 2557 .trimMargin(), 2558 deduceMaxWidth = true) 2559 2560 @Test keep function call with type name even if array expression is nextnull2561 fun `keep function call with type name even if array expression is next`() = 2562 assertFormatted( 2563 """ 2564 |class f { 2565 | private val somePropertyWithBackingOne 2566 | get() = 2567 | _somePropertyWithBackingOne 2568 | ?: Classname.getStuff<SomePropertyRelatedClassProvider>(requireContext())[ 2569 | somePropertiesProvider, somePropertyCallbacks] 2570 | .also { _somePropertyWithBackingOne = it } 2571 |} 2572 |""" 2573 .trimMargin()) 2574 2575 @Test array access in middle of chain and end of it behaves similarlynull2576 fun `array access in middle of chain and end of it behaves similarly`() = 2577 assertFormatted( 2578 """ 2579 |-------------------------------------- 2580 |fun f() { 2581 | if (aaaaa == null || 2582 | aaaaa.bbbbb[0] == null || 2583 | aaaaa.bbbbb[0].cc == null || 2584 | aaaaa.bbbbb[0].dddd == null) { 2585 | println() 2586 | } 2587 |} 2588 |""" 2589 .trimMargin(), 2590 deduceMaxWidth = true) 2591 2592 @Test handle qmark for nullalble typesnull2593 fun `handle qmark for nullalble types`() = 2594 assertFormatted( 2595 """ 2596 |fun doItWithNullReturns(a: String, b: String): Int? { 2597 | return 5 2598 |} 2599 | 2600 |fun doItWithNulls(a: String, b: String?) {} 2601 |""" 2602 .trimMargin()) 2603 2604 @Test nullable function typenull2605 fun `nullable function type`() = 2606 assertFormatted( 2607 """ 2608 |var listener: ((Boolean) -> Unit)? = null 2609 |""" 2610 .trimMargin()) 2611 2612 @Test 2613 fun `redundant parenthesis in function types`() = 2614 assertFormatted( 2615 """ 2616 |val a: (Int) = 7 2617 | 2618 |var listener: ((Boolean) -> Unit) = foo 2619 |""" 2620 .trimMargin()) 2621 2622 @Test 2623 fun `handle string literals`() = 2624 assertFormatted( 2625 """ 2626 |fun doIt(world: String) { 2627 | println("Hello world!") 2628 | println("Hello! ${'$'}world") 2629 | println("Hello! ${'$'}{"wor" + "ld"}") 2630 |} 2631 |""" 2632 .trimMargin()) 2633 2634 @Test handle multiline string literalsnull2635 fun `handle multiline string literals`() = 2636 assertFormatted( 2637 """ 2638 |fun doIt(world: String) { 2639 | println(${"\"".repeat(3)}Hello 2640 | world!${"\"".repeat(3)}) 2641 |} 2642 |""" 2643 .trimMargin()) 2644 2645 @Test Trailing whitespaces are preserved in multiline stringsnull2646 fun `Trailing whitespaces are preserved in multiline strings`() { 2647 val code = 2648 listOf( 2649 "fun doIt(world: String) {", 2650 " println(\"\"\"This line has trailing whitespace ", 2651 " world!\"\"\")", 2652 " println(\"\"\"This line has trailing whitespace \$s ", 2653 " world!\"\"\")", 2654 " println(\"\"\"This line has trailing whitespace \${s} ", 2655 " world!\"\"\")", 2656 " println(\"\"\"This line has trailing whitespace \$ ", 2657 " world!\"\"\")", 2658 "}", 2659 "") 2660 .joinToString("\n") 2661 assertThatFormatting(code).allowTrailingWhitespace().isEqualTo(code) 2662 } 2663 2664 @Test 2665 fun `Consecutive line breaks in multiline strings are preserved`() = 2666 assertFormatted( 2667 """ 2668 |val x = $TQ 2669 | 2670 | 2671 | 2672 |Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do 2673 |$TQ 2674 |""" 2675 .trimMargin()) 2676 2677 @Test 2678 fun `Trailing spaces in a comment are not preserved`() { 2679 val before = 2680 listOf("// trailing spaces in a comment are not preserved ", "").joinToString("\n") 2681 val after = listOf("// trailing spaces in a comment are not preserved", "").joinToString("\n") 2682 assertThatFormatting(before).allowTrailingWhitespace().isEqualTo(after) 2683 } 2684 2685 @Test 2686 fun `Code with tombstones is not supported`() { 2687 val code = 2688 """ 2689 |fun good() { 2690 | // ${'\u0003'} 2691 |} 2692 |""" 2693 .trimMargin() 2694 try { 2695 Formatter.format(code) 2696 fail() 2697 } catch (e: ParseError) { 2698 assertThat(e.errorDescription).contains("\\u0003") 2699 assertThat(e.lineColumn.line).isEqualTo(1) 2700 assertThat(e.lineColumn.column).isEqualTo(5) 2701 } 2702 } 2703 2704 @Test handle some basic generics scenariosnull2705 fun `handle some basic generics scenarios`() = 2706 assertFormatted( 2707 """ 2708 |fun <T> doIt(a: List<T>): List<Int>? { 2709 | val b: List<Int> = convert<Int>(listOf(5, 4)) 2710 | return b 2711 |} 2712 | 2713 |class Foo<T> 2714 |""" 2715 .trimMargin()) 2716 2717 @Test handle for loopsnull2718 fun `handle for loops`() = 2719 assertFormatted( 2720 """ 2721 |fun f(a: List<Int>) { 2722 | for (i in a.indices) { 2723 | println(i) 2724 | } 2725 |} 2726 |""" 2727 .trimMargin()) 2728 2729 @Test handle for loops with long dot chainsnull2730 fun `handle for loops with long dot chains`() = 2731 assertFormatted( 2732 """ 2733 |----------------------------------- 2734 |fun f(a: Node<Int>) { 2735 | for (child in node.next.data()) { 2736 | println(child) 2737 | } 2738 | for (child in 2739 | node.next.next.data()) { 2740 | println(child) 2741 | } 2742 | for (child in 2743 | node.next.next.next.next 2744 | .data()) { 2745 | println(child) 2746 | } 2747 |} 2748 |""" 2749 .trimMargin(), 2750 deduceMaxWidth = true) 2751 2752 @Test when two lambdas following a call, indent the lambda properlynull2753 fun `when two lambdas following a call, indent the lambda properly`() = 2754 assertFormatted( 2755 """ 2756 |---------------------------- 2757 |fun f() { 2758 | doIt() 2759 | .apply { 2760 | number = 2761 | computeNumber1() 2762 | } 2763 | .apply { 2764 | number = 2 * number 2765 | } 2766 |} 2767 |""" 2768 .trimMargin(), 2769 deduceMaxWidth = true) 2770 2771 @Test when two lambdas following a field, indent the lambda properlynull2772 fun `when two lambdas following a field, indent the lambda properly`() = 2773 assertFormatted( 2774 """ 2775 |---------------------------- 2776 |fun f() { 2777 | field 2778 | .apply { 2779 | number = 2780 | computeNumber1() 2781 | } 2782 | .apply { 2783 | number = 2 * number 2784 | } 2785 |} 2786 |""" 2787 .trimMargin(), 2788 deduceMaxWidth = true) 2789 2790 @Test break after 'four' (even though it's 4 chars long) because there's a lambda afterwardsnull2791 fun `break after 'four' (even though it's 4 chars long) because there's a lambda afterwards`() = 2792 assertFormatted( 2793 """ 2794 |fun f() { 2795 | four 2796 | .let { 2797 | // 2798 | foo() 2799 | } 2800 | .methodCall() 2801 |} 2802 |""" 2803 .trimMargin()) 2804 2805 @Test keep last expression in qualified indentednull2806 fun `keep last expression in qualified indented`() = 2807 assertFormatted( 2808 """ 2809 |---------------------------- 2810 |fun f() { 2811 | Stuff() 2812 | .doIt( 2813 | Foo.doIt() 2814 | .doThat()) 2815 | .doIt( 2816 | Foo.doIt() 2817 | .doThat()) 2818 |} 2819 |""" 2820 .trimMargin(), 2821 deduceMaxWidth = true) 2822 2823 @Test properly place lambda arguments into blocksnull2824 fun `properly place lambda arguments into blocks`() = 2825 assertFormatted( 2826 """ 2827 |----------------------- 2828 |fun f() { 2829 | foo { 2830 | red.orange.yellow() 2831 | } 2832 | 2833 | foo.bar { 2834 | red.orange.yellow() 2835 | } 2836 |} 2837 |""" 2838 .trimMargin(), 2839 deduceMaxWidth = true) 2840 2841 @Test properly handle one statement lambda with commentnull2842 fun `properly handle one statement lambda with comment`() = 2843 assertFormatted( 2844 """ 2845 |----------------------- 2846 |fun f() { 2847 | foo { 2848 | // this is a comment 2849 | red.orange.yellow() 2850 | } 2851 | foo { 2852 | /* this is also a comment */ 2853 | red.orange.yellow() 2854 | } 2855 | foo.bar { 2856 | // this is a comment 2857 | red.orange.yellow() 2858 | } 2859 | foo.bar() { 2860 | // this is a comment 2861 | red.orange.yellow() 2862 | } 2863 | foo.bar { 2864 | /* this is also a comment */ 2865 | red.orange.yellow() 2866 | } 2867 |} 2868 |""" 2869 .trimMargin(), 2870 deduceMaxWidth = true) 2871 2872 @Test properly handle one statement lambda with comment after body statementsnull2873 fun `properly handle one statement lambda with comment after body statements`() = 2874 assertFormatted( 2875 """ 2876 |----------------------- 2877 |fun f() { 2878 | foo { 2879 | red.orange.yellow() 2880 | // this is a comment 2881 | } 2882 | foo { 2883 | red.orange.yellow() 2884 | /* this is also a comment */ 2885 | } 2886 | foo.bar { 2887 | red.orange.yellow() 2888 | // this is a comment 2889 | } 2890 | foo.bar() { 2891 | red.orange.yellow() 2892 | // this is a comment 2893 | } 2894 | foo.bar { 2895 | red.orange.yellow() 2896 | /* this is also a comment */ 2897 | } 2898 | red.orange.yellow() 2899 | // this is a comment 2900 |} 2901 |""" 2902 .trimMargin(), 2903 deduceMaxWidth = true) 2904 2905 @Test try to keep expression in the same line until the first lambdanull2906 fun `try to keep expression in the same line until the first lambda`() = 2907 assertFormatted( 2908 """ 2909 |------------------------- 2910 |fun f() { 2911 | foo.bar.bar?.let { 2912 | a() 2913 | } 2914 | foo.bar.bar?.let { 2915 | action() 2916 | action2() 2917 | } 2918 | foo.bar.bar.bar.bar 2919 | ?.let { a() } 2920 | foo.bar.bar.bar.bar 2921 | ?.let { 2922 | action() 2923 | action2() 2924 | } 2925 |} 2926 |""" 2927 .trimMargin(), 2928 deduceMaxWidth = true) 2929 2930 @Test different indentation in chained callsnull2931 fun `different indentation in chained calls`() = 2932 assertFormatted( 2933 """ 2934 |--------------------------- 2935 |fun f() { 2936 | fooDdoIt( 2937 | foo1, foo2, foo3) 2938 | foo.doIt( 2939 | foo1, foo2, foo3) 2940 | foo.doIt( 2941 | foo1, foo2, foo3) 2942 | .doThat() 2943 |} 2944 |""" 2945 .trimMargin(), 2946 deduceMaxWidth = true) 2947 2948 @Test always add a conditional break for a lambda which is not lastnull2949 fun `always add a conditional break for a lambda which is not last`() = 2950 assertFormatted( 2951 """ 2952 |-------------------- 2953 |fun f() { 2954 | foofoo 2955 | .doIt { 2956 | doStuff() 2957 | } 2958 | .doIt { 2959 | doStuff() 2960 | } 2961 |} 2962 |""" 2963 .trimMargin(), 2964 deduceMaxWidth = true) 2965 2966 @Test keep parenthesis and braces together when there's only one lambda argumentnull2967 fun `keep parenthesis and braces together when there's only one lambda argument`() = 2968 assertFormatted( 2969 """ 2970 |fun f() { 2971 | doIt({}) 2972 | doIt({ it + it }) 2973 | doIt({ 2974 | val a = it 2975 | a + a 2976 | }) 2977 | doIt(functor = { it + it }) 2978 | doIt( 2979 | functor = { 2980 | val a = it 2981 | a + a 2982 | }) 2983 |} 2984 |""" 2985 .trimMargin()) 2986 2987 @Test Qualified typenull2988 fun `Qualified type`() = 2989 assertFormatted( 2990 """ 2991 |fun f() { 2992 | var plusFour: Indent.Const 2993 | var x: Map.Entry<String, Integer> 2994 | var x: List<String>.Iterator 2995 |} 2996 |""" 2997 .trimMargin()) 2998 2999 @Test handle destructuring declaration in for loopnull3000 fun `handle destructuring declaration in for loop`() = 3001 assertFormatted( 3002 """ 3003 |fun f(a: List<Pair<Int, Int>>) { 3004 | for ((x, y: Int) in a) {} 3005 |} 3006 |""" 3007 .trimMargin()) 3008 3009 @Test handle function referencesnull3010 fun `handle function references`() = 3011 assertFormatted( 3012 """ 3013 |-------------------------------- 3014 |fun f(a: List<Int>) { 3015 | a.forEach(::println) 3016 | a.map(Int::toString) 3017 | a.map(String?::isNullOrEmpty) 3018 | a.map( 3019 | SuperLongClassName?:: 3020 | functionName) 3021 | val f = 3022 | SuperLongClassName:: 3023 | functionName 3024 | val g = 3025 | invoke(a, b)::functionName 3026 | val h = 3027 | invoke(a, b, c):: 3028 | functionName 3029 |} 3030 |""" 3031 .trimMargin(), 3032 deduceMaxWidth = true) 3033 3034 @Test handle escaped identifiernull3035 fun `handle escaped identifier`() = 3036 assertFormatted( 3037 """ 3038 |import foo as `foo foo` 3039 |import org.mockito.Mockito.`when` as `yay yay` 3040 | 3041 |fun `spaces in functions`() { 3042 | val `when` = NEVER 3043 | val (`do not`, `ever write`) = SERIOUSLY 3044 | val `a a`: Int 3045 | `yay yay`(`foo foo`) 3046 |} 3047 | 3048 |class `more spaces` 3049 |""" 3050 .trimMargin()) 3051 3052 @Test handle annotations with argumentsnull3053 fun `handle annotations with arguments`() = 3054 assertFormatted( 3055 """ 3056 |@Px fun f(): Int = 5 3057 | 3058 |@Dimenstion(unit = DP) fun g(): Int = 5 3059 | 3060 |@RunWith(MagicRunner::class) 3061 |@Px 3062 |class Test { 3063 | // 3064 |} 3065 |""" 3066 .trimMargin()) 3067 3068 @Test no newlines after annotations if entire expr fits in one linenull3069 fun `no newlines after annotations if entire expr fits in one line`() = 3070 assertFormatted( 3071 """ 3072 |----------------------------------------------- 3073 |@Px @Px fun f(): Int = 5 3074 | 3075 |@Px 3076 |@Px 3077 |@Px 3078 |@Px 3079 |@Px 3080 |@Px 3081 |@Px 3082 |@Px 3083 |fun f(): Int = 5 3084 | 3085 |@Px 3086 |@Px 3087 |fun f(): Int { 3088 | return 5 3089 |} 3090 | 3091 |@Dimenstion(unit = DP) @Px fun g(): Int = 5 3092 | 3093 |@Dimenstion(unit = DP) 3094 |@Px 3095 |fun g(): Int { 3096 | return 5 3097 |} 3098 | 3099 |@RunWith @Px class Test 3100 | 3101 |@RunWith(MagicRunner::class) @Px class Test 3102 | 3103 |@RunWith @Px class Test {} 3104 | 3105 |@RunWith(MagicRunner::class) @Px class Test {} 3106 | 3107 |@RunWith(MagicRunner::class) 3108 |@Px 3109 |@Px 3110 |class Test {} 3111 | 3112 |@RunWith(MagicRunner::class) 3113 |@Px 3114 |class Test { 3115 | // 3116 |} 3117 | 3118 |fun f() { 3119 | if (@Stuff(Magic::class) isGood()) { 3120 | println("") 3121 | } 3122 |} 3123 |""" 3124 .trimMargin(), 3125 deduceMaxWidth = true) 3126 3127 @Test no newlines after annotations on properties if entire expression fits in one linenull3128 fun `no newlines after annotations on properties if entire expression fits in one line`() = 3129 assertFormatted( 3130 """ 3131 |-------------------------------------------- 3132 |@Suppress("UnsafeCast") 3133 |val ClassA.methodA 3134 | get() = foo as Bar 3135 |""" 3136 .trimMargin(), 3137 deduceMaxWidth = true) 3138 3139 @Test 3140 fun `when annotations cause line breaks, and constant has no type dont break before value`() = 3141 assertFormatted( 3142 """ 3143 |---------------------------------------------------------- 3144 |object Foo { 3145 | @LongLongLongLongAnnotation 3146 | @LongLongLongLongLongAnnotation 3147 | private val ROW_HEIGHT = 72 3148 |} 3149 |""" 3150 .trimMargin(), 3151 deduceMaxWidth = true) 3152 3153 @Test annotations in literal function typesnull3154 fun `annotations in literal function types`() = 3155 assertFormatted( 3156 """ 3157 |val callback: (@Anno List<@JvmSuppressWildcards String>) -> Unit = foo 3158 |""" 3159 .trimMargin()) 3160 3161 @Test 3162 fun `annotations on type parameters`() = 3163 assertFormatted( 3164 """ 3165 |class Foo<@Anno out @Anno T, @Anno in @Anno U> { 3166 | inline fun <@Anno reified @Anno X, @Anno reified @Anno Y> bar() {} 3167 |} 3168 |""" 3169 .trimMargin()) 3170 3171 @Test annotations on type constraintsnull3172 fun `annotations on type constraints`() = 3173 assertFormatted( 3174 """ 3175 |class Foo<T : @Anno Kip, U> where U : @Anno Kip, U : @Anno Qux { 3176 | fun <T : @Anno Kip, U> bar() where U : @Anno Kip, U : @Anno Qux {} 3177 |} 3178 |""" 3179 .trimMargin()) 3180 3181 @Test annotations on type argumentsnull3182 fun `annotations on type arguments`() = 3183 assertFormatted( 3184 """ 3185 |fun foo(x: Foo<in @Anno Int>) {} 3186 |""" 3187 .trimMargin()) 3188 3189 @Test annotations on destructuring declaration elementsnull3190 fun `annotations on destructuring declaration elements`() = 3191 assertFormatted( 3192 """ 3193 |val x = { (@Anno x, @Anno y) -> x } 3194 |""" 3195 .trimMargin()) 3196 3197 @Test annotations on exceptionsnull3198 fun `annotations on exceptions`() = 3199 assertFormatted( 3200 """ 3201 |fun doIt() { 3202 | try { 3203 | doItAgain() 3204 | } catch (@Nullable e: Exception) { 3205 | // 3206 | } catch (@Suppress("GeneralException") e: Exception) {} 3207 |} 3208 |""" 3209 .trimMargin()) 3210 3211 @Test Unary prefix expressionsnull3212 fun `Unary prefix expressions`() = 3213 assertFormatted( 3214 """ 3215 |fun f() { 3216 | !a 3217 | -4 3218 | val x = -foo() 3219 | +4 3220 | ++a 3221 | --a 3222 | 3223 | + +a 3224 | +-a 3225 | +!a 3226 | -+a 3227 | - -a 3228 | -!a 3229 | !+a 3230 | !a 3231 | ! !a 3232 | 3233 | + ++a 3234 | +--a 3235 | -++a 3236 | - --a 3237 | !++a 3238 | !--a 3239 |} 3240 |""" 3241 .trimMargin()) 3242 3243 @Test Unary postfix expressionsnull3244 fun `Unary postfix expressions`() = 3245 assertFormatted( 3246 """ 3247 |fun f() { 3248 | a!! 3249 | a++ 3250 | a-- 3251 | 3252 | a--!! 3253 | a++!! 3254 | 3255 | a!! !! 3256 |} 3257 |""" 3258 .trimMargin()) 3259 3260 @Test handle wildcard genericsnull3261 fun `handle wildcard generics`() = 3262 assertFormatted( 3263 """ 3264 |fun f() { 3265 | val l: List<*> 3266 | val p: Pair<*, *> 3267 |} 3268 |""" 3269 .trimMargin()) 3270 3271 @Test handle intersection genericsnull3272 fun `handle intersection generics`() = 3273 assertFormatted( 3274 """ 3275 |fun f() { 3276 | val l: Decl<A & B & C> 3277 | val p = Ctor<A & B & C, T & Y & Z> 3278 |} 3279 |""" 3280 .trimMargin()) 3281 3282 @Test handle covariant and contravariant type argumentsnull3283 fun `handle covariant and contravariant type arguments`() = 3284 assertFormatted( 3285 """ 3286 |val p: Pair<in T, out S> 3287 |""" 3288 .trimMargin()) 3289 3290 @Test 3291 fun `handle covariant and contravariant type parameters`() = 3292 assertFormatted( 3293 """ 3294 |class Foo<in T, out S> 3295 |""" 3296 .trimMargin()) 3297 3298 @Test 3299 fun `handle bounds for type parameters`() = 3300 assertFormatted( 3301 """ 3302 |class Foo<in T : List<*>, out S : Any?> 3303 |""" 3304 .trimMargin()) 3305 3306 @Test 3307 fun `handle compound generic bounds on classes`() = 3308 assertFormatted( 3309 """ 3310 |class Foo<T>(n: Int) where T : Bar, T : FooBar {} 3311 |""" 3312 .trimMargin()) 3313 3314 @Test handle compound generic bounds on functionsnull3315 fun `handle compound generic bounds on functions`() = 3316 assertFormatted( 3317 """ 3318 |fun <T> foo(n: Int) where T : Bar, T : FooBar {} 3319 |""" 3320 .trimMargin()) 3321 3322 @Test handle compound generic bounds on propertiesnull3323 fun `handle compound generic bounds on properties`() = 3324 assertFormatted( 3325 """ 3326 |val <T> List<T>.twiceSum: Int where T : Int 3327 | get() { 3328 | return 2 * sum() 3329 | } 3330 |""" 3331 .trimMargin()) 3332 3333 @Test handle compound generic bounds on class with delegatenull3334 fun `handle compound generic bounds on class with delegate`() = 3335 assertFormatted( 3336 """ 3337 |class Foo<T>() : Bar by bar 3338 |where T : Qux 3339 |""" 3340 .trimMargin()) 3341 3342 @Test 3343 fun `explicit type on property getter`() = 3344 assertFormatted( 3345 """ 3346 |class Foo { 3347 | val silly: Int 3348 | get(): Int = 1 3349 |} 3350 |""" 3351 .trimMargin()) 3352 3353 @Test handle method calls with lambda arg onlynull3354 fun `handle method calls with lambda arg only`() = 3355 assertFormatted( 3356 """ 3357 |fun f() { 3358 | val a = g { 1 + 1 } 3359 |} 3360 |""" 3361 .trimMargin()) 3362 3363 @Test handle method calls value args and a lambda argnull3364 fun `handle method calls value args and a lambda arg`() = 3365 assertFormatted( 3366 """ 3367 |fun f() { 3368 | val a = g(1, 2) { 1 + 1 } 3369 |} 3370 |""" 3371 .trimMargin()) 3372 3373 @Test handle top level constantsnull3374 fun `handle top level constants`() = 3375 assertFormatted( 3376 """ 3377 |----------------------------- 3378 |val a = 5 3379 | 3380 |const val b = "a" 3381 | 3382 |val a = 5 3383 |""" 3384 .trimMargin(), 3385 deduceMaxWidth = true) 3386 3387 @Test 3388 fun `handle lambda arg with named arguments`() = 3389 assertFormatted( 3390 """ 3391 |fun f() { 3392 | val b = { x: Int, y: Int -> x + y } 3393 |} 3394 |""" 3395 .trimMargin()) 3396 3397 @Test avoid newline before lambda argument if it is namednull3398 fun `avoid newline before lambda argument if it is named`() = 3399 assertFormatted( 3400 """ 3401 |private fun f(items: List<Int>) { 3402 | doSomethingCool( 3403 | items, 3404 | lambdaArgument = { 3405 | step1() 3406 | step2() 3407 | }) { 3408 | it.doIt() 3409 | } 3410 |} 3411 |""" 3412 .trimMargin()) 3413 3414 @Test handle labeled this pointernull3415 fun `handle labeled this pointer`() = 3416 assertFormatted( 3417 """ 3418 |class Foo { 3419 | fun f() { 3420 | g { println(this@Foo) } 3421 | } 3422 |} 3423 |""" 3424 .trimMargin()) 3425 3426 @Test handle extension and operator functionsnull3427 fun `handle extension and operator functions`() = 3428 assertFormatted( 3429 """ 3430 |operator fun Point.component1() = x 3431 |""" 3432 .trimMargin()) 3433 3434 @Test 3435 fun `handle extension methods with very long names`() = 3436 assertFormatted( 3437 """ 3438 |------------------------------------------ 3439 |fun LongReceiverNameThatRequiresBreaking 3440 | .doIt() {} 3441 | 3442 |fun LongButNotTooLong.doIt( 3443 | n: Int, 3444 | f: Float 3445 |) {} 3446 |""" 3447 .trimMargin(), 3448 deduceMaxWidth = true) 3449 3450 @Test handle extension propertiesnull3451 fun `handle extension properties`() = 3452 assertFormatted( 3453 """ 3454 |val Int.isPrime: Boolean 3455 | get() = runMillerRabinPrimality(this) 3456 |""" 3457 .trimMargin()) 3458 3459 @Test 3460 fun `generic extension property`() = 3461 assertFormatted( 3462 """ 3463 |val <T> List<T>.twiceSize = 2 * size() 3464 |""" 3465 .trimMargin()) 3466 3467 @Test 3468 fun `handle file annotations`() = 3469 assertFormatted( 3470 """ 3471 |@file:JvmName("DifferentName") 3472 | 3473 |package com.somecompany.example 3474 | 3475 |import com.somecompany.example2 3476 | 3477 |class Foo { 3478 | val a = example2("and 1") 3479 |} 3480 |""" 3481 .trimMargin()) 3482 3483 @Test handle init blocknull3484 fun `handle init block`() = 3485 assertFormatted( 3486 """ 3487 |class Foo { 3488 | init { 3489 | println("Init!") 3490 | } 3491 |} 3492 |""" 3493 .trimMargin()) 3494 3495 @Test handle interface delegationnull3496 fun `handle interface delegation`() = 3497 assertFormatted( 3498 """ 3499 |class MyList(impl: List<Int>) : Collection<Int> by impl 3500 |""" 3501 .trimMargin()) 3502 3503 @Test 3504 fun `handle property delegation`() = 3505 assertFormatted( 3506 """ 3507 |val a by lazy { 1 + 1 } 3508 |""" 3509 .trimMargin()) 3510 3511 @Test handle property delegation with type and breaksnull3512 fun `handle property delegation with type and breaks`() = 3513 assertFormatted( 3514 """ 3515 |--------------------------------- 3516 |val importantValue: Int by lazy { 3517 | 1 + 1 3518 |} 3519 | 3520 |val importantValue: Int by lazy { 3521 | val b = 1 + 1 3522 | b + b 3523 |} 3524 | 3525 |val importantValueLonger: 3526 | Int by lazy { 1 + 1 } 3527 | 3528 |val importantValue: Int by 3529 | doIt(1 + 1) 3530 |""" 3531 .trimMargin(), 3532 deduceMaxWidth = true) 3533 3534 @Test handle multi-annotations with use-site targetsnull3535 fun `handle multi-annotations with use-site targets`() = 3536 assertFormatted( 3537 """ 3538 |class Something { 3539 | @field:[Inject Named("WEB_VIEW")] 3540 | internal lateinit var httpClient: OkHttpClient 3541 | 3542 | @field:[Inject Named("WEB_VIEW")] 3543 | var httpClient: OkHttpClient 3544 | 3545 | @Px 3546 | @field:[Inject Named("WEB_VIEW")] 3547 | var httpClient: OkHttpClient 3548 |} 3549 | 3550 """ 3551 .trimMargin()) 3552 3553 @Test handle parameters with annoations with parametersnull3554 fun `handle parameters with annoations with parameters`() = 3555 assertFormatted( 3556 """ 3557 |class Something { 3558 | fun doIt(@Magic(withHat = true) foo: Foo) { 3559 | println(foo) 3560 | } 3561 |} 3562 | 3563 """ 3564 .trimMargin()) 3565 3566 @Test handle lambda typesnull3567 fun `handle lambda types`() = 3568 assertFormatted( 3569 """ 3570 |val listener1: (Boolean) -> Unit = { b -> !b } 3571 | 3572 |val listener2: () -> Unit = {} 3573 | 3574 |val listener3: (Int, Double) -> Int = { a, b -> a } 3575 | 3576 |val listener4: Int.(Int, Boolean) -> Unit 3577 |""" 3578 .trimMargin()) 3579 3580 @Test handle unicode in string literalsnull3581 fun `handle unicode in string literals`() = 3582 assertFormatted( 3583 """ 3584 |val a = "\uD83D\uDC4D" 3585 |""" 3586 .trimMargin()) 3587 3588 @Test 3589 fun `handle casting`() = 3590 assertFormatted( 3591 """ 3592 |fun castIt(o: Object) { 3593 | println(o is Double) 3594 | println(o !is Double) 3595 | doIt(o as Int) 3596 | doIt(o as? Int) 3597 |} 3598 |""" 3599 .trimMargin()) 3600 3601 @Test handle casting with breaksnull3602 fun `handle casting with breaks`() = 3603 assertFormatted( 3604 """ 3605 |----------------------- 3606 |fun castIt( 3607 | something: Any 3608 |) { 3609 | doIt( 3610 | something 3611 | as List<*>) 3612 | doIt( 3613 | something 3614 | is List<*>) 3615 | println( 3616 | something 3617 | is 3618 | List<String>) 3619 | doIt( 3620 | something 3621 | as 3622 | List<String>) 3623 | println( 3624 | something 3625 | is 3626 | PairList< 3627 | String, 3628 | Int>) 3629 | doIt( 3630 | something 3631 | as 3632 | PairList< 3633 | String, 3634 | Int>) 3635 | println( 3636 | a is Int && 3637 | b is String) 3638 | l.b?.s?.sOrNull() is 3639 | SomethingLongEnough 3640 |} 3641 | 3642 |val a = 3643 | l.sOrNull() is 3644 | SomethingLongEnough 3645 |""" 3646 .trimMargin(), 3647 deduceMaxWidth = true) 3648 3649 @Test handle collection literals in annotationsnull3650 fun `handle collection literals in annotations`() = 3651 assertFormatted( 3652 """ 3653 |@Foo(a = [1, 2]) 3654 |fun doIt(o: Object) { 3655 | // 3656 |} 3657 |""" 3658 .trimMargin()) 3659 3660 @Test handle try, catch and finallynull3661 fun `handle try, catch and finally`() = 3662 assertFormatted( 3663 """ 3664 |fun foo() { 3665 | try { 3666 | bar() 3667 | } catch (e: Exception) { 3668 | throw e 3669 | } finally { 3670 | println("finally") 3671 | } 3672 |} 3673 |""" 3674 .trimMargin()) 3675 3676 @Test handle infix methodsnull3677 fun `handle infix methods`() = 3678 assertFormatted( 3679 """ 3680 |fun numbers() { 3681 | (0 until 100).size 3682 |} 3683 |""" 3684 .trimMargin()) 3685 3686 @Test handle while loopsnull3687 fun `handle while loops`() = 3688 assertFormatted( 3689 """ 3690 |fun numbers() { 3691 | while (1 < 2) { 3692 | println("Everything is okay") 3693 | } 3694 |} 3695 |""" 3696 .trimMargin()) 3697 3698 @Test handle do while loopsnull3699 fun `handle do while loops`() = 3700 assertFormatted( 3701 """ 3702 |fun numbers() { 3703 | do { 3704 | println("Everything is okay") 3705 | } while (1 < 2) 3706 | 3707 | do while (1 < 2) 3708 |} 3709 |""" 3710 .trimMargin()) 3711 3712 @Test handle break and continuenull3713 fun `handle break and continue`() = 3714 assertFormatted( 3715 """ 3716 |fun numbers() { 3717 | while (1 < 2) { 3718 | if (true) { 3719 | break 3720 | } 3721 | if (false) { 3722 | continue 3723 | } 3724 | } 3725 |} 3726 |""" 3727 .trimMargin()) 3728 3729 @Test handle all kinds of labels and jumpsnull3730 fun `handle all kinds of labels and jumps`() = 3731 assertFormatted( 3732 """ 3733 |fun f(a: List<Int>) { 3734 | a.map { 3735 | myloop@ for (i in a) { 3736 | if (true) { 3737 | break@myloop 3738 | } else if (false) { 3739 | continue@myloop 3740 | } else { 3741 | a.map `inner map`@{ 3742 | return@`inner map` 3743 | } 3744 | } 3745 | } 3746 | return@map 2 * it 3747 | } 3748 |} 3749 |""" 3750 .trimMargin()) 3751 3752 @Test don't crash on top level statements with semicolonsnull3753 fun `don't crash on top level statements with semicolons`() { 3754 val code = 3755 """ 3756 |val x = { 0 }; 3757 | 3758 |foo({ 0 }); 3759 | 3760 |foo { 0 }; 3761 | 3762 |val fill = 0; 3763 |""" 3764 .trimMargin() 3765 val expected = 3766 """ 3767 |val x = { 0 } 3768 | 3769 |foo({ 0 }) 3770 | 3771 |foo { 0 } 3772 | 3773 |val fill = 0 3774 |""" 3775 .trimMargin() 3776 assertThatFormatting(code).isEqualTo(expected) 3777 } 3778 3779 @Test preserve semicolons in enumsnull3780 fun `preserve semicolons in enums`() { 3781 val code = 3782 """ 3783 |enum class SemiColonIsNotRequired { 3784 | TRUE, FALSE; 3785 |} 3786 | 3787 |enum class SemiColonIsRequired { 3788 | ONE, TWO; 3789 | 3790 | fun isOne(): Boolean = this == ONE 3791 |} 3792 |""" 3793 .trimMargin() 3794 val expected = 3795 """ 3796 |enum class SemiColonIsNotRequired { 3797 | TRUE, 3798 | FALSE 3799 |} 3800 | 3801 |enum class SemiColonIsRequired { 3802 | ONE, 3803 | TWO; 3804 | 3805 | fun isOne(): Boolean = this == ONE 3806 |} 3807 |""" 3808 .trimMargin() 3809 assertThatFormatting(code).isEqualTo(expected) 3810 } 3811 3812 @Test preserve semicolons in comments and stringsnull3813 fun `preserve semicolons in comments and strings`() { 3814 val code = 3815 """ 3816 |fun f() { 3817 | val x = ";" 3818 | val x = $TQ don't touch ; in raw strings $TQ 3819 |} 3820 | 3821 |// Don't touch ; inside comments. 3822 | 3823 |/** Don't touch ; inside comments. */ 3824 |""" 3825 .trimMargin() 3826 val expected = 3827 """ 3828 |fun f() { 3829 | val x = ";" 3830 | val x = $TQ don't touch ; in raw strings $TQ 3831 |} 3832 | 3833 |// Don't touch ; inside comments. 3834 | 3835 |/** Don't touch ; inside comments. */ 3836 |""" 3837 .trimMargin() 3838 assertThatFormatting(code).isEqualTo(expected) 3839 } 3840 3841 @Test 3842 fun `preserve semicolons in empty if-s and while-s`() { 3843 val code = 3844 """ 3845 |fun f() { 3846 | while (true); 3847 | while (true) /** a */ ; 3848 | 3849 | if (true); 3850 | if (true) /** a */ ; 3851 | 3852 | if (true) 3853 | else 3854 | ; 3855 |} 3856 |""" 3857 .trimMargin() 3858 val expected = 3859 """ 3860 |fun f() { 3861 | while (true) ; 3862 | while (true) 3863 | /** a */ 3864 | ; 3865 | 3866 | if (true) ; 3867 | if (true) 3868 | /** a */ 3869 | ; 3870 | 3871 | if (true) else ; 3872 |} 3873 |""" 3874 .trimMargin() 3875 assertThatFormatting(code).isEqualTo(expected) 3876 } 3877 3878 @Test 3879 fun `preserve semicolons between calls and dead lambdas`() { 3880 val code = 3881 """ 3882 |fun f() { 3883 | foo(0); { dead -> lambda } 3884 | 3885 | foo(0) ; { dead -> lambda } 3886 | 3887 | foo(0) /** a */ ; /** b */ { dead -> lambda } 3888 | 3889 | foo(0) { trailing -> lambda }; { dead -> lambda } 3890 | 3891 | foo { trailing -> lambda }; { dead -> lambda } 3892 | 3893 | val x = foo(); { dead -> lambda } 3894 | 3895 | val x = bar() && foo(); { dead -> lambda } 3896 | 3897 | // `z` has a property and a method both named `bar` 3898 | val x = z.bar; { dead -> lambda } 3899 | 3900 | // `this` has a property and a method both named `bar` 3901 | val x = bar; { dead -> lambda } 3902 | 3903 | // Literally any callable expression is dangerous 3904 | val x = (if (cond) x::foo else x::bar); { dead -> lambda } 3905 |} 3906 |""" 3907 .trimMargin() 3908 val expected = 3909 """ 3910 |fun f() { 3911 | foo(0); 3912 | { dead -> lambda } 3913 | 3914 | foo(0); 3915 | { dead -> lambda } 3916 | 3917 | foo(0) 3918 | /** a */ 3919 | ; 3920 | /** b */ 3921 | { dead -> lambda } 3922 | 3923 | foo(0) { trailing -> lambda }; 3924 | { dead -> lambda } 3925 | 3926 | foo { trailing -> lambda }; 3927 | { dead -> lambda } 3928 | 3929 | val x = foo(); 3930 | { dead -> lambda } 3931 | 3932 | val x = bar() && foo(); 3933 | { dead -> lambda } 3934 | 3935 | // `z` has a property and a method both named `bar` 3936 | val x = z.bar; 3937 | { dead -> lambda } 3938 | 3939 | // `this` has a property and a method both named `bar` 3940 | val x = bar; 3941 | { dead -> lambda } 3942 | 3943 | // Literally any callable expression is dangerous 3944 | val x = (if (cond) x::foo else x::bar); 3945 | { dead -> lambda } 3946 |} 3947 |""" 3948 .trimMargin() 3949 assertThatFormatting(code).isEqualTo(expected) 3950 } 3951 3952 @Test 3953 fun `drop redundant semicolons`() { 3954 val code = 3955 """ 3956 |package org.examples; 3957 |import org.examples.wow.MuchWow; 3958 |import org.examples.wow.ManyAmaze 3959 | 3960 |typealias Int2 = Int; 3961 | 3962 |fun f() { 3963 | val a = 3; 3964 | val x = 5 ; val y = ManyAmaze(); 3965 | myThingMap.forEach { val (key, value) = it; println("mapped ${"$"}MuchWow") } 3966 | when { 3967 | true -> "1"; false -> "0" 3968 | } 3969 | someLongVariableName.let { 3970 | someReallyLongFunctionNameThatMakesThisNotFitInOneLineWithTheAboveVariable(); 3971 | } 3972 | if (cond) ; else 6 3973 |} ; 3974 | 3975 |""" 3976 .trimMargin() 3977 val expected = 3978 """ 3979 |package org.examples 3980 | 3981 |import org.examples.wow.ManyAmaze 3982 |import org.examples.wow.MuchWow 3983 | 3984 |typealias Int2 = Int 3985 | 3986 |fun f() { 3987 | val a = 3 3988 | val x = 5 3989 | val y = ManyAmaze() 3990 | myThingMap.forEach { 3991 | val (key, value) = it 3992 | println("mapped ${"$"}MuchWow") 3993 | } 3994 | when { 3995 | true -> "1" 3996 | false -> "0" 3997 | } 3998 | someLongVariableName.let { 3999 | someReallyLongFunctionNameThatMakesThisNotFitInOneLineWithTheAboveVariable() 4000 | } 4001 | if (cond) else 6 4002 |} 4003 |""" 4004 .trimMargin() 4005 assertThatFormatting(code).isEqualTo(expected) 4006 } 4007 4008 @Test 4009 fun `pretty-print after dropping redundant semicolons`() { 4010 val code = 4011 """ 4012 |fun f() { 4013 | val veryLongName = 5; 4014 |} 4015 |""" 4016 .trimMargin() 4017 val expected = 4018 """ 4019 |fun f() { 4020 | val veryLongName = 5 4021 |} 4022 |""" 4023 .trimMargin() 4024 assertThatFormatting(code).withOptions(FormattingOptions(maxWidth = 22)).isEqualTo(expected) 4025 } 4026 4027 @Test 4028 fun `handle no parenthesis in lambda calls`() = 4029 assertFormatted( 4030 """ 4031 |fun f() { 4032 | a { println("a") } 4033 |} 4034 |""" 4035 .trimMargin()) 4036 4037 @Test 4038 fun `handle multi statement lambdas`() = 4039 assertFormatted( 4040 """ 4041 |fun f() { 4042 | a { 4043 | println("a") 4044 | println("b") 4045 | } 4046 |} 4047 |""" 4048 .trimMargin()) 4049 4050 @Test 4051 fun `handle multi line one statement lambda`() = 4052 assertFormatted( 4053 """ 4054 |------------------------- 4055 |fun f() { 4056 | a { 4057 | println(foo.bar.boom) 4058 | } 4059 |} 4060 |""" 4061 .trimMargin(), 4062 deduceMaxWidth = true) 4063 4064 @Test 4065 fun `statements are wrapped in blocks`() = 4066 assertFormatted( 4067 """ 4068 |fun f() { 4069 | builder.block { 4070 | getArgumentName().accept 4071 | return 4072 | } 4073 |} 4074 |""" 4075 .trimMargin()) 4076 4077 @Test 4078 fun `properly break fully qualified nested user types`() = 4079 assertFormatted( 4080 """ 4081 |------------------------------------------------------- 4082 |val complicated: 4083 | com.example.interesting.SomeType< 4084 | com.example.interesting.SomeType<Int, Nothing>, 4085 | com.example.interesting.SomeType< 4086 | com.example.interesting.SomeType< 4087 | Int, Nothing>, 4088 | Nothing>> = 4089 | DUMMY 4090 |""" 4091 .trimMargin(), 4092 deduceMaxWidth = true) 4093 4094 @Test 4095 fun `handle multi-line lambdas within lambdas and calling chains`() = 4096 assertFormatted( 4097 """ 4098 |fun f() { 4099 | builder.block(ZERO) { 4100 | builder.token("when") 4101 | expression1.let { subjectExp -> 4102 | builder.token(")") 4103 | return 4104 | } 4105 | } 4106 | builder.block(ZERO) { 4107 | expression2.subjectExpression.let { subjectExp -> 4108 | builder.token(")") 4109 | return 4110 | } 4111 | } 4112 | builder.block(ZERO) { 4113 | expression2.subjectExpression 4114 | .let { subjectExp -> 4115 | builder.token(")") 4116 | return 4117 | } 4118 | .sum 4119 | } 4120 |} 4121 |""" 4122 .trimMargin()) 4123 4124 @Test 4125 fun `handle multi line lambdas with explicit args`() = 4126 assertFormatted( 4127 """ 4128 |-------------------- 4129 |fun f() { 4130 | a { (x, y) -> 4131 | x + y 4132 | } 4133 |} 4134 |""" 4135 .trimMargin(), 4136 deduceMaxWidth = true) 4137 4138 @Test 4139 fun `handle lambda with destructuring and type`() = 4140 assertFormatted( 4141 """ 4142 |fun f() { 4143 | g { (a, b): List<Int> -> a } 4144 | g { (a, b): List<Int>, (c, d): List<Int> -> a } 4145 |} 4146 |""" 4147 .trimMargin()) 4148 4149 @Test 4150 fun `handle parenthesis in lambda calls for now`() = 4151 assertFormatted( 4152 """ 4153 |fun f() { 4154 | a() { println("a") } 4155 |} 4156 |""" 4157 .trimMargin()) 4158 4159 @Test 4160 fun `handle chaining of calls with lambdas`() = 4161 assertFormatted( 4162 """ 4163 |fun f() { 4164 | bobby 4165 | .map { x -> x * x } 4166 | .map { x -> x * x } 4167 | ?.map { x -> 4168 | val y = x * x 4169 | y 4170 | } 4171 | .sum 4172 |} 4173 |""" 4174 .trimMargin()) 4175 4176 @Test 4177 fun `handle break of lambda args per line with indentation`() = 4178 assertFormatted( 4179 """ 4180 |----------- 4181 |fun f() { 4182 | a() { 4183 | arg1, 4184 | arg2, 4185 | x -> 4186 | doIt() 4187 | doIt() 4188 | } 4189 | a() { 4190 | arg1, 4191 | arg2, 4192 | arg3 4193 | -> 4194 | doIt() 4195 | doIt() 4196 | } 4197 |} 4198 |""" 4199 .trimMargin(), 4200 deduceMaxWidth = true) 4201 4202 @Test 4203 fun `handle trailing comma in lambda`() = 4204 assertFormatted( 4205 """ 4206 |----------- 4207 |fun f() { 4208 | a() { 4209 | arg1, 4210 | arg2, 4211 | x, 4212 | -> 4213 | doIt() 4214 | doIt() 4215 | } 4216 |} 4217 |""" 4218 .trimMargin(), 4219 deduceMaxWidth = true) 4220 4221 @Test 4222 fun `break before Elvis operator`() = 4223 assertFormatted( 4224 """ 4225 |-------------------------------------------------- 4226 |fun f() { 4227 | someObject 4228 | .someMethodReturningCollection() 4229 | .map { it.someProperty } 4230 | .find { it.contains(someSearchValue) } 4231 | ?: someDefaultValue 4232 |} 4233 |""" 4234 .trimMargin(), 4235 deduceMaxWidth = true) 4236 4237 @Test 4238 fun `handle comments in the middle of calling chain`() = 4239 assertFormatted( 4240 """ 4241 |--------------------------- 4242 |fun f() { 4243 | someObject 4244 | .letsDoIt() 4245 | // this is a comment 4246 | .doItOnce() 4247 | // this is a comment 4248 | .doItTwice() 4249 |} 4250 |""" 4251 .trimMargin(), 4252 deduceMaxWidth = true) 4253 4254 @Test 4255 fun `handle reified types`() = 4256 assertFormatted( 4257 """ 4258 |inline fun <reified T> foo(t: T) { 4259 | println(t) 4260 |} 4261 | 4262 |inline fun <reified in T> foo2(t: T) { 4263 | println(t) 4264 |} 4265 |""" 4266 .trimMargin()) 4267 4268 @Test 4269 fun `handle suspended types`() = 4270 assertFormatted( 4271 """ 4272 |private val reader: suspend (Key) -> Output? 4273 | 4274 |private val delete: (suspend (Key) -> Unit)? = null 4275 | 4276 |inline fun <R> foo(noinline block: suspend () -> R): suspend () -> R 4277 | 4278 |inline fun <R> bar(noinline block: (suspend () -> R)?): (suspend () -> R)? 4279 |""" 4280 .trimMargin()) 4281 4282 @Test 4283 fun `handle simple enum classes`() = 4284 assertFormatted( 4285 """ 4286 |enum class BetterBoolean { 4287 | TRUE, 4288 | FALSE, 4289 | FILE_NOT_FOUND, 4290 |} 4291 |""" 4292 .trimMargin()) 4293 4294 @Test 4295 fun `handle enum class with functions`() = 4296 assertFormatted( 4297 """ 4298 |enum class BetterBoolean { 4299 | TRUE, 4300 | FALSE, 4301 | FILE_NOT_FOUND; 4302 | fun isGood(): Boolean { 4303 | return true 4304 | } 4305 |} 4306 |""" 4307 .trimMargin()) 4308 4309 @Test 4310 fun `handle enum with annotations`() = 4311 assertFormatted( 4312 """ 4313 |enum class BetterBoolean { 4314 | @True TRUE, 4315 | @False @WhatIsTruth FALSE, 4316 |} 4317 |""" 4318 .trimMargin()) 4319 4320 @Test 4321 fun `handle enum constructor calls`() = 4322 assertFormatted( 4323 """ 4324 |enum class BetterBoolean(val name: String, val value: Boolean = true) { 4325 | TRUE("true"), 4326 | FALSE("false", false), 4327 |} 4328 |""" 4329 .trimMargin()) 4330 4331 @Test 4332 fun `handle enum entries with body`() = 4333 assertFormatted( 4334 """ 4335 |enum class Animal(canWalk: Boolean = true) { 4336 | DOG { 4337 | fun speak() = "woof" 4338 | }, 4339 | FISH(false) {}, 4340 |} 4341 |""" 4342 .trimMargin()) 4343 4344 @Test 4345 fun `handle empty enum`() = 4346 assertFormatted( 4347 """ 4348 |enum class YTho { 4349 |} 4350 |""" 4351 .trimMargin()) 4352 4353 @Test 4354 fun `expect enum class`() = 4355 assertFormatted( 4356 """ 4357 |expect enum class ExpectedEnum 4358 |""" 4359 .trimMargin()) 4360 4361 @Test 4362 fun `enum without trailing comma`() = 4363 assertFormatted( 4364 """ 4365 |enum class Highlander { 4366 | ONE 4367 |} 4368 |""" 4369 .trimMargin()) 4370 4371 @Test 4372 fun `enum comma and semicolon`() { 4373 assertThatFormatting( 4374 """ 4375 |enum class Highlander { 4376 | ONE,; 4377 |} 4378 |""" 4379 .trimMargin()) 4380 .isEqualTo( 4381 """ 4382 |enum class Highlander { 4383 | ONE, 4384 |} 4385 |""" 4386 .trimMargin()) 4387 } 4388 4389 @Test 4390 fun `semicolon is placed on next line when there's a trailing comma in an enum declaration`() = 4391 assertFormatted( 4392 """ 4393 |enum class Highlander { 4394 | ONE, 4395 | TWO, 4396 | ; 4397 | 4398 | fun f() {} 4399 |} 4400 |""" 4401 .trimMargin()) 4402 4403 @Test 4404 fun `handle varargs and spread operator`() = 4405 assertFormatted( 4406 """ 4407 |fun foo(vararg args: String) { 4408 | foo2(*args) 4409 | foo3(options = *args) 4410 |} 4411 |""" 4412 .trimMargin()) 4413 4414 @Test 4415 fun `handle typealias`() = 4416 assertFormatted( 4417 """ 4418 |---------------------------------------------- 4419 |private typealias TextChangedListener = 4420 | (string: String) -> Unit 4421 | 4422 |typealias PairPair<X, Y> = Pair<Pair<X, Y>, X> 4423 | 4424 |class Foo 4425 |""" 4426 .trimMargin(), 4427 deduceMaxWidth = true) 4428 4429 @Test 4430 fun `handle the 'dynamic' type`() = 4431 assertFormatted( 4432 """ 4433 |fun x(): dynamic = "x" 4434 | 4435 |val dyn: dynamic = 1 4436 |""" 4437 .trimMargin()) 4438 4439 @Test 4440 fun `handle class expression with generics`() = 4441 assertFormatted( 4442 """ 4443 |fun f() { 4444 | println(Array<String>::class.java) 4445 |} 4446 |""" 4447 .trimMargin()) 4448 4449 @Test 4450 fun `ParseError contains correct line and column numbers`() { 4451 val code = 4452 """ 4453 |// Foo 4454 |fun good() { 4455 | // 4456 |} 4457 | 4458 |fn ( 4459 |""" 4460 .trimMargin() 4461 try { 4462 Formatter.format(code) 4463 fail() 4464 } catch (e: ParseError) { 4465 assertThat(e.lineColumn.line).isEqualTo(6) 4466 assertThat(e.lineColumn.column).isEqualTo(0) 4467 assertThat(e.errorDescription).contains("Expecting an expression") 4468 } 4469 } 4470 4471 @Test 4472 fun `fail() reports line+column number`() { 4473 val code = 4474 """ 4475 |// Foo 4476 |fun good() { 4477 | return@ 5 4478 |} 4479 |""" 4480 .trimMargin() 4481 try { 4482 Formatter.format(code) 4483 fail() 4484 } catch (e: ParseError) { 4485 assertThat(e.lineColumn.line).isEqualTo(2) 4486 assertThat(e.lineColumn.column).isEqualTo(8) 4487 } 4488 } 4489 4490 @Test 4491 fun `annotations on class, fun, parameters and literals`() = 4492 assertFormatted( 4493 """ 4494 |@Fancy 4495 |class Foo { 4496 | @Fancy 4497 | fun baz(@Fancy foo: Int): Int { 4498 | return (@Fancy 1) 4499 | } 4500 |} 4501 |""" 4502 .trimMargin()) 4503 4504 @Test 4505 fun `annotations on function types`() = 4506 assertFormatted( 4507 """ 4508 |fun foo(bar: @StringRes Int) {} 4509 | 4510 |fun foo(error: @Composable ((x) -> Unit)) {} 4511 | 4512 |fun foo(error: (@Composable (x) -> Unit)) {} 4513 | 4514 |fun foo( 4515 | error: 4516 | @field:[Inject Named("WEB_VIEW")] 4517 | ((x) -> Unit) 4518 |) {} 4519 | 4520 |fun foo( 4521 | error: 4522 | (@field:[Inject Named("WEB_VIEW")] 4523 | (x) -> Unit) 4524 |) {} 4525 |""" 4526 .trimMargin()) 4527 4528 @Test 4529 fun `handle annotations with use-site targets`() = 4530 assertFormatted( 4531 """ 4532 |class FooTest { 4533 | @get:Rule val exceptionRule: ExpectedException = ExpectedException.none() 4534 | 4535 | @set:Magic(name = "Jane") var field: String 4536 |} 4537 |""" 4538 .trimMargin()) 4539 4540 @Test 4541 fun `handle annotations mixed with keywords since we cannot reorder them for now`() = 4542 assertFormatted( 4543 """ 4544 |public @Magic final class Foo 4545 | 4546 |public @Magic(1) final class Foo 4547 | 4548 |@Magic(1) public final class Foo 4549 |""" 4550 .trimMargin()) 4551 4552 @Test 4553 fun `handle annotations more`() = 4554 assertFormatted( 4555 """ 4556 |------------------------------------------------- 4557 |@Anno1 4558 |@Anno2(param = Param1::class) 4559 |@Anno3 4560 |@Anno4(param = Param2::class) 4561 |class MyClass {} 4562 | 4563 |fun f() { 4564 | @Suppress("MagicNumber") add(10) 4565 | 4566 | @Annotation // test a comment after annotations 4567 | return 5 4568 |} 4569 |""" 4570 .trimMargin(), 4571 deduceMaxWidth = true) 4572 4573 @Test 4574 fun `annotated expressions`() = 4575 assertFormatted( 4576 """ 4577 |------------------------------------------------ 4578 |fun f() { 4579 | @Suppress("MagicNumber") add(10) && add(20) 4580 | 4581 | @Suppress("MagicNumber") 4582 | add(10) && add(20) 4583 | 4584 | @Anno1 @Anno2(param = Param1::class) 4585 | add(10) && add(20) 4586 | 4587 | @Anno1 4588 | @Anno2(param = Param1::class) 4589 | @Anno3 4590 | @Anno4(param = Param2::class) 4591 | add(10) && add(20) 4592 | 4593 | @Anno1 4594 | @Anno2(param = Param1::class) 4595 | @Anno3 4596 | @Anno4(param = Param2::class) 4597 | add(10) && add(20) 4598 | 4599 | @Suppress("MagicNumber") add(10) && 4600 | add(20) && 4601 | add(30) 4602 | 4603 | add(@Suppress("MagicNumber") 10) && 4604 | add(20) && 4605 | add(30) 4606 |} 4607 |""" 4608 .trimMargin(), 4609 deduceMaxWidth = true) 4610 4611 @Test 4612 fun `annotated function declarations`() = 4613 assertFormatted( 4614 """ 4615 |@Anno 4616 |fun f() { 4617 | add(10) 4618 |} 4619 | 4620 |@Anno(param = 1) 4621 |fun f() { 4622 | add(10) 4623 |} 4624 |""" 4625 .trimMargin()) 4626 4627 @Test 4628 fun `annotated class declarations`() = 4629 assertFormatted( 4630 """ 4631 |@Anno class F 4632 | 4633 |@Anno(param = 1) class F 4634 | 4635 |@Anno(P) 4636 |// Foo 4637 |@Anno("param") 4638 |class F 4639 |""" 4640 .trimMargin()) 4641 4642 @Test 4643 fun `handle type arguments in annotations`() = 4644 assertFormatted( 4645 """ 4646 |@TypeParceler<UUID, UUIDParceler>() class MyClass {} 4647 |""" 4648 .trimMargin()) 4649 4650 @Test 4651 fun `handle one line KDoc`() = 4652 assertFormatted( 4653 """ 4654 |/** Hi, I am a one line kdoc */ 4655 |class MyClass {} 4656 |""" 4657 .trimMargin()) 4658 4659 @Test 4660 fun `handle KDoc with Link`() = 4661 assertFormatted( 4662 """ 4663 |/** This links to [AnotherClass] */ 4664 |class MyClass {} 4665 |""" 4666 .trimMargin()) 4667 4668 @Test 4669 fun `handle KDoc with paragraphs`() = 4670 assertFormatted( 4671 """ 4672 |/** 4673 | * Hi, I am a two paragraphs kdoc 4674 | * 4675 | * There's a space line to preserve between them 4676 | */ 4677 |class MyClass {} 4678 |""" 4679 .trimMargin()) 4680 4681 @Test 4682 fun `handle KDoc with blocks`() = 4683 assertFormatted( 4684 """ 4685 |/** 4686 | * Hi, I am a two paragraphs kdoc 4687 | * 4688 | * @param param1 this is param1 4689 | * @param[param2] this is param2 4690 | */ 4691 |class MyClass {} 4692 |""" 4693 .trimMargin()) 4694 4695 @Test 4696 fun `handle KDoc with code examples`() = 4697 assertFormatted( 4698 """ 4699 |/** 4700 | * This is how you write a simple hello world in Kotlin: 4701 | * ``` 4702 | * fun main(args: Array<String>) { 4703 | * println("Hello World!") 4704 | * } 4705 | * ``` 4706 | * 4707 | * Amazing ah? 4708 | * 4709 | * ``` 4710 | * fun `code can be with a blank line above it` () {} 4711 | * ``` 4712 | * 4713 | * Or after it! 4714 | */ 4715 |class MyClass {} 4716 |""" 4717 .trimMargin()) 4718 4719 @Test 4720 fun `handle KDoc with tagged code examples`() = 4721 assertFormatted( 4722 """ 4723 |/** 4724 | * ```kotlin 4725 | * fun main(args: Array<String>) { 4726 | * println("Hello World!") 4727 | * } 4728 | * ``` 4729 | */ 4730 |class MyClass {} 4731 |""" 4732 .trimMargin()) 4733 4734 @Test 4735 fun `handle stray code markers in lines and produce stable output`() { 4736 val code = 4737 """ 4738 |/** 4739 | * Look! code: ``` aaa 4740 | * fun f() = Unit 4741 | * foo 4742 | * ``` 4743 | */ 4744 |class MyClass {} 4745 |""" 4746 .trimMargin() 4747 assertFormatted(Formatter.format(code)) 4748 } 4749 4750 @Test 4751 fun `code block with triple backtick`() { 4752 val code = 4753 """ 4754 |/** 4755 | * Look! code: 4756 | * ``` 4757 | * aaa ``` wow 4758 | * ``` 4759 | */ 4760 |class MyClass {} 4761 |""" 4762 .trimMargin() 4763 val expected = 4764 """ 4765 |/** 4766 | * Look! code: 4767 | * ``` 4768 | * aaa ``` wow 4769 | * ``` 4770 | */ 4771 |class MyClass {} 4772 |""" 4773 .trimMargin() 4774 assertThatFormatting(code).isEqualTo(expected) 4775 } 4776 4777 @Test 4778 fun `when code closer in mid of line, produce stable output`() { 4779 val code = 4780 """ 4781 |/** 4782 | * Look! code: ``` aaa 4783 | * fun f() = Unit 4784 | * foo ``` wow 4785 | */ 4786 |class MyClass {} 4787 |""" 4788 .trimMargin() 4789 assertFormatted(Formatter.format(code)) 4790 } 4791 4792 @Test 4793 fun `handle KDoc with link reference`() = 4794 assertFormatted( 4795 """ 4796 |/** Doc line with a reference to [AnotherClass] in the middle of a sentence */ 4797 |class MyClass {} 4798 |""" 4799 .trimMargin()) 4800 4801 @Test 4802 fun `handle KDoc with links one after another`() = 4803 assertFormatted( 4804 """ 4805 |/** Here are some links [AnotherClass] [AnotherClass2] */ 4806 |class MyClass {} 4807 |""" 4808 .trimMargin()) 4809 4810 @Test 4811 fun `don't add spaces after links in Kdoc`() = 4812 assertFormatted( 4813 """ 4814 |/** Here are some links [AnotherClass][AnotherClass2]hello */ 4815 |class MyClass {} 4816 |""" 4817 .trimMargin()) 4818 4819 @Test 4820 fun `don't remove spaces after links in Kdoc`() = 4821 assertFormatted( 4822 """ 4823 |/** Please see [onNext] (which has more details) */ 4824 |class MyClass {} 4825 |""" 4826 .trimMargin()) 4827 4828 @Test 4829 fun `link anchor in KDoc are preserved`() = 4830 assertFormatted( 4831 """ 4832 |/** [link anchor](the URL for the link anchor goes here) */ 4833 |class MyClass {} 4834 |""" 4835 .trimMargin()) 4836 4837 @Test 4838 fun `don't add spaces between links in KDoc (because they're actually references)`() = 4839 assertFormatted( 4840 """ 4841 |/** Here are some links [AnotherClass][AnotherClass2] */ 4842 |class MyClass {} 4843 | 4844 |/** The final produced value may have [size][ByteString.size] < [bufferSize]. */ 4845 |class MyClass {} 4846 |""" 4847 .trimMargin()) 4848 4849 @Test 4850 fun `collapse spaces after links in KDoc`() { 4851 val code = 4852 """ 4853 |/** Here are some links [Class1], [Class2] [Class3]. hello */ 4854 |class MyClass {} 4855 |""" 4856 .trimMargin() 4857 val expected = 4858 """ 4859 |/** Here are some links [Class1], [Class2] [Class3]. hello */ 4860 |class MyClass {} 4861 |""" 4862 .trimMargin() 4863 assertThatFormatting(code).isEqualTo(expected) 4864 } 4865 4866 @Test 4867 fun `collapse newlines after links in KDoc`() { 4868 val code = 4869 """ 4870 |/** 4871 | * Here are some links [Class1] 4872 | * [Class2] 4873 | */ 4874 |class MyClass {} 4875 |""" 4876 .trimMargin() 4877 val expected = 4878 """ 4879 |/** Here are some links [Class1] [Class2] */ 4880 |class MyClass {} 4881 |""" 4882 .trimMargin() 4883 assertThatFormatting(code).isEqualTo(expected) 4884 } 4885 4886 @Test 4887 fun `do not crash because of malformed KDocs and produce stable output`() { 4888 val code = 4889 """ 4890 |/** Surprise ``` */ 4891 |class MyClass {} 4892 |""" 4893 .trimMargin() 4894 assertFormatted(Formatter.format(code)) 4895 } 4896 4897 @Test 4898 fun `Respect spacing of text after link`() = 4899 assertFormatted( 4900 """ 4901 |/** Enjoy this link [linkstuff]. */ 4902 |class MyClass {} 4903 | 4904 |/** There are many [FooObject]s. */ 4905 |class MyClass {} 4906 |""" 4907 .trimMargin()) 4908 4909 @Test 4910 fun `handle KDoc with multiple separated param tags, breaking and merging lines and missing asterisk`() { 4911 val code = 4912 """ 4913 |/** 4914 | * Trims leading whitespace characters followed by [marginPrefix] from every line of a source string and removes 4915 | * the first and the last lines if they are blank (notice difference blank vs empty). 4916 | 4917 | * Doesn't affect a line if it doesn't contain [marginPrefix] except the first and the last blank lines. 4918 | * 4919 | * Doesn't preserve the original line endings. 4920 | * 4921 | * @param marginPrefix non-blank string, which is used as a margin delimiter. Default is `|` (pipe character). 4922 | * 4923 | * @sample samples.text.Strings.trimMargin 4924 | * @see trimIndent 4925 | * @see kotlin.text.isWhitespace 4926 | */ 4927 |class ThisWasCopiedFromTheTrimMarginMethod {} 4928 |""" 4929 .trimMargin() 4930 val expected = 4931 """ 4932 |/** 4933 | * Trims leading whitespace characters followed by [marginPrefix] from every line of a source string 4934 | * and removes the first and the last lines if they are blank (notice difference blank vs empty). 4935 | * 4936 | * Doesn't affect a line if it doesn't contain [marginPrefix] except the first and the last blank 4937 | * lines. 4938 | * 4939 | * Doesn't preserve the original line endings. 4940 | * 4941 | * @param marginPrefix non-blank string, which is used as a margin delimiter. Default is `|` (pipe 4942 | * character). 4943 | * @sample samples.text.Strings.trimMargin 4944 | * @see trimIndent 4945 | * @see kotlin.text.isWhitespace 4946 | */ 4947 |class ThisWasCopiedFromTheTrimMarginMethod {} 4948 |""" 4949 .trimMargin() 4950 assertThatFormatting(code).isEqualTo(expected) 4951 } 4952 4953 @Test 4954 fun `KDoc is reflowed`() { 4955 val code = 4956 """ 4957 |/** Lorem ipsum dolor sit amet, consectetur */ 4958 |class MyClass {} 4959 |""" 4960 .trimMargin() 4961 val expected = 4962 """ 4963 |/** 4964 | * Lorem ipsum dolor sit amet, 4965 | * consectetur 4966 | */ 4967 |class MyClass {} 4968 |""" 4969 .trimMargin() 4970 assertThatFormatting(code).withOptions(FormattingOptions(maxWidth = 33)).isEqualTo(expected) 4971 } 4972 4973 @Test 4974 fun `sanity - block and continuation indents are 4`() { 4975 val code = 4976 """ 4977 |fun f() { 4978 | for (child in 4979 | node.next.next.next.next 4980 | .data()) { 4981 | println(child) 4982 | } 4983 |} 4984 |""" 4985 .trimMargin() 4986 assertThatFormatting(code) 4987 .withOptions(FormattingOptions(maxWidth = 35, blockIndent = 4, continuationIndent = 4)) 4988 .isEqualTo(code) 4989 } 4990 4991 @Test 4992 fun `comment after a block is stable and does not add space lines`() = 4993 assertFormatted( 4994 """ 4995 |fun doIt() {} 4996 | 4997 |/* this is the first comment */ 4998 |""" 4999 .trimMargin()) 5000 5001 @Test 5002 fun `preserve LF, CRLF and CR line endings`() { 5003 val lines = listOf("fun main() {", " println(\"test\")", "}") 5004 for (ending in listOf("\n", "\r\n", "\r")) { 5005 val code = lines.joinToString(ending) + ending 5006 assertThatFormatting(code).isEqualTo(code) 5007 } 5008 } 5009 5010 @Test 5011 fun `handle trailing commas (constructors)`() = 5012 assertFormatted( 5013 """ 5014 |-------------------- 5015 |class Foo( 5016 | a: Int, 5017 |) 5018 | 5019 |class Foo( 5020 | a: Int, 5021 | b: Int, 5022 |) 5023 | 5024 |class Foo( 5025 | a: Int, 5026 | b: Int 5027 |) 5028 |""" 5029 .trimMargin(), 5030 deduceMaxWidth = true) 5031 5032 @Test 5033 fun `handle trailing commas (explicit constructors)`() = 5034 assertFormatted( 5035 """ 5036 |------------------------ 5037 |class Foo 5038 |constructor( 5039 | a: Int, 5040 |) 5041 | 5042 |class Foo 5043 |constructor( 5044 | a: Int, 5045 | b: Int, 5046 |) 5047 | 5048 |class Foo 5049 |constructor( 5050 | a: Int, 5051 | b: Int 5052 |) 5053 |""" 5054 .trimMargin(), 5055 deduceMaxWidth = true) 5056 5057 @Test 5058 fun `handle trailing commas (secondary constructors)`() = 5059 assertFormatted( 5060 """ 5061 |------------------------ 5062 |class Foo { 5063 | constructor( 5064 | a: Int, 5065 | ) 5066 |} 5067 | 5068 |class Foo { 5069 | constructor( 5070 | a: Int, 5071 | b: Int, 5072 | ) 5073 |} 5074 | 5075 |class Foo { 5076 | constructor( 5077 | a: Int, 5078 | b: Int 5079 | ) 5080 |} 5081 |""" 5082 .trimMargin(), 5083 deduceMaxWidth = true) 5084 5085 @Test 5086 fun `handle trailing commas (function definitions)`() = 5087 assertFormatted( 5088 """ 5089 |------------------------ 5090 |fun < 5091 | T, 5092 |> foo() {} 5093 | 5094 |fun < 5095 | T, 5096 | S, 5097 |> foo() {} 5098 | 5099 |fun foo( 5100 | a: Int, 5101 |) {} 5102 | 5103 |fun foo( 5104 | a: Int, 5105 | b: Int 5106 |) {} 5107 | 5108 |fun foo( 5109 | a: Int, 5110 | b: Int, 5111 |) {} 5112 | 5113 |fun foo( 5114 | a: Int, 5115 | b: Int, 5116 | c: Int, 5117 |) {} 5118 |""" 5119 .trimMargin(), 5120 deduceMaxWidth = true) 5121 5122 @Test 5123 fun `handle trailing commas (function calls)`() = 5124 assertFormatted( 5125 """ 5126 |------------------------ 5127 |fun main() { 5128 | foo( 5129 | 3, 5130 | ) 5131 | 5132 | foo<Int>( 5133 | 3, 5134 | ) 5135 | 5136 | foo< 5137 | Int, 5138 | >( 5139 | 3, 5140 | ) 5141 | 5142 | foo<Int>( 5143 | "asdf", "asdf") 5144 | 5145 | foo< 5146 | Int, 5147 | >( 5148 | "asd", 5149 | "asd", 5150 | ) 5151 | 5152 | foo< 5153 | Int, 5154 | Boolean, 5155 | >( 5156 | 3, 5157 | ) 5158 |} 5159 |""" 5160 .trimMargin(), 5161 deduceMaxWidth = true) 5162 5163 @Test 5164 fun `handle trailing commas (proprties)`() = 5165 assertFormatted( 5166 """ 5167 |-------------------------- 5168 |val foo: String 5169 | set( 5170 | value, 5171 | ) {} 5172 |""" 5173 .trimMargin(), 5174 deduceMaxWidth = true) 5175 5176 @Test 5177 fun `handle trailing commas (higher-order functions)`() = 5178 assertFormatted( 5179 """ 5180 |-------------------------- 5181 |fun foo( 5182 | x: 5183 | ( 5184 | Int, 5185 | ) -> Unit 5186 |) {} 5187 |""" 5188 .trimMargin(), 5189 deduceMaxWidth = true) 5190 5191 @Test 5192 fun `handle trailing commas (after lambda arg)`() = 5193 assertFormatted( 5194 """ 5195 |-------------------------- 5196 |fun foo() { 5197 | foo( 5198 | { it }, 5199 | ) 5200 |} 5201 |""" 5202 .trimMargin(), 5203 deduceMaxWidth = true) 5204 5205 @Test 5206 fun `handle trailing commas (other)`() = 5207 assertFormatted( 5208 """ 5209 |-------------------------- 5210 |fun main() { 5211 | val ( 5212 | x: Int, 5213 | ) = foo() 5214 | val ( 5215 | x: Int, 5216 | y: Int, 5217 | ) = foo() 5218 | 5219 | val ( 5220 | x: Int, 5221 | ) = foo( 5222 | blablablablFoobar, 5223 | alskdjasld) 5224 | 5225 | val ( 5226 | x: Int, 5227 | y: Int, 5228 | ) = foo( 5229 | blablablablFoobar, 5230 | asldkalsd) 5231 | 5232 | a[ 5233 | 0, 5234 | ] = 43 5235 | a[ 5236 | 0, 5237 | 1, 5238 | ] = 43 5239 | 5240 | [ 5241 | 0, 5242 | ] 5243 | [ 5244 | 0, 5245 | 1, 5246 | ] 5247 | 5248 | when (foo) { 5249 | 'x', -> 43 5250 | 'x', 5251 | 'y', -> 43 5252 | 'x', 5253 | 'y', 5254 | 'z', 5255 | 'w', 5256 | 'a', 5257 | 'b', -> 43 5258 | } 5259 | 5260 | try { 5261 | // 5262 | } catch (e: Error,) { 5263 | // 5264 | } 5265 |} 5266 |""" 5267 .trimMargin(), 5268 deduceMaxWidth = true) 5269 5270 @Test 5271 fun `assignment of a scoping function`() = 5272 assertFormatted( 5273 """ 5274 |---------------------------- 5275 |val foo = coroutineScope { 5276 | foo() 5277 | // 5278 |} 5279 | 5280 |fun foo() = coroutineScope { 5281 | foo() 5282 | // 5283 |} 5284 | 5285 |fun foo() = use { x -> 5286 | foo() 5287 | // 5288 |} 5289 | 5290 |fun foo() = 5291 | coroutineScope { x -> 5292 | foo() 5293 | // 5294 | } 5295 | 5296 |fun foo() = 5297 | Runnable @Px { 5298 | foo() 5299 | // 5300 | } 5301 | 5302 |fun longName() = 5303 | coroutineScope { 5304 | foo() 5305 | // 5306 | } 5307 |""" 5308 .trimMargin(), 5309 deduceMaxWidth = true) 5310 5311 @Test 5312 fun `top level properties with other types preserve newline spacing`() { 5313 assertFormatted( 5314 """ 5315 |--------------------------------- 5316 |fun something() { 5317 | println("hi") 5318 |} 5319 | 5320 |const val SOME_CONST = 1 5321 |val SOME_STR = "hi" 5322 |// Single comment 5323 |val SOME_INT = 1 5324 | 5325 |// Intentional space above single comment 5326 |val SOME_INT2 = 1 5327 | 5328 |val FOO = 2 5329 |const val BAR = 3 5330 | 5331 |fun baz() = 1 5332 | 5333 |val d = 1 5334 | 5335 |class Bar {} 5336 | 5337 |val e = 1 5338 |/** Doc block */ 5339 |val f = 1 5340 | 5341 |/** Intent. space above doc */ 5342 |val g = 1 5343 | 5344 |data class Qux(val foo: String) 5345 |""" 5346 .trimMargin(), 5347 deduceMaxWidth = true) 5348 5349 assertThatFormatting( 5350 """ 5351 |import com.example.foo 5352 |import com.example.bar 5353 |const val SOME_CONST = foo.a 5354 |val SOME_STR = bar.a 5355 |""" 5356 .trimMargin()) 5357 .isEqualTo( 5358 """ 5359 |import com.example.bar 5360 |import com.example.foo 5361 | 5362 |const val SOME_CONST = foo.a 5363 |val SOME_STR = bar.a 5364 |""" 5365 .trimMargin()) 5366 } 5367 5368 @Test 5369 fun `first line is never empty`() = 5370 assertThatFormatting( 5371 """ 5372 | 5373 |fun f() {} 5374 |""" 5375 .trimMargin()) 5376 .isEqualTo( 5377 """ 5378 |fun f() {} 5379 |""" 5380 .trimMargin()) 5381 5382 @Test 5383 fun `at most one newline between any adjacent top-level elements`() = 5384 assertThatFormatting( 5385 """ 5386 |import com.Bar 5387 | 5388 | 5389 |import com.Foo 5390 | 5391 | 5392 |fun f() {} 5393 | 5394 | 5395 |fun f() {} 5396 | 5397 | 5398 |class C {} 5399 | 5400 | 5401 |class C {} 5402 | 5403 | 5404 |val x = Foo() 5405 | 5406 | 5407 |val x = Bar() 5408 |""" 5409 .trimMargin()) 5410 .isEqualTo( 5411 """ 5412 |import com.Bar 5413 |import com.Foo 5414 | 5415 |fun f() {} 5416 | 5417 |fun f() {} 5418 | 5419 |class C {} 5420 | 5421 |class C {} 5422 | 5423 |val x = Foo() 5424 | 5425 |val x = Bar() 5426 |""" 5427 .trimMargin()) 5428 5429 @Test 5430 fun `at least one newline between any adjacent top-level elements, unless it's a property`() = 5431 assertThatFormatting( 5432 """ 5433 |import com.Bar 5434 |import com.Foo 5435 |fun f() {} 5436 |fun f() {} 5437 |class C {} 5438 |class C {} 5439 |val x = Foo() 5440 |val x = Bar() 5441 |""" 5442 .trimMargin()) 5443 .isEqualTo( 5444 """ 5445 |import com.Bar 5446 |import com.Foo 5447 | 5448 |fun f() {} 5449 | 5450 |fun f() {} 5451 | 5452 |class C {} 5453 | 5454 |class C {} 5455 | 5456 |val x = Foo() 5457 |val x = Bar() 5458 |""" 5459 .trimMargin()) 5460 5461 @Test 5462 fun `handle array of annotations with field prefix`() { 5463 val code: String = 5464 """ 5465 |class MyClass { 5466 | @field:[JvmStatic Volatile] 5467 | var myVar: String? = null 5468 |} 5469 | 5470 """ 5471 .trimMargin() 5472 assertThatFormatting(code).isEqualTo(code) 5473 } 5474 5475 @Test 5476 fun `handle array of annotations without field prefix`() { 5477 val code: String = 5478 """ 5479 |class MyClass { 5480 | @[JvmStatic Volatile] 5481 | var myVar: String? = null 5482 |} 5483 | 5484 """ 5485 .trimMargin() 5486 assertThatFormatting(code).isEqualTo(code) 5487 } 5488 5489 // Regression test against https://github.com/facebookincubator/ktfmt/issues/243 5490 @Test 5491 fun `regression test against Issue 243`() { 5492 val code = 5493 """ 5494 |class Foo { 5495 | companion object { 5496 | var instance: Foo? = null 5497 | 5498 | fun getInstance() { 5499 | return instance ?: synchronized(Foo::class) { 5500 | Foo().also { instance = it } 5501 | } 5502 | } 5503 | } 5504 |} 5505 |""" 5506 .trimMargin() 5507 5508 // Don't throw. 5509 Formatter.format(code) 5510 } 5511 5512 @Test 5513 fun `lambda with required arrow`() = 5514 assertFormatted( 5515 """ 5516 |val a = { x: Int -> } 5517 |val b = { x: Int -> 0 } 5518 |val c = { x: Int -> 5519 | val y = 0 5520 | y 5521 |} 5522 |""" 5523 .trimMargin()) 5524 5525 @Test 5526 fun `lambda with optional arrow`() = 5527 assertFormatted( 5528 """ 5529 |val a = { -> } 5530 |val b = { -> 0 } 5531 |val c = { -> 5532 | val y = 0 5533 | y 5534 |} 5535 |""" 5536 .trimMargin()) 5537 5538 @Test 5539 fun `lambda missing optional arrow`() = 5540 assertFormatted( 5541 """ 5542 |val a = {} 5543 |val b = { 0 } 5544 |val c = { 5545 | val y = 0 5546 | y 5547 |} 5548 |""" 5549 .trimMargin()) 5550 5551 @Test 5552 fun `chaining - many dereferences`() = 5553 assertFormatted( 5554 """ 5555 |------------------------- 5556 |rainbow.red.orange.yellow 5557 | .green 5558 | .blue 5559 | .indigo 5560 | .violet 5561 | .cyan 5562 | .magenta 5563 | .key 5564 |""" 5565 .trimMargin(), 5566 deduceMaxWidth = true) 5567 5568 @Test 5569 fun `chaining - many dereferences, fit on one line`() = 5570 assertFormatted( 5571 """ 5572 |--------------------------------------------------------------------------- 5573 |rainbow.red.orange.yellow.green.blue.indigo.violet.cyan.magenta.key 5574 |""" 5575 .trimMargin(), 5576 deduceMaxWidth = true) 5577 5578 @Test 5579 fun `chaining - many dereferences, one invocation at end`() = 5580 assertFormatted( 5581 """ 5582 |------------------------- 5583 |rainbow.red.orange.yellow 5584 | .green 5585 | .blue 5586 | .indigo 5587 | .violet 5588 | .cyan 5589 | .magenta 5590 | .key 5591 | .build() 5592 |""" 5593 .trimMargin(), 5594 deduceMaxWidth = true) 5595 5596 @Test 5597 fun `chaining - many dereferences, one invocation at end, fit on one line`() = 5598 assertFormatted( 5599 """ 5600 |--------------------------------------------------------------------------- 5601 |rainbow.red.orange.yellow.green.blue.indigo.violet.cyan.magenta.key.build() 5602 |""" 5603 .trimMargin(), 5604 deduceMaxWidth = true) 5605 5606 @Test 5607 fun `chaining - many dereferences, two invocations at end`() = 5608 assertFormatted( 5609 """ 5610 |------------------------- 5611 |rainbow.red.orange.yellow 5612 | .green 5613 | .blue 5614 | .indigo 5615 | .violet 5616 | .cyan 5617 | .magenta 5618 | .key 5619 | .build() 5620 | .shine() 5621 |""" 5622 .trimMargin(), 5623 deduceMaxWidth = true) 5624 5625 @Test 5626 fun `chaining - many dereferences, one invocation in the middle`() = 5627 assertFormatted( 5628 """ 5629 |------------------------- 5630 |rainbow.red.orange.yellow 5631 | .green 5632 | .blue 5633 | .shine() 5634 | .indigo 5635 | .violet 5636 | .cyan 5637 | .magenta 5638 | .key 5639 |""" 5640 .trimMargin(), 5641 deduceMaxWidth = true) 5642 5643 @Test 5644 fun `chaining - many dereferences, two invocations in the middle`() = 5645 assertFormatted( 5646 """ 5647 |------------------------- 5648 |rainbow.red.orange.yellow 5649 | .green 5650 | .blue 5651 | .indigo 5652 | .shine() 5653 | .bright() 5654 | .violet 5655 | .cyan 5656 | .magenta 5657 | .key 5658 |""" 5659 .trimMargin(), 5660 deduceMaxWidth = true) 5661 5662 @Test 5663 fun `chaining - many dereferences, one lambda at end`() = 5664 assertFormatted( 5665 """ 5666 |------------------------- 5667 |rainbow.red.orange.yellow 5668 | .green 5669 | .blue 5670 | .indigo 5671 | .violet 5672 | .cyan 5673 | .magenta 5674 | .key 5675 | .build { it.appear } 5676 |""" 5677 .trimMargin(), 5678 deduceMaxWidth = true) 5679 5680 @Test 5681 fun `chaining - many dereferences, one short lambda at end`() = 5682 assertFormatted( 5683 """ 5684 |------------------------- 5685 |rainbow.red.orange.yellow 5686 | .green 5687 | .blue 5688 | .indigo 5689 | .violet 5690 | .cyan 5691 | .magenta 5692 | .key 5693 | .z { it } 5694 |""" 5695 .trimMargin(), 5696 deduceMaxWidth = true) 5697 5698 @Test 5699 fun `chaining - many dereferences, one multiline lambda at end`() = 5700 assertFormatted( 5701 """ 5702 |------------------------- 5703 |rainbow.red.orange.yellow 5704 | .green 5705 | .blue 5706 | .indigo 5707 | .violet 5708 | .cyan 5709 | .magenta 5710 | .key 5711 | .z { 5712 | it 5713 | it 5714 | } 5715 |""" 5716 .trimMargin(), 5717 deduceMaxWidth = true) 5718 5719 @Test 5720 fun `chaining - many dereferences, one short lambda in the middle`() = 5721 assertFormatted( 5722 """ 5723 |------------------------- 5724 |rainbow.red.orange.yellow 5725 | .green 5726 | .blue 5727 | .z { it } 5728 | .indigo 5729 | .violet 5730 | .cyan 5731 | .magenta 5732 | .key 5733 |""" 5734 .trimMargin(), 5735 deduceMaxWidth = true) 5736 5737 @Test 5738 fun `chaining - many dereferences, one multiline lambda in the middle`() = 5739 assertFormatted( 5740 """ 5741 |------------------------- 5742 |rainbow.red.orange.yellow 5743 | .green 5744 | .blue 5745 | .z { 5746 | it 5747 | it 5748 | } 5749 | .indigo 5750 | .violet 5751 | .cyan 5752 | .magenta 5753 | .key 5754 |""" 5755 .trimMargin(), 5756 deduceMaxWidth = true) 5757 5758 @Test 5759 fun `chaining - many dereferences, one multiline lambda in the middle, remainder could fit on one line`() = 5760 assertFormatted( 5761 """ 5762 |----------------------------------------------------------------------------------------- 5763 |rainbow.red.orange.yellow.green.blue 5764 | .z { 5765 | it 5766 | it 5767 | } 5768 | .indigo 5769 | .violet 5770 | .cyan 5771 | .magenta 5772 | .key 5773 |""" 5774 .trimMargin(), 5775 deduceMaxWidth = true) 5776 5777 @Test 5778 fun `chaining - many dereferences, one multiline lambda and two invocations in the middle, remainder could fit on one line`() = 5779 assertFormatted( 5780 """ 5781 |----------------------------------------------------------------------------------------- 5782 |rainbow.red.orange.yellow.green.blue 5783 | .z { 5784 | it 5785 | it 5786 | } 5787 | .shine() 5788 | .bright() 5789 | .indigo 5790 | .violet 5791 | .cyan 5792 | .magenta 5793 | .key 5794 |""" 5795 .trimMargin(), 5796 deduceMaxWidth = true) 5797 5798 @Test 5799 fun `chaining - many dereferences, one lambda and invocation at end`() = 5800 assertFormatted( 5801 """ 5802 |------------------------- 5803 |rainbow.red.orange.yellow 5804 | .green 5805 | .blue 5806 | .indigo 5807 | .violet 5808 | .cyan 5809 | .magenta 5810 | .key 5811 | .z { it } 5812 | .shine() 5813 |""" 5814 .trimMargin(), 5815 deduceMaxWidth = true) 5816 5817 @Test 5818 fun `chaining - many dereferences, one multiline lambda and invocation at end`() = 5819 assertFormatted( 5820 """ 5821 |------------------------- 5822 |rainbow.red.orange.yellow 5823 | .green 5824 | .blue 5825 | .indigo 5826 | .violet 5827 | .cyan 5828 | .magenta 5829 | .key 5830 | .z { 5831 | it 5832 | it 5833 | } 5834 | .shine() 5835 |""" 5836 .trimMargin(), 5837 deduceMaxWidth = true) 5838 5839 @Test 5840 fun `chaining - many dereferences, one invocation and lambda at end`() = 5841 assertFormatted( 5842 """ 5843 |------------------------- 5844 |rainbow.red.orange.yellow 5845 | .green 5846 | .blue 5847 | .indigo 5848 | .violet 5849 | .cyan 5850 | .magenta 5851 | .key 5852 | .shine() 5853 | .z { it } 5854 |""" 5855 .trimMargin(), 5856 deduceMaxWidth = true) 5857 5858 @Test 5859 fun `chaining - many dereferences, one short lambda and invocation in the middle`() = 5860 assertFormatted( 5861 """ 5862 |------------------------- 5863 |rainbow.red.orange.yellow 5864 | .green 5865 | .blue 5866 | .indigo 5867 | .z { it } 5868 | .shine() 5869 | .violet 5870 | .cyan 5871 | .magenta 5872 | .key 5873 |""" 5874 .trimMargin(), 5875 deduceMaxWidth = true) 5876 5877 @Test 5878 fun `chaining - many dereferences, invocation and one short lambda in the middle`() = 5879 assertFormatted( 5880 """ 5881 |------------------------- 5882 |rainbow.red.orange.yellow 5883 | .green 5884 | .blue 5885 | .indigo 5886 | .shine() 5887 | .z { it } 5888 | .violet 5889 | .cyan 5890 | .magenta 5891 | .key 5892 |""" 5893 .trimMargin(), 5894 deduceMaxWidth = true) 5895 5896 @Test 5897 fun `chaining - many dereferences, starting with this`() = 5898 assertFormatted( 5899 """ 5900 |------------------------- 5901 |this.red.orange.yellow 5902 | .green 5903 | .blue 5904 | .indigo 5905 | .violet 5906 | .cyan 5907 | .magenta 5908 | .key 5909 |""" 5910 .trimMargin(), 5911 deduceMaxWidth = true) 5912 5913 @Test 5914 fun `chaining - many dereferences, starting with this, one invocation at end`() = 5915 assertFormatted( 5916 """ 5917 |------------------------- 5918 |this.red.orange.yellow 5919 | .green 5920 | .blue 5921 | .indigo 5922 | .violet 5923 | .cyan 5924 | .magenta 5925 | .key 5926 | .build() 5927 |""" 5928 .trimMargin(), 5929 deduceMaxWidth = true) 5930 5931 @Test 5932 fun `chaining - many dereferences, starting with super`() = 5933 assertFormatted( 5934 """ 5935 |------------------------- 5936 |super.red.orange.yellow 5937 | .green 5938 | .blue 5939 | .indigo 5940 | .violet 5941 | .cyan 5942 | .magenta 5943 | .key 5944 |""" 5945 .trimMargin(), 5946 deduceMaxWidth = true) 5947 5948 @Test 5949 fun `chaining - many dereferences, starting with super, one invocation at end`() = 5950 assertFormatted( 5951 """ 5952 |------------------------- 5953 |super.red.orange.yellow 5954 | .green 5955 | .blue 5956 | .indigo 5957 | .violet 5958 | .cyan 5959 | .magenta 5960 | .key 5961 | .build() 5962 |""" 5963 .trimMargin(), 5964 deduceMaxWidth = true) 5965 5966 @Test 5967 fun `chaining - many dereferences, starting with short variable`() = 5968 assertFormatted( 5969 """ 5970 |------------------------- 5971 |z123.red.orange.yellow 5972 | .green 5973 | .blue 5974 | .indigo 5975 | .violet 5976 | .cyan 5977 | .magenta 5978 | .key 5979 |""" 5980 .trimMargin(), 5981 deduceMaxWidth = true) 5982 5983 @Test 5984 fun `chaining - many dereferences, starting with short variable, one invocation at end`() = 5985 assertFormatted( 5986 """ 5987 |------------------------- 5988 |z123.red.orange.yellow 5989 | .green 5990 | .blue 5991 | .indigo 5992 | .violet 5993 | .cyan 5994 | .magenta 5995 | .key 5996 | .build() 5997 |""" 5998 .trimMargin(), 5999 deduceMaxWidth = true) 6000 6001 @Test 6002 fun `chaining - many dereferences, starting with short variable and lambda, invocation at end`() = 6003 assertFormatted( 6004 """ 6005 |------------------------- 6006 |z12.z { it } 6007 | .red 6008 | .orange 6009 | .yellow 6010 | .green 6011 | .blue 6012 | .indigo 6013 | .violet 6014 | .cyan 6015 | .magenta 6016 | .key 6017 | .shine() 6018 |""" 6019 .trimMargin(), 6020 deduceMaxWidth = true) 6021 6022 @Test 6023 fun `chaining - many dereferences, starting with this and lambda, invocation at end`() = 6024 assertFormatted( 6025 """ 6026 |------------------------- 6027 |this.z { it } 6028 | .red 6029 | .orange 6030 | .yellow 6031 | .green 6032 | .blue 6033 | .indigo 6034 | .violet 6035 | .cyan 6036 | .magenta 6037 | .key 6038 | .shine() 6039 |""" 6040 .trimMargin(), 6041 deduceMaxWidth = true) 6042 6043 @Test 6044 fun `chaining - many invocations`() = 6045 assertFormatted( 6046 """ 6047 |------------------------- 6048 |rainbow.a().b().c() 6049 |""" 6050 .trimMargin(), 6051 deduceMaxWidth = true) 6052 6053 @Test 6054 fun `chaining - many invocations, with multiline lambda at end`() = 6055 assertFormatted( 6056 """ 6057 |------------------------- 6058 |rainbow.a().b().c().zz { 6059 | it 6060 | it 6061 |} 6062 |""" 6063 .trimMargin(), 6064 deduceMaxWidth = true) 6065 6066 @Test 6067 fun `chaining - many dereferences, starting type name`() = 6068 assertFormatted( 6069 """ 6070 |------------------------- 6071 |com.sky.Rainbow.red 6072 | .orange 6073 | .yellow 6074 | .green 6075 | .blue 6076 | .indigo 6077 | .violet 6078 | .cyan 6079 | .magenta 6080 | .key 6081 |""" 6082 .trimMargin(), 6083 deduceMaxWidth = true) 6084 6085 @Test 6086 fun `chaining - many invocations, starting with short variable, lambda at end`() = 6087 assertFormatted( 6088 """ 6089 |------------- 6090 |z12.shine() 6091 | .bright() 6092 | .z { it } 6093 |""" 6094 .trimMargin(), 6095 deduceMaxWidth = true) 6096 6097 @Test 6098 fun `chaining - start with invocation, lambda at end`() = 6099 assertFormatted( 6100 """ 6101 |--------------------- 6102 |getRainbow( 6103 | aa, bb, cc) 6104 | .z { it } 6105 |""" 6106 .trimMargin(), 6107 deduceMaxWidth = true) 6108 6109 @Test 6110 fun `chaining - many invocations, start with lambda`() = 6111 assertFormatted( 6112 """ 6113 |--------------------- 6114 |z { it } 6115 | .shine() 6116 | .bright() 6117 |""" 6118 .trimMargin(), 6119 deduceMaxWidth = true) 6120 6121 @Test 6122 fun `chaining - start with type name, end with invocation`() = 6123 assertFormatted( 6124 """ 6125 |------------------------- 6126 |com.sky.Rainbow 6127 | .colorFactory 6128 | .build() 6129 |""" 6130 .trimMargin(), 6131 deduceMaxWidth = true) 6132 6133 @Test 6134 fun `chaining (indentation) - multiline lambda`() = 6135 assertFormatted( 6136 """ 6137 |------------------------- 6138 |rainbow.z { 6139 | it 6140 | it 6141 |} 6142 |""" 6143 .trimMargin(), 6144 deduceMaxWidth = true) 6145 6146 @Test 6147 fun `chaining (indentation) - multiline lambda with trailing dereferences`() = 6148 assertFormatted( 6149 """ 6150 |------------------------- 6151 |rainbow 6152 | .z { 6153 | it 6154 | it 6155 | } 6156 | .red 6157 |""" 6158 .trimMargin(), 6159 deduceMaxWidth = true) 6160 6161 @Test 6162 fun `chaining (indentation) - multiline lambda with long name`() = 6163 assertFormatted( 6164 """ 6165 |------------------------- 6166 |rainbow 6167 | .someLongLambdaName { 6168 | it 6169 | it 6170 | } 6171 |""" 6172 .trimMargin(), 6173 deduceMaxWidth = true) 6174 6175 @Test 6176 fun `chaining (indentation) - multiline lambda with long name and trailing dereferences`() = 6177 assertFormatted( 6178 """ 6179 |------------------------- 6180 |rainbow 6181 | .someLongLambdaName { 6182 | it 6183 | it 6184 | } 6185 | .red 6186 |""" 6187 .trimMargin(), 6188 deduceMaxWidth = true) 6189 6190 @Test 6191 fun `chaining (indentation) - multiline lambda with prefix`() = 6192 assertFormatted( 6193 """ 6194 |------------------------- 6195 |rainbow.red.z { 6196 | it 6197 | it 6198 |} 6199 |""" 6200 .trimMargin(), 6201 deduceMaxWidth = true) 6202 6203 @Test 6204 fun `chaining (indentation) - multiline lambda with prefix, forced to next line`() = 6205 assertFormatted( 6206 """ 6207 |------------------------- 6208 |rainbow.red.orange.yellow 6209 | .longLambdaName { 6210 | it 6211 | it 6212 | } 6213 |""" 6214 .trimMargin(), 6215 deduceMaxWidth = true) 6216 6217 @Test 6218 fun `chaining (indentation) - multiline lambda with prefix, forced to next line with another expression`() = 6219 assertFormatted( 6220 """ 6221 |------------------------- 6222 |rainbow.red.orange.yellow 6223 | .key 6224 | .longLambdaName { 6225 | it 6226 | it 6227 | } 6228 |""" 6229 .trimMargin(), 6230 deduceMaxWidth = true) 6231 6232 @Test 6233 fun `chaining (indentation) - multiline arguments`() = 6234 assertFormatted( 6235 """ 6236 |------------------------- 6237 |rainbow.shine( 6238 | infrared, 6239 | ultraviolet, 6240 |) 6241 |""" 6242 .trimMargin(), 6243 deduceMaxWidth = true) 6244 6245 @Test 6246 fun `chaining (indentation) - multiline arguments with trailing dereferences`() = 6247 assertFormatted( 6248 """ 6249 |------------------------- 6250 |rainbow 6251 | .shine( 6252 | infrared, 6253 | ultraviolet, 6254 | ) 6255 | .red 6256 |""" 6257 .trimMargin(), 6258 deduceMaxWidth = true) 6259 6260 @Test 6261 fun `chaining (indentation) - multiline arguments, forced to next line`() = 6262 assertFormatted( 6263 """ 6264 |------------------------- 6265 |rainbow.red.orange.yellow 6266 | .shine( 6267 | infrared, 6268 | ultraviolet, 6269 | ) 6270 |""" 6271 .trimMargin(), 6272 deduceMaxWidth = true) 6273 6274 @Test 6275 fun `chaining (indentation) - multiline arguments, forced to next line with another expression`() = 6276 assertFormatted( 6277 """ 6278 |------------------------- 6279 |rainbow.red.orange.yellow 6280 | .key 6281 | .shine( 6282 | infrared, 6283 | ultraviolet, 6284 | ) 6285 |""" 6286 .trimMargin(), 6287 deduceMaxWidth = true) 6288 6289 @Test 6290 fun `chaining (indentation) - multiline arguments, forced to next line with another expression, with trailing dereferences`() = 6291 assertFormatted( 6292 """ 6293 |------------------------- 6294 |rainbow.red.orange.yellow 6295 | .key 6296 | .shine( 6297 | infrared, 6298 | ultraviolet, 6299 | ) 6300 | .red 6301 |""" 6302 .trimMargin(), 6303 deduceMaxWidth = true) 6304 6305 @Test 6306 fun `chaining (indentation) - multiline arguments, with trailing invocation`() = 6307 assertFormatted( 6308 """ 6309 |------------------------- 6310 |rainbow 6311 | .shine( 6312 | infrared, 6313 | ultraviolet, 6314 | ) 6315 | .bright() 6316 |""" 6317 .trimMargin(), 6318 deduceMaxWidth = true) 6319 6320 @Test 6321 fun `chaining (indentation) - multiline arguments, with trailing lambda`() = 6322 assertFormatted( 6323 """ 6324 |------------------------- 6325 |rainbow 6326 | .shine( 6327 | infrared, 6328 | ultraviolet, 6329 | ) 6330 | .z { it } 6331 |""" 6332 .trimMargin(), 6333 deduceMaxWidth = true) 6334 6335 @Test 6336 fun `chaining (indentation) - multiline arguments, prefixed with super, with trailing invocation`() = 6337 assertFormatted( 6338 """ 6339 |------------------------- 6340 |super.shine( 6341 | infrared, 6342 | ultraviolet, 6343 | ) 6344 | .bright() 6345 |""" 6346 .trimMargin(), 6347 deduceMaxWidth = true) 6348 6349 @Test 6350 fun `chaining (indentation) - multiline arguments, starting with short variable, with trailing invocation`() = 6351 assertFormatted( 6352 """ 6353 |------------------------- 6354 |z12.shine( 6355 | infrared, 6356 | ultraviolet, 6357 | ) 6358 | .bright() 6359 |""" 6360 .trimMargin(), 6361 deduceMaxWidth = true) 6362 6363 @Test 6364 fun `chaining (indentation) - start with multiline arguments`() = 6365 assertFormatted( 6366 """ 6367 |------------------------- 6368 |getRainbow( 6369 | infrared, 6370 | ultraviolet, 6371 |) 6372 |""" 6373 .trimMargin(), 6374 deduceMaxWidth = true) 6375 6376 @Test 6377 fun `chaining (indentation) - start with multiline arguments, with trailing invocation`() = 6378 assertFormatted( 6379 """ 6380 |------------------------- 6381 |getRainbow( 6382 | infrared, 6383 | ultraviolet, 6384 | ) 6385 | .z { it } 6386 |""" 6387 .trimMargin(), 6388 deduceMaxWidth = true) 6389 6390 @Test 6391 fun `annotations for expressions`() = 6392 assertFormatted( 6393 """ 6394 |fun f() { 6395 | var b 6396 | @Suppress("UNCHECKED_CAST") b = f(1) as Int 6397 | @Suppress("UNCHECKED_CAST") 6398 | b = f(1) as Int 6399 | 6400 | @Suppress("UNCHECKED_CAST") b = f(1) to 5 6401 | @Suppress("UNCHECKED_CAST") 6402 | b = f(1) to 5 6403 | 6404 | @Suppress("UNCHECKED_CAST") f(1) as Int + 5 6405 | @Suppress("UNCHECKED_CAST") 6406 | f(1) as Int + 5 6407 | 6408 | @Anno1 /* comment */ @Anno2 f(1) as Int 6409 |} 6410 |""" 6411 .trimMargin()) 6412 6413 @Test 6414 fun `annotations for expressions 2`() { 6415 val code = 6416 """ 6417 |fun f() { 6418 | @Suppress("UNCHECKED_CAST") f(1 + f(1) as Int) 6419 | @Suppress("UNCHECKED_CAST") 6420 | f(1 + f(1) as Int) 6421 |} 6422 |""" 6423 .trimMargin() 6424 6425 val expected = 6426 """ 6427 |fun f() { 6428 | @Suppress("UNCHECKED_CAST") f(1 + f(1) as Int) 6429 | @Suppress("UNCHECKED_CAST") f(1 + f(1) as Int) 6430 |} 6431 |""" 6432 .trimMargin() 6433 6434 assertThatFormatting(code).isEqualTo(expected) 6435 } 6436 6437 @Test 6438 fun `function call following long multiline string`() = 6439 assertFormatted( 6440 """ 6441 |-------------------------------- 6442 |fun f() { 6443 | val str1 = 6444 | $TQ 6445 | Some very long string that might mess things up 6446 | $TQ 6447 | .trimIndent() 6448 | 6449 | val str2 = 6450 | $TQ 6451 | Some very long string that might mess things up 6452 | $TQ 6453 | .trimIndent(someArg) 6454 |} 6455 |""" 6456 .trimMargin(), 6457 deduceMaxWidth = true) 6458 6459 @Test 6460 fun `array-literal in annotation`() = 6461 assertFormatted( 6462 """ 6463 |-------------------------------- 6464 |@Anno( 6465 | array = 6466 | [ 6467 | someItem, 6468 | andAnother, 6469 | noTrailingComma]) 6470 |class Host 6471 | 6472 |@Anno( 6473 | array = 6474 | [ 6475 | someItem, 6476 | andAnother, 6477 | withTrailingComma, 6478 | ]) 6479 |class Host 6480 | 6481 |@Anno( 6482 | array = 6483 | [ 6484 | // Comment 6485 | someItem, 6486 | // Comment 6487 | andAnother, 6488 | // Comment 6489 | withTrailingComment 6490 | // Comment 6491 | // Comment 6492 | ]) 6493 |class Host 6494 |""" 6495 .trimMargin(), 6496 deduceMaxWidth = true) 6497 6498 companion object { 6499 /** Triple quotes, useful to use within triple-quoted strings. */ 6500 private const val TQ = "\"\"\"" 6501 } 6502 } 6503