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

org.gradle.api.internal.collections.AbstractElementSourceTest.groovy Maven / Gradle / Ivy

There is a newer version: 8.6
Show newest version
/*
 * Copyright 2018 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.collections

import org.gradle.api.Action
import org.gradle.api.internal.provider.AbstractReadOnlyProvider
import org.gradle.api.internal.provider.ChangingValue
import org.gradle.api.internal.provider.ChangingValueHandler
import org.gradle.api.internal.provider.CollectionProviderInternal
import org.gradle.api.internal.provider.ProviderInternal
import spock.lang.Specification

abstract class AbstractElementSourceTest extends Specification {
    abstract ElementSource getSource()

    abstract List iterationOrder(CharSequence... values)

    def "can add a realized element"() {
        when:
        source.add("foo")

        then:
        source.size() == 1
        source.contains("foo")
    }

    def "can add a provider"() {
        when:
        source.addPending(provider("foo"))

        then:
        source.size() == 1
        source.contains("foo")
    }

    def "can add a provider of iterable"() {
        when:
        source.addPendingCollection(setProvider("foo", "bar"))

        then:
        source.size() == 2
        source.containsAll("foo", "bar")
    }

    def "iterates elements in the correct order"() {
        when:
        source.addPending(provider("foo"))
        source.add("bar")
        source.add("baz")
        source.addPending(provider("fizz"))
        source.addPendingCollection(setProvider("fuzz", "bazz"))

        then:
        source.iteratorNoFlush().collect() == iterationOrder("bar", "baz")

        and:
        source.iterator().collect() == iterationOrder("foo", "bar", "baz", "fizz", "fuzz", "bazz")
    }

    def "once realized, provided values appear like realized values"() {
        when:
        source.addPending(provider("foo"))
        source.add("bar")
        source.add("baz")
        source.addPending(provider("fizz"))
        source.addPendingCollection(setProvider("fuzz", "bazz"))

        then:
        source.iteratorNoFlush().collect() == iterationOrder("bar", "baz")

        when:
        source.realizePending()

        then:
        source.iteratorNoFlush().collect() == iterationOrder("foo", "bar", "baz", "fizz", "fuzz", "bazz")
    }

    def "can add only providers"() {
        when:
        source.addPending(provider("foo"))
        source.addPending(provider("bar"))
        source.addPending(provider("baz"))
        source.addPending(provider("fizz"))

        then:
        source.iteratorNoFlush().collect() == []

        and:
        source.iterator().collect() == iterationOrder("foo", "bar", "baz", "fizz")
    }

    def "can add only realized providers"() {
        when:
        source.add("foo")
        source.add("bar")
        source.add("baz")
        source.add("fizz")

        then:
        source.iteratorNoFlush().collect() == iterationOrder("foo", "bar", "baz", "fizz")

        and:
        source.iterator().collect() == iterationOrder("foo", "bar", "baz", "fizz")
    }

    def "can add only providers of iterable"() {
        when:
        source.addPendingCollection(setProvider("foo", "bar"))
        source.addPendingCollection(setProvider("baz", "fizz", "fuzz"))
        source.addPendingCollection(setProvider("buzz"))

        then:
        source.iteratorNoFlush().collect() == []

        and:
        source.iterator().collect() == iterationOrder("foo", "bar", "baz", "fizz", "fuzz", "buzz")
    }

    def "can remove a realized element"() {
        given:
        source.add("foo")
        source.addPending(provider("bar"))
        source.add("baz")

        expect:
        source.remove("foo")

        and:
        source.size() == 2
        source.iterator().collect() == iterationOrder("bar", "baz")

        and:
        !source.remove("foo")
    }

    def "can remove a provider"() {
        given:
        def bar = provider("bar")
        source.add("foo")
        source.addPending(bar)
        source.add("baz")

        expect:
        source.removePending(bar)

        and:
        source.size() == 2
        source.iterator().collect() == iterationOrder("foo", "baz")
    }

    def "can remove a provider of iterable"() {
        given:
        def barBazzFizz = setProvider("bar", "bazz", "fizz")
        source.add("foo")
        source.addPendingCollection(barBazzFizz)
        source.add("baz")

        expect:
        source.removePendingCollection(barBazzFizz)

        and:
        source.size() == 2
        source.iterator().collect() == iterationOrder("foo", "baz")
    }

    def "can handle elements with changing values"() {
        def provider1 = setProvider("baz", "fooz")
        def provider2 = provider("bar")

        when:
        source.add("foo")
        source.addPendingCollection(provider1)
        source.addPending(provider2)
        source.add("fizz")

        then:
        source.iteratorNoFlush().collect() == iterationOrder("foo", "fizz")

        when:
        provider1.value = ["fuzz", "buzz"]

        then:
        source.iterator().collect() == iterationOrder("foo", "fuzz", "buzz", "bar", "fizz")

        when:
        provider1.value = ["baz"]

        then:
        source.iterator().collect() == iterationOrder("foo", "baz", "bar", "fizz")

        when:
        provider2.value = "fooz"

        then:
        source.iterator().collect() == iterationOrder("foo", "baz", "fooz", "fizz")
    }

    def "comodification with iterator causes an exception" () {
        given:
        def provider = provider("baz")
        def providerOfSet = setProvider("fuzz", "buzz")
        source.add("foo")
        source.addPending(provider)
        source.addPendingCollection(providerOfSet)

        when:
        def iterator = source.iteratorNoFlush()
        source.add("bar")
        iterator.next()

        then:
        thrown(ConcurrentModificationException)

        when:
        iterator = source.iteratorNoFlush()
        source.remove("bar")
        iterator.next()

        then:
        thrown(ConcurrentModificationException)

        when:
        iterator = source.iteratorNoFlush()
        source.realizePending()
        iterator.next()

        then:
        thrown(ConcurrentModificationException)

        when:
        iterator = source.iteratorNoFlush()
        iterator.next()
        source.remove("foo")
        iterator.remove()

        then:
        thrown(ConcurrentModificationException)

        when:
        iterator = source.iteratorNoFlush()
        providerOfSet.value = ["fizz"]
        iterator.next()

        then:
        thrown(ConcurrentModificationException)
    }

    ProviderInternal provider(String value) {
        return new TypedProvider(String, value)
    }

    ProviderInternal provider(StringBuffer value) {
        return new TypedProvider(StringBuffer, value)
    }

    CollectionProviderInternal> setProvider(String... values) {
        return new TypedProviderOfSet(String, values as LinkedHashSet)
    }

    CollectionProviderInternal> setProvider(StringBuffer... values) {
        return new TypedProviderOfSet(StringBuffer, values as LinkedHashSet)
    }

    private static class TypedProvider extends AbstractReadOnlyProvider implements ChangingValue {
        final Class type
        T value
        final ChangingValueHandler changingValue = new ChangingValueHandler()

        TypedProvider(Class type, T value) {
            this.type = type
            this.value = value
        }

        @Override
        Class getType() {
            return type
        }

        @Override
        T getOrNull() {
            return value
        }

        void setValue(T value) {
            T previousValue = this.value
            this.value = value
            changingValue.handle(previousValue)
        }

        @Override
        void onValueChange(Action action) {
            changingValue.onValueChange(action)
        }
    }

    private static class TypedProviderOfSet extends AbstractReadOnlyProvider> implements CollectionProviderInternal>, ChangingValue> {
        final Class type
        Set value
        final ChangingValueHandler> changingValue = new ChangingValueHandler>()

        TypedProviderOfSet(Class type, Set value) {
            this.type = type
            this.value = value
        }

        @Override
        Class getElementType() {
            return type
        }

        @Override
        Set getOrNull() {
            return value
        }

        @Override
        int size() {
            return value.size()
        }

        void setValue(Set value) {
            Set previousValue = this.value
            this.value = value
            changingValue.handle(previousValue)
        }

        @Override
        void onValueChange(Action> action) {
            changingValue.onValueChange(action)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy