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