/*
 * Copyright 2015 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.jvm.plugins;

import com.beust.jcommander.internal.Lists;
import org.gradle.api.Action;
import org.gradle.api.Incubating;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.internal.service.ServiceRegistry;
import org.gradle.jvm.internal.JvmAssembly;
import org.gradle.jvm.internal.WithJvmAssembly;
import org.gradle.jvm.test.JUnitTestSuiteBinarySpec;
import org.gradle.jvm.test.JUnitTestSuiteSpec;
import org.gradle.jvm.test.internal.DefaultJUnitTestSuiteBinarySpec;
import org.gradle.jvm.test.internal.DefaultJUnitTestSuiteSpec;
import org.gradle.jvm.test.internal.JUnitTestSuiteRules;
import org.gradle.jvm.test.internal.JvmTestSuites;
import org.gradle.jvm.toolchain.JavaToolChainRegistry;
import org.gradle.model.Defaults;
import org.gradle.model.ModelMap;
import org.gradle.model.Path;
import org.gradle.model.RuleSource;
import org.gradle.model.internal.manage.schema.ModelSchemaStore;
import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.platform.base.*;
import org.gradle.platform.base.internal.PlatformResolvers;
import org.gradle.testing.base.plugins.TestingModelBasePlugin;

import javax.inject.Inject;
import java.io.File;

import static org.gradle.model.internal.core.ModelNodes.withType;
import static org.gradle.model.internal.core.NodePredicate.allDescendants;

/**
 * This plugin adds support for execution of JUnit test suites to the Java software model.
 *
 * @since 2.11
 */
@Incubating
public class JUnitTestSuitePlugin implements Plugin<Project> {

    private final ModelRegistry modelRegistry;

    @Inject
    public JUnitTestSuitePlugin(ModelRegistry modelRegistry) {
        this.modelRegistry = modelRegistry;
    }

    @Override
    public void apply(Project project) {
        project.getPluginManager().apply(TestingModelBasePlugin.class);
        project.getPluginManager().apply(JvmComponentPlugin.class);
        applyJUnitTestSuiteRules();
    }

    private void applyJUnitTestSuiteRules() {
        modelRegistry.getRoot().applyTo(allDescendants(withType(JUnitTestSuiteSpec.class)), JUnitTestSuiteRules.class);
    }

    @SuppressWarnings("UnusedDeclaration")
    static class PluginRules extends RuleSource {

        @ComponentType
        public void register(ComponentTypeBuilder<JUnitTestSuiteSpec> builder) {
            builder.defaultImplementation(DefaultJUnitTestSuiteSpec.class);
        }

        @BinaryType
        public void registerJUnitBinary(BinaryTypeBuilder<JUnitTestSuiteBinarySpec> builder) {
            builder.defaultImplementation(DefaultJUnitTestSuiteBinarySpec.class);
        }

        @Defaults
        public void createTestSuiteTasks(
                                  final ModelMap<JUnitTestSuiteBinarySpec> binaries,
                                  final @Path("buildDir") File buildDir,
                                  final ServiceRegistry registry,
                                  final ModelSchemaStore schemaStore) {
            binaries.afterEach(new Action<JUnitTestSuiteBinarySpec>() {
                @Override
                public void execute(JUnitTestSuiteBinarySpec binary) {
                    final JvmAssembly jvmAssembly = ((WithJvmAssembly) binary).getAssembly();
                    JvmTestSuites.createJvmTestSuiteTasks(binary, jvmAssembly, buildDir);
                }
            });
        }

        /**
         * Create binaries for test suites.
         */
        @ComponentBinaries
        void createJUnitComponentBinaries(ModelMap<BinarySpec> testBinaries,
                                          ServiceRegistry registry,
                                          PlatformResolvers platformResolver,
                                          JUnitTestSuiteSpec testSuite,
                                          JavaToolChainRegistry toolChains,
                                          ModelSchemaStore modelSchemaStore) {
            final String jUnitVersion = testSuite.getjUnitVersion();
            final DependencySpecContainer dependencies = testSuite.getDependencies();
            addJUnitDependencyTo(dependencies, jUnitVersion);
            JvmTestSuites.createJvmTestSuiteBinaries(
                testBinaries,
                registry,
                testSuite,
                JUnitTestSuiteBinarySpec.class,
                toolChains,
                platformResolver,
                modelSchemaStore,
                new Action<JUnitTestSuiteBinarySpec>() {
                @Override
                public void execute(JUnitTestSuiteBinarySpec jUnitTestSuiteBinarySpec) {
                    jUnitTestSuiteBinarySpec.setjUnitVersion(jUnitVersion);
                    setDependenciesOf(jUnitTestSuiteBinarySpec, dependencies);
                }
            });
        }

        private void setDependenciesOf(JUnitTestSuiteBinarySpec binary, DependencySpecContainer dependencies) {
            binary.setDependencies(Lists.newArrayList(dependencies.getDependencies()));
        }

        private void addJUnitDependencyTo(DependencySpecContainer dependencies, String jUnitVersion) {
            dependencies.group("junit").module("junit").version(jUnitVersion);
        }

    }

}

@@ -1047,32 +1047,83 @@
 tTestSuiteSpec;%0A
+import org.gradle.jvm.test.JvmTestSuiteBinarySpec;%0A
 import org.gradl
@@ -3389,20 +3389,18 @@
 delMap%3CJ
-Unit
+vm
 TestSuit
@@ -3668,36 +3668,34 @@
 ach(new Action%3CJ
-Unit
+vm
 TestSuiteBinaryS
@@ -3758,36 +3758,34 @@
 c void execute(J
-Unit
+vm
 TestSuiteBinaryS

Fix `createTestSuiteTasks` that has nothing specific to JUnit specs