<commit_before>/*
 * Copyright 2019 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.configurationcache

import org.gradle.internal.reflect.problems.ValidationProblemId
import org.gradle.internal.reflect.validation.ValidationMessageChecker
import org.gradle.internal.reflect.validation.ValidationTestFor
import spock.lang.Issue

import static org.junit.Assume.assumeFalse

class ConfigurationCacheBuildOptionsIntegrationTest extends AbstractConfigurationCacheIntegrationTest implements ValidationMessageChecker {

    def setup() {
        expectReindentedValidationMessage()
    }

    @Issue("https://github.com/gradle/gradle/issues/13333")
    def "absent #operator orElse #orElseKind used as task input"() {

        assumeFalse(
            'task dependency inference for orElse(taskOutput) not implemented yet!',
            orElseKind == 'task output'
        )

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """
            abstract class PrintString : DefaultTask() {
                @get:Input
                abstract val string: Property<String>
                @TaskAction
                fun printString() {
                    println("The string is " + string.get())
                }
            }
            abstract class ProduceString : DefaultTask() {
                @get:OutputFile
                abstract val outputFile: RegularFileProperty
                @TaskAction
                fun printString() {
                    outputFile.get().asFile.writeText("absent")
                }
            }
            val producer = tasks.register<ProduceString>("produceString") {
                outputFile.set(layout.buildDirectory.file("output.txt"))
            }
            val stringProvider = providers
                .$operator("string")
                .orElse($orElseArgument)
            tasks.register<PrintString>("printString") {
                string.set(stringProvider)
            }
        """
        def printString = { string ->
            switch (operator) {
                case 'systemProperty':
                    configurationCacheRun "printString", "-Dstring=$string"
                    break
                case 'environmentVariable':
                    withEnvironmentVars(string: string)
                    configurationCacheRun "printString"
                    break
            }
        }

        when:
        configurationCacheRun "printString"

        then:
        output.count("The string is absent") == 1
        configurationCache.assertStateStored()
        problems.assertResultHasProblems(result) {
            withNoInputs()
        }

        when:
        printString "alice"

        then:
        output.count("The string is alice") == 1
        configurationCache.assertStateLoaded()

        when:
        printString "bob"

        then:
        output.count("The string is bob") == 1
        configurationCache.assertStateLoaded()

        where:
        [operator, orElseKind] << [
            ['systemProperty', 'environmentVariable'],
            ['primitive', 'provider', 'task output']
        ].combinations()
        orElseArgument = orElseKind == 'primitive'
            ? '"absent"'
            : orElseKind == 'provider'
            ? 'providers.provider { "absent" }'
            : 'producer.flatMap { it.outputFile }.map { it.asFile.readText() }'
    }

    @ValidationTestFor(
        ValidationProblemId.VALUE_NOT_SET
    )
    @Issue("https://github.com/gradle/gradle/issues/13334")
    def "task input property with convention set to absent #operator is reported correctly"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """
            val stringProvider = providers
                .$operator("string")
            abstract class PrintString @Inject constructor(objects: ObjectFactory) : DefaultTask() {
                @get:Input
                val string: Property<String> = objects.property<String>().convention("absent")
                @TaskAction
                fun printString() {
                    println("The string is " + string.orNull)
                }
            }
            tasks.register<PrintString>("printString") {
                string.set(stringProvider)
            }
        """

        when:
        configurationCacheFails "printString"

        then:
        failureDescriptionContains missingValueMessage { type('Build_gradle.PrintString').property('string') }
        configurationCache.assertStateStored()

        when:
        configurationCacheFails "printString"

        then:
        failureDescriptionContains missingValueMessage { type('Build_gradle.PrintString').property('string') }
        configurationCache.assertStateLoaded()

        where:
        operator << ['systemProperty', 'environmentVariable']
    }

    @Issue("https://github.com/gradle/gradle/issues/13334")
    def "absent #operator used as optional task input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """
            val stringProvider = providers
                .$operator("string")
            abstract class PrintString : DefaultTask() {
                @get:Input
                @get:Optional
                abstract val string: Property<String>
                @TaskAction
                fun printString() {
                    println("The string is " + (string.orNull ?: "absent"))
                }
            }
            tasks.register<PrintString>("printString") {
                string.set(stringProvider)
            }
        """

        when:
        configurationCacheRun "printString"

        then:
        output.count("The string is absent") == 1
        configurationCache.assertStateStored()

        when:
        configurationCacheRun "printString"

        then:
        output.count("The string is absent") == 1
        configurationCache.assertStateLoaded()

        where:
        operator << ['systemProperty', 'environmentVariable']
    }

    def "system property from #systemPropertySource used as task and build logic input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        createDir('root') {
            file('build.gradle.kts') << """

                $greetTask

                val greetingProp = providers.systemProperty("greeting")
                if (greetingProp.get() == "hello") {
                    tasks.register<Greet>("greet") {
                        greeting.set("hello, hello")
                    }
                } else {
                    tasks.register<Greet>("greet") {
                        greeting.set(greetingProp)
                    }
                }
            """
        }
        def runGreetWith = { String greeting ->
            inDirectory('root')
            switch (systemPropertySource) {
                case SystemPropertySource.COMMAND_LINE:
                    return configurationCacheRun('greet', "-Dgreeting=$greeting")
                case SystemPropertySource.GRADLE_PROPERTIES:
                    file('root/gradle.properties').text = "systemProp.greeting=$greeting"
                    return configurationCacheRun('greet')
            }
            throw new IllegalArgumentException('source')
        }
        when:
        runGreetWith 'hi'

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateStored()

        and: "the input is reported"
        problems.assertResultHasProblems(result) {
            withInput("Build file 'build.gradle.kts': system property 'greeting'")
        }

        when:
        runGreetWith 'hi'

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateLoaded()

        when:
        runGreetWith 'hello'

        then:
        output.count("Hello, hello!") == 1
        configurationCache.assertStateStored()

        where:
        systemPropertySource << SystemPropertySource.values()
    }

    enum SystemPropertySource {
        COMMAND_LINE,
        GRADLE_PROPERTIES

        @Override
        String toString() {
            name().toLowerCase().replace('_', ' ')
        }
    }

    def "#usage property from properties file used as build logic input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """

            import org.gradle.api.provider.*

            abstract class PropertyFromPropertiesFile : ValueSource<String, PropertyFromPropertiesFile.Parameters> {

                interface Parameters : ValueSourceParameters {

                    @get:InputFile
                    val propertiesFile: RegularFileProperty

                    @get:Input
                    val propertyName: Property<String>
                }

                override fun obtain(): String? = parameters.run {
                    propertiesFile.get().asFile.takeIf { it.isFile }?.inputStream()?.use {
                        java.util.Properties().apply { load(it) }
                    }?.get(propertyName.get()) as String?
                }
            }

            val isCi: Provider<String> = providers.of(PropertyFromPropertiesFile::class) {
                parameters {
                    propertiesFile.set(layout.projectDirectory.file("local.properties"))
                    propertyName.set("ci")
                }
            }

            if ($expression) {
                tasks.register("run") {
                    doLast { println("ON CI") }
                }
            } else {
                tasks.register("run") {
                    doLast { println("NOT CI") }
                }
            }
        """

        when: "running without a file present"
        configurationCacheRun "run"

        then:
        output.count("NOT CI") == 1
        configurationCache.assertStateStored()

        when: "running with an empty file"
        file("local.properties") << ""
        configurationCacheRun "run"

        then:
        output.count("NOT CI") == 1
        configurationCache.assertStateLoaded()

        when: "running with the property present in the file"
        file("local.properties") << "ci=true"
        configurationCacheRun "run"

        then:
        output.count("ON CI") == 1
        configurationCache.assertStateStored()

        when: "running after changing the file without changing the property value"
        file("local.properties") << "\nunrelated.properties=foo"
        configurationCacheRun "run"

        then:
        output.count("ON CI") == 1
        configurationCache.assertStateLoaded()

        when: "running after changing the property value"
        file("local.properties").text = "ci=false"
        configurationCacheRun "run"

        then:
        output.count("NOT CI") == 1
        configurationCache.assertStateStored()

        where:
        expression                                     | usage
        'isCi.map(String::toBoolean).getOrElse(false)' | 'mapped'
        'isCi.getOrElse("false") != "false"'           | 'raw'
    }

    def "#kind property used as task and build logic input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """

            $greetTask

            val greetingProp = providers.${kind}Property("greeting")
            if (greetingProp.get() == "hello") {
                tasks.register<Greet>("greet") {
                    greeting.set("hello, hello")
                }
            } else {
                tasks.register<Greet>("greet") {
                    greeting.set(greetingProp)
                }
            }
        """
        when:
        configurationCacheRun("greet", "-${option}greeting=hi")

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateStored()
        problems.assertResultHasProblems(result) {
            withInput("Build file 'build.gradle.kts': $reportedInput")
        }

        when:
        configurationCacheRun("greet", "-${option}greeting=hi")

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateLoaded()

        when:
        configurationCacheRun("greet", "-${option}greeting=hello")

        then:
        output.count("Hello, hello!") == 1
        configurationCache.assertStateStored()
        outputContains "$description property 'greeting' has changed"

        where:
        kind     | option | description | reportedInput
        'system' | 'D'    | 'system'    | "system property 'greeting'"
//        'gradle' | 'P'    | 'Gradle'    | "Gradle property 'greeting'"
    }

    def "mapped system property used as task input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile("""

            val sysPropProvider = providers
                .systemProperty("thread.pool.size")
                .map(Integer::valueOf)
                .orElse(1)

            abstract class TaskA : DefaultTask() {

                @get:Input
                abstract val threadPoolSize: Property<Int>

                @TaskAction
                fun act() {
                    println("ThreadPoolSize = " + threadPoolSize.get())
                }
            }

            tasks.register<TaskA>("a") {
                threadPoolSize.set(sysPropProvider)
            }
        """)

        when:
        configurationCacheRun("a")

        then:
        output.count("ThreadPoolSize = 1") == 1
        configurationCache.assertStateStored()

        when:
        configurationCacheRun("a", "-Dthread.pool.size=4")

        then:
        output.count("ThreadPoolSize = 4") == 1
        configurationCache.assertStateLoaded()

        when:
        configurationCacheRun("a", "-Dthread.pool.size=3")

        then:
        output.count("ThreadPoolSize = 3") == 1
        configurationCache.assertStateLoaded()
    }

    @Issue("https://github.com/gradle/gradle/issues/19649")
    def "zip chain used as task input"() {
        given:
        def configurationCache = newConfigurationCacheFixture()
        buildFile '''
            def userProvider = providers.gradleProperty("ci").map { "" }.orElse(providers.systemProperty("user"))<commit_msg>Prove provider map orElse chains work with the configuration cache<commit_after>/*
 * Copyright 2019 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.configurationcache

import org.gradle.internal.reflect.problems.ValidationProblemId
import org.gradle.internal.reflect.validation.ValidationMessageChecker
import org.gradle.internal.reflect.validation.ValidationTestFor
import spock.lang.Issue

import static org.junit.Assume.assumeFalse

class ConfigurationCacheBuildOptionsIntegrationTest extends AbstractConfigurationCacheIntegrationTest implements ValidationMessageChecker {

    def setup() {
        expectReindentedValidationMessage()
    }

    @Issue("https://github.com/gradle/gradle/issues/13333")
    def "absent #operator orElse #orElseKind used as task input"() {

        assumeFalse(
            'task dependency inference for orElse(taskOutput) not implemented yet!',
            orElseKind == 'task output'
        )

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """
            abstract class PrintString : DefaultTask() {
                @get:Input
                abstract val string: Property<String>
                @TaskAction
                fun printString() {
                    println("The string is " + string.get())
                }
            }
            abstract class ProduceString : DefaultTask() {
                @get:OutputFile
                abstract val outputFile: RegularFileProperty
                @TaskAction
                fun printString() {
                    outputFile.get().asFile.writeText("absent")
                }
            }
            val producer = tasks.register<ProduceString>("produceString") {
                outputFile.set(layout.buildDirectory.file("output.txt"))
            }
            val stringProvider = providers
                .$operator("string")
                .orElse($orElseArgument)
            tasks.register<PrintString>("printString") {
                string.set(stringProvider)
            }
        """
        def printString = { string ->
            switch (operator) {
                case 'systemProperty':
                    configurationCacheRun "printString", "-Dstring=$string"
                    break
                case 'environmentVariable':
                    withEnvironmentVars(string: string)
                    configurationCacheRun "printString"
                    break
            }
        }

        when:
        configurationCacheRun "printString"

        then:
        output.count("The string is absent") == 1
        configurationCache.assertStateStored()
        problems.assertResultHasProblems(result) {
            withNoInputs()
        }

        when:
        printString "alice"

        then:
        output.count("The string is alice") == 1
        configurationCache.assertStateLoaded()

        when:
        printString "bob"

        then:
        output.count("The string is bob") == 1
        configurationCache.assertStateLoaded()

        where:
        [operator, orElseKind] << [
            ['systemProperty', 'environmentVariable'],
            ['primitive', 'provider', 'task output']
        ].combinations()
        orElseArgument = orElseKind == 'primitive'
            ? '"absent"'
            : orElseKind == 'provider'
            ? 'providers.provider { "absent" }'
            : 'producer.flatMap { it.outputFile }.map { it.asFile.readText() }'
    }

    @ValidationTestFor(
        ValidationProblemId.VALUE_NOT_SET
    )
    @Issue("https://github.com/gradle/gradle/issues/13334")
    def "task input property with convention set to absent #operator is reported correctly"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """
            val stringProvider = providers
                .$operator("string")
            abstract class PrintString @Inject constructor(objects: ObjectFactory) : DefaultTask() {
                @get:Input
                val string: Property<String> = objects.property<String>().convention("absent")
                @TaskAction
                fun printString() {
                    println("The string is " + string.orNull)
                }
            }
            tasks.register<PrintString>("printString") {
                string.set(stringProvider)
            }
        """

        when:
        configurationCacheFails "printString"

        then:
        failureDescriptionContains missingValueMessage { type('Build_gradle.PrintString').property('string') }
        configurationCache.assertStateStored()

        when:
        configurationCacheFails "printString"

        then:
        failureDescriptionContains missingValueMessage { type('Build_gradle.PrintString').property('string') }
        configurationCache.assertStateLoaded()

        where:
        operator << ['systemProperty', 'environmentVariable']
    }

    @Issue("https://github.com/gradle/gradle/issues/13334")
    def "absent #operator used as optional task input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """
            val stringProvider = providers
                .$operator("string")
            abstract class PrintString : DefaultTask() {
                @get:Input
                @get:Optional
                abstract val string: Property<String>
                @TaskAction
                fun printString() {
                    println("The string is " + (string.orNull ?: "absent"))
                }
            }
            tasks.register<PrintString>("printString") {
                string.set(stringProvider)
            }
        """

        when:
        configurationCacheRun "printString"

        then:
        output.count("The string is absent") == 1
        configurationCache.assertStateStored()

        when:
        configurationCacheRun "printString"

        then:
        output.count("The string is absent") == 1
        configurationCache.assertStateLoaded()

        where:
        operator << ['systemProperty', 'environmentVariable']
    }

    def "system property from #systemPropertySource used as task and build logic input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        createDir('root') {
            file('build.gradle.kts') << """

                $greetTask

                val greetingProp = providers.systemProperty("greeting")
                if (greetingProp.get() == "hello") {
                    tasks.register<Greet>("greet") {
                        greeting.set("hello, hello")
                    }
                } else {
                    tasks.register<Greet>("greet") {
                        greeting.set(greetingProp)
                    }
                }
            """
        }
        def runGreetWith = { String greeting ->
            inDirectory('root')
            switch (systemPropertySource) {
                case SystemPropertySource.COMMAND_LINE:
                    return configurationCacheRun('greet', "-Dgreeting=$greeting")
                case SystemPropertySource.GRADLE_PROPERTIES:
                    file('root/gradle.properties').text = "systemProp.greeting=$greeting"
                    return configurationCacheRun('greet')
            }
            throw new IllegalArgumentException('source')
        }
        when:
        runGreetWith 'hi'

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateStored()

        and: "the input is reported"
        problems.assertResultHasProblems(result) {
            withInput("Build file 'build.gradle.kts': system property 'greeting'")
        }

        when:
        runGreetWith 'hi'

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateLoaded()

        when:
        runGreetWith 'hello'

        then:
        output.count("Hello, hello!") == 1
        configurationCache.assertStateStored()

        where:
        systemPropertySource << SystemPropertySource.values()
    }

    enum SystemPropertySource {
        COMMAND_LINE,
        GRADLE_PROPERTIES

        @Override
        String toString() {
            name().toLowerCase().replace('_', ' ')
        }
    }

    def "#usage property from properties file used as build logic input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """

            import org.gradle.api.provider.*

            abstract class PropertyFromPropertiesFile : ValueSource<String, PropertyFromPropertiesFile.Parameters> {

                interface Parameters : ValueSourceParameters {

                    @get:InputFile
                    val propertiesFile: RegularFileProperty

                    @get:Input
                    val propertyName: Property<String>
                }

                override fun obtain(): String? = parameters.run {
                    propertiesFile.get().asFile.takeIf { it.isFile }?.inputStream()?.use {
                        java.util.Properties().apply { load(it) }
                    }?.get(propertyName.get()) as String?
                }
            }

            val isCi: Provider<String> = providers.of(PropertyFromPropertiesFile::class) {
                parameters {
                    propertiesFile.set(layout.projectDirectory.file("local.properties"))
                    propertyName.set("ci")
                }
            }

            if ($expression) {
                tasks.register("run") {
                    doLast { println("ON CI") }
                }
            } else {
                tasks.register("run") {
                    doLast { println("NOT CI") }
                }
            }
        """

        when: "running without a file present"
        configurationCacheRun "run"

        then:
        output.count("NOT CI") == 1
        configurationCache.assertStateStored()

        when: "running with an empty file"
        file("local.properties") << ""
        configurationCacheRun "run"

        then:
        output.count("NOT CI") == 1
        configurationCache.assertStateLoaded()

        when: "running with the property present in the file"
        file("local.properties") << "ci=true"
        configurationCacheRun "run"

        then:
        output.count("ON CI") == 1
        configurationCache.assertStateStored()

        when: "running after changing the file without changing the property value"
        file("local.properties") << "\nunrelated.properties=foo"
        configurationCacheRun "run"

        then:
        output.count("ON CI") == 1
        configurationCache.assertStateLoaded()

        when: "running after changing the property value"
        file("local.properties").text = "ci=false"
        configurationCacheRun "run"

        then:
        output.count("NOT CI") == 1
        configurationCache.assertStateStored()

        where:
        expression                                     | usage
        'isCi.map(String::toBoolean).getOrElse(false)' | 'mapped'
        'isCi.getOrElse("false") != "false"'           | 'raw'
    }

    def "#kind property used as task and build logic input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile """

            $greetTask

            val greetingProp = providers.${kind}Property("greeting")
            if (greetingProp.get() == "hello") {
                tasks.register<Greet>("greet") {
                    greeting.set("hello, hello")
                }
            } else {
                tasks.register<Greet>("greet") {
                    greeting.set(greetingProp)
                }
            }
        """
        when:
        configurationCacheRun("greet", "-${option}greeting=hi")

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateStored()
        problems.assertResultHasProblems(result) {
            withInput("Build file 'build.gradle.kts': $reportedInput")
        }

        when:
        configurationCacheRun("greet", "-${option}greeting=hi")

        then:
        output.count("Hi!") == 1
        configurationCache.assertStateLoaded()

        when:
        configurationCacheRun("greet", "-${option}greeting=hello")

        then:
        output.count("Hello, hello!") == 1
        configurationCache.assertStateStored()
        outputContains "$description property 'greeting' has changed"

        where:
        kind     | option | description | reportedInput
        'system' | 'D'    | 'system'    | "system property 'greeting'"
//        'gradle' | 'P'    | 'Gradle'    | "Gradle property 'greeting'"
    }

    def "mapped system property used as task input"() {

        given:
        def configurationCache = newConfigurationCacheFixture()
        buildKotlinFile("""

            val sysPropProvider = providers
                .systemProperty("thread.pool.size")
                .map(Integer::valueOf)
                .orElse(1)

            abstract class TaskA : DefaultTask() {

                @get:Input
                abstract val threadPoolSize: Property<Int>

                @TaskAction
                fun act() {
                    println("ThreadPoolSize = " + threadPoolSize.get())
                }
            }

            tasks.register<TaskA>("a") {
                threadPoolSize.set(sysPropProvider)
            }
        """)

        when:
        configurationCacheRun("a")

        then:
        output.count("ThreadPoolSize = 1") == 1
        configurationCache.assertStateStored()

        when:
        configurationCacheRun("a", "-Dthread.pool.size=4")

        then:
        output.count("ThreadPoolSize = 4") == 1
        configurationCache.assertStateLoaded()

        when:
        configurationCacheRun("a", "-Dthread.pool.size=3")

        then:
        output.count("ThreadPoolSize = 3") == 1
        configurationCache.assertStateLoaded()
    }

    @Issue("https://github.com/gradle/gradle/issues/19658")
    def "map orElse chain used as task input"() {
        given:
        def configurationCache = newConfigurationCacheFixture()
        buildFile '''
            abstract class PrintValueTask extends DefaultTask {

                @Input
                abstract Property<String> getValue();

                @TaskAction
                void printValue() {
                    println("*" + value.get() + "*")
                }
            }

            def chain = providers
                .systemProperty("foo")
                .orElse(providers.systemProperty("bar"))
                .map { "foo | bar = $it" }
                .orElse(providers.systemProperty("baz"))
                .map { "($it)" }

            tasks.register("ok", PrintValueTask.class) { task ->
                task.value = chain
            }
        '''

        when:
        configurationCacheRun 'ok', '-Dfoo=foo'

        then:
        outputContains "*(foo | bar = foo)*"
        configurationCache.assertStateStored()

        when:
        configurationCacheRun 'ok', '-Dbar=bar'

        then:
        outputContains "*(foo | bar = bar)*"
        configurationCache.assertStateLoaded()

        when:
        configurationCacheRun 'ok', '-Dbaz=baz'

        then:
        outputContains "*(baz)*"
        configurationCache.assertStateLoaded()
    }

    @Issue("https://github.com/gradle/gradle/issues/19649")
    def "zip orElse chain used as task input"() {
        given:
        def configurationCache = newConfigurationCacheFixture()
        buildFile '''
            def userProvider = providers.gradleProperty("ci").map { "" }.orElse(providers.systemProperty("user"))
{'fraction_non_alphanumeric': 0.10053572001411477, 'fraction_numerical': 0.003560773746511404, 'mean_word_length': 1.79964077233947, 'pattern_counts': {'":': 0, '<': 70, '<?xml version=': 0, '>': 43, 'https://': 9, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5223435', 'n_tokens_mistral': 7952, 'n_tokens_neox': 7407, 'n_words': 1640}