| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.jack.error; |
| |
| import com.google.common.io.Files; |
| |
| import com.android.jack.JackAbortException; |
| import com.android.jack.backend.jayce.JayceFileImporter.CollisionPolicy; |
| import com.android.jack.errorhandling.annotationprocessor.ResourceAnnotationProcessor; |
| import com.android.jack.errorhandling.annotationprocessor.ResourceAnnotationTest; |
| import com.android.jack.errorhandling.annotationprocessor.SourceAnnotationProcessor; |
| import com.android.jack.errorhandling.annotationprocessor.SourceAnnotationTest; |
| import com.android.jack.errorhandling.annotationprocessor.SourceErrorAnnotationTest; |
| import com.android.jack.frontend.FrontendCompilationException; |
| import com.android.jack.resource.ResourceImporter; |
| import com.android.jack.resource.ResourceReadingException; |
| import com.android.jack.test.TestsProperties; |
| import com.android.jack.test.helper.ErrorTestHelper; |
| import com.android.jack.test.junit.KnownIssue; |
| import com.android.jack.test.toolchain.AbstractTestTools; |
| import com.android.jack.test.toolchain.IncrementalToolchain; |
| import com.android.jack.test.toolchain.JackApiToolchainBase; |
| |
| import junit.framework.Assert; |
| |
| import org.jf.dexlib.ClassDefItem; |
| import org.jf.dexlib.DexFile; |
| import org.junit.Test; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.LineNumberReader; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import javax.annotation.Nonnull; |
| |
| /** |
| * JUnit test checking Jack behavior when using annotation processor. |
| */ |
| public class AnnotationProcessorErrorTest { |
| |
| /** |
| * Checks that compilation succeed when running annotation processor to generate resource file. |
| */ |
| @Test |
| public void testAnnotationProcessorError002() throws Exception { |
| runAnnotProcBuildingResource(new ErrorTestHelper()); |
| } |
| |
| /** |
| * Checks that last compilation failed since the resource created by annotation processor already |
| * exist. |
| */ |
| @Test |
| public void testAnnotationProcessorError003() throws Exception { |
| ErrorTestHelper te = new ErrorTestHelper(); |
| |
| runAnnotProcBuildingResource(te); |
| |
| JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); |
| jackApiToolchain.setAnnotationProcessorClasses( |
| Collections.singletonList(ResourceAnnotationProcessor.class.getName())); |
| ByteArrayOutputStream errOut = new ByteArrayOutputStream(); |
| jackApiToolchain.setErrorStream(errOut); |
| jackApiToolchain.addResourceDir(te.getOutputDexFolder()); |
| jackApiToolchain.addProperty(ResourceImporter.RESOURCE_COLLISION_POLICY.getName(), |
| CollisionPolicy.FAIL.name()); |
| |
| try { |
| |
| jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath()) |
| .addToClasspath(te.getJackFolder()) |
| .srcToExe(te.getOutputDexFolder(), /* zipFile = */ false, te.getSourceFolder()); |
| |
| Assert.fail(); |
| } catch (JackAbortException e) { |
| Assert.assertTrue(e.getCause() instanceof ResourceReadingException); |
| // Failure is ok since created file already exists |
| } |
| } |
| |
| /** |
| * Checks that compilation failed since the source file generated by the annotation processor |
| * does not compile. |
| */ |
| @Test |
| public void testAnnotationProcessorError004() throws Exception { |
| ErrorTestHelper te = new ErrorTestHelper(); |
| |
| buildAnnotationRequiredByAnnotationProc(te, new Class<?>[] {SourceAnnotationTest.class, |
| SourceErrorAnnotationTest.class}); |
| |
| AbstractTestTools.createFile(te.getSourceFolder(), "jack.incremental", "A.java", "package jack.incremental;\n" |
| + "import " + SourceErrorAnnotationTest.class.getName() + ";\n" |
| + "@" + SourceErrorAnnotationTest.class.getSimpleName() + "\n" |
| + "public class A {}\n"); |
| |
| |
| JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); |
| jackApiToolchain.setAnnotationProcessorClasses( |
| Collections.singletonList(SourceAnnotationProcessor.class.getName())); |
| ByteArrayOutputStream errOut = new ByteArrayOutputStream(); |
| jackApiToolchain.setErrorStream(errOut); |
| |
| try { |
| jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath()) |
| .addToClasspath(te.getJackFolder()) |
| .srcToExe(te.getOutputDexFolder(), /* zipFile = */ false, te.getSourceFolder()); |
| Assert.fail(); |
| } catch (FrontendCompilationException ex) { |
| // Failure is ok since source generated by annotation processor does not compile. |
| } finally { |
| Assert.assertTrue(errOut.toString().contains("Syntax error on tokens, delete these tokens")); |
| } |
| } |
| |
| /** |
| * Checks that compilation succeed to compile source file generated by the annotation processor. |
| */ |
| @Test |
| public void testAnnotationProcessorError005() throws Exception { |
| ErrorTestHelper te = new ErrorTestHelper(); |
| |
| buildAnnotationRequiredByAnnotationProc(te, new Class<?>[] {SourceAnnotationTest.class, |
| SourceErrorAnnotationTest.class}); |
| |
| AbstractTestTools.createFile(te.getSourceFolder(), "jack.incremental", "A.java", "package jack.incremental;\n" |
| + "import " + SourceAnnotationTest.class.getName() + ";\n" |
| + "@" + SourceAnnotationTest.class.getSimpleName() + "\n" |
| + "public class A {}\n"); |
| |
| JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); |
| jackApiToolchain.setAnnotationProcessorClasses( |
| Collections.singletonList(SourceAnnotationProcessor.class.getName())); |
| |
| File dexOutput = te.getOutputDexFolder(); |
| jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath()) |
| .addToClasspath(te.getJackFolder()) |
| .srcToExe(dexOutput, /* zipFile = */ false, te.getSourceFolder()); |
| |
| DexFile dexFile = new DexFile(new File(dexOutput, jackApiToolchain.getBinaryFileName())); |
| List<String> sourceFileInDex = new ArrayList<String>(); |
| for (ClassDefItem classDef : dexFile.ClassDefsSection.getItems()) { |
| sourceFileInDex.add(classDef.getSourceFile().getStringValue()); |
| } |
| |
| Assert.assertTrue(sourceFileInDex.contains("ADuplicated.java")); |
| Assert.assertTrue(sourceFileInDex.contains("A.java")); |
| } |
| |
| private void runAnnotProcBuildingResource(@Nonnull ErrorTestHelper te) throws Exception { |
| |
| buildAnnotationRequiredByAnnotationProc(te, new Class<?>[] {ResourceAnnotationTest.class}); |
| |
| AbstractTestTools.createFile(te.getSourceFolder(), "jack.incremental", "A.java", "package jack.incremental;\n" |
| + "import " + ResourceAnnotationTest.class.getName() + ";\n" |
| + "@" + ResourceAnnotationTest.class.getSimpleName() + "\n" |
| + "public class A {}\n"); |
| |
| JackApiToolchainBase jackApiToolchain = AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); |
| jackApiToolchain.setAnnotationProcessorClasses( |
| Collections.singletonList(ResourceAnnotationProcessor.class.getName())); |
| |
| jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath()) |
| .addToClasspath(te.getJackFolder()) |
| .srcToExe(te.getOutputDexFolder(), /* zipFile = */ false, te.getSourceFolder()); |
| |
| File discoverFile = new File(te.getOutputDexFolder(), ResourceAnnotationProcessor.FILENAME); |
| Assert.assertTrue(discoverFile.exists()); |
| LineNumberReader lnr = new LineNumberReader(new FileReader(discoverFile)); |
| Assert.assertEquals(ResourceAnnotationTest.class.getName(), lnr.readLine()); |
| Assert.assertEquals("jack.incremental.A", lnr.readLine()); |
| Assert.assertNull(lnr.readLine()); |
| lnr.close(); |
| } |
| |
| private void buildAnnotationRequiredByAnnotationProc(@Nonnull ErrorTestHelper te, |
| Class<?>[] annotationClasses) throws Exception { |
| File targetAnnotationFileFolder = |
| new File(te.getSourceFolder(), "com/android/jack/errorhandling/annotationprocessor/"); |
| if (!targetAnnotationFileFolder.mkdirs()) { |
| Assert.fail("Fail to create folder " + targetAnnotationFileFolder.getAbsolutePath()); |
| } |
| |
| for (Class<?> annotationClass : annotationClasses) { |
| Files.copy(new File(TestsProperties.getJackRootDir(), |
| "jack/tests/com/android/jack/errorhandling/annotationprocessor/" |
| + annotationClass.getSimpleName() + ".java"), new File( |
| targetAnnotationFileFolder, annotationClass.getSimpleName() + ".java")); |
| } |
| |
| // Compile annotation to a jack file |
| JackApiToolchainBase jackApiToolchain = |
| AbstractTestTools.getCandidateToolchain(JackApiToolchainBase.class); |
| jackApiToolchain.addToClasspath(jackApiToolchain.getDefaultBootClasspath()) |
| .srcToLib(te.getJackFolder(), false /* zipFiles = */, te.getSourceFolder()); |
| |
| AbstractTestTools.deleteTempDir(te.getSourceFolder()); |
| } |
| } |