All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gradle.api.internal.tasks.DefaultTaskDependencyTest.groovy Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2007, 2008 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.tasks

import org.gradle.api.Buildable
import org.gradle.api.Task
import org.gradle.api.internal.provider.ProviderInternal
import org.gradle.api.tasks.TaskDependency
import org.gradle.api.tasks.TaskProvider
import org.gradle.internal.typeconversion.UnsupportedNotationException
import org.gradle.util.TextUtil
import spock.lang.Specification

import java.util.concurrent.Callable

import static org.gradle.util.WrapUtil.toSet

class DefaultTaskDependencyTest extends Specification {
    private final TaskResolver resolver = Mock(TaskResolver.class)
    private final DefaultTaskDependency dependency = new DefaultTaskDependency(resolver)
    private Task task
    private Task otherTask

    def setup() {
        task = Mock(Task)
        otherTask = Mock(Task)
    }

    def "has no dependencies by default"() {
        expect:
        dependency.getDependencies(task) == emptySet()
    }

    def "can depend on char sequence"() {
        def input = new StringBuilder("other")

        given:
        1 * resolver.resolveTask("other") >> otherTask

        when:
        dependency.add(input)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can depend on a task instance"() {
        when:
        dependency.add(otherTask)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can depend on a task dependency"() {
        def otherDependency = Mock(TaskDependency)

        given:
        1 * otherDependency.getDependencies(task) >> toSet(otherTask)

        when:
        dependency.add(otherDependency);

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can depend on a closure"() {
        when:
        dependency.add({ Task suppliedTask ->
            assert suppliedTask == task
            otherTask
        })

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can depend on a closure that returns null"() {
        when:
        dependency.add({ null })

        then:
        dependency.getDependencies(task) == emptySet()
    }

    def "can depend on a buildable"() {
        Buildable buildable = Mock(Buildable)
        TaskDependency otherDependency = Mock(TaskDependency)

        given:
        1 * buildable.getBuildDependencies() >> otherDependency
        1 * otherDependency.getDependencies(task) >> toSet(otherTask)

        when:
        dependency.add(buildable)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can depend on an iterable"() {
        List tasks = [otherTask]
        Iterable iterable = { tasks.iterator() } as Iterable

        when:
        dependency.add(iterable)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can depend on a callable"() {
        Callable callable = Mock(Callable)

        given:
        1 * callable.call() >> otherTask

        when:
        dependency.add(callable)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can depend on a callable that returns null"() {
        Callable callable = Mock(Callable)

        given:
        1 * callable.call() >> null

        when:
        dependency.add(callable)

        then:
        dependency.getDependencies(task) == emptySet()
    }

    def "delegates to TaskDependencyContainer to determine build dependencies"() {
        def dep = Mock(TaskDependencyContainer)

        given:
        1 * dep.visitDependencies(_) >> { TaskDependencyResolveContext context -> context.add(otherTask) }

        when:
        dependency.add(dep)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "delegates to nested TaskDependencyContainer to determine build dependencies"() {
        def dep = Mock(TaskDependencyContainer)
        def nested = Mock(TaskDependencyContainer)

        given:
        1 * dep.visitDependencies(_) >> { TaskDependencyResolveContext context -> context.add(nested) }
        1 * nested.visitDependencies(_) >> { TaskDependencyResolveContext context -> context.add(otherTask) }

        when:
        dependency.add(dep)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "fails when a TaskDependencyContainer has an unsupported value"() {
        def dep = Mock(TaskDependencyContainer)

        given:
        1 * dep.visitDependencies(_) >> { TaskDependencyResolveContext context -> context.add(123) }
        dependency.add(dep)

        when:
        dependency.getDependencies(task)

        then:
        def e = thrown(TaskDependencyResolveException)
        e.cause instanceof UnsupportedNotationException
        e.cause.message.startsWith('Cannot convert 123 to a task.')
    }

    def "fails for other types"() {
        when:
        dependency.add(12)
        dependency.getDependencies(task)

        then:
        def e = thrown(TaskDependencyResolveException)
        e.cause instanceof UnsupportedNotationException
        e.cause.message == TextUtil.toPlatformLineSeparators('''Cannot convert 12 to a task.
The following types/formats are supported:
  - A String or CharSequence task name or path
  - A TaskReference instance
  - A Task instance
  - A Buildable instance
  - A TaskDependency instance
  - A Provider that represents a task output
  - A Provider instance that returns any of these types
  - A Closure instance that returns any of these types
  - A Callable instance that returns any of these types
  - An Iterable, Collection, Map or array instance that contains any of these types''')
    }

    def "fails for char sequence when no resolver provided"() {
        DefaultTaskDependency dependency = new DefaultTaskDependency()
        StringBuffer dep = new StringBuffer("task")

        when:
        dependency.add(dep)
        dependency.getDependencies(task)

        then:
        def e = thrown(TaskDependencyResolveException)
        e.cause instanceof UnsupportedNotationException
        e.cause.message.startsWith "Cannot convert $dep to a task."
    }

    def "flattens collections"() {
        when:
        dependency.add(toSet(otherTask))

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "flattens maps"() {
        when:
        dependency.add([key: otherTask])

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "flattens arrays"() {
        when:
        dependency.add([[otherTask] as Task[]])

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    def "can mutate dependency values by removing a Task instance from dependency"() {
        given:
        dependency.add(otherTask)

        when:
        dependency.mutableValues.remove(otherTask)

        then:
        dependency.getDependencies(task) == toSet()
    }

    def "can mutate dependency values by removing a Task instance from dependency containing a Provider to the Task instance"() {
        given:
        otherTask.name >> "otherTask"

        def provider = Mock(TestTaskProvider)
        provider.type >> otherTask.class
        provider.name >> otherTask.name
        dependency.add(provider)

        when:
        dependency.mutableValues.remove(otherTask)

        then:
        dependency.getDependencies(task) == toSet()
    }

    def "can mutate dependency values by removing a Provider instance from dependency containing the Provider instance"() {
        given:
        def provider = Mock(TestTaskProvider)
        dependency.add(provider)

        when:
        dependency.mutableValues.remove(provider)

        then:
        dependency.getDependencies(task) == toSet()
    }

    def "can nest iterables and maps and closures and callables"() {
        Map nestedMap = [task: otherTask]
        Iterable nestedCollection = [nestedMap]
        Callable nestedCallable = { nestedCollection } as Callable
        Closure nestedClosure = { nestedCallable }
        List collection = [nestedClosure]
        Closure closure = { collection }
        Object[] array = [closure] as Object[]
        Map map = [key: array]
        Callable callable = { map } as Callable

        when:
        dependency.add(callable)

        then:
        dependency.getDependencies(task) == toSet(otherTask)
    }

    static emptySet() {
        return [] as Set
    }

    interface TestTaskProvider extends ProviderInternal, TaskProvider {
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy