com.google.dart.tools.debug.core.coverage.CoverageManager.java Source code

Java tutorial

Introduction

Here is the source code for com.google.dart.tools.debug.core.coverage.CoverageManager.java

Source

/*
 * Copyright (c) 2014, the Dart project authors.
 * 
 * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
 * 
 * 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.dart.tools.debug.core.coverage;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.dart.engine.utilities.source.SourceRange;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.core.utilities.io.FileUtilities;
import com.google.dart.tools.debug.core.source.UriToFileResolver;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

public class CoverageManager {
    private static final String MARKER_TEXT = "com.google.dart.tools.debug.core.coverageText";
    private static final String MARKER_OVERVIEW = "com.google.dart.tools.debug.core.coverageOverview";

    public static String createTempDir() {
        return Files.createTempDir().getAbsolutePath();
    }

    @VisibleForTesting
    public static TreeMap<Integer, Integer> parseHitMap(JSONObject coverageEntry) throws Exception {
        TreeMap<Integer, Integer> hitMap = Maps.newTreeMap();
        JSONArray hitsArray = coverageEntry.getJSONArray("hits");
        for (int j = 0; j < hitsArray.length() / 2; j++) {
            int line = hitsArray.getInt(2 * j + 0);
            int hits = hitsArray.getInt(2 * j + 1);
            Integer prevHits = hitMap.get(line);
            if (prevHits != null) {
                hits += prevHits.intValue();
            }
            hitMap.put(line, hits);
        }
        return hitMap;
    }

    public static void registerProcess(final UriToFileResolver uriToFileResolver, final String tempDir,
            final String scriptPath, final Process process) {
        Thread thread = new Thread("Coverage process handler") {
            @Override
            public void run() {
                while (true) {
                    try {
                        process.waitFor();
                        break;
                    } catch (InterruptedException e) {
                    }
                }
                try {
                    parseCoverageDirectory(uriToFileResolver, tempDir, scriptPath);
                } finally {
                    uriToFileResolver.dispose();
                }
            }
        };
        thread.setDaemon(true);
        thread.start();
    }

    private static List<SourceRange> createMarkerRanges(final IFile file, final TreeMap<Integer, Integer> hitMap)
            throws Exception {
        List<SourceRange> markerRanges = Lists.newArrayList();
        List<SourceRange> lineRanges = parseFileLines(file);
        SourceRange markerRange = null;
        for (Entry<Integer, Integer> entry : hitMap.entrySet()) {
            if (entry.getValue() == 0) {
                int line = entry.getKey();
                if (line >= lineRanges.size()) {
                    continue;
                }
                SourceRange range = lineRanges.get(line - 1);
                if (markerRange == null) {
                    markerRange = range;
                } else {
                    markerRange = markerRange.getUnion(range);
                }
            } else if (markerRange != null) {
                markerRanges.add(markerRange);
                markerRange = null;
            }
        }
        if (markerRange != null) {
            markerRanges.add(markerRange);
        }
        return markerRanges;
    }

    private static void createMarkers(final Map<IFile, List<SourceRange>> filesMarkerRanges) throws Exception {
        final IWorkspace workspace = ResourcesPlugin.getWorkspace();
        IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
            @Override
            public void run(IProgressMonitor monitor) throws CoreException {
                deleteMarkers();
                for (Entry<IFile, List<SourceRange>> entry : filesMarkerRanges.entrySet()) {
                    IFile file = entry.getKey();
                    List<SourceRange> markerRanges = entry.getValue();
                    for (SourceRange range : markerRanges) {
                        createMarker(file, range, MARKER_TEXT);
                        createMarker(file, range, MARKER_OVERVIEW);
                    }
                }
            }

            private void createMarker(IFile file, SourceRange range, String type) throws CoreException {
                IMarker marker = file.createMarker(type);
                marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_LOW);
                marker.setAttribute(IMarker.CHAR_START, range.getOffset());
                marker.setAttribute(IMarker.CHAR_END, range.getEnd());
            }

            private void deleteMarkers() throws CoreException {
                IWorkspaceRoot root = workspace.getRoot();
                root.deleteMarkers(MARKER_TEXT, true, IResource.DEPTH_INFINITE);
                root.deleteMarkers(MARKER_OVERVIEW, true, IResource.DEPTH_INFINITE);
            }
        };
        workspace.run(runnable, null, IWorkspace.AVOID_UPDATE, null);
    }

    private static IFile getFile(UriToFileResolver uriToFileResolver, IContainer container,
            JSONObject coverageEntry) throws Exception {
        String uri = coverageEntry.getString("source");
        String path = uriToFileResolver.getFileForUri(uri);
        if (path == null) {
            return null;
        }
        File file = new File(path);
        IFile resource = getResourceFile(file);
        return resource;
    }

    private static IFile getResourceFile(File file) {
        try {
            IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
            URI uri = URI.create("file://" + file.getPath());
            IFile[] files = root.findFilesForLocationURI(uri);
            if (files.length == 1) {
                return files[0];
            }
        } catch (Throwable e) {
        }
        return null;
    }

    private static IContainer getScriptContextContainer(String scriptPath) {
        IResource scriptResource = ResourcesPlugin.getWorkspace().getRoot().findMember(scriptPath);
        if (scriptResource == null) {
            return null;
        }
        return scriptResource.getProject();
    }

    private static void parseCoverageDirectory(UriToFileResolver uriToFileResolver, String tempPath,
            String scriptPath) {
        IContainer contextContainer = getScriptContextContainer(scriptPath);
        if (contextContainer == null) {
            return;
        }
        // parse coverage output
        final Map<IFile, List<SourceRange>> filesMarkerRanges = parseCoverageFilesInTempDirectory(uriToFileResolver,
                contextContainer, tempPath);
        if (filesMarkerRanges == null) {
            return;
        }
        // add not loaded Dart files
        try {
            contextContainer.accept(new IResourceVisitor() {
                @Override
                public boolean visit(IResource resource) throws CoreException {
                    if (resource instanceof IFile) {
                        IFile file = (IFile) resource;
                        if (!DartCore.isDartLikeFile(file)) {
                            return false;
                        }
                        if (filesMarkerRanges.containsKey(file)) {
                            return false;
                        }
                        int length = (int) file.getLocation().toFile().length();
                        filesMarkerRanges.put(file, Lists.newArrayList(new SourceRange(0, length)));
                    }
                    return true;
                }
            });
        } catch (Throwable e) {
            e.printStackTrace();
        }
        // create markers for all files in the context
        try {
            createMarkers(filesMarkerRanges);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private static Map<IFile, List<SourceRange>> parseCoverageFile(UriToFileResolver uriToFileResolver,
            IContainer container, File jsonFile) throws Exception {
        Map<IFile, TreeMap<Integer, Integer>> filesHitMaps = Maps.newHashMap();
        Map<IFile, List<SourceRange>> filesMarkerRanges = Maps.newHashMap();
        String fileString = Files.toString(jsonFile, Charsets.UTF_8);
        JSONObject rootObject = new JSONObject(fileString);
        JSONArray coverageArray = rootObject.getJSONArray("coverage");
        for (int i = 0; i < coverageArray.length(); i++) {
            JSONObject coverageEntry = coverageArray.getJSONObject(i);
            // prepare IFile
            IFile file = getFile(uriToFileResolver, container, coverageEntry);
            if (file == null) {
                continue;
            }
            // prepare hit map
            TreeMap<Integer, Integer> hitMap = parseHitMap(coverageEntry);
            if (hitMap == null) {
                continue;
            }
            // merge hit maps
            TreeMap<Integer, Integer> hitMapOld = filesHitMaps.get(file);
            if (hitMapOld != null) {
                Set<Entry<Integer, Integer>> entrySet = hitMapOld.entrySet();
                for (Entry<Integer, Integer> entry : entrySet) {
                    int line = entry.getKey();
                    int hitsOld = entry.getValue();
                    Integer hits = hitMap.get(line);
                    if (hits != null) {
                        hitMap.put(line, hitsOld + hits.intValue());
                    } else {
                        hitMap.put(line, hitsOld);
                    }
                }
            }
            filesHitMaps.put(file, hitMap);
        }
        // add marker ranges
        for (Entry<IFile, TreeMap<Integer, Integer>> entry : filesHitMaps.entrySet()) {
            IFile file = entry.getKey();
            TreeMap<Integer, Integer> hitMap = entry.getValue();
            filesMarkerRanges.put(file, createMarkerRanges(file, hitMap));
        }
        //
        return filesMarkerRanges;
    }

    private static Map<IFile, List<SourceRange>> parseCoverageFilesInTempDirectory(
            UriToFileResolver uriToFileResolver, IContainer container, String tempPath) {
        Map<IFile, List<SourceRange>> result = Maps.newHashMap();
        File tempFile = new File(tempPath);
        File[] outputFiles = tempFile.listFiles();
        try {
            for (File file : outputFiles) {
                String fileName = file.getName().toLowerCase();
                if (fileName.startsWith("dart-cov-") && fileName.endsWith(".json")) {
                    try {
                        Map<IFile, List<SourceRange>> fileResult = parseCoverageFile(uriToFileResolver, container,
                                file);
                        result.putAll(fileResult);
                    } catch (Exception e) {
                    }
                }
            }
        } finally {
            FileUtilities.delete(tempFile);
        }
        return result;
    }

    private static List<SourceRange> parseFileLines(IFile file) throws Exception {
        List<SourceRange> lineRanges = Lists.newArrayList();
        String contents = Files.toString(file.getLocation().toFile(), Charsets.UTF_8);
        int start = 0;
        int offset = 0;
        while (offset < contents.length()) {
            char c = contents.charAt(offset++);
            if (c == '\r') {
                continue;
            }
            if (c == '\n') {
                int end = offset;
                lineRanges.add(new SourceRange(start, end - start));
                start = end;
            }
        }
        return lineRanges;
    }
}