1 /* 2 * Copyright (C) 2019 The Android Open Source Project 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 android.processor.compat.changeid; 18 19 import static java.nio.charset.StandardCharsets.UTF_8; 20 21 import static javax.tools.StandardLocation.CLASS_OUTPUT; 22 23 import com.google.common.collect.ObjectArrays; 24 import com.google.testing.compile.Compilation; 25 import com.google.testing.compile.CompilationSubject; 26 import com.google.testing.compile.Compiler; 27 import com.google.testing.compile.JavaFileObjects; 28 29 import org.junit.Test; 30 31 import javax.tools.JavaFileObject; 32 33 34 public class ChangeIdProcessorTest { 35 36 // Hard coding the annotation definitions to avoid dependency on libcore, where they're defined. 37 private static final JavaFileObject[] mAnnotations = { 38 JavaFileObjects.forSourceLines("android.compat.annotation.ChangeId", 39 "package android.compat.annotation;", 40 "import static java.lang.annotation.ElementType.FIELD;", 41 "import static java.lang.annotation.ElementType.PARAMETER;", 42 "import static java.lang.annotation.RetentionPolicy.SOURCE;", 43 "import java.lang.annotation.Retention;", 44 "import java.lang.annotation.Target;", 45 "@Retention(SOURCE)", 46 "@Target({FIELD, PARAMETER})", 47 "public @interface ChangeId {", 48 "}"), 49 JavaFileObjects.forSourceLines("android.compat.annotation.Disabled", 50 "package android.compat.annotation;", 51 "import static java.lang.annotation.ElementType.FIELD;", 52 "import static java.lang.annotation.RetentionPolicy.SOURCE;", 53 "import java.lang.annotation.Retention;", 54 "import java.lang.annotation.Target;", 55 "@Retention(SOURCE)", 56 "@Target({FIELD})", 57 "public @interface Disabled {", 58 "}"), 59 JavaFileObjects.forSourceLines("android.compat.annotation.LoggingOnly", 60 "package android.compat.annotation;", 61 "import static java.lang.annotation.ElementType.FIELD;", 62 "import static java.lang.annotation.RetentionPolicy.SOURCE;", 63 "import java.lang.annotation.Retention;", 64 "import java.lang.annotation.Target;", 65 "@Retention(SOURCE)", 66 "@Target({FIELD})", 67 "public @interface LoggingOnly {", 68 "}"), 69 JavaFileObjects.forSourceLines("android.compat.annotation.EnabledAfter", 70 "package android.compat.annotation;", 71 "import static java.lang.annotation.ElementType.FIELD;", 72 "import static java.lang.annotation.RetentionPolicy.SOURCE;", 73 "import java.lang.annotation.Retention;", 74 "import java.lang.annotation.Target;", 75 "@Retention(SOURCE)", 76 "@Target({FIELD})", 77 "public @interface EnabledAfter {", 78 "int targetSdkVersion();", 79 "}"), 80 JavaFileObjects.forSourceLines("android.compat.annotation.EnabledSince", 81 "package android.compat.annotation;", 82 "import static java.lang.annotation.ElementType.FIELD;", 83 "import static java.lang.annotation.RetentionPolicy.SOURCE;", 84 "import java.lang.annotation.Retention;", 85 "import java.lang.annotation.Target;", 86 "@Retention(SOURCE)", 87 "@Target({FIELD})", 88 "public @interface EnabledSince {", 89 "int targetSdkVersion();", 90 "}"), 91 JavaFileObjects.forSourceLines("android.compat.annotation.Overridable", 92 "package android.compat.annotation;", 93 "import static java.lang.annotation.ElementType.FIELD;", 94 "import static java.lang.annotation.RetentionPolicy.SOURCE;", 95 "import java.lang.annotation.Retention;", 96 "import java.lang.annotation.Target;", 97 "@Retention(SOURCE)", 98 "@Target({FIELD})", 99 "public @interface Overridable {", 100 "}") 101 102 }; 103 104 private static final String HEADER = 105 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"; 106 107 @Test testCompatConfigXmlOutput()108 public void testCompatConfigXmlOutput() { 109 JavaFileObject[] source = { 110 JavaFileObjects.forSourceLines( 111 "libcore.util.Compat", 112 "package libcore.util;", 113 "import android.compat.annotation.ChangeId;", 114 "import android.compat.annotation.EnabledAfter;", 115 "import android.compat.annotation.EnabledSince;", 116 "import android.compat.annotation.Disabled;", 117 "import android.compat.annotation.Overridable;", 118 "public class Compat {", 119 " /**", 120 " * description of", 121 " * MY_CHANGE_ID", 122 " */", 123 " @EnabledAfter(targetSdkVersion=29)", 124 " @ChangeId", 125 " static final long MY_CHANGE_ID = 123456789l;", 126 " /** description of ANOTHER_CHANGE **/", 127 " @ChangeId", 128 " @Disabled", 129 " public static final long ANOTHER_CHANGE = 23456700l;", 130 " /** description of LAST_CHANGE **/", 131 " @ChangeId", 132 " @EnabledSince(targetSdkVersion=30)", 133 " public static final long LAST_CHANGE = 23456701l;", 134 " /** description of OVERRIDABLE_CHANGE **/", 135 " @ChangeId", 136 " @Overridable", 137 " public static final long OVERRIDABLE_CHANGE = 23456702l;", 138 "}") 139 }; 140 String expectedFile = HEADER + "<config>" + 141 "<compat-change description=\"description of MY_CHANGE_ID\" " 142 + "enableAfterTargetSdk=\"29\" id=\"123456789\" name=\"MY_CHANGE_ID\">" 143 + "<meta-data definedIn=\"libcore.util.Compat\" " 144 + "sourcePosition=\"libcore/util/Compat.java:13\"/></compat-change>" 145 + "<compat-change description=\"description of ANOTHER_CHANGE\" disabled=\"true\" " 146 + "id=\"23456700\" name=\"ANOTHER_CHANGE\"><meta-data definedIn=\"libcore.util" 147 + ".Compat\" sourcePosition=\"libcore/util/Compat.java:16\"/></compat-change>" 148 + "<compat-change description=\"description of LAST_CHANGE\" " 149 + "enableSinceTargetSdk=\"30\" id=\"23456701\" name=\"LAST_CHANGE\">" 150 + "<meta-data definedIn=\"libcore.util.Compat\" " 151 + "sourcePosition=\"libcore/util/Compat.java:20\"/></compat-change>" 152 + "<compat-change description=\"description of OVERRIDABLE_CHANGE\" " 153 + "id=\"23456702\" name=\"OVERRIDABLE_CHANGE\" overridable=\"true\">" 154 + "<meta-data definedIn=\"libcore.util.Compat\" " 155 + "sourcePosition=\"libcore/util/Compat.java:24\"/></compat-change>" 156 + "</config>"; 157 Compilation compilation = 158 Compiler.javac() 159 .withProcessors(new ChangeIdProcessor()) 160 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 161 CompilationSubject.assertThat(compilation).succeeded(); 162 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "libcore.util", 163 "Compat_compat_config.xml").contentsAsString(UTF_8).isEqualTo(expectedFile); 164 } 165 166 @Test testCompatConfigXmlOutput_multiplePackages()167 public void testCompatConfigXmlOutput_multiplePackages() { 168 JavaFileObject[] source = { 169 JavaFileObjects.forSourceLines( 170 "libcore.util.Compat", 171 "package libcore.util;", 172 "import android.compat.annotation.ChangeId;", 173 "import android.compat.annotation.EnabledAfter;", 174 "import android.compat.annotation.Disabled;", 175 "public class Compat {", 176 " /**", 177 " * description of", 178 " * MY_CHANGE_ID", 179 " */", 180 " @ChangeId", 181 " static final long MY_CHANGE_ID = 123456789l;", 182 "}"), 183 JavaFileObjects.forSourceLines("android.util.SomeClass", 184 "package android.util;", 185 "import android.compat.annotation.ChangeId;", 186 "import android.compat.annotation.EnabledAfter;", 187 "import android.compat.annotation.Disabled;", 188 "public class SomeClass {", 189 " /** description of ANOTHER_CHANGE **/", 190 " @ChangeId", 191 " public static final long ANOTHER_CHANGE = 23456700l;", 192 "}") 193 }; 194 String libcoreExpectedFile = HEADER + "<config>" + 195 "<compat-change description=\"description of MY_CHANGE_ID\" " 196 + "id=\"123456789\" name=\"MY_CHANGE_ID\">" 197 + "<meta-data definedIn=\"libcore.util.Compat\" " 198 + "sourcePosition=\"libcore/util/Compat.java:10\"/></compat-change>" 199 + "</config>"; 200 String androidExpectedFile = HEADER + "<config>" + 201 "<compat-change description=\"description of ANOTHER_CHANGE\" " 202 + "id=\"23456700\" name=\"ANOTHER_CHANGE\"><meta-data definedIn=\"android.util" 203 + ".SomeClass\" sourcePosition=\"android/util/SomeClass.java:7\"/></compat-change>" 204 + "</config>"; 205 Compilation compilation = 206 Compiler.javac() 207 .withProcessors(new ChangeIdProcessor()) 208 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 209 CompilationSubject.assertThat(compilation).succeeded(); 210 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "libcore.util", 211 "Compat_compat_config.xml").contentsAsString(UTF_8).isEqualTo(libcoreExpectedFile); 212 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "android.util", 213 "SomeClass_compat_config.xml").contentsAsString(UTF_8).isEqualTo( 214 androidExpectedFile); 215 } 216 217 @Test testCompatConfigXmlOutput_innerClass()218 public void testCompatConfigXmlOutput_innerClass() { 219 JavaFileObject[] source = { 220 JavaFileObjects.forSourceLines( 221 "libcore.util.Compat", 222 "package libcore.util;", 223 "import android.compat.annotation.ChangeId;", 224 "import android.compat.annotation.EnabledAfter;", 225 "import android.compat.annotation.Disabled;", 226 "public class Compat {", 227 " public class Inner {", 228 " /**", 229 " * description of", 230 " * MY_CHANGE_ID", 231 " */", 232 " @ChangeId", 233 " static final long MY_CHANGE_ID = 123456789l;", 234 " }", 235 "}"), 236 }; 237 String expectedFile = HEADER + "<config>" + 238 "<compat-change description=\"description of MY_CHANGE_ID\" " 239 + "id=\"123456789\" name=\"MY_CHANGE_ID\"><meta-data definedIn=\"libcore.util" 240 + ".Compat.Inner\" sourcePosition=\"libcore/util/Compat.java:11\"/>" 241 + "</compat-change></config>"; 242 Compilation compilation = 243 Compiler.javac() 244 .withProcessors(new ChangeIdProcessor()) 245 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 246 CompilationSubject.assertThat(compilation).succeeded(); 247 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "libcore.util", 248 "Compat.Inner_compat_config.xml").contentsAsString(UTF_8).isEqualTo(expectedFile); 249 } 250 251 @Test testCompatConfigXmlOutput_interface()252 public void testCompatConfigXmlOutput_interface() { 253 JavaFileObject[] source = { 254 JavaFileObjects.forSourceLines( 255 "libcore.util.Compat", 256 "package libcore.util;", 257 "import android.compat.annotation.ChangeId;", 258 "import android.compat.annotation.EnabledAfter;", 259 "import android.compat.annotation.Disabled;", 260 "public interface Compat {", 261 " /**", 262 " * description of", 263 " * MY_CHANGE_ID", 264 " */", 265 " @ChangeId", 266 " static final long MY_CHANGE_ID = 123456789l;", 267 "}"), 268 }; 269 String expectedFile = HEADER + "<config>" + 270 "<compat-change description=\"description of MY_CHANGE_ID\" " 271 + "id=\"123456789\" name=\"MY_CHANGE_ID\"><meta-data definedIn=\"libcore.util" 272 + ".Compat\" sourcePosition=\"libcore/util/Compat.java:10\"/>" 273 + "</compat-change></config>"; 274 Compilation compilation = 275 Compiler.javac() 276 .withProcessors(new ChangeIdProcessor()) 277 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 278 CompilationSubject.assertThat(compilation).succeeded(); 279 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "libcore.util", 280 "Compat_compat_config.xml").contentsAsString(UTF_8).isEqualTo(expectedFile); 281 } 282 283 @Test testCompatConfigXmlOutput_enum()284 public void testCompatConfigXmlOutput_enum() { 285 JavaFileObject[] source = { 286 JavaFileObjects.forSourceLines( 287 "libcore.util.Compat", 288 "package libcore.util;", 289 "import android.compat.annotation.ChangeId;", 290 "import android.compat.annotation.EnabledAfter;", 291 "import android.compat.annotation.Disabled;", 292 "public enum Compat {", 293 " ENUM_CONSTANT;", 294 " /**", 295 " * description of", 296 " * MY_CHANGE_ID", 297 " */", 298 " @ChangeId", 299 " private static final long MY_CHANGE_ID = 123456789l;", 300 "}"), 301 }; 302 String expectedFile = HEADER + "<config>" + 303 "<compat-change description=\"description of MY_CHANGE_ID\" " 304 + "id=\"123456789\" name=\"MY_CHANGE_ID\"><meta-data definedIn=\"libcore.util" 305 + ".Compat\" sourcePosition=\"libcore/util/Compat.java:11\"/>" 306 + "</compat-change></config>"; 307 Compilation compilation = 308 Compiler.javac() 309 .withProcessors(new ChangeIdProcessor()) 310 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 311 CompilationSubject.assertThat(compilation).succeeded(); 312 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "libcore.util", 313 "Compat_compat_config.xml").contentsAsString(UTF_8).isEqualTo(expectedFile); 314 } 315 316 @Test testBothDisabledAndEnabledAfter()317 public void testBothDisabledAndEnabledAfter() { 318 JavaFileObject[] source = { 319 JavaFileObjects.forSourceLines( 320 "libcore.util.Compat", 321 "package libcore.util;", 322 "import android.compat.annotation.ChangeId;", 323 "import android.compat.annotation.EnabledAfter;", 324 "import android.compat.annotation.Disabled;", 325 "public class Compat {", 326 " @EnabledAfter(targetSdkVersion=29)", 327 " @Disabled", 328 " @ChangeId", 329 " static final long MY_CHANGE_ID = 123456789l;", 330 "}") 331 }; 332 Compilation compilation = 333 Compiler.javac() 334 .withProcessors(new ChangeIdProcessor()) 335 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 336 CompilationSubject.assertThat(compilation).hadErrorContaining( 337 "ChangeId cannot be annotated with both @Disabled and " 338 + "(@EnabledAfter | @EnabledSince)."); 339 } 340 341 @Test testBothDisabledAndEnabledSince()342 public void testBothDisabledAndEnabledSince() { 343 JavaFileObject[] source = { 344 JavaFileObjects.forSourceLines( 345 "libcore.util.Compat", 346 "package libcore.util;", 347 "import android.compat.annotation.ChangeId;", 348 "import android.compat.annotation.EnabledSince;", 349 "import android.compat.annotation.Disabled;", 350 "public class Compat {", 351 " @EnabledSince(targetSdkVersion=29)", 352 " @Disabled", 353 " @ChangeId", 354 " static final long MY_CHANGE_ID = 123456789l;", 355 "}") 356 }; 357 Compilation compilation = 358 Compiler.javac() 359 .withProcessors(new ChangeIdProcessor()) 360 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 361 CompilationSubject.assertThat(compilation).hadErrorContaining( 362 "ChangeId cannot be annotated with both @Disabled and " 363 + "(@EnabledAfter | @EnabledSince)."); 364 } 365 366 367 @Test testBothLoggingOnlyAndEnabledAfter()368 public void testBothLoggingOnlyAndEnabledAfter() { 369 JavaFileObject[] source = { 370 JavaFileObjects.forSourceLines( 371 "libcore.util.Compat", 372 "package libcore.util;", 373 "import android.compat.annotation.ChangeId;", 374 "import android.compat.annotation.EnabledAfter;", 375 "import android.compat.annotation.LoggingOnly;", 376 "public class Compat {", 377 " @EnabledAfter(targetSdkVersion=29)", 378 " @LoggingOnly", 379 " @ChangeId", 380 " static final long MY_CHANGE_ID = 123456789l;", 381 "}") 382 }; 383 Compilation compilation = 384 Compiler.javac() 385 .withProcessors(new ChangeIdProcessor()) 386 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 387 CompilationSubject.assertThat(compilation).hadErrorContaining( 388 "ChangeId cannot be annotated with both @LoggingOnly and " 389 + "(@EnabledAfter | @EnabledSince | @Disabled)."); 390 } 391 392 @Test testBothLoggingOnlyAndEnabledSince()393 public void testBothLoggingOnlyAndEnabledSince() { 394 JavaFileObject[] source = { 395 JavaFileObjects.forSourceLines( 396 "libcore.util.Compat", 397 "package libcore.util;", 398 "import android.compat.annotation.ChangeId;", 399 "import android.compat.annotation.EnabledSince;", 400 "import android.compat.annotation.LoggingOnly;", 401 "public class Compat {", 402 " @EnabledSince(targetSdkVersion=29)", 403 " @LoggingOnly", 404 " @ChangeId", 405 " static final long MY_CHANGE_ID = 123456789l;", 406 "}") 407 }; 408 Compilation compilation = 409 Compiler.javac() 410 .withProcessors(new ChangeIdProcessor()) 411 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 412 CompilationSubject.assertThat(compilation).hadErrorContaining( 413 "ChangeId cannot be annotated with both @LoggingOnly and " 414 + "(@EnabledAfter | @EnabledSince | @Disabled)."); 415 } 416 417 @Test testBothLoggingOnlyAndDisabled()418 public void testBothLoggingOnlyAndDisabled() { 419 JavaFileObject[] source = { 420 JavaFileObjects.forSourceLines( 421 "libcore.util.Compat", 422 "package libcore.util;", 423 "import android.compat.annotation.ChangeId;", 424 "import android.compat.annotation.LoggingOnly;", 425 "import android.compat.annotation.Disabled;", 426 "public class Compat {", 427 " @LoggingOnly", 428 " @Disabled", 429 " @ChangeId", 430 " static final long MY_CHANGE_ID = 123456789l;", 431 "}") 432 }; 433 Compilation compilation = 434 Compiler.javac() 435 .withProcessors(new ChangeIdProcessor()) 436 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 437 CompilationSubject.assertThat(compilation).hadErrorContaining( 438 "ChangeId cannot be annotated with both @LoggingOnly and " 439 + "(@EnabledAfter | @EnabledSince | @Disabled)."); 440 } 441 442 @Test testBothEnabledAfterAndEnabledSince()443 public void testBothEnabledAfterAndEnabledSince() { 444 JavaFileObject[] source = { 445 JavaFileObjects.forSourceLines( 446 "libcore.util.Compat", 447 "package libcore.util;", 448 "import android.compat.annotation.ChangeId;", 449 "import android.compat.annotation.EnabledAfter;", 450 "import android.compat.annotation.EnabledSince;", 451 "public class Compat {", 452 " @EnabledAfter(targetSdkVersion=29)", 453 " @EnabledSince(targetSdkVersion=30)", 454 " @ChangeId", 455 " static final long MY_CHANGE_ID = 123456789l;", 456 "}") 457 }; 458 Compilation compilation = 459 Compiler.javac() 460 .withProcessors(new ChangeIdProcessor()) 461 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 462 CompilationSubject.assertThat(compilation).hadErrorContaining( 463 "ChangeId cannot be annotated with both @EnabledAfter and " 464 + "@EnabledSince. Prefer using the latter."); 465 } 466 467 @Test testLoggingOnly()468 public void testLoggingOnly() { 469 JavaFileObject[] source = { 470 JavaFileObjects.forSourceLines( 471 "libcore.util.Compat", 472 "package libcore.util;", 473 "import android.compat.annotation.ChangeId;", 474 "import android.compat.annotation.LoggingOnly;", 475 "public class Compat {", 476 " @LoggingOnly", 477 " @ChangeId", 478 " static final long MY_CHANGE_ID = 123456789l;", 479 "}") 480 }; 481 String expectedFile = HEADER + "<config>" + 482 "<compat-change id=\"123456789\" loggingOnly=\"true\" name=\"MY_CHANGE_ID\">" + 483 "<meta-data definedIn=\"libcore.util.Compat\" " + 484 "sourcePosition=\"libcore/util/Compat.java:6\"/>" + 485 "</compat-change></config>"; 486 Compilation compilation = 487 Compiler.javac() 488 .withProcessors(new ChangeIdProcessor()) 489 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 490 CompilationSubject.assertThat(compilation).succeeded(); 491 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "libcore.util", 492 "Compat_compat_config.xml").contentsAsString(UTF_8).isEqualTo(expectedFile); 493 } 494 495 @Test testIgnoredParams()496 public void testIgnoredParams() { 497 JavaFileObject[] source = { 498 JavaFileObjects.forSourceLines( 499 "android.compat.Compatibility", 500 "package android.compat;", 501 "import android.compat.annotation.ChangeId;", 502 "public final class Compatibility {", 503 " public static void reportUnconditionalChange(@ChangeId long changeId) {}", 504 " public static boolean isChangeEnabled(@ChangeId long changeId) {", 505 " return true;", 506 " }", 507 "}") 508 }; 509 Compilation compilation = 510 Compiler.javac() 511 .withProcessors(new ChangeIdProcessor()) 512 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 513 CompilationSubject.assertThat(compilation).succeeded(); 514 } 515 516 @Test testOtherClassParams()517 public void testOtherClassParams() { 518 JavaFileObject[] source = { 519 JavaFileObjects.forSourceLines( 520 "android.compat.OtherClass", 521 "package android.compat;", 522 "import android.compat.annotation.ChangeId;", 523 "public final class OtherClass {", 524 " public static void reportUnconditionalChange(@ChangeId long changeId) {}", 525 "}") 526 }; 527 Compilation compilation = 528 Compiler.javac() 529 .withProcessors(new ChangeIdProcessor()) 530 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 531 CompilationSubject.assertThat(compilation).hadErrorContaining( 532 "Non FIELD element annotated with @ChangeId."); 533 } 534 535 @Test testOtherMethodParams()536 public void testOtherMethodParams() { 537 JavaFileObject[] source = { 538 JavaFileObjects.forSourceLines( 539 "android.compat.Compatibility", 540 "package android.compat;", 541 "import android.compat.annotation.ChangeId;", 542 "public final class Compatibility {", 543 " public static void otherMethod(@ChangeId long changeId) {}", 544 "}") 545 }; 546 Compilation compilation = 547 Compiler.javac() 548 .withProcessors(new ChangeIdProcessor()) 549 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 550 CompilationSubject.assertThat(compilation).hadErrorContaining( 551 "Non FIELD element annotated with @ChangeId."); 552 } 553 554 @Test testNonFinal()555 public void testNonFinal() { 556 JavaFileObject[] source = { 557 JavaFileObjects.forSourceLines( 558 "libcore.util.Compat", 559 "package libcore.util;", 560 "import android.compat.annotation.ChangeId;", 561 "import android.compat.annotation.EnabledAfter;", 562 "public class Compat {", 563 " @EnabledAfter(targetSdkVersion=29)", 564 " @ChangeId", 565 " static long MY_CHANGE_ID = 123456789l;", 566 "}") 567 }; 568 Compilation compilation = 569 Compiler.javac() 570 .withProcessors(new ChangeIdProcessor()) 571 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 572 CompilationSubject.assertThat(compilation).hadErrorContaining( 573 "Non constant/final variable annotated with @ChangeId."); 574 } 575 576 @Test testNonLong()577 public void testNonLong() { 578 JavaFileObject[] source = { 579 JavaFileObjects.forSourceLines( 580 "libcore.util.Compat", 581 "package libcore.util;", 582 "import android.compat.annotation.ChangeId;", 583 "import android.compat.annotation.EnabledAfter;", 584 "public class Compat {", 585 " @EnabledAfter(targetSdkVersion=29)", 586 " @ChangeId", 587 " static final int MY_CHANGE_ID = 12345;", 588 "}") 589 }; 590 Compilation compilation = 591 Compiler.javac() 592 .withProcessors(new ChangeIdProcessor()) 593 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 594 CompilationSubject.assertThat(compilation).hadErrorContaining( 595 "Variables annotated with @ChangeId must be of type long."); 596 } 597 598 @Test testNonStatic()599 public void testNonStatic() { 600 JavaFileObject[] source = { 601 JavaFileObjects.forSourceLines( 602 "libcore.util.Compat", 603 "package libcore.util;", 604 "import android.compat.annotation.ChangeId;", 605 "import android.compat.annotation.EnabledAfter;", 606 "public class Compat {", 607 " @EnabledAfter(targetSdkVersion=29)", 608 " @ChangeId", 609 " final long MY_CHANGE_ID = 123456789l;", 610 "}") 611 }; 612 Compilation compilation = 613 Compiler.javac() 614 .withProcessors(new ChangeIdProcessor()) 615 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 616 CompilationSubject.assertThat(compilation).hadErrorContaining( 617 "Non static variable annotated with @ChangeId."); 618 } 619 620 @Test testCompatConfigXmlOutput_hideTag()621 public void testCompatConfigXmlOutput_hideTag() { 622 JavaFileObject[] source = { 623 JavaFileObjects.forSourceLines( 624 "libcore.util.Compat", 625 "package libcore.util;", 626 "import android.compat.annotation.ChangeId;", 627 "import android.compat.annotation.EnabledAfter;", 628 "import android.compat.annotation.Disabled;", 629 "public class Compat {", 630 " public class Inner {", 631 " /**", 632 " * description of MY_CHANGE_ID.", 633 " * @hide", 634 " */", 635 " @ChangeId", 636 " static final long MY_CHANGE_ID = 123456789l;", 637 " }", 638 "}"), 639 }; 640 String expectedFile = HEADER + "<config>" + 641 "<compat-change description=\"description of MY_CHANGE_ID.\" " 642 + "id=\"123456789\" name=\"MY_CHANGE_ID\"><meta-data definedIn=\"libcore.util" 643 + ".Compat.Inner\" sourcePosition=\"libcore/util/Compat.java:11\"/>" 644 + "</compat-change></config>"; 645 Compilation compilation = 646 Compiler.javac() 647 .withProcessors(new ChangeIdProcessor()) 648 .compile(ObjectArrays.concat(mAnnotations, source, JavaFileObject.class)); 649 CompilationSubject.assertThat(compilation).succeeded(); 650 CompilationSubject.assertThat(compilation).generatedFile(CLASS_OUTPUT, "libcore.util", 651 "Compat.Inner_compat_config.xml").contentsAsString(UTF_8).isEqualTo(expectedFile); 652 } 653 654 } 655