/*
 * Copyright 2010-2017 JetBrains s.r.o.
 *
 * 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.jetbrains.kotlin.idea.codeInsight.gradle

import com.intellij.openapi.application.Result
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import junit.framework.TestCase
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo
import org.jetbrains.kotlin.idea.caches.project.testSourceInfo
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinStatus
import org.jetbrains.kotlin.idea.configuration.ModuleSourceRootMap
import org.jetbrains.kotlin.idea.configuration.allConfigurators
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.idea.util.projectStructure.sdk
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.impl.isCommon
import org.jetbrains.kotlin.platform.impl.isJavaScript
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Assert
import org.junit.Test
import java.util.*

internal fun GradleImportingTestCase.facetSettings(moduleName: String) = KotlinFacet.get(getModule(moduleName))!!.configuration.settings

internal val GradleImportingTestCase.facetSettings: KotlinFacetSettings
    get() = facetSettings("project_main")

internal val GradleImportingTestCase.testFacetSettings: KotlinFacetSettings
    get() = facetSettings("project_test")

internal fun GradleImportingTestCase.getSourceRootInfos(moduleName: String): List<Pair<String, JpsModuleSourceRootType<*>>> {
    return ModuleRootManager.getInstance(getModule(moduleName)).contentEntries.flatMap {
        it.sourceFolders.map { it.url.replace(projectPath, "") to it.rootType }
    }
}

class GradleFacetImportTest : GradleImportingTestCase() {
    private var isCreateEmptyContentRootDirectories = true

    override fun setUp() {
        super.setUp()
        isCreateEmptyContentRootDirectories = currentExternalProjectSettings.isCreateEmptyContentRootDirectories
        currentExternalProjectSettings.isCreateEmptyContentRootDirectories = true
    }

    override fun tearDown() {
        currentExternalProjectSettings.isCreateEmptyContentRootDirectories = isCreateEmptyContentRootDirectories
        super.tearDown()
    }

    private fun assertSameKotlinSdks(vararg moduleNames: String) {
        val sdks = moduleNames.map { getModule(it).sdk!! }
        val refSdk = sdks.firstOrNull() ?: return
        Assert.assertTrue(refSdk.sdkType is KotlinSdkType)
        Assert.assertTrue(sdks.all { it === refSdk })
    }

    @Test
    fun testJvmImport() {
        createProjectSubFile(
            "build.gradle", """
            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
            }

            compileKotlin {
                kotlinOptions.jvmTarget = "1.7"
                kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to", "tmp"]
            }

            compileTestKotlin {
                kotlinOptions.jvmTarget = "1.6"
                kotlinOptions.apiVersion = "1.0"
                kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to", "tmpTest"]
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion)
            Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_8), platform)
            Assert.assertEquals("1.7", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmp -Xsingle-module",
                compilerSettings!!.additionalArguments
            )
        }
        with(testFacetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion)
            Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_6), platform)
            Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmpTest",
                compilerSettings!!.additionalArguments
            )
        }

        assertAllModulesConfigured()

        Assert.assertEquals(
                listOf("file:///src/main/java" to JavaSourceRootType.SOURCE,
                       "file:///src/main/kotlin" to JavaSourceRootType.SOURCE,
                       "file:///src/main/resources" to JavaResourceRootType.RESOURCE),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
                listOf("file:///src/test/java" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/kotlin" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/resources" to JavaResourceRootType.TEST_RESOURCE),
                getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testJvmImportWithPlugin() {
        createProjectSubFile(
                "build.gradle", """
buildscript {
    repositories {
        mavenCentral()
    }
}

plugins {
    id "org.jetbrains.kotlin.jvm" version "1.1.3"
}

version '1.0-SNAPSHOT'

apply plugin: 'java'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.3"
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
        """
        )
        importProject()

        assertAllModulesConfigured()
    }

    @Test
    fun testJvmImport_1_1_2() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-dev'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.2-5")
                }
            }

            apply plugin: 'kotlin'

            repositories {
                mavenCentral()
                maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' }
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.2-5"
            }

            compileKotlin {
                kotlinOptions.jvmTarget = "1.7"
                kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to", "tmp"]
            }

            compileTestKotlin {
                kotlinOptions.jvmTarget = "1.6"
                kotlinOptions.apiVersion = "1.0"
                kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to", "tmpTest"]
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_8), platform)
            Assert.assertEquals("1.7", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmp -Xsingle-module",
                compilerSettings!!.additionalArguments
            )
        }
        with(testFacetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_6), platform)
            Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmpTest",
                compilerSettings!!.additionalArguments
            )
        }

        Assert.assertEquals(
                listOf("file:///src/main/java" to JavaSourceRootType.SOURCE,
                       "file:///src/main/kotlin" to JavaSourceRootType.SOURCE,
                       "file:///src/main/resources" to JavaResourceRootType.RESOURCE),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
                listOf("file:///src/test/java" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/kotlin" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/resources" to JavaResourceRootType.TEST_RESOURCE),
                getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testJvmImportWithCustomSourceSets() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            sourceSets {
                myMain {
                    kotlin {
                        srcDir 'src'
                    }
                }
                myTest {
                    kotlin {
                        srcDir 'test'
                    }
                }
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
            }

            compileMyMainKotlin {
                kotlinOptions.jvmTarget = "1.7"
                kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to", "tmp"]
            }

            compileMyTestKotlin {
                kotlinOptions.jvmTarget = "1.6"
                kotlinOptions.apiVersion = "1.0"
                kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to", "tmpTest"]
            }
        """
        )
        importProject()

        with(facetSettings("project_myMain")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_8), platform)
            Assert.assertEquals("1.7", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmp -Xsingle-module",
                compilerSettings!!.additionalArguments
            )
        }
        with(facetSettings("project_myTest")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_6), platform)
            Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmpTest",
                compilerSettings!!.additionalArguments
            )
        }

        assertAllModulesConfigured()

        Assert.assertEquals(
                listOf("file:///src/main/java" to JavaSourceRootType.SOURCE,
                       "file:///src/main/kotlin" to JavaSourceRootType.SOURCE,
                       "file:///src/main/resources" to JavaResourceRootType.RESOURCE),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
                listOf("file:///src/test/java" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/kotlin" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/resources" to JavaResourceRootType.TEST_RESOURCE),
                getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testJvmImportWithCustomSourceSets_1_1_2() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.2-5")
                }
            }

            apply plugin: 'kotlin'

            repositories {
                mavenCentral()
                maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' }
            }

            sourceSets {
                myMain {
                    kotlin {
                        srcDir 'src'
                    }
                }
                myTest {
                    kotlin {
                        srcDir 'test'
                    }
                }
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.2-5"
            }

            compileMyMainKotlin {
                kotlinOptions.jvmTarget = "1.7"
                kotlinOptions.freeCompilerArgs = ["-Xsingle-module", "-Xdump-declarations-to", "tmp"]
            }

            compileMyTestKotlin {
                kotlinOptions.jvmTarget = "1.6"
                kotlinOptions.apiVersion = "1.0"
                kotlinOptions.freeCompilerArgs = ["-Xdump-declarations-to", "tmpTest"]
            }
        """
        )
        importProject()

        with(facetSettings("project_myMain")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_8), platform)
            Assert.assertEquals("1.7", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmp -Xsingle-module",
                compilerSettings!!.additionalArguments
            )
        }
        with(facetSettings("project_myTest")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_6), platform)
            Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget)
            Assert.assertEquals(
                "-Xdump-declarations-to=tmpTest",
                compilerSettings!!.additionalArguments
            )
        }

        Assert.assertEquals(
                listOf("file:///src/main/java" to JavaSourceRootType.SOURCE,
                       "file:///src/main/kotlin" to JavaSourceRootType.SOURCE,
                       "file:///src/main/resources" to JavaResourceRootType.RESOURCE),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
                listOf("file:///src/test/java" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/kotlin" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/resources" to JavaResourceRootType.TEST_RESOURCE),
                getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testCoroutineImportByOptions() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
            }

            kotlin {
                experimental {
                    coroutines 'enable'
                }
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals(LanguageFeature.State.ENABLED, coroutineSupport)
        }
    }

    @Test
    fun testCoroutineImportByProperties() {
        createProjectSubFile("gradle.properties", "kotlin.coroutines=enable")
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals(LanguageFeature.State.ENABLED, coroutineSupport)
        }
    }

    @Test
    fun testJsImport() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin2js'

            repositories {
                mavenCentral()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.1.0"
            }

            compileKotlin2Js {
                kotlinOptions.sourceMap = true
                kotlinOptions.freeCompilerArgs = ["-module-kind", "plain", "-main", "callMain"]
            }

            compileTestKotlin2Js {
                kotlinOptions.apiVersion = "1.0"
                kotlinOptions.freeCompilerArgs = ["-module-kind", "umd", "-main", "callTest"]
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion)
            Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion)
            Assert.assertTrue(platform.isJavaScript)
            with(compilerArguments as K2JSCompilerArguments) {
                Assert.assertEquals(true, sourceMap)
                Assert.assertEquals("plain", moduleKind)
            }
            Assert.assertEquals(
                "-main callMain",
                compilerSettings!!.additionalArguments
            )
        }

        with(testFacetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion)
            Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion)
            Assert.assertTrue(platform.isJavaScript)
            with(compilerArguments as K2JSCompilerArguments) {
                Assert.assertEquals(false, sourceMap)
                Assert.assertEquals("umd", moduleKind)
            }
            Assert.assertEquals(
                "-main callTest",
                compilerSettings!!.additionalArguments
            )
        }

        val rootManager = ModuleRootManager.getInstance(getModule("project_main"))
        val stdlib = rootManager.orderEntries.filterIsInstance<LibraryOrderEntry>().single().library
        assertEquals(JSLibraryKind, (stdlib as LibraryEx).kind)
        assertTrue(stdlib.getFiles(OrderRootType.CLASSES).isNotEmpty())

        assertSameKotlinSdks("project_main", "project_test")

        Assert.assertEquals(
                listOf("file:///src/main/java" to SourceKotlinRootType,
                       "file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
            listOf("file:///src/test/java" to TestSourceKotlinRootType,
                       "file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project_test")
        )

        assertAllModulesConfigured()
    }

    @Test
    fun testJsImportTransitive() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin2js'

            repositories {
                mavenCentral()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-test-js:1.1.0"
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertTrue(platform.isJavaScript)
        }

        val rootManager = ModuleRootManager.getInstance(getModule("project_main"))
        val stdlib = rootManager.orderEntries
            .filterIsInstance<LibraryOrderEntry>()
            .map { it.library as LibraryEx }
            .first { "kotlin-stdlib-js" in it.name!! }
        assertEquals(JSLibraryKind, stdlib.kind)

        assertAllModulesConfigured()

        Assert.assertEquals(
                listOf("file:///src/main/java" to SourceKotlinRootType,
                       "file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
            listOf("file:///src/test/java" to TestSourceKotlinRootType,
                       "file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testJsImportWithCustomSourceSets() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin2js'

            sourceSets {
                myMain {
                    kotlin {
                        srcDir 'src'
                    }
                }
                myTest {
                    kotlin {
                        srcDir 'test'
                    }
                }
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.1.0"
            }

            compileMyMainKotlin2Js {
                kotlinOptions.sourceMap = true
                kotlinOptions.freeCompilerArgs = ["-module-kind", "plain", "-main", "callMain"]
            }

            compileMyTestKotlin2Js {
                kotlinOptions.apiVersion = "1.0"
                kotlinOptions.freeCompilerArgs = ["-module-kind", "umd", "-main", "callTest"]
            }
        """
        )
        importProject()

        with(facetSettings("project_myMain")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertTrue(platform.isJavaScript)
            with(compilerArguments as K2JSCompilerArguments) {
                Assert.assertEquals(true, sourceMap)
                Assert.assertEquals("plain", moduleKind)
            }
            Assert.assertEquals(
                "-main callMain",
                compilerSettings!!.additionalArguments
            )
        }

        with(facetSettings("project_myTest")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertTrue(platform.isJavaScript)
            with(compilerArguments as K2JSCompilerArguments) {
                Assert.assertEquals(false, sourceMap)
                Assert.assertEquals("umd", moduleKind)
            }
            Assert.assertEquals(
                "-main callTest",
                compilerSettings!!.additionalArguments
            )
        }

        assertAllModulesConfigured()

        Assert.assertEquals(
                listOf("file:///src/main/java" to SourceKotlinRootType,
                       "file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
            listOf("file:///src/test/java" to TestSourceKotlinRootType,
                       "file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testDetectOldJsStdlib() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.6")
                }
            }

            apply plugin: 'kotlin2js'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-js-library:1.0.6"
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertTrue(platform.isJavaScript)
        }
    }

    @Test
    fun testJvmImportByPlatformPlugin() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin-platform-jvm'
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_6), platform)
        }

        Assert.assertEquals(
                listOf("file:///src/main/java" to JavaSourceRootType.SOURCE,
                       "file:///src/main/kotlin" to JavaSourceRootType.SOURCE,
                       "file:///src/main/resources" to JavaResourceRootType.RESOURCE),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
                listOf("file:///src/test/java" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/kotlin" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/resources" to JavaResourceRootType.TEST_RESOURCE),
                getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testJsImportByPlatformPlugin() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin-platform-js'

            repositories {
                mavenCentral()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.1.0"
                compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.1.0"
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertTrue(platform.isJavaScript)
        }

        val rootManager = ModuleRootManager.getInstance(getModule("project_main"))
        val libraries = rootManager.orderEntries.filterIsInstance<LibraryOrderEntry>().mapNotNull { it.library as LibraryEx }
        assertEquals(JSLibraryKind, libraries.single { it.name?.contains("kotlin-stdlib-js") == true }.kind)
        assertEquals(CommonLibraryKind, libraries.single { it.name?.contains("kotlin-stdlib-common") == true }.kind)

        Assert.assertEquals(
                listOf("file:///src/main/java" to SourceKotlinRootType,
                       "file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
            listOf("file:///src/test/java" to TestSourceKotlinRootType,
                       "file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testCommonImportByPlatformPlugin() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin-platform-common'

            repositories {
                mavenCentral()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.1.0"
            }

        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertTrue(platform.isCommon)
        }

        val rootManager = ModuleRootManager.getInstance(getModule("project_main"))
        val stdlib = rootManager.orderEntries.filterIsInstance<LibraryOrderEntry>().single().library
        assertEquals(CommonLibraryKind, (stdlib as LibraryEx).kind)

        Assert.assertEquals(
                listOf("file:///src/main/java" to SourceKotlinRootType,
                       "file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
            listOf("file:///src/test/java" to TestSourceKotlinRootType,
                       "file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testCommonImportByPlatformPlugin_SingleModule() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    jcenter()
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin-platform-common'

            repositories {
                    mavenCentral()
                    jcenter()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.1.0"
            }

        """
        )
        importProjectUsingSingeModulePerGradleProject()

        with(facetSettings("project")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertTrue(platform.isCommon)
        }

        val rootManager = ModuleRootManager.getInstance(getModule("project"))
        val stdlib = rootManager.orderEntries.filterIsInstance<LibraryOrderEntry>().mapTo(HashSet()) { it.library }.single()
        assertEquals(CommonLibraryKind, (stdlib as LibraryEx).kind)

        Assert.assertEquals(
            listOf("file:///src/main/java" to SourceKotlinRootType,
                       "file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/test/java" to TestSourceKotlinRootType,
                       "file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project")
        )
    }

    @Test
    fun testJvmImportByKotlinPlugin() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertEquals(JvmIdePlatformKind.Platform(JvmTarget.JVM_1_6), platform)
        }

        Assert.assertEquals(
                listOf("file:///src/main/java" to JavaSourceRootType.SOURCE,
                       "file:///src/main/kotlin" to JavaSourceRootType.SOURCE,
                       "file:///src/main/resources" to JavaResourceRootType.RESOURCE),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
                listOf("file:///src/test/java" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/kotlin" to JavaSourceRootType.TEST_SOURCE,
                       "file:///src/test/resources" to JavaResourceRootType.TEST_RESOURCE),
                getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testJsImportByKotlin2JsPlugin() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin2js'
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
            Assert.assertTrue(platform.isJavaScript)
        }

        Assert.assertEquals(
                listOf("file:///src/main/java" to SourceKotlinRootType,
                       "file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
            listOf("file:///src/test/java" to TestSourceKotlinRootType,
                       "file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testArgumentEscaping() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin-platform-jvm'

            compileKotlin {
                kotlinOptions.freeCompilerArgs = ["-module", "module with spaces"]
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals(
                listOf("-Xbuild-file=module with spaces"),
                compilerSettings!!.additionalArgumentsAsList
            )
        }
    }

    @Test
    fun testNoPluginsInAdditionalArgs() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.10")
                    classpath("org.jetbrains.kotlin:kotlin-allopen:1.2.10")
                }
            }

            apply plugin: 'kotlin'
            apply plugin: "kotlin-spring"
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals(
                "-version",
                compilerSettings!!.additionalArguments
            )
            Assert.assertEquals(
                listOf(
                    "plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.stereotype.Component",
                    "plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.transaction.annotation.Transactional",
                    "plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.scheduling.annotation.Async",
                    "plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.cache.annotation.Cacheable",
                    "plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.boot.test.context.SpringBootTest",
                    "plugin:org.jetbrains.kotlin.allopen:annotation=org.springframework.validation.annotation.Validated"
                ),
                compilerArguments!!.pluginOptions!!.toList()
            )
        }
    }

    @Test
    fun testNoArgInvokeInitializers() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.10")
                    classpath("org.jetbrains.kotlin:kotlin-noarg:1.2.10")
                }
            }

            apply plugin: 'kotlin'
            apply plugin: "kotlin-noarg"

            noArg {
                invokeInitializers = true
                annotation("NoArg")
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals(
                "-version",
                compilerSettings!!.additionalArguments
            )
            Assert.assertEquals(
                listOf(
                    "plugin:org.jetbrains.kotlin.noarg:annotation=NoArg",
                    "plugin:org.jetbrains.kotlin.noarg:invokeInitializers=true"
                ),
                compilerArguments!!.pluginOptions!!.toList()
            )
        }
    }

    @Test
    fun testAndroidGradleJsDetection() {
        createProjectSubFile(
            "android-module/build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    jcenter()
                }
                dependencies {
                    classpath "com.android.tools.build:gradle:2.3.0"
                }
            }

            apply plugin: 'com.android.application'

            android {
                compileSdkVersion 26
                buildToolsVersion "23.0.1"

                defaultConfig {
                    minSdkVersion 11
                    targetSdkVersion 23
                    versionCode 1002003
                    versionName version
                }

                dataBinding {
                    enabled = true
                }

                compileOptions {
                    sourceCompatibility JavaVersion.VERSION_1_7
                    targetCompatibility JavaVersion.VERSION_1_7
                }

                buildTypes {
                    debug {
                        applicationIdSuffix ".debug"
                        versionNameSuffix "-debug"
                    }
                    release {
                        minifyEnabled true
                        shrinkResources true
                    }
                }
            }
        """
        )
        createProjectSubFile(
            "android-module/src/main/AndroidManifest.xml", """
            <manifest xmlns:android="https://schemas.android.com/apk/res/android"
                      xmlns:tools="https://schemas.android.com/tools"
                      package="my.test.project" >
            </manifest>
        """
        )
        createProjectSubFile(
            "js-module/build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-dev'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.40")
                }
            }

            apply plugin: 'kotlin2js'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.1.0"
            }
        """
        )
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenLocal()
                    maven {
                        url='https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                    jcenter()
                }
                dependencies {
                    classpath "com.android.tools.build:gradle:2.3.0"
                    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
                }
            }

            ext {
                androidBuildToolsVersion = '23.0.1'
            }

            allprojects {
                repositories {
                    mavenLocal()
                    maven {
                        url='https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                    jcenter()
                }
            }
        """
        )
        createProjectSubFile(
            "settings.gradle", """
            rootProject.name = "android-js-test"
            include ':android-module'
            include ':js-module'
        """
        )
        createProjectSubFile(
            "local.properties", """
            sdk.dir=/${KotlinTestUtils.getAndroidSdkSystemIndependentPath()}
        """
        )
        importProject()

        with(facetSettings("js-module")) {
            Assert.assertTrue(platform.isJavaScript)
        }

        val rootManager = ModuleRootManager.getInstance(getModule("js-module"))
        val stdlib = rootManager
            .orderEntries
            .filterIsInstance<LibraryOrderEntry>()
            .first { it.libraryName?.startsWith("Gradle: kotlin-stdlib-js-") ?: false }
            .library!!
        assertTrue(stdlib.getFiles(OrderRootType.CLASSES).isNotEmpty())
        assertEquals(JSLibraryKind, (stdlib as LibraryEx).kind)
    }

    @Test
    fun testKotlinAndroidPluginDetection() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    jcenter()
                    mavenCentral()
                }
                dependencies {
                    classpath "com.android.tools.build:gradle:2.3.0"
                    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.50"
                }
            }

            apply plugin: 'com.android.application'
            apply plugin: 'kotlin-android'

            android {
                compileSdkVersion 26
                buildToolsVersion "23.0.1"

                defaultConfig {
                    minSdkVersion 11
                    targetSdkVersion 23
                    versionCode 1002003
                    versionName version
                }

                dataBinding {
                    enabled = true
                }

                compileOptions {
                    sourceCompatibility JavaVersion.VERSION_1_7
                    targetCompatibility JavaVersion.VERSION_1_7
                }

                buildTypes {
                    debug {
                        applicationIdSuffix ".debug"
                        versionNameSuffix "-debug"
                    }
                    release {
                        minifyEnabled true
                        shrinkResources true
                    }
                }
            }

            tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
                kotlinOptions {
                    freeCompilerArgs = ['-progressive']
                }
            }
        """
        )
        createProjectSubFile(
            "local.properties", """
            sdk.dir=/${KotlinTestUtils.getAndroidSdkSystemIndependentPath()}
        """
        )
        createProjectSubFile(
            "src/main/AndroidManifest.xml", """
            <manifest xmlns:android="https://schemas.android.com/apk/res/android"
                      xmlns:tools="https://schemas.android.com/tools"
                      package="my.test.project" >
            </manifest>
        """
        )
        importProject()

        val kotlinFacet = KotlinFacet.get(getModule("project"))!!
        Assert.assertTrue(kotlinFacet.configuration.settings.mergedCompilerArguments!!.progressiveMode)
    }

    @Test
    fun testNoFacetInModuleWithoutKotlinPlugin() {
        createProjectSubFile(
            "build.gradle", """
            group 'gr01'
            version '1.0-SNAPSHOT'

            apply plugin: 'java'
            apply plugin: 'kotlin'

            sourceCompatibility = 1.8

            repositories {
                mavenCentral()
            }

            buildscript {
                repositories {
                    mavenCentral()
                }
                dependencies {
                    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.1"
                }
            }
            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.1"
            }
        """
        )
        createProjectSubFile(
            "settings.gradle", """
            rootProject.name = 'gr01'
            include 'm1'
        """
        )
        createProjectSubFile(
            "m1/build.gradle", """
            group 'gr01'
            version '1.0-SNAPSHOT'

            apply plugin: 'java'

            sourceCompatibility = 1.8

            repositories {
                mavenCentral()
            }

            buildscript {
                repositories {
                    mavenCentral()
                }
            }
            dependencies {
                testCompile group: 'junit', name: 'junit', version: '4.11'
            }
        """
        )
        importProject()

        Assert.assertNotNull(KotlinFacet.get(getModule("gr01_main")))
        Assert.assertNotNull(KotlinFacet.get(getModule("gr01_test")))
        Assert.assertNull(KotlinFacet.get(getModule("m1_main")))
        Assert.assertNull(KotlinFacet.get(getModule("m1_test")))
    }

    @Test
    fun testClasspathWithDependenciesImport() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
                compile "org.apache.logging.log4j:log4j-core:2.7"
            }

            compileKotlin {
                kotlinOptions.freeCompilerArgs += ["-cp", "tmp.jar"]
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("tmp.jar", (compilerArguments as K2JVMCompilerArguments).classpath)
        }
    }

    @Test
    fun testDependenciesClasspathImport() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
                compile "org.apache.logging.log4j:log4j-core:2.7"
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals(null, (compilerArguments as K2JVMCompilerArguments).classpath)
        }
    }

    @Test
    fun testJDKImport() {
        object : WriteAction<Unit>() {
            override fun run(result: Result<Unit>) {
                val jdk = JavaSdk.getInstance().createJdk("myJDK", "my/path/to/jdk")
                ProjectJdkTable.getInstance().addJdk(jdk)
            }
        }.execute()

        try {
            createProjectSubFile(
                "build.gradle", """
                group 'Again'
                version '1.0-SNAPSHOT'

                buildscript {
                    repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }

                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                    }
                }

                apply plugin: 'kotlin'

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
                    compile "org.apache.logging.log4j:log4j-core:2.7"
                }

                compileKotlin {
                    kotlinOptions.jdkHome = "my/path/to/jdk"
                }
            """
            )
            importProject()

            val moduleSDK = ModuleRootManager.getInstance(getModule("project_main")).sdk!!
            Assert.assertTrue(moduleSDK.sdkType is JavaSdk)
            Assert.assertEquals("myJDK", moduleSDK.name)
            Assert.assertEquals("my/path/to/jdk", moduleSDK.homePath)
        } finally {
            object : WriteAction<Unit>() {
                override fun run(result: Result<Unit>) {
                    val jdkTable = ProjectJdkTable.getInstance()
                    jdkTable.removeJdk(jdkTable.findJdk("myJDK")!!)
                }
            }.execute()
        }
    }

    @Test
    fun testImplementsDependency() {
        createProjectSubFile(
            "build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                    }
                }

                apply plugin: 'kotlin-platform-common'

                repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.1.0"
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "settings.gradle",
            """
                    rootProject.name = 'MultiTest'
                    include 'MultiTest-jvm', 'MultiTest-js'
                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-js/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                    }
                }

                apply plugin: 'kotlin-platform-js'

                repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.1.0"
                    implement project(":")
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-jvm/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                    }
                }

                apply plugin: 'kotlin-platform-jvm'

                repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
                    implement project(":")
                }

                """.trimIndent()
        )

        importProject()

        Assert.assertEquals(listOf("MultiTest_main"), facetSettings("MultiTest-jvm_main").implementedModuleNames)
        Assert.assertEquals(listOf("MultiTest_test"), facetSettings("MultiTest-jvm_test").implementedModuleNames)
        Assert.assertEquals(listOf("MultiTest_main"), facetSettings("MultiTest-js_main").implementedModuleNames)
        Assert.assertEquals(listOf("MultiTest_test"), facetSettings("MultiTest-js_test").implementedModuleNames)
    }

    @Test
    fun testImplementsDependencyWithCustomSourceSets() {
        createProjectSubFile(
            "build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                    }
                }

                apply plugin: 'kotlin-platform-common'

                sourceSets {
                    myMain {
                        kotlin {
                            srcDir 'src'
                        }
                    }
                    myTest {
                        kotlin {
                            srcDir 'test'
                        }
                    }
                }

                repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.1.0"
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "settings.gradle",
            """
                    rootProject.name = 'MultiTest'
                    include 'MultiTest-jvm', 'MultiTest-js'
                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-js/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                    }
                }

                apply plugin: 'kotlin-platform-js'

                sourceSets {
                    myMain {
                        kotlin {
                            srcDir 'src'
                        }
                    }
                    myTest {
                        kotlin {
                            srcDir 'test'
                        }
                    }
                }

                repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.1.0"
                    implement project(":")
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-jvm/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                    }
                }

                apply plugin: 'kotlin-platform-jvm'

                sourceSets {
                    myMain {
                        kotlin {
                            srcDir 'src'
                        }
                    }
                    myTest {
                        kotlin {
                            srcDir 'test'
                        }
                    }
                }

                repositories {
                        mavenCentral()
                        maven {
                            url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                        }
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
                    implement project(":")
                }

                """.trimIndent()
        )

        importProject()

        Assert.assertEquals(listOf("MultiTest_myMain"), facetSettings("MultiTest-jvm_myMain").implementedModuleNames)
        Assert.assertEquals(listOf("MultiTest_myTest"), facetSettings("MultiTest-jvm_myTest").implementedModuleNames)
        Assert.assertEquals(listOf("MultiTest_myMain"), facetSettings("MultiTest-js_myMain").implementedModuleNames)
        Assert.assertEquals(listOf("MultiTest_myTest"), facetSettings("MultiTest-js_myTest").implementedModuleNames)
    }

    @Test
    fun testAPIVersionExceedingLanguageVersion() {
        createProjectSubFile(
            "build.gradle", """
            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
            }

            compileKotlin {
                kotlinOptions.languageVersion = "1.1"
                kotlinOptions.apiVersion = "1.2"
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
        }

        assertAllModulesConfigured()
    }

    @Test
    fun testIgnoreProjectLanguageAndAPIVersion() {
        KotlinCommonCompilerArgumentsHolder.getInstance(myProject).update {
            languageVersion = "1.0"
            apiVersion = "1.0"
        }

        createProjectSubFile(
            "build.gradle", """
            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.1'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0")
                }
            }

            apply plugin: 'kotlin'

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.0"
            }
        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.1", apiLevel!!.versionString)
        }

        assertAllModulesConfigured()
    }

    @Test
    fun testCommonArgumentsImport() {
        createProjectSubFile(
            "build.gradle", """
            group 'Again'
            version '1.0-SNAPSHOT'

            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-eap-1.2'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.40")
                }
            }

            apply plugin: 'kotlin-platform-common'

            repositories {
                mavenCentral()
                maven {
                    url 'https://dl.bintray.com/kotlin/kotlin-eap-1.2'
                }
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.2.40"
            }

            compileKotlinCommon{
                kotlinOptions {
                    languageVersion = 1.1
                    apiVersion = 1.0
                    freeCompilerArgs += ["-cp", "my/classpath"]
                    freeCompilerArgs += ["-d", "my/destination"]
                }
            }

            compileTestKotlinCommon{
                kotlinOptions {
                    languageVersion = 1.1
                    apiVersion = 1.0
                    freeCompilerArgs += ["-cp", "my/test/classpath"]
                    freeCompilerArgs += ["-d", "my/test/destination"]
                }
            }

        """
        )
        importProject()

        with(facetSettings) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion)
            Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion)
            Assert.assertTrue(platform.isCommon)
            Assert.assertEquals("my/classpath", (compilerArguments as K2MetadataCompilerArguments).classpath)
            Assert.assertEquals("my/destination", (compilerArguments as K2MetadataCompilerArguments).destination)
        }

        with(facetSettings("project_test")) {
            Assert.assertEquals("1.1", languageLevel!!.versionString)
            Assert.assertEquals("1.0", apiLevel!!.versionString)
            Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion)
            Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion)
            Assert.assertTrue(platform.isCommon)
            Assert.assertEquals("my/test/classpath", (compilerArguments as K2MetadataCompilerArguments).classpath)
            Assert.assertEquals("my/test/destination", (compilerArguments as K2MetadataCompilerArguments).destination)
        }

        val rootManager = ModuleRootManager.getInstance(getModule("project_main"))
        val stdlib = rootManager.orderEntries.filterIsInstance<LibraryOrderEntry>().single().library
        assertEquals(CommonLibraryKind, (stdlib as LibraryEx).kind)

        assertSameKotlinSdks("project_main", "project_test")

        Assert.assertEquals(
                listOf("file:///src/main/kotlin" to SourceKotlinRootType,
                       "file:///src/main/resources" to ResourceKotlinRootType),
                getSourceRootInfos("project_main")
        )
        Assert.assertEquals(
            listOf("file:///src/test/kotlin" to TestSourceKotlinRootType,
                       "file:///src/test/resources" to TestResourceKotlinRootType),
            getSourceRootInfos("project_test")
        )
    }

    @Test
    fun testInternalArgumentsFacetImporting() {
        createProjectSubFile(
            "build.gradle", """
            buildscript {
                repositories {
                    mavenCentral()
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.50")
                }
            }

            apply plugin: 'kotlin'

            repositories {
                mavenCentral()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.50"
            }

            compileKotlin {
                kotlinOptions.freeCompilerArgs = ["-XXLanguage:+InlineClasses"]
                kotlinOptions.languageVersion = "1.2"
            }
        """
        )
        importProject()

        // Version is indeed 1.2
        Assert.assertEquals(LanguageVersion.KOTLIN_1_2, facetSettings.languageLevel)

        // We haven't lost internal argument during importing to facet
        Assert.assertEquals("-XXLanguage:+InlineClasses", facetSettings.compilerSettings?.additionalArguments)

        // Inline classes are enabled even though LV = 1.2
        Assert.assertEquals(
            LanguageFeature.State.ENABLED,
            getModule("project_main").languageVersionSettings.getFeatureSupport(LanguageFeature.InlineClasses)
        )

        assertAllModulesConfigured()
    }

    @Test
    fun testStableModuleNameWhileUsingGradle_JS() {
        createProjectSubFile(
            "build.gradle", """
            buildscript {
                repositories {
                    mavenCentral()
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.50")
                }
            }

            apply plugin: 'kotlin2js'

            repositories {
                mavenCentral()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.50"
            }

        """
        )
        importProject()

        checkStableModuleName("project_main", "project", JsPlatform, isProduction = true)
        // Note "_test" suffix: this is current behavior of K2JS Compiler
        checkStableModuleName("project_test", "project_test", JsPlatform, isProduction = false)

        assertAllModulesConfigured()
    }

    @Test
    fun testStableModuleNameWhileUsingGradle_JVM() {
        createProjectSubFile(
            "build.gradle", """
            buildscript {
                repositories {
                    mavenCentral()
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.50")
                }
            }

            apply plugin: 'kotlin'

            repositories {
                mavenCentral()
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.50"
            }

            compileKotlin {
                kotlinOptions.languageVersion = "1.2"
            }
        """
        )
        importProject()

        checkStableModuleName("project_main", "project", JvmPlatform, isProduction = true)
        checkStableModuleName("project_test", "project", JvmPlatform, isProduction = false)

        assertAllModulesConfigured()
    }

    @Test
    fun testNoFriendPathsAreShown() {
        createProjectSubFile(
            "build.gradle", """
            buildscript {
                repositories {
                    mavenCentral()
                    maven {
                        url 'https://dl.bintray.com/kotlin/kotlin-dev'
                    }
                }

                dependencies {
                    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.70-eap-4")
                }
            }

            apply plugin: 'kotlin'

            repositories {
                mavenCentral()
                maven {
                    url 'https://dl.bintray.com/kotlin/kotlin-dev'
                }
            }

            dependencies {
                compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.70-eap-4"
            }
        """
        )
        importProject()

        Assert.assertEquals(
            "-version",
            testFacetSettings.compilerSettings!!.additionalArguments
        )

        assertAllModulesConfigured()
    }

    @Test
    fun testSharedLanguageVersion() {
        createProjectSubFile(
            "build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.60")
                    }
                }

                apply plugin: 'kotlin-platform-common'

                repositories {
                        mavenCentral()
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "settings.gradle",
            """
                    rootProject.name = 'MultiTest'
                    include 'MultiTest-jvm', 'MultiTest-js'
                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-js/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.60")
                    }
                }

                apply plugin: 'kotlin-platform-js'

                sourceSets {
                    myMain {
                        kotlin {
                            srcDir 'src'
                        }
                    }
                    myTest {
                        kotlin {
                            srcDir 'test'
                        }
                    }
                }

                repositories {
                        mavenCentral()
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.2.60"
                    implement project(":")
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-jvm/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.60")
                    }
                }

                apply plugin: 'kotlin-platform-jvm'

                repositories {
                    mavenCentral()
                }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.60"
                    implement project(":")
                }

                """.trimIndent()
        )

        val holder = KotlinCommonCompilerArgumentsHolder.getInstance(myProject)

        holder.update { languageVersion = "1.1" }

        importProject()

        TestCase.assertEquals("1.2", holder.settings.languageVersion)
    }

    @Test
    fun testNonSharedLanguageVersion() {
        createProjectSubFile(
            "build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.60")
                    }
                }

                apply plugin: 'kotlin-platform-common'

                repositories {
                    mavenCentral()
                }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-common:1.2.60"
                }

                compileKotlinCommon {
                    kotlinOptions.languageVersion = "1.1"
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "settings.gradle",
            """
                    rootProject.name = 'MultiTest'
                    include 'MultiTest-jvm', 'MultiTest-js'
                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-js/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.60")
                    }
                }

                apply plugin: 'kotlin-platform-js'

                repositories {
                    mavenCentral()
                }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib-js:1.2.60"
                    implement project(":")
                }

                """.trimIndent()
        )
        createProjectSubFile(
            "MultiTest-jvm/build.gradle",
            """
                buildscript {
                    repositories {
                        mavenCentral()
                    }
                    dependencies {
                        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.60")
                    }
                }

                apply plugin: 'kotlin-platform-jvm'

                sourceSets {
                    myMain {
                        kotlin {
                            srcDir 'src'
                        }
                    }
                    myTest {
                        kotlin {
                            srcDir 'test'
                        }
                    }
                }

                repositories {
                        mavenCentral()
                    }

                dependencies {
                    compile "org.jetbrains.kotlin:kotlin-stdlib:1.2.60"
                    implement project(":")
                }

                """.trimIndent()
        )

        val holder = KotlinCommonCompilerArgumentsHolder.getInstance(myProject)

        holder.update { languageVersion = "1.1" }

        importProject()

        TestCase.assertEquals("1.1", holder.settings.languageVersion)
    }

    private fun checkStableModuleName(projectName: String, expectedName: String, platform: TargetPlatform, isProduction: Boolean) {
        val module = getModule(projectName)
        val moduleInfo = if (isProduction) module.productionSourceInfo() else module.testSourceInfo()

        val resolutionFacade = KotlinCacheService.getInstance(myProject).getResolutionFacadeByModuleInfo(moduleInfo!!, platform)!!
        val moduleDescriptor = resolutionFacade.moduleDescriptor

        Assert.assertEquals("<$expectedName>", moduleDescriptor.stableName?.asString())
    }

    private fun assertAllModulesConfigured() {
        runReadAction {
            for (moduleGroup in ModuleSourceRootMap(myProject).groupByBaseModules(myProject.allModules())) {
                val configurator = allConfigurators().find {
                    it.getStatus(moduleGroup) == ConfigureKotlinStatus.CAN_BE_CONFIGURED
                }
                Assert.assertNull("Configurator $configurator tells that ${moduleGroup.baseModule} can be configured", configurator)
            }
        }
    }
}
