| /********************************************************************** |
| * Copyright (c) 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| **********************************************************************/ |
| package org.eclipse.wtp.releng.tools.component.api.testcoverage; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import org.eclipse.jdt.core.util.IModifierConstants; |
| import org.eclipse.wtp.releng.tools.component.ILocation; |
| import org.eclipse.wtp.releng.tools.component.api.APIs; |
| import org.eclipse.wtp.releng.tools.component.api.ClassAPI; |
| import org.eclipse.wtp.releng.tools.component.api.ComponentAPI; |
| import org.eclipse.wtp.releng.tools.component.api.ComponentAPIEmitter; |
| import org.eclipse.wtp.releng.tools.component.api.MethodAPI; |
| import org.eclipse.wtp.releng.tools.component.api.PackageAPI; |
| import org.eclipse.wtp.releng.tools.component.api.testcoverage.MethodAPITestCoverage; |
| import org.eclipse.wtp.releng.tools.component.api.testcoverage.Testcase; |
| import org.eclipse.wtp.releng.tools.component.internal.AbstractEmitter; |
| import org.eclipse.wtp.releng.tools.component.internal.ComponentEntry; |
| import org.eclipse.wtp.releng.tools.component.internal.ComponentSummary; |
| import org.eclipse.wtp.releng.tools.component.internal.FileLocation; |
| import org.eclipse.wtp.releng.tools.component.model.ComponentXML; |
| import org.eclipse.wtp.releng.tools.component.model.Package; |
| import org.eclipse.wtp.releng.tools.component.use.ClassUse; |
| import org.eclipse.wtp.releng.tools.component.use.ComponentUse; |
| import org.eclipse.wtp.releng.tools.component.use.ComponentUseEmitter; |
| import org.eclipse.wtp.releng.tools.component.use.MethodUse; |
| import org.eclipse.wtp.releng.tools.component.use.Source; |
| import org.eclipse.wtp.releng.tools.component.util.CommandOptionParser; |
| |
| public class APITestCoverageEmitter extends AbstractEmitter |
| { |
| public static final String CONST_COMPONENT_API_TEST_COVERAGE_XML = "component-api-tc.xml"; |
| public static final String CONST_COMPONENT_API_TEST_COVERAGE_HTML = "component-api-tc.html"; |
| public static final String OPTION_ECLIPSE_DIR = "eclipseDir"; |
| public static final String OPTION_TEST_DIR = "testDir"; |
| public static final String OPTION_COMPONENT_XML_DIR = "compXMLDir"; |
| public static final String OPTION_COMPONENT_API_DIR = "compAPIDir"; |
| public static final String OPTION_GEN_HTML = "genHTML"; |
| public static final String OPTION_GEN_API = "genAPI"; |
| |
| private String compAPIDir; |
| private Map id2Plugin; |
| private Map id2Fragment; |
| private Map id2TestPlugin; |
| private Map id2TestFragment; |
| private Map compLoc2CompXML; |
| private boolean genHTML; |
| private boolean genAPI; |
| private ComponentAPIEmitter compAPIEmitter; |
| |
| public APITestCoverageEmitter(String compAPIDir) |
| { |
| this.compAPIDir = addTrailingSeperator(compAPIDir); |
| genHTML = false; |
| genAPI = false; |
| } |
| |
| public void init(List eclipseDirs, List testDirs, List compXMLDirs) |
| { |
| id2Plugin = new HashMap(); |
| id2Fragment = new HashMap(); |
| for (Iterator it = eclipseDirs.iterator(); it.hasNext();) |
| { |
| File eclipseFile = new File(addTrailingSeperator((String)it.next())); |
| if (eclipseFile.exists()) |
| harvestPlugins(eclipseFile, id2Plugin, id2Fragment); |
| } |
| linkPluginsAndFragments(id2Plugin, id2Fragment); |
| id2TestPlugin = new HashMap(); |
| id2TestFragment = new HashMap(); |
| for (Iterator it = testDirs.iterator(); it.hasNext();) |
| { |
| File testFile = new File(addTrailingSeperator((String)it.next())); |
| if (testFile.exists()) |
| harvestPlugins(testFile, id2TestPlugin, id2TestFragment); |
| } |
| linkPluginsAndFragments(id2TestPlugin, id2TestFragment); |
| compLoc2CompXML = new HashMap(); |
| for (Iterator it = compXMLDirs.iterator(); it.hasNext();) |
| { |
| File compXMLFile = new File(addTrailingSeperator((String)it.next())); |
| if (compXMLFile.exists()) |
| harvestComponents(compXMLFile, compLoc2CompXML); |
| } |
| init(); |
| } |
| |
| public void init(Map compLoc2CompXML, Map id2Plugin, Map id2Fragment, Map id2TestPlugin, Map id2TestFragment) |
| { |
| this.compLoc2CompXML = compLoc2CompXML; |
| this.id2Plugin = id2Plugin; |
| this.id2Fragment = id2Fragment; |
| this.id2TestPlugin = id2TestPlugin; |
| this.id2TestFragment = id2TestFragment; |
| init(); |
| } |
| |
| private void init() |
| { |
| compAPIEmitter = new ComponentAPIEmitter(genAPI ? compAPIDir : null); |
| compAPIEmitter.init(compLoc2CompXML, id2Plugin, id2Fragment); |
| } |
| |
| /** |
| * @return Returns the genHTML. |
| */ |
| public boolean isGenHTML() |
| { |
| return genHTML; |
| } |
| |
| /** |
| * @param genHTML The genHTML to set. |
| */ |
| public void setGenHTML(boolean genHTML) |
| { |
| this.genHTML = genHTML; |
| } |
| |
| public boolean getGenAPI() |
| { |
| return genAPI; |
| } |
| |
| public void setGenAPI(boolean genAPI) |
| { |
| this.genAPI = genAPI; |
| } |
| |
| public void genAPITestCoverageXML() throws IOException |
| { |
| ComponentSummary compSummary = genAPI ? new ComponentSummary() : null; |
| APITestCoverageSummary summary = new APITestCoverageSummary(); |
| List includes = new ArrayList(); |
| for (Iterator it = compLoc2CompXML.values().iterator(); it.hasNext();) |
| harvestPackages((ComponentXML)it.next(), includes); |
| ComponentUseEmitter compUseEmitter = newComponentUseEmitter(id2TestPlugin, id2TestFragment, includes); |
| ComponentUse compUse = compUseEmitter.genAll(); |
| for (Iterator it = compLoc2CompXML.keySet().iterator(); it.hasNext();) |
| { |
| String compLoc = (String)it.next(); |
| ComponentAPI compAPI = compAPIEmitter.genComponentApiXml(compLoc); |
| compAPI.save(); |
| if (genAPI) |
| { |
| ComponentEntry entry = new ComponentEntry(); |
| entry.setCompName(compAPI.getName()); |
| entry.setRef(compAPI.getLocation().getAbsolutePath()); |
| compSummary.add(entry); |
| } |
| summary.add(genAPITestCoverageXML(compLoc, compUse, compAPI)); |
| } |
| if (compAPIDir != null) |
| { |
| if (genAPI) |
| compSummary.save(new FileLocation(new File(compAPIDir + ComponentSummary.INDEX_COMPONENT_SUMMARY_XML))); |
| summary.save(new FileLocation(new File(compAPIDir + "index-api-tc.xml"))); |
| if (genHTML) |
| { |
| try |
| { |
| summary.saveAsHTML(new FileLocation(new File(compAPIDir + "index-api-tc.html"))); |
| } |
| catch (TransformerConfigurationException e) |
| { |
| e.printStackTrace(); |
| } |
| catch (TransformerException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| |
| public ComponentAPI genAPITestCoverageXML(String compLoc) throws IOException |
| { |
| List includes = new ArrayList(); |
| ComponentXML componentXML = (ComponentXML)compLoc2CompXML.get(compLoc); |
| if (componentXML != null) |
| harvestPackages(componentXML, includes); |
| ComponentUseEmitter compUseEmitter = newComponentUseEmitter(id2TestPlugin, id2TestFragment, includes); |
| ComponentUse compUse = compUseEmitter.genAll(); |
| ComponentAPI compAPI = compAPIEmitter.genComponentApiXml(compLoc); |
| compAPI.save(); |
| return genAPITestCoverageXML(compLoc, compUse, compAPI); |
| } |
| |
| private ComponentAPI genAPITestCoverageXML(String compLoc, ComponentUse compUse, ComponentAPI compAPI) throws IOException |
| { |
| ComponentXML componentXML = (ComponentXML)compLoc2CompXML.get(compLoc); |
| if (componentXML != null) |
| { |
| componentXML.load(); |
| APIs apis = compAPI.getExternalAPIs(); |
| List pkgAPIs = apis.getPackageAPIs(); |
| for (int i = 0; i < pkgAPIs.size(); i++) |
| { |
| PackageAPI pkgAPI = (PackageAPI)pkgAPIs.get(i); |
| List classAPIs = pkgAPI.getClassAPIs(); |
| for (int j = 0; j < classAPIs.size(); j++) |
| { |
| ClassAPI classAPI = (ClassAPI)classAPIs.get(j); |
| int classAccess = classAPI.getAccess(); |
| if (!isBit(classAccess, IModifierConstants.ACC_PUBLIC) || isBit(classAccess, IModifierConstants.ACC_INTERFACE) || !classAPI.isReference()) |
| { |
| // We don't need test coverage for non-public classes, interfaces, |
| // classes that cannot be referenced. |
| classAPIs.remove(j); |
| j--; |
| } |
| else |
| { |
| classAPI.getFieldAPIs().clear(); |
| List methodAPIs = classAPI.getMethodAPIs(); |
| List methodApiTcs = new ArrayList(methodAPIs.size()); |
| for (Iterator it = methodAPIs.iterator(); it.hasNext();) |
| { |
| MethodAPI methodAPI = (MethodAPI)it.next(); |
| methodApiTcs.add(newMethodAPITestCoverage(methodAPI, getTestcases(compUse, classAPI.getName(), methodAPI))); |
| } |
| methodAPIs.clear(); |
| methodAPIs.addAll(methodApiTcs); |
| if (methodAPIs.size() == 0) |
| { |
| // We don't need test coverage for classes with no API methods. |
| classAPIs.remove(j); |
| j--; |
| } |
| } |
| } |
| if (classAPIs.size() == 0) |
| { |
| pkgAPIs.remove(i); |
| i--; |
| } |
| } |
| if (compAPIDir != null) |
| { |
| String compName = componentXML.getName(); |
| StringBuffer sb = new StringBuffer(compAPIDir); |
| sb.append(compName); |
| sb.append('/'); |
| ILocation location = new FileLocation(new File(sb.toString() + CONST_COMPONENT_API_TEST_COVERAGE_XML)); |
| compAPI.setLocation(location); |
| System.out.println("Writing component-api-tc.xml for " + compName); |
| compAPI.save(); |
| if (genHTML) |
| { |
| try |
| { |
| ILocation html = new FileLocation(new File(sb.toString() + CONST_COMPONENT_API_TEST_COVERAGE_HTML)); |
| compAPI.setLocation(html); |
| compAPI.saveAsHTML(html, "org/eclipse/wtp/releng/tools/component/xsl/component-api-tc.xsl"); |
| copyImages(); |
| } |
| catch (TransformerConfigurationException e) |
| { |
| e.printStackTrace(); |
| } |
| catch (TransformerException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| return compAPI; |
| } |
| |
| private void harvestPackages(ComponentXML compXML, List includes) throws IOException |
| { |
| compXML.load(); |
| List pkgs = compXML.getPackages(); |
| for (Iterator it = pkgs.iterator(); it.hasNext();) |
| { |
| String pkgName = ((Package)it.next()).getName(); |
| if (!includes.contains(pkgName)) |
| includes.add(pkgName); |
| } |
| } |
| |
| private ComponentUseEmitter newComponentUseEmitter(Map plugins, Map fragments, List includes) |
| { |
| ComponentUseEmitter compUseEmitter = new ComponentUseEmitter(null); |
| compUseEmitter.setDebug(false); |
| compUseEmitter.setClassUseIncludes(includes); |
| compUseEmitter.init(new HashMap(0), plugins, fragments); |
| return compUseEmitter; |
| } |
| |
| private boolean isBit(int flag, int bit) |
| { |
| return ((flag & bit) == bit); |
| } |
| |
| private MethodAPITestCoverage newMethodAPITestCoverage(MethodAPI methodAPI, List testcases) |
| { |
| MethodAPITestCoverage methodAPITestCoverage = new MethodAPITestCoverage(); |
| methodAPITestCoverage.setName(methodAPI.getName()); |
| methodAPITestCoverage.setDescriptor(methodAPI.getDescriptor()); |
| methodAPITestCoverage.setAccess(methodAPI.getAccess()); |
| methodAPITestCoverage.setTestcases(testcases); |
| return methodAPITestCoverage; |
| } |
| |
| private List getTestcases(ComponentUse compUse, String className, MethodAPI methodAPI) |
| { |
| List testcases = new ArrayList(); |
| for (Iterator sourcesIt = compUse.getSources().iterator(); sourcesIt.hasNext();) |
| { |
| Source source = (Source)sourcesIt.next(); |
| for (Iterator classUsesIt = source.getClassUses().iterator(); classUsesIt.hasNext();) |
| { |
| ClassUse classUse = (ClassUse)classUsesIt.next(); |
| if (classUse.getName().equals(className)) |
| { |
| for (Iterator methodUsesIt = classUse.getMethodUses().iterator(); methodUsesIt.hasNext();) |
| { |
| MethodUse methodUse = (MethodUse)methodUsesIt.next(); |
| if (methodUse.getName().equals(methodAPI.getName()) && methodUse.getDescriptor().equals(methodAPI.getDescriptor())) |
| { |
| Testcase testcase = new Testcase(); |
| testcase.setClassName(source.getName()); |
| testcases.add(testcase); |
| } |
| } |
| } |
| } |
| } |
| return testcases; |
| } |
| |
| private void copyImages() |
| { |
| StringBuffer outputDir = new StringBuffer(compAPIDir).append('/'); |
| File ok = new File(outputDir.toString() + "OK.gif"); |
| if (!ok.exists()) |
| { |
| try |
| { |
| InputStream is = ClassLoader.getSystemResourceAsStream("org/eclipse/wtp/releng/tools/component/images/OK.gif"); |
| BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(ok)); |
| copy(is, bos); |
| } |
| catch (FileNotFoundException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| File fail = new File(outputDir.toString() + "FAIL.gif"); |
| if (!fail.exists()) |
| { |
| try |
| { |
| InputStream is = ClassLoader.getSystemResourceAsStream("org/eclipse/wtp/releng/tools/component/images/FAIL.gif"); |
| BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fail)); |
| copy(is, bos); |
| } |
| catch (FileNotFoundException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| private void copy(InputStream is, OutputStream os) |
| { |
| try |
| { |
| byte[] b = new byte[2048]; |
| int read = is.read(b); |
| while (read != -1) |
| { |
| os.write(b, 0, read); |
| read = is.read(b); |
| } |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| finally |
| { |
| try |
| { |
| os.close(); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| try |
| { |
| is.close(); |
| } |
| catch (IOException e) |
| { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| public static void main(String[] args) |
| { |
| CommandOptionParser optionParser = new CommandOptionParser(args); |
| Map options = optionParser.getOptions(); |
| List eclipseDir = (List)options.get(APITestCoverageEmitter.OPTION_ECLIPSE_DIR); |
| List testDir = (List)options.get(APITestCoverageEmitter.OPTION_TEST_DIR); |
| List compXMLDir = (List)options.get(APITestCoverageEmitter.OPTION_COMPONENT_XML_DIR); |
| List compAPIDir = (List)options.get(APITestCoverageEmitter.OPTION_COMPONENT_API_DIR); |
| List genHTML = (List)options.get(APITestCoverageEmitter.OPTION_GEN_HTML); |
| List genAPI = (List)options.get(APITestCoverageEmitter.OPTION_GEN_API); |
| if (eclipseDir == null || testDir == null || compXMLDir == null || compAPIDir == null || eclipseDir.size() < 1 || testDir.size() < 1 || compXMLDir.size() < 1 || compAPIDir.size() < 1) |
| { |
| printUsage(); |
| System.exit(-1); |
| } |
| APITestCoverageEmitter apiTestCoverageEmitter = new APITestCoverageEmitter((String)compAPIDir.get(0)); |
| apiTestCoverageEmitter.setGenHTML(genHTML != null); |
| apiTestCoverageEmitter.setGenAPI(genAPI != null); |
| apiTestCoverageEmitter.init(eclipseDir, testDir, compXMLDir); |
| try |
| { |
| apiTestCoverageEmitter.genAPITestCoverageXML(); |
| } |
| catch (IOException ioe) |
| { |
| ioe.printStackTrace(); |
| } |
| } |
| |
| private static void printUsage() |
| { |
| System.out.println("Usage: java org.eclipse.wtp.releng.tools.component.api.testcoverage.APITestCoverageEmitter -eclipseDir <eclipseDir> -testDir <testDir> -compXMLDir <compXMLDir> -compAPIDir <compAPIDir> [-options]"); |
| System.out.println(""); |
| System.out.println("\t-eclipseDir\t<eclipseDir>\tspace seperated list of directories containing Eclipse plugins"); |
| System.out.println("\t-testDir\t<testDir>\tspace separated list of directories containing test plugins"); |
| System.out.println("\t-compXMLDir\t<compXMLDir>\tdirectories containing component.xml that will be checked for API test coverage"); |
| System.out.println("\t-compAPIDir\t<compVioDir>\toutput directory of component-api-tc.xml"); |
| System.out.println(""); |
| System.out.println("where options include:"); |
| System.out.println(""); |
| System.out.println("\t-genHTML\tgenerate test coverage report in HTML"); |
| System.out.println("\t-genAPI\t\tgenerate component-api.xml"); |
| } |
| } |