/*
 * Copyright 2024 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.internal.buildconfiguration

import org.gradle.internal.buildconfiguration.tasks.DaemonJvmPropertiesModifier
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.platform.Architecture
import org.gradle.platform.BuildPlatform
import org.gradle.platform.BuildPlatformFactory
import org.gradle.platform.OperatingSystem
import org.gradle.test.fixtures.file.TestFile
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.junit.Rule
import spock.lang.Specification

class DaemonJvmPropertiesModifierTest extends Specification {
    @Rule
    final TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider(getClass())

    final TestFile daemonJvmPropertiesFile = tmpDir.file(DaemonJvmPropertiesDefaults.DAEMON_JVM_PROPERTIES_FILE)

    def "writes expected properties into file"() {
        given:
        def propertiesModifier = new DaemonJvmPropertiesModifier()
        when:
        propertiesModifier.updateJvmCriteria(daemonJvmPropertiesFile, JavaLanguageVersion.of(11), "IBM", true,
                [(createBuildPlatform(Architecture.AARCH64, OperatingSystem.LINUX)): new URI("https://server/whatever1"),
                 (createBuildPlatform(Architecture.X86_64, OperatingSystem.MAC_OS)): new URI("https://server/whatever2"),
                 (createBuildPlatform(Architecture.X86_64, OperatingSystem.WINDOWS)): new URI("https://server/whatever3")])
        then:
        def props = daemonJvmPropertiesFile.properties
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION_PROPERTY] == "11"
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VENDOR_PROPERTY] == "IBM"
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_NATIVE_IMAGE_CAPABLE_PROPERTY] == "true"
        props[String.format(DaemonJvmPropertiesDefaults.TOOLCHAIN_URL_PROPERTY_FORMAT, OperatingSystem.LINUX, Architecture.AARCH64)] == "https://server/whatever1"
        props[String.format(DaemonJvmPropertiesDefaults.TOOLCHAIN_URL_PROPERTY_FORMAT, OperatingSystem.MAC_OS, Architecture.X86_64)] == "https://server/whatever2"
        props[String.format(DaemonJvmPropertiesDefaults.TOOLCHAIN_URL_PROPERTY_FORMAT, OperatingSystem.WINDOWS, Architecture.X86_64)] == "https://server/whatever3"
        daemonJvmPropertiesFile.text.contains("#This file is generated by " + DaemonJvmPropertiesConfigurator.TASK_NAME)
    }

    def "writes only non-null properties into file"() {
        given:
        def propertiesModifier = new DaemonJvmPropertiesModifier()
        when:
        propertiesModifier.updateJvmCriteria(daemonJvmPropertiesFile, JavaLanguageVersion.of(11), null, false, [:])
        then:
        def props = daemonJvmPropertiesFile.properties
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION_PROPERTY] == "11"
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VENDOR_PROPERTY] == null
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_NATIVE_IMAGE_CAPABLE_PROPERTY] == null
    }

    def "writes only java version when no other properties are given"() {
        given:
        def propertiesModifier = new DaemonJvmPropertiesModifier()
        when:
        propertiesModifier.updateJvmCriteria(daemonJvmPropertiesFile, JavaLanguageVersion.of(11), null, false, [:])
        then:
        def props = daemonJvmPropertiesFile.properties
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION_PROPERTY] == "11"
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VENDOR_PROPERTY] == null
    }

    def "existing properties are removed when null is passed"() {
        given:
        def propertiesModifier = new DaemonJvmPropertiesModifier()
        daemonJvmPropertiesFile.text = """
            ${DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION_PROPERTY}=11
            ${DaemonJvmPropertiesDefaults.TOOLCHAIN_VENDOR_PROPERTY}=IBM
            ${DaemonJvmPropertiesDefaults.TOOLCHAIN_IMPLEMENTATION_PROPERTY}=vendor-specific
        """
        when:
        propertiesModifier.updateJvmCriteria(daemonJvmPropertiesFile, JavaLanguageVersion.of(15), null, false, [:])
        then:
        def props = daemonJvmPropertiesFile.properties
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION_PROPERTY] == "15"
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VENDOR_PROPERTY] == null
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_IMPLEMENTATION_PROPERTY] == null
    }

    def "existing unrecognized properties are not preserved"() {
        given:
        def propertiesModifier = new DaemonJvmPropertiesModifier()
        daemonJvmPropertiesFile.text = """
            # this comment is not preserved
            com.example.foo=bar
            ${DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION_PROPERTY}=15
        """
        when:
        propertiesModifier.updateJvmCriteria(daemonJvmPropertiesFile, JavaLanguageVersion.of(11), "IBM", false, [:])
        then:
        def props = daemonJvmPropertiesFile.properties
        props.size() == 2
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VERSION_PROPERTY] == "11"
        props[DaemonJvmPropertiesDefaults.TOOLCHAIN_VENDOR_PROPERTY] == "IBM"
        !daemonJvmPropertiesFile.text.contains("# this comment is not preserved")
    }

    private BuildPlatform createBuildPlatform(Architecture architecture, OperatingSystem operatingSystem) {
        return BuildPlatformFactory.of(architecture, operatingSystem)
    }
}
