private void processScm(@Nullable BatchReport.Changesets scm) {
      if (scm == null) {
        return;
      }

      for (BatchReport.Changesets.Changeset changeset : scm.getChangesetList()) {
        if (changeset.hasDate() && changeset.getDate() > lastCommitTimestampFromReport) {
          lastCommitTimestampFromReport = changeset.getDate();
        }
      }
    }
 @Override
 public void visitFile(Component file, Path<LastCommit> path) {
   // load SCM blame information from report. It can be absent when the file was not touched
   // since previous analysis (optimization to decrease execution of blame commands). In this case
   // the date is loaded from database, as it did not change from previous analysis.
   BatchReport.Changesets changesets =
       reportReader.readChangesets(file.getReportAttributes().getRef());
   if (changesets == null) {
     Optional<Measure> baseMeasure = measureRepository.getBaseMeasure(file, lastCommitDateMetric);
     if (baseMeasure.isPresent()) {
       path.current().addDate(baseMeasure.get().getLongValue());
     }
   } else {
     for (BatchReport.Changesets.Changeset changeset : changesets.getChangesetList()) {
       if (changeset.hasDate()) {
         path.current().addDate(changeset.getDate());
       }
     }
   }
   saveAndAggregate(file, path);
 }
  @Override
  public synchronized void blameResult(InputFile file, List<BlameLine> lines) {
    Preconditions.checkNotNull(file);
    Preconditions.checkNotNull(lines);
    Preconditions.checkArgument(
        allFilesToBlame.contains(file),
        "It was not expected to blame file %s",
        file.relativePath());

    if (lines.size() != file.lines()) {
      LOG.debug(
          "Ignoring blame result since provider returned {} blame lines but file {} has {} lines",
          lines.size(),
          file.relativePath(),
          file.lines());
      return;
    }

    BatchComponent batchComponent = componentCache.get(file);
    Builder scmBuilder = BatchReport.Changesets.newBuilder();
    scmBuilder.setComponentRef(batchComponent.batchId());
    Map<String, Integer> changesetsIdByRevision = new HashMap<>();

    int lineId = 1;
    for (BlameLine line : lines) {
      validateLine(line, lineId, file);
      Integer changesetId = changesetsIdByRevision.get(line.revision());
      if (changesetId == null) {
        addChangeset(scmBuilder, line);
        changesetId = scmBuilder.getChangesetCount() - 1;
        changesetsIdByRevision.put(line.revision(), changesetId);
      }
      scmBuilder.addChangesetIndexByLine(changesetId);
      lineId++;
    }
    writer.writeComponentChangesets(scmBuilder.build());
    allFilesToBlame.remove(file);
    count++;
    progressReport.message(count + "/" + total + " files analyzed");
  }
public class BatchReportReaderImplTest {
  private static final int COMPONENT_REF = 1;
  private static final BatchReport.Changesets CHANGESETS =
      BatchReport.Changesets.newBuilder().setComponentRef(COMPONENT_REF).build();
  private static final BatchReport.Measure MEASURE = BatchReport.Measure.newBuilder().build();
  private static final BatchReport.Component COMPONENT =
      BatchReport.Component.newBuilder().setRef(COMPONENT_REF).build();
  private static final BatchReport.Issue ISSUE = BatchReport.Issue.newBuilder().build();
  private static final BatchReport.Duplication DUPLICATION =
      BatchReport.Duplication.newBuilder().build();
  private static final BatchReport.CpdTextBlock DUPLICATION_BLOCK =
      BatchReport.CpdTextBlock.newBuilder().build();
  private static final BatchReport.Symbol SYMBOL = BatchReport.Symbol.newBuilder().build();
  private static final BatchReport.SyntaxHighlighting SYNTAX_HIGHLIGHTING_1 =
      BatchReport.SyntaxHighlighting.newBuilder().build();
  private static final BatchReport.SyntaxHighlighting SYNTAX_HIGHLIGHTING_2 =
      BatchReport.SyntaxHighlighting.newBuilder().build();
  private static final BatchReport.Coverage COVERAGE_1 = BatchReport.Coverage.newBuilder().build();
  private static final BatchReport.Coverage COVERAGE_2 = BatchReport.Coverage.newBuilder().build();
  private static final BatchReport.Test TEST_1 = BatchReport.Test.newBuilder().setName("1").build();
  private static final BatchReport.Test TEST_2 = BatchReport.Test.newBuilder().setName("2").build();
  private static final BatchReport.CoverageDetail COVERAGE_DETAIL_1 =
      BatchReport.CoverageDetail.newBuilder().setTestName("1").build();
  private static final BatchReport.CoverageDetail COVERAGE_DETAIL_2 =
      BatchReport.CoverageDetail.newBuilder().setTestName("2").build();

  @Rule public JUnitTempFolder tempFolder = new JUnitTempFolder();

  private BatchReportWriter writer;
  private BatchReportReaderImpl underTest;

  @Before
  public void setUp() {
    BatchReportDirectoryHolder holder =
        new ImmutableBatchReportDirectoryHolder(tempFolder.newDir());
    underTest = new BatchReportReaderImpl(holder);
    writer = new BatchReportWriter(holder.getDirectory());
  }

  @Test(expected = IllegalStateException.class)
  public void readMetadata_throws_ISE_if_no_metadata() {
    underTest.readMetadata();
  }

  @Test
  public void readMetadata_result_is_cached() {
    BatchReport.Metadata metadata = BatchReport.Metadata.newBuilder().build();

    writer.writeMetadata(metadata);

    BatchReport.Metadata res = underTest.readMetadata();
    assertThat(res).isEqualTo(metadata);
    assertThat(underTest.readMetadata()).isSameAs(res);
  }

  @Test
  public void readScannerLogs() throws IOException {
    File scannerLogFile = writer.getFileStructure().analysisLog();
    FileUtils.write(scannerLogFile, "log1\nlog2");

    CloseableIterator<String> logs = underTest.readScannerLogs();
    assertThat(logs).containsExactly("log1", "log2");
  }

  @Test
  public void readScannerLogs_no_logs() {
    CloseableIterator<String> logs = underTest.readScannerLogs();
    assertThat(logs.hasNext()).isFalse();
  }

  @Test
  public void readComponentMeasures_returns_empty_list_if_there_is_no_measure() {
    assertThat(underTest.readComponentMeasures(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readComponentMeasures_returns_measures() {
    writer.writeComponentMeasures(COMPONENT_REF, of(MEASURE));

    try (CloseableIterator<BatchReport.Measure> measures =
        underTest.readComponentMeasures(COMPONENT_REF)) {
      assertThat(measures.next()).isEqualTo(MEASURE);
      assertThat(measures.hasNext()).isFalse();
    }
  }

  @Test
  public void readComponentMeasures_is_not_cached() {
    writer.writeComponentMeasures(COMPONENT_REF, of(MEASURE));

    assertThat(underTest.readComponentMeasures(COMPONENT_REF))
        .isNotSameAs(underTest.readComponentMeasures(COMPONENT_REF));
  }

  @Test
  public void readChangesets_returns_null_if_no_changeset() {
    assertThat(underTest.readChangesets(COMPONENT_REF)).isNull();
  }

  @Test
  public void verify_readChangesets_returns_changesets() {
    writer.writeComponentChangesets(CHANGESETS);

    BatchReport.Changesets res = underTest.readChangesets(COMPONENT_REF);
    assertThat(res).isEqualTo(CHANGESETS);
  }

  @Test
  public void readChangesets_is_not_cached() {
    writer.writeComponentChangesets(CHANGESETS);

    assertThat(underTest.readChangesets(COMPONENT_REF))
        .isNotSameAs(underTest.readChangesets(COMPONENT_REF));
  }

  @Test(expected = IllegalStateException.class)
  public void readComponent_throws_ISE_if_file_does_not_exist() {
    underTest.readComponent(COMPONENT_REF);
  }

  @Test
  public void verify_readComponent_returns_Component() {
    writer.writeComponent(COMPONENT);

    assertThat(underTest.readComponent(COMPONENT_REF)).isEqualTo(COMPONENT);
  }

  @Test
  public void readComponent_is_not_cached() {
    writer.writeComponent(COMPONENT);

    assertThat(underTest.readComponent(COMPONENT_REF))
        .isNotSameAs(underTest.readComponent(COMPONENT_REF));
  }

  @Test
  public void readComponentIssues_returns_empty_list_if_file_does_not_exist() {
    assertThat(underTest.readComponentIssues(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readComponentIssues_returns_Issues() {
    writer.writeComponentIssues(COMPONENT_REF, of(ISSUE));

    try (CloseableIterator<BatchReport.Issue> res = underTest.readComponentIssues(COMPONENT_REF)) {
      assertThat(res.next()).isEqualTo(ISSUE);
      assertThat(res.hasNext()).isFalse();
    }
  }

  @Test
  public void readComponentIssues_it_not_cached() {
    writer.writeComponentIssues(COMPONENT_REF, of(ISSUE));

    assertThat(underTest.readComponentIssues(COMPONENT_REF))
        .isNotSameAs(underTest.readComponentIssues(COMPONENT_REF));
  }

  @Test
  public void readComponentDuplications_returns_empty_list_if_file_does_not_exist() {
    assertThat(underTest.readComponentDuplications(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readComponentDuplications_returns_Issues() {
    writer.writeComponentDuplications(COMPONENT_REF, of(DUPLICATION));

    try (CloseableIterator<BatchReport.Duplication> res =
        underTest.readComponentDuplications(COMPONENT_REF)) {
      assertThat(res.next()).isEqualTo(DUPLICATION);
      assertThat(res.hasNext()).isFalse();
    }
  }

  @Test
  public void readComponentDuplications_it_not_cached() {
    writer.writeComponentDuplications(COMPONENT_REF, of(DUPLICATION));

    assertThat(underTest.readComponentDuplications(COMPONENT_REF))
        .isNotSameAs(underTest.readComponentDuplications(COMPONENT_REF));
  }

  @Test
  public void readComponentDuplicationBlocks_returns_empty_list_if_file_does_not_exist() {
    assertThat(underTest.readCpdTextBlocks(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readComponentDuplicationBlocks_returns_Issues() {
    writer.writeCpdTextBlocks(COMPONENT_REF, of(DUPLICATION_BLOCK));

    try (CloseableIterator<BatchReport.CpdTextBlock> res =
        underTest.readCpdTextBlocks(COMPONENT_REF)) {
      assertThat(res.next()).isEqualTo(DUPLICATION_BLOCK);
      assertThat(res.hasNext()).isFalse();
    }
  }

  @Test
  public void readComponentDuplicationBlocks_is_not_cached() {
    writer.writeCpdTextBlocks(COMPONENT_REF, of(DUPLICATION_BLOCK));

    assertThat(underTest.readCpdTextBlocks(COMPONENT_REF))
        .isNotSameAs(underTest.readCpdTextBlocks(COMPONENT_REF));
  }

  @Test
  public void readComponentSymbols_returns_empty_list_if_file_does_not_exist() {
    assertThat(underTest.readComponentSymbols(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readComponentSymbols_returns_Issues() {
    writer.writeComponentSymbols(COMPONENT_REF, of(SYMBOL));

    try (CloseableIterator<BatchReport.Symbol> res =
        underTest.readComponentSymbols(COMPONENT_REF)) {
      assertThat(res.next()).isEqualTo(SYMBOL);
      assertThat(res.hasNext()).isFalse();
    }
  }

  @Test
  public void readComponentSymbols_it_not_cached() {
    writer.writeComponentSymbols(COMPONENT_REF, of(SYMBOL));

    assertThat(underTest.readComponentSymbols(COMPONENT_REF))
        .isNotSameAs(underTest.readComponentSymbols(COMPONENT_REF));
  }

  @Test
  public void
      readComponentSyntaxHighlighting_returns_empty_CloseableIterator_when_file_does_not_exist() {
    assertThat(underTest.readComponentSyntaxHighlighting(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readComponentSyntaxHighlighting() {
    writer.writeComponentSyntaxHighlighting(
        COMPONENT_REF, of(SYNTAX_HIGHLIGHTING_1, SYNTAX_HIGHLIGHTING_2));

    CloseableIterator<BatchReport.SyntaxHighlighting> res =
        underTest.readComponentSyntaxHighlighting(COMPONENT_REF);
    assertThat(res).containsExactly(SYNTAX_HIGHLIGHTING_1, SYNTAX_HIGHLIGHTING_2);
    res.close();
  }

  @Test
  public void readComponentCoverage_returns_empty_CloseableIterator_when_file_does_not_exist() {
    assertThat(underTest.readComponentCoverage(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readComponentCoverage() {
    writer.writeComponentCoverage(COMPONENT_REF, of(COVERAGE_1, COVERAGE_2));

    CloseableIterator<BatchReport.Coverage> res = underTest.readComponentCoverage(COMPONENT_REF);
    assertThat(res).containsExactly(COVERAGE_1, COVERAGE_2);
    res.close();
  }

  @Test
  public void readFileSource_returns_absent_optional_when_file_does_not_exist() {
    assertThat(underTest.readFileSource(COMPONENT_REF)).isAbsent();
  }

  @Test
  public void verify_readFileSource() throws IOException {
    File file = writer.getSourceFile(COMPONENT_REF);
    FileUtils.writeLines(file, of("1", "2", "3"));

    CloseableIterator<String> res = underTest.readFileSource(COMPONENT_REF).get();
    assertThat(res).containsExactly("1", "2", "3");
    res.close();
  }

  @Test
  public void readTests_returns_empty_CloseableIterator_when_file_does_not_exist() {
    assertThat(underTest.readTests(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readTests() {
    writer.writeTests(COMPONENT_REF, of(TEST_1, TEST_2));

    CloseableIterator<BatchReport.Test> res = underTest.readTests(COMPONENT_REF);
    assertThat(res).containsExactly(TEST_1, TEST_2);
    res.close();
  }

  @Test
  public void readCoverageDetails_returns_empty_CloseableIterator_when_file_does_not_exist() {
    assertThat(underTest.readCoverageDetails(COMPONENT_REF)).isEmpty();
  }

  @Test
  public void verify_readCoverageDetails() {
    writer.writeCoverageDetails(COMPONENT_REF, of(COVERAGE_DETAIL_1, COVERAGE_DETAIL_2));

    CloseableIterator<BatchReport.CoverageDetail> res =
        underTest.readCoverageDetails(COMPONENT_REF);
    assertThat(res).containsExactly(COVERAGE_DETAIL_1, COVERAGE_DETAIL_2);
    res.close();
  }
}