<commit_before>/*
 * Copyright 2018, TeamDev. All rights reserved.
 *
 * 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.compiler;

import com.google.protobuf.DescriptorProtos;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor;
import io.spine.code.java.DefaultJavaProject;
import io.spine.code.java.SourceFile;
import io.spine.code.proto.FileName;
import io.spine.code.proto.FileSet;
import io.spine.tools.compiler.annotation.check.FieldAnnotationCheck;
import io.spine.tools.compiler.annotation.check.MainDefinitionAnnotationCheck;
import io.spine.tools.compiler.annotation.check.NestedTypeFieldsAnnotationCheck;
import io.spine.tools.compiler.annotation.check.NestedTypesAnnotationCheck;
import io.spine.tools.compiler.annotation.check.SourceCheck;
import io.spine.tools.gradle.GradleProject;
import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.impl.AbstractJavaSource;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junitpioneer.jupiter.TempDirectory;
import org.junitpioneer.jupiter.TempDirectory.TempDir;

import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkState;
import static io.spine.code.java.SourceFile.forMessage;
import static io.spine.code.java.SourceFile.forMessageOrBuilder;
import static io.spine.code.java.SourceFile.forOuterClassOf;
import static io.spine.code.java.SourceFile.forService;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.NO_SPI_OPTIONS;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.NO_SPI_OPTIONS_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.POTENTIAL_ANNOTATION_DUP;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_ALL;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_ALL_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_ALL_SERVICE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_FIELD;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_FIELD_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_MESSAGE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_MESSAGE_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_SERVICE;
import static io.spine.tools.gradle.TaskName.ANNOTATE_PROTO;
import static io.spine.tools.gradle.TaskName.COMPILE_JAVA;

@DisplayName("ProtoAnnotatorPlugin should")
@ExtendWith(TempDirectory.class)
class ProtoAnnotatorPluginTest {

    private static final String PROJECT_NAME = "annotator-plugin-test";

    private File testProjectDir;

    @BeforeEach
    void setUp(@TempDir Path tempDirPath) {
        testProjectDir = tempDirPath.toFile();
    }

    @Test
    @DisplayName("annotate if file option is true")
    void annotate_if_file_option_is_true() throws FileNotFoundException {
        assertNestedTypesAnnotations(SPI_ALL, true);
    }

    @Test
    @DisplayName("annotate service if file option if true")
    void annotate_service_if_file_option_is_true() throws FileNotFoundException {
        assertServiceAnnotations(SPI_ALL_SERVICE, true);
    }

    @Test
    @DisplayName("not annotate if file option if false")
    void not_annotate_if_file_option_if_false() throws FileNotFoundException {
        assertNestedTypesAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("not annotate service if file option is false")
    void not_annotate_service_if_file_option_if_false() throws FileNotFoundException {
        assertNestedTypesAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("annotate multiple files if file option is true")
    void annotate_multiple_files_if_file_option_is_true() throws FileNotFoundException {
        assertMainDefinitionAnnotations(SPI_ALL_MULTIPLE, true);
    }

    @Test
    @DisplayName("not annotate multiple files if file option is false")
    void not_annotate_multiple_files_if_file_option_is_false() throws FileNotFoundException {
        assertMainDefinitionAnnotations(NO_SPI_OPTIONS_MULTIPLE, false);
    }

    @Test
    @DisplayName("annotate if message option is true")
    void annotate_if_message_option_is_true() throws FileNotFoundException {
        assertNestedTypesAnnotations(SPI_MESSAGE, true);
    }

    @Test
    @DisplayName("not annotate if message option is false")
    void not_annotate_if_message_option_is_false() throws FileNotFoundException {
        assertNestedTypesAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("annotate multiple files if message option is true")
    void annotate_multiple_files_if_message_option_is_true() throws FileNotFoundException {
        assertMainDefinitionAnnotations(SPI_MESSAGE_MULTIPLE, true);
    }

    @Test
    @DisplayName("not annotate multiple files if message option is false")
    void not_annotate_multiple_files_if_message_option_is_false() throws FileNotFoundException {
        assertMainDefinitionAnnotations(NO_SPI_OPTIONS_MULTIPLE, false);
    }

    @Test
    @DisplayName("annotate accessors if field option is true")
    void annotate_accessors_if_field_option_is_true() throws FileNotFoundException {
        assertFieldAnnotations(SPI_FIELD, true);
    }

    @Test
    @DisplayName("not annotate accessors if field option is false")
    void not_annotate_accessors_if_field_option_is_false() throws FileNotFoundException {
        assertFieldAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("annotate accessors in multiple files if field option is true")
    void annotate_accessors_in_multiple_files_if_field_option_is_true()
            throws FileNotFoundException {
        assertFieldAnnotationsMultiple(SPI_FIELD_MULTIPLE, true);
    }

    @Test
    @DisplayName("not annotate accessors in multiple files if field option is false")
    void not_annotate_accessors_in_multiple_files_if_field_option_is_false()
            throws FileNotFoundException {
        assertFieldAnnotationsMultiple(NO_SPI_OPTIONS_MULTIPLE, false);
    }

    @Test
    @DisplayName("annotate GRPC services if section option is true")
    void annotate_grpc_services_if_service_option_is_true() throws FileNotFoundException {
        assertServiceAnnotations(SPI_SERVICE, true);
    }

    @Test
    @DisplayName("not annotate GRPC services if service option is false")
    void not_annotate_grpc_services_if_service_option_is_false() throws FileNotFoundException {
        assertServiceAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("compile generated source with potential annotation duplication")
    void compile_generated_sources_with_potential_annotation_duplication() {
        newProjectWithFile(POTENTIAL_ANNOTATION_DUP).executeTask(COMPILE_JAVA);
    }

    private void assertServiceAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        List<ServiceDescriptor> services = fileDescriptor.getServices();
        for (ServiceDescriptor serviceDescriptor : services) {
            SourceFile serviceFile = forService(serviceDescriptor.toProto(),
                                                fileDescriptor.toProto());
            checkGrpcService(serviceFile, new MainDefinitionAnnotationCheck(shouldBeAnnotated));
        }
    }

    private void assertFieldAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        Descriptor messageDescriptor = fileDescriptor.getMessageTypes().get(0);
        Path sourcePath = forMessage(messageDescriptor.toProto(), fileDescriptor.toProto())
                .getPath();
        NestedTypeFieldsAnnotationCheck check =
                new NestedTypeFieldsAnnotationCheck(messageDescriptor, shouldBeAnnotated);
        check(sourcePath, check);
    }

    private void assertFieldAnnotationsMultiple(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        Descriptor messageDescriptor = fileDescriptor.getMessageTypes().get(0);
        FieldDescriptor experimentalField = messageDescriptor.getFields().get(0);
        Path sourcePath = forMessage(messageDescriptor.toProto(), fileDescriptor.toProto())
                                    .getPath();
        check(sourcePath, new FieldAnnotationCheck(experimentalField, shouldBeAnnotated));
    }

    private void assertMainDefinitionAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        for (Descriptor messageDescriptor : fileDescriptor.getMessageTypes()) {
            DescriptorProto messageProto = messageDescriptor.toProto();
            DescriptorProtos.FileDescriptorProto fileProto = fileDescriptor.toProto();
            Path messagePath = forMessage(messageProto, fileProto).getPath();
            Path messageOrBuilderPath = forMessageOrBuilder(messageProto, fileProto).getPath();
            SourceCheck annotationCheck = new MainDefinitionAnnotationCheck(shouldBeAnnotated);
            check(messagePath, annotationCheck);
            check(messageOrBuilderPath, annotationCheck);
        }
    }

    private void assertNestedTypesAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        Path sourcePath = forOuterClassOf(fileDescriptor.toProto()).getPath();
        check(sourcePath, new NestedTypesAnnotationCheck(shouldBeAnnotated));
    }

    private void check(Path sourcePath, SourceCheck check) throws FileNotFoundException {
        Path filePath = DefaultJavaProject.at(testProjectDir)
                                          .generated()
                                          .mainJava()
                                          .resolve(sourcePath);
        @SuppressWarnings("unchecked")
        AbstractJavaSource<JavaClassSource> javaSource =
                Roaster.parse(AbstractJavaSource.class, filePath.toFile());
        check.apply(javaSource);
    }

    private void checkGrpcService(SourceFile serviceFile, SourceCheck check)
            throws FileNotFoundException {
        Path fullPath = DefaultJavaProject.at(testProjectDir)
                                          .generated()
                                          .mainGrpc()
                                          .resolve(serviceFile);
        @SuppressWarnings("unchecked")
        AbstractJavaSource<JavaClassSource> javaSource =
                Roaster.parse(AbstractJavaSource.class, fullPath.toFile());
        check.apply(javaSource);
    }

    /*
     * Test environment setup
     ************************************/

    private GradleProject newProjectWithFile(FileName protoFileName) {
        return GradleProject.newBuilder()
                            .setProjectName(PROJECT_NAME)
                            .setProjectFolder(testProjectDir)
                            .addProtoFile(protoFileName.value())
                            .enableDebug()
                            .build();
    }

    private FileDescriptor compileAndAnnotate(FileName testFile) {
        GradleProject gradleProject = newProjectWithFile(testFile);
        gradleProject.executeTask(ANNOTATE_PROTO);
        FileDescriptor result = getDescriptor(testFile);
        return result;
    }

    private FileDescriptor getDescriptor(FileName fileName) {
        File descriptorSet = DefaultJavaProject.at(testProjectDir)
                                               .mainDescriptors();
        FileSet fileSet = FileSet.parse(descriptorSet);
        Optional<FileDescriptor> file = fileSet.tryFind(fileName);
        checkState(file.isPresent(), "Unable to get file descriptor for %s", fileName);
        return file.get();
    }
}
<commit_msg>Fix test case naming.<commit_after>/*
 * Copyright 2018, TeamDev. All rights reserved.
 *
 * 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.compiler;

import com.google.protobuf.DescriptorProtos;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor;
import io.spine.code.java.DefaultJavaProject;
import io.spine.code.java.SourceFile;
import io.spine.code.proto.FileName;
import io.spine.code.proto.FileSet;
import io.spine.tools.compiler.annotation.check.FieldAnnotationCheck;
import io.spine.tools.compiler.annotation.check.MainDefinitionAnnotationCheck;
import io.spine.tools.compiler.annotation.check.NestedTypeFieldsAnnotationCheck;
import io.spine.tools.compiler.annotation.check.NestedTypesAnnotationCheck;
import io.spine.tools.compiler.annotation.check.SourceCheck;
import io.spine.tools.gradle.GradleProject;
import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.impl.AbstractJavaSource;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junitpioneer.jupiter.TempDirectory;
import org.junitpioneer.jupiter.TempDirectory.TempDir;

import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkState;
import static io.spine.code.java.SourceFile.forMessage;
import static io.spine.code.java.SourceFile.forMessageOrBuilder;
import static io.spine.code.java.SourceFile.forOuterClassOf;
import static io.spine.code.java.SourceFile.forService;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.NO_SPI_OPTIONS;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.NO_SPI_OPTIONS_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.POTENTIAL_ANNOTATION_DUP;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_ALL;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_ALL_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_ALL_SERVICE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_FIELD;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_FIELD_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_MESSAGE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_MESSAGE_MULTIPLE;
import static io.spine.tools.compiler.annotation.given.GivenProtoFile.SPI_SERVICE;
import static io.spine.tools.gradle.TaskName.ANNOTATE_PROTO;
import static io.spine.tools.gradle.TaskName.COMPILE_JAVA;

@DisplayName("ProtoAnnotatorPlugin should")
@ExtendWith(TempDirectory.class)
class ProtoAnnotatorPluginTest {

    private static final String PROJECT_NAME = "annotator-plugin-test";

    private File testProjectDir;

    @BeforeEach
    void setUp(@TempDir Path tempDirPath) {
        testProjectDir = tempDirPath.toFile();
    }

    @Test
    @DisplayName("annotate if file option is true")
    void annotateIfFileOptionIsTrue() throws FileNotFoundException {
        assertNestedTypesAnnotations(SPI_ALL, true);
    }

    @Test
    @DisplayName("annotate service if file option if true")
    void annotateServiceIfFileOptionIsTrue() throws FileNotFoundException {
        assertServiceAnnotations(SPI_ALL_SERVICE, true);
    }

    @Test
    @DisplayName("not annotate if file option if false")
    void notAnnotateIfFileOptionIfFalse() throws FileNotFoundException {
        assertNestedTypesAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("not annotate service if file option is false")
    void notAnnotateServiceIfFileOptionIfFalse() throws FileNotFoundException {
        assertNestedTypesAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("annotate multiple files if file option is true")
    void annotateMultipleFilesIfFileOptionIsTrue() throws FileNotFoundException {
        assertMainDefinitionAnnotations(SPI_ALL_MULTIPLE, true);
    }

    @Test
    @DisplayName("not annotate multiple files if file option is false")
    void notAnnotateMultipleFilesIfFileOptionIsFalse() throws FileNotFoundException {
        assertMainDefinitionAnnotations(NO_SPI_OPTIONS_MULTIPLE, false);
    }

    @Test
    @DisplayName("annotate if message option is true")
    void annotateIfMessageOptionIsTrue() throws FileNotFoundException {
        assertNestedTypesAnnotations(SPI_MESSAGE, true);
    }

    @Test
    @DisplayName("not annotate if message option is false")
    void notAnnotateIfMessageOptionIsFalse() throws FileNotFoundException {
        assertNestedTypesAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("annotate multiple files if message option is true")
    void annotateMultipleFilesIfMessageOptionIsTrue() throws FileNotFoundException {
        assertMainDefinitionAnnotations(SPI_MESSAGE_MULTIPLE, true);
    }

    @Test
    @DisplayName("not annotate multiple files if message option is false")
    void notAnnotateMultipleFilesIfMessageOptionIsFalse() throws FileNotFoundException {
        assertMainDefinitionAnnotations(NO_SPI_OPTIONS_MULTIPLE, false);
    }

    @Test
    @DisplayName("annotate accessors if field option is true")
    void annotateAccessorsIfFieldOptionIsTrue() throws FileNotFoundException {
        assertFieldAnnotations(SPI_FIELD, true);
    }

    @Test
    @DisplayName("not annotate accessors if field option is false")
    void notAnnotateAccessorsIfFieldOptionIsFalse() throws FileNotFoundException {
        assertFieldAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("annotate accessors in multiple files if field option is true")
    void annotateAccessorsInMultipleFilesIfFieldOptionIsTrue()
            throws FileNotFoundException {
        assertFieldAnnotationsMultiple(SPI_FIELD_MULTIPLE, true);
    }

    @Test
    @DisplayName("not annotate accessors in multiple files if field option is false")
    void notAnnotateAccessorsInMultipleFilesIfFieldOptionIsFalse()
            throws FileNotFoundException {
        assertFieldAnnotationsMultiple(NO_SPI_OPTIONS_MULTIPLE, false);
    }

    @Test
    @DisplayName("annotate GRPC services if section option is true")
    void annotateGrpcServicesIfServiceOptionIsTrue() throws FileNotFoundException {
        assertServiceAnnotations(SPI_SERVICE, true);
    }

    @Test
    @DisplayName("not annotate GRPC services if service option is false")
    void notAnnotateGrpcServicesIfServiceOptionIsFalse() throws FileNotFoundException {
        assertServiceAnnotations(NO_SPI_OPTIONS, false);
    }

    @Test
    @DisplayName("compile generated source with potential annotation duplication")
    void compileGeneratedSourcesWithPotentialAnnotationDuplication() {
        newProjectWithFile(POTENTIAL_ANNOTATION_DUP).executeTask(COMPILE_JAVA);
    }

    private void assertServiceAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        List<ServiceDescriptor> services = fileDescriptor.getServices();
        for (ServiceDescriptor serviceDescriptor : services) {
            SourceFile serviceFile = forService(serviceDescriptor.toProto(),
                                                fileDescriptor.toProto());
            checkGrpcService(serviceFile, new MainDefinitionAnnotationCheck(shouldBeAnnotated));
        }
    }

    private void assertFieldAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        Descriptor messageDescriptor = fileDescriptor.getMessageTypes().get(0);
        Path sourcePath = forMessage(messageDescriptor.toProto(), fileDescriptor.toProto())
                .getPath();
        NestedTypeFieldsAnnotationCheck check =
                new NestedTypeFieldsAnnotationCheck(messageDescriptor, shouldBeAnnotated);
        check(sourcePath, check);
    }

    private void assertFieldAnnotationsMultiple(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        Descriptor messageDescriptor = fileDescriptor.getMessageTypes().get(0);
        FieldDescriptor experimentalField = messageDescriptor.getFields().get(0);
        Path sourcePath = forMessage(messageDescriptor.toProto(), fileDescriptor.toProto())
                                    .getPath();
        check(sourcePath, new FieldAnnotationCheck(experimentalField, shouldBeAnnotated));
    }

    private void assertMainDefinitionAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        for (Descriptor messageDescriptor : fileDescriptor.getMessageTypes()) {
            DescriptorProto messageProto = messageDescriptor.toProto();
            DescriptorProtos.FileDescriptorProto fileProto = fileDescriptor.toProto();
            Path messagePath = forMessage(messageProto, fileProto).getPath();
            Path messageOrBuilderPath = forMessageOrBuilder(messageProto, fileProto).getPath();
            SourceCheck annotationCheck = new MainDefinitionAnnotationCheck(shouldBeAnnotated);
            check(messagePath, annotationCheck);
            check(messageOrBuilderPath, annotationCheck);
        }
    }

    private void assertNestedTypesAnnotations(FileName testFile, boolean shouldBeAnnotated)
            throws FileNotFoundException {
        FileDescriptor fileDescriptor = compileAndAnnotate(testFile);
        Path sourcePath = forOuterClassOf(fileDescriptor.toProto()).getPath();
        check(sourcePath, new NestedTypesAnnotationCheck(shouldBeAnnotated));
    }

    private void check(Path sourcePath, SourceCheck check) throws FileNotFoundException {
        Path filePath = DefaultJavaProject.at(testProjectDir)
                                          .generated()
                                          .mainJava()
                                          .resolve(sourcePath);
        @SuppressWarnings("unchecked")
        AbstractJavaSource<JavaClassSource> javaSource =
                Roaster.parse(AbstractJavaSource.class, filePath.toFile());
        check.apply(javaSource);
    }

    private void checkGrpcService(SourceFile serviceFile, SourceCheck check)
            throws FileNotFoundException {
        Path fullPath = DefaultJavaProject.at(testProjectDir)
                                          .generated()
                                          .mainGrpc()
                                          .resolve(serviceFile);
        @SuppressWarnings("unchecked")
        AbstractJavaSource<JavaClassSource> javaSource =
                Roaster.parse(AbstractJavaSource.class, fullPath.toFile());
        check.apply(javaSource);
    }

    /*
     * Test environment setup
     ************************************/

    private GradleProject newProjectWithFile(FileName protoFileName) {
        return GradleProject.newBuilder()
                            .setProjectName(PROJECT_NAME)
                            .setProjectFolder(testProjectDir)
                            .addProtoFile(protoFileName.value())
                            .enableDebug()
                            .build();
    }

    private FileDescriptor compileAndAnnotate(FileName testFile) {
        GradleProject gradleProject = newProjectWithFile(testFile);
        gradleProject.executeTask(ANNOTATE_PROTO);
        FileDescriptor result = getDescriptor(testFile);
        return result;
    }

    private FileDescriptor getDescriptor(FileName fileName) {
        File descriptorSet = DefaultJavaProject.at(testProjectDir)
                                               .mainDescriptors();
        FileSet fileSet = FileSet.parse(descriptorSet);
        Optional<FileDescriptor> file = fileSet.tryFind(fileName);
        checkState(file.isPresent(), "Unable to get file descriptor for %s", fileName);
        return file.get();
    }
}

{'fraction_non_alphanumeric': 0.07558956161750573, 'fraction_numerical': 0.0005174835514156871, 'mean_word_length': 3.7290683446949835, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4269211', 'n_tokens_mistral': 7154, 'n_tokens_neox': 6876, 'n_words': 1515}