1 /* 2 * Copyright (C) 2015 Square, Inc. 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 package com.squareup.javapoet; 17 18 import com.google.common.collect.ImmutableMap; 19 import com.google.testing.compile.CompilationRule; 20 import java.io.File; 21 import java.io.IOException; 22 import java.io.Serializable; 23 import java.math.BigDecimal; 24 import java.util.AbstractSet; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.Comparator; 29 import java.util.EventListener; 30 import java.util.List; 31 import java.util.Locale; 32 import java.util.Map; 33 import java.util.Random; 34 import java.util.concurrent.Callable; 35 import javax.lang.model.element.Element; 36 import javax.lang.model.element.Modifier; 37 import javax.lang.model.element.TypeElement; 38 import javax.lang.model.type.TypeMirror; 39 import org.junit.Rule; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 import org.junit.runners.JUnit4; 43 import org.mockito.Mockito; 44 45 import static com.google.common.truth.Truth.assertThat; 46 import static org.junit.Assert.assertEquals; 47 import static org.junit.Assert.fail; 48 49 @RunWith(JUnit4.class) 50 public final class TypeSpecTest { 51 private final String tacosPackage = "com.squareup.tacos"; 52 private static final String donutsPackage = "com.squareup.donuts"; 53 54 @Rule public final CompilationRule compilation = new CompilationRule(); 55 getElement(Class<?> clazz)56 private TypeElement getElement(Class<?> clazz) { 57 return compilation.getElements().getTypeElement(clazz.getCanonicalName()); 58 } 59 basic()60 @Test public void basic() throws Exception { 61 TypeSpec taco = TypeSpec.classBuilder("Taco") 62 .addMethod(MethodSpec.methodBuilder("toString") 63 .addAnnotation(Override.class) 64 .addModifiers(Modifier.PUBLIC, Modifier.FINAL) 65 .returns(String.class) 66 .addCode("return $S;\n", "taco") 67 .build()) 68 .build(); 69 assertThat(toString(taco)).isEqualTo("" 70 + "package com.squareup.tacos;\n" 71 + "\n" 72 + "import java.lang.Override;\n" 73 + "import java.lang.String;\n" 74 + "\n" 75 + "class Taco {\n" 76 + " @Override\n" 77 + " public final String toString() {\n" 78 + " return \"taco\";\n" 79 + " }\n" 80 + "}\n"); 81 assertEquals(472949424, taco.hashCode()); // update expected number if source changes 82 } 83 interestingTypes()84 @Test public void interestingTypes() throws Exception { 85 TypeName listOfAny = ParameterizedTypeName.get( 86 ClassName.get(List.class), WildcardTypeName.subtypeOf(Object.class)); 87 TypeName listOfExtends = ParameterizedTypeName.get( 88 ClassName.get(List.class), WildcardTypeName.subtypeOf(Serializable.class)); 89 TypeName listOfSuper = ParameterizedTypeName.get(ClassName.get(List.class), 90 WildcardTypeName.supertypeOf(String.class)); 91 TypeSpec taco = TypeSpec.classBuilder("Taco") 92 .addField(listOfAny, "extendsObject") 93 .addField(listOfExtends, "extendsSerializable") 94 .addField(listOfSuper, "superString") 95 .build(); 96 assertThat(toString(taco)).isEqualTo("" 97 + "package com.squareup.tacos;\n" 98 + "\n" 99 + "import java.io.Serializable;\n" 100 + "import java.lang.String;\n" 101 + "import java.util.List;\n" 102 + "\n" 103 + "class Taco {\n" 104 + " List<?> extendsObject;\n" 105 + "\n" 106 + " List<? extends Serializable> extendsSerializable;\n" 107 + "\n" 108 + " List<? super String> superString;\n" 109 + "}\n"); 110 } 111 anonymousInnerClass()112 @Test public void anonymousInnerClass() throws Exception { 113 ClassName foo = ClassName.get(tacosPackage, "Foo"); 114 ClassName bar = ClassName.get(tacosPackage, "Bar"); 115 ClassName thingThang = ClassName.get(tacosPackage, "Thing", "Thang"); 116 TypeName thingThangOfFooBar = ParameterizedTypeName.get(thingThang, foo, bar); 117 ClassName thung = ClassName.get(tacosPackage, "Thung"); 118 ClassName simpleThung = ClassName.get(tacosPackage, "SimpleThung"); 119 TypeName thungOfSuperBar = ParameterizedTypeName.get(thung, WildcardTypeName.supertypeOf(bar)); 120 TypeName thungOfSuperFoo = ParameterizedTypeName.get(thung, WildcardTypeName.supertypeOf(foo)); 121 TypeName simpleThungOfBar = ParameterizedTypeName.get(simpleThung, bar); 122 123 ParameterSpec thungParameter = ParameterSpec.builder(thungOfSuperFoo, "thung") 124 .addModifiers(Modifier.FINAL) 125 .build(); 126 TypeSpec aSimpleThung = TypeSpec.anonymousClassBuilder(CodeBlock.of("$N", thungParameter)) 127 .superclass(simpleThungOfBar) 128 .addMethod(MethodSpec.methodBuilder("doSomething") 129 .addAnnotation(Override.class) 130 .addModifiers(Modifier.PUBLIC) 131 .addParameter(bar, "bar") 132 .addCode("/* code snippets */\n") 133 .build()) 134 .build(); 135 TypeSpec aThingThang = TypeSpec.anonymousClassBuilder("") 136 .superclass(thingThangOfFooBar) 137 .addMethod(MethodSpec.methodBuilder("call") 138 .addAnnotation(Override.class) 139 .addModifiers(Modifier.PUBLIC) 140 .returns(thungOfSuperBar) 141 .addParameter(thungParameter) 142 .addCode("return $L;\n", aSimpleThung) 143 .build()) 144 .build(); 145 TypeSpec taco = TypeSpec.classBuilder("Taco") 146 .addField(FieldSpec.builder(thingThangOfFooBar, "NAME") 147 .addModifiers(Modifier.STATIC, Modifier.FINAL, Modifier.FINAL) 148 .initializer("$L", aThingThang) 149 .build()) 150 .build(); 151 152 assertThat(toString(taco)).isEqualTo("" 153 + "package com.squareup.tacos;\n" 154 + "\n" 155 + "import java.lang.Override;\n" 156 + "\n" 157 + "class Taco {\n" 158 + " static final Thing.Thang<Foo, Bar> NAME = new Thing.Thang<Foo, Bar>() {\n" 159 + " @Override\n" 160 + " public Thung<? super Bar> call(final Thung<? super Foo> thung) {\n" 161 + " return new SimpleThung<Bar>(thung) {\n" 162 + " @Override\n" 163 + " public void doSomething(Bar bar) {\n" 164 + " /* code snippets */\n" 165 + " }\n" 166 + " };\n" 167 + " }\n" 168 + " };\n" 169 + "}\n"); 170 } 171 annotatedParameters()172 @Test public void annotatedParameters() throws Exception { 173 TypeSpec service = TypeSpec.classBuilder("Foo") 174 .addMethod(MethodSpec.constructorBuilder() 175 .addModifiers(Modifier.PUBLIC) 176 .addParameter(long.class, "id") 177 .addParameter(ParameterSpec.builder(String.class, "one") 178 .addAnnotation(ClassName.get(tacosPackage, "Ping")) 179 .build()) 180 .addParameter(ParameterSpec.builder(String.class, "two") 181 .addAnnotation(ClassName.get(tacosPackage, "Ping")) 182 .build()) 183 .addParameter(ParameterSpec.builder(String.class, "three") 184 .addAnnotation(AnnotationSpec.builder(ClassName.get(tacosPackage, "Pong")) 185 .addMember("value", "$S", "pong") 186 .build()) 187 .build()) 188 .addParameter(ParameterSpec.builder(String.class, "four") 189 .addAnnotation(ClassName.get(tacosPackage, "Ping")) 190 .build()) 191 .addCode("/* code snippets */\n") 192 .build()) 193 .build(); 194 195 assertThat(toString(service)).isEqualTo("" 196 + "package com.squareup.tacos;\n" 197 + "\n" 198 + "import java.lang.String;\n" 199 + "\n" 200 + "class Foo {\n" 201 + " public Foo(long id, @Ping String one, @Ping String two, @Pong(\"pong\") String three,\n" 202 + " @Ping String four) {\n" 203 + " /* code snippets */\n" 204 + " }\n" 205 + "}\n"); 206 } 207 208 /** 209 * We had a bug where annotations were preventing us from doing the right thing when resolving 210 * imports. https://github.com/square/javapoet/issues/422 211 */ annotationsAndJavaLangTypes()212 @Test public void annotationsAndJavaLangTypes() throws Exception { 213 ClassName freeRange = ClassName.get("javax.annotation", "FreeRange"); 214 TypeSpec taco = TypeSpec.classBuilder("EthicalTaco") 215 .addField(ClassName.get(String.class) 216 .annotated(AnnotationSpec.builder(freeRange).build()), "meat") 217 .build(); 218 219 assertThat(toString(taco)).isEqualTo("" 220 + "package com.squareup.tacos;\n" 221 + "\n" 222 + "import java.lang.String;\n" 223 + "import javax.annotation.FreeRange;\n" 224 + "\n" 225 + "class EthicalTaco {\n" 226 + " @FreeRange String meat;\n" 227 + "}\n"); 228 } 229 retrofitStyleInterface()230 @Test public void retrofitStyleInterface() throws Exception { 231 ClassName observable = ClassName.get(tacosPackage, "Observable"); 232 ClassName fooBar = ClassName.get(tacosPackage, "FooBar"); 233 ClassName thing = ClassName.get(tacosPackage, "Thing"); 234 ClassName things = ClassName.get(tacosPackage, "Things"); 235 ClassName map = ClassName.get("java.util", "Map"); 236 ClassName string = ClassName.get("java.lang", "String"); 237 ClassName headers = ClassName.get(tacosPackage, "Headers"); 238 ClassName post = ClassName.get(tacosPackage, "POST"); 239 ClassName body = ClassName.get(tacosPackage, "Body"); 240 ClassName queryMap = ClassName.get(tacosPackage, "QueryMap"); 241 ClassName header = ClassName.get(tacosPackage, "Header"); 242 TypeSpec service = TypeSpec.interfaceBuilder("Service") 243 .addMethod(MethodSpec.methodBuilder("fooBar") 244 .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) 245 .addAnnotation(AnnotationSpec.builder(headers) 246 .addMember("value", "$S", "Accept: application/json") 247 .addMember("value", "$S", "User-Agent: foobar") 248 .build()) 249 .addAnnotation(AnnotationSpec.builder(post) 250 .addMember("value", "$S", "/foo/bar") 251 .build()) 252 .returns(ParameterizedTypeName.get(observable, fooBar)) 253 .addParameter(ParameterSpec.builder(ParameterizedTypeName.get(things, thing), "things") 254 .addAnnotation(body) 255 .build()) 256 .addParameter(ParameterSpec.builder( 257 ParameterizedTypeName.get(map, string, string), "query") 258 .addAnnotation(AnnotationSpec.builder(queryMap) 259 .addMember("encodeValues", "false") 260 .build()) 261 .build()) 262 .addParameter(ParameterSpec.builder(string, "authorization") 263 .addAnnotation(AnnotationSpec.builder(header) 264 .addMember("value", "$S", "Authorization") 265 .build()) 266 .build()) 267 .build()) 268 .build(); 269 270 assertThat(toString(service)).isEqualTo("" 271 + "package com.squareup.tacos;\n" 272 + "\n" 273 + "import java.lang.String;\n" 274 + "import java.util.Map;\n" 275 + "\n" 276 + "interface Service {\n" 277 + " @Headers({\n" 278 + " \"Accept: application/json\",\n" 279 + " \"User-Agent: foobar\"\n" 280 + " })\n" 281 + " @POST(\"/foo/bar\")\n" 282 + " Observable<FooBar> fooBar(@Body Things<Thing> things,\n" 283 + " @QueryMap(encodeValues = false) Map<String, String> query,\n" 284 + " @Header(\"Authorization\") String authorization);\n" 285 + "}\n"); 286 } 287 annotatedField()288 @Test public void annotatedField() throws Exception { 289 TypeSpec taco = TypeSpec.classBuilder("Taco") 290 .addField(FieldSpec.builder(String.class, "thing", Modifier.PRIVATE, Modifier.FINAL) 291 .addAnnotation(AnnotationSpec.builder(ClassName.get(tacosPackage, "JsonAdapter")) 292 .addMember("value", "$T.class", ClassName.get(tacosPackage, "Foo")) 293 .build()) 294 .build()) 295 .build(); 296 assertThat(toString(taco)).isEqualTo("" 297 + "package com.squareup.tacos;\n" 298 + "\n" 299 + "import java.lang.String;\n" 300 + "\n" 301 + "class Taco {\n" 302 + " @JsonAdapter(Foo.class)\n" 303 + " private final String thing;\n" 304 + "}\n"); 305 } 306 annotatedClass()307 @Test public void annotatedClass() throws Exception { 308 ClassName someType = ClassName.get(tacosPackage, "SomeType"); 309 TypeSpec taco = TypeSpec.classBuilder("Foo") 310 .addAnnotation(AnnotationSpec.builder(ClassName.get(tacosPackage, "Something")) 311 .addMember("hi", "$T.$N", someType, "FIELD") 312 .addMember("hey", "$L", 12) 313 .addMember("hello", "$S", "goodbye") 314 .build()) 315 .addModifiers(Modifier.PUBLIC) 316 .build(); 317 assertThat(toString(taco)).isEqualTo("" 318 + "package com.squareup.tacos;\n" 319 + "\n" 320 + "@Something(\n" 321 + " hi = SomeType.FIELD,\n" 322 + " hey = 12,\n" 323 + " hello = \"goodbye\"\n" 324 + ")\n" 325 + "public class Foo {\n" 326 + "}\n"); 327 } 328 addAnnotationDisallowsNull()329 @Test public void addAnnotationDisallowsNull() { 330 try { 331 TypeSpec.classBuilder("Foo").addAnnotation((AnnotationSpec) null); 332 fail(); 333 } catch (NullPointerException expected) { 334 assertThat(expected).hasMessageThat().isEqualTo("annotationSpec == null"); 335 } 336 try { 337 TypeSpec.classBuilder("Foo").addAnnotation((ClassName) null); 338 fail(); 339 } catch (NullPointerException expected) { 340 assertThat(expected).hasMessageThat().isEqualTo("type == null"); 341 } 342 try { 343 TypeSpec.classBuilder("Foo").addAnnotation((Class<?>) null); 344 fail(); 345 } catch (NullPointerException expected) { 346 assertThat(expected).hasMessageThat().isEqualTo("clazz == null"); 347 } 348 } 349 enumWithSubclassing()350 @Test public void enumWithSubclassing() throws Exception { 351 TypeSpec roshambo = TypeSpec.enumBuilder("Roshambo") 352 .addModifiers(Modifier.PUBLIC) 353 .addEnumConstant("ROCK", TypeSpec.anonymousClassBuilder("") 354 .addJavadoc("Avalanche!\n") 355 .build()) 356 .addEnumConstant("PAPER", TypeSpec.anonymousClassBuilder("$S", "flat") 357 .addMethod(MethodSpec.methodBuilder("toString") 358 .addAnnotation(Override.class) 359 .addModifiers(Modifier.PUBLIC) 360 .returns(String.class) 361 .addCode("return $S;\n", "paper airplane!") 362 .build()) 363 .build()) 364 .addEnumConstant("SCISSORS", TypeSpec.anonymousClassBuilder("$S", "peace sign") 365 .build()) 366 .addField(String.class, "handPosition", Modifier.PRIVATE, Modifier.FINAL) 367 .addMethod(MethodSpec.constructorBuilder() 368 .addParameter(String.class, "handPosition") 369 .addCode("this.handPosition = handPosition;\n") 370 .build()) 371 .addMethod(MethodSpec.constructorBuilder() 372 .addCode("this($S);\n", "fist") 373 .build()) 374 .build(); 375 assertThat(toString(roshambo)).isEqualTo("" 376 + "package com.squareup.tacos;\n" 377 + "\n" 378 + "import java.lang.Override;\n" 379 + "import java.lang.String;\n" 380 + "\n" 381 + "public enum Roshambo {\n" 382 + " /**\n" 383 + " * Avalanche!\n" 384 + " */\n" 385 + " ROCK,\n" 386 + "\n" 387 + " PAPER(\"flat\") {\n" 388 + " @Override\n" 389 + " public String toString() {\n" 390 + " return \"paper airplane!\";\n" 391 + " }\n" 392 + " },\n" 393 + "\n" 394 + " SCISSORS(\"peace sign\");\n" 395 + "\n" 396 + " private final String handPosition;\n" 397 + "\n" 398 + " Roshambo(String handPosition) {\n" 399 + " this.handPosition = handPosition;\n" 400 + " }\n" 401 + "\n" 402 + " Roshambo() {\n" 403 + " this(\"fist\");\n" 404 + " }\n" 405 + "}\n"); 406 } 407 408 /** https://github.com/square/javapoet/issues/193 */ enumsMayDefineAbstractMethods()409 @Test public void enumsMayDefineAbstractMethods() throws Exception { 410 TypeSpec roshambo = TypeSpec.enumBuilder("Tortilla") 411 .addModifiers(Modifier.PUBLIC) 412 .addEnumConstant("CORN", TypeSpec.anonymousClassBuilder("") 413 .addMethod(MethodSpec.methodBuilder("fold") 414 .addAnnotation(Override.class) 415 .addModifiers(Modifier.PUBLIC) 416 .build()) 417 .build()) 418 .addMethod(MethodSpec.methodBuilder("fold") 419 .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) 420 .build()) 421 .build(); 422 assertThat(toString(roshambo)).isEqualTo("" 423 + "package com.squareup.tacos;\n" 424 + "\n" 425 + "import java.lang.Override;\n" 426 + "\n" 427 + "public enum Tortilla {\n" 428 + " CORN {\n" 429 + " @Override\n" 430 + " public void fold() {\n" 431 + " }\n" 432 + " };\n" 433 + "\n" 434 + " public abstract void fold();\n" 435 + "}\n"); 436 } 437 enumConstantsRequired()438 @Test public void enumConstantsRequired() throws Exception { 439 try { 440 TypeSpec.enumBuilder("Roshambo") 441 .build(); 442 fail(); 443 } catch (IllegalArgumentException expected) { 444 } 445 } 446 onlyEnumsMayHaveEnumConstants()447 @Test public void onlyEnumsMayHaveEnumConstants() throws Exception { 448 try { 449 TypeSpec.classBuilder("Roshambo") 450 .addEnumConstant("ROCK") 451 .build(); 452 fail(); 453 } catch (IllegalStateException expected) { 454 } 455 } 456 enumWithMembersButNoConstructorCall()457 @Test public void enumWithMembersButNoConstructorCall() throws Exception { 458 TypeSpec roshambo = TypeSpec.enumBuilder("Roshambo") 459 .addEnumConstant("SPOCK", TypeSpec.anonymousClassBuilder("") 460 .addMethod(MethodSpec.methodBuilder("toString") 461 .addAnnotation(Override.class) 462 .addModifiers(Modifier.PUBLIC) 463 .returns(String.class) 464 .addCode("return $S;\n", "west side") 465 .build()) 466 .build()) 467 .build(); 468 assertThat(toString(roshambo)).isEqualTo("" 469 + "package com.squareup.tacos;\n" 470 + "\n" 471 + "import java.lang.Override;\n" 472 + "import java.lang.String;\n" 473 + "\n" 474 + "enum Roshambo {\n" 475 + " SPOCK {\n" 476 + " @Override\n" 477 + " public String toString() {\n" 478 + " return \"west side\";\n" 479 + " }\n" 480 + " }\n" 481 + "}\n"); 482 } 483 484 /** https://github.com/square/javapoet/issues/253 */ enumWithAnnotatedValues()485 @Test public void enumWithAnnotatedValues() throws Exception { 486 TypeSpec roshambo = TypeSpec.enumBuilder("Roshambo") 487 .addModifiers(Modifier.PUBLIC) 488 .addEnumConstant("ROCK", TypeSpec.anonymousClassBuilder("") 489 .addAnnotation(Deprecated.class) 490 .build()) 491 .addEnumConstant("PAPER") 492 .addEnumConstant("SCISSORS") 493 .build(); 494 assertThat(toString(roshambo)).isEqualTo("" 495 + "package com.squareup.tacos;\n" 496 + "\n" 497 + "import java.lang.Deprecated;\n" 498 + "\n" 499 + "public enum Roshambo {\n" 500 + " @Deprecated\n" 501 + " ROCK,\n" 502 + "\n" 503 + " PAPER,\n" 504 + "\n" 505 + " SCISSORS\n" 506 + "}\n"); 507 } 508 methodThrows()509 @Test public void methodThrows() throws Exception { 510 TypeSpec taco = TypeSpec.classBuilder("Taco") 511 .addModifiers(Modifier.ABSTRACT) 512 .addMethod(MethodSpec.methodBuilder("throwOne") 513 .addException(IOException.class) 514 .build()) 515 .addMethod(MethodSpec.methodBuilder("throwTwo") 516 .addException(IOException.class) 517 .addException(ClassName.get(tacosPackage, "SourCreamException")) 518 .build()) 519 .addMethod(MethodSpec.methodBuilder("abstractThrow") 520 .addModifiers(Modifier.ABSTRACT) 521 .addException(IOException.class) 522 .build()) 523 .addMethod(MethodSpec.methodBuilder("nativeThrow") 524 .addModifiers(Modifier.NATIVE) 525 .addException(IOException.class) 526 .build()) 527 .build(); 528 assertThat(toString(taco)).isEqualTo("" 529 + "package com.squareup.tacos;\n" 530 + "\n" 531 + "import java.io.IOException;\n" 532 + "\n" 533 + "abstract class Taco {\n" 534 + " void throwOne() throws IOException {\n" 535 + " }\n" 536 + "\n" 537 + " void throwTwo() throws IOException, SourCreamException {\n" 538 + " }\n" 539 + "\n" 540 + " abstract void abstractThrow() throws IOException;\n" 541 + "\n" 542 + " native void nativeThrow() throws IOException;\n" 543 + "}\n"); 544 } 545 typeVariables()546 @Test public void typeVariables() throws Exception { 547 TypeVariableName t = TypeVariableName.get("T"); 548 TypeVariableName p = TypeVariableName.get("P", Number.class); 549 ClassName location = ClassName.get(tacosPackage, "Location"); 550 TypeSpec typeSpec = TypeSpec.classBuilder("Location") 551 .addTypeVariable(t) 552 .addTypeVariable(p) 553 .addSuperinterface(ParameterizedTypeName.get(ClassName.get(Comparable.class), p)) 554 .addField(t, "label") 555 .addField(p, "x") 556 .addField(p, "y") 557 .addMethod(MethodSpec.methodBuilder("compareTo") 558 .addAnnotation(Override.class) 559 .addModifiers(Modifier.PUBLIC) 560 .returns(int.class) 561 .addParameter(p, "p") 562 .addCode("return 0;\n") 563 .build()) 564 .addMethod(MethodSpec.methodBuilder("of") 565 .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 566 .addTypeVariable(t) 567 .addTypeVariable(p) 568 .returns(ParameterizedTypeName.get(location, t, p)) 569 .addParameter(t, "label") 570 .addParameter(p, "x") 571 .addParameter(p, "y") 572 .addCode("throw new $T($S);\n", UnsupportedOperationException.class, "TODO") 573 .build()) 574 .build(); 575 assertThat(toString(typeSpec)).isEqualTo("" 576 + "package com.squareup.tacos;\n" 577 + "\n" 578 + "import java.lang.Comparable;\n" 579 + "import java.lang.Number;\n" 580 + "import java.lang.Override;\n" 581 + "import java.lang.UnsupportedOperationException;\n" 582 + "\n" 583 + "class Location<T, P extends Number> implements Comparable<P> {\n" 584 + " T label;\n" 585 + "\n" 586 + " P x;\n" 587 + "\n" 588 + " P y;\n" 589 + "\n" 590 + " @Override\n" 591 + " public int compareTo(P p) {\n" 592 + " return 0;\n" 593 + " }\n" 594 + "\n" 595 + " public static <T, P extends Number> Location<T, P> of(T label, P x, P y) {\n" 596 + " throw new UnsupportedOperationException(\"TODO\");\n" 597 + " }\n" 598 + "}\n"); 599 } 600 typeVariableWithBounds()601 @Test public void typeVariableWithBounds() { 602 AnnotationSpec a = AnnotationSpec.builder(ClassName.get("com.squareup.tacos", "A")).build(); 603 TypeVariableName p = TypeVariableName.get("P", Number.class); 604 TypeVariableName q = (TypeVariableName) TypeVariableName.get("Q", Number.class).annotated(a); 605 TypeSpec typeSpec = TypeSpec.classBuilder("Location") 606 .addTypeVariable(p.withBounds(Comparable.class)) 607 .addTypeVariable(q.withBounds(Comparable.class)) 608 .addField(p, "x") 609 .addField(q, "y") 610 .build(); 611 assertThat(toString(typeSpec)).isEqualTo("" 612 + "package com.squareup.tacos;\n" 613 + "\n" 614 + "import java.lang.Comparable;\n" 615 + "import java.lang.Number;\n" 616 + "\n" 617 + "class Location<P extends Number & Comparable, @A Q extends Number & Comparable> {\n" 618 + " P x;\n" 619 + "\n" 620 + " @A Q y;\n" 621 + "}\n"); 622 } 623 classImplementsExtends()624 @Test public void classImplementsExtends() throws Exception { 625 ClassName taco = ClassName.get(tacosPackage, "Taco"); 626 ClassName food = ClassName.get("com.squareup.tacos", "Food"); 627 TypeSpec typeSpec = TypeSpec.classBuilder("Taco") 628 .addModifiers(Modifier.ABSTRACT) 629 .superclass(ParameterizedTypeName.get(ClassName.get(AbstractSet.class), food)) 630 .addSuperinterface(Serializable.class) 631 .addSuperinterface(ParameterizedTypeName.get(ClassName.get(Comparable.class), taco)) 632 .build(); 633 assertThat(toString(typeSpec)).isEqualTo("" 634 + "package com.squareup.tacos;\n" 635 + "\n" 636 + "import java.io.Serializable;\n" 637 + "import java.lang.Comparable;\n" 638 + "import java.util.AbstractSet;\n" 639 + "\n" 640 + "abstract class Taco extends AbstractSet<Food> " 641 + "implements Serializable, Comparable<Taco> {\n" 642 + "}\n"); 643 } 644 classImplementsNestedClass()645 @Test public void classImplementsNestedClass() throws Exception { 646 ClassName outer = ClassName.get(tacosPackage, "Outer"); 647 ClassName inner = outer.nestedClass("Inner"); 648 ClassName callable = ClassName.get(Callable.class); 649 TypeSpec typeSpec = TypeSpec.classBuilder("Outer") 650 .superclass(ParameterizedTypeName.get(callable, 651 inner)) 652 .addType(TypeSpec.classBuilder("Inner") 653 .addModifiers(Modifier.STATIC) 654 .build()) 655 .build(); 656 657 assertThat(toString(typeSpec)).isEqualTo("" 658 + "package com.squareup.tacos;\n" 659 + "\n" 660 + "import java.util.concurrent.Callable;\n" 661 + "\n" 662 + "class Outer extends Callable<Outer.Inner> {\n" 663 + " static class Inner {\n" 664 + " }\n" 665 + "}\n"); 666 } 667 enumImplements()668 @Test public void enumImplements() throws Exception { 669 TypeSpec typeSpec = TypeSpec.enumBuilder("Food") 670 .addSuperinterface(Serializable.class) 671 .addSuperinterface(Cloneable.class) 672 .addEnumConstant("LEAN_GROUND_BEEF") 673 .addEnumConstant("SHREDDED_CHEESE") 674 .build(); 675 assertThat(toString(typeSpec)).isEqualTo("" 676 + "package com.squareup.tacos;\n" 677 + "\n" 678 + "import java.io.Serializable;\n" 679 + "import java.lang.Cloneable;\n" 680 + "\n" 681 + "enum Food implements Serializable, Cloneable {\n" 682 + " LEAN_GROUND_BEEF,\n" 683 + "\n" 684 + " SHREDDED_CHEESE\n" 685 + "}\n"); 686 } 687 interfaceExtends()688 @Test public void interfaceExtends() throws Exception { 689 ClassName taco = ClassName.get(tacosPackage, "Taco"); 690 TypeSpec typeSpec = TypeSpec.interfaceBuilder("Taco") 691 .addSuperinterface(Serializable.class) 692 .addSuperinterface(ParameterizedTypeName.get(ClassName.get(Comparable.class), taco)) 693 .build(); 694 assertThat(toString(typeSpec)).isEqualTo("" 695 + "package com.squareup.tacos;\n" 696 + "\n" 697 + "import java.io.Serializable;\n" 698 + "import java.lang.Comparable;\n" 699 + "\n" 700 + "interface Taco extends Serializable, Comparable<Taco> {\n" 701 + "}\n"); 702 } 703 nestedClasses()704 @Test public void nestedClasses() throws Exception { 705 ClassName taco = ClassName.get(tacosPackage, "Combo", "Taco"); 706 ClassName topping = ClassName.get(tacosPackage, "Combo", "Taco", "Topping"); 707 ClassName chips = ClassName.get(tacosPackage, "Combo", "Chips"); 708 ClassName sauce = ClassName.get(tacosPackage, "Combo", "Sauce"); 709 TypeSpec typeSpec = TypeSpec.classBuilder("Combo") 710 .addField(taco, "taco") 711 .addField(chips, "chips") 712 .addType(TypeSpec.classBuilder(taco.simpleName()) 713 .addModifiers(Modifier.STATIC) 714 .addField(ParameterizedTypeName.get(ClassName.get(List.class), topping), "toppings") 715 .addField(sauce, "sauce") 716 .addType(TypeSpec.enumBuilder(topping.simpleName()) 717 .addEnumConstant("SHREDDED_CHEESE") 718 .addEnumConstant("LEAN_GROUND_BEEF") 719 .build()) 720 .build()) 721 .addType(TypeSpec.classBuilder(chips.simpleName()) 722 .addModifiers(Modifier.STATIC) 723 .addField(topping, "topping") 724 .addField(sauce, "dippingSauce") 725 .build()) 726 .addType(TypeSpec.enumBuilder(sauce.simpleName()) 727 .addEnumConstant("SOUR_CREAM") 728 .addEnumConstant("SALSA") 729 .addEnumConstant("QUESO") 730 .addEnumConstant("MILD") 731 .addEnumConstant("FIRE") 732 .build()) 733 .build(); 734 735 assertThat(toString(typeSpec)).isEqualTo("" 736 + "package com.squareup.tacos;\n" 737 + "\n" 738 + "import java.util.List;\n" 739 + "\n" 740 + "class Combo {\n" 741 + " Taco taco;\n" 742 + "\n" 743 + " Chips chips;\n" 744 + "\n" 745 + " static class Taco {\n" 746 + " List<Topping> toppings;\n" 747 + "\n" 748 + " Sauce sauce;\n" 749 + "\n" 750 + " enum Topping {\n" 751 + " SHREDDED_CHEESE,\n" 752 + "\n" 753 + " LEAN_GROUND_BEEF\n" 754 + " }\n" 755 + " }\n" 756 + "\n" 757 + " static class Chips {\n" 758 + " Taco.Topping topping;\n" 759 + "\n" 760 + " Sauce dippingSauce;\n" 761 + " }\n" 762 + "\n" 763 + " enum Sauce {\n" 764 + " SOUR_CREAM,\n" 765 + "\n" 766 + " SALSA,\n" 767 + "\n" 768 + " QUESO,\n" 769 + "\n" 770 + " MILD,\n" 771 + "\n" 772 + " FIRE\n" 773 + " }\n" 774 + "}\n"); 775 } 776 annotation()777 @Test public void annotation() throws Exception { 778 TypeSpec annotation = TypeSpec.annotationBuilder("MyAnnotation") 779 .addModifiers(Modifier.PUBLIC) 780 .addMethod(MethodSpec.methodBuilder("test") 781 .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) 782 .defaultValue("$L", 0) 783 .returns(int.class) 784 .build()) 785 .build(); 786 787 assertThat(toString(annotation)).isEqualTo("" 788 + "package com.squareup.tacos;\n" 789 + "\n" 790 + "public @interface MyAnnotation {\n" 791 + " int test() default 0;\n" 792 + "}\n" 793 ); 794 } 795 innerAnnotationInAnnotationDeclaration()796 @Test public void innerAnnotationInAnnotationDeclaration() throws Exception { 797 TypeSpec bar = TypeSpec.annotationBuilder("Bar") 798 .addMethod(MethodSpec.methodBuilder("value") 799 .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) 800 .defaultValue("@$T", Deprecated.class) 801 .returns(Deprecated.class) 802 .build()) 803 .build(); 804 805 assertThat(toString(bar)).isEqualTo("" 806 + "package com.squareup.tacos;\n" 807 + "\n" 808 + "import java.lang.Deprecated;\n" 809 + "\n" 810 + "@interface Bar {\n" 811 + " Deprecated value() default @Deprecated;\n" 812 + "}\n" 813 ); 814 } 815 annotationWithFields()816 @Test public void annotationWithFields() { 817 FieldSpec field = FieldSpec.builder(int.class, "FOO") 818 .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) 819 .initializer("$L", 101) 820 .build(); 821 822 TypeSpec anno = TypeSpec.annotationBuilder("Anno") 823 .addField(field) 824 .build(); 825 826 assertThat(toString(anno)).isEqualTo("" 827 + "package com.squareup.tacos;\n" 828 + "\n" 829 + "@interface Anno {\n" 830 + " int FOO = 101;\n" 831 + "}\n" 832 ); 833 } 834 835 @Test classCannotHaveDefaultValueForMethod()836 public void classCannotHaveDefaultValueForMethod() throws Exception { 837 try { 838 TypeSpec.classBuilder("Tacos") 839 .addMethod(MethodSpec.methodBuilder("test") 840 .addModifiers(Modifier.PUBLIC) 841 .defaultValue("0") 842 .returns(int.class) 843 .build()) 844 .build(); 845 fail(); 846 } catch (IllegalStateException expected) { 847 } 848 } 849 850 @Test classCannotHaveDefaultMethods()851 public void classCannotHaveDefaultMethods() throws Exception { 852 try { 853 TypeSpec.classBuilder("Tacos") 854 .addMethod(MethodSpec.methodBuilder("test") 855 .addModifiers(Modifier.PUBLIC, Modifier.DEFAULT) 856 .returns(int.class) 857 .addCode(CodeBlock.builder().addStatement("return 0").build()) 858 .build()) 859 .build(); 860 fail(); 861 } catch (IllegalStateException expected) { 862 } 863 } 864 865 @Test interfaceStaticMethods()866 public void interfaceStaticMethods() throws Exception { 867 TypeSpec bar = TypeSpec.interfaceBuilder("Tacos") 868 .addMethod(MethodSpec.methodBuilder("test") 869 .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 870 .returns(int.class) 871 .addCode(CodeBlock.builder().addStatement("return 0").build()) 872 .build()) 873 .build(); 874 875 assertThat(toString(bar)).isEqualTo("" 876 + "package com.squareup.tacos;\n" 877 + "\n" 878 + "interface Tacos {\n" 879 + " static int test() {\n" 880 + " return 0;\n" 881 + " }\n" 882 + "}\n" 883 ); 884 } 885 886 @Test interfaceDefaultMethods()887 public void interfaceDefaultMethods() throws Exception { 888 TypeSpec bar = TypeSpec.interfaceBuilder("Tacos") 889 .addMethod(MethodSpec.methodBuilder("test") 890 .addModifiers(Modifier.PUBLIC, Modifier.DEFAULT) 891 .returns(int.class) 892 .addCode(CodeBlock.builder().addStatement("return 0").build()) 893 .build()) 894 .build(); 895 896 assertThat(toString(bar)).isEqualTo("" 897 + "package com.squareup.tacos;\n" 898 + "\n" 899 + "interface Tacos {\n" 900 + " default int test() {\n" 901 + " return 0;\n" 902 + " }\n" 903 + "}\n" 904 ); 905 } 906 referencedAndDeclaredSimpleNamesConflict()907 @Test public void referencedAndDeclaredSimpleNamesConflict() throws Exception { 908 FieldSpec internalTop = FieldSpec.builder( 909 ClassName.get(tacosPackage, "Top"), "internalTop").build(); 910 FieldSpec internalBottom = FieldSpec.builder( 911 ClassName.get(tacosPackage, "Top", "Middle", "Bottom"), "internalBottom").build(); 912 FieldSpec externalTop = FieldSpec.builder( 913 ClassName.get(donutsPackage, "Top"), "externalTop").build(); 914 FieldSpec externalBottom = FieldSpec.builder( 915 ClassName.get(donutsPackage, "Bottom"), "externalBottom").build(); 916 TypeSpec top = TypeSpec.classBuilder("Top") 917 .addField(internalTop) 918 .addField(internalBottom) 919 .addField(externalTop) 920 .addField(externalBottom) 921 .addType(TypeSpec.classBuilder("Middle") 922 .addField(internalTop) 923 .addField(internalBottom) 924 .addField(externalTop) 925 .addField(externalBottom) 926 .addType(TypeSpec.classBuilder("Bottom") 927 .addField(internalTop) 928 .addField(internalBottom) 929 .addField(externalTop) 930 .addField(externalBottom) 931 .build()) 932 .build()) 933 .build(); 934 assertThat(toString(top)).isEqualTo("" 935 + "package com.squareup.tacos;\n" 936 + "\n" 937 + "import com.squareup.donuts.Bottom;\n" 938 + "\n" 939 + "class Top {\n" 940 + " Top internalTop;\n" 941 + "\n" 942 + " Middle.Bottom internalBottom;\n" 943 + "\n" 944 + " com.squareup.donuts.Top externalTop;\n" 945 + "\n" 946 + " Bottom externalBottom;\n" 947 + "\n" 948 + " class Middle {\n" 949 + " Top internalTop;\n" 950 + "\n" 951 + " Bottom internalBottom;\n" 952 + "\n" 953 + " com.squareup.donuts.Top externalTop;\n" 954 + "\n" 955 + " com.squareup.donuts.Bottom externalBottom;\n" 956 + "\n" 957 + " class Bottom {\n" 958 + " Top internalTop;\n" 959 + "\n" 960 + " Bottom internalBottom;\n" 961 + "\n" 962 + " com.squareup.donuts.Top externalTop;\n" 963 + "\n" 964 + " com.squareup.donuts.Bottom externalBottom;\n" 965 + " }\n" 966 + " }\n" 967 + "}\n"); 968 } 969 simpleNamesConflictInThisAndOtherPackage()970 @Test public void simpleNamesConflictInThisAndOtherPackage() throws Exception { 971 FieldSpec internalOther = FieldSpec.builder( 972 ClassName.get(tacosPackage, "Other"), "internalOther").build(); 973 FieldSpec externalOther = FieldSpec.builder( 974 ClassName.get(donutsPackage, "Other"), "externalOther").build(); 975 TypeSpec gen = TypeSpec.classBuilder("Gen") 976 .addField(internalOther) 977 .addField(externalOther) 978 .build(); 979 assertThat(toString(gen)).isEqualTo("" 980 + "package com.squareup.tacos;\n" 981 + "\n" 982 + "class Gen {\n" 983 + " Other internalOther;\n" 984 + "\n" 985 + " com.squareup.donuts.Other externalOther;\n" 986 + "}\n"); 987 } 988 simpleNameConflictsWithTypeVariable()989 @Test public void simpleNameConflictsWithTypeVariable() { 990 ClassName inPackage = ClassName.get("com.squareup.tacos", "InPackage"); 991 ClassName otherType = ClassName.get("com.other", "OtherType"); 992 ClassName methodInPackage = ClassName.get("com.squareup.tacos", "MethodInPackage"); 993 ClassName methodOtherType = ClassName.get("com.other", "MethodOtherType"); 994 TypeSpec gen = TypeSpec.classBuilder("Gen") 995 .addTypeVariable(TypeVariableName.get("InPackage")) 996 .addTypeVariable(TypeVariableName.get("OtherType")) 997 .addField(FieldSpec.builder(inPackage, "inPackage").build()) 998 .addField(FieldSpec.builder(otherType, "otherType").build()) 999 .addMethod(MethodSpec.methodBuilder("withTypeVariables") 1000 .addTypeVariable(TypeVariableName.get("MethodInPackage")) 1001 .addTypeVariable(TypeVariableName.get("MethodOtherType")) 1002 .addStatement("$T inPackage = null", methodInPackage) 1003 .addStatement("$T otherType = null", methodOtherType) 1004 .build()) 1005 .addMethod(MethodSpec.methodBuilder("withoutTypeVariables") 1006 .addStatement("$T inPackage = null", methodInPackage) 1007 .addStatement("$T otherType = null", methodOtherType) 1008 .build()) 1009 .addMethod(MethodSpec.methodBuilder("againWithTypeVariables") 1010 .addTypeVariable(TypeVariableName.get("MethodInPackage")) 1011 .addTypeVariable(TypeVariableName.get("MethodOtherType")) 1012 .addStatement("$T inPackage = null", methodInPackage) 1013 .addStatement("$T otherType = null", methodOtherType) 1014 .build()) 1015 // https://github.com/square/javapoet/pull/657#discussion_r205514292 1016 .addMethod(MethodSpec.methodBuilder("masksEnclosingTypeVariable") 1017 .addTypeVariable(TypeVariableName.get("InPackage")) 1018 .build()) 1019 .addMethod(MethodSpec.methodBuilder("hasSimpleNameThatWasPreviouslyMasked") 1020 .addStatement("$T inPackage = null", inPackage) 1021 .build()) 1022 .build(); 1023 assertThat(toString(gen)).isEqualTo("" 1024 + "package com.squareup.tacos;\n" 1025 + "\n" 1026 + "import com.other.MethodOtherType;\n" 1027 + "\n" 1028 + "class Gen<InPackage, OtherType> {\n" 1029 + " com.squareup.tacos.InPackage inPackage;\n" 1030 + "\n" 1031 + " com.other.OtherType otherType;\n" 1032 + "\n" 1033 + " <MethodInPackage, MethodOtherType> void withTypeVariables() {\n" 1034 + " com.squareup.tacos.MethodInPackage inPackage = null;\n" 1035 + " com.other.MethodOtherType otherType = null;\n" 1036 + " }\n" 1037 + "\n" 1038 + " void withoutTypeVariables() {\n" 1039 + " MethodInPackage inPackage = null;\n" 1040 + " MethodOtherType otherType = null;\n" 1041 + " }\n" 1042 + "\n" 1043 + " <MethodInPackage, MethodOtherType> void againWithTypeVariables() {\n" 1044 + " com.squareup.tacos.MethodInPackage inPackage = null;\n" 1045 + " com.other.MethodOtherType otherType = null;\n" 1046 + " }\n" 1047 + "\n" 1048 + " <InPackage> void masksEnclosingTypeVariable() {\n" 1049 + " }\n" 1050 + "\n" 1051 + " void hasSimpleNameThatWasPreviouslyMasked() {\n" 1052 + " com.squareup.tacos.InPackage inPackage = null;\n" 1053 + " }\n" 1054 + "}\n"); 1055 } 1056 originatingElementsIncludesThoseOfNestedTypes()1057 @Test public void originatingElementsIncludesThoseOfNestedTypes() { 1058 Element outerElement = Mockito.mock(Element.class); 1059 Element innerElement = Mockito.mock(Element.class); 1060 TypeSpec outer = TypeSpec.classBuilder("Outer") 1061 .addOriginatingElement(outerElement) 1062 .addType(TypeSpec.classBuilder("Inner") 1063 .addOriginatingElement(innerElement) 1064 .build()) 1065 .build(); 1066 assertThat(outer.originatingElements).containsExactly(outerElement, innerElement); 1067 } 1068 intersectionType()1069 @Test public void intersectionType() { 1070 TypeVariableName typeVariable = TypeVariableName.get("T", Comparator.class, Serializable.class); 1071 TypeSpec taco = TypeSpec.classBuilder("Taco") 1072 .addMethod(MethodSpec.methodBuilder("getComparator") 1073 .addTypeVariable(typeVariable) 1074 .returns(typeVariable) 1075 .addCode("return null;\n") 1076 .build()) 1077 .build(); 1078 assertThat(toString(taco)).isEqualTo("" 1079 + "package com.squareup.tacos;\n" 1080 + "\n" 1081 + "import java.io.Serializable;\n" 1082 + "import java.util.Comparator;\n" 1083 + "\n" 1084 + "class Taco {\n" 1085 + " <T extends Comparator & Serializable> T getComparator() {\n" 1086 + " return null;\n" 1087 + " }\n" 1088 + "}\n"); 1089 } 1090 arrayType()1091 @Test public void arrayType() { 1092 TypeSpec taco = TypeSpec.classBuilder("Taco") 1093 .addField(int[].class, "ints") 1094 .build(); 1095 assertThat(toString(taco)).isEqualTo("" 1096 + "package com.squareup.tacos;\n" 1097 + "\n" 1098 + "class Taco {\n" 1099 + " int[] ints;\n" 1100 + "}\n"); 1101 } 1102 javadoc()1103 @Test public void javadoc() { 1104 TypeSpec taco = TypeSpec.classBuilder("Taco") 1105 .addJavadoc("A hard or soft tortilla, loosely folded and filled with whatever {@link \n") 1106 .addJavadoc("{@link $T random} tex-mex stuff we could find in the pantry\n", Random.class) 1107 .addJavadoc(CodeBlock.of("and some {@link $T} cheese.\n", String.class)) 1108 .addField(FieldSpec.builder(boolean.class, "soft") 1109 .addJavadoc("True for a soft flour tortilla; false for a crunchy corn tortilla.\n") 1110 .build()) 1111 .addMethod(MethodSpec.methodBuilder("refold") 1112 .addJavadoc("Folds the back of this taco to reduce sauce leakage.\n" 1113 + "\n" 1114 + "<p>For {@link $T#KOREAN}, the front may also be folded.\n", Locale.class) 1115 .addParameter(Locale.class, "locale") 1116 .build()) 1117 .build(); 1118 // Mentioning a type in Javadoc will not cause an import to be added (java.util.Random here), 1119 // but the short name will be used if it's already imported (java.util.Locale here). 1120 assertThat(toString(taco)).isEqualTo("" 1121 + "package com.squareup.tacos;\n" 1122 + "\n" 1123 + "import java.util.Locale;\n" 1124 + "\n" 1125 + "/**\n" 1126 + " * A hard or soft tortilla, loosely folded and filled with whatever {@link \n" 1127 + " * {@link java.util.Random random} tex-mex stuff we could find in the pantry\n" 1128 + " * and some {@link java.lang.String} cheese.\n" 1129 + " */\n" 1130 + "class Taco {\n" 1131 + " /**\n" 1132 + " * True for a soft flour tortilla; false for a crunchy corn tortilla.\n" 1133 + " */\n" 1134 + " boolean soft;\n" 1135 + "\n" 1136 + " /**\n" 1137 + " * Folds the back of this taco to reduce sauce leakage.\n" 1138 + " *\n" 1139 + " * <p>For {@link Locale#KOREAN}, the front may also be folded.\n" 1140 + " */\n" 1141 + " void refold(Locale locale) {\n" 1142 + " }\n" 1143 + "}\n"); 1144 } 1145 annotationsInAnnotations()1146 @Test public void annotationsInAnnotations() throws Exception { 1147 ClassName beef = ClassName.get(tacosPackage, "Beef"); 1148 ClassName chicken = ClassName.get(tacosPackage, "Chicken"); 1149 ClassName option = ClassName.get(tacosPackage, "Option"); 1150 ClassName mealDeal = ClassName.get(tacosPackage, "MealDeal"); 1151 TypeSpec menu = TypeSpec.classBuilder("Menu") 1152 .addAnnotation(AnnotationSpec.builder(mealDeal) 1153 .addMember("price", "$L", 500) 1154 .addMember("options", "$L", AnnotationSpec.builder(option) 1155 .addMember("name", "$S", "taco") 1156 .addMember("meat", "$T.class", beef) 1157 .build()) 1158 .addMember("options", "$L", AnnotationSpec.builder(option) 1159 .addMember("name", "$S", "quesadilla") 1160 .addMember("meat", "$T.class", chicken) 1161 .build()) 1162 .build()) 1163 .build(); 1164 assertThat(toString(menu)).isEqualTo("" 1165 + "package com.squareup.tacos;\n" 1166 + "\n" 1167 + "@MealDeal(\n" 1168 + " price = 500,\n" 1169 + " options = {\n" 1170 + " @Option(name = \"taco\", meat = Beef.class),\n" 1171 + " @Option(name = \"quesadilla\", meat = Chicken.class)\n" 1172 + " }\n" 1173 + ")\n" 1174 + "class Menu {\n" 1175 + "}\n"); 1176 } 1177 varargs()1178 @Test public void varargs() throws Exception { 1179 TypeSpec taqueria = TypeSpec.classBuilder("Taqueria") 1180 .addMethod(MethodSpec.methodBuilder("prepare") 1181 .addParameter(int.class, "workers") 1182 .addParameter(Runnable[].class, "jobs") 1183 .varargs() 1184 .build()) 1185 .build(); 1186 assertThat(toString(taqueria)).isEqualTo("" 1187 + "package com.squareup.tacos;\n" 1188 + "\n" 1189 + "import java.lang.Runnable;\n" 1190 + "\n" 1191 + "class Taqueria {\n" 1192 + " void prepare(int workers, Runnable... jobs) {\n" 1193 + " }\n" 1194 + "}\n"); 1195 } 1196 codeBlocks()1197 @Test public void codeBlocks() throws Exception { 1198 CodeBlock ifBlock = CodeBlock.builder() 1199 .beginControlFlow("if (!a.equals(b))") 1200 .addStatement("return i") 1201 .endControlFlow() 1202 .build(); 1203 CodeBlock methodBody = CodeBlock.builder() 1204 .addStatement("$T size = $T.min(listA.size(), listB.size())", int.class, Math.class) 1205 .beginControlFlow("for ($T i = 0; i < size; i++)", int.class) 1206 .addStatement("$T $N = $N.get(i)", String.class, "a", "listA") 1207 .addStatement("$T $N = $N.get(i)", String.class, "b", "listB") 1208 .add("$L", ifBlock) 1209 .endControlFlow() 1210 .addStatement("return size") 1211 .build(); 1212 CodeBlock fieldBlock = CodeBlock.builder() 1213 .add("$>$>") 1214 .add("\n$T.<$T, $T>builder()$>$>", ImmutableMap.class, String.class, String.class) 1215 .add("\n.add($S, $S)", '\'', "'") 1216 .add("\n.add($S, $S)", '&', "&") 1217 .add("\n.add($S, $S)", '<', "<") 1218 .add("\n.add($S, $S)", '>', ">") 1219 .add("\n.build()$<$<") 1220 .add("$<$<") 1221 .build(); 1222 FieldSpec escapeHtml = FieldSpec.builder(ParameterizedTypeName.get( 1223 Map.class, String.class, String.class), "ESCAPE_HTML") 1224 .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) 1225 .initializer(fieldBlock) 1226 .build(); 1227 TypeSpec util = TypeSpec.classBuilder("Util") 1228 .addField(escapeHtml) 1229 .addMethod(MethodSpec.methodBuilder("commonPrefixLength") 1230 .returns(int.class) 1231 .addParameter(ParameterizedTypeName.get(List.class, String.class), "listA") 1232 .addParameter(ParameterizedTypeName.get(List.class, String.class), "listB") 1233 .addCode(methodBody) 1234 .build()) 1235 .build(); 1236 assertThat(toString(util)).isEqualTo("" 1237 + "package com.squareup.tacos;\n" 1238 + "\n" 1239 + "import com.google.common.collect.ImmutableMap;\n" 1240 + "import java.lang.Math;\n" 1241 + "import java.lang.String;\n" 1242 + "import java.util.List;\n" 1243 + "import java.util.Map;\n" 1244 + "\n" 1245 + "class Util {\n" 1246 + " private static final Map<String, String> ESCAPE_HTML = \n" 1247 + " ImmutableMap.<String, String>builder()\n" 1248 + " .add(\"\'\", \"'\")\n" 1249 + " .add(\"&\", \"&\")\n" 1250 + " .add(\"<\", \"<\")\n" 1251 + " .add(\">\", \">\")\n" 1252 + " .build();\n" 1253 + "\n" 1254 + " int commonPrefixLength(List<String> listA, List<String> listB) {\n" 1255 + " int size = Math.min(listA.size(), listB.size());\n" 1256 + " for (int i = 0; i < size; i++) {\n" 1257 + " String a = listA.get(i);\n" 1258 + " String b = listB.get(i);\n" 1259 + " if (!a.equals(b)) {\n" 1260 + " return i;\n" 1261 + " }\n" 1262 + " }\n" 1263 + " return size;\n" 1264 + " }\n" 1265 + "}\n"); 1266 } 1267 indexedElseIf()1268 @Test public void indexedElseIf() throws Exception { 1269 TypeSpec taco = TypeSpec.classBuilder("Taco") 1270 .addMethod(MethodSpec.methodBuilder("choices") 1271 .beginControlFlow("if ($1L != null || $1L == $2L)", "taco", "otherTaco") 1272 .addStatement("$T.out.println($S)", System.class, "only one taco? NOO!") 1273 .nextControlFlow("else if ($1L.$3L && $2L.$3L)", "taco", "otherTaco", "isSupreme()") 1274 .addStatement("$T.out.println($S)", System.class, "taco heaven") 1275 .endControlFlow() 1276 .build()) 1277 .build(); 1278 assertThat(toString(taco)).isEqualTo("" 1279 + "package com.squareup.tacos;\n" 1280 + "\n" 1281 + "import java.lang.System;\n" 1282 + "\n" 1283 + "class Taco {\n" 1284 + " void choices() {\n" 1285 + " if (taco != null || taco == otherTaco) {\n" 1286 + " System.out.println(\"only one taco? NOO!\");\n" 1287 + " } else if (taco.isSupreme() && otherTaco.isSupreme()) {\n" 1288 + " System.out.println(\"taco heaven\");\n" 1289 + " }\n" 1290 + " }\n" 1291 + "}\n"); 1292 } 1293 elseIf()1294 @Test public void elseIf() throws Exception { 1295 TypeSpec taco = TypeSpec.classBuilder("Taco") 1296 .addMethod(MethodSpec.methodBuilder("choices") 1297 .beginControlFlow("if (5 < 4) ") 1298 .addStatement("$T.out.println($S)", System.class, "wat") 1299 .nextControlFlow("else if (5 < 6)") 1300 .addStatement("$T.out.println($S)", System.class, "hello") 1301 .endControlFlow() 1302 .build()) 1303 .build(); 1304 assertThat(toString(taco)).isEqualTo("" 1305 + "package com.squareup.tacos;\n" 1306 + "\n" 1307 + "import java.lang.System;\n" 1308 + "\n" 1309 + "class Taco {\n" 1310 + " void choices() {\n" 1311 + " if (5 < 4) {\n" 1312 + " System.out.println(\"wat\");\n" 1313 + " } else if (5 < 6) {\n" 1314 + " System.out.println(\"hello\");\n" 1315 + " }\n" 1316 + " }\n" 1317 + "}\n"); 1318 } 1319 doWhile()1320 @Test public void doWhile() throws Exception { 1321 TypeSpec taco = TypeSpec.classBuilder("Taco") 1322 .addMethod(MethodSpec.methodBuilder("loopForever") 1323 .beginControlFlow("do") 1324 .addStatement("$T.out.println($S)", System.class, "hello") 1325 .endControlFlow("while (5 < 6)") 1326 .build()) 1327 .build(); 1328 assertThat(toString(taco)).isEqualTo("" 1329 + "package com.squareup.tacos;\n" 1330 + "\n" 1331 + "import java.lang.System;\n" 1332 + "\n" 1333 + "class Taco {\n" 1334 + " void loopForever() {\n" 1335 + " do {\n" 1336 + " System.out.println(\"hello\");\n" 1337 + " } while (5 < 6);\n" 1338 + " }\n" 1339 + "}\n"); 1340 } 1341 inlineIndent()1342 @Test public void inlineIndent() throws Exception { 1343 TypeSpec taco = TypeSpec.classBuilder("Taco") 1344 .addMethod(MethodSpec.methodBuilder("inlineIndent") 1345 .addCode("if (3 < 4) {\n$>$T.out.println($S);\n$<}\n", System.class, "hello") 1346 .build()) 1347 .build(); 1348 assertThat(toString(taco)).isEqualTo("" 1349 + "package com.squareup.tacos;\n" 1350 + "\n" 1351 + "import java.lang.System;\n" 1352 + "\n" 1353 + "class Taco {\n" 1354 + " void inlineIndent() {\n" 1355 + " if (3 < 4) {\n" 1356 + " System.out.println(\"hello\");\n" 1357 + " }\n" 1358 + " }\n" 1359 + "}\n"); 1360 } 1361 defaultModifiersForInterfaceMembers()1362 @Test public void defaultModifiersForInterfaceMembers() throws Exception { 1363 TypeSpec taco = TypeSpec.interfaceBuilder("Taco") 1364 .addField(FieldSpec.builder(String.class, "SHELL") 1365 .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) 1366 .initializer("$S", "crunchy corn") 1367 .build()) 1368 .addMethod(MethodSpec.methodBuilder("fold") 1369 .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) 1370 .build()) 1371 .addType(TypeSpec.classBuilder("Topping") 1372 .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 1373 .build()) 1374 .build(); 1375 assertThat(toString(taco)).isEqualTo("" 1376 + "package com.squareup.tacos;\n" 1377 + "\n" 1378 + "import java.lang.String;\n" 1379 + "\n" 1380 + "interface Taco {\n" 1381 + " String SHELL = \"crunchy corn\";\n" 1382 + "\n" 1383 + " void fold();\n" 1384 + "\n" 1385 + " class Topping {\n" 1386 + " }\n" 1387 + "}\n"); 1388 } 1389 defaultModifiersForMemberInterfacesAndEnums()1390 @Test public void defaultModifiersForMemberInterfacesAndEnums() throws Exception { 1391 TypeSpec taco = TypeSpec.classBuilder("Taco") 1392 .addType(TypeSpec.classBuilder("Meat") 1393 .addModifiers(Modifier.STATIC) 1394 .build()) 1395 .addType(TypeSpec.interfaceBuilder("Tortilla") 1396 .addModifiers(Modifier.STATIC) 1397 .build()) 1398 .addType(TypeSpec.enumBuilder("Topping") 1399 .addModifiers(Modifier.STATIC) 1400 .addEnumConstant("SALSA") 1401 .build()) 1402 .build(); 1403 assertThat(toString(taco)).isEqualTo("" 1404 + "package com.squareup.tacos;\n" 1405 + "\n" 1406 + "class Taco {\n" 1407 + " static class Meat {\n" 1408 + " }\n" 1409 + "\n" 1410 + " interface Tortilla {\n" 1411 + " }\n" 1412 + "\n" 1413 + " enum Topping {\n" 1414 + " SALSA\n" 1415 + " }\n" 1416 + "}\n"); 1417 } 1418 membersOrdering()1419 @Test public void membersOrdering() throws Exception { 1420 // Hand out names in reverse-alphabetical order to defend against unexpected sorting. 1421 TypeSpec taco = TypeSpec.classBuilder("Members") 1422 .addType(TypeSpec.classBuilder("Z").build()) 1423 .addType(TypeSpec.classBuilder("Y").build()) 1424 .addField(String.class, "X", Modifier.STATIC) 1425 .addField(String.class, "W") 1426 .addField(String.class, "V", Modifier.STATIC) 1427 .addField(String.class, "U") 1428 .addMethod(MethodSpec.methodBuilder("T").addModifiers(Modifier.STATIC).build()) 1429 .addMethod(MethodSpec.methodBuilder("S").build()) 1430 .addMethod(MethodSpec.methodBuilder("R").addModifiers(Modifier.STATIC).build()) 1431 .addMethod(MethodSpec.methodBuilder("Q").build()) 1432 .addMethod(MethodSpec.constructorBuilder().addParameter(int.class, "p").build()) 1433 .addMethod(MethodSpec.constructorBuilder().addParameter(long.class, "o").build()) 1434 .build(); 1435 // Static fields, instance fields, constructors, methods, classes. 1436 assertThat(toString(taco)).isEqualTo("" 1437 + "package com.squareup.tacos;\n" 1438 + "\n" 1439 + "import java.lang.String;\n" 1440 + "\n" 1441 + "class Members {\n" 1442 + " static String X;\n" 1443 + "\n" 1444 + " static String V;\n" 1445 + "\n" 1446 + " String W;\n" 1447 + "\n" 1448 + " String U;\n" 1449 + "\n" 1450 + " Members(int p) {\n" 1451 + " }\n" 1452 + "\n" 1453 + " Members(long o) {\n" 1454 + " }\n" 1455 + "\n" 1456 + " static void T() {\n" 1457 + " }\n" 1458 + "\n" 1459 + " void S() {\n" 1460 + " }\n" 1461 + "\n" 1462 + " static void R() {\n" 1463 + " }\n" 1464 + "\n" 1465 + " void Q() {\n" 1466 + " }\n" 1467 + "\n" 1468 + " class Z {\n" 1469 + " }\n" 1470 + "\n" 1471 + " class Y {\n" 1472 + " }\n" 1473 + "}\n"); 1474 } 1475 nativeMethods()1476 @Test public void nativeMethods() throws Exception { 1477 TypeSpec taco = TypeSpec.classBuilder("Taco") 1478 .addMethod(MethodSpec.methodBuilder("nativeInt") 1479 .addModifiers(Modifier.NATIVE) 1480 .returns(int.class) 1481 .build()) 1482 // GWT JSNI 1483 .addMethod(MethodSpec.methodBuilder("alert") 1484 .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.NATIVE) 1485 .addParameter(String.class, "msg") 1486 .addCode(CodeBlock.builder() 1487 .add(" /*-{\n") 1488 .indent() 1489 .addStatement("$$wnd.alert(msg)") 1490 .unindent() 1491 .add("}-*/") 1492 .build()) 1493 .build()) 1494 .build(); 1495 assertThat(toString(taco)).isEqualTo("" 1496 + "package com.squareup.tacos;\n" 1497 + "\n" 1498 + "import java.lang.String;\n" 1499 + "\n" 1500 + "class Taco {\n" 1501 + " native int nativeInt();\n" 1502 + "\n" 1503 + " public static native void alert(String msg) /*-{\n" 1504 + " $wnd.alert(msg);\n" 1505 + " }-*/;\n" 1506 + "}\n"); 1507 } 1508 nullStringLiteral()1509 @Test public void nullStringLiteral() throws Exception { 1510 TypeSpec taco = TypeSpec.classBuilder("Taco") 1511 .addField(FieldSpec.builder(String.class, "NULL") 1512 .initializer("$S", (Object) null) 1513 .build()) 1514 .build(); 1515 assertThat(toString(taco)).isEqualTo("" 1516 + "package com.squareup.tacos;\n" 1517 + "\n" 1518 + "import java.lang.String;\n" 1519 + "\n" 1520 + "class Taco {\n" 1521 + " String NULL = null;\n" 1522 + "}\n"); 1523 } 1524 annotationToString()1525 @Test public void annotationToString() throws Exception { 1526 AnnotationSpec annotation = AnnotationSpec.builder(SuppressWarnings.class) 1527 .addMember("value", "$S", "unused") 1528 .build(); 1529 assertThat(annotation.toString()).isEqualTo("@java.lang.SuppressWarnings(\"unused\")"); 1530 } 1531 codeBlockToString()1532 @Test public void codeBlockToString() throws Exception { 1533 CodeBlock codeBlock = CodeBlock.builder() 1534 .addStatement("$T $N = $S.substring(0, 3)", String.class, "s", "taco") 1535 .build(); 1536 assertThat(codeBlock.toString()).isEqualTo("java.lang.String s = \"taco\".substring(0, 3);\n"); 1537 } 1538 codeBlockAddStatementOfCodeBlockToString()1539 @Test public void codeBlockAddStatementOfCodeBlockToString() throws Exception { 1540 CodeBlock contents = CodeBlock.of("$T $N = $S.substring(0, 3)", String.class, "s", "taco"); 1541 CodeBlock statement = CodeBlock.builder().addStatement(contents).build(); 1542 assertThat(statement.toString()).isEqualTo("java.lang.String s = \"taco\".substring(0, 3);\n"); 1543 } 1544 fieldToString()1545 @Test public void fieldToString() throws Exception { 1546 FieldSpec field = FieldSpec.builder(String.class, "s", Modifier.FINAL) 1547 .initializer("$S.substring(0, 3)", "taco") 1548 .build(); 1549 assertThat(field.toString()) 1550 .isEqualTo("final java.lang.String s = \"taco\".substring(0, 3);\n"); 1551 } 1552 methodToString()1553 @Test public void methodToString() throws Exception { 1554 MethodSpec method = MethodSpec.methodBuilder("toString") 1555 .addAnnotation(Override.class) 1556 .addModifiers(Modifier.PUBLIC) 1557 .returns(String.class) 1558 .addStatement("return $S", "taco") 1559 .build(); 1560 assertThat(method.toString()).isEqualTo("" 1561 + "@java.lang.Override\n" 1562 + "public java.lang.String toString() {\n" 1563 + " return \"taco\";\n" 1564 + "}\n"); 1565 } 1566 constructorToString()1567 @Test public void constructorToString() throws Exception { 1568 MethodSpec constructor = MethodSpec.constructorBuilder() 1569 .addModifiers(Modifier.PUBLIC) 1570 .addParameter(ClassName.get(tacosPackage, "Taco"), "taco") 1571 .addStatement("this.$N = $N", "taco", "taco") 1572 .build(); 1573 assertThat(constructor.toString()).isEqualTo("" 1574 + "public Constructor(com.squareup.tacos.Taco taco) {\n" 1575 + " this.taco = taco;\n" 1576 + "}\n"); 1577 } 1578 parameterToString()1579 @Test public void parameterToString() throws Exception { 1580 ParameterSpec parameter = ParameterSpec.builder(ClassName.get(tacosPackage, "Taco"), "taco") 1581 .addModifiers(Modifier.FINAL) 1582 .addAnnotation(ClassName.get("javax.annotation", "Nullable")) 1583 .build(); 1584 assertThat(parameter.toString()) 1585 .isEqualTo("@javax.annotation.Nullable final com.squareup.tacos.Taco taco"); 1586 } 1587 classToString()1588 @Test public void classToString() throws Exception { 1589 TypeSpec type = TypeSpec.classBuilder("Taco") 1590 .build(); 1591 assertThat(type.toString()).isEqualTo("" 1592 + "class Taco {\n" 1593 + "}\n"); 1594 } 1595 anonymousClassToString()1596 @Test public void anonymousClassToString() throws Exception { 1597 TypeSpec type = TypeSpec.anonymousClassBuilder("") 1598 .addSuperinterface(Runnable.class) 1599 .addMethod(MethodSpec.methodBuilder("run") 1600 .addAnnotation(Override.class) 1601 .addModifiers(Modifier.PUBLIC) 1602 .build()) 1603 .build(); 1604 assertThat(type.toString()).isEqualTo("" 1605 + "new java.lang.Runnable() {\n" 1606 + " @java.lang.Override\n" 1607 + " public void run() {\n" 1608 + " }\n" 1609 + "}"); 1610 } 1611 interfaceClassToString()1612 @Test public void interfaceClassToString() throws Exception { 1613 TypeSpec type = TypeSpec.interfaceBuilder("Taco") 1614 .build(); 1615 assertThat(type.toString()).isEqualTo("" 1616 + "interface Taco {\n" 1617 + "}\n"); 1618 } 1619 annotationDeclarationToString()1620 @Test public void annotationDeclarationToString() throws Exception { 1621 TypeSpec type = TypeSpec.annotationBuilder("Taco") 1622 .build(); 1623 assertThat(type.toString()).isEqualTo("" 1624 + "@interface Taco {\n" 1625 + "}\n"); 1626 } 1627 toString(TypeSpec typeSpec)1628 private String toString(TypeSpec typeSpec) { 1629 return JavaFile.builder(tacosPackage, typeSpec).build().toString(); 1630 } 1631 multilineStatement()1632 @Test public void multilineStatement() throws Exception { 1633 TypeSpec taco = TypeSpec.classBuilder("Taco") 1634 .addMethod(MethodSpec.methodBuilder("toString") 1635 .addAnnotation(Override.class) 1636 .addModifiers(Modifier.PUBLIC) 1637 .returns(String.class) 1638 .addStatement("return $S\n+ $S\n+ $S\n+ $S\n+ $S", 1639 "Taco(", "beef,", "lettuce,", "cheese", ")") 1640 .build()) 1641 .build(); 1642 assertThat(toString(taco)).isEqualTo("" 1643 + "package com.squareup.tacos;\n" 1644 + "\n" 1645 + "import java.lang.Override;\n" 1646 + "import java.lang.String;\n" 1647 + "\n" 1648 + "class Taco {\n" 1649 + " @Override\n" 1650 + " public String toString() {\n" 1651 + " return \"Taco(\"\n" 1652 + " + \"beef,\"\n" 1653 + " + \"lettuce,\"\n" 1654 + " + \"cheese\"\n" 1655 + " + \")\";\n" 1656 + " }\n" 1657 + "}\n"); 1658 } 1659 multilineStatementWithAnonymousClass()1660 @Test public void multilineStatementWithAnonymousClass() throws Exception { 1661 TypeName stringComparator = ParameterizedTypeName.get(Comparator.class, String.class); 1662 TypeName listOfString = ParameterizedTypeName.get(List.class, String.class); 1663 TypeSpec prefixComparator = TypeSpec.anonymousClassBuilder("") 1664 .addSuperinterface(stringComparator) 1665 .addMethod(MethodSpec.methodBuilder("compare") 1666 .addAnnotation(Override.class) 1667 .addModifiers(Modifier.PUBLIC) 1668 .returns(int.class) 1669 .addParameter(String.class, "a") 1670 .addParameter(String.class, "b") 1671 .addStatement("return a.substring(0, length)\n" 1672 + ".compareTo(b.substring(0, length))") 1673 .build()) 1674 .build(); 1675 TypeSpec taco = TypeSpec.classBuilder("Taco") 1676 .addMethod(MethodSpec.methodBuilder("comparePrefix") 1677 .returns(stringComparator) 1678 .addParameter(int.class, "length", Modifier.FINAL) 1679 .addStatement("return $L", prefixComparator) 1680 .build()) 1681 .addMethod(MethodSpec.methodBuilder("sortPrefix") 1682 .addParameter(listOfString, "list") 1683 .addParameter(int.class, "length", Modifier.FINAL) 1684 .addStatement("$T.sort(\nlist,\n$L)", Collections.class, prefixComparator) 1685 .build()) 1686 .build(); 1687 assertThat(toString(taco)).isEqualTo("" 1688 + "package com.squareup.tacos;\n" 1689 + "\n" 1690 + "import java.lang.Override;\n" 1691 + "import java.lang.String;\n" 1692 + "import java.util.Collections;\n" 1693 + "import java.util.Comparator;\n" 1694 + "import java.util.List;\n" 1695 + "\n" 1696 + "class Taco {\n" 1697 + " Comparator<String> comparePrefix(final int length) {\n" 1698 + " return new Comparator<String>() {\n" 1699 + " @Override\n" 1700 + " public int compare(String a, String b) {\n" 1701 + " return a.substring(0, length)\n" 1702 + " .compareTo(b.substring(0, length));\n" 1703 + " }\n" 1704 + " };\n" 1705 + " }\n" 1706 + "\n" 1707 + " void sortPrefix(List<String> list, final int length) {\n" 1708 + " Collections.sort(\n" 1709 + " list,\n" 1710 + " new Comparator<String>() {\n" 1711 + " @Override\n" 1712 + " public int compare(String a, String b) {\n" 1713 + " return a.substring(0, length)\n" 1714 + " .compareTo(b.substring(0, length));\n" 1715 + " }\n" 1716 + " });\n" 1717 + " }\n" 1718 + "}\n"); 1719 } 1720 multilineStrings()1721 @Test public void multilineStrings() throws Exception { 1722 TypeSpec taco = TypeSpec.classBuilder("Taco") 1723 .addField(FieldSpec.builder(String.class, "toppings") 1724 .initializer("$S", "shell\nbeef\nlettuce\ncheese\n") 1725 .build()) 1726 .build(); 1727 assertThat(toString(taco)).isEqualTo("" 1728 + "package com.squareup.tacos;\n" 1729 + "\n" 1730 + "import java.lang.String;\n" 1731 + "\n" 1732 + "class Taco {\n" 1733 + " String toppings = \"shell\\n\"\n" 1734 + " + \"beef\\n\"\n" 1735 + " + \"lettuce\\n\"\n" 1736 + " + \"cheese\\n\";\n" 1737 + "}\n"); 1738 } 1739 doubleFieldInitialization()1740 @Test public void doubleFieldInitialization() { 1741 try { 1742 FieldSpec.builder(String.class, "listA") 1743 .initializer("foo") 1744 .initializer("bar") 1745 .build(); 1746 fail(); 1747 } catch (IllegalStateException expected) { 1748 } 1749 1750 try { 1751 FieldSpec.builder(String.class, "listA") 1752 .initializer(CodeBlock.builder().add("foo").build()) 1753 .initializer(CodeBlock.builder().add("bar").build()) 1754 .build(); 1755 fail(); 1756 } catch (IllegalStateException expected) { 1757 } 1758 } 1759 nullAnnotationsAddition()1760 @Test public void nullAnnotationsAddition() { 1761 try { 1762 TypeSpec.classBuilder("Taco").addAnnotations(null); 1763 fail(); 1764 } catch (IllegalArgumentException expected) { 1765 assertThat(expected.getMessage()) 1766 .isEqualTo("annotationSpecs == null"); 1767 } 1768 } 1769 multipleAnnotationAddition()1770 @Test public void multipleAnnotationAddition() { 1771 TypeSpec taco = TypeSpec.classBuilder("Taco") 1772 .addAnnotations(Arrays.asList( 1773 AnnotationSpec.builder(SuppressWarnings.class) 1774 .addMember("value", "$S", "unchecked") 1775 .build(), 1776 AnnotationSpec.builder(Deprecated.class).build())) 1777 .build(); 1778 assertThat(toString(taco)).isEqualTo("" 1779 + "package com.squareup.tacos;\n" 1780 + "\n" 1781 + "import java.lang.Deprecated;\n" 1782 + "import java.lang.SuppressWarnings;\n" 1783 + "\n" 1784 + "@SuppressWarnings(\"unchecked\")\n" 1785 + "@Deprecated\n" 1786 + "class Taco {\n" 1787 + "}\n"); 1788 } 1789 nullFieldsAddition()1790 @Test public void nullFieldsAddition() { 1791 try { 1792 TypeSpec.classBuilder("Taco").addFields(null); 1793 fail(); 1794 } catch (IllegalArgumentException expected) { 1795 assertThat(expected.getMessage()) 1796 .isEqualTo("fieldSpecs == null"); 1797 } 1798 } 1799 multipleFieldAddition()1800 @Test public void multipleFieldAddition() { 1801 TypeSpec taco = TypeSpec.classBuilder("Taco") 1802 .addFields(Arrays.asList( 1803 FieldSpec.builder(int.class, "ANSWER", Modifier.STATIC, Modifier.FINAL).build(), 1804 FieldSpec.builder(BigDecimal.class, "price", Modifier.PRIVATE).build())) 1805 .build(); 1806 assertThat(toString(taco)).isEqualTo("" 1807 + "package com.squareup.tacos;\n" 1808 + "\n" 1809 + "import java.math.BigDecimal;\n" 1810 + "\n" 1811 + "class Taco {\n" 1812 + " static final int ANSWER;\n" 1813 + "\n" 1814 + " private BigDecimal price;\n" 1815 + "}\n"); 1816 } 1817 nullMethodsAddition()1818 @Test public void nullMethodsAddition() { 1819 try { 1820 TypeSpec.classBuilder("Taco").addMethods(null); 1821 fail(); 1822 } catch (IllegalArgumentException expected) { 1823 assertThat(expected.getMessage()) 1824 .isEqualTo("methodSpecs == null"); 1825 } 1826 } 1827 multipleMethodAddition()1828 @Test public void multipleMethodAddition() { 1829 TypeSpec taco = TypeSpec.classBuilder("Taco") 1830 .addMethods(Arrays.asList( 1831 MethodSpec.methodBuilder("getAnswer") 1832 .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 1833 .returns(int.class) 1834 .addStatement("return $L", 42) 1835 .build(), 1836 MethodSpec.methodBuilder("getRandomQuantity") 1837 .addModifiers(Modifier.PUBLIC) 1838 .returns(int.class) 1839 .addJavadoc("chosen by fair dice roll ;)") 1840 .addStatement("return $L", 4) 1841 .build())) 1842 .build(); 1843 assertThat(toString(taco)).isEqualTo("" 1844 + "package com.squareup.tacos;\n" 1845 + "\n" 1846 + "class Taco {\n" 1847 + " public static int getAnswer() {\n" 1848 + " return 42;\n" 1849 + " }\n" 1850 + "\n" 1851 + " /**\n" 1852 + " * chosen by fair dice roll ;)\n" 1853 + " */\n" 1854 + " public int getRandomQuantity() {\n" 1855 + " return 4;\n" 1856 + " }\n" 1857 + "}\n"); 1858 } 1859 nullSuperinterfacesAddition()1860 @Test public void nullSuperinterfacesAddition() { 1861 try { 1862 TypeSpec.classBuilder("Taco").addSuperinterfaces(null); 1863 fail(); 1864 } catch (IllegalArgumentException expected) { 1865 assertThat(expected.getMessage()) 1866 .isEqualTo("superinterfaces == null"); 1867 } 1868 } 1869 nullSingleSuperinterfaceAddition()1870 @Test public void nullSingleSuperinterfaceAddition() { 1871 try { 1872 TypeSpec.classBuilder("Taco").addSuperinterface((TypeName) null); 1873 fail(); 1874 } catch (IllegalArgumentException expected) { 1875 assertThat(expected.getMessage()) 1876 .isEqualTo("superinterface == null"); 1877 } 1878 } 1879 nullInSuperinterfaceIterableAddition()1880 @Test public void nullInSuperinterfaceIterableAddition() { 1881 List<TypeName> superinterfaces = new ArrayList<>(); 1882 superinterfaces.add(TypeName.get(List.class)); 1883 superinterfaces.add(null); 1884 1885 try { 1886 TypeSpec.classBuilder("Taco").addSuperinterfaces(superinterfaces); 1887 fail(); 1888 } catch (IllegalArgumentException expected) { 1889 assertThat(expected.getMessage()) 1890 .isEqualTo("superinterface == null"); 1891 } 1892 } 1893 multipleSuperinterfaceAddition()1894 @Test public void multipleSuperinterfaceAddition() { 1895 TypeSpec taco = TypeSpec.classBuilder("Taco") 1896 .addSuperinterfaces(Arrays.asList( 1897 TypeName.get(Serializable.class), 1898 TypeName.get(EventListener.class))) 1899 .build(); 1900 assertThat(toString(taco)).isEqualTo("" 1901 + "package com.squareup.tacos;\n" 1902 + "\n" 1903 + "import java.io.Serializable;\n" 1904 + "import java.util.EventListener;\n" 1905 + "\n" 1906 + "class Taco implements Serializable, EventListener {\n" 1907 + "}\n"); 1908 } 1909 nullModifiersAddition()1910 @Test public void nullModifiersAddition() { 1911 try { 1912 TypeSpec.classBuilder("Taco").addModifiers((Modifier) null).build(); 1913 fail(); 1914 } catch(IllegalArgumentException expected) { 1915 assertThat(expected.getMessage()) 1916 .isEqualTo("modifiers contain null"); 1917 } 1918 } 1919 nullTypeVariablesAddition()1920 @Test public void nullTypeVariablesAddition() { 1921 try { 1922 TypeSpec.classBuilder("Taco").addTypeVariables(null); 1923 fail(); 1924 } catch (IllegalArgumentException expected) { 1925 assertThat(expected.getMessage()) 1926 .isEqualTo("typeVariables == null"); 1927 } 1928 } 1929 multipleTypeVariableAddition()1930 @Test public void multipleTypeVariableAddition() { 1931 TypeSpec location = TypeSpec.classBuilder("Location") 1932 .addTypeVariables(Arrays.asList( 1933 TypeVariableName.get("T"), 1934 TypeVariableName.get("P", Number.class))) 1935 .build(); 1936 assertThat(toString(location)).isEqualTo("" 1937 + "package com.squareup.tacos;\n" 1938 + "\n" 1939 + "import java.lang.Number;\n" 1940 + "\n" 1941 + "class Location<T, P extends Number> {\n" 1942 + "}\n"); 1943 } 1944 nullTypesAddition()1945 @Test public void nullTypesAddition() { 1946 try { 1947 TypeSpec.classBuilder("Taco").addTypes(null); 1948 fail(); 1949 } catch (IllegalArgumentException expected) { 1950 assertThat(expected.getMessage()) 1951 .isEqualTo("typeSpecs == null"); 1952 } 1953 } 1954 multipleTypeAddition()1955 @Test public void multipleTypeAddition() { 1956 TypeSpec taco = TypeSpec.classBuilder("Taco") 1957 .addTypes(Arrays.asList( 1958 TypeSpec.classBuilder("Topping").build(), 1959 TypeSpec.classBuilder("Sauce").build())) 1960 .build(); 1961 assertThat(toString(taco)).isEqualTo("" 1962 + "package com.squareup.tacos;\n" 1963 + "\n" 1964 + "class Taco {\n" 1965 + " class Topping {\n" 1966 + " }\n" 1967 + "\n" 1968 + " class Sauce {\n" 1969 + " }\n" 1970 + "}\n"); 1971 } 1972 tryCatch()1973 @Test public void tryCatch() { 1974 TypeSpec taco = TypeSpec.classBuilder("Taco") 1975 .addMethod(MethodSpec.methodBuilder("addTopping") 1976 .addParameter(ClassName.get("com.squareup.tacos", "Topping"), "topping") 1977 .beginControlFlow("try") 1978 .addCode("/* do something tricky with the topping */\n") 1979 .nextControlFlow("catch ($T e)", 1980 ClassName.get("com.squareup.tacos", "IllegalToppingException")) 1981 .endControlFlow() 1982 .build()) 1983 .build(); 1984 assertThat(toString(taco)).isEqualTo("" 1985 + "package com.squareup.tacos;\n" 1986 + "\n" 1987 + "class Taco {\n" 1988 + " void addTopping(Topping topping) {\n" 1989 + " try {\n" 1990 + " /* do something tricky with the topping */\n" 1991 + " } catch (IllegalToppingException e) {\n" 1992 + " }\n" 1993 + " }\n" 1994 + "}\n"); 1995 } 1996 ifElse()1997 @Test public void ifElse() { 1998 TypeSpec taco = TypeSpec.classBuilder("Taco") 1999 .addMethod( 2000 MethodSpec.methodBuilder("isDelicious") 2001 .addParameter(TypeName.INT, "count") 2002 .returns(TypeName.BOOLEAN) 2003 .beginControlFlow("if (count > 0)") 2004 .addStatement("return true") 2005 .nextControlFlow("else") 2006 .addStatement("return false") 2007 .endControlFlow() 2008 .build() 2009 ) 2010 .build(); 2011 assertThat(toString(taco)).isEqualTo("" 2012 + "package com.squareup.tacos;\n" 2013 + "\n" 2014 + "class Taco {\n" 2015 + " boolean isDelicious(int count) {\n" 2016 + " if (count > 0) {\n" 2017 + " return true;\n" 2018 + " } else {\n" 2019 + " return false;\n" 2020 + " }\n" 2021 + " }\n" 2022 + "}\n"); 2023 } 2024 literalFromAnything()2025 @Test public void literalFromAnything() { 2026 Object value = new Object() { 2027 @Override public String toString() { 2028 return "foo"; 2029 } 2030 }; 2031 assertThat(CodeBlock.of("$L", value).toString()).isEqualTo("foo"); 2032 } 2033 nameFromCharSequence()2034 @Test public void nameFromCharSequence() { 2035 assertThat(CodeBlock.of("$N", "text").toString()).isEqualTo("text"); 2036 } 2037 nameFromField()2038 @Test public void nameFromField() { 2039 FieldSpec field = FieldSpec.builder(String.class, "field").build(); 2040 assertThat(CodeBlock.of("$N", field).toString()).isEqualTo("field"); 2041 } 2042 nameFromParameter()2043 @Test public void nameFromParameter() { 2044 ParameterSpec parameter = ParameterSpec.builder(String.class, "parameter").build(); 2045 assertThat(CodeBlock.of("$N", parameter).toString()).isEqualTo("parameter"); 2046 } 2047 nameFromMethod()2048 @Test public void nameFromMethod() { 2049 MethodSpec method = MethodSpec.methodBuilder("method") 2050 .addModifiers(Modifier.ABSTRACT) 2051 .returns(String.class) 2052 .build(); 2053 assertThat(CodeBlock.of("$N", method).toString()).isEqualTo("method"); 2054 } 2055 nameFromType()2056 @Test public void nameFromType() { 2057 TypeSpec type = TypeSpec.classBuilder("Type").build(); 2058 assertThat(CodeBlock.of("$N", type).toString()).isEqualTo("Type"); 2059 } 2060 nameFromUnsupportedType()2061 @Test public void nameFromUnsupportedType() { 2062 try { 2063 CodeBlock.builder().add("$N", String.class); 2064 fail(); 2065 } catch (IllegalArgumentException expected) { 2066 assertThat(expected).hasMessageThat().isEqualTo("expected name but was " + String.class); 2067 } 2068 } 2069 stringFromAnything()2070 @Test public void stringFromAnything() { 2071 Object value = new Object() { 2072 @Override public String toString() { 2073 return "foo"; 2074 } 2075 }; 2076 assertThat(CodeBlock.of("$S", value).toString()).isEqualTo("\"foo\""); 2077 } 2078 stringFromNull()2079 @Test public void stringFromNull() { 2080 assertThat(CodeBlock.of("$S", new Object[] {null}).toString()).isEqualTo("null"); 2081 } 2082 typeFromTypeName()2083 @Test public void typeFromTypeName() { 2084 TypeName typeName = TypeName.get(String.class); 2085 assertThat(CodeBlock.of("$T", typeName).toString()).isEqualTo("java.lang.String"); 2086 } 2087 typeFromTypeMirror()2088 @Test public void typeFromTypeMirror() { 2089 TypeMirror mirror = getElement(String.class).asType(); 2090 assertThat(CodeBlock.of("$T", mirror).toString()).isEqualTo("java.lang.String"); 2091 } 2092 typeFromTypeElement()2093 @Test public void typeFromTypeElement() { 2094 TypeElement element = getElement(String.class); 2095 assertThat(CodeBlock.of("$T", element).toString()).isEqualTo("java.lang.String"); 2096 } 2097 typeFromReflectType()2098 @Test public void typeFromReflectType() { 2099 assertThat(CodeBlock.of("$T", String.class).toString()).isEqualTo("java.lang.String"); 2100 } 2101 typeFromUnsupportedType()2102 @Test public void typeFromUnsupportedType() { 2103 try { 2104 CodeBlock.builder().add("$T", "java.lang.String"); 2105 fail(); 2106 } catch (IllegalArgumentException expected) { 2107 assertThat(expected).hasMessageThat().isEqualTo("expected type but was java.lang.String"); 2108 } 2109 } 2110 tooFewArguments()2111 @Test public void tooFewArguments() { 2112 try { 2113 CodeBlock.builder().add("$S"); 2114 fail(); 2115 } catch (IllegalArgumentException expected) { 2116 assertThat(expected).hasMessageThat().isEqualTo("index 1 for '$S' not in range (received 0 arguments)"); 2117 } 2118 } 2119 unusedArgumentsRelative()2120 @Test public void unusedArgumentsRelative() { 2121 try { 2122 CodeBlock.builder().add("$L $L", "a", "b", "c"); 2123 fail(); 2124 } catch (IllegalArgumentException expected) { 2125 assertThat(expected).hasMessageThat().isEqualTo("unused arguments: expected 2, received 3"); 2126 } 2127 } 2128 unusedArgumentsIndexed()2129 @Test public void unusedArgumentsIndexed() { 2130 try { 2131 CodeBlock.builder().add("$1L $2L", "a", "b", "c"); 2132 fail(); 2133 } catch (IllegalArgumentException expected) { 2134 assertThat(expected).hasMessageThat().isEqualTo("unused argument: $3"); 2135 } 2136 try { 2137 CodeBlock.builder().add("$1L $1L $1L", "a", "b", "c"); 2138 fail(); 2139 } catch (IllegalArgumentException expected) { 2140 assertThat(expected).hasMessageThat().isEqualTo("unused arguments: $2, $3"); 2141 } 2142 try { 2143 CodeBlock.builder().add("$3L $1L $3L $1L $3L", "a", "b", "c", "d"); 2144 fail(); 2145 } catch (IllegalArgumentException expected) { 2146 assertThat(expected).hasMessageThat().isEqualTo("unused arguments: $2, $4"); 2147 } 2148 } 2149 superClassOnlyValidForClasses()2150 @Test public void superClassOnlyValidForClasses() { 2151 try { 2152 TypeSpec.annotationBuilder("A").superclass(ClassName.get(Object.class)); 2153 fail(); 2154 } catch (IllegalStateException expected) { 2155 } 2156 try { 2157 TypeSpec.enumBuilder("E").superclass(ClassName.get(Object.class)); 2158 fail(); 2159 } catch (IllegalStateException expected) { 2160 } 2161 try { 2162 TypeSpec.interfaceBuilder("I").superclass(ClassName.get(Object.class)); 2163 fail(); 2164 } catch (IllegalStateException expected) { 2165 } 2166 } 2167 invalidSuperClass()2168 @Test public void invalidSuperClass() { 2169 try { 2170 TypeSpec.classBuilder("foo") 2171 .superclass(ClassName.get(List.class)) 2172 .superclass(ClassName.get(Map.class)); 2173 fail(); 2174 } catch (IllegalStateException expected) { 2175 } 2176 try { 2177 TypeSpec.classBuilder("foo") 2178 .superclass(TypeName.INT); 2179 fail(); 2180 } catch (IllegalArgumentException expected) { 2181 } 2182 } 2183 staticCodeBlock()2184 @Test public void staticCodeBlock() { 2185 TypeSpec taco = TypeSpec.classBuilder("Taco") 2186 .addField(String.class, "foo", Modifier.PRIVATE) 2187 .addField(String.class, "FOO", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) 2188 .addStaticBlock(CodeBlock.builder() 2189 .addStatement("FOO = $S", "FOO") 2190 .build()) 2191 .addMethod(MethodSpec.methodBuilder("toString") 2192 .addAnnotation(Override.class) 2193 .addModifiers(Modifier.PUBLIC) 2194 .returns(String.class) 2195 .addCode("return FOO;\n") 2196 .build()) 2197 .build(); 2198 assertThat(toString(taco)).isEqualTo("" 2199 + "package com.squareup.tacos;\n" 2200 + "\n" 2201 + "import java.lang.Override;\n" 2202 + "import java.lang.String;\n" 2203 + "\n" 2204 + "class Taco {\n" 2205 + " private static final String FOO;\n" 2206 + "\n" 2207 + " static {\n" 2208 + " FOO = \"FOO\";\n" 2209 + " }\n" 2210 + "\n" 2211 + " private String foo;\n" 2212 + "\n" 2213 + " @Override\n" 2214 + " public String toString() {\n" 2215 + " return FOO;\n" 2216 + " }\n" 2217 + "}\n"); 2218 } 2219 initializerBlockInRightPlace()2220 @Test public void initializerBlockInRightPlace() { 2221 TypeSpec taco = TypeSpec.classBuilder("Taco") 2222 .addField(String.class, "foo", Modifier.PRIVATE) 2223 .addField(String.class, "FOO", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) 2224 .addStaticBlock(CodeBlock.builder() 2225 .addStatement("FOO = $S", "FOO") 2226 .build()) 2227 .addMethod(MethodSpec.constructorBuilder().build()) 2228 .addMethod(MethodSpec.methodBuilder("toString") 2229 .addAnnotation(Override.class) 2230 .addModifiers(Modifier.PUBLIC) 2231 .returns(String.class) 2232 .addCode("return FOO;\n") 2233 .build()) 2234 .addInitializerBlock(CodeBlock.builder() 2235 .addStatement("foo = $S", "FOO") 2236 .build()) 2237 .build(); 2238 assertThat(toString(taco)).isEqualTo("" 2239 + "package com.squareup.tacos;\n" 2240 + "\n" 2241 + "import java.lang.Override;\n" 2242 + "import java.lang.String;\n" 2243 + "\n" 2244 + "class Taco {\n" 2245 + " private static final String FOO;\n" 2246 + "\n" 2247 + " static {\n" 2248 + " FOO = \"FOO\";\n" 2249 + " }\n" 2250 + "\n" 2251 + " private String foo;\n" 2252 + "\n" 2253 + " {\n" 2254 + " foo = \"FOO\";\n" 2255 + " }\n" 2256 + "\n" 2257 + " Taco() {\n" 2258 + " }\n" 2259 + "\n" 2260 + " @Override\n" 2261 + " public String toString() {\n" 2262 + " return FOO;\n" 2263 + " }\n" 2264 + "}\n"); 2265 } 2266 initializersToBuilder()2267 @Test public void initializersToBuilder() { 2268 // Tests if toBuilder() contains correct static and instance initializers 2269 Element originatingElement = getElement(TypeSpecTest.class); 2270 TypeSpec taco = TypeSpec.classBuilder("Taco") 2271 .addField(String.class, "foo", Modifier.PRIVATE) 2272 .addField(String.class, "FOO", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) 2273 .addStaticBlock(CodeBlock.builder() 2274 .addStatement("FOO = $S", "FOO") 2275 .build()) 2276 .addMethod(MethodSpec.constructorBuilder().build()) 2277 .addMethod(MethodSpec.methodBuilder("toString") 2278 .addAnnotation(Override.class) 2279 .addModifiers(Modifier.PUBLIC) 2280 .returns(String.class) 2281 .addCode("return FOO;\n") 2282 .build()) 2283 .addInitializerBlock(CodeBlock.builder() 2284 .addStatement("foo = $S", "FOO") 2285 .build()) 2286 .addOriginatingElement(originatingElement) 2287 .alwaysQualify("com.example.AlwaysQualified") 2288 .build(); 2289 2290 TypeSpec recreatedTaco = taco.toBuilder().build(); 2291 assertThat(toString(taco)).isEqualTo(toString(recreatedTaco)); 2292 assertThat(taco.originatingElements) 2293 .containsExactlyElementsIn(recreatedTaco.originatingElements); 2294 assertThat(taco.alwaysQualifiedNames) 2295 .containsExactlyElementsIn(recreatedTaco.alwaysQualifiedNames); 2296 2297 TypeSpec initializersAdded = taco.toBuilder() 2298 .addInitializerBlock(CodeBlock.builder() 2299 .addStatement("foo = $S", "instanceFoo") 2300 .build()) 2301 .addStaticBlock(CodeBlock.builder() 2302 .addStatement("FOO = $S", "staticFoo") 2303 .build()) 2304 .build(); 2305 2306 assertThat(toString(initializersAdded)).isEqualTo("" 2307 + "package com.squareup.tacos;\n" 2308 + "\n" 2309 + "import java.lang.Override;\n" 2310 + "import java.lang.String;\n" 2311 + "\n" 2312 + "class Taco {\n" 2313 + " private static final String FOO;\n" 2314 + "\n" 2315 + " static {\n" 2316 + " FOO = \"FOO\";\n" 2317 + " }\n" 2318 + " static {\n" 2319 + " FOO = \"staticFoo\";\n" 2320 + " }\n" 2321 + "\n" 2322 + " private String foo;\n" 2323 + "\n" 2324 + " {\n" 2325 + " foo = \"FOO\";\n" 2326 + " }\n" 2327 + " {\n" 2328 + " foo = \"instanceFoo\";\n" 2329 + " }\n" 2330 + "\n" 2331 + " Taco() {\n" 2332 + " }\n" 2333 + "\n" 2334 + " @Override\n" 2335 + " public String toString() {\n" 2336 + " return FOO;\n" 2337 + " }\n" 2338 + "}\n"); 2339 } 2340 initializerBlockUnsupportedExceptionOnInterface()2341 @Test public void initializerBlockUnsupportedExceptionOnInterface() { 2342 TypeSpec.Builder interfaceBuilder = TypeSpec.interfaceBuilder("Taco"); 2343 try { 2344 interfaceBuilder.addInitializerBlock(CodeBlock.builder().build()); 2345 fail("Exception expected"); 2346 } catch (UnsupportedOperationException e) { 2347 } 2348 } 2349 initializerBlockUnsupportedExceptionOnAnnotation()2350 @Test public void initializerBlockUnsupportedExceptionOnAnnotation() { 2351 TypeSpec.Builder annotationBuilder = TypeSpec.annotationBuilder("Taco"); 2352 try { 2353 annotationBuilder.addInitializerBlock(CodeBlock.builder().build()); 2354 fail("Exception expected"); 2355 } catch (UnsupportedOperationException e) { 2356 } 2357 } 2358 lineWrapping()2359 @Test public void lineWrapping() { 2360 MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("call"); 2361 methodBuilder.addCode("$[call("); 2362 for (int i = 0; i < 32; i++) { 2363 methodBuilder.addParameter(String.class, "s" + i); 2364 methodBuilder.addCode(i > 0 ? ",$W$S" : "$S", i); 2365 } 2366 methodBuilder.addCode(");$]\n"); 2367 2368 TypeSpec taco = TypeSpec.classBuilder("Taco") 2369 .addMethod(methodBuilder.build()) 2370 .build(); 2371 assertThat(toString(taco)).isEqualTo("" 2372 + "package com.squareup.tacos;\n" 2373 + "\n" 2374 + "import java.lang.String;\n" 2375 + "\n" 2376 + "class Taco {\n" 2377 + " void call(String s0, String s1, String s2, String s3, String s4, String s5, String s6, String s7,\n" 2378 + " String s8, String s9, String s10, String s11, String s12, String s13, String s14, String s15,\n" 2379 + " String s16, String s17, String s18, String s19, String s20, String s21, String s22,\n" 2380 + " String s23, String s24, String s25, String s26, String s27, String s28, String s29,\n" 2381 + " String s30, String s31) {\n" 2382 + " call(\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\",\n" 2383 + " \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"30\", \"31\");\n" 2384 + " }\n" 2385 + "}\n"); 2386 } 2387 lineWrappingWithZeroWidthSpace()2388 @Test public void lineWrappingWithZeroWidthSpace() { 2389 MethodSpec method = MethodSpec.methodBuilder("call") 2390 .addCode("$[iAmSickOfWaitingInLine($Z") 2391 .addCode("it, has, been, far, too, long, of, a, wait, and, i, would, like, to, eat, ") 2392 .addCode("this, is, a, run, on, sentence") 2393 .addCode(");$]\n") 2394 .build(); 2395 2396 TypeSpec taco = TypeSpec.classBuilder("Taco") 2397 .addMethod(method) 2398 .build(); 2399 assertThat(toString(taco)).isEqualTo("" 2400 + "package com.squareup.tacos;\n" 2401 + "\n" 2402 + "class Taco {\n" 2403 + " void call() {\n" 2404 + " iAmSickOfWaitingInLine(\n" 2405 + " it, has, been, far, too, long, of, a, wait, and, i, would, like, to, eat, this, is, a, run, on, sentence);\n" 2406 + " }\n" 2407 + "}\n"); 2408 } 2409 equalsAndHashCode()2410 @Test public void equalsAndHashCode() { 2411 TypeSpec a = TypeSpec.interfaceBuilder("taco").build(); 2412 TypeSpec b = TypeSpec.interfaceBuilder("taco").build(); 2413 assertThat(a.equals(b)).isTrue(); 2414 assertThat(a.hashCode()).isEqualTo(b.hashCode()); 2415 a = TypeSpec.classBuilder("taco").build(); 2416 b = TypeSpec.classBuilder("taco").build(); 2417 assertThat(a.equals(b)).isTrue(); 2418 assertThat(a.hashCode()).isEqualTo(b.hashCode()); 2419 a = TypeSpec.enumBuilder("taco").addEnumConstant("SALSA").build(); 2420 b = TypeSpec.enumBuilder("taco").addEnumConstant("SALSA").build(); 2421 assertThat(a.equals(b)).isTrue(); 2422 assertThat(a.hashCode()).isEqualTo(b.hashCode()); 2423 a = TypeSpec.annotationBuilder("taco").build(); 2424 b = TypeSpec.annotationBuilder("taco").build(); 2425 assertThat(a.equals(b)).isTrue(); 2426 assertThat(a.hashCode()).isEqualTo(b.hashCode()); 2427 } 2428 classNameFactories()2429 @Test public void classNameFactories() { 2430 ClassName className = ClassName.get("com.example", "Example"); 2431 assertThat(TypeSpec.classBuilder(className).build().name).isEqualTo("Example"); 2432 assertThat(TypeSpec.interfaceBuilder(className).build().name).isEqualTo("Example"); 2433 assertThat(TypeSpec.enumBuilder(className).addEnumConstant("A").build().name).isEqualTo("Example"); 2434 assertThat(TypeSpec.annotationBuilder(className).build().name).isEqualTo("Example"); 2435 } 2436 2437 @Test modifyAnnotations()2438 public void modifyAnnotations() { 2439 TypeSpec.Builder builder = 2440 TypeSpec.classBuilder("Taco") 2441 .addAnnotation(Override.class) 2442 .addAnnotation(SuppressWarnings.class); 2443 2444 builder.annotations.remove(1); 2445 assertThat(builder.build().annotations).hasSize(1); 2446 } 2447 2448 @Test modifyModifiers()2449 public void modifyModifiers() { 2450 TypeSpec.Builder builder = 2451 TypeSpec.classBuilder("Taco").addModifiers(Modifier.PUBLIC, Modifier.FINAL); 2452 2453 builder.modifiers.remove(1); 2454 assertThat(builder.build().modifiers).containsExactly(Modifier.PUBLIC); 2455 } 2456 2457 @Test modifyFields()2458 public void modifyFields() { 2459 TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") 2460 .addField(int.class, "source"); 2461 2462 builder.fieldSpecs.remove(0); 2463 assertThat(builder.build().fieldSpecs).isEmpty(); 2464 } 2465 2466 @Test modifyTypeVariables()2467 public void modifyTypeVariables() { 2468 TypeVariableName t = TypeVariableName.get("T"); 2469 TypeSpec.Builder builder = 2470 TypeSpec.classBuilder("Taco") 2471 .addTypeVariable(t) 2472 .addTypeVariable(TypeVariableName.get("V")); 2473 2474 builder.typeVariables.remove(1); 2475 assertThat(builder.build().typeVariables).containsExactly(t); 2476 } 2477 2478 @Test modifySuperinterfaces()2479 public void modifySuperinterfaces() { 2480 TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") 2481 .addSuperinterface(File.class); 2482 2483 builder.superinterfaces.clear(); 2484 assertThat(builder.build().superinterfaces).isEmpty(); 2485 } 2486 2487 @Test modifyMethods()2488 public void modifyMethods() { 2489 TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") 2490 .addMethod(MethodSpec.methodBuilder("bell").build()); 2491 2492 builder.methodSpecs.clear(); 2493 assertThat(builder.build().methodSpecs).isEmpty(); 2494 } 2495 2496 @Test modifyTypes()2497 public void modifyTypes() { 2498 TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") 2499 .addType(TypeSpec.classBuilder("Bell").build()); 2500 2501 builder.typeSpecs.clear(); 2502 assertThat(builder.build().typeSpecs).isEmpty(); 2503 } 2504 2505 @Test modifyEnumConstants()2506 public void modifyEnumConstants() { 2507 TypeSpec constantType = TypeSpec.anonymousClassBuilder("").build(); 2508 TypeSpec.Builder builder = TypeSpec.enumBuilder("Taco") 2509 .addEnumConstant("BELL", constantType) 2510 .addEnumConstant("WUT", TypeSpec.anonymousClassBuilder("").build()); 2511 2512 builder.enumConstants.remove("WUT"); 2513 assertThat(builder.build().enumConstants).containsExactly("BELL", constantType); 2514 } 2515 2516 @Test modifyOriginatingElements()2517 public void modifyOriginatingElements() { 2518 TypeSpec.Builder builder = TypeSpec.classBuilder("Taco") 2519 .addOriginatingElement(Mockito.mock(Element.class)); 2520 2521 builder.originatingElements.clear(); 2522 assertThat(builder.build().originatingElements).isEmpty(); 2523 } 2524 javadocWithTrailingLineDoesNotAddAnother()2525 @Test public void javadocWithTrailingLineDoesNotAddAnother() { 2526 TypeSpec spec = TypeSpec.classBuilder("Taco") 2527 .addJavadoc("Some doc with a newline\n") 2528 .build(); 2529 2530 assertThat(toString(spec)).isEqualTo("" 2531 + "package com.squareup.tacos;\n" 2532 + "\n" 2533 + "/**\n" 2534 + " * Some doc with a newline\n" 2535 + " */\n" 2536 + "class Taco {\n" 2537 + "}\n"); 2538 } 2539 javadocEnsuresTrailingLine()2540 @Test public void javadocEnsuresTrailingLine() { 2541 TypeSpec spec = TypeSpec.classBuilder("Taco") 2542 .addJavadoc("Some doc with a newline") 2543 .build(); 2544 2545 assertThat(toString(spec)).isEqualTo("" 2546 + "package com.squareup.tacos;\n" 2547 + "\n" 2548 + "/**\n" 2549 + " * Some doc with a newline\n" 2550 + " */\n" 2551 + "class Taco {\n" 2552 + "}\n"); 2553 } 2554 } 2555