<commit_before>/*
 * Copyright 2021, TeamDev. All rights reserved.
 *
 * 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
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.tools.gradle.testing;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.spine.tools.gradle.TaskName;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.spine.io.Files2.copyDir;
import static io.spine.util.Exceptions.illegalStateWithCauseOf;
import static java.nio.file.Files.copy;
import static java.nio.file.Files.createDirectories;
import static java.nio.file.Files.write;
import static java.util.Arrays.asList;

/**
 * Allows to configure a Gradle project for testing needs.
 *
 * <p>The project operates in the given test project directory and allows to execute Gradle tasks.
 */
public final class GradleProject {

    private static final String mainProtoDir = "src/main/proto/";
    private static final String mainJavaDir = "src/main/java/";
    private static final String buildSrcDir = "buildSrc";

    private final String name;
    private final GradleRunner gradleRunner;
    private final boolean debug;
    private final ImmutableMap<String, String> gradleProperties;

    /**
     * Creates new builder for the project.
     */
    public static Builder newBuilder() {
        return new Builder();
    }

    /**
     * Obtains the name of the Java Gradle plugin.
     */
    public static String javaPlugin() {
        return "java";
    }

    private GradleProject(Builder builder) throws IOException {
        this.name = builder.name;
        this.debug = builder.debug;
        this.gradleRunner = GradleRunner.create()
                .withProjectDir(builder.folder)
                .withDebug(builder.debug);
        if (builder.addPluginUnderTestClasspath) {
            gradleRunner.withPluginClasspath();
        }
        if (builder.environment != null) {
            gradleRunner.withEnvironment(builder.environment);
        }
        this.gradleProperties = ImmutableMap.copyOf(builder.gradleProperties);
        writeGradleScripts();
        writeBuildSrc();
        writeProtoFiles(builder.protoFileNames);
        writeJavaFiles(builder.javaFileNames);
    }

    private void writeGradleScripts() throws IOException {
        BuildGradle buildGradle = new BuildGradle(projectRoot());
        buildGradle.createFile();

        Path projectRoot = ProjectRoot.instance().toPath();
        TestEnvGradle testEnvGradle = new TestEnvGradle(projectRoot, projectRoot());
        testEnvGradle.createFile();
    }

    private void writeBuildSrc() throws IOException {
        Path projectRoot = ProjectRoot.instance().toPath();
        Path buildSrc = projectRoot.resolve(buildSrcDir);
        Path target = projectRoot();
        copyDir(buildSrc, target, new SkipNonSrcDirs());
    }

    /**
     * The predicate to prevent copying Gradle cache directory, and build results.
     *
     * <p>The predicate 1) saves on unnecessary copying, 2) prevents file locking issue
     * under Windows, which fails the build because locked under the {@code .gradle}
     * directory could not be copied.
     */
    private static class SkipNonSrcDirs implements Predicate<Path> {

        @Override
        public boolean test(Path path) {
            String str = path.toString();
            String slash = File.separator;
            // Use leading slash to accept `.gradle` files, but filter out the Gradle cache dir.
            boolean isGradleCache = str.contains(slash + ".gradle");
//            // Use two slashes to accept `build.gradle.kts`, but filter out the `build` dir.
//            @SuppressWarnings("DuplicateStringLiteralInspection")
//            boolean isBuildDir = str.contains(slash + "build" + slash);
            return !isGradleCache /*&& !isBuildDir*/;
        }
    }

    private void writeProtoFiles(Iterable<String> fileNames) throws IOException {
        for (String protoFile : fileNames) {
            writeProto(protoFile);
        }
    }

    private void writeJavaFiles(Iterable<String> fileNames) throws IOException {<commit_msg>Associate commented block with its issue<commit_after>/*
 * Copyright 2021, TeamDev. All rights reserved.
 *
 * 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
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.tools.gradle.testing;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.spine.tools.gradle.TaskName;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static io.spine.io.Files2.copyDir;
import static io.spine.util.Exceptions.illegalStateWithCauseOf;
import static java.nio.file.Files.copy;
import static java.nio.file.Files.createDirectories;
import static java.nio.file.Files.write;
import static java.util.Arrays.asList;

/**
 * Allows to configure a Gradle project for testing needs.
 *
 * <p>The project operates in the given test project directory and allows to execute Gradle tasks.
 */
public final class GradleProject {

    private static final String mainProtoDir = "src/main/proto/";
    private static final String mainJavaDir = "src/main/java/";
    private static final String buildSrcDir = "buildSrc";

    private final String name;
    private final GradleRunner gradleRunner;
    private final boolean debug;
    private final ImmutableMap<String, String> gradleProperties;

    /**
     * Creates new builder for the project.
     */
    public static Builder newBuilder() {
        return new Builder();
    }

    /**
     * Obtains the name of the Java Gradle plugin.
     */
    public static String javaPlugin() {
        return "java";
    }

    private GradleProject(Builder builder) throws IOException {
        this.name = builder.name;
        this.debug = builder.debug;
        this.gradleRunner = GradleRunner.create()
                .withProjectDir(builder.folder)
                .withDebug(builder.debug);
        if (builder.addPluginUnderTestClasspath) {
            gradleRunner.withPluginClasspath();
        }
        if (builder.environment != null) {
            gradleRunner.withEnvironment(builder.environment);
        }
        this.gradleProperties = ImmutableMap.copyOf(builder.gradleProperties);
        writeGradleScripts();
        writeBuildSrc();
        writeProtoFiles(builder.protoFileNames);
        writeJavaFiles(builder.javaFileNames);
    }

    private void writeGradleScripts() throws IOException {
        BuildGradle buildGradle = new BuildGradle(projectRoot());
        buildGradle.createFile();

        Path projectRoot = ProjectRoot.instance().toPath();
        TestEnvGradle testEnvGradle = new TestEnvGradle(projectRoot, projectRoot());
        testEnvGradle.createFile();
    }

    private void writeBuildSrc() throws IOException {
        Path projectRoot = ProjectRoot.instance().toPath();
        Path buildSrc = projectRoot.resolve(buildSrcDir);
        Path target = projectRoot();
        copyDir(buildSrc, target, new SkipNonSrcDirs());
    }

    /**
     * The predicate to prevent copying unnecessary files when {@linkplain #writeBuildSrc() copying}
     * the {@code buildSrc} directory.
     *
     * <p>The predicate 1) saves on unnecessary copying, 2) prevents file locking issue
     * under Windows, which fails the build because locked under the {@code .gradle}
     * directory could not be copied.
     */
    private static class SkipNonSrcDirs implements Predicate<Path> {

        @Override
        public boolean test(Path path) {
            String str = path.toString();
            String slash = File.separator;
            // Use leading slash to accept `.gradle` files, but filter out the Gradle cache dir.
            boolean isGradleCache = str.contains(slash + ".gradle");

            /**
             * The following block is commented out because not copying the `build`
             * makes dependencies defined as Kotlin objects (see
             * `buildSrc/src/main/kotlin/io/spine/internal/dependency`) unresolvable in
             * Groovy-based Gradle scripts in tests.
             *
             * Uncomment the below block and the associated boolean operation in the `return`
             * statement when resolving
             * the [associated issue][https://github.com/SpineEventEngine/base/issues/655].
             */
//            // Use two slashes to accept `build.gradle.kts`, but filter out the `build` dir.
//            @SuppressWarnings("DuplicateStringLiteralInspection")
//            boolean isBuildDir = str.contains(slash + "build" + slash);
            return !isGradleCache /*&& !isBuildDir*/;
        }
    }

    private void writeProtoFiles(Iterable<String> fileNames) throws IOException {
        for (String protoFile : fileNames) {
            writeProto(protoFile);
        }
    }

    private void writeJavaFiles(Iterable<String> fileNames) throws IOException {
{'fraction_non_alphanumeric': 0.08660785886126704, 'fraction_numerical': 0.002004811547714515, 'mean_word_length': 3.2288911495422177, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 1, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '683380', 'n_tokens_mistral': 3395, 'n_tokens_neox': 3210, 'n_words': 1067}