/*
 * Copyright 2017 The Bazel Authors. 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
 *
 * 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 com.google.idea.blaze.base.command.buildresult;

import static com.google.common.truth.Truth.assertThat;
import static com.google.idea.common.guava.GuavaHelper.toImmutableList;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.idea.blaze.base.model.primitives.Kind;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.run.testlogs.BlazeTestResult;
import com.google.idea.blaze.base.run.testlogs.BlazeTestResult.TestStatus;
import com.google.idea.blaze.base.run.testlogs.BlazeTestResults;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEvent;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.TargetCompletedId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.TargetConfiguredId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.TestResultId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.NamedSetOfFiles;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TargetComplete;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TargetConfigured;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TestResult;
import com.intellij.openapi.vfs.LocalFileSystem;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Unit tests for {@link BuildEventProtocolOutputReader}. */
@RunWith(JUnit4.class)
public class BuildEventProtocolOutputReaderTest {

  @Rule public TemporaryFolder tmpFolder = new TemporaryFolder();

  @Test
  public void parseAllOutputFilenames_singleFileEvent_returnsAllFilenames() throws IOException {
    ImmutableList<String> filePaths =
        ImmutableList.of(
            "/usr/local/lib/File.py", "/usr/bin/python2.7", "/usr/local/home/script.sh");
    BuildEvent.Builder event = BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(filePaths));

    ImmutableList<File> parsedFilenames =
        BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(event), path -> true);

    assertThat(parsedFilenames)
        .containsExactly(filePaths.stream().map(File::new).toArray())
        .inOrder();
  }

  @Test
  public void parseAllOutputFilenamesWithFilter_singleFileEvent_returnsFilteredFilenames()
      throws IOException {
    Predicate<String> filter = path -> path.endsWith(".py");
    ImmutableList<String> filePaths =
        ImmutableList.of(
            "/usr/local/lib/File.py", "/usr/bin/python2.7", "/usr/local/home/script.sh");
    BuildEvent.Builder event = BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(filePaths));

    ImmutableList<File> parsedFilenames =
        BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(event), filter);

    assertThat(parsedFilenames).containsExactly(new File("/usr/local/lib/File.py"));
  }

  @Test
  public void parseAllOutputFilenames_nonFileEvent_returnsEmptyList() throws IOException {
    BuildEvent.Builder targetFinishedEvent =
        BuildEvent.newBuilder()
            .setCompleted(BuildEventStreamProtos.TargetComplete.getDefaultInstance());

    ImmutableList<File> parsedFilenames =
        BuildEventProtocolOutputReader.parseAllOutputFilenames(
            asInputStream(targetFinishedEvent), path -> true);

    assertThat(parsedFilenames).isEmpty();
  }

  @Test
  public void parseAllOutputFilenames_streamWithOneFileEvent_returnsAllFilenames()
      throws IOException {
    ImmutableList<String> filePaths =
        ImmutableList.of(
            "/usr/local/lib/Provider.java",
            "/usr/local/home/Executor.java",
            "/google/code/script.sh");
    List<BuildEvent.Builder> events =
        ImmutableList.of(
            BuildEvent.newBuilder()
                .setStarted(BuildEventStreamProtos.BuildStarted.getDefaultInstance()),
            BuildEvent.newBuilder()
                .setProgress(BuildEventStreamProtos.Progress.getDefaultInstance()),
            BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(filePaths)));

    ImmutableList<File> parsedFilenames =
        BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(events), path -> true);

    assertThat(parsedFilenames)
        .containsExactly(filePaths.stream().map(File::new).toArray())
        .inOrder();
  }

  @Test
  public void parseAllOutputFilenames_streamWithMultipleFileEvents_returnsAllFilenames()
      throws IOException {
    ImmutableList<String> fileSet1 =
        ImmutableList.of(
            "/usr/local/lib/Provider.java",
            "/usr/local/home/Executor.java",
            "/google/code/script.sh");

    ImmutableList<String> fileSet2 =
        ImmutableList.of(
            "/usr/local/code/ParserTest.java",
            "/usr/local/code/action_output.bzl",
            "/usr/genfiles/BUILD.bazel");

    List<BuildEvent.Builder> events =
        ImmutableList.of(
            BuildEvent.newBuilder()
                .setStarted(BuildEventStreamProtos.BuildStarted.getDefaultInstance()),
            BuildEvent.newBuilder()
                .setProgress(BuildEventStreamProtos.Progress.getDefaultInstance()),
            BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(fileSet1)),
            BuildEvent.newBuilder()
                .setProgress(BuildEventStreamProtos.Progress.getDefaultInstance()),
            BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(fileSet2)),
            BuildEvent.newBuilder()
                .setCompleted(BuildEventStreamProtos.TargetComplete.getDefaultInstance()));

    ImmutableList<File> allFiles =
        ImmutableList.<String>builder()
            .addAll(fileSet1)
            .addAll(fileSet2)
            .build()
            .stream()
            .map(File::new)
            .collect(toImmutableList());

    ImmutableList<File> parsedFilenames =
        BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(events), path -> true);

    assertThat(parsedFilenames).containsExactlyElementsIn(allFiles).inOrder();
  }

  @Test
  public void testStatusEnum_handlesAllProtoEnumValues() {
    Set<String> protoValues =
        EnumSet.allOf(BuildEventStreamProtos.TestStatus.class)
            .stream()
            .map(Enum::name)
            .collect(Collectors.toSet());
    protoValues.remove(BuildEventStreamProtos.TestStatus.UNRECOGNIZED.name());
    Set<String> handledValues =
        EnumSet.allOf(TestStatus.class).stream().map(Enum::name).collect(Collectors.toSet());

    assertThat(protoValues).containsExactlyElementsIn(handledValues);
  }

  @Test
  public void parseTestResults_singleEvent_returnsTestResults() throws IOException {
    Label label = Label.create("//java/com/google:unit_tests");
    BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
    ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
    BuildEvent.Builder event = testResultEvent(label.toString(), status, filePaths);

    BlazeTestResults results =
        BuildEventProtocolOutputReader.parseTestResults(asInputStream(event));

    assertThat(results.perTargetResults.keySet()).containsExactly(label);
    assertThat(results.perTargetResults.get(label)).hasSize(1);
    BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
    assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
    assertThat(result.getOutputXmlFiles())
        .containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
  }

  @Test
  public void parseTestResults_singleTestEventWithTargetConfigured_resultsIncludeTargetKind()
      throws IOException {
    Label label = Label.create("//java/com/google:unit_tests");
    BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
    ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
    InputStream events =
        asInputStream(
            targetConfiguredEvent(label.toString(), "java_test rule"),
            testResultEvent(label.toString(), status, filePaths));

    BlazeTestResults results = BuildEventProtocolOutputReader.parseTestResults(events);

    assertThat(results.perTargetResults.keySet()).containsExactly(label);
    assertThat(results.perTargetResults.get(label)).hasSize(1);
    BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
    assertThat(result.getTargetKind()).isEqualTo(Kind.JAVA_TEST);
    assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
    assertThat(result.getOutputXmlFiles())
        .containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
  }

  @Test
  public void parseTestResults_singleTestEventWithTargetCompleted_resultsIncludeTargetKind()
      throws IOException {
    Label label = Label.create("//java/com/google:unit_tests");
    BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
    ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
    InputStream events =
        asInputStream(
            targetCompletedEvent(label.toString(), "java_test rule"),
            testResultEvent(label.toString(), status, filePaths));

    BlazeTestResults results = BuildEventProtocolOutputReader.parseTestResults(events);

    assertThat(results.perTargetResults.keySet()).containsExactly(label);
    assertThat(results.perTargetResults.get(label)).hasSize(1);
    BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
    assertThat(result.getTargetKind()).isEqualTo(Kind.JAVA_TEST);
    assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
    assertThat(result.getOutputXmlFiles())
        .containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
  }

  @Test
  public void parseTestResults_multipleTargetKindSources_resultsIncludeCorrectTargetKind()
      throws IOException {
    Label label = Label.create("//java/com/google:unit_tests");
    BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
    ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
    InputStream events =
        asInputStream(
            targetConfiguredEvent(label.toString(), "java_test rule"),
            targetCompletedEvent(label.toString(), "java_test rule"),
            testResultEvent(label.toString(), status, filePaths));

    BlazeTestResults results = BuildEventProtocolOutputReader.parseTestResults(events);

    assertThat(results.perTargetResults.keySet()).containsExactly(label);
    assertThat(results.perTargetResults.get(label)).hasSize(1);
    BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
    assertThat(result.getTargetKind()).isEqualTo(Kind.JAVA_TEST);
    assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
    assertThat(result.getOutputXmlFiles())
        .containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
  }

  @Test
  public void parseTestResults_singleEvent_ignoresNonXmlOutputFiles() throws IOException {
    Label label = Label.create("//java/com/google:unit_tests");
    BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
    ImmutableList<String> filePaths =
        ImmutableList.of(
            "/usr/local/tmp/_cache/test_result.xml",
            "/usr/local/tmp/_cache/test_result.log",
            "/usr/local/tmp/other_output_file");
    BuildEvent.Builder event = testResultEvent(label.toString(), status, filePaths);

    BlazeTestResults results =
        BuildEventProtocolOutputReader.parseTestResults(asInputStream(event));

    BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
    assertThat(result.getOutputXmlFiles())
        .containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
  }

  @Test
  public void parseTestResults_singleTargetWithMultipleEvents_returnsTestResults()
      throws IOException {
    Label label = Label.create("//java/com/google:unit_tests");
    BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.PASSED;
    BuildEvent.Builder shard1 =
        testResultEvent(
            label.toString(), status, ImmutableList.of("/usr/local/tmp/_cache/shard1_of_2.xml"));
    BuildEvent.Builder shard2 =
        testResultEvent(
            label.toString(), status, ImmutableList.of("/usr/local/tmp/_cache/shard2_of_2.xml"));

    BlazeTestResults results =
        BuildEventProtocolOutputReader.parseTestResults(asInputStream(shard1, shard2));

    assertThat(results.perTargetResults).hasSize(2);
    Collection<BlazeTestResult> targetResults = results.perTargetResults.get(label);
    assertThat(targetResults)
        .containsExactly(
            BlazeTestResult.create(
                label,
                null,
                TestStatus.PASSED,
                ImmutableSet.of(new File("/usr/local/tmp/_cache/shard1_of_2.xml"))),
            BlazeTestResult.create(
                label,
                null,
                TestStatus.PASSED,
                ImmutableSet.of(new File("/usr/local/tmp/_cache/shard2_of_2.xml"))));
  }

  @Test
  public void parseTestResults_multipleEvents_returnsAllResults() throws IOException {
    BuildEvent.Builder test1 =
        testResultEvent(
            "//java/com/google:Test1",
            BuildEventStreamProtos.TestStatus.PASSED,
            ImmutableList.of("/usr/local/tmp/_cache/test_result.xml"));
    BuildEvent.Builder test2 =
        testResultEvent(
            "//java/com/google:Test2",
            BuildEventStreamProtos.TestStatus.INCOMPLETE,
            ImmutableList.of("/usr/local/tmp/_cache/second_result.xml"));

    BlazeTestResults results =
        BuildEventProtocolOutputReader.parseTestResults(asInputStream(test1, test2));

    assertThat(results.perTargetResults).hasSize(2);
    assertThat(results.perTargetResults.get(Label.create("//java/com/google:Test1"))).hasSize(1);
    assertThat(results.perTargetResults.get(Label.create("//java/com/google:Test2"))).hasSize(1);
    BlazeTestResult result1 =
        results.perTargetResults.get(Label.create("//java/com/google:Test1")).iterator().next();
    assertThat(result1.getTestStatus()).isEqualTo(TestStatus.PASSED);
    assertThat(result1.getOutputXmlFiles())
        .containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
    BlazeTestResult result2 =
        results.perTargetResults.get(Label.create("//java/com/google:Test2")).iterator().next();
    assertThat(result2.getTestStatus()).isEqualTo(TestStatus.INCOMPLETE);
    assertThat(result2.getOutputXmlFiles())
        .containsExactly(new File("/usr/local/tmp/_cache/second_result.xml"));
  }

  private static InputStream asInputStream(BuildEvent.Builder... events) throws IOException {
    return asInputStream(Arrays.asList(events));
  }

  private static InputStream asInputStream(Iterable<BuildEvent.Builder> events) throws IOException {
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    for (BuildEvent.Builder event : events) {
      event.build().writeDelimitedTo(output);
    }
    return new ByteArrayInputStream(output.toByteArray());
  }

  private static BuildEvent.Builder targetConfiguredEvent(String label, String targetKind) {
    return BuildEvent.newBuilder()
        .setId(
            BuildEventId.newBuilder()
                .setTargetConfigured(TargetConfiguredId.newBuilder().setLabel(label)))
        .setConfigured(TargetConfigured.newBuilder().setTargetKind(targetKind));
  }

  private static BuildEvent.Builder targetCompletedEvent(String label, String targetKind) {
    return BuildEvent.newBuilder()
        .setId(
            BuildEventId.newBuilder()
                .setTargetCompleted(TargetCompletedId.newBuilder().setLabel(label)))
        .setCompleted(TargetComplete.newBuilder().setTargetKind(targetKind));
  }

  private static BuildEvent.Builder testResultEvent(
      String label, BuildEventStreamProtos.TestStatus status, List<String> filePaths) {
    return BuildEvent.newBuilder()
        .setId(BuildEventId.newBuilder().setTestResult(TestResultId.newBuilder().setLabel(label)))
        .setTestResult(
            TestResult.newBuilder()
                .setStatus(status)
                .addAllTestActionOutput(
                    filePaths
                        .stream()
                        .map(BuildEventProtocolOutputReaderTest::toEventFile)
                        .collect(toImmutableList())));
  }

  private static NamedSetOfFiles setOfFiles(List<String> filePaths) {
    return NamedSetOfFiles.newBuilder()
        .addAllFiles(
            filePaths
                .stream()
                .map(BuildEventProtocolOutputReaderTest::toEventFile)
                .collect(toImmutableList()))
        .build();
  }

  private static BuildEventStreamProtos.File toEventFile(String filePath) {
    return BuildEventStreamProtos.File.newBuilder().setUri(fileUrl(filePath)).build();
  }

  private static String fileUrl(String filePath) {
    return LocalFileSystem.PROTOCOL_PREFIX + filePath;
  }
}
