Package org.gradle.api.internal.project.taskfactory

Source Code of org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactoryTest

/*
* Copyright 2010 the original author or authors.
*
* 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 org.gradle.api.internal.project.taskfactory;

import org.gradle.api.*;
import org.gradle.api.file.FileCollection;
import org.gradle.api.internal.AbstractTask;
import org.gradle.api.internal.TaskInternal;
import org.gradle.api.internal.project.DefaultProject;
import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.api.tasks.*;
import org.gradle.util.GFileUtils;
import org.gradle.util.HelperUtil;
import org.gradle.util.TemporaryFolder;
import org.gradle.util.TestFile;
import org.jmock.Expectations;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

import static org.gradle.util.Matchers.*;
import static org.gradle.util.WrapUtil.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

@RunWith(JMock.class)
public class AnnotationProcessingTaskFactoryTest {
    private final JUnit4Mockery context = new JUnit4Mockery() {{
        setImposteriser(ClassImposteriser.INSTANCE);
    }};

    private final ITaskFactory delegate = context.mock(ITaskFactory.class);
    private final ProjectInternal project = context.mock(ProjectInternal.class);
    private final Map args = new HashMap();
    @Rule
    public TemporaryFolder tmpDir = new TemporaryFolder();
    private final TestFile testDir = tmpDir.getDir();
    private final File existingFile = testDir.file("file.txt").touch();
    private final File missingFile = testDir.file("missing.txt");
    private final TestFile existingDir = testDir.file("dir").createDir();
    private final File missingDir = testDir.file("missing-dir");
    private final AnnotationProcessingTaskFactory factory = new AnnotationProcessingTaskFactory(delegate);

    @Test
    public void attachesAnActionToTaskForMethodMarkedWithTaskActionAnnotation() {
        final Runnable action = context.mock(Runnable.class);
        final TestTask task = expectTaskCreated(TestTask.class, action);

        context.checking(new Expectations() {{
            one(action).run();
        }});
        task.execute();
    }

    private <T extends Task> T expectTaskCreated(final Class<T> type, final Object... params) {
        DefaultProject project = HelperUtil.createRootProject();
        T task = AbstractTask.injectIntoNewInstance(project, "task", new Callable<T>() {
            public T call() throws Exception {
                if (params.length > 0) {
                    return type.cast(type.getConstructors()[0].newInstance(params));
                } else {
                    return type.newInstance();
                }
            }
        });
        return expectTaskCreated(task);
    }

    private <T extends Task> T expectTaskCreated(final T task) {
        context.checking(new Expectations() {{
            one(delegate).createTask(project, args);
            will(returnValue(task));
        }});

        assertThat(factory.createTask(project, args), sameInstance((Object) task));
        return task;
    }

    @Test
    public void doesNothingToTaskWithNoTaskActionAnnotations() {
        TaskInternal task = expectTaskCreated(DefaultTask.class);

        assertThat(task.getActions(), isEmpty());
    }

    @Test
    public void propagatesExceptionThrownByTaskActionMethod() {
        final Runnable action = context.mock(Runnable.class);
        TestTask task = expectTaskCreated(TestTask.class, action);

        final RuntimeException failure = new RuntimeException();
        context.checking(new Expectations() {{
            one(action).run();
            will(throwException(failure));
        }});

        try {
            task.getActions().get(0).execute(task);
            fail();
        } catch (RuntimeException e) {
            assertThat(e, sameInstance(failure));
        }
    }

    @Test
    public void canHaveMultipleMethodsWithTaskActionAnnotation() {
        final Runnable action = context.mock(Runnable.class);
        TaskWithMultipleMethods task = expectTaskCreated(TaskWithMultipleMethods.class, action);

        context.checking(new Expectations() {{
            exactly(3).of(action).run();
        }});

        task.execute();
    }

    @Test
    public void cachesClassMetaInfo() {
        TaskWithInputFile task = expectTaskCreated(TaskWithInputFile.class, existingFile);
        TaskWithInputFile task2 = expectTaskCreated(TaskWithInputFile.class, missingFile);

        assertThat(task.getActions().get(0), sameInstance((Action) task2.getActions().get(0)));
    }
   
    @Test
    public void failsWhenStaticMethodHasTaskActionAnnotation() {
        assertTaskCreationFails(TaskWithStaticMethod.class,
                "Cannot use @TaskAction annotation on static method TaskWithStaticMethod.doStuff().");
    }

    @Test
    public void failsWhenMethodWithParametersHasTaskActionAnnotation() {
        assertTaskCreationFails(TaskWithParamMethod.class,
                "Cannot use @TaskAction annotation on method TaskWithParamMethod.doStuff() as this method takes parameters.");
    }

    private void assertTaskCreationFails(Class<? extends Task> type, String message) {
        try {
            expectTaskCreated(type);
            fail();
        } catch (GradleException e) {
            assertThat(e.getMessage(), equalTo(message));
        }
    }

    @Test
    public void taskActionWorksForInheritedMethods() {
        final Runnable action = context.mock(Runnable.class);
        TaskWithInheritedMethod task = expectTaskCreated(TaskWithInheritedMethod.class, action);

        context.checking(new Expectations() {{
            one(action).run();
        }});
        task.execute();
    }
   
    @Test
    public void taskActionWorksForOverriddenMethods() {
        final Runnable action = context.mock(Runnable.class);
        TaskWithOverriddenMethod task = expectTaskCreated(TaskWithOverriddenMethod.class, action);

        context.checking(new Expectations() {{
            one(action).run();
        }});
        task.execute();
    }

    @Test
    public void taskActionWorksForProtectedMethods() {
        final Runnable action = context.mock(Runnable.class);
        TaskWithProtectedMethod task = expectTaskCreated(TaskWithProtectedMethod.class, action);

        context.checking(new Expectations() {{
            one(action).run();
        }});
        task.execute();
    }

    @Test
    public void validationActionSucceedsWhenSpecifiedInputFileExists() {
        TaskWithInputFile task = expectTaskCreated(TaskWithInputFile.class, existingFile);
        task.execute();
    }

    @Test
    public void validationActionFailsWhenInputFileNotSpecified() {
        TaskWithInputFile task = expectTaskCreated(TaskWithInputFile.class, new Object[]{null});
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'inputFile'.");
    }

    @Test
    public void validationActionFailsWhenInputFileDoesNotExist() {
        TaskWithInputFile task = expectTaskCreated(TaskWithInputFile.class, missingFile);
        assertValidationFails(task, String.format("Error validating task ':task': File '%s' specified for property 'inputFile' does not exist.",
                task.inputFile));
    }

    @Test
    public void validationActionFailsWhenInputFileIsADirectory() {
        TaskWithInputFile task = expectTaskCreated(TaskWithInputFile.class, existingDir);
        assertValidationFails(task, String.format("Error validating task ':task': File '%s' specified for property 'inputFile' is not a file.",
                task.inputFile));
    }

    @Test
    public void registersSpecifiedInputFile() {
        TaskWithInputFile task = expectTaskCreated(TaskWithInputFile.class, existingFile);
        assertThat(task.getInputs().getFiles().getFiles(), equalTo(toSet(existingFile)));
    }

    @Test
    public void doesNotRegistersInputFileWhenNoneSpecified() {
        TaskWithInputFile task = expectTaskCreated(TaskWithInputFile.class, new Object[]{null});
        assertThat(task.getInputs().getFiles().getFiles(), isEmpty());
    }
   
    @Test
    public void validationActionSucceedsWhenSpecifiedOutputFileIsAFile() {
        TaskWithOutputFile task = expectTaskCreated(TaskWithOutputFile.class, existingFile);
        task.execute();
    }

    @Test
    public void validationActionSucceedsWhenSpecifiedOutputFileIsNotAFile() {
        TaskWithOutputFile task = expectTaskCreated(TaskWithOutputFile.class, new File(testDir, "subdir/output.txt"));

        task.execute();

        assertTrue(new File(testDir, "subdir").isDirectory());
    }

    @Test
    public void validationActionFailsWhenOutputFileNotSpecified() {
        TaskWithOutputFile task = expectTaskCreated(TaskWithOutputFile.class, new Object[]{null});
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'outputFile'.");
    }

    @Test
    public void validationActionFailsWhenSpecifiedOutputFileIsADirectory() {
        TaskWithOutputFile task = expectTaskCreated(TaskWithOutputFile.class, existingDir);
        assertValidationFails(task, String.format(
                "Error validating task ':task': Cannot write to file '%s' specified for property 'outputFile' as it is a directory.",
                task.outputFile));
    }

    @Test
    public void validationActionFailsWhenSpecifiedOutputFileParentIsAFile() {
        TaskWithOutputFile task = expectTaskCreated(TaskWithOutputFile.class, new File(testDir, "subdir/output.txt"));
        GFileUtils.touch(task.outputFile.getParentFile());

        assertValidationFails(task, String.format(
                "Error validating task ':task': Cannot create parent directory '%s' of file specified for property 'outputFile'.",
                task.outputFile.getParentFile()));
    }

    @Test
    public void registersSpecifiedOutputFile() {
        TaskWithOutputFile task = expectTaskCreated(TaskWithOutputFile.class, existingFile);
        assertThat(task.getOutputs().getFiles().getFiles(), equalTo(toSet(existingFile)));
    }

    @Test
    public void doesNotRegisterOutputFileWhenNoneSpecified() {
        TaskWithOutputFile task = expectTaskCreated(TaskWithOutputFile.class, new Object[]{null});
        assertThat(task.getOutputs().getFiles().getFiles(), isEmpty());
    }

    @Test
    public void validationActionSucceedsWhenInputFilesSpecified() {
        TaskWithInputFiles task = expectTaskCreated(TaskWithInputFiles.class, toList(testDir));
        task.execute();
    }

    @Test
    public void validationActionFailsWhenInputFilesNotSpecified() {
        TaskWithInputFiles task = expectTaskCreated(TaskWithInputFiles.class, new Object[]{null});
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'input'.");
    }

    @Test
    public void registersSpecifiedInputFiles() {
        TaskWithInputFiles task = expectTaskCreated(TaskWithInputFiles.class, toList(testDir, missingFile));
        assertThat(task.getInputs().getFiles().getFiles(), equalTo(toSet(testDir, missingFile)));
    }

    @Test
    public void doesNotRegisterInputFilesWhenNoneSpecified() {
        TaskWithInputFiles task = expectTaskCreated(TaskWithInputFiles.class, new Object[]{null});
        assertThat(task.getInputs().getFiles().getFiles(), isEmpty());
    }

    @Test
    public void skipsTaskWhenInputFileCollectionIsEmpty() {
        final FileCollection inputFiles = context.mock(FileCollection.class);
        context.checking(new Expectations() {{
            one(inputFiles).stopExecutionIfEmpty();
            will(throwException(new StopExecutionException()));
        }});

        TaskWithInputFiles task = expectTaskCreated(BrokenTaskWithInputFiles.class, inputFiles);

        task.execute();
    }

    @Test
    public void validationActionSucceedsWhenSpecifiedOutputDirectoryDoesNotExist() {
        TaskWithOutputDir task = expectTaskCreated(TaskWithOutputDir.class, missingDir);
        task.execute();

        assertTrue(task.outputDir.isDirectory());
    }

    @Test
    public void validationActionSucceedsWhenSpecifiedOutputDirectoryIsDirectory() {
        TaskWithOutputDir task = expectTaskCreated(TaskWithOutputDir.class, existingDir);
        task.execute();
    }

    @Test
    public void validationActionFailsWhenOutputDirectoryNotSpecified() {
        TaskWithOutputDir task = expectTaskCreated(TaskWithOutputDir.class, new Object[]{null});
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'outputDir'.");
    }

    @Test
    public void validationActionFailsWhenOutputDirectoryIsAFile() {
        TaskWithOutputDir task = expectTaskCreated(TaskWithOutputDir.class, existingFile);
        assertValidationFails(task, String.format("Error validating task ':task': Cannot create directory '%s' specified for property 'outputDir'.",
                task.outputDir));
    }

    @Test
    public void validationActionFailsWhenParentOfOutputDirectoryIsAFile() {
        TaskWithOutputDir task = expectTaskCreated(TaskWithOutputDir.class, new File(testDir, "subdir/output"));
        GFileUtils.touch(task.outputDir.getParentFile());

        assertValidationFails(task, String.format("Error validating task ':task': Cannot create directory '%s' specified for property 'outputDir'.",
                task.outputDir));
    }

    @Test
    public void registersSpecifiedOutputDirectory() {
        TaskWithOutputDir task = expectTaskCreated(TaskWithOutputDir.class, missingDir);
        assertThat(task.getOutputs().getFiles().getFiles(), equalTo(toSet(missingDir)));
    }

    @Test
    public void doesNotRegisterOutputDirectoryWhenNoneSpecified() {
        TaskWithOutputDir task = expectTaskCreated(TaskWithOutputDir.class, new Object[]{null});
        assertThat(task.getOutputs().getFiles().getFiles(), isEmpty());
    }

    @Test
    public void validationActionSucceedsWhenSpecifiedInputDirectoryIsDirectory() {
        TaskWithInputDir task = expectTaskCreated(TaskWithInputDir.class, existingDir);
        task.execute();
    }

    @Test
    public void validationActionFailsWhenInputDirectoryNotSpecified() {
        TaskWithInputDir task = expectTaskCreated(TaskWithInputDir.class, new Object[]{null});
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'inputDir'.");
    }
   
    @Test
    public void validationActionFailsWhenInputDirectoryDoesNotExist() {
        TaskWithInputDir task = expectTaskCreated(TaskWithInputDir.class, missingDir);
        assertValidationFails(task, String.format("Error validating task ':task': Directory '%s' specified for property 'inputDir' does not exist.",
                task.inputDir));
    }

    @Test
    public void validationActionFailsWhenInputDirectoryIsAFile() {
        TaskWithInputDir task = expectTaskCreated(TaskWithInputDir.class, existingFile);
        GFileUtils.touch(task.inputDir);

        assertValidationFails(task, String.format(
                "Error validating task ':task': Directory '%s' specified for property 'inputDir' is not a directory.", task.inputDir));
    }

    @Test
    public void registersSpecifiedInputDirectory() {
        TaskWithInputDir task = expectTaskCreated(TaskWithInputDir.class, existingDir);
        File file = existingDir.file("some-file").createFile();
        assertThat(task.getInputs().getFiles().getFiles(), equalTo(toSet(file)));
    }

    @Test
    public void doesNotRegisterInputDirectoryWhenNoneSpecified() {
        TaskWithInputDir task = expectTaskCreated(TaskWithInputDir.class, new Object[]{null});
        assertThat(task.getInputs().getFiles().getFiles(), isEmpty());
    }

    @Test
    public void skipsTaskWhenInputDirectoryIsEmptyAndSkipWhenEmpty() {
        TaskWithInputDir task = expectTaskCreated(BrokenTaskWithInputDir.class, existingDir);
        task.execute();
    }

    @Test
    public void skipsTaskWhenInputDirectoryIsDoesNotExistAndSkipWhenEmpty() {
        TaskWithInputDir task = expectTaskCreated(BrokenTaskWithInputDir.class, missingDir);
        task.execute();
    }

    @Test
    public void validationActionSucceedsWhenInputValueSpecified() {
        TaskWithInput task = expectTaskCreated(TaskWithInput.class, "value");
        task.execute();
    }

    @Test
    public void validationActionFailsWhenInputValueNotSpecified() {
        TaskWithInput task = expectTaskCreated(TaskWithInput.class, new Object[]{null});
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'inputValue'.");
    }

    @Test
    public void registersSpecifiedInputValue() {
        TaskWithInput task = expectTaskCreated(TaskWithInput.class, "value");
        assertThat(task.getInputs().getProperties().get("inputValue"), equalTo((Object) "value"));
    }

    @Test
    public void validationActionSucceedsWhenPropertyMarkedWithOptionalAnnotationNotSpecified() {
        TaskWithOptionalInputFile task = expectTaskCreated(TaskWithOptionalInputFile.class);
        task.execute();
    }

    @Test
    public void validatesNestedBeans() {
        TaskWithNestedBean task = expectTaskCreated(TaskWithNestedBean.class, new Object[]{null});
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'bean.inputFile'.");
    }

    @Test
    public void registersInputPropertyForNestedBeanClass() {
        TaskWithNestedBean task = expectTaskCreated(TaskWithNestedBean.class, new Object[]{null});
        assertThat(task.getInputs().getProperties().get("bean.class"), equalTo((Object) Bean.class.getName()));
    }

    @Test
    public void doesNotRegisterInputPropertyWhenNestedBeanIsNull() {
        TaskWithOptionalNestedBean task = expectTaskCreated(TaskWithOptionalNestedBean.class);
        assertThat(task.getInputs().getProperties().get("bean.class"), nullValue());
    }

    @Test
    public void validationFailsWhenNestedBeanIsNull() {
        TaskWithNestedBean task = expectTaskCreated(TaskWithNestedBean.class, new Object[]{null});
        task.bean = null;
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'bean'.");
    }

    @Test
    public void validationSucceedsWhenNestedBeanIsNullAndMarkedOptional() {
        TaskWithOptionalNestedBean task = expectTaskCreated(TaskWithOptionalNestedBean.class);
        task.execute();
    }

    @Test
    public void canAttachAnnotationToGroovyProperty() {
        InputFileTask task = expectTaskCreated(InputFileTask.class);
        assertValidationFails(task, "Error validating task ':task': No value has been specified for property 'srcFile'.");
    }
   
    private void assertValidationFails(TaskInternal task, String expectedErrorMessage) {
        try {
            task.execute();
            fail();
        } catch (GradleException e) {
            assertThat(e.getCause(), instanceOf(InvalidUserDataException.class));
            assertThat(e.getCause().getMessage(), equalTo(expectedErrorMessage));
        }
    }

    public static class TestTask extends DefaultTask {
        final Runnable action;

        public TestTask(Runnable action) {
            this.action = action;
        }

        @TaskAction
        public void doStuff() {
            action.run();
        }
    }

    public static class TaskWithInheritedMethod extends TestTask {
        public TaskWithInheritedMethod(Runnable action) {
            super(action);
        }
    }

    public static class TaskWithOverriddenMethod extends TestTask {
        private final Runnable action;

        public TaskWithOverriddenMethod(Runnable action) {
            super(null);
            this.action = action;
        }

        @Override @TaskAction
        public void doStuff() {
            action.run();
        }
    }

    public static class TaskWithProtectedMethod extends DefaultTask {
        private final Runnable action;

        public TaskWithProtectedMethod(Runnable action) {
            this.action = action;
        }

        @TaskAction
        protected void doStuff() {
            action.run();
        }
    }

    public static class TaskWithStaticMethod extends DefaultTask {
        @TaskAction
        public static void doStuff() {
        }
    }

    public static class TaskWithMultipleMethods extends TestTask {
        public TaskWithMultipleMethods(Runnable action) {
            super(action);
        }

        @TaskAction
        public void aMethod() {
            action.run();
        }

        @TaskAction
        public void anotherMethod() {
            action.run();
        }
    }

    public static class TaskWithParamMethod extends DefaultTask {
        @TaskAction
        public void doStuff(int value) {
        }
    }

    public static class TaskWithInputFile extends DefaultTask {
        File inputFile;

        public TaskWithInputFile(File inputFile) {
            this.inputFile = inputFile;
        }

        @InputFile
        public File getInputFile() {
            return inputFile;
        }
    }

    public static class TaskWithInputDir extends DefaultTask {
        File inputDir;

        public TaskWithInputDir(File inputDir) {
            this.inputDir = inputDir;
        }

        @InputDirectory
        public File getInputDir() {
            return inputDir;
        }
    }

    public static class TaskWithInput extends DefaultTask {
        String inputValue;

        public TaskWithInput(String inputValue) {
            this.inputValue = inputValue;
        }

        @Input
        public String getInputValue() {
            return inputValue;
        }
    }

    public static class BrokenTaskWithInputDir extends TaskWithInputDir {
        public BrokenTaskWithInputDir(File inputDir) {
            super(inputDir);
        }

        @Override @InputDirectory @SkipWhenEmpty
        public File getInputDir() {
            return super.getInputDir();
        }

        @TaskAction
        public void doStuff() {
            fail();
        }

    }

    public static class TaskWithOutputFile extends DefaultTask {
        File outputFile;

        public TaskWithOutputFile(File outputFile) {
            this.outputFile = outputFile;
        }

        @OutputFile
        public File getOutputFile() {
            return outputFile;
        }
    }

    public static class TaskWithOutputDir extends DefaultTask {
        File outputDir;

        public TaskWithOutputDir(File outputDir) {
            this.outputDir = outputDir;
        }

        @OutputDirectory
        public File getOutputDir() {
            return outputDir;
        }
    }

    public static class TaskWithInputFiles extends DefaultTask {
        Iterable<? extends File> input;

        public TaskWithInputFiles(Iterable<? extends File> input) {
            this.input = input;
        }

        @InputFiles @SkipWhenEmpty
        public Iterable<? extends File> getInput() {
            return input;
        }
    }

    public static class BrokenTaskWithInputFiles extends TaskWithInputFiles {
        public BrokenTaskWithInputFiles(Iterable<? extends File> input) {
            super(input);
        }

        @TaskAction
        public void doStuff() {
            fail();
        }
    }

    public static class TaskWithOptionalInputFile extends DefaultTask {
        @InputFile @Optional
        public File getInputFile() {
            return null;
        }
    }

    public static class TaskWithNestedBean extends DefaultTask {
        Bean bean = new Bean();

        public TaskWithNestedBean(File inputFile) {
            bean.inputFile = inputFile;
        }

        @Nested
        public Bean getBean() {
            return bean;
        }
    }

    public static class TaskWithOptionalNestedBean extends DefaultTask {
        @Nested @Optional
        public Bean getBean() {
            return null;
        }
    }

    public static class Bean {
        @InputFile
        File inputFile;

        public File getInputFile() {
            return inputFile;
        }
    }
}
TOP

Related Classes of org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactoryTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.