/* * Copyright 2000-2016 JetBrains s.r.o. * * 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.jetbrains.lang.dart.coverage; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.intellij.coverage.CoverageEngine; import com.intellij.coverage.CoverageRunner; import com.intellij.coverage.CoverageSuite; import com.intellij.execution.process.ProcessHandler; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.rt.coverage.data.ClassData; import com.intellij.rt.coverage.data.LineData; import com.intellij.rt.coverage.data.ProjectData; import com.jetbrains.lang.dart.analyzer.DartAnalysisServerService; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.util.Map; import java.util.SortedMap; public class DartCoverageRunner extends CoverageRunner { private static final String ID = "DartCoverageRunner"; private static final Logger LOG = Logger.getInstance(DartCoverageRunner.class.getName()); @Nullable @Override public ProjectData loadCoverageData(@NotNull final File sessionDataFile, @Nullable CoverageSuite baseCoverageSuite) { if (!(baseCoverageSuite instanceof DartCoverageSuite)) { return null; } if (ApplicationManager.getApplication().isDispatchThread()) { final Ref<ProjectData> projectDataRef = new Ref<>(); ProgressManager.getInstance().runProcessWithProgressSynchronously( () -> projectDataRef.set(doLoadCoverageData(sessionDataFile, (DartCoverageSuite)baseCoverageSuite)), "Loading Coverage Data...", true, baseCoverageSuite.getProject()); return projectDataRef.get(); } else { return doLoadCoverageData(sessionDataFile, (DartCoverageSuite)baseCoverageSuite); } } @Nullable private static ProjectData doLoadCoverageData(@NotNull final File sessionDataFile, @NotNull final DartCoverageSuite coverageSuite) { final ProcessHandler coverageProcess = coverageSuite.getCoverageProcess(); // coverageProcess == null means that we are switching to data gathered earlier if (coverageProcess != null) { for (int i = 0; i < 100; ++i) { ProgressManager.checkCanceled(); if (coverageProcess.waitFor(100)) { break; } } if (!coverageProcess.isProcessTerminated()) { coverageProcess.destroyProcess(); return null; } } final Project project = coverageSuite.getProject(); final String contextFilePath = coverageSuite.getContextFilePath(); if (project == null || contextFilePath == null) { return null; } final String contextId = DartAnalysisServerService.getInstance(project).execution_createContext(contextFilePath); if (contextId == null) { return null; } final ProjectData projectData = new ProjectData(); try { DartCoverageData data = new Gson().fromJson(new BufferedReader(new FileReader(sessionDataFile)), DartCoverageData.class); if (data == null) { LOG.warn("Coverage file does not contain valid data."); return null; } for (Map.Entry<String, SortedMap<Integer, Integer>> entry : data.getMergedDartFileCoverageData().entrySet()) { ProgressManager.checkCanceled(); String filePath = getFileForUri(project, contextId, entry.getKey()); if (filePath == null) { // File is not found. continue; } SortedMap<Integer, Integer> lineHits = entry.getValue(); ClassData classData = projectData.getOrCreateClassData(filePath); if (lineHits.size() == 0) { classData.setLines(new LineData[1]); continue; } LineData[] lines = new LineData[lineHits.lastKey() + 1]; for (Map.Entry<Integer, Integer> hit : lineHits.entrySet()) { LineData lineData = new LineData(hit.getKey(), null); lineData.setHits(hit.getValue()); lines[hit.getKey()] = lineData; } classData.setLines(lines); } } catch (FileNotFoundException | JsonSyntaxException e) { LOG.warn(e); } finally { DartAnalysisServerService.getInstance(project).execution_deleteContext(contextId); } return projectData; } @Nullable private static String getFileForUri(@NotNull final Project project, @NotNull final String contextId, @NotNull final String uri) { if (uri.startsWith("dart:_") || uri.startsWith("dart:") && uri.contains("-patch/")) { // dart:_builtin or dart:core-patch/core_patch.dart return null; } return DartAnalysisServerService.getInstance(project).execution_mapUri(contextId, null, uri); } @NotNull @Override public String getPresentableName() { return "Dart"; } @NotNull @Override public String getId() { return ID; } @NotNull @Override public String getDataFileExtension() { return "json"; } @Override public boolean acceptsCoverageEngine(@NotNull CoverageEngine engine) { return engine instanceof DartCoverageEngine; } }